#include "global.h" #include "item.h" #include "util.h" #include "pokemon.h" #include "random.h" #include "data.h" #include "text.h" #include "sound.h" #include "pokedex.h" #include "window.h" #include "main.h" #include "palette.h" #include "money.h" #include "bg.h" #include "string_util.h" #include "pokemon_icon.h" #include "m4a.h" #include "mail.h" #include "event_data.h" #include "pokemon_storage_system.h" #include "task.h" #include "naming_screen.h" #include "overworld.h" #include "party_menu.h" #include "field_specials.h" #include "battle.h" #include "battle_message.h" #include "battle_anim.h" #include "battle_setup.h" #include "battle_ai_script_commands.h" #include "battle_scripts.h" #include "battle_string_ids.h" #include "reshow_battle_screen.h" #include "battle_controllers.h" #include "battle_interface.h" #include "constants/battle_anim.h" #include "constants/battle_move_effects.h" #include "constants/battle_script_commands.h" #include "constants/items.h" #include "constants/hold_effects.h" #include "constants/songs.h" #include "constants/species.h" #include "constants/moves.h" #include "constants/abilities.h" #include "constants/pokemon.h" #define DEFENDER_IS_PROTECTED ((gProtectStructs[gBattlerTarget].protected) && (gBattleMoves[gCurrentMove].flags & FLAG_PROTECT_AFFECTED)) struct StatFractions { u8 dividend; u8 divisor; }; extern const u8 *const gBattleScriptsForMoveEffects[]; bool8 IsTwoTurnsMove(u16 move); void TrySetDestinyBondToHappen(void); u8 AttacksThisTurn(u8 battlerId, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. void CheckWonderGuardAndLevitate(void); u8 ChangeStatBuffs(s8 statValue, u8 statId, u8, const u8 *BS_ptr); bool32 IsMonGettingExpSentOut(void); void sub_8026480(void); bool8 sub_80264D0(void); void DrawLevelUpWindow1(void); void DrawLevelUpWindow2(void); bool8 sub_8026648(void); void PutMonIconOnLvlUpBox(void); void PutLevelAndGenderOnLvlUpBox(void); void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite); void atk00_attackcanceler(void); void atk01_accuracycheck(void); void atk02_attackstring(void); void atk03_ppreduce(void); void atk04_critcalc(void); void atk05_damagecalc(void); void atk06_typecalc(void); void atk07_adjustnormaldamage(void); void atk08_adjustnormaldamage2(void); void atk09_attackanimation(void); void atk0A_waitanimation(void); void atk0B_healthbarupdate(void); void atk0C_datahpupdate(void); void atk0D_critmessage(void); void atk0E_effectivenesssound(void); void atk0F_resultmessage(void); void atk10_printstring(void); void atk11_printselectionstring(void); void atk12_waitmessage(void); void atk13_printfromtable(void); void atk14_printselectionstringfromtable(void); void atk15_seteffectwithchance(void); void atk16_seteffectprimary(void); void atk17_seteffectsecondary(void); void atk18_clearstatusfromeffect(void); void atk19_tryfaintmon(void); void atk1A_dofaintanimation(void); void atk1B_cleareffectsonfaint(void); void atk1C_jumpifstatus(void); void atk1D_jumpifstatus2(void); void atk1E_jumpifability(void); void atk1F_jumpifsideaffecting(void); void atk20_jumpifstat(void); void atk21_jumpifstatus3condition(void); void atk22_jumpiftype(void); void atk23_getexp(void); void atk24(void); void atk25_movevaluescleanup(void); void atk26_setmultihit(void); void atk27_decrementmultihit(void); void atk28_goto(void); void atk29_jumpifbyte(void); void atk2A_jumpifhalfword(void); void atk2B_jumpifword(void); void atk2C_jumpifarrayequal(void); void atk2D_jumpifarraynotequal(void); void atk2E_setbyte(void); void atk2F_addbyte(void); void atk30_subbyte(void); void atk31_copyarray(void); void atk32_copyarraywithindex(void); void atk33_orbyte(void); void atk34_orhalfword(void); void atk35_orword(void); void atk36_bicbyte(void); void atk37_bichalfword(void); void atk38_bicword(void); void atk39_pause(void); void atk3A_waitstate(void); void atk3B_healthbar_update(void); void atk3C_return(void); void atk3D_end(void); void atk3E_end2(void); void atk3F_end3(void); void atk40_jumpifaffectedbyprotect(void); void atk41_call(void); void atk42_jumpiftype2(void); void atk43_jumpifabilitypresent(void); void atk44_endselectionscript(void); void atk45_playanimation(void); void atk46_playanimation2(void); void atk47_setgraphicalstatchangevalues(void); void atk48_playstatchangeanimation(void); void atk49_moveend(void); void atk4A_typecalc2(void); void atk4B_returnatktoball(void); void atk4C_getswitchedmondata(void); void atk4D_switchindataupdate(void); void atk4E_switchinanim(void); void atk4F_jumpifcantswitch(void); void atk50_openpartyscreen(void); void atk51_switchhandleorder(void); void atk52_switchineffects(void); void atk53_trainerslidein(void); void atk54_playse(void); void atk55_fanfare(void); void atk56_playfaintcry(void); void atk57(void); void atk58_returntoball(void); void atk59_handlelearnnewmove(void); void atk5A_yesnoboxlearnmove(void); void atk5B_yesnoboxstoplearningmove(void); void atk5C_hitanimation(void); void atk5D_getmoneyreward(void); void atk5E(void); void atk5F_swapattackerwithtarget(void); void atk60_incrementgamestat(void); void atk61_drawpartystatussummary(void); void atk62_hidepartystatussummary(void); void atk63_jumptocalledmove(void); void atk64_statusanimation(void); void atk65_status2animation(void); void atk66_chosenstatusanimation(void); void atk67_yesnobox(void); void atk68_cancelallactions(void); void atk69_adjustsetdamage(void); void atk6A_removeitem(void); void atk6B_atknameinbuff1(void); void atk6C_drawlvlupbox(void); void atk6D_resetsentmonsvalue(void); void atk6E_setatktoplayer0(void); void atk6F_makevisible(void); void atk70_recordlastability(void); void atk71_buffermovetolearn(void); void atk72_jumpifplayerran(void); void atk73_hpthresholds(void); void atk74_hpthresholds2(void); void atk75_useitemonopponent(void); void atk76_various(void); void atk77_setprotectlike(void); void atk78_faintifabilitynotdamp(void); void atk79_setatkhptozero(void); void atk7A_jumpifnexttargetvalid(void); void atk7B_tryhealhalfhealth(void); void atk7C_trymirrormove(void); void atk7D_setrain(void); void atk7E_setreflect(void); void atk7F_setseeded(void); void atk80_manipulatedamage(void); void atk81_trysetrest(void); void atk82_jumpifnotfirstturn(void); void atk83_nop(void); void atk84_jumpifcantmakeasleep(void); void atk85_stockpile(void); void atk86_stockpiletobasedamage(void); void atk87_stockpiletohpheal(void); void atk88_negativedamage(void); void atk89_statbuffchange(void); void atk8A_normalisebuffs(void); void atk8B_setbide(void); void atk8C_confuseifrepeatingattackends(void); void atk8D_setmultihitcounter(void); void atk8E_initmultihitstring(void); void atk8F_forcerandomswitch(void); void atk90_tryconversiontypechange(void); void atk91_givepaydaymoney(void); void atk92_setlightscreen(void); void atk93_tryKO(void); void atk94_damagetohalftargethp(void); void atk95_setsandstorm(void); void atk96_weatherdamage(void); void atk97_tryinfatuating(void); void atk98_updatestatusicon(void); void atk99_setmist(void); void atk9A_setfocusenergy(void); void atk9B_transformdataexecution(void); void atk9C_setsubstitute(void); void atk9D_mimicattackcopy(void); void atk9E_metronome(void); void atk9F_dmgtolevel(void); void atkA0_psywavedamageeffect(void); void atkA1_counterdamagecalculator(void); void atkA2_mirrorcoatdamagecalculator(void); void atkA3_disablelastusedattack(void); void atkA4_trysetencore(void); void atkA5_painsplitdmgcalc(void); void atkA6_settypetorandomresistance(void); void atkA7_setalwayshitflag(void); void atkA8_copymovepermanently(void); void atkA9_trychoosesleeptalkmove(void); void atkAA_setdestinybond(void); void atkAB_trysetdestinybondtohappen(void); void atkAC_remaininghptopower(void); void atkAD_tryspiteppreduce(void); void atkAE_healpartystatus(void); void atkAF_cursetarget(void); void atkB0_trysetspikes(void); void atkB1_setforesight(void); void atkB2_trysetperishsong(void); void atkB3_rolloutdamagecalculation(void); void atkB4_jumpifconfusedandstatmaxed(void); void atkB5_furycuttercalc(void); void atkB6_happinesstodamagecalculation(void); void atkB7_presentdamagecalculation(void); void atkB8_setsafeguard(void); void atkB9_magnitudedamagecalculation(void); void atkBA_jumpifnopursuitswitchdmg(void); void atkBB_setsunny(void); void atkBC_maxattackhalvehp(void); void atkBD_copyfoestats(void); void atkBE_rapidspinfree(void); void atkBF_setdefensecurlbit(void); void atkC0_recoverbasedonsunlight(void); void atkC1_hiddenpowercalc(void); void atkC2_selectfirstvalidtarget(void); void atkC3_trysetfutureattack(void); void atkC4_trydobeatup(void); void atkC5_setsemiinvulnerablebit(void); void atkC6_clearsemiinvulnerablebit(void); void atkC7_setminimize(void); void atkC8_sethail(void); void atkC9_jumpifattackandspecialattackcannotfall(void); void atkCA_setforcedtarget(void); void atkCB_setcharge(void); void atkCC_callterrainattack(void); void atkCD_cureifburnedparalysedorpoisoned(void); void atkCE_settorment(void); void atkCF_jumpifnodamage(void); void atkD0_settaunt(void); void atkD1_trysethelpinghand(void); void atkD2_tryswapitems(void); void atkD3_trycopyability(void); void atkD4_trywish(void); void atkD5_trysetroots(void); void atkD6_doubledamagedealtifdamaged(void); void atkD7_setyawn(void); void atkD8_setdamagetohealthdifference(void); void atkD9_scaledamagebyhealthratio(void); void atkDA_tryswapabilities(void); void atkDB_tryimprison(void); void atkDC_trysetgrudge(void); void atkDD_weightdamagecalculation(void); void atkDE_assistattackselect(void); void atkDF_trysetmagiccoat(void); void atkE0_trysetsnatch(void); void atkE1_trygetintimidatetarget(void); void atkE2_switchoutabilities(void); void atkE3_jumpifhasnohp(void); void atkE4_getsecretpowereffect(void); void atkE5_pickup(void); void atkE6_docastformchangeanimation(void); void atkE7_trycastformdatachange(void); void atkE8_settypebasedhalvers(void); void atkE9_setweatherballtype(void); void atkEA_tryrecycleitem(void); void atkEB_settypetoterrain(void); void atkEC_pursuitrelated(void); void atkED_snatchsetbattlers(void); void atkEE_removelightscreenreflect(void); void atkEF_handleballthrow(void); void atkF0_givecaughtmon(void); void atkF1_trysetcaughtmondexflags(void); void atkF2_displaydexinfo(void); void atkF3_trygivecaughtmonnick(void); void atkF4_subattackerhpbydmg(void); void atkF5_removeattackerstatus1(void); void atkF6_finishaction(void); void atkF7_finishturn(void); void (* const gBattleScriptingCommandsTable[])(void) = { atk00_attackcanceler, atk01_accuracycheck, atk02_attackstring, atk03_ppreduce, atk04_critcalc, atk05_damagecalc, atk06_typecalc, atk07_adjustnormaldamage, atk08_adjustnormaldamage2, atk09_attackanimation, atk0A_waitanimation, atk0B_healthbarupdate, atk0C_datahpupdate, atk0D_critmessage, atk0E_effectivenesssound, atk0F_resultmessage, atk10_printstring, atk11_printselectionstring, atk12_waitmessage, atk13_printfromtable, atk14_printselectionstringfromtable, atk15_seteffectwithchance, atk16_seteffectprimary, atk17_seteffectsecondary, atk18_clearstatusfromeffect, atk19_tryfaintmon, atk1A_dofaintanimation, atk1B_cleareffectsonfaint, atk1C_jumpifstatus, atk1D_jumpifstatus2, atk1E_jumpifability, atk1F_jumpifsideaffecting, atk20_jumpifstat, atk21_jumpifstatus3condition, atk22_jumpiftype, atk23_getexp, atk24, atk25_movevaluescleanup, atk26_setmultihit, atk27_decrementmultihit, atk28_goto, atk29_jumpifbyte, atk2A_jumpifhalfword, atk2B_jumpifword, atk2C_jumpifarrayequal, atk2D_jumpifarraynotequal, atk2E_setbyte, atk2F_addbyte, atk30_subbyte, atk31_copyarray, atk32_copyarraywithindex, atk33_orbyte, atk34_orhalfword, atk35_orword, atk36_bicbyte, atk37_bichalfword, atk38_bicword, atk39_pause, atk3A_waitstate, atk3B_healthbar_update, atk3C_return, atk3D_end, atk3E_end2, atk3F_end3, atk40_jumpifaffectedbyprotect, atk41_call, atk42_jumpiftype2, atk43_jumpifabilitypresent, atk44_endselectionscript, atk45_playanimation, atk46_playanimation2, atk47_setgraphicalstatchangevalues, atk48_playstatchangeanimation, atk49_moveend, atk4A_typecalc2, atk4B_returnatktoball, atk4C_getswitchedmondata, atk4D_switchindataupdate, atk4E_switchinanim, atk4F_jumpifcantswitch, atk50_openpartyscreen, atk51_switchhandleorder, atk52_switchineffects, atk53_trainerslidein, atk54_playse, atk55_fanfare, atk56_playfaintcry, atk57, atk58_returntoball, atk59_handlelearnnewmove, atk5A_yesnoboxlearnmove, atk5B_yesnoboxstoplearningmove, atk5C_hitanimation, atk5D_getmoneyreward, atk5E, atk5F_swapattackerwithtarget, atk60_incrementgamestat, atk61_drawpartystatussummary, atk62_hidepartystatussummary, atk63_jumptocalledmove, atk64_statusanimation, atk65_status2animation, atk66_chosenstatusanimation, atk67_yesnobox, atk68_cancelallactions, atk69_adjustsetdamage, atk6A_removeitem, atk6B_atknameinbuff1, atk6C_drawlvlupbox, atk6D_resetsentmonsvalue, atk6E_setatktoplayer0, atk6F_makevisible, atk70_recordlastability, atk71_buffermovetolearn, atk72_jumpifplayerran, atk73_hpthresholds, atk74_hpthresholds2, atk75_useitemonopponent, atk76_various, atk77_setprotectlike, atk78_faintifabilitynotdamp, atk79_setatkhptozero, atk7A_jumpifnexttargetvalid, atk7B_tryhealhalfhealth, atk7C_trymirrormove, atk7D_setrain, atk7E_setreflect, atk7F_setseeded, atk80_manipulatedamage, atk81_trysetrest, atk82_jumpifnotfirstturn, atk83_nop, atk84_jumpifcantmakeasleep, atk85_stockpile, atk86_stockpiletobasedamage, atk87_stockpiletohpheal, atk88_negativedamage, atk89_statbuffchange, atk8A_normalisebuffs, atk8B_setbide, atk8C_confuseifrepeatingattackends, atk8D_setmultihitcounter, atk8E_initmultihitstring, atk8F_forcerandomswitch, atk90_tryconversiontypechange, atk91_givepaydaymoney, atk92_setlightscreen, atk93_tryKO, atk94_damagetohalftargethp, atk95_setsandstorm, atk96_weatherdamage, atk97_tryinfatuating, atk98_updatestatusicon, atk99_setmist, atk9A_setfocusenergy, atk9B_transformdataexecution, atk9C_setsubstitute, atk9D_mimicattackcopy, atk9E_metronome, atk9F_dmgtolevel, atkA0_psywavedamageeffect, atkA1_counterdamagecalculator, atkA2_mirrorcoatdamagecalculator, atkA3_disablelastusedattack, atkA4_trysetencore, atkA5_painsplitdmgcalc, atkA6_settypetorandomresistance, atkA7_setalwayshitflag, atkA8_copymovepermanently, atkA9_trychoosesleeptalkmove, atkAA_setdestinybond, atkAB_trysetdestinybondtohappen, atkAC_remaininghptopower, atkAD_tryspiteppreduce, atkAE_healpartystatus, atkAF_cursetarget, atkB0_trysetspikes, atkB1_setforesight, atkB2_trysetperishsong, atkB3_rolloutdamagecalculation, atkB4_jumpifconfusedandstatmaxed, atkB5_furycuttercalc, atkB6_happinesstodamagecalculation, atkB7_presentdamagecalculation, atkB8_setsafeguard, atkB9_magnitudedamagecalculation, atkBA_jumpifnopursuitswitchdmg, atkBB_setsunny, atkBC_maxattackhalvehp, atkBD_copyfoestats, atkBE_rapidspinfree, atkBF_setdefensecurlbit, atkC0_recoverbasedonsunlight, atkC1_hiddenpowercalc, atkC2_selectfirstvalidtarget, atkC3_trysetfutureattack, atkC4_trydobeatup, atkC5_setsemiinvulnerablebit, atkC6_clearsemiinvulnerablebit, atkC7_setminimize, atkC8_sethail, atkC9_jumpifattackandspecialattackcannotfall, atkCA_setforcedtarget, atkCB_setcharge, atkCC_callterrainattack, atkCD_cureifburnedparalysedorpoisoned, atkCE_settorment, atkCF_jumpifnodamage, atkD0_settaunt, atkD1_trysethelpinghand, atkD2_tryswapitems, atkD3_trycopyability, atkD4_trywish, atkD5_trysetroots, atkD6_doubledamagedealtifdamaged, atkD7_setyawn, atkD8_setdamagetohealthdifference, atkD9_scaledamagebyhealthratio, atkDA_tryswapabilities, atkDB_tryimprison, atkDC_trysetgrudge, atkDD_weightdamagecalculation, atkDE_assistattackselect, atkDF_trysetmagiccoat, atkE0_trysetsnatch, atkE1_trygetintimidatetarget, atkE2_switchoutabilities, atkE3_jumpifhasnohp, atkE4_getsecretpowereffect, atkE5_pickup, atkE6_docastformchangeanimation, atkE7_trycastformdatachange, atkE8_settypebasedhalvers, atkE9_setweatherballtype, atkEA_tryrecycleitem, atkEB_settypetoterrain, atkEC_pursuitrelated, atkED_snatchsetbattlers, atkEE_removelightscreenreflect, atkEF_handleballthrow, atkF0_givecaughtmon, atkF1_trysetcaughtmondexflags, atkF2_displaydexinfo, atkF3_trygivecaughtmonnick, atkF4_subattackerhpbydmg, atkF5_removeattackerstatus1, atkF6_finishaction, atkF7_finishturn, }; const struct StatFractions sAccuracyStageRatios[] = { { 33, 100 }, // -6 { 36, 100 }, // -5 { 43, 100 }, // -4 { 50, 100 }, // -3 { 60, 100 }, // -2 { 75, 100 }, // -1 { 1, 1 }, // 0 { 133, 100 }, // +1 { 166, 100 }, // +2 { 2, 1 }, // +3 { 233, 100 }, // +4 { 133, 50 }, // +5 { 3, 1 }, // +6 }; // The chance is 1/N for each stage. const u16 sCriticalHitChance[] = { 16, 8, 4, 3, 2 }; const u32 sStatusFlagsForMoveEffects[] = { 0x00000000, STATUS1_SLEEP, STATUS1_POISON, STATUS1_BURN, STATUS1_FREEZE, STATUS1_PARALYSIS, STATUS1_TOXIC_POISON, STATUS2_CONFUSION, STATUS2_FLINCHED, 0x00000000, STATUS2_UPROAR, 0x00000000, STATUS2_MULTIPLETURNS, STATUS2_WRAPPED, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, STATUS2_RECHARGE, 0x00000000, 0x00000000, STATUS2_ESCAPE_PREVENTION, STATUS2_NIGHTMARE, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, STATUS2_LOCK_CONFUSE, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; const u8 *const sMoveEffectBS_Ptrs[] = { [0] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_SLEEP] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_POISON] = BattleScript_MoveEffectPoison, [MOVE_EFFECT_BURN] = BattleScript_MoveEffectBurn, [MOVE_EFFECT_FREEZE] = BattleScript_MoveEffectFreeze, [MOVE_EFFECT_PARALYSIS] = BattleScript_MoveEffectParalysis, [MOVE_EFFECT_TOXIC] = BattleScript_MoveEffectToxic, [MOVE_EFFECT_CONFUSION] = BattleScript_MoveEffectConfusion, [MOVE_EFFECT_FLINCH] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_TRI_ATTACK] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_UPROAR] = BattleScript_MoveEffectUproar, [MOVE_EFFECT_PAYDAY] = BattleScript_MoveEffectPayDay, [MOVE_EFFECT_CHARGING] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_WRAP] = BattleScript_MoveEffectWrap, [MOVE_EFFECT_RECOIL_25] = BattleScript_MoveEffectRecoil, [MOVE_EFFECT_ATK_PLUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_DEF_PLUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_SPD_PLUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_SP_ATK_PLUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_SP_DEF_PLUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_ACC_PLUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_EVS_PLUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_ATK_MINUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_DEF_MINUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_SPD_MINUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_SP_ATK_MINUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_SP_DEF_MINUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_ACC_MINUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_EVS_MINUS_1] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_RECHARGE] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_RAGE] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_STEAL_ITEM] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_PREVENT_ESCAPE] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_NIGHTMARE] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_ALL_STATS_UP] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_RAPIDSPIN] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_REMOVE_PARALYSIS] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_ATK_DEF_DOWN] = BattleScript_MoveEffectSleep, [MOVE_EFFECT_RECOIL_33] = BattleScript_MoveEffectRecoil, }; // not used static const struct WindowTemplate sUnusedWinTemplate = { .bg = 0, .tilemapLeft = 1, .tilemapTop = 3, .width = 7, .height = 15, .paletteNum = 31, .baseBlock = 0x3F, }; const u16 gUnknown_82506D0[] = INCBIN_U16("graphics/battle_interface/unk_battlebox.gbapal"); const u32 gUnknown_82506F0[] = INCBIN_U32("graphics/battle_interface/unk_battlebox.4bpp.lz"); // not used const u8 sRubyLevelUpStatBoxStats[] = { MON_DATA_MAX_HP, MON_DATA_SPATK, MON_DATA_ATK, MON_DATA_SPDEF, MON_DATA_DEF, MON_DATA_SPEED }; const struct OamData sOamData_MonIconOnLvlUpBox = { .y = 0, .affineMode = 0, .objMode = 0, .mosaic = 0, .bpp = 0, .shape = SPRITE_SHAPE(32x32), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(32x32), .tileNum = 0, .priority = 0, .paletteNum = 0, .affineParam = 0, }; #define MON_ICON_LVLUP_BOX_TAG 0xD75A const struct SpriteTemplate sSpriteTemplate_MonIconOnLvlUpBox = { .tileTag = MON_ICON_LVLUP_BOX_TAG, .paletteTag = MON_ICON_LVLUP_BOX_TAG, .oam = &sOamData_MonIconOnLvlUpBox, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCB_MonIconOnLvlUpBox }; const u16 sProtectSuccessRates[] = { USHRT_MAX, USHRT_MAX / 2, USHRT_MAX / 4, USHRT_MAX / 8 }; #define MIMIC_FORBIDDEN_END 0xFFFE #define METRONOME_FORBIDDEN_END 0xFFFF #define ASSIST_FORBIDDEN_END 0xFFFF const u16 sMovesForbiddenToCopy[] = { MOVE_METRONOME, MOVE_STRUGGLE, MOVE_SKETCH, MOVE_MIMIC, MIMIC_FORBIDDEN_END, MOVE_COUNTER, MOVE_MIRROR_COAT, MOVE_PROTECT, MOVE_DETECT, MOVE_ENDURE, MOVE_DESTINY_BOND, MOVE_SLEEP_TALK, MOVE_THIEF, MOVE_FOLLOW_ME, MOVE_SNATCH, MOVE_HELPING_HAND, MOVE_COVET, MOVE_TRICK, MOVE_FOCUS_PUNCH, METRONOME_FORBIDDEN_END }; const u8 sFlailHpScaleToPowerTable[] = { 1, 200, 4, 150, 9, 100, 16, 80, 32, 40, 48, 20 }; const u16 sNaturePowerMoves[] = { MOVE_STUN_SPORE, MOVE_RAZOR_LEAF, MOVE_EARTHQUAKE, MOVE_HYDRO_PUMP, MOVE_SURF, MOVE_BUBBLE_BEAM, MOVE_ROCK_SLIDE, MOVE_SHADOW_BALL, MOVE_SWIFT, MOVE_SWIFT }; const u16 sWeightToDamageTable[] = { 100, 20, 250, 40, 500, 60, 1000, 80, 2000, 100, 0xFFFF, 0xFFFF }; struct PickupItem { u16 itemId; u8 chance; }; const struct PickupItem sPickupItems[] = { { ITEM_ORAN_BERRY, 15 }, { ITEM_CHERI_BERRY, 25 }, { ITEM_CHESTO_BERRY, 35 }, { ITEM_PECHA_BERRY, 45 }, { ITEM_RAWST_BERRY, 55 }, { ITEM_ASPEAR_BERRY, 65 }, { ITEM_PERSIM_BERRY, 75 }, { ITEM_TM10, 80 }, { ITEM_PP_UP, 85 }, { ITEM_RARE_CANDY, 90 }, { ITEM_NUGGET, 95 }, { ITEM_SPELON_BERRY, 96 }, { ITEM_PAMTRE_BERRY, 97 }, { ITEM_WATMEL_BERRY, 98 }, { ITEM_DURIN_BERRY, 99 }, { ITEM_BELUE_BERRY, 1 }, }; const u8 sTerrainToType[] = { TYPE_GRASS, // tall grass TYPE_GRASS, // long grass TYPE_GROUND, // sand TYPE_WATER, // underwater TYPE_WATER, // water TYPE_WATER, // pond water TYPE_ROCK, // rock TYPE_ROCK, // cave TYPE_NORMAL, // building TYPE_NORMAL, // plain }; const u8 sBallCatchBonuses[] = { 20, 15, 10, 15 // Ultra, Great, Poke, Safari }; // not used const u32 gUnknown_8250898 = 0xFF7EAE60; void atk00_attackcanceler(void) { s32 i; if (gBattleOutcome) { gCurrentActionFuncId = B_ACTION_FINISHED; return; } if (gBattleMons[gBattlerAttacker].hp == 0 && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) { gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattlescriptCurrInstr = BattleScript_MoveEnd; return; } if (AtkCanceller_UnableToUseMove()) return; if (AbilityBattleEffects(ABILITYEFFECT_MOVES_BLOCK, gBattlerTarget, 0, 0, 0)) return; if (!gBattleMons[gBattlerAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE && !(gHitMarker & (HITMARKER_x800000 | HITMARKER_NO_ATTACKSTRING)) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) { gBattlescriptCurrInstr = BattleScript_NoPPForMove; gMoveResultFlags |= MOVE_RESULT_MISSED; return; } gHitMarker &= ~(HITMARKER_x800000); if (!(gHitMarker & HITMARKER_OBEYS) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) { i = IsMonDisobedient(); switch (i) { case 0: break; case 2: gHitMarker |= HITMARKER_OBEYS; return; default: gMoveResultFlags |= MOVE_RESULT_MISSED; return; } } gHitMarker |= HITMARKER_OBEYS; if (gProtectStructs[gBattlerTarget].bounceMove && gBattleMoves[gCurrentMove].flags & FLAG_MAGICCOAT_AFFECTED) { PressurePPLose(gBattlerAttacker, gBattlerTarget, MOVE_MAGIC_COAT); gProtectStructs[gBattlerTarget].bounceMove = FALSE; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MagicCoatBounce; return; } for (i = 0; i < gBattlersCount; ++i) { if ((gProtectStructs[gBattlerByTurnOrder[i]].stealMove) && gBattleMoves[gCurrentMove].flags & FLAG_SNATCH_AFFECTED) { PressurePPLose(gBattlerAttacker, gBattlerByTurnOrder[i], MOVE_SNATCH); gProtectStructs[gBattlerByTurnOrder[i]].stealMove = FALSE; gBattleScripting.battler = gBattlerByTurnOrder[i]; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_SnatchedMove; return; } } if (gSpecialStatuses[gBattlerTarget].lightningRodRedirected) { gSpecialStatuses[gBattlerTarget].lightningRodRedirected = FALSE; gLastUsedAbility = ABILITY_LIGHTNING_ROD; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_TookAttack; RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); } else if (DEFENDER_IS_PROTECTED && (gCurrentMove != MOVE_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) && ((!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))) { CancelMultiTurnMoves(gBattlerAttacker); gMoveResultFlags |= MOVE_RESULT_MISSED; gLastLandedMoves[gBattlerTarget] = 0; gLastHitByType[gBattlerTarget] = 0; gBattleCommunication[6] = 1; ++gBattlescriptCurrInstr; } else { ++gBattlescriptCurrInstr; } } void JumpIfMoveFailed(u8 adder, u16 move) { const u8 *BS_ptr = gBattlescriptCurrInstr + adder; if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) { gLastLandedMoves[gBattlerTarget] = 0; gLastHitByType[gBattlerTarget] = 0; BS_ptr = T1_READ_PTR(gBattlescriptCurrInstr + 1); } else { TrySetDestinyBondToHappen(); if (AbilityBattleEffects(ABILITYEFFECT_ABSORBING, gBattlerTarget, 0, 0, move)) return; } gBattlescriptCurrInstr = BS_ptr; } void atk40_jumpifaffectedbyprotect(void) { if (DEFENDER_IS_PROTECTED) { gMoveResultFlags |= MOVE_RESULT_MISSED; JumpIfMoveFailed(5, 0); gBattleCommunication[6] = 1; } else { gBattlescriptCurrInstr += 5; } } bool8 JumpIfMoveAffectedByProtect(u16 move) { bool8 affected = FALSE; if (DEFENDER_IS_PROTECTED) { gMoveResultFlags |= MOVE_RESULT_MISSED; JumpIfMoveFailed(7, move); gBattleCommunication[6] = 1; affected = TRUE; } return affected; } bool8 AccuracyCalcHelper(u16 move) { if (gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker) { JumpIfMoveFailed(7, move); return TRUE; } if (!(gHitMarker & HITMARKER_IGNORE_ON_AIR) && gStatuses3[gBattlerTarget] & STATUS3_ON_AIR) { gMoveResultFlags |= MOVE_RESULT_MISSED; JumpIfMoveFailed(7, move); return TRUE; } gHitMarker &= ~HITMARKER_IGNORE_ON_AIR; if (!(gHitMarker & HITMARKER_IGNORE_UNDERGROUND) && gStatuses3[gBattlerTarget] & STATUS3_UNDERGROUND) { gMoveResultFlags |= MOVE_RESULT_MISSED; JumpIfMoveFailed(7, move); return TRUE; } gHitMarker &= ~HITMARKER_IGNORE_UNDERGROUND; if (!(gHitMarker & HITMARKER_IGNORE_UNDERWATER) && gStatuses3[gBattlerTarget] & STATUS3_UNDERWATER) { gMoveResultFlags |= MOVE_RESULT_MISSED; JumpIfMoveFailed(7, move); return TRUE; } gHitMarker &= ~HITMARKER_IGNORE_UNDERWATER; if ((WEATHER_HAS_EFFECT && (gBattleWeather & WEATHER_RAIN_ANY) && gBattleMoves[move].effect == EFFECT_THUNDER) || (gBattleMoves[move].effect == EFFECT_ALWAYS_HIT || gBattleMoves[move].effect == EFFECT_VITAL_THROW)) { JumpIfMoveFailed(7, move); return TRUE; } return FALSE; } void atk01_accuracycheck(void) { u16 move = T2_READ_16(gBattlescriptCurrInstr + 5); if ((gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE && !sub_80EB2E0(1) && gBattleMoves[move].power != 0 && GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) || (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE && !sub_80EB2E0(2) && gBattleMoves[move].power == 0 && GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) || (gBattleTypeFlags & BATTLE_TYPE_POKEDUDE)) { JumpIfMoveFailed(7, move); return; } if (move == NO_ACC_CALC || move == NO_ACC_CALC_CHECK_LOCK_ON) { if (gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && move == NO_ACC_CALC_CHECK_LOCK_ON && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker) gBattlescriptCurrInstr += 7; else if (gStatuses3[gBattlerTarget] & (STATUS3_ON_AIR | STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); else if (!JumpIfMoveAffectedByProtect(0)) gBattlescriptCurrInstr += 7; } else { u8 type, moveAcc, holdEffect, param; s8 buff; u16 calc; if (move == 0) move = gCurrentMove; GET_MOVE_TYPE(move, type); if (JumpIfMoveAffectedByProtect(move) || AccuracyCalcHelper(move)) return; if (gBattleMons[gBattlerTarget].status2 & STATUS2_FORESIGHT) { u8 acc = gBattleMons[gBattlerAttacker].statStages[STAT_ACC]; buff = acc; } else { u8 acc = gBattleMons[gBattlerAttacker].statStages[STAT_ACC]; buff = acc + 6 - gBattleMons[gBattlerTarget].statStages[STAT_EVASION]; } if (buff < 0) buff = 0; if (buff > 0xC) buff = 0xC; moveAcc = gBattleMoves[move].accuracy; // check Thunder on sunny weather if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY && gBattleMoves[move].effect == EFFECT_THUNDER) moveAcc = 50; calc = sAccuracyStageRatios[buff].dividend * moveAcc; calc /= sAccuracyStageRatios[buff].divisor; if (gBattleMons[gBattlerAttacker].ability == ABILITY_COMPOUND_EYES) calc = (calc * 130) / 100; // 1.3 compound eyes boost if (WEATHER_HAS_EFFECT && gBattleMons[gBattlerTarget].ability == ABILITY_SAND_VEIL && gBattleWeather & WEATHER_SANDSTORM_ANY) calc = (calc * 80) / 100; // 1.2 sand veil loss if (gBattleMons[gBattlerAttacker].ability == ABILITY_HUSTLE && IS_TYPE_PHYSICAL(type)) calc = (calc * 80) / 100; // 1.2 hustle loss if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY) { holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect; param = gEnigmaBerries[gBattlerTarget].holdEffectParam; } else { holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item); param = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item); } gPotentialItemEffectBattler = gBattlerTarget; if (holdEffect == HOLD_EFFECT_EVASION_UP) calc = (calc * (100 - param)) / 100; // final calculation if ((Random() % 100 + 1) > calc) { gMoveResultFlags |= MOVE_RESULT_MISSED; if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && (gBattleMoves[move].target == MOVE_TARGET_BOTH || gBattleMoves[move].target == MOVE_TARGET_FOES_AND_ALLY)) gBattleCommunication[6] = 2; else gBattleCommunication[6] = 0; CheckWonderGuardAndLevitate(); } JumpIfMoveFailed(7, move); } } void atk02_attackstring(void) { if (!gBattleControllerExecFlags) { if (!(gHitMarker & (HITMARKER_NO_ATTACKSTRING | HITMARKER_ATTACKSTRING_PRINTED))) { PrepareStringBattle(STRINGID_USEDMOVE, gBattlerAttacker); gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED; } ++gBattlescriptCurrInstr; gBattleCommunication[MSG_DISPLAY] = 0; } } void atk03_ppreduce(void) { s32 ppToDeduct = 1; if (!gBattleControllerExecFlags) { if (!gSpecialStatuses[gBattlerAttacker].ppNotAffectedByPressure) { switch (gBattleMoves[gCurrentMove].target) { case MOVE_TARGET_FOES_AND_ALLY: ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_ON_FIELD, gBattlerAttacker, ABILITY_PRESSURE, 0, 0); break; case MOVE_TARGET_BOTH: case MOVE_TARGET_OPPONENTS_FIELD: ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBattlerAttacker, ABILITY_PRESSURE, 0, 0); break; default: if (gBattlerAttacker != gBattlerTarget && gBattleMons[gBattlerTarget].ability == ABILITY_PRESSURE) ++ppToDeduct; break; } } if (!(gHitMarker & (HITMARKER_NO_PPDEDUCT | HITMARKER_NO_ATTACKSTRING)) && gBattleMons[gBattlerAttacker].pp[gCurrMovePos]) { gProtectStructs[gBattlerAttacker].notFirstStrike = 1; if (gBattleMons[gBattlerAttacker].pp[gCurrMovePos] > ppToDeduct) gBattleMons[gBattlerAttacker].pp[gCurrMovePos] -= ppToDeduct; else gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = 0; if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED) && !((gDisableStructs[gBattlerAttacker].mimickedMoves) & gBitTable[gCurrMovePos])) { gActiveBattler = gBattlerAttacker; BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0, 1, &gBattleMons[gBattlerAttacker].pp[gCurrMovePos]); MarkBattlerForControllerExec(gBattlerAttacker); } } gHitMarker &= ~(HITMARKER_NO_PPDEDUCT); ++gBattlescriptCurrInstr; } } void atk04_critcalc(void) { u8 holdEffect; u16 item, critChance; item = gBattleMons[gBattlerAttacker].item; if (item == ITEM_ENIGMA_BERRY) holdEffect = gEnigmaBerries[gBattlerAttacker].holdEffect; else holdEffect = ItemId_GetHoldEffect(item); gPotentialItemEffectBattler = gBattlerAttacker; critChance = 2 * ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) + (gBattleMoves[gCurrentMove].effect == EFFECT_HIGH_CRITICAL) + (gBattleMoves[gCurrentMove].effect == EFFECT_SKY_ATTACK) + (gBattleMoves[gCurrentMove].effect == EFFECT_BLAZE_KICK) + (gBattleMoves[gCurrentMove].effect == EFFECT_POISON_TAIL) + (holdEffect == HOLD_EFFECT_SCOPE_LENS) + 2 * (holdEffect == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY) + 2 * (holdEffect == HOLD_EFFECT_STICK && gBattleMons[gBattlerAttacker].species == SPECIES_FARFETCHD); if (critChance >= NELEMS(sCriticalHitChance)) critChance = NELEMS(sCriticalHitChance) - 1; if ((gBattleMons[gBattlerTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBattlerTarget].ability != ABILITY_SHELL_ARMOR) && !(gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT) && !(gBattleTypeFlags & BATTLE_TYPE_OLDMAN_TUTORIAL) && !(Random() % sCriticalHitChance[critChance]) && (!(gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) || sub_80EB2E0(1)) && !(gBattleTypeFlags & BATTLE_TYPE_POKEDUDE)) gCritMultiplier = 2; else gCritMultiplier = 1; ++gBattlescriptCurrInstr; } void atk05_damagecalc(void) { u16 sideStatus = gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)]; gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerTarget], gCurrentMove, sideStatus, gDynamicBasePower, gBattleStruct->dynamicMoveType, gBattlerAttacker, gBattlerTarget); gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier; if (gStatuses3[gBattlerAttacker] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) gBattleMoveDamage *= 2; if (gProtectStructs[gBattlerAttacker].helpingHand) gBattleMoveDamage = gBattleMoveDamage * 15 / 10; ++gBattlescriptCurrInstr; } void AI_CalcDmg(u8 attacker, u8 defender) { u16 sideStatus = gSideStatuses[GET_BATTLER_SIDE(defender)]; gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[attacker], &gBattleMons[defender], gCurrentMove, sideStatus, gDynamicBasePower, gBattleStruct->dynamicMoveType, attacker, defender); gDynamicBasePower = 0; gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier; if (gStatuses3[attacker] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) gBattleMoveDamage *= 2; if (gProtectStructs[attacker].helpingHand) gBattleMoveDamage = gBattleMoveDamage * 15 / 10; } void ModulateDmgByType(u8 multiplier) { gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; if (gBattleMoveDamage == 0 && multiplier) gBattleMoveDamage = 1; switch (multiplier) { case TYPE_MUL_NO_EFFECT: gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE; gMoveResultFlags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE; gMoveResultFlags &= ~MOVE_RESULT_SUPER_EFFECTIVE; break; case TYPE_MUL_NOT_EFFECTIVE: if (gBattleMoves[gCurrentMove].power && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) { if (gMoveResultFlags & MOVE_RESULT_SUPER_EFFECTIVE) gMoveResultFlags &= ~MOVE_RESULT_SUPER_EFFECTIVE; else gMoveResultFlags |= MOVE_RESULT_NOT_VERY_EFFECTIVE; } break; case TYPE_MUL_SUPER_EFFECTIVE: if (gBattleMoves[gCurrentMove].power && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) { if (gMoveResultFlags & MOVE_RESULT_NOT_VERY_EFFECTIVE) gMoveResultFlags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE; else gMoveResultFlags |= MOVE_RESULT_SUPER_EFFECTIVE; } break; } } void atk06_typecalc(void) { s32 i = 0; u8 moveType; if (gCurrentMove == MOVE_STRUGGLE) { ++gBattlescriptCurrInstr; return; } GET_MOVE_TYPE(gCurrentMove, moveType); // check stab if (IS_BATTLER_OF_TYPE(gBattlerAttacker, moveType)) { gBattleMoveDamage = gBattleMoveDamage * 15; gBattleMoveDamage = gBattleMoveDamage / 10; } if (gBattleMons[gBattlerTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) { gLastUsedAbility = gBattleMons[gBattlerTarget].ability; gMoveResultFlags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE); gLastLandedMoves[gBattlerTarget] = 0; gLastHitByType[gBattlerTarget] = 0; gBattleCommunication[6] = moveType; RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); } else { while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE) { if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT) { if (gBattleMons[gBattlerTarget].status2 & STATUS2_FORESIGHT) break; i += 3; continue; } else if (TYPE_EFFECT_ATK_TYPE(i) == moveType) { // check type1 if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type1) ModulateDmgByType(TYPE_EFFECT_MULTIPLIER(i)); // check type2 if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2 && gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2) ModulateDmgByType(TYPE_EFFECT_MULTIPLIER(i)); } i += 3; } } if (gBattleMons[gBattlerTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBattlerAttacker, gCurrentMove) == 2 && (!(gMoveResultFlags & MOVE_RESULT_SUPER_EFFECTIVE) || ((gMoveResultFlags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE))) && gBattleMoves[gCurrentMove].power) { gLastUsedAbility = ABILITY_WONDER_GUARD; gMoveResultFlags |= MOVE_RESULT_MISSED; gLastLandedMoves[gBattlerTarget] = 0; gLastHitByType[gBattlerTarget] = 0; gBattleCommunication[6] = 3; RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); } if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) gProtectStructs[gBattlerAttacker].targetNotAffected = 1; ++gBattlescriptCurrInstr; } void CheckWonderGuardAndLevitate(void) { u8 flags = 0; s32 i = 0; u8 moveType; if (gCurrentMove == MOVE_STRUGGLE || !gBattleMoves[gCurrentMove].power) return; GET_MOVE_TYPE(gCurrentMove, moveType); if (gBattleMons[gBattlerTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) { gLastUsedAbility = ABILITY_LEVITATE; gBattleCommunication[6] = moveType; RecordAbilityBattle(gBattlerTarget, ABILITY_LEVITATE); return; } while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE) { if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT) { if (gBattleMons[gBattlerTarget].status2 & STATUS2_FORESIGHT) break; i += 3; continue; } if (TYPE_EFFECT_ATK_TYPE(i) == moveType) { // check no effect if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type1 && TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_NO_EFFECT) { gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE; gProtectStructs[gBattlerAttacker].targetNotAffected = 1; } if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2 && gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2 && TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_NO_EFFECT) { gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE; gProtectStructs[gBattlerAttacker].targetNotAffected = 1; } // check super effective if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type1 && TYPE_EFFECT_MULTIPLIER(i) == 20) flags |= 1; if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2 && gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2 && TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_SUPER_EFFECTIVE) flags |= 1; // check not very effective if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type1 && TYPE_EFFECT_MULTIPLIER(i) == 5) flags |= 2; if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2 && gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2 && TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_NOT_EFFECTIVE) flags |= 2; } i += 3; } if (gBattleMons[gBattlerTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBattlerAttacker, gCurrentMove) == 2) { if (((flags & 2) || !(flags & 1)) && gBattleMoves[gCurrentMove].power) { gLastUsedAbility = ABILITY_WONDER_GUARD; gBattleCommunication[6] = 3; RecordAbilityBattle(gBattlerTarget, ABILITY_WONDER_GUARD); } } } // same as ModulateDmgByType except different arguments void ModulateDmgByType2(u8 multiplier, u16 move, u8 *flags) { gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; if (gBattleMoveDamage == 0 && multiplier != 0) gBattleMoveDamage = 1; switch (multiplier) { case TYPE_MUL_NO_EFFECT: *flags |= MOVE_RESULT_DOESNT_AFFECT_FOE; *flags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE; *flags &= ~MOVE_RESULT_SUPER_EFFECTIVE; break; case TYPE_MUL_NOT_EFFECTIVE: if (gBattleMoves[move].power && !(*flags & MOVE_RESULT_NO_EFFECT)) { if (*flags & MOVE_RESULT_SUPER_EFFECTIVE) *flags &= ~MOVE_RESULT_SUPER_EFFECTIVE; else *flags |= MOVE_RESULT_NOT_VERY_EFFECTIVE; } break; case TYPE_MUL_SUPER_EFFECTIVE: if (gBattleMoves[move].power && !(*flags & MOVE_RESULT_NO_EFFECT)) { if (*flags & MOVE_RESULT_NOT_VERY_EFFECTIVE) *flags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE; else *flags |= MOVE_RESULT_SUPER_EFFECTIVE; } break; } } u8 TypeCalc(u16 move, u8 attacker, u8 defender) { s32 i = 0; u8 flags = 0; u8 moveType; if (move == MOVE_STRUGGLE) return 0; moveType = gBattleMoves[move].type; // check stab if (IS_BATTLER_OF_TYPE(attacker, moveType)) { gBattleMoveDamage = gBattleMoveDamage * 15; gBattleMoveDamage = gBattleMoveDamage / 10; } if (gBattleMons[defender].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) { flags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE); } else { while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE) { if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT) { if (gBattleMons[defender].status2 & STATUS2_FORESIGHT) break; i += 3; continue; } else if (TYPE_EFFECT_ATK_TYPE(i) == moveType) { // check type1 if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[defender].type1) ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags); // check type2 if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[defender].type2 && gBattleMons[defender].type1 != gBattleMons[defender].type2) ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags); } i += 3; } } if (gBattleMons[defender].ability == ABILITY_WONDER_GUARD && !(flags & MOVE_RESULT_MISSED) && AttacksThisTurn(attacker, move) == 2 && (!(flags & MOVE_RESULT_SUPER_EFFECTIVE) || ((flags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE))) && gBattleMoves[move].power) flags |= MOVE_RESULT_MISSED; return flags; } u8 AI_TypeCalc(u16 move, u16 targetSpecies, u8 targetAbility) { s32 i = 0; u8 flags = 0; u8 type1 = gBaseStats[targetSpecies].type1, type2 = gBaseStats[targetSpecies].type2; u8 moveType; if (move == MOVE_STRUGGLE) return 0; moveType = gBattleMoves[move].type; if (targetAbility == ABILITY_LEVITATE && moveType == TYPE_GROUND) { flags = MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE; } else { while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE) { if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT) { i += 3; continue; } if (TYPE_EFFECT_ATK_TYPE(i) == moveType) { // check type1 if (TYPE_EFFECT_DEF_TYPE(i) == type1) ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags); // check type2 if (TYPE_EFFECT_DEF_TYPE(i) == type2 && type1 != type2) ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags); } i += 3; } } if (targetAbility == ABILITY_WONDER_GUARD && (!(flags & MOVE_RESULT_SUPER_EFFECTIVE) || ((flags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE))) && gBattleMoves[move].power) flags |= MOVE_RESULT_DOESNT_AFFECT_FOE; return flags; } static inline void ApplyRandomDmgMultiplier(void) { u16 rand = Random(); u16 randPercent = 100 - (rand % 16); if (gBattleMoveDamage != 0) { gBattleMoveDamage *= randPercent; gBattleMoveDamage /= 100; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; } } void Unused_ApplyRandomDmgMultiplier(void) { ApplyRandomDmgMultiplier(); } void atk07_adjustnormaldamage(void) { u8 holdEffect, param; ApplyRandomDmgMultiplier(); if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY) { holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect; param = gEnigmaBerries[gBattlerTarget].holdEffectParam; } else { holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item); param = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item); } gPotentialItemEffectBattler = gBattlerTarget; if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param) { RecordItemEffectBattle(gBattlerTarget, holdEffect); gSpecialStatuses[gBattlerTarget].focusBanded = 1; } if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE) && (gBattleMoves[gCurrentMove].effect == EFFECT_FALSE_SWIPE || gProtectStructs[gBattlerTarget].endured || gSpecialStatuses[gBattlerTarget].focusBanded) && gBattleMons[gBattlerTarget].hp <= gBattleMoveDamage) { gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - 1; if (gProtectStructs[gBattlerTarget].endured) { gMoveResultFlags |= MOVE_RESULT_FOE_ENDURED; } else if (gSpecialStatuses[gBattlerTarget].focusBanded) { gMoveResultFlags |= MOVE_RESULT_FOE_HUNG_ON; gLastUsedItem = gBattleMons[gBattlerTarget].item; } } ++gBattlescriptCurrInstr; } // The same as 0x7 except it doesn't check for false swipe move effect. void atk08_adjustnormaldamage2(void) { u8 holdEffect, param; ApplyRandomDmgMultiplier(); if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY) { holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect; param = gEnigmaBerries[gBattlerTarget].holdEffectParam; } else { holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item); param = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item); } gPotentialItemEffectBattler = gBattlerTarget; if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param) { RecordItemEffectBattle(gBattlerTarget, holdEffect); gSpecialStatuses[gBattlerTarget].focusBanded = 1; } if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE) && (gProtectStructs[gBattlerTarget].endured || gSpecialStatuses[gBattlerTarget].focusBanded) && gBattleMons[gBattlerTarget].hp <= gBattleMoveDamage) { gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - 1; if (gProtectStructs[gBattlerTarget].endured) { gMoveResultFlags |= MOVE_RESULT_FOE_ENDURED; } else if (gSpecialStatuses[gBattlerTarget].focusBanded) { gMoveResultFlags |= MOVE_RESULT_FOE_HUNG_ON; gLastUsedItem = gBattleMons[gBattlerTarget].item; } } ++gBattlescriptCurrInstr; } void atk09_attackanimation(void) { if (!gBattleControllerExecFlags) { if ((gHitMarker & HITMARKER_NO_ANIMATIONS) && (gCurrentMove != MOVE_TRANSFORM && gCurrentMove != MOVE_SUBSTITUTE)) { BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_Pausex20; ++gBattleScripting.animTurn; ++gBattleScripting.animTargetsHit; } else { if ((gBattleMoves[gCurrentMove].target & MOVE_TARGET_BOTH || gBattleMoves[gCurrentMove].target & MOVE_TARGET_FOES_AND_ALLY || gBattleMoves[gCurrentMove].target & MOVE_TARGET_DEPENDS) && gBattleScripting.animTargetsHit) { ++gBattlescriptCurrInstr; return; } if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) { gActiveBattler = gBattlerAttacker; BtlController_EmitMoveAnimation(0, gCurrentMove, gBattleScripting.animTurn, gBattleMovePower, gBattleMoveDamage, gBattleMons[gBattlerAttacker].friendship, &gDisableStructs[gBattlerAttacker]); ++gBattleScripting.animTurn; ++gBattleScripting.animTargetsHit; MarkBattlerForControllerExec(gBattlerAttacker); ++gBattlescriptCurrInstr; } else { BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_Pausex20; } } } } void atk0A_waitanimation(void) { if (!gBattleControllerExecFlags) ++gBattlescriptCurrInstr; } void atk0B_healthbarupdate(void) { if (!gBattleControllerExecFlags) { if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) { gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); if (gBattleMons[gActiveBattler].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBattler].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) { PrepareStringBattle(STRINGID_SUBSTITUTEDAMAGED, gActiveBattler); } else { s16 healthValue; s32 currDmg = gBattleMoveDamage; s32 maxPossibleDmgValue = 10000; // not present in R/S, ensures that huge damage values don't change sign if (currDmg <= maxPossibleDmgValue) healthValue = currDmg; else healthValue = maxPossibleDmgValue; BtlController_EmitHealthBarUpdate(0, healthValue); MarkBattlerForControllerExec(gActiveBattler); if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER && gBattleMoveDamage > 0) gBattleResults.playerMonWasDamaged = TRUE; } } gBattlescriptCurrInstr += 2; } } void atk0C_datahpupdate(void) { u32 moveType; if (!gBattleControllerExecFlags) { if (gBattleStruct->dynamicMoveType == 0) moveType = gBattleMoves[gCurrentMove].type; else if (!(gBattleStruct->dynamicMoveType & 0x40)) moveType = gBattleStruct->dynamicMoveType & 0x3F; else moveType = gBattleMoves[gCurrentMove].type; if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) { gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); if (gBattleMons[gActiveBattler].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBattler].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) { if (gDisableStructs[gActiveBattler].substituteHP >= gBattleMoveDamage) { if (gSpecialStatuses[gActiveBattler].dmg == 0) gSpecialStatuses[gActiveBattler].dmg = gBattleMoveDamage; gDisableStructs[gActiveBattler].substituteHP -= gBattleMoveDamage; gHpDealt = gBattleMoveDamage; } else { if (gSpecialStatuses[gActiveBattler].dmg == 0) gSpecialStatuses[gActiveBattler].dmg = gDisableStructs[gActiveBattler].substituteHP; gHpDealt = gDisableStructs[gActiveBattler].substituteHP; gDisableStructs[gActiveBattler].substituteHP = 0; } // check substitute fading if (gDisableStructs[gActiveBattler].substituteHP == 0) { gBattlescriptCurrInstr += 2; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_SubstituteFade; return; } } else { gHitMarker &= ~(HITMARKER_IGNORE_SUBSTITUTE); if (gBattleMoveDamage < 0) // hp goes up { gBattleMons[gActiveBattler].hp -= gBattleMoveDamage; if (gBattleMons[gActiveBattler].hp > gBattleMons[gActiveBattler].maxHP) gBattleMons[gActiveBattler].hp = gBattleMons[gActiveBattler].maxHP; } else // hp goes down { if (gHitMarker & HITMARKER_x20) { gHitMarker &= ~(HITMARKER_x20); } else { gTakenDmg[gActiveBattler] += gBattleMoveDamage; if (gBattlescriptCurrInstr[1] == BS_TARGET) gTakenDmgByBattler[gActiveBattler] = gBattlerAttacker; else gTakenDmgByBattler[gActiveBattler] = gBattlerTarget; } if (gBattleMons[gActiveBattler].hp > gBattleMoveDamage) { gBattleMons[gActiveBattler].hp -= gBattleMoveDamage; gHpDealt = gBattleMoveDamage; } else { gHpDealt = gBattleMons[gActiveBattler].hp; gBattleMons[gActiveBattler].hp = 0; } if (!gSpecialStatuses[gActiveBattler].dmg && !(gHitMarker & HITMARKER_x100000)) gSpecialStatuses[gActiveBattler].dmg = gHpDealt; if (IS_TYPE_PHYSICAL(moveType) && !(gHitMarker & HITMARKER_x100000) && gCurrentMove != MOVE_PAIN_SPLIT) { gProtectStructs[gActiveBattler].physicalDmg = gHpDealt; gSpecialStatuses[gActiveBattler].physicalDmg = gHpDealt; if (gBattlescriptCurrInstr[1] == BS_TARGET) { gProtectStructs[gActiveBattler].physicalBattlerId = gBattlerAttacker; gSpecialStatuses[gActiveBattler].physicalBattlerId = gBattlerAttacker; } else { gProtectStructs[gActiveBattler].physicalBattlerId = gBattlerTarget; gSpecialStatuses[gActiveBattler].physicalBattlerId = gBattlerTarget; } } else if (!IS_TYPE_PHYSICAL(moveType) && !(gHitMarker & HITMARKER_x100000)) { gProtectStructs[gActiveBattler].specialDmg = gHpDealt; gSpecialStatuses[gActiveBattler].specialDmg = gHpDealt; if (gBattlescriptCurrInstr[1] == BS_TARGET) { gProtectStructs[gActiveBattler].specialBattlerId = gBattlerAttacker; gSpecialStatuses[gActiveBattler].specialBattlerId = gBattlerAttacker; } else { gProtectStructs[gActiveBattler].specialBattlerId = gBattlerTarget; gSpecialStatuses[gActiveBattler].specialBattlerId = gBattlerTarget; } } } gHitMarker &= ~(HITMARKER_x100000); BtlController_EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBattler].hp); MarkBattlerForControllerExec(gActiveBattler); } } else { gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); if (gSpecialStatuses[gActiveBattler].dmg == 0) gSpecialStatuses[gActiveBattler].dmg = 0xFFFF; } gBattlescriptCurrInstr += 2; } } void atk0D_critmessage(void) { if (!gBattleControllerExecFlags) { if (gCritMultiplier == 2 && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) { PrepareStringBattle(STRINGID_CRITICALHIT, gBattlerAttacker); gBattleCommunication[MSG_DISPLAY] = 1; } ++gBattlescriptCurrInstr; } } void atk0E_effectivenesssound(void) { if (!gBattleControllerExecFlags) { gActiveBattler = gBattlerTarget; if (!(gMoveResultFlags & MOVE_RESULT_MISSED)) { switch (gMoveResultFlags & (u8)(~(MOVE_RESULT_MISSED))) { case MOVE_RESULT_SUPER_EFFECTIVE: BtlController_EmitPlaySE(0, SE_KOUKA_H); MarkBattlerForControllerExec(gActiveBattler); break; case MOVE_RESULT_NOT_VERY_EFFECTIVE: BtlController_EmitPlaySE(0, SE_KOUKA_L); MarkBattlerForControllerExec(gActiveBattler); break; case MOVE_RESULT_DOESNT_AFFECT_FOE: case MOVE_RESULT_FAILED: // no sound break; case MOVE_RESULT_FOE_ENDURED: case MOVE_RESULT_ONE_HIT_KO: case MOVE_RESULT_FOE_HUNG_ON: default: if (gMoveResultFlags & MOVE_RESULT_SUPER_EFFECTIVE) { BtlController_EmitPlaySE(0, SE_KOUKA_H); MarkBattlerForControllerExec(gActiveBattler); } else if (gMoveResultFlags & MOVE_RESULT_NOT_VERY_EFFECTIVE) { BtlController_EmitPlaySE(0, SE_KOUKA_L); MarkBattlerForControllerExec(gActiveBattler); } else if (!(gMoveResultFlags & (MOVE_RESULT_DOESNT_AFFECT_FOE | MOVE_RESULT_FAILED))) { BtlController_EmitPlaySE(0, SE_KOUKA_M); MarkBattlerForControllerExec(gActiveBattler); } break; } } ++gBattlescriptCurrInstr; } } void atk0F_resultmessage(void) { u32 stringId = 0; if (!gBattleControllerExecFlags) { if (gMoveResultFlags & MOVE_RESULT_MISSED && (!(gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) || gBattleCommunication[6] > 2)) { stringId = gMissStringIds[gBattleCommunication[6]]; gBattleCommunication[MSG_DISPLAY] = 1; } else { gBattleCommunication[MSG_DISPLAY] = 1; switch (gMoveResultFlags & (u8)(~(MOVE_RESULT_MISSED))) { case MOVE_RESULT_SUPER_EFFECTIVE: stringId = STRINGID_SUPEREFFECTIVE; break; case MOVE_RESULT_NOT_VERY_EFFECTIVE: stringId = STRINGID_NOTVERYEFFECTIVE; break; case MOVE_RESULT_ONE_HIT_KO: stringId = STRINGID_ONEHITKO; break; case MOVE_RESULT_FOE_ENDURED: stringId = STRINGID_PKMNENDUREDHIT; break; case MOVE_RESULT_FAILED: stringId = STRINGID_BUTITFAILED; break; case MOVE_RESULT_DOESNT_AFFECT_FOE: stringId = STRINGID_ITDOESNTAFFECT; break; case MOVE_RESULT_FOE_HUNG_ON: gLastUsedItem = gBattleMons[gBattlerTarget].item; gPotentialItemEffectBattler = gBattlerTarget; gMoveResultFlags &= ~(MOVE_RESULT_FOE_ENDURED | MOVE_RESULT_FOE_HUNG_ON); BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_HangedOnMsg; return; default: if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) { stringId = STRINGID_ITDOESNTAFFECT; } else if (gMoveResultFlags & MOVE_RESULT_ONE_HIT_KO) { gMoveResultFlags &= ~(MOVE_RESULT_ONE_HIT_KO); gMoveResultFlags &= ~(MOVE_RESULT_SUPER_EFFECTIVE); gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE); BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_OneHitKOMsg; return; } else if (gMoveResultFlags & MOVE_RESULT_FOE_ENDURED) { gMoveResultFlags &= ~(MOVE_RESULT_FOE_ENDURED | MOVE_RESULT_FOE_HUNG_ON); BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_EnduredMsg; return; } else if (gMoveResultFlags & MOVE_RESULT_FOE_HUNG_ON) { gLastUsedItem = gBattleMons[gBattlerTarget].item; gPotentialItemEffectBattler = gBattlerTarget; gMoveResultFlags &= ~(MOVE_RESULT_FOE_ENDURED | MOVE_RESULT_FOE_HUNG_ON); BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_HangedOnMsg; return; } else if (gMoveResultFlags & MOVE_RESULT_FAILED) { stringId = STRINGID_BUTITFAILED; } else { gBattleCommunication[MSG_DISPLAY] = 0; } } } if (stringId) PrepareStringBattle(stringId, gBattlerAttacker); ++gBattlescriptCurrInstr; } } void atk10_printstring(void) { if (!gBattleControllerExecFlags) { u16 var = T2_READ_16(gBattlescriptCurrInstr + 1); PrepareStringBattle(var, gBattlerAttacker); gBattlescriptCurrInstr += 3; gBattleCommunication[MSG_DISPLAY] = 1; } } void atk11_printselectionstring(void) { gActiveBattler = gBattlerAttacker; BtlController_EmitPrintSelectionString(0, T2_READ_16(gBattlescriptCurrInstr + 1)); MarkBattlerForControllerExec(gActiveBattler); gBattlescriptCurrInstr += 3; gBattleCommunication[MSG_DISPLAY] = 1; } void atk12_waitmessage(void) { if (!gBattleControllerExecFlags) { if (!gBattleCommunication[MSG_DISPLAY]) { gBattlescriptCurrInstr += 3; } else { u16 toWait = T2_READ_16(gBattlescriptCurrInstr + 1); if (++gPauseCounterBattle >= toWait) { gPauseCounterBattle = 0; gBattlescriptCurrInstr += 3; gBattleCommunication[MSG_DISPLAY] = 0; } } } } void atk13_printfromtable(void) { if (!gBattleControllerExecFlags) { const u16 *ptr = (const u16 *) T1_READ_PTR(gBattlescriptCurrInstr + 1); ptr += gBattleCommunication[MULTISTRING_CHOOSER]; PrepareStringBattle(*ptr, gBattlerAttacker); gBattlescriptCurrInstr += 5; gBattleCommunication[MSG_DISPLAY] = 1; } } void atk14_printselectionstringfromtable(void) { if (!gBattleControllerExecFlags) { const u16 *ptr = (const u16 *) T1_READ_PTR(gBattlescriptCurrInstr + 1); ptr += gBattleCommunication[MULTISTRING_CHOOSER]; gActiveBattler = gBattlerAttacker; BtlController_EmitPrintSelectionString(0, *ptr); MarkBattlerForControllerExec(gActiveBattler); gBattlescriptCurrInstr += 5; gBattleCommunication[MSG_DISPLAY] = 1; } } u8 GetBattlerTurnOrderNum(u8 battlerId) { s32 i; for (i = 0; i < gBattlersCount && gBattlerByTurnOrder[i] != battlerId; ++i); return i; } void SetMoveEffect(bool8 primary, u8 certain) { bool32 statusChanged = FALSE; u8 affectsUser = 0; // 0x40 otherwise bool32 noSunCanFreeze = TRUE; if (gBattleCommunication[MOVE_EFFECT_BYTE] & MOVE_EFFECT_AFFECTS_USER) { gEffectBattler = gBattlerAttacker; // battlerId that effects get applied on gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_AFFECTS_USER); affectsUser = MOVE_EFFECT_AFFECTS_USER; gBattleScripting.battler = gBattlerTarget; // theoretically the attacker } else { gEffectBattler = gBattlerTarget; gBattleScripting.battler = gBattlerAttacker; } if (gBattleTypeFlags & BATTLE_TYPE_POKEDUDE && gBattleCommunication[MOVE_EFFECT_BYTE] != 1 && GetBattlerSide(gEffectBattler) == B_SIDE_OPPONENT) { ++gBattlescriptCurrInstr; return; } if (gBattleMons[gEffectBattler].ability == ABILITY_SHIELD_DUST && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) && !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 9) { ++gBattlescriptCurrInstr; return; } if (gSideStatuses[GET_BATTLER_SIDE(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) && !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 7) { ++gBattlescriptCurrInstr; return; } if (gBattleMons[gEffectBattler].hp == 0 && gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_PAYDAY && gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_STEAL_ITEM) { ++gBattlescriptCurrInstr; return; } if (gBattleMons[gEffectBattler].status2 & STATUS2_SUBSTITUTE && affectsUser != MOVE_EFFECT_AFFECTS_USER) { ++gBattlescriptCurrInstr; return; } if (gBattleCommunication[MOVE_EFFECT_BYTE] <= 6) // status change { switch (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) { case STATUS1_SLEEP: // check active uproar if (gBattleMons[gEffectBattler].ability != ABILITY_SOUNDPROOF) for (gActiveBattler = 0; gActiveBattler < gBattlersCount && !(gBattleMons[gActiveBattler].status2 & STATUS2_UPROAR); ++gActiveBattler); else gActiveBattler = gBattlersCount; if (gBattleMons[gEffectBattler].status1) break; if (gActiveBattler != gBattlersCount) break; if (gBattleMons[gEffectBattler].ability == ABILITY_VITAL_SPIRIT) break; if (gBattleMons[gEffectBattler].ability == ABILITY_INSOMNIA) break; CancelMultiTurnMoves(gEffectBattler); statusChanged = TRUE; break; case STATUS1_POISON: if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { gLastUsedAbility = ABILITY_IMMUNITY; RecordAbilityBattle(gEffectBattler, ABILITY_IMMUNITY); BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_PSNPrevention; if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) { gBattleCommunication[MULTISTRING_CHOOSER] = 1; gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); } else { gBattleCommunication[MULTISTRING_CHOOSER] = 0; } return; } if ((IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_POISON) || IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_STEEL)) && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_PSNPrevention; gBattleCommunication[MULTISTRING_CHOOSER] = 2; return; } if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_POISON)) break; if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_STEEL)) break; if (gBattleMons[gEffectBattler].status1) break; if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY) break; statusChanged = TRUE; break; case STATUS1_BURN: if (gBattleMons[gEffectBattler].ability == ABILITY_WATER_VEIL && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { gLastUsedAbility = ABILITY_WATER_VEIL; RecordAbilityBattle(gEffectBattler, ABILITY_WATER_VEIL); BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_BRNPrevention; if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) { gBattleCommunication[MULTISTRING_CHOOSER] = 1; gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); } else { gBattleCommunication[MULTISTRING_CHOOSER] = 0; } return; } if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_FIRE) && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_BRNPrevention; gBattleCommunication[MULTISTRING_CHOOSER] = 2; return; } if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_FIRE)) break; if (gBattleMons[gEffectBattler].ability == ABILITY_WATER_VEIL) break; if (gBattleMons[gEffectBattler].status1) break; statusChanged = TRUE; break; case STATUS1_FREEZE: if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY) noSunCanFreeze = FALSE; if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_ICE)) break; if (gBattleMons[gEffectBattler].status1) break; if (noSunCanFreeze == 0) break; if (gBattleMons[gEffectBattler].ability == ABILITY_MAGMA_ARMOR) break; CancelMultiTurnMoves(gEffectBattler); statusChanged = TRUE; break; case STATUS1_PARALYSIS: if (gBattleMons[gEffectBattler].ability == ABILITY_LIMBER) { if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) { gLastUsedAbility = ABILITY_LIMBER; RecordAbilityBattle(gEffectBattler, ABILITY_LIMBER); BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_PRLZPrevention; if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) { gBattleCommunication[MULTISTRING_CHOOSER] = 1; gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); } else { gBattleCommunication[MULTISTRING_CHOOSER] = 0; } return; } else break; } if (gBattleMons[gEffectBattler].status1) break; statusChanged = TRUE; break; case STATUS1_TOXIC_POISON: if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { gLastUsedAbility = ABILITY_IMMUNITY; RecordAbilityBattle(gEffectBattler, ABILITY_IMMUNITY); BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_PSNPrevention; if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) { gBattleCommunication[MULTISTRING_CHOOSER] = 1; gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); } else { gBattleCommunication[MULTISTRING_CHOOSER] = 0; } return; } if ((IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_POISON) || IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_STEEL)) && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_PSNPrevention; gBattleCommunication[MULTISTRING_CHOOSER] = 2; return; } if (gBattleMons[gEffectBattler].status1) break; if (!IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_POISON) && !IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_STEEL)) { if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY) break; // It's redundant, because at this point we know the status1 value is 0. gBattleMons[gEffectBattler].status1 &= ~(STATUS1_TOXIC_POISON); gBattleMons[gEffectBattler].status1 &= ~(STATUS1_POISON); statusChanged = TRUE; break; } else { gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE; } break; } if (statusChanged == TRUE) { BattleScriptPush(gBattlescriptCurrInstr + 1); if (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]] == STATUS1_SLEEP) gBattleMons[gEffectBattler].status1 |= ((Random() & 3) + 2); else gBattleMons[gEffectBattler].status1 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; gActiveBattler = gEffectBattler; BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBattler].status1); MarkBattlerForControllerExec(gActiveBattler); if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) { gBattleCommunication[MULTISTRING_CHOOSER] = 1; gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); } else { gBattleCommunication[MULTISTRING_CHOOSER] = 0; } // for synchronize if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_POISON || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_TOXIC || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_PARALYSIS || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN) { u8 *synchronizeEffect = &gBattleStruct->synchronizeMoveEffect; *synchronizeEffect = gBattleCommunication[MOVE_EFFECT_BYTE]; gHitMarker |= HITMARKER_SYNCHRONISE_EFFECT; } return; } else if (statusChanged == FALSE) { ++gBattlescriptCurrInstr; return; } return; } else { if (gBattleMons[gEffectBattler].status2 & sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) { ++gBattlescriptCurrInstr; } else { u8 side; switch (gBattleCommunication[MOVE_EFFECT_BYTE]) { case MOVE_EFFECT_CONFUSION: if (gBattleMons[gEffectBattler].ability == ABILITY_OWN_TEMPO || gBattleMons[gEffectBattler].status2 & STATUS2_CONFUSION) { ++gBattlescriptCurrInstr; } else { gBattleMons[gEffectBattler].status2 |= (((Random()) % 0x4)) + 2; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; } break; case MOVE_EFFECT_FLINCH: if (gBattleMons[gEffectBattler].ability == ABILITY_INNER_FOCUS) { if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) { gLastUsedAbility = ABILITY_INNER_FOCUS; RecordAbilityBattle(gEffectBattler, ABILITY_INNER_FOCUS); gBattlescriptCurrInstr = BattleScript_FlinchPrevention; } else { ++gBattlescriptCurrInstr; } } else { if (GetBattlerTurnOrderNum(gEffectBattler) > gCurrentTurnActionNumber) gBattleMons[gEffectBattler].status2 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; ++gBattlescriptCurrInstr; } break; case MOVE_EFFECT_UPROAR: if (!(gBattleMons[gEffectBattler].status2 & STATUS2_UPROAR)) { gBattleMons[gEffectBattler].status2 |= STATUS2_MULTIPLETURNS; gLockedMoves[gEffectBattler] = gCurrentMove; gBattleMons[gEffectBattler].status2 |= ((Random() & 3) + 2) << 4; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; } else { ++gBattlescriptCurrInstr; } break; case MOVE_EFFECT_PAYDAY: if (GET_BATTLER_SIDE(gBattlerAttacker) == B_SIDE_PLAYER) { u16 PayDay = gPaydayMoney; gPaydayMoney += (gBattleMons[gBattlerAttacker].level * 5); if (PayDay > gPaydayMoney) gPaydayMoney = 0xFFFF; } BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; break; case MOVE_EFFECT_TRI_ATTACK: if (gBattleMons[gEffectBattler].status1) { ++gBattlescriptCurrInstr; } else { gBattleCommunication[MOVE_EFFECT_BYTE] = Random() % 3 + 3; SetMoveEffect(FALSE, 0); } break; case MOVE_EFFECT_CHARGING: gBattleMons[gEffectBattler].status2 |= STATUS2_MULTIPLETURNS; gLockedMoves[gEffectBattler] = gCurrentMove; gProtectStructs[gEffectBattler].chargingTurn = 1; ++gBattlescriptCurrInstr; break; case MOVE_EFFECT_WRAP: if (gBattleMons[gEffectBattler].status2 & STATUS2_WRAPPED) { ++gBattlescriptCurrInstr; } else { gBattleMons[gEffectBattler].status2 |= ((Random() & 3) + 3) << 0xD; *(gBattleStruct->wrappedMove + gEffectBattler * 2 + 0) = gCurrentMove; *(gBattleStruct->wrappedMove + gEffectBattler * 2 + 1) = gCurrentMove >> 8; *(gBattleStruct->wrappedBy + gEffectBattler) = gBattlerAttacker; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; ++gBattleCommunication[MULTISTRING_CHOOSER]) { if (gBattleCommunication[MULTISTRING_CHOOSER] > 4) break; if (gTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove) break; } } break; case MOVE_EFFECT_RECOIL_25: // 25% recoil gBattleMoveDamage = (gHpDealt) / 4; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; break; case MOVE_EFFECT_ATK_PLUS_1: case MOVE_EFFECT_DEF_PLUS_1: case MOVE_EFFECT_SPD_PLUS_1: case MOVE_EFFECT_SP_ATK_PLUS_1: case MOVE_EFFECT_SP_DEF_PLUS_1: case MOVE_EFFECT_ACC_PLUS_1: case MOVE_EFFECT_EVS_PLUS_1: if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1), gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_1 + 1, affectsUser, NULL)) { ++gBattlescriptCurrInstr; } else { gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); gBattleScripting.animArg2 = 0; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_StatUp; } break; case MOVE_EFFECT_ATK_MINUS_1: case MOVE_EFFECT_DEF_MINUS_1: case MOVE_EFFECT_SPD_MINUS_1: case MOVE_EFFECT_SP_ATK_MINUS_1: case MOVE_EFFECT_SP_DEF_MINUS_1: case MOVE_EFFECT_ACC_MINUS_1: case MOVE_EFFECT_EVS_MINUS_1: if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE, gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_MINUS_1 + 1, affectsUser, NULL)) { ++gBattlescriptCurrInstr; } else { gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); gBattleScripting.animArg2 = 0; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_StatDown; } break; case MOVE_EFFECT_ATK_PLUS_2: case MOVE_EFFECT_DEF_PLUS_2: case MOVE_EFFECT_SPD_PLUS_2: case MOVE_EFFECT_SP_ATK_PLUS_2: case MOVE_EFFECT_SP_DEF_PLUS_2: case MOVE_EFFECT_ACC_PLUS_2: case MOVE_EFFECT_EVS_PLUS_2: if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2), gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_2 + 1, affectsUser, NULL)) { ++gBattlescriptCurrInstr; } else { gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); gBattleScripting.animArg2 = 0; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_StatUp; } break; case MOVE_EFFECT_ATK_MINUS_2: case MOVE_EFFECT_DEF_MINUS_2: case MOVE_EFFECT_SPD_MINUS_2: case MOVE_EFFECT_SP_ATK_MINUS_2: case MOVE_EFFECT_SP_DEF_MINUS_2: case MOVE_EFFECT_ACC_MINUS_2: case MOVE_EFFECT_EVS_MINUS_2: if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE, gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_MINUS_2 + 1, affectsUser, NULL)) { ++gBattlescriptCurrInstr; } else { gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); gBattleScripting.animArg2 = 0; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_StatDown; } break; case MOVE_EFFECT_RECHARGE: gBattleMons[gEffectBattler].status2 |= STATUS2_RECHARGE; gDisableStructs[gEffectBattler].rechargeTimer = 2; gLockedMoves[gEffectBattler] = gCurrentMove; ++gBattlescriptCurrInstr; break; case MOVE_EFFECT_RAGE: gBattleMons[gBattlerAttacker].status2 |= STATUS2_RAGE; ++gBattlescriptCurrInstr; break; case MOVE_EFFECT_STEAL_ITEM: { if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER) { ++gBattlescriptCurrInstr; break; } side = GetBattlerSide(gBattlerAttacker); if (GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT && !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_LINK)) && gTrainerBattleOpponent_A != 0x400) { ++gBattlescriptCurrInstr; } else if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_LINK)) && gTrainerBattleOpponent_A != 0x400 && (gWishFutureKnock.knockedOffMons[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]])) { ++gBattlescriptCurrInstr; } else if (gBattleMons[gBattlerTarget].item && gBattleMons[gBattlerTarget].ability == ABILITY_STICKY_HOLD) { gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; gLastUsedAbility = gBattleMons[gBattlerTarget].ability; RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); } else if (gBattleMons[gBattlerAttacker].item != ITEM_NONE || gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY || IS_ITEM_MAIL(gBattleMons[gBattlerTarget].item) || gBattleMons[gBattlerTarget].item == ITEM_NONE) { ++gBattlescriptCurrInstr; } else { u16 *changedItem = &gBattleStruct->changedItems[gBattlerAttacker]; gLastUsedItem = *changedItem = gBattleMons[gBattlerTarget].item; gBattleMons[gBattlerTarget].item = ITEM_NONE; gActiveBattler = gBattlerAttacker; BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); MarkBattlerForControllerExec(gBattlerAttacker); gActiveBattler = gBattlerTarget; BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBattlerTarget].item); MarkBattlerForControllerExec(gBattlerTarget); BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_ItemSteal; *(u8 *)((u8 *)(&gBattleStruct->choicedMove[gBattlerTarget]) + 0) = 0; *(u8 *)((u8 *)(&gBattleStruct->choicedMove[gBattlerTarget]) + 1) = 0; } } break; case MOVE_EFFECT_PREVENT_ESCAPE: gBattleMons[gBattlerTarget].status2 |= STATUS2_ESCAPE_PREVENTION; gDisableStructs[gBattlerTarget].battlerPreventingEscape = gBattlerAttacker; ++gBattlescriptCurrInstr; break; case MOVE_EFFECT_NIGHTMARE: gBattleMons[gBattlerTarget].status2 |= STATUS2_NIGHTMARE; ++gBattlescriptCurrInstr; break; case MOVE_EFFECT_ALL_STATS_UP: BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_AllStatsUp; break; case MOVE_EFFECT_RAPIDSPIN: BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_RapidSpinAway; break; case MOVE_EFFECT_REMOVE_PARALYSIS: // Smelling salts if (!(gBattleMons[gBattlerTarget].status1 & STATUS1_PARALYSIS)) { ++gBattlescriptCurrInstr; } else { gBattleMons[gBattlerTarget].status1 &= ~(STATUS1_PARALYSIS); gActiveBattler = gBattlerTarget; BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1); MarkBattlerForControllerExec(gActiveBattler); BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_TargetPRLZHeal; } break; case MOVE_EFFECT_ATK_DEF_DOWN: // SuperPower BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_AtkDefDown; break; case MOVE_EFFECT_RECOIL_33: // Double Edge gBattleMoveDamage = gHpDealt / 3; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; break; case MOVE_EFFECT_THRASH: if (gBattleMons[gEffectBattler].status2 & STATUS2_LOCK_CONFUSE) { ++gBattlescriptCurrInstr; } else { gBattleMons[gEffectBattler].status2 |= STATUS2_MULTIPLETURNS; gLockedMoves[gEffectBattler] = gCurrentMove; gBattleMons[gEffectBattler].status2 |= (((Random() & 1) + 2) << 0xA); } break; case MOVE_EFFECT_KNOCK_OFF: if (gBattleMons[gEffectBattler].ability == ABILITY_STICKY_HOLD) { if (gBattleMons[gEffectBattler].item == ITEM_NONE) { ++gBattlescriptCurrInstr; } else { gLastUsedAbility = ABILITY_STICKY_HOLD; gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; RecordAbilityBattle(gEffectBattler, ABILITY_STICKY_HOLD); } break; } if (gBattleMons[gEffectBattler].item) { side = GetBattlerSide(gEffectBattler); gLastUsedItem = gBattleMons[gEffectBattler].item; gBattleMons[gEffectBattler].item = ITEM_NONE; gWishFutureKnock.knockedOffMons[side] |= gBitTable[gBattlerPartyIndexes[gEffectBattler]]; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_KnockedOff; *(u8 *)((u8 *)(&gBattleStruct->choicedMove[gEffectBattler]) + 0) = 0; *(u8 *)((u8 *)(&gBattleStruct->choicedMove[gEffectBattler]) + 1) = 0; } else { ++gBattlescriptCurrInstr; } break; case MOVE_EFFECT_SP_ATK_TWO_DOWN: // Overheat BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_SAtkDown2; break; } } } } void atk15_seteffectwithchance(void) { u32 percentChance; if (gBattleMons[gBattlerAttacker].ability == ABILITY_SERENE_GRACE) percentChance = gBattleMoves[gCurrentMove].secondaryEffectChance * 2; else percentChance = gBattleMoves[gCurrentMove].secondaryEffectChance; if (gBattleCommunication[MOVE_EFFECT_BYTE] & MOVE_EFFECT_CERTAIN && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) { gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_CERTAIN); SetMoveEffect(0, MOVE_EFFECT_CERTAIN); } else if (Random() % 100 <= percentChance && gBattleCommunication[MOVE_EFFECT_BYTE] && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) { if (percentChance >= 100) SetMoveEffect(0, MOVE_EFFECT_CERTAIN); else SetMoveEffect(0, 0); } else { ++gBattlescriptCurrInstr; } gBattleCommunication[MOVE_EFFECT_BYTE] = 0; gBattleScripting.multihitMoveEffect = 0; } void atk16_seteffectprimary(void) { SetMoveEffect(TRUE, 0); } void atk17_seteffectsecondary(void) { SetMoveEffect(FALSE, 0); } void atk18_clearstatusfromeffect(void) { gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); if (gBattleCommunication[MOVE_EFFECT_BYTE] <= MOVE_EFFECT_TOXIC) gBattleMons[gActiveBattler].status1 &= (~sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); else gBattleMons[gActiveBattler].status2 &= (~sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); gBattleCommunication[MOVE_EFFECT_BYTE] = 0; gBattlescriptCurrInstr += 2; gBattleScripting.multihitMoveEffect = 0; } void atk19_tryfaintmon(void) { const u8 *BS_ptr; if (gBattlescriptCurrInstr[2] != 0) { gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); if (gHitMarker & HITMARKER_FAINTED(gActiveBattler)) { BS_ptr = T1_READ_PTR(gBattlescriptCurrInstr + 3); BattleScriptPop(); gBattlescriptCurrInstr = BS_ptr; gSideStatuses[GetBattlerSide(gActiveBattler)] &= ~(SIDE_STATUS_SPIKES_DAMAGED); } else { gBattlescriptCurrInstr += 7; } } else { u8 battlerId; if (gBattlescriptCurrInstr[1] == BS_ATTACKER) { gActiveBattler = gBattlerAttacker; battlerId = gBattlerTarget; BS_ptr = BattleScript_FaintAttacker; } else { gActiveBattler = gBattlerTarget; battlerId = gBattlerAttacker; BS_ptr = BattleScript_FaintTarget; } if (!(gAbsentBattlerFlags & gBitTable[gActiveBattler]) && gBattleMons[gActiveBattler].hp == 0) { gHitMarker |= HITMARKER_FAINTED(gActiveBattler); BattleScriptPush(gBattlescriptCurrInstr + 7); gBattlescriptCurrInstr = BS_ptr; if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) { gHitMarker |= HITMARKER_x400000; if (gBattleResults.playerFaintCounter < 0xFF) ++gBattleResults.playerFaintCounter; AdjustFriendshipOnBattleFaint(gActiveBattler); } else { if (gBattleResults.opponentFaintCounter < 0xFF) ++gBattleResults.opponentFaintCounter; gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES); *(u8 *)(&gBattleStruct->field_182) = gBattlerAttacker; } if ((gHitMarker & HITMARKER_DESTINYBOND) && gBattleMons[gBattlerAttacker].hp != 0) { gHitMarker &= ~(HITMARKER_DESTINYBOND); BattleScriptPush(gBattlescriptCurrInstr); gBattleMoveDamage = gBattleMons[battlerId].hp; gBattlescriptCurrInstr = BattleScript_DestinyBondTakesLife; } if ((gStatuses3[gBattlerTarget] & STATUS3_GRUDGE) && !(gHitMarker & HITMARKER_GRUDGE) && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget) && gBattleMons[gBattlerAttacker].hp != 0 && gCurrentMove != MOVE_STRUGGLE) { u8 moveIndex = *(gBattleStruct->chosenMovePositions + gBattlerAttacker); gBattleMons[gBattlerAttacker].pp[moveIndex] = 0; BattleScriptPush(gBattlescriptCurrInstr); gBattlescriptCurrInstr = BattleScript_GrudgeTakesPp; gActiveBattler = gBattlerAttacker; BtlController_EmitSetMonData(0, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, 1, &gBattleMons[gActiveBattler].pp[moveIndex]); MarkBattlerForControllerExec(gActiveBattler); PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].moves[moveIndex]) } } else { gBattlescriptCurrInstr += 7; } } } void atk1A_dofaintanimation(void) { if (!gBattleControllerExecFlags) { gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); BtlController_EmitFaintAnimation(0); MarkBattlerForControllerExec(gActiveBattler); gBattlescriptCurrInstr += 2; } } void atk1B_cleareffectsonfaint(void) { if (!gBattleControllerExecFlags) { gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); gBattleMons[gActiveBattler].status1 = 0; BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 0x4, &gBattleMons[gActiveBattler].status1); MarkBattlerForControllerExec(gActiveBattler); FaintClearSetData(); // Effects like attractions, trapping, etc. gBattlescriptCurrInstr += 2; } } void atk1C_jumpifstatus(void) { u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); u32 flags = T2_READ_32(gBattlescriptCurrInstr + 2); const u8 *jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 6); if (gBattleMons[battlerId].status1 & flags && gBattleMons[battlerId].hp != 0) gBattlescriptCurrInstr = jumpPtr; else gBattlescriptCurrInstr += 10; } void atk1D_jumpifstatus2(void) { u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); u32 flags = T2_READ_32(gBattlescriptCurrInstr + 2); const u8 *jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 6); if (gBattleMons[battlerId].status2 & flags && gBattleMons[battlerId].hp != 0) gBattlescriptCurrInstr = jumpPtr; else gBattlescriptCurrInstr += 10; } void atk1E_jumpifability(void) { u8 battlerId; u8 ability = gBattlescriptCurrInstr[2]; const u8 *jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 3); if (gBattlescriptCurrInstr[1] == BS_ATTACKER_SIDE) { battlerId = AbilityBattleEffects(ABILITYEFFECT_CHECK_BATTLER_SIDE, gBattlerAttacker, ability, 0, 0); if (battlerId) { gLastUsedAbility = ability; gBattlescriptCurrInstr = jumpPtr; RecordAbilityBattle(battlerId - 1, gLastUsedAbility); gBattleScripting.battlerWithAbility = battlerId - 1; } else gBattlescriptCurrInstr += 7; } else if (gBattlescriptCurrInstr[1] == BS_NOT_ATTACKER_SIDE) { battlerId = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gBattlerAttacker, ability, 0, 0); if (battlerId) { gLastUsedAbility = ability; gBattlescriptCurrInstr = jumpPtr; RecordAbilityBattle(battlerId - 1, gLastUsedAbility); gBattleScripting.battlerWithAbility = battlerId - 1; } else gBattlescriptCurrInstr += 7; } else { battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); if (gBattleMons[battlerId].ability == ability) { gLastUsedAbility = ability; gBattlescriptCurrInstr = jumpPtr; RecordAbilityBattle(battlerId, gLastUsedAbility); gBattleScripting.battlerWithAbility = battlerId; } else gBattlescriptCurrInstr += 7; } } void atk1F_jumpifsideaffecting(void) { u8 side; u16 flags; const u8 *jumpPtr; if (gBattlescriptCurrInstr[1] == BS_ATTACKER) side = GET_BATTLER_SIDE(gBattlerAttacker); else side = GET_BATTLER_SIDE(gBattlerTarget); flags = T2_READ_16(gBattlescriptCurrInstr + 2); jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 4); if (gSideStatuses[side] & flags) gBattlescriptCurrInstr = jumpPtr; else gBattlescriptCurrInstr += 8; } void atk20_jumpifstat(void) { u8 ret = 0; u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); u8 value = gBattleMons[battlerId].statStages[gBattlescriptCurrInstr[3]]; switch (gBattlescriptCurrInstr[2]) { case CMP_EQUAL: if (value == gBattlescriptCurrInstr[4]) ++ret; break; case CMP_NOT_EQUAL: if (value != gBattlescriptCurrInstr[4]) ++ret; break; case CMP_GREATER_THAN: if (value > gBattlescriptCurrInstr[4]) ++ret; break; case CMP_LESS_THAN: if (value < gBattlescriptCurrInstr[4]) ++ret; break; case CMP_COMMON_BITS: if (value & gBattlescriptCurrInstr[4]) ++ret; break; case CMP_NO_COMMON_BITS: if (!(value & gBattlescriptCurrInstr[4])) ++ret; break; } if (ret) gBattlescriptCurrInstr = T2_READ_PTR(gBattlescriptCurrInstr + 5); else gBattlescriptCurrInstr += 9; } void atk21_jumpifstatus3condition(void) { u32 flags; const u8 *jumpPtr; gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); flags = T2_READ_32(gBattlescriptCurrInstr + 2); jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 7); if (gBattlescriptCurrInstr[6]) { if (gStatuses3[gActiveBattler] & flags) gBattlescriptCurrInstr += 11; else gBattlescriptCurrInstr = jumpPtr; } else { if (gStatuses3[gActiveBattler] & flags) gBattlescriptCurrInstr = jumpPtr; else gBattlescriptCurrInstr += 11; } } void atk22_jumpiftype(void) { u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); u8 type = gBattlescriptCurrInstr[2]; const u8 *jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 3); if (IS_BATTLER_OF_TYPE(battlerId, type)) gBattlescriptCurrInstr = jumpPtr; else gBattlescriptCurrInstr += 7; } void atk23_getexp(void) { u16 item; s32 i; // also used as stringId u8 holdEffect; s32 sentIn; s32 viaExpShare = 0; u16 *exp = &gBattleStruct->expValue; gBattlerFainted = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); sentIn = gSentPokesToOpponent[(gBattlerFainted & 2) >> 1]; switch (gBattleScripting.atk23_state) { case 0: // check if should receive exp at all if (GetBattlerSide(gBattlerFainted) != B_SIDE_OPPONENT || (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER_TOWER | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_SAFARI | BATTLE_TYPE_EREADER_TRAINER))) { gBattleScripting.atk23_state = 6; // goto last case } else { ++gBattleScripting.atk23_state; gBattleStruct->givenExpMons |= gBitTable[gBattlerPartyIndexes[gBattlerFainted]]; } break; case 1: // calculate experience points to redistribute { u16 calculatedExp; s32 viaSentIn; for (viaSentIn = 0, i = 0; i < PARTY_SIZE; ++i) { if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) == SPECIES_NONE || GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) continue; if (gBitTable[i] & sentIn) ++viaSentIn; item = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); if (item == ITEM_ENIGMA_BERRY) holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; else holdEffect = ItemId_GetHoldEffect(item); if (holdEffect == HOLD_EFFECT_EXP_SHARE) ++viaExpShare; } calculatedExp = gBaseStats[gBattleMons[gBattlerFainted].species].expYield * gBattleMons[gBattlerFainted].level / 7; if (viaExpShare) // at least one mon is getting exp via exp share { *exp = calculatedExp / 2 / viaSentIn; if (*exp == 0) *exp = 1; gExpShareExp = calculatedExp / 2 / viaExpShare; if (gExpShareExp == 0) gExpShareExp = 1; } else { *exp = calculatedExp / viaSentIn; if (*exp == 0) *exp = 1; gExpShareExp = 0; } ++gBattleScripting.atk23_state; gBattleStruct->expGetterMonId = 0; gBattleStruct->sentInPokes = sentIn; } // fall through case 2: // set exp value to the poke in expgetter_id and print message if (!gBattleControllerExecFlags) { item = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HELD_ITEM); if (item == ITEM_ENIGMA_BERRY) holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; else holdEffect = ItemId_GetHoldEffect(item); if (holdEffect != HOLD_EFFECT_EXP_SHARE && !(gBattleStruct->sentInPokes & 1)) { *(&gBattleStruct->sentInPokes) >>= 1; gBattleScripting.atk23_state = 5; gBattleMoveDamage = 0; // used for exp } else if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) == MAX_LEVEL) { *(&gBattleStruct->sentInPokes) >>= 1; gBattleScripting.atk23_state = 5; gBattleMoveDamage = 0; // used for exp } else { // music change in wild battle after fainting a poke if (!(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_POKEDUDE)) && gBattleMons[0].hp && !gBattleStruct->wildVictorySong) { BattleStopLowHpSound(); PlayBGM(BGM_FRLG_KACHI_WILD_POKEMON); ++gBattleStruct->wildVictorySong; } if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP)) { if (gBattleStruct->sentInPokes & 1) gBattleMoveDamage = *exp; else gBattleMoveDamage = 0; if (holdEffect == HOLD_EFFECT_EXP_SHARE) gBattleMoveDamage += gExpShareExp; if (holdEffect == HOLD_EFFECT_LUCKY_EGG) gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterMonId]) && !(gBattleTypeFlags & BATTLE_TYPE_POKEDUDE)) { gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; i = STRINGID_ABOOSTED; } else { i = STRINGID_EMPTYSTRING4; } // get exp getter battlerId if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { if (!(gBattlerPartyIndexes[2] != gBattleStruct->expGetterMonId) && !(gAbsentBattlerFlags & gBitTable[2])) gBattleStruct->expGetterBattlerId = 2; else { if (!(gAbsentBattlerFlags & gBitTable[0])) gBattleStruct->expGetterBattlerId = 0; else gBattleStruct->expGetterBattlerId = 2; } } else { gBattleStruct->expGetterBattlerId = 0; } PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattleStruct->expGetterBattlerId, gBattleStruct->expGetterMonId); // buffer 'gained' or 'gained a boosted' PREPARE_STRING_BUFFER(gBattleTextBuff2, i); PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff3, 5, gBattleMoveDamage); PrepareStringBattle(STRINGID_PKMNGAINEDEXP, gBattleStruct->expGetterBattlerId); MonGainEVs(&gPlayerParty[gBattleStruct->expGetterMonId], gBattleMons[gBattlerFainted].species); } gBattleStruct->sentInPokes >>= 1; ++gBattleScripting.atk23_state; } } break; case 3: // Set stats and give exp if (!gBattleControllerExecFlags) { gBattleBufferB[gBattleStruct->expGetterBattlerId][0] = 0; if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP) && GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) != MAX_LEVEL) { gBattleResources->beforeLvlUp->stats[STAT_HP] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MAX_HP); gBattleResources->beforeLvlUp->stats[STAT_ATK] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_ATK); gBattleResources->beforeLvlUp->stats[STAT_DEF] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_DEF); gBattleResources->beforeLvlUp->stats[STAT_SPEED] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED); gBattleResources->beforeLvlUp->stats[STAT_SPATK] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPATK); gBattleResources->beforeLvlUp->stats[STAT_SPDEF] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPDEF); gActiveBattler = gBattleStruct->expGetterBattlerId; BtlController_EmitExpUpdate(0, gBattleStruct->expGetterMonId, gBattleMoveDamage); MarkBattlerForControllerExec(gActiveBattler); } ++gBattleScripting.atk23_state; } break; case 4: // lvl up if necessary if (!gBattleControllerExecFlags) { gActiveBattler = gBattleStruct->expGetterBattlerId; if (gBattleBufferB[gActiveBattler][0] == CONTROLLER_TWORETURNVALUES && gBattleBufferB[gActiveBattler][1] == RET_VALUE_LEVELED_UP) { if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattlerPartyIndexes[gActiveBattler] == gBattleStruct->expGetterMonId) HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler); PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBattler, gBattleStruct->expGetterMonId); PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 3, GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL)); BattleScriptPushCursor(); gLeveledUpInBattle |= gBitTable[gBattleStruct->expGetterMonId]; gBattlescriptCurrInstr = BattleScript_LevelUp; gBattleMoveDamage = (gBattleBufferB[gActiveBattler][2] | (gBattleBufferB[gActiveBattler][3] << 8)); AdjustFriendship(&gPlayerParty[gBattleStruct->expGetterMonId], 0); // update battle mon structure after level up if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId && gBattleMons[0].hp) { gBattleMons[0].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL); gBattleMons[0].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP); gBattleMons[0].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MAX_HP); gBattleMons[0].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_ATK); gBattleMons[0].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_DEF); // Why is this duplicated? gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED); gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED); gBattleMons[0].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPATK); gBattleMons[0].spDefense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPDEF); } // What is else if? if (gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId && gBattleMons[2].hp && (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) { gBattleMons[2].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL); gBattleMons[2].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP); gBattleMons[2].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MAX_HP); gBattleMons[2].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_ATK); gBattleMons[2].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_DEF); // Duplicated again, but this time there's no Sp Defense gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED); gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED); gBattleMons[2].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPATK); } gBattleScripting.atk23_state = 5; } else { gBattleMoveDamage = 0; gBattleScripting.atk23_state = 5; } } break; case 5: // looper increment if (gBattleMoveDamage) // there is exp to give, goto case 3 that gives exp { gBattleScripting.atk23_state = 3; } else { ++gBattleStruct->expGetterMonId; if (gBattleStruct->expGetterMonId <= 5) gBattleScripting.atk23_state = 2; // loop again else gBattleScripting.atk23_state = 6; // we're done } break; case 6: // increment instruction if (!gBattleControllerExecFlags) { // not sure why gf clears the item and ability here gBattleMons[gBattlerFainted].item = ITEM_NONE; gBattleMons[gBattlerFainted].ability = ABILITY_NONE; gBattlescriptCurrInstr += 2; } break; } }