#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 }; 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; }