mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-18 12:37:38 +01:00
11018 lines
357 KiB
C
11018 lines
357 KiB
C
#include "global.h"
|
|
#include "battle.h"
|
|
#include "constants/battle_move_effects.h"
|
|
#include "battle_message.h"
|
|
#include "battle_ai_script_commands.h"
|
|
#include "battle_scripts.h"
|
|
#include "constants/moves.h"
|
|
#include "constants/abilities.h"
|
|
#include "item.h"
|
|
#include "constants/items.h"
|
|
#include "constants/hold_effects.h"
|
|
#include "util.h"
|
|
#include "pokemon.h"
|
|
#include "calculate_base_damage.h"
|
|
#include "random.h"
|
|
#include "battle_controllers.h"
|
|
#include "battle_interface.h"
|
|
#include "constants/species.h"
|
|
#include "constants/songs.h"
|
|
#include "constants/trainers.h"
|
|
#include "constants/battle_anim.h"
|
|
#include "text.h"
|
|
#include "sound.h"
|
|
#include "pokedex.h"
|
|
#include "recorded_battle.h"
|
|
#include "window.h"
|
|
#include "reshow_battle_screen.h"
|
|
#include "main.h"
|
|
#include "palette.h"
|
|
#include "money.h"
|
|
#include "bg.h"
|
|
#include "string_util.h"
|
|
#include "pokemon_icon.h"
|
|
#include "pokemon_item_effects.h"
|
|
#include "m4a.h"
|
|
#include "mail.h"
|
|
#include "event_data.h"
|
|
#include "pokemon_storage_system.h"
|
|
#include "task.h"
|
|
#include "naming_screen.h"
|
|
#include "battle_string_ids.h"
|
|
|
|
// variables
|
|
|
|
extern u8 gCritMultiplier;
|
|
extern s32 gBattleMoveDamage;
|
|
extern struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT];
|
|
extern struct BattlePokemon gBattleMons[MAX_BATTLERS_COUNT];
|
|
extern u8 gActiveBattler;
|
|
extern u32 gBattleControllerExecFlags;
|
|
extern u8 gBattlersCount;
|
|
extern u16 gBattlerPartyIndexes[MAX_BATTLERS_COUNT];
|
|
extern u8 gBattleTurnOrder[MAX_BATTLERS_COUNT];
|
|
extern u8 gActionsByTurnOrder[MAX_BATTLERS_COUNT];
|
|
extern u16 gCurrentMove;
|
|
extern u8 gLastUsedAbility;
|
|
extern u8 gStringBattler;
|
|
extern u8 gEffectBank;
|
|
extern u8 gAbsentBattlerFlags;
|
|
extern u8 gMultiHitCounter;
|
|
extern u16 gChosenMoveByBattler[MAX_BATTLERS_COUNT];
|
|
extern u16 gPauseCounterBattle;
|
|
extern u16 gPaydayMoney;
|
|
extern u16 gRandomTurnNumber;
|
|
extern u8 gBattlerAttacker;
|
|
extern u8 gBattlerTarget;
|
|
extern const u8* gBattlescriptCurrInstr;
|
|
extern u8 gCurrMovePos;
|
|
extern u8 gCurrentActionFuncId;
|
|
extern u8 gMoveResultFlags;
|
|
extern u8 gBattleCommunication[];
|
|
extern u16 gLastLandedMoves[4];
|
|
extern u16 gLastHitByType[4];
|
|
extern u16 gLastResultingMoves[4];
|
|
extern u8 gLastHitBy[4];
|
|
extern u8 gStringBattler;
|
|
extern u16 gDynamicBasePower;
|
|
extern u16 gLastUsedItem;
|
|
extern u16 gBattleMovePower;
|
|
extern s32 gHpDealt;
|
|
extern s32 gTakenDmg[MAX_BATTLERS_COUNT];
|
|
extern u8 gTakenDmgBanks[MAX_BATTLERS_COUNT];
|
|
extern u8 gSentPokesToOpponent[2];
|
|
extern u8 gBank1;
|
|
extern u16 gExpShareExp;
|
|
extern u8 gLeveledUpInBattle;
|
|
extern void (*gBattleMainFunc)(void);
|
|
extern u8 gPlayerPartyCount;
|
|
extern u16 gMoveToLearn;
|
|
extern u16 gRandomMove;
|
|
extern u8 gBankInMenu;
|
|
extern u8 gChosenActionByBattler[MAX_BATTLERS_COUNT];
|
|
extern u8 gCurrentTurnActionNumber;
|
|
extern u8 gBattleBufferB[MAX_BATTLERS_COUNT][0x200];
|
|
extern u16 gLockedMoves[MAX_BATTLERS_COUNT];
|
|
extern u16 gPartnerTrainerId;
|
|
extern u16 gChosenMove;
|
|
extern u16 gLastPrintedMoves[MAX_BATTLERS_COUNT];
|
|
extern u16 gLastMoves[MAX_BATTLERS_COUNT];
|
|
extern u16 gTrainerBattleOpponent_A;
|
|
extern u16 gTrainerBattleOpponent_B;
|
|
extern u8 gUnknown_020241E9;
|
|
extern u16 gBattle_BG1_X;
|
|
extern u16 gBattle_BG1_Y;
|
|
extern u16 gBattle_BG2_X;
|
|
extern u16 gBattle_BG2_Y;
|
|
extern u16 gBattle_BG3_X;
|
|
extern struct MusicPlayerInfo gMPlayInfo_BGM;
|
|
|
|
struct TrainerMoney
|
|
{
|
|
u8 classId;
|
|
u8 value;
|
|
};
|
|
|
|
extern const struct BattleMove gBattleMoves[];
|
|
extern const struct BaseStats gBaseStats[];
|
|
extern const u8 gTypeEffectiveness[336];
|
|
extern const struct TrainerMoney gTrainerMoneyTable[];
|
|
extern const u8* const gBattleScriptsForMoveEffects[];
|
|
|
|
// functions
|
|
extern void sub_81A5718(u8 bank); // battle frontier 2
|
|
extern void sub_81A56B4(void); // battle frontier 2
|
|
extern void sub_81BFA38(struct Pokemon* party, u8 monPartyId, u8 monCount, void (*callback)(void), u16 move); // pokemon summary screen
|
|
extern u8 sub_81C1B94(void); // pokemon summary screen
|
|
extern void IncrementGameStat(u8 statId); // rom_4
|
|
extern void sub_81D388C(struct Pokemon* mon, void* statStoreLocation); // pokenav.s
|
|
extern void sub_81D3640(u8 arg0, void* statStoreLocation1, void* statStoreLocation2, u8 arg3, u8 arg4, u8 arg5); // pokenav.s
|
|
extern void sub_81D3784(u8 arg0, void* statStoreLocation1, u8 arg2, u8 arg3, u8 arg4); // pokenav.s
|
|
extern u8* GetMonNickname(struct Pokemon* mon, u8* dst); // party_menu
|
|
extern u8 sub_81A5258(u8* arg0); // battle frontier 2
|
|
extern void sub_81A5BF8(void); // battle frontier 2
|
|
extern void sub_81A5D44(void); // battle frontier 2
|
|
extern void sub_81B8E80(u8 bank, u8, u8); // party menu
|
|
extern bool8 sub_81B1250(void); // ?
|
|
extern bool8 InBattlePike(void);
|
|
extern bool8 InBattlePyramid(void);
|
|
extern u16 GetBattlePyramidPickupItemId(void);
|
|
extern u8 sav1_map_get_light_level(void);
|
|
extern u8 sub_813B21C(void);
|
|
extern u16 get_unknown_box_id(void);
|
|
extern void sub_80356D0(void);
|
|
|
|
// strings
|
|
extern const u8 gText_BattleYesNoChoice[];
|
|
|
|
// read via orr
|
|
#define BSScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24)
|
|
#define BSScriptRead16(ptr) ((ptr)[0] | ((ptr)[1] << 8))
|
|
#define BSScriptReadPtr(ptr) ((void *)BSScriptRead32(ptr))
|
|
|
|
// read via add
|
|
#define BS2ScriptRead32(ptr) ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24))
|
|
#define BS2ScriptRead16(ptr) ((ptr)[0] + ((ptr)[1] << 8))
|
|
#define BS2ScriptReadPtr(ptr) ((void *)BS2ScriptRead32(ptr))
|
|
|
|
#define DEFENDER_IS_PROTECTED ((gProtectStructs[gBattlerTarget].protected) && (gBattleMoves[gCurrentMove].flags & FLAG_PROTECT_AFFECTED))
|
|
|
|
#define TARGET_TURN_DAMAGED (gSpecialStatuses[gBattlerTarget].moveturnLostHP_physical != 0 \
|
|
|| gSpecialStatuses[gBattlerTarget].moveturnLostHP_special != 0)
|
|
|
|
// this file's functions
|
|
static bool8 IsTwoTurnsMove(u16 move);
|
|
static void TrySetDestinyBondToHappen(void);
|
|
static u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2.
|
|
static void CheckWonderGuardAndLevitate(void);
|
|
static u8 ChangeStatBuffs(s8 statValue, u8 statId, u8, const u8* BS_ptr);
|
|
static bool32 IsMonGettingExpSentOut(void);
|
|
static void sub_804F17C(void);
|
|
static bool8 sub_804F1CC(void);
|
|
static void sub_804F100(void);
|
|
static void sub_804F144(void);
|
|
static bool8 sub_804F344(void);
|
|
static void PutMonIconOnLvlUpBox(void);
|
|
static void PutLevelAndGenderOnLvlUpBox(void);
|
|
|
|
static void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite);
|
|
|
|
static void atk00_attackcanceler(void);
|
|
static void atk01_accuracycheck(void);
|
|
static void atk02_attackstring(void);
|
|
static void atk03_ppreduce(void);
|
|
static void atk04_critcalc(void);
|
|
static void atk05_damagecalc(void);
|
|
static void atk06_typecalc(void);
|
|
static void atk07_adjustnormaldamage(void);
|
|
static void atk08_adjustnormaldamage2(void);
|
|
static void atk09_attackanimation(void);
|
|
static void atk0A_waitanimation(void);
|
|
static void atk0B_healthbarupdate(void);
|
|
static void atk0C_datahpupdate(void);
|
|
static void atk0D_critmessage(void);
|
|
static void atk0E_effectivenesssound(void);
|
|
static void atk0F_resultmessage(void);
|
|
static void atk10_printstring(void);
|
|
static void atk11_printselectionstring(void);
|
|
static void atk12_waitmessage(void);
|
|
static void atk13_printfromtable(void);
|
|
static void atk14_printselectionstringfromtable(void);
|
|
static void atk15_seteffectwithchance(void);
|
|
static void atk16_seteffectprimary(void);
|
|
static void atk17_seteffectsecondary(void);
|
|
static void atk18_clearstatusfromeffect(void);
|
|
static void atk19_tryfaintmon(void);
|
|
static void atk1A_dofaintanimation(void);
|
|
static void atk1B_cleareffectsonfaint(void);
|
|
static void atk1C_jumpifstatus(void);
|
|
static void atk1D_jumpifstatus2(void);
|
|
static void atk1E_jumpifability(void);
|
|
static void atk1F_jumpifsideaffecting(void);
|
|
static void atk20_jumpifstat(void);
|
|
static void atk21_jumpifstatus3condition(void);
|
|
static void atk22_jumpiftype(void);
|
|
static void atk23_getexp(void);
|
|
static void atk24(void);
|
|
static void atk25_movevaluescleanup(void);
|
|
static void atk26_setmultihit(void);
|
|
static void atk27_decrementmultihit(void);
|
|
static void atk28_goto(void);
|
|
static void atk29_jumpifbyte(void);
|
|
static void atk2A_jumpifhalfword(void);
|
|
static void atk2B_jumpifword(void);
|
|
static void atk2C_jumpifarrayequal(void);
|
|
static void atk2D_jumpifarraynotequal(void);
|
|
static void atk2E_setbyte(void);
|
|
static void atk2F_addbyte(void);
|
|
static void atk30_subbyte(void);
|
|
static void atk31_copyarray(void);
|
|
static void atk32_copyarraywithindex(void);
|
|
static void atk33_orbyte(void);
|
|
static void atk34_orhalfword(void);
|
|
static void atk35_orword(void);
|
|
static void atk36_bicbyte(void);
|
|
static void atk37_bichalfword(void);
|
|
static void atk38_bicword(void);
|
|
static void atk39_pause(void);
|
|
static void atk3A_waitstate(void);
|
|
static void atk3B_healthbar_update(void);
|
|
static void atk3C_return(void);
|
|
static void atk3D_end(void);
|
|
static void atk3E_end2(void);
|
|
static void atk3F_end3(void);
|
|
static void atk40_jumpifaffectedbyprotect(void);
|
|
static void atk41_call(void);
|
|
static void atk42_jumpiftype2(void);
|
|
static void atk43_jumpifabilitypresent(void);
|
|
static void atk44_endselectionscript(void);
|
|
static void atk45_playanimation(void);
|
|
static void atk46_playanimation2(void);
|
|
static void atk47_setgraphicalstatchangevalues(void);
|
|
static void atk48_playstatchangeanimation(void);
|
|
static void atk49_moveend(void);
|
|
static void atk4A_typecalc2(void);
|
|
static void atk4B_returnatktoball(void);
|
|
static void atk4C_getswitchedmondata(void);
|
|
static void atk4D_switchindataupdate(void);
|
|
static void atk4E_switchinanim(void);
|
|
static void atk4F_jumpifcantswitch(void);
|
|
static void atk50_openpartyscreen(void);
|
|
static void atk51_switchhandleorder(void);
|
|
static void atk52_switchineffects(void);
|
|
static void atk53_trainerslidein(void);
|
|
static void atk54_playse(void);
|
|
static void atk55_fanfare(void);
|
|
static void atk56_playfaintcry(void);
|
|
static void atk57(void);
|
|
static void atk58_returntoball(void);
|
|
static void atk59_handlelearnnewmove(void);
|
|
static void atk5A_yesnoboxlearnmove(void);
|
|
static void atk5B_yesnoboxstoplearningmove(void);
|
|
static void atk5C_hitanimation(void);
|
|
static void atk5D_getmoneyreward(void);
|
|
static void atk5E(void);
|
|
static void atk5F(void);
|
|
static void atk60_incrementgamestat(void);
|
|
static void atk61_drawpartystatussummary(void);
|
|
static void atk62(void);
|
|
static void atk63_jumptorandomattack(void);
|
|
static void atk64_statusanimation(void);
|
|
static void atk65_status2animation(void);
|
|
static void atk66_chosenstatusanimation(void);
|
|
static void atk67_yesnobox(void);
|
|
static void atk68_cancelallactions(void);
|
|
static void atk69_adjustsetdamage(void);
|
|
static void atk6A_removeitem(void);
|
|
static void atk6B_atknameinbuff1(void);
|
|
static void atk6C_drawlvlupbox(void);
|
|
static void atk6D_resetsentmonsvalue(void);
|
|
static void atk6E_setatktoplayer0(void);
|
|
static void atk6F_makevisible(void);
|
|
static void atk70_recordlastability(void);
|
|
static void atk71_buffermovetolearn(void);
|
|
static void atk72_jumpifplayerran(void);
|
|
static void atk73_hpthresholds(void);
|
|
static void atk74_hpthresholds2(void);
|
|
static void atk75_useitemonopponent(void);
|
|
static void atk76_various(void);
|
|
static void atk77_setprotectlike(void);
|
|
static void atk78_faintifabilitynotdamp(void);
|
|
static void atk79_setatkhptozero(void);
|
|
static void atk7A_jumpifnexttargetvalid(void);
|
|
static void atk7B_tryhealhalfhealth(void);
|
|
static void atk7C_trymirrormove(void);
|
|
static void atk7D_setrain(void);
|
|
static void atk7E_setreflect(void);
|
|
static void atk7F_setseeded(void);
|
|
static void atk80_manipulatedamage(void);
|
|
static void atk81_trysetrest(void);
|
|
static void atk82_jumpifnotfirstturn(void);
|
|
static void atk83_nop(void);
|
|
static void atk84_jumpifcantmakeasleep(void);
|
|
static void atk85_stockpile(void);
|
|
static void atk86_stockpiletobasedamage(void);
|
|
static void atk87_stockpiletohpheal(void);
|
|
static void atk88_negativedamage(void);
|
|
static void atk89_statbuffchange(void);
|
|
static void atk8A_normalisebuffs(void);
|
|
static void atk8B_setbide(void);
|
|
static void atk8C_confuseifrepeatingattackends(void);
|
|
static void atk8D_setmultihitcounter(void);
|
|
static void atk8E_initmultihitstring(void);
|
|
static void atk8F_forcerandomswitch(void);
|
|
static void atk90_tryconversiontypechange(void);
|
|
static void atk91_givepaydaymoney(void);
|
|
static void atk92_setlightscreen(void);
|
|
static void atk93_tryKO(void);
|
|
static void atk94_damagetohalftargethp(void);
|
|
static void atk95_setsandstorm(void);
|
|
static void atk96_weatherdamage(void);
|
|
static void atk97_tryinfatuating(void);
|
|
static void atk98_updatestatusicon(void);
|
|
static void atk99_setmist(void);
|
|
static void atk9A_setfocusenergy(void);
|
|
static void atk9B_transformdataexecution(void);
|
|
static void atk9C_setsubstitute(void);
|
|
static void atk9D_mimicattackcopy(void);
|
|
static void atk9E_metronome(void);
|
|
static void atk9F_dmgtolevel(void);
|
|
static void atkA0_psywavedamageeffect(void);
|
|
static void atkA1_counterdamagecalculator(void);
|
|
static void atkA2_mirrorcoatdamagecalculator(void);
|
|
static void atkA3_disablelastusedattack(void);
|
|
static void atkA4_trysetencore(void);
|
|
static void atkA5_painsplitdmgcalc(void);
|
|
static void atkA6_settypetorandomresistance(void);
|
|
static void atkA7_setalwayshitflag(void);
|
|
static void atkA8_copymovepermanently(void);
|
|
static void atkA9_trychoosesleeptalkmove(void);
|
|
static void atkAA_setdestinybond(void);
|
|
static void atkAB_trysetdestinybondtohappen(void);
|
|
static void atkAC_remaininghptopower(void);
|
|
static void atkAD_tryspiteppreduce(void);
|
|
static void atkAE_healpartystatus(void);
|
|
static void atkAF_cursetarget(void);
|
|
static void atkB0_trysetspikes(void);
|
|
static void atkB1_setforesight(void);
|
|
static void atkB2_trysetperishsong(void);
|
|
static void atkB3_rolloutdamagecalculation(void);
|
|
static void atkB4_jumpifconfusedandstatmaxed(void);
|
|
static void atkB5_furycuttercalc(void);
|
|
static void atkB6_happinesstodamagecalculation(void);
|
|
static void atkB7_presentdamagecalculation(void);
|
|
static void atkB8_setsafeguard(void);
|
|
static void atkB9_magnitudedamagecalculation(void);
|
|
static void atkBA_jumpifnopursuitswitchdmg(void);
|
|
static void atkBB_setsunny(void);
|
|
static void atkBC_maxattackhalvehp(void);
|
|
static void atkBD_copyfoestats(void);
|
|
static void atkBE_rapidspinfree(void);
|
|
static void atkBF_setdefensecurlbit(void);
|
|
static void atkC0_recoverbasedonsunlight(void);
|
|
static void atkC1_hiddenpowercalc(void);
|
|
static void atkC2_selectfirstvalidtarget(void);
|
|
static void atkC3_trysetfutureattack(void);
|
|
static void atkC4_trydobeatup(void);
|
|
static void atkC5_setsemiinvulnerablebit(void);
|
|
static void atkC6_clearsemiinvulnerablebit(void);
|
|
static void atkC7_setminimize(void);
|
|
static void atkC8_sethail(void);
|
|
static void atkC9_jumpifattackandspecialattackcannotfall(void);
|
|
static void atkCA_setforcedtarget(void);
|
|
static void atkCB_setcharge(void);
|
|
static void atkCC_callterrainattack(void);
|
|
static void atkCD_cureifburnedparalysedorpoisoned(void);
|
|
static void atkCE_settorment(void);
|
|
static void atkCF_jumpifnodamage(void);
|
|
static void atkD0_settaunt(void);
|
|
static void atkD1_trysethelpinghand(void);
|
|
static void atkD2_tryswapitems(void);
|
|
static void atkD3_trycopyability(void);
|
|
static void atkD4_trywish(void);
|
|
static void atkD5_trysetroots(void);
|
|
static void atkD6_doubledamagedealtifdamaged(void);
|
|
static void atkD7_setyawn(void);
|
|
static void atkD8_setdamagetohealthdifference(void);
|
|
static void atkD9_scaledamagebyhealthratio(void);
|
|
static void atkDA_tryswapabilities(void);
|
|
static void atkDB_tryimprision(void);
|
|
static void atkDC_trysetgrudge(void);
|
|
static void atkDD_weightdamagecalculation(void);
|
|
static void atkDE_asistattackselect(void);
|
|
static void atkDF_trysetmagiccoat(void);
|
|
static void atkE0_trysetsnatch(void);
|
|
static void atkE1_trygetintimidatetarget(void);
|
|
static void atkE2_switchoutabilities(void);
|
|
static void atkE3_jumpifhasnohp(void);
|
|
static void atkE4_getsecretpowereffect(void);
|
|
static void atkE5_pickup(void);
|
|
static void atkE6_docastformchangeanimation(void);
|
|
static void atkE7_trycastformdatachange(void);
|
|
static void atkE8_settypebasedhalvers(void);
|
|
static void atkE9_setweatherballtype(void);
|
|
static void atkEA_tryrecycleitem(void);
|
|
static void atkEB_settypetoterrain(void);
|
|
static void atkEC_pursuitrelated(void);
|
|
static void atkEF_snatchsetbanks(void);
|
|
static void atkEE_removelightscreenreflect(void);
|
|
static void atkEF_handleballthrow(void);
|
|
static void atkF0_givecaughtmon(void);
|
|
static void atkF1_trysetcaughtmondexflags(void);
|
|
static void atkF2_displaydexinfo(void);
|
|
static void atkF3_trygivecaughtmonnick(void);
|
|
static void atkF4_subattackerhpbydmg(void);
|
|
static void atkF5_removeattackerstatus1(void);
|
|
static void atkF6_finishaction(void);
|
|
static void atkF7_finishturn(void);
|
|
static void atkF8_trainerslideout(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,
|
|
atk60_incrementgamestat,
|
|
atk61_drawpartystatussummary,
|
|
atk62,
|
|
atk63_jumptorandomattack,
|
|
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_tryimprision,
|
|
atkDC_trysetgrudge,
|
|
atkDD_weightdamagecalculation,
|
|
atkDE_asistattackselect,
|
|
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,
|
|
atkEF_snatchsetbanks,
|
|
atkEE_removelightscreenreflect,
|
|
atkEF_handleballthrow,
|
|
atkF0_givecaughtmon,
|
|
atkF1_trysetcaughtmondexflags,
|
|
atkF2_displaydexinfo,
|
|
atkF3_trygivecaughtmonnick,
|
|
atkF4_subattackerhpbydmg,
|
|
atkF5_removeattackerstatus1,
|
|
atkF6_finishaction,
|
|
atkF7_finishturn,
|
|
atkF8_trainerslideout
|
|
};
|
|
|
|
struct StatFractions
|
|
{
|
|
u8 dividend;
|
|
u8 divisor;
|
|
};
|
|
|
|
static 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.
|
|
static const u16 sCriticalHitChance[] = {16, 8, 4, 3, 2};
|
|
|
|
static 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
|
|
};
|
|
|
|
static const u8* const sMoveEffectBS_Ptrs[] =
|
|
{
|
|
BattleScript_MoveEffectSleep, // 0
|
|
BattleScript_MoveEffectSleep, // MOVE_EFFECT_SLEEP
|
|
BattleScript_MoveEffectPoison, // MOVE_EFFECT_POISON
|
|
BattleScript_MoveEffectBurn, // MOVE_EFFECT_BURN
|
|
BattleScript_MoveEffectFreeze, // MOVE_EFFECT_FREEZE
|
|
BattleScript_MoveEffectParalysis, // MOVE_EFFECT_PARALYSIS
|
|
BattleScript_MoveEffectToxic, // MOVE_EFFECT_TOXIC
|
|
BattleScript_MoveEffectConfusion, // MOVE_EFFECT_CONFUSION
|
|
BattleScript_MoveEffectSleep, // MOVE_EFFECT_FLINCH
|
|
BattleScript_MoveEffectSleep, // MOVE_EFFECT_TRI_ATTACK
|
|
BattleScript_MoveEffectUproar, // MOVE_EFFECT_UPROAR
|
|
BattleScript_MoveEffectPayDay, // MOVE_EFFECT_PAYDAY
|
|
BattleScript_MoveEffectSleep, // MOVE_EFFECT_CHARGING
|
|
BattleScript_MoveEffectWrap, // MOVE_EFFECT_WRAP
|
|
BattleScript_MoveEffectRecoil33, // MOVE_EFFECT_RECOIL_25
|
|
BattleScript_MoveEffectSleep, // 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_MoveEffectRecoil33, // MOVE_EFFECT_RECOIL_33_PARALYSIS
|
|
};
|
|
|
|
static const struct WindowTemplate sUnusedWinTemplate = {0, 1, 3, 7, 0xF, 0x1F, 0x3F};
|
|
|
|
static const u16 sUnknown_0831C2C8[] = INCBIN_U16("graphics/battle_interface/unk_battlebox.gbapal");
|
|
static const u8 sUnknown_0831C2E8[] = INCBIN_U8("graphics/battle_interface/unk_battlebox.4bpp.lz");
|
|
|
|
// unused
|
|
static const u8 sRubyLevelUpStatBoxStats[] =
|
|
{
|
|
MON_DATA_MAX_HP, MON_DATA_SPATK, MON_DATA_ATK,
|
|
MON_DATA_SPDEF, MON_DATA_DEF, MON_DATA_SPEED
|
|
};
|
|
|
|
#define MON_ICON_LVLUP_BOX_TAG 0xD75A
|
|
|
|
static const struct OamData sOamData_MonIconOnLvlUpBox =
|
|
{
|
|
.y = 0,
|
|
.affineMode = 0,
|
|
.objMode = 0,
|
|
.mosaic = 0,
|
|
.bpp = 0,
|
|
.shape = 0,
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = 2,
|
|
.tileNum = 0,
|
|
.priority = 0,
|
|
.paletteNum = 0,
|
|
.affineParam = 0,
|
|
};
|
|
|
|
static 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
|
|
};
|
|
|
|
static 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
|
|
|
|
static 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
|
|
};
|
|
|
|
static const u8 sFlailHpScaleToPowerTable[] =
|
|
{
|
|
1, 200,
|
|
4, 150,
|
|
9, 100,
|
|
16, 80,
|
|
32, 40,
|
|
48, 20
|
|
};
|
|
|
|
static 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
|
|
};
|
|
|
|
// format: min. weight (hectograms), base power
|
|
static const u16 sWeightToDamageTable[] =
|
|
{
|
|
100, 20,
|
|
250, 40,
|
|
500, 60,
|
|
1000, 80,
|
|
2000, 100,
|
|
0xFFFF, 0xFFFF
|
|
};
|
|
|
|
static const u16 sPickupItems[] =
|
|
{
|
|
ITEM_POTION,
|
|
ITEM_ANTIDOTE,
|
|
ITEM_SUPER_POTION,
|
|
ITEM_GREAT_BALL,
|
|
ITEM_REPEL,
|
|
ITEM_ESCAPE_ROPE,
|
|
ITEM_X_ATTACK,
|
|
ITEM_FULL_HEAL,
|
|
ITEM_ULTRA_BALL,
|
|
ITEM_HYPER_POTION,
|
|
ITEM_RARE_CANDY,
|
|
ITEM_PROTEIN,
|
|
ITEM_REVIVE,
|
|
ITEM_HP_UP,
|
|
ITEM_FULL_RESTORE,
|
|
ITEM_MAX_REVIVE,
|
|
ITEM_PP_UP,
|
|
ITEM_MAX_ELIXIR,
|
|
};
|
|
|
|
static const u16 sRarePickupItems[] =
|
|
{
|
|
ITEM_HYPER_POTION,
|
|
ITEM_NUGGET,
|
|
ITEM_KINGS_ROCK,
|
|
ITEM_FULL_RESTORE,
|
|
ITEM_ETHER,
|
|
ITEM_WHITE_HERB,
|
|
ITEM_TM44_REST,
|
|
ITEM_ELIXIR,
|
|
ITEM_TM01_FOCUS_PUNCH,
|
|
ITEM_LEFTOVERS,
|
|
ITEM_TM26_EARTHQUAKE,
|
|
};
|
|
|
|
static const u8 sPickupProbabilities[] =
|
|
{
|
|
30, 40, 50, 60, 70, 80, 90, 94, 98
|
|
};
|
|
|
|
static 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
|
|
};
|
|
|
|
static const u8 sBallCatchBonuses[] =
|
|
{
|
|
20, 15, 10, 15 // Ultra, Great, Poke, Safari
|
|
};
|
|
|
|
const ALIGNED(4) u8 gUnknown_0831C494[][4] =
|
|
{
|
|
{0x3d, 0x44, 0x3d, 0x44},
|
|
{0x14, 0x2d, 0x54, 0x5c},
|
|
{0x46, 0x55, 0x20, 0x5c},
|
|
{0x26, 0x45, 0x46, 0x55},
|
|
{0x14, 0x5a, 0x46, 0x5c},
|
|
{0x1e, 0x32, 0x20, 0x5a},
|
|
{0x38, 0x4e, 0x38, 0x4e},
|
|
{0x19, 0x28, 0x4b, 0x5a},
|
|
{0x45, 0x4b, 0x1c, 0x53},
|
|
{0x23, 0x2d, 0x1d, 0x23},
|
|
{0x3e, 0x48, 0x1e, 0x32},
|
|
{0x3a, 0x5f, 0x58, 0x5e},
|
|
{0x22, 0x2d, 0x1d, 0x28},
|
|
{0x23, 0x28, 0x23, 0x5f},
|
|
{0x38, 0x4e, 0x38, 0x4e},
|
|
{0x23, 0x50, 0x22, 0x5e},
|
|
{0x2c, 0x5e, 0x22, 0x28},
|
|
{0x38, 0x4e, 0x38, 0x4e},
|
|
{0x1e, 0x58, 0x1e, 0x58},
|
|
{0x1e, 0x2b, 0x1b, 0x21},
|
|
{0x28, 0x5a, 0x19, 0x57},
|
|
{0x12, 0x58, 0x5a, 0x5f},
|
|
{0x58, 0x5e, 0x16, 0x2a},
|
|
{0x2a, 0x5c, 0x2a, 0x2f},
|
|
{0x38, 0x4e, 0x38, 0x4e}
|
|
};
|
|
|
|
static const u8 sUnknown_0831C4F8[] =
|
|
{
|
|
0x03, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00,
|
|
0x01, 0x02, 0x02, 0x00, 0x03, 0x01, 0x03, 0x01,
|
|
0x02, 0x03, 0x03, 0x02, 0x01, 0x00, 0x02, 0x02,
|
|
0x03, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
static void atk00_attackcanceler(void)
|
|
{
|
|
s32 i;
|
|
|
|
if (gBattleOutcome != 0)
|
|
{
|
|
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 & 0x800200)
|
|
&& !(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(); // why use the 'i' variable...?
|
|
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 = 0;
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_MagicCoatBounce;
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if ((gProtectStructs[gBattleTurnOrder[i]].stealMove) && gBattleMoves[gCurrentMove].flags & FLAG_SNATCH_AFFECTED)
|
|
{
|
|
PressurePPLose(gBattlerAttacker, gBattleTurnOrder[i], MOVE_SNATCH);
|
|
gProtectStructs[gBattleTurnOrder[i]].stealMove = 0;
|
|
gBattleScripting.battler = gBattleTurnOrder[i];
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_SnatchedMove;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (gSpecialStatuses[gBattlerTarget].lightningRodRedirected)
|
|
{
|
|
gSpecialStatuses[gBattlerTarget].lightningRodRedirected = 0;
|
|
gLastUsedAbility = ABILITY_LIGHTNING_ROD;
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_TookAttack;
|
|
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
|
|
}
|
|
else if (DEFENDER_IS_PROTECTED
|
|
&& (gCurrentMove != MOVE_CURSE || (gBattleMons[gBattlerAttacker].type1 == TYPE_GHOST || gBattleMons[gBattlerAttacker].type2 == 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++;
|
|
}
|
|
}
|
|
|
|
static 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 = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
TrySetDestinyBondToHappen();
|
|
if (AbilityBattleEffects(ABILITYEFFECT_ABSORBING, gBattlerTarget, 0, 0, move))
|
|
return;
|
|
}
|
|
gBattlescriptCurrInstr = BS_ptr;
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
|
|
static void atk01_accuracycheck(void)
|
|
{
|
|
u16 move = BS2ScriptRead16(gBattlescriptCurrInstr + 5);
|
|
|
|
if (move == 0xFFFE || move == 0xFFFF)
|
|
{
|
|
if (gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && move == 0xFFFF && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker)
|
|
gBattlescriptCurrInstr += 7;
|
|
else if (gStatuses3[gBattlerTarget] & (STATUS3_ON_AIR | STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
else if (!JumpIfMoveAffectedByProtect(0))
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
else
|
|
{
|
|
u8 type, moveAcc, holdEffect, quality;
|
|
s8 buff;
|
|
u16 calc;
|
|
|
|
if (move == 0)
|
|
move = gCurrentMove;
|
|
|
|
GET_MOVE_TYPE(move, type);
|
|
|
|
if (JumpIfMoveAffectedByProtect(move))
|
|
return;
|
|
if (AccuracyCalcHelper(move))
|
|
return;
|
|
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_FORESIGHT)
|
|
{
|
|
u8 acc = gBattleMons[gBattlerAttacker].statStages[STAT_STAGE_ACC];
|
|
buff = acc;
|
|
}
|
|
else
|
|
{
|
|
u8 acc = gBattleMons[gBattlerAttacker].statStages[STAT_STAGE_ACC];
|
|
buff = acc + 6 - gBattleMons[gBattlerTarget].statStages[STAT_STAGE_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 && type < 9)
|
|
calc = (calc * 80) / 100; // 1.2 hustle loss
|
|
|
|
if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY)
|
|
{
|
|
holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect;
|
|
quality = gEnigmaBerries[gBattlerTarget].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item);
|
|
quality = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item);
|
|
}
|
|
|
|
gStringBattler = gBattlerTarget;
|
|
|
|
if (holdEffect == HOLD_EFFECT_EVASION_UP)
|
|
calc = (calc * (100 - quality)) / 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);
|
|
}
|
|
}
|
|
|
|
static void atk02_attackstring(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
if (!(gHitMarker & (HITMARKER_NO_ATTACKSTRING | HITMARKER_ATTACKSTRING_PRINTED)))
|
|
{
|
|
PrepareStringBattle(STRINGID_USEDMOVE, gBattlerAttacker);
|
|
gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
gBattleCommunication[MSG_DISPLAY] = 0;
|
|
}
|
|
|
|
static void atk03_ppreduce(void)
|
|
{
|
|
s32 ppToDeduct = 1;
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
if (!gSpecialStatuses[gBattlerAttacker].flag20)
|
|
{
|
|
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].unk18_b) & gBitTable[gCurrMovePos]))
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0, 1, &gBattleMons[gBattlerAttacker].pp[gCurrMovePos]);
|
|
MarkBattlerForControllerExec(gBattlerAttacker);
|
|
}
|
|
}
|
|
|
|
gHitMarker &= ~(HITMARKER_NO_PPDEDUCT);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static 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);
|
|
|
|
gStringBattler = 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 > 4)
|
|
critChance = 4;
|
|
|
|
if ((gBattleMons[gBattlerTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBattlerTarget].ability != ABILITY_SHELL_ARMOR)
|
|
&& !(gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT)
|
|
&& !(gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE))
|
|
&& !(Random() % sCriticalHitChance[critChance]))
|
|
gCritMultiplier = 2;
|
|
else
|
|
gCritMultiplier = 1;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
|
|
static void ModulateDmgByType(u8 multiplier)
|
|
{
|
|
gBattleMoveDamage = gBattleMoveDamage * multiplier / 10;
|
|
if (gBattleMoveDamage == 0 && multiplier != 0)
|
|
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;
|
|
}
|
|
}
|
|
|
|
static void atk06_typecalc(void)
|
|
{
|
|
s32 i = 0;
|
|
u8 moveType;
|
|
|
|
if (gCurrentMove == MOVE_STRUGGLE)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
return;
|
|
}
|
|
|
|
GET_MOVE_TYPE(gCurrentMove, moveType);
|
|
|
|
// check stab
|
|
if (gBattleMons[gBattlerAttacker].type1 == moveType || gBattleMons[gBattlerAttacker].type2 == 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++;
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ModulateDmgByType2(u8 multiplier, u16 move, u8* flags) // same as ModulateDmgByType except different arguments
|
|
{
|
|
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 (gBattleMons[attacker].type1 == moveType || gBattleMons[attacker].type2 == 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;
|
|
}
|
|
|
|
// Multiplies the damage by a random factor between 85% to 100% inclusive
|
|
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;
|
|
}
|
|
}
|
|
|
|
static void Unused_ApplyRandomDmgMultiplier(void)
|
|
{
|
|
ApplyRandomDmgMultiplier();
|
|
}
|
|
|
|
static void atk07_adjustnormaldamage(void)
|
|
{
|
|
u8 holdEffect, quality;
|
|
|
|
ApplyRandomDmgMultiplier();
|
|
|
|
if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY)
|
|
{
|
|
holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect, quality = gEnigmaBerries[gBattlerTarget].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item);
|
|
quality = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item);
|
|
}
|
|
|
|
gStringBattler = gBattlerTarget;
|
|
|
|
if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality)
|
|
{
|
|
RecordItemEffectBattle(gBattlerTarget, holdEffect);
|
|
gSpecialStatuses[gBattlerTarget].focusBanded = 1;
|
|
}
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE)
|
|
goto END;
|
|
if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBattlerTarget].endured
|
|
&& !gSpecialStatuses[gBattlerTarget].focusBanded)
|
|
goto END;
|
|
|
|
if (gBattleMons[gBattlerTarget].hp > gBattleMoveDamage)
|
|
goto END;
|
|
|
|
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;
|
|
}
|
|
|
|
END:
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk08_adjustnormaldamage2(void) // The same as 0x7 except it doesn't check for false swipe move effect.
|
|
{
|
|
u8 holdEffect, quality;
|
|
|
|
ApplyRandomDmgMultiplier();
|
|
|
|
if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY)
|
|
{
|
|
holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect, quality = gEnigmaBerries[gBattlerTarget].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item);
|
|
quality = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item);
|
|
}
|
|
|
|
gStringBattler = gBattlerTarget;
|
|
|
|
if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality)
|
|
{
|
|
RecordItemEffectBattle(gBattlerTarget, holdEffect);
|
|
gSpecialStatuses[gBattlerTarget].focusBanded = 1;
|
|
}
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE)
|
|
goto END;
|
|
if (!gProtectStructs[gBattlerTarget].endured && !gSpecialStatuses[gBattlerTarget].focusBanded)
|
|
goto END;
|
|
if (gBattleMons[gBattlerTarget].hp > gBattleMoveDamage)
|
|
goto END;
|
|
|
|
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;
|
|
}
|
|
|
|
END:
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk09_attackanimation(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
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))
|
|
{
|
|
u8 multihit;
|
|
|
|
gActiveBattler = gBattlerAttacker;
|
|
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE)
|
|
multihit = gMultiHitCounter;
|
|
else if (gMultiHitCounter != 0 && gMultiHitCounter != 1)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].hp <= gBattleMoveDamage)
|
|
multihit = 1;
|
|
else
|
|
multihit = gMultiHitCounter;
|
|
}
|
|
else
|
|
multihit = gMultiHitCounter;
|
|
|
|
BtlController_EmitMoveAnimation(0, gCurrentMove, gBattleScripting.animTurn, gBattleMovePower, gBattleMoveDamage, gBattleMons[gBattlerAttacker].friendship, &gDisableStructs[gBattlerAttacker], multihit);
|
|
gBattleScripting.animTurn += 1;
|
|
gBattleScripting.animTargetsHit += 1;
|
|
MarkBattlerForControllerExec(gBattlerAttacker);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_Pausex20;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atk0A_waitanimation(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk0B_healthbarupdate(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
|
|
{
|
|
gActiveBattler = GetBattleBank(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.unk5_0 = 1;
|
|
}
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk0C_datahpupdate(void)
|
|
{
|
|
u32 moveType;
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
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 = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
if (gBattleMons[gActiveBattler].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBattler].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE))
|
|
{
|
|
if (gDisableStructs[gActiveBattler].substituteHP >= gBattleMoveDamage)
|
|
{
|
|
if (gSpecialStatuses[gActiveBattler].moveturnLostHP == 0)
|
|
gSpecialStatuses[gActiveBattler].moveturnLostHP = gBattleMoveDamage;
|
|
gDisableStructs[gActiveBattler].substituteHP -= gBattleMoveDamage;
|
|
gHpDealt = gBattleMoveDamage;
|
|
}
|
|
else
|
|
{
|
|
if (gSpecialStatuses[gActiveBattler].moveturnLostHP == 0)
|
|
gSpecialStatuses[gActiveBattler].moveturnLostHP = 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_GET_TARGET)
|
|
gTakenDmgBanks[gActiveBattler] = gBattlerAttacker;
|
|
else
|
|
gTakenDmgBanks[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].moveturnLostHP && !(gHitMarker & HITMARKER_x100000))
|
|
gSpecialStatuses[gActiveBattler].moveturnLostHP = gHpDealt;
|
|
|
|
if (moveType <= 8 && !(gHitMarker & HITMARKER_x100000) && gCurrentMove != MOVE_PAIN_SPLIT)
|
|
{
|
|
gProtectStructs[gActiveBattler].physicalDmg = gHpDealt;
|
|
gSpecialStatuses[gActiveBattler].moveturnLostHP_physical = gHpDealt;
|
|
if (gBattlescriptCurrInstr[1] == BS_GET_TARGET)
|
|
{
|
|
gProtectStructs[gActiveBattler].physicalBank = gBattlerAttacker;
|
|
gSpecialStatuses[gActiveBattler].moveturnPhysicalBank = gBattlerAttacker;
|
|
}
|
|
else
|
|
{
|
|
gProtectStructs[gActiveBattler].physicalBank = gBattlerTarget;
|
|
gSpecialStatuses[gActiveBattler].moveturnPhysicalBank = gBattlerTarget;
|
|
}
|
|
}
|
|
else if (moveType > 8 && !(gHitMarker & HITMARKER_x100000))
|
|
{
|
|
gProtectStructs[gActiveBattler].specialDmg = gHpDealt;
|
|
gSpecialStatuses[gActiveBattler].moveturnLostHP_special = gHpDealt;
|
|
if (gBattlescriptCurrInstr[1] == BS_GET_TARGET)
|
|
{
|
|
gProtectStructs[gActiveBattler].specialBank = gBattlerAttacker;
|
|
gSpecialStatuses[gActiveBattler].moveturnSpecialBank = gBattlerAttacker;
|
|
}
|
|
else
|
|
{
|
|
gProtectStructs[gActiveBattler].specialBank = gBattlerTarget;
|
|
gSpecialStatuses[gActiveBattler].moveturnSpecialBank = gBattlerTarget;
|
|
}
|
|
}
|
|
}
|
|
gHitMarker &= ~(HITMARKER_x100000);
|
|
BtlController_EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBattler].hp);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
if (gSpecialStatuses[gActiveBattler].moveturnLostHP == 0)
|
|
gSpecialStatuses[gActiveBattler].moveturnLostHP = 0xFFFF;
|
|
}
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk0D_critmessage(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
if (gCritMultiplier == 2 && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
|
|
{
|
|
PrepareStringBattle(STRINGID_CRITICALHIT, gBattlerAttacker);
|
|
gBattleCommunication[MSG_DISPLAY] = 1;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
|
|
static void atk0E_effectivenesssound(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
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++;
|
|
}
|
|
|
|
static void atk0F_resultmessage(void)
|
|
{
|
|
u32 stringId = 0;
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
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;
|
|
gStringBattler = 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;
|
|
gStringBattler = 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++;
|
|
}
|
|
|
|
static void atk10_printstring(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
u16 var = BS2ScriptRead16(gBattlescriptCurrInstr + 1);
|
|
PrepareStringBattle(var, gBattlerAttacker);
|
|
gBattlescriptCurrInstr += 3;
|
|
gBattleCommunication[MSG_DISPLAY] = 1;
|
|
}
|
|
}
|
|
|
|
static void atk11_printselectionstring(void)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
|
|
BtlController_EmitPrintSelectionString(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1));
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
gBattleCommunication[MSG_DISPLAY] = 1;
|
|
}
|
|
|
|
static void atk12_waitmessage(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
if (!gBattleCommunication[MSG_DISPLAY])
|
|
{
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
else
|
|
{
|
|
u16 toWait = BS2ScriptRead16(gBattlescriptCurrInstr + 1);
|
|
if (++gPauseCounterBattle >= toWait)
|
|
{
|
|
gPauseCounterBattle = 0;
|
|
gBattlescriptCurrInstr += 3;
|
|
gBattleCommunication[MSG_DISPLAY] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atk13_printfromtable(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
const u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
ptr += gBattleCommunication[MULTISTRING_CHOOSER];
|
|
|
|
PrepareStringBattle(*ptr, gBattlerAttacker);
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
gBattleCommunication[MSG_DISPLAY] = 1;
|
|
}
|
|
}
|
|
|
|
static void atk14_printselectionstringfromtable(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
const u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
ptr += gBattleCommunication[MULTISTRING_CHOOSER];
|
|
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitPrintSelectionString(0, *ptr);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
gBattleCommunication[MSG_DISPLAY] = 1;
|
|
}
|
|
}
|
|
|
|
u8 GetBattlerTurnOrderNum(u8 bank)
|
|
{
|
|
s32 i;
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gBattleTurnOrder[i] == bank)
|
|
break;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
#define INCREMENT_RESET_RETURN \
|
|
{ \
|
|
gBattlescriptCurrInstr++; \
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = 0; \
|
|
return; \
|
|
}
|
|
|
|
#define RESET_RETURN \
|
|
{ \
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = 0; \
|
|
return; \
|
|
}
|
|
|
|
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)
|
|
{
|
|
gEffectBank = gBattlerAttacker; // bank 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
|
|
{
|
|
gEffectBank = gBattlerTarget;
|
|
gBattleScripting.battler = gBattlerAttacker;
|
|
}
|
|
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_SHIELD_DUST && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
&& !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 9)
|
|
INCREMENT_RESET_RETURN
|
|
|
|
if (gSideStatuses[GET_BATTLER_SIDE(gEffectBank)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
&& !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 7)
|
|
INCREMENT_RESET_RETURN
|
|
|
|
if (gBattleMons[gEffectBank].hp == 0
|
|
&& gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_PAYDAY
|
|
&& gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_STEAL_ITEM)
|
|
INCREMENT_RESET_RETURN
|
|
|
|
if (gBattleMons[gEffectBank].status2 & STATUS2_SUBSTITUTE && affectsUser != MOVE_EFFECT_AFFECTS_USER)
|
|
INCREMENT_RESET_RETURN
|
|
|
|
if (gBattleCommunication[MOVE_EFFECT_BYTE] <= 6) // status change
|
|
{
|
|
switch (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]])
|
|
{
|
|
case STATUS1_SLEEP:
|
|
// check active uproar
|
|
if (gBattleMons[gEffectBank].ability != ABILITY_SOUNDPROOF)
|
|
{
|
|
for (gActiveBattler = 0;
|
|
gActiveBattler < gBattlersCount && !(gBattleMons[gActiveBattler].status2 & STATUS2_UPROAR);
|
|
gActiveBattler++)
|
|
{}
|
|
}
|
|
else
|
|
gActiveBattler = gBattlersCount;
|
|
|
|
if (gBattleMons[gEffectBank].status1)
|
|
break;
|
|
if (gActiveBattler != gBattlersCount)
|
|
break;
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_VITAL_SPIRIT)
|
|
break;
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_INSOMNIA)
|
|
break;
|
|
|
|
CancelMultiTurnMoves(gEffectBank);
|
|
statusChanged = TRUE;
|
|
break;
|
|
case STATUS1_POISON:
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY
|
|
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
gLastUsedAbility = ABILITY_IMMUNITY;
|
|
RecordAbilityBattle(gEffectBank, 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;
|
|
}
|
|
RESET_RETURN
|
|
}
|
|
if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON
|
|
|| gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL)
|
|
&& (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_PSNPrevention;
|
|
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
RESET_RETURN
|
|
}
|
|
if (gBattleMons[gEffectBank].type1 == TYPE_POISON)
|
|
break;
|
|
if (gBattleMons[gEffectBank].type2 == TYPE_POISON)
|
|
break;
|
|
if (gBattleMons[gEffectBank].type1 == TYPE_STEEL)
|
|
break;
|
|
if (gBattleMons[gEffectBank].type2 == TYPE_STEEL)
|
|
break;
|
|
if (gBattleMons[gEffectBank].status1)
|
|
break;
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY)
|
|
break;
|
|
|
|
statusChanged = TRUE;
|
|
break;
|
|
case STATUS1_BURN:
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL
|
|
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
gLastUsedAbility = ABILITY_WATER_VEIL;
|
|
RecordAbilityBattle(gEffectBank, 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;
|
|
}
|
|
RESET_RETURN
|
|
}
|
|
if ((gBattleMons[gEffectBank].type1 == TYPE_FIRE
|
|
|| gBattleMons[gEffectBank].type2 == TYPE_FIRE)
|
|
&& (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_BRNPrevention;
|
|
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
RESET_RETURN
|
|
}
|
|
if (gBattleMons[gEffectBank].type1 == TYPE_FIRE)
|
|
break;
|
|
if (gBattleMons[gEffectBank].type2 == TYPE_FIRE)
|
|
break;
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL)
|
|
break;
|
|
if (gBattleMons[gEffectBank].status1)
|
|
break;
|
|
|
|
statusChanged = TRUE;
|
|
break;
|
|
case STATUS1_FREEZE:
|
|
if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY)
|
|
noSunCanFreeze = FALSE;
|
|
if (gBattleMons[gEffectBank].type1 == TYPE_ICE)
|
|
break;
|
|
if (gBattleMons[gEffectBank].type2 == TYPE_ICE)
|
|
break;
|
|
if (gBattleMons[gEffectBank].status1)
|
|
break;
|
|
if (noSunCanFreeze == 0)
|
|
break;
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_MAGMA_ARMOR)
|
|
break;
|
|
|
|
CancelMultiTurnMoves(gEffectBank);
|
|
statusChanged = TRUE;
|
|
break;
|
|
case STATUS1_PARALYSIS:
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_LIMBER)
|
|
{
|
|
if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)
|
|
{
|
|
gLastUsedAbility = ABILITY_LIMBER;
|
|
RecordAbilityBattle(gEffectBank, 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;
|
|
}
|
|
RESET_RETURN
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
if (gBattleMons[gEffectBank].status1)
|
|
break;
|
|
|
|
statusChanged = TRUE;
|
|
break;
|
|
case STATUS1_TOXIC_POISON:
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
gLastUsedAbility = ABILITY_IMMUNITY;
|
|
RecordAbilityBattle(gEffectBank, 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;
|
|
}
|
|
RESET_RETURN
|
|
}
|
|
if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON
|
|
|| gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL)
|
|
&& (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_PSNPrevention;
|
|
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
RESET_RETURN
|
|
}
|
|
if (gBattleMons[gEffectBank].status1)
|
|
break;
|
|
if (gBattleMons[gEffectBank].type1 != TYPE_POISON
|
|
&& gBattleMons[gEffectBank].type2 != TYPE_POISON
|
|
&& gBattleMons[gEffectBank].type1 != TYPE_STEEL
|
|
&& gBattleMons[gEffectBank].type2 != TYPE_STEEL)
|
|
{
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY)
|
|
break;
|
|
|
|
// It's redundant, because at this point we know the status1 value is 0.
|
|
gBattleMons[gEffectBank].status1 &= ~(STATUS1_TOXIC_POISON);
|
|
gBattleMons[gEffectBank].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[gEffectBank].status1 |= ((Random() & 3) + 2);
|
|
else
|
|
gBattleMons[gEffectBank].status1 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
|
|
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
|
|
gActiveBattler = gEffectBank;
|
|
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBank].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)
|
|
{
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = 0;
|
|
gBattlescriptCurrInstr++;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (gBattleMons[gEffectBank].status2 & sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]])
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
u8 side;
|
|
switch (gBattleCommunication[MOVE_EFFECT_BYTE])
|
|
{
|
|
case MOVE_EFFECT_CONFUSION:
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_OWN_TEMPO
|
|
|| gBattleMons[gEffectBank].status2 & STATUS2_CONFUSION)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gEffectBank].status2 |= (((Random()) % 0x4)) + 2;
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_FLINCH:
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_INNER_FOCUS)
|
|
{
|
|
if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)
|
|
{
|
|
gLastUsedAbility = ABILITY_INNER_FOCUS;
|
|
RecordAbilityBattle(gEffectBank, ABILITY_INNER_FOCUS);
|
|
gBattlescriptCurrInstr = BattleScript_FlinchPrevention;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GetBattlerTurnOrderNum(gEffectBank) > gCurrentTurnActionNumber)
|
|
gBattleMons[gEffectBank].status2 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_UPROAR:
|
|
if (!(gBattleMons[gEffectBank].status2 & STATUS2_UPROAR))
|
|
{
|
|
|
|
gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS;
|
|
gLockedMoves[gEffectBank] = gCurrentMove;
|
|
gBattleMons[gEffectBank].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[gEffectBank].status1)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = Random() % 3 + 3;
|
|
SetMoveEffect(FALSE, 0);
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_CHARGING:
|
|
gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS;
|
|
gLockedMoves[gEffectBank] = gCurrentMove;
|
|
gProtectStructs[gEffectBank].chargingTurn = 1;
|
|
gBattlescriptCurrInstr++;
|
|
break;
|
|
case MOVE_EFFECT_WRAP:
|
|
if (gBattleMons[gEffectBank].status2 & STATUS2_WRAPPED)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 3) << 0xD;
|
|
|
|
*(gBattleStruct->wrappedMove + gEffectBank * 2 + 0) = gCurrentMove;
|
|
*(gBattleStruct->wrappedMove + gEffectBank * 2 + 1) = gCurrentMove >> 8;
|
|
*(gBattleStruct->wrappedBy + gEffectBank) = 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, 0))
|
|
{
|
|
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, 0))
|
|
{
|
|
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, 0))
|
|
{
|
|
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, 0))
|
|
{
|
|
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[gEffectBank].status2 |= STATUS2_RECHARGE;
|
|
gDisableStructs[gEffectBank].rechargeCounter = 2;
|
|
gLockedMoves[gEffectBank] = gCurrentMove;
|
|
gBattlescriptCurrInstr++;
|
|
break;
|
|
case MOVE_EFFECT_RAGE:
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_RAGE;
|
|
gBattlescriptCurrInstr++;
|
|
break;
|
|
case MOVE_EFFECT_STEAL_ITEM:
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_x4000000)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
break;
|
|
}
|
|
|
|
side = GetBattlerSide(gBattlerAttacker);
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT
|
|
&& !(gBattleTypeFlags &
|
|
(BATTLE_TYPE_EREADER_TRAINER
|
|
| BATTLE_TYPE_FRONTIER
|
|
| BATTLE_TYPE_LINK
|
|
| BATTLE_TYPE_x2000000
|
|
| BATTLE_TYPE_SECRET_BASE)))
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else if (!(gBattleTypeFlags &
|
|
(BATTLE_TYPE_EREADER_TRAINER
|
|
| BATTLE_TYPE_FRONTIER
|
|
| BATTLE_TYPE_LINK
|
|
| BATTLE_TYPE_x2000000
|
|
| BATTLE_TYPE_SECRET_BASE))
|
|
&& (gWishFutureKnock.knockedOffPokes[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]]))
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else if (gBattleMons[gBattlerTarget].item
|
|
&& gBattleMons[gBattlerTarget].ability == ABILITY_STICKY_HOLD)
|
|
{
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_NoItemSteal;
|
|
|
|
gLastUsedAbility = gBattleMons[gBattlerTarget].ability;
|
|
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
|
|
}
|
|
else if (gBattleMons[gBattlerAttacker].item != 0
|
|
|| gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY
|
|
|| IS_ITEM_MAIL(gBattleMons[gBattlerTarget].item)
|
|
|| gBattleMons[gBattlerTarget].item == 0)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
u16* changedItem = &gBattleStruct->changedItems[gBattlerAttacker];
|
|
gLastUsedItem = *changedItem = gBattleMons[gBattlerTarget].item;
|
|
gBattleMons[gBattlerTarget].item = 0;
|
|
|
|
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_PARALYSIS: // Volt Tackle
|
|
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[gEffectBank].status2 & STATUS2_LOCK_CONFUSE)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS;
|
|
gLockedMoves[gEffectBank] = gCurrentMove;
|
|
gBattleMons[gEffectBank].status2 |= (((Random() & 1) + 2) << 0xA);
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_KNOCK_OFF:
|
|
if (gBattleMons[gEffectBank].ability == ABILITY_STICKY_HOLD)
|
|
{
|
|
if (gBattleMons[gEffectBank].item == 0)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gLastUsedAbility = ABILITY_STICKY_HOLD;
|
|
gBattlescriptCurrInstr = BattleScript_StickyHoldActivates;
|
|
RecordAbilityBattle(gEffectBank, ABILITY_STICKY_HOLD);
|
|
}
|
|
break;
|
|
}
|
|
if (gBattleMons[gEffectBank].item)
|
|
{
|
|
side = GetBattlerSide(gEffectBank);
|
|
|
|
gLastUsedItem = gBattleMons[gEffectBank].item;
|
|
gBattleMons[gEffectBank].item = 0;
|
|
gWishFutureKnock.knockedOffPokes[side] |= gBitTable[gBattlerPartyIndexes[gEffectBank]];
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_KnockedOff;
|
|
|
|
*(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 0) = 0;
|
|
*(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 1) = 0;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_SP_ATK_TWO_DOWN: // Overheat
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_SAtkDown2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = 0;
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
|
|
static void atk16_seteffectprimary(void)
|
|
{
|
|
SetMoveEffect(TRUE, 0);
|
|
}
|
|
|
|
static void atk17_seteffectsecondary(void)
|
|
{
|
|
SetMoveEffect(FALSE, 0);
|
|
}
|
|
|
|
static void atk18_clearstatusfromeffect(void)
|
|
{
|
|
gActiveBattler = GetBattleBank(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;
|
|
}
|
|
|
|
static void atk19_tryfaintmon(void)
|
|
{
|
|
const u8 *BS_ptr;
|
|
|
|
if (gBattlescriptCurrInstr[2] != 0)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
if (gHitMarker & HITMARKER_FAINTED(gActiveBattler))
|
|
{
|
|
BS_ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 3);
|
|
|
|
BattleScriptPop();
|
|
gBattlescriptCurrInstr = BS_ptr;
|
|
gSideStatuses[GetBattlerSide(gActiveBattler)] &= ~(SIDE_STATUS_SPIKES_DAMAGED);
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
u8 bank;
|
|
|
|
if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
bank = gBattlerTarget;
|
|
BS_ptr = BattleScript_FaintAttacker;
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = gBattlerTarget;
|
|
bank = 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, NULL);
|
|
}
|
|
if ((gHitMarker & HITMARKER_DESTINYBOND) && gBattleMons[gBattlerAttacker].hp != 0)
|
|
{
|
|
gHitMarker &= ~(HITMARKER_DESTINYBOND);
|
|
BattleScriptPush(gBattlescriptCurrInstr);
|
|
gBattleMoveDamage = gBattleMons[bank].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;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atk1A_dofaintanimation(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitFaintAnimation(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
}
|
|
|
|
static void atk1B_cleareffectsonfaint(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
if (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || gBattleMons[gActiveBattler].hp == 0)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
static void atk1C_jumpifstatus(void)
|
|
{
|
|
u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2);
|
|
const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6);
|
|
|
|
if (gBattleMons[bank].status1 & flags && gBattleMons[bank].hp)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
|
|
static void atk1D_jumpifstatus2(void)
|
|
{
|
|
u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2);
|
|
const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6);
|
|
|
|
if (gBattleMons[bank].status2 & flags && gBattleMons[bank].hp)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
|
|
static void atk1E_jumpifability(void)
|
|
{
|
|
u8 bank;
|
|
u8 ability = gBattlescriptCurrInstr[2];
|
|
const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3);
|
|
|
|
if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER_SIDE)
|
|
{
|
|
bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_BANK_SIDE, gBattlerAttacker, ability, 0, 0);
|
|
if (bank)
|
|
{
|
|
gLastUsedAbility = ability;
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
RecordAbilityBattle(bank - 1, gLastUsedAbility);
|
|
gBattleScripting.battlerWithAbility = bank - 1;
|
|
}
|
|
else
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
else if (gBattlescriptCurrInstr[1] == BS_GET_NOT_ATTACKER_SIDE)
|
|
{
|
|
bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gBattlerAttacker, ability, 0, 0);
|
|
if (bank)
|
|
{
|
|
gLastUsedAbility = ability;
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
RecordAbilityBattle(bank - 1, gLastUsedAbility);
|
|
gBattleScripting.battlerWithAbility = bank - 1;
|
|
}
|
|
else
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
else
|
|
{
|
|
bank = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
if (gBattleMons[bank].ability == ability)
|
|
{
|
|
gLastUsedAbility = ability;
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
RecordAbilityBattle(bank, gLastUsedAbility);
|
|
gBattleScripting.battlerWithAbility = bank;
|
|
}
|
|
else
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
}
|
|
|
|
static void atk1F_jumpifsideaffecting(void)
|
|
{
|
|
u8 side;
|
|
u16 flags;
|
|
const u8* jumpPtr;
|
|
|
|
if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER)
|
|
side = GET_BATTLER_SIDE(gBattlerAttacker);
|
|
else
|
|
side = GET_BATTLER_SIDE(gBattlerTarget);
|
|
|
|
flags = BS2ScriptRead16(gBattlescriptCurrInstr + 2);
|
|
jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 4);
|
|
|
|
if (gSideStatuses[side] & flags)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 8;
|
|
}
|
|
|
|
static void atk20_jumpifstat(void)
|
|
{
|
|
u8 ret = 0;
|
|
u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
u8 value = gBattleMons[bank].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 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5);
|
|
else
|
|
gBattlescriptCurrInstr += 9;
|
|
}
|
|
|
|
static void atk21_jumpifstatus3condition(void)
|
|
{
|
|
u32 flags;
|
|
const u8 *jumpPtr;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2);
|
|
jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7);
|
|
|
|
if (gBattlescriptCurrInstr[6])
|
|
{
|
|
if ((gStatuses3[gActiveBattler] & flags) != 0)
|
|
gBattlescriptCurrInstr += 11;
|
|
else
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
}
|
|
else
|
|
{
|
|
if ((gStatuses3[gActiveBattler] & flags) != 0)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 11;
|
|
}
|
|
}
|
|
|
|
static void atk22_jumpiftype(void)
|
|
{
|
|
u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
u8 type = gBattlescriptCurrInstr[2];
|
|
const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3);
|
|
|
|
if (gBattleMons[bank].type1 == type || gBattleMons[bank].type2 == type)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
|
|
static void atk23_getexp(void)
|
|
{
|
|
u16 item;
|
|
s32 i; // also used as stringId
|
|
u8 holdEffect;
|
|
s32 sentIn;
|
|
|
|
s32 viaExpShare = 0;
|
|
u16* exp = &gBattleStruct->expValue;
|
|
|
|
gBank1 = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
sentIn = gSentPokesToOpponent[(gBank1 & 2) >> 1];
|
|
|
|
switch (gBattleScripting.atk23_state)
|
|
{
|
|
case 0: // check if should receive exp at all
|
|
if (GetBattlerSide(gBank1) != B_SIDE_OPPONENT || (gBattleTypeFlags &
|
|
(BATTLE_TYPE_LINK
|
|
| BATTLE_TYPE_x2000000
|
|
| BATTLE_TYPE_x4000000
|
|
| BATTLE_TYPE_FRONTIER
|
|
| BATTLE_TYPE_SAFARI
|
|
| BATTLE_TYPE_BATTLE_TOWER
|
|
| BATTLE_TYPE_EREADER_TRAINER)))
|
|
{
|
|
gBattleScripting.atk23_state = 6; // goto last case
|
|
}
|
|
else
|
|
{
|
|
gBattleScripting.atk23_state++;
|
|
gBattleStruct->field_DF |= gBitTable[gBattlerPartyIndexes[gBank1]];
|
|
}
|
|
break;
|
|
case 1: // calculate experience points to redistribute
|
|
{
|
|
u16 calculatedExp;
|
|
s32 viaSentIn;
|
|
|
|
for (viaSentIn = 0, i = 0; i < 6; 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[gBank1].species].expYield * gBattleMons[gBank1].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->expGetterId = 0;
|
|
gBattleStruct->sentInPokes = sentIn;
|
|
}
|
|
// fall through
|
|
case 2: // set exp value to the poke in expgetter_id and print message
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
item = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], 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->expGetterId], MON_DATA_LEVEL) == MAX_MON_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) && gBattleMons[0].hp && !gBattleStruct->wildVictorySong)
|
|
{
|
|
BattleStopLowHpSound();
|
|
PlayBGM(0x161);
|
|
gBattleStruct->wildVictorySong++;
|
|
}
|
|
|
|
if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], 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->expGetterId]))
|
|
{
|
|
// check if the pokemon doesn't belong to the player
|
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gBattleStruct->expGetterId >= 3)
|
|
{
|
|
i = 0x149;
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = (gBattleMoveDamage * 150) / 100;
|
|
i = 0x14A;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
i = 0x149;
|
|
}
|
|
|
|
// get exp getter bank
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
{
|
|
if (!(gBattlerPartyIndexes[2] != gBattleStruct->expGetterId) && !(gAbsentBattlerFlags & gBitTable[2]))
|
|
gBattleStruct->expGetterBank = 2;
|
|
else
|
|
{
|
|
if (!(gAbsentBattlerFlags & gBitTable[0]))
|
|
gBattleStruct->expGetterBank = 0;
|
|
else
|
|
gBattleStruct->expGetterBank = 2;
|
|
}
|
|
}
|
|
else
|
|
gBattleStruct->expGetterBank = 0;
|
|
|
|
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattleStruct->expGetterBank, gBattleStruct->expGetterId)
|
|
|
|
// buffer 'gained' or 'gained a boosted'
|
|
PREPARE_STRING_BUFFER(gBattleTextBuff2, i)
|
|
|
|
PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff3, 5, gBattleMoveDamage)
|
|
|
|
PrepareStringBattle(STRINGID_PKMNGAINEDEXP, gBattleStruct->expGetterBank);
|
|
MonGainEVs(&gPlayerParty[gBattleStruct->expGetterId], gBattleMons[gBank1].species);
|
|
}
|
|
gBattleStruct->sentInPokes >>= 1;
|
|
gBattleScripting.atk23_state++;
|
|
}
|
|
}
|
|
break;
|
|
case 3: // Set stats and give exp
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gBattleBufferB[gBattleStruct->expGetterBank][0] = 0;
|
|
if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP) && GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL) != MAX_MON_LEVEL)
|
|
{
|
|
gBattleResources->statsBeforeLvlUp->hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP);
|
|
gBattleResources->statsBeforeLvlUp->atk = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK);
|
|
gBattleResources->statsBeforeLvlUp->def = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF);
|
|
gBattleResources->statsBeforeLvlUp->spd = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPEED);
|
|
gBattleResources->statsBeforeLvlUp->spAtk = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK);
|
|
gBattleResources->statsBeforeLvlUp->spDef = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPDEF);
|
|
|
|
gActiveBattler = gBattleStruct->expGetterBank;
|
|
BtlController_EmitExpUpdate(0, gBattleStruct->expGetterId, gBattleMoveDamage);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
gBattleScripting.atk23_state++;
|
|
}
|
|
break;
|
|
case 4: // lvl up if necessary
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = gBattleStruct->expGetterBank;
|
|
if (gBattleBufferB[gActiveBattler][0] == CONTROLLER_TWORETURNVALUES && gBattleBufferB[gActiveBattler][1] == RET_VALUE_LEVELLED_UP)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattlerPartyIndexes[gActiveBattler] == gBattleStruct->expGetterId)
|
|
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
|
|
|
|
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBattler, gBattleStruct->expGetterId)
|
|
|
|
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 3, GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL))
|
|
|
|
BattleScriptPushCursor();
|
|
gLeveledUpInBattle |= gBitTable[gBattleStruct->expGetterId];
|
|
gBattlescriptCurrInstr = BattleScript_LevelUp;
|
|
gBattleMoveDamage = (gBattleBufferB[gActiveBattler][2] | (gBattleBufferB[gActiveBattler][3] << 8));
|
|
AdjustFriendship(&gPlayerParty[gBattleStruct->expGetterId], 0);
|
|
|
|
// update battle mon structure after level up
|
|
if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterId && gBattleMons[0].hp)
|
|
{
|
|
gBattleMons[0].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL);
|
|
gBattleMons[0].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP);
|
|
gBattleMons[0].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP);
|
|
gBattleMons[0].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK);
|
|
gBattleMons[0].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF);
|
|
// Why is this duplicated?
|
|
gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPEED);
|
|
gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPEED);
|
|
|
|
gBattleMons[0].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK);
|
|
gBattleMons[0].spDefense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPDEF);
|
|
}
|
|
// What is else if?
|
|
if (gBattlerPartyIndexes[2] == gBattleStruct->expGetterId && gBattleMons[2].hp && (gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
|
{
|
|
gBattleMons[2].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL);
|
|
gBattleMons[2].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP);
|
|
gBattleMons[2].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP);
|
|
gBattleMons[2].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK);
|
|
gBattleMons[2].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF);
|
|
// Duplicated again, but this time there's no Sp Defense
|
|
gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPEED);
|
|
gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPEED);
|
|
|
|
gBattleMons[2].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], 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->expGetterId++;
|
|
if (gBattleStruct->expGetterId <= 5)
|
|
gBattleScripting.atk23_state = 2; // loop again
|
|
else
|
|
gBattleScripting.atk23_state = 6; // we're done
|
|
}
|
|
break;
|
|
case 6: // increment instruction
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
// not sure why gf clears the item and ability here
|
|
gBattleMons[gBank1].item = 0;
|
|
gBattleMons[gBank1].ability = 0;
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef NONMATCHING
|
|
static void atk24(void)
|
|
{
|
|
u16 HP_count = 0;
|
|
s32 i;
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId == STEVEN_PARTNER_ID)
|
|
{
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG))
|
|
HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)
|
|
&& (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->field_2A0 & gBitTable[i])))
|
|
{
|
|
HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (HP_count == 0)
|
|
gBattleOutcome |= B_OUTCOME_LOST;
|
|
|
|
for (HP_count = 0, i = 0; i < 6; i++)
|
|
{
|
|
if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES) && !GetMonData(&gEnemyParty[i], MON_DATA_IS_EGG)
|
|
&& (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->field_2A1 & gBitTable[i])))
|
|
{
|
|
HP_count += GetMonData(&gEnemyParty[i], MON_DATA_HP);
|
|
}
|
|
}
|
|
|
|
if (HP_count == 0)
|
|
gBattleOutcome |= B_OUTCOME_WON;
|
|
|
|
if (gBattleOutcome == 0 && (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)))
|
|
{
|
|
s32 foundPlayer;
|
|
s32 foundOpponent;
|
|
|
|
// Impossible to decompile loops.
|
|
for (foundPlayer = 0, i = 0; i < gBattlersCount; i += 2)
|
|
{
|
|
if (HITMARKER_UNK(i) & gHitMarker && !gSpecialStatuses[i].flag40)
|
|
foundPlayer++;
|
|
}
|
|
|
|
for (foundOpponent = 0, i = 1; i < gBattlersCount; i += 2)
|
|
{
|
|
if (HITMARKER_UNK(i) & gHitMarker && !gSpecialStatuses[i].flag40)
|
|
foundOpponent++;
|
|
}
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
|
{
|
|
if (foundOpponent + foundPlayer > 1)
|
|
gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
if (foundOpponent != 0 && foundPlayer != 0)
|
|
gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
#else
|
|
__attribute__((naked))
|
|
static void atk24(void)
|
|
{
|
|
asm("\n\
|
|
.syntax unified\n\
|
|
push {r4-r7,lr}\n\
|
|
mov r7, r8\n\
|
|
push {r7}\n\
|
|
movs r6, 0\n\
|
|
ldr r0, =gBattleControllerExecFlags\n\
|
|
ldr r0, [r0]\n\
|
|
cmp r0, 0\n\
|
|
beq _0804ACE2\n\
|
|
b _0804AF22\n\
|
|
_0804ACE2:\n\
|
|
ldr r0, =gBattleTypeFlags\n\
|
|
ldr r0, [r0]\n\
|
|
movs r1, 0x80\n\
|
|
lsls r1, 15\n\
|
|
ands r0, r1\n\
|
|
cmp r0, 0\n\
|
|
beq _0804AD48\n\
|
|
ldr r0, =gPartnerTrainerId\n\
|
|
ldrh r1, [r0]\n\
|
|
ldr r0, =0x00000c03\n\
|
|
cmp r1, r0\n\
|
|
bne _0804AD48\n\
|
|
movs r5, 0\n\
|
|
_0804ACFC:\n\
|
|
movs r0, 0x64\n\
|
|
adds r1, r5, 0\n\
|
|
muls r1, r0\n\
|
|
ldr r0, =gPlayerParty\n\
|
|
adds r4, r1, r0\n\
|
|
adds r0, r4, 0\n\
|
|
movs r1, 0xB\n\
|
|
bl GetMonData\n\
|
|
cmp r0, 0\n\
|
|
beq _0804AD2C\n\
|
|
adds r0, r4, 0\n\
|
|
movs r1, 0x2D\n\
|
|
bl GetMonData\n\
|
|
cmp r0, 0\n\
|
|
bne _0804AD2C\n\
|
|
adds r0, r4, 0\n\
|
|
movs r1, 0x39\n\
|
|
bl GetMonData\n\
|
|
adds r0, r6, r0\n\
|
|
lsls r0, 16\n\
|
|
lsrs r6, r0, 16\n\
|
|
_0804AD2C:\n\
|
|
adds r5, 0x1\n\
|
|
cmp r5, 0x2\n\
|
|
ble _0804ACFC\n\
|
|
b _0804ADA8\n\
|
|
.pool\n\
|
|
_0804AD48:\n\
|
|
movs r5, 0\n\
|
|
_0804AD4A:\n\
|
|
movs r0, 0x64\n\
|
|
adds r1, r5, 0\n\
|
|
muls r1, r0\n\
|
|
ldr r0, =gPlayerParty\n\
|
|
adds r4, r1, r0\n\
|
|
adds r0, r4, 0\n\
|
|
movs r1, 0xB\n\
|
|
bl GetMonData\n\
|
|
cmp r0, 0\n\
|
|
beq _0804ADA2\n\
|
|
adds r0, r4, 0\n\
|
|
movs r1, 0x2D\n\
|
|
bl GetMonData\n\
|
|
cmp r0, 0\n\
|
|
bne _0804ADA2\n\
|
|
ldr r0, =gBattleTypeFlags\n\
|
|
ldr r0, [r0]\n\
|
|
movs r1, 0x80\n\
|
|
lsls r1, 11\n\
|
|
ands r0, r1\n\
|
|
cmp r0, 0\n\
|
|
beq _0804AD94\n\
|
|
ldr r0, =gBattleStruct\n\
|
|
ldr r0, [r0]\n\
|
|
movs r1, 0xA8\n\
|
|
lsls r1, 2\n\
|
|
adds r0, r1\n\
|
|
ldrb r1, [r0]\n\
|
|
ldr r2, =gBitTable\n\
|
|
lsls r0, r5, 2\n\
|
|
adds r0, r2\n\
|
|
ldr r0, [r0]\n\
|
|
ands r1, r0\n\
|
|
cmp r1, 0\n\
|
|
bne _0804ADA2\n\
|
|
_0804AD94:\n\
|
|
adds r0, r4, 0\n\
|
|
movs r1, 0x39\n\
|
|
bl GetMonData\n\
|
|
adds r0, r6, r0\n\
|
|
lsls r0, 16\n\
|
|
lsrs r6, r0, 16\n\
|
|
_0804ADA2:\n\
|
|
adds r5, 0x1\n\
|
|
cmp r5, 0x5\n\
|
|
ble _0804AD4A\n\
|
|
_0804ADA8:\n\
|
|
cmp r6, 0\n\
|
|
bne _0804ADB6\n\
|
|
ldr r0, =gBattleOutcome\n\
|
|
ldrb r1, [r0]\n\
|
|
movs r2, 0x2\n\
|
|
orrs r1, r2\n\
|
|
strb r1, [r0]\n\
|
|
_0804ADB6:\n\
|
|
movs r6, 0\n\
|
|
movs r5, 0\n\
|
|
_0804ADBA:\n\
|
|
movs r0, 0x64\n\
|
|
adds r1, r5, 0\n\
|
|
muls r1, r0\n\
|
|
ldr r0, =gEnemyParty\n\
|
|
adds r4, r1, r0\n\
|
|
adds r0, r4, 0\n\
|
|
movs r1, 0xB\n\
|
|
bl GetMonData\n\
|
|
cmp r0, 0\n\
|
|
beq _0804AE10\n\
|
|
adds r0, r4, 0\n\
|
|
movs r1, 0x2D\n\
|
|
bl GetMonData\n\
|
|
cmp r0, 0\n\
|
|
bne _0804AE10\n\
|
|
ldr r0, =gBattleTypeFlags\n\
|
|
ldr r0, [r0]\n\
|
|
movs r1, 0x80\n\
|
|
lsls r1, 11\n\
|
|
ands r0, r1\n\
|
|
cmp r0, 0\n\
|
|
beq _0804AE02\n\
|
|
ldr r0, =gBattleStruct\n\
|
|
ldr r0, [r0]\n\
|
|
ldr r1, =0x000002a1\n\
|
|
adds r0, r1\n\
|
|
ldrb r1, [r0]\n\
|
|
ldr r2, =gBitTable\n\
|
|
lsls r0, r5, 2\n\
|
|
adds r0, r2\n\
|
|
ldr r0, [r0]\n\
|
|
ands r1, r0\n\
|
|
cmp r1, 0\n\
|
|
bne _0804AE10\n\
|
|
_0804AE02:\n\
|
|
adds r0, r4, 0\n\
|
|
movs r1, 0x39\n\
|
|
bl GetMonData\n\
|
|
adds r0, r6, r0\n\
|
|
lsls r0, 16\n\
|
|
lsrs r6, r0, 16\n\
|
|
_0804AE10:\n\
|
|
adds r5, 0x1\n\
|
|
cmp r5, 0x5\n\
|
|
ble _0804ADBA\n\
|
|
ldr r2, =gBattleOutcome\n\
|
|
cmp r6, 0\n\
|
|
bne _0804AE24\n\
|
|
ldrb r0, [r2]\n\
|
|
movs r1, 0x1\n\
|
|
orrs r0, r1\n\
|
|
strb r0, [r2]\n\
|
|
_0804AE24:\n\
|
|
ldrb r0, [r2]\n\
|
|
cmp r0, 0\n\
|
|
bne _0804AF1A\n\
|
|
ldr r0, =gBattleTypeFlags\n\
|
|
ldr r1, [r0]\n\
|
|
ldr r2, =0x02000002\n\
|
|
ands r1, r2\n\
|
|
mov r8, r0\n\
|
|
cmp r1, 0\n\
|
|
beq _0804AF1A\n\
|
|
movs r3, 0\n\
|
|
movs r5, 0\n\
|
|
ldr r0, =gBattlersCount\n\
|
|
ldrb r1, [r0]\n\
|
|
mov r12, r0\n\
|
|
ldr r7, =gBattlescriptCurrInstr\n\
|
|
cmp r3, r1\n\
|
|
bge _0804AE70\n\
|
|
ldr r0, =gHitMarker\n\
|
|
movs r6, 0x80\n\
|
|
lsls r6, 21\n\
|
|
ldr r4, [r0]\n\
|
|
adds r2, r1, 0\n\
|
|
ldr r1, =gSpecialStatuses\n\
|
|
_0804AE54:\n\
|
|
adds r0, r6, 0\n\
|
|
lsls r0, r5\n\
|
|
ands r0, r4\n\
|
|
cmp r0, 0\n\
|
|
beq _0804AE68\n\
|
|
ldrb r0, [r1]\n\
|
|
lsls r0, 25\n\
|
|
cmp r0, 0\n\
|
|
blt _0804AE68\n\
|
|
adds r3, 0x1\n\
|
|
_0804AE68:\n\
|
|
adds r1, 0x28\n\
|
|
adds r5, 0x2\n\
|
|
cmp r5, r2\n\
|
|
blt _0804AE54\n\
|
|
_0804AE70:\n\
|
|
movs r2, 0\n\
|
|
movs r5, 0x1\n\
|
|
mov r4, r12\n\
|
|
ldrb r1, [r4]\n\
|
|
cmp r5, r1\n\
|
|
bge _0804AEAA\n\
|
|
ldr r0, =gHitMarker\n\
|
|
movs r4, 0x80\n\
|
|
lsls r4, 21\n\
|
|
mov r12, r4\n\
|
|
ldr r6, [r0]\n\
|
|
ldr r0, =gSpecialStatuses\n\
|
|
adds r4, r1, 0\n\
|
|
adds r1, r0, 0\n\
|
|
adds r1, 0x14\n\
|
|
_0804AE8E:\n\
|
|
mov r0, r12\n\
|
|
lsls r0, r5\n\
|
|
ands r0, r6\n\
|
|
cmp r0, 0\n\
|
|
beq _0804AEA2\n\
|
|
ldrb r0, [r1]\n\
|
|
lsls r0, 25\n\
|
|
cmp r0, 0\n\
|
|
blt _0804AEA2\n\
|
|
adds r2, 0x1\n\
|
|
_0804AEA2:\n\
|
|
adds r1, 0x28\n\
|
|
adds r5, 0x2\n\
|
|
cmp r5, r4\n\
|
|
blt _0804AE8E\n\
|
|
_0804AEAA:\n\
|
|
mov r1, r8\n\
|
|
ldr r0, [r1]\n\
|
|
movs r1, 0x40\n\
|
|
ands r0, r1\n\
|
|
cmp r0, 0\n\
|
|
beq _0804AEF0\n\
|
|
adds r0, r2, r3\n\
|
|
cmp r0, 0x1\n\
|
|
bgt _0804AEF8\n\
|
|
b _0804AF12\n\
|
|
.pool\n\
|
|
_0804AEF0:\n\
|
|
cmp r2, 0\n\
|
|
beq _0804AF12\n\
|
|
cmp r3, 0\n\
|
|
beq _0804AF12\n\
|
|
_0804AEF8:\n\
|
|
ldr r2, [r7]\n\
|
|
ldrb r1, [r2, 0x1]\n\
|
|
ldrb r0, [r2, 0x2]\n\
|
|
lsls r0, 8\n\
|
|
adds r1, r0\n\
|
|
ldrb r0, [r2, 0x3]\n\
|
|
lsls r0, 16\n\
|
|
adds r1, r0\n\
|
|
ldrb r0, [r2, 0x4]\n\
|
|
lsls r0, 24\n\
|
|
adds r1, r0\n\
|
|
str r1, [r7]\n\
|
|
b _0804AF22\n\
|
|
_0804AF12:\n\
|
|
ldr r0, [r7]\n\
|
|
adds r0, 0x5\n\
|
|
str r0, [r7]\n\
|
|
b _0804AF22\n\
|
|
_0804AF1A:\n\
|
|
ldr r1, =gBattlescriptCurrInstr\n\
|
|
ldr r0, [r1]\n\
|
|
adds r0, 0x5\n\
|
|
str r0, [r1]\n\
|
|
_0804AF22:\n\
|
|
pop {r3}\n\
|
|
mov r8, r3\n\
|
|
pop {r4-r7}\n\
|
|
pop {r0}\n\
|
|
bx r0\n\
|
|
.pool\n\
|
|
.syntax divided");
|
|
}
|
|
|
|
#endif // NONMATCHING
|
|
|
|
static void MoveValuesCleanUp(void)
|
|
{
|
|
gMoveResultFlags = 0;
|
|
gBattleScripting.dmgMultiplier = 1;
|
|
gCritMultiplier = 1;
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = 0;
|
|
gBattleCommunication[6] = 0;
|
|
gHitMarker &= ~(HITMARKER_DESTINYBOND);
|
|
gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT);
|
|
}
|
|
|
|
static void atk25_movevaluescleanup(void)
|
|
{
|
|
MoveValuesCleanUp();
|
|
gBattlescriptCurrInstr += 1;
|
|
}
|
|
|
|
static void atk26_setmultihit(void)
|
|
{
|
|
gMultiHitCounter = gBattlescriptCurrInstr[1];
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk27_decrementmultihit(void)
|
|
{
|
|
if (--gMultiHitCounter == 0)
|
|
gBattlescriptCurrInstr += 5;
|
|
else
|
|
gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
|
|
static void atk28_goto(void)
|
|
{
|
|
gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
|
|
static void atk29_jumpifbyte(void)
|
|
{
|
|
u8 caseID = gBattlescriptCurrInstr[1];
|
|
const u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
u8 value = gBattlescriptCurrInstr[6];
|
|
const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7);
|
|
|
|
gBattlescriptCurrInstr += 11;
|
|
|
|
switch (caseID)
|
|
{
|
|
case CMP_EQUAL:
|
|
if (*memByte == value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_NOT_EQUAL:
|
|
if (*memByte != value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_GREATER_THAN:
|
|
if (*memByte > value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_LESS_THAN:
|
|
if (*memByte < value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_COMMON_BITS:
|
|
if (*memByte & value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_NO_COMMON_BITS:
|
|
if (!(*memByte & value))
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void atk2A_jumpifhalfword(void)
|
|
{
|
|
u8 caseID = gBattlescriptCurrInstr[1];
|
|
const u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 6);
|
|
const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 8);
|
|
|
|
gBattlescriptCurrInstr += 12;
|
|
|
|
switch (caseID)
|
|
{
|
|
case CMP_EQUAL:
|
|
if (*memHword == value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_NOT_EQUAL:
|
|
if (*memHword != value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_GREATER_THAN:
|
|
if (*memHword > value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_LESS_THAN:
|
|
if (*memHword < value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_COMMON_BITS:
|
|
if (*memHword & value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_NO_COMMON_BITS:
|
|
if (!(*memHword & value))
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void atk2B_jumpifword(void)
|
|
{
|
|
u8 caseID = gBattlescriptCurrInstr[1];
|
|
const u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
u32 value = BSScriptRead32(gBattlescriptCurrInstr + 6);
|
|
const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10);
|
|
|
|
gBattlescriptCurrInstr += 14;
|
|
|
|
switch (caseID)
|
|
{
|
|
case CMP_EQUAL:
|
|
if (*memWord == value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_NOT_EQUAL:
|
|
if (*memWord != value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_GREATER_THAN:
|
|
if (*memWord > value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_LESS_THAN:
|
|
if (*memWord < value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_COMMON_BITS:
|
|
if (*memWord & value)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
case CMP_NO_COMMON_BITS:
|
|
if (!(*memWord & value))
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void atk2C_jumpifarrayequal(void)
|
|
{
|
|
const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5);
|
|
u32 size = gBattlescriptCurrInstr[9];
|
|
const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10);
|
|
|
|
u8 i;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
if (*mem1 != *mem2)
|
|
{
|
|
gBattlescriptCurrInstr += 14;
|
|
break;
|
|
}
|
|
mem1++, mem2++;
|
|
}
|
|
|
|
if (i == size)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
}
|
|
|
|
static void atk2D_jumpifarraynotequal(void)
|
|
{
|
|
u8 equalBytes = 0;
|
|
const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5);
|
|
u32 size = gBattlescriptCurrInstr[9];
|
|
const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10);
|
|
|
|
u8 i;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
if (*mem1 == *mem2)
|
|
{
|
|
equalBytes++;
|
|
}
|
|
mem1++, mem2++;
|
|
}
|
|
|
|
if (equalBytes != size)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 14;
|
|
}
|
|
|
|
static void atk2E_setbyte(void)
|
|
{
|
|
u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
*memByte = gBattlescriptCurrInstr[5];
|
|
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void atk2F_addbyte(void)
|
|
{
|
|
u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
*memByte += gBattlescriptCurrInstr[5];
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void atk30_subbyte(void)
|
|
{
|
|
u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
*memByte -= gBattlescriptCurrInstr[5];
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void atk31_copyarray(void)
|
|
{
|
|
u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5);
|
|
s32 size = gBattlescriptCurrInstr[9];
|
|
|
|
s32 i;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
dest[i] = src[i];
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
|
|
static void atk32_copyarraywithindex(void)
|
|
{
|
|
u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5);
|
|
const u8* index = BS2ScriptReadPtr(gBattlescriptCurrInstr + 9);
|
|
s32 size = gBattlescriptCurrInstr[13];
|
|
|
|
s32 i;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
dest[i] = src[i + *index];
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 14;
|
|
}
|
|
|
|
static void atk33_orbyte(void)
|
|
{
|
|
u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
*memByte |= gBattlescriptCurrInstr[5];
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void atk34_orhalfword(void)
|
|
{
|
|
u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5);
|
|
|
|
*memHword |= val;
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
|
|
static void atk35_orword(void)
|
|
{
|
|
u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5);
|
|
|
|
*memWord |= val;
|
|
gBattlescriptCurrInstr += 9;
|
|
}
|
|
|
|
static void atk36_bicbyte(void)
|
|
{
|
|
u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
*memByte &= ~(gBattlescriptCurrInstr[5]);
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void atk37_bichalfword(void)
|
|
{
|
|
u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5);
|
|
|
|
*memHword &= ~val;
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
|
|
static void atk38_bicword(void)
|
|
{
|
|
u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5);
|
|
|
|
*memWord &= ~val;
|
|
gBattlescriptCurrInstr += 9;
|
|
}
|
|
|
|
static void atk39_pause(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 1);
|
|
if (++gPauseCounterBattle >= value)
|
|
{
|
|
gPauseCounterBattle = 0;
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atk3A_waitstate(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk3B_healthbar_update(void)
|
|
{
|
|
if (gBattlescriptCurrInstr[1] == BS_GET_TARGET)
|
|
gActiveBattler = gBattlerTarget;
|
|
else
|
|
gActiveBattler = gBattlerAttacker;
|
|
|
|
BtlController_EmitHealthBarUpdate(0, gBattleMoveDamage);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk3C_return(void)
|
|
{
|
|
BattleScriptPop();
|
|
}
|
|
|
|
static void atk3D_end(void)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
|
sub_81A5718(gBattlerAttacker);
|
|
|
|
gMoveResultFlags = 0;
|
|
gActiveBattler = 0;
|
|
gCurrentActionFuncId = 0xB;
|
|
}
|
|
|
|
static void atk3E_end2(void)
|
|
{
|
|
gActiveBattler = 0;
|
|
gCurrentActionFuncId = 0xB;
|
|
}
|
|
|
|
static void atk3F_end3(void) // pops the main function stack
|
|
{
|
|
BattleScriptPop();
|
|
if (gBattleResources->battleCallbackStack->size != 0)
|
|
gBattleResources->battleCallbackStack->size--;
|
|
gBattleMainFunc = gBattleResources->battleCallbackStack->function[gBattleResources->battleCallbackStack->size];
|
|
}
|
|
|
|
static void atk41_call(void)
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 5);
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
|
|
static void atk42_jumpiftype2(void)
|
|
{
|
|
u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
if (gBattlescriptCurrInstr[2] == gBattleMons[bank].type1 || gBattlescriptCurrInstr[2] == gBattleMons[bank].type2)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 3);
|
|
else
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
|
|
static void atk43_jumpifabilitypresent(void)
|
|
{
|
|
if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, gBattlescriptCurrInstr[1], 0, 0))
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void atk44_endselectionscript(void)
|
|
{
|
|
*(gBattlerAttacker + gBattleStruct->selectionScriptFinished) = TRUE;
|
|
}
|
|
|
|
static void atk45_playanimation(void)
|
|
{
|
|
const u16* argumentPtr;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3);
|
|
|
|
if (gBattlescriptCurrInstr[2] == B_ANIM_STATS_CHANGE
|
|
|| gBattlescriptCurrInstr[2] == B_ANIM_SNATCH_MOVE
|
|
|| gBattlescriptCurrInstr[2] == B_ANIM_SUBSTITUTE_FADE)
|
|
{
|
|
BtlController_EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
else if (gHitMarker & HITMARKER_NO_ANIMATIONS)
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 7);
|
|
gBattlescriptCurrInstr = BattleScript_Pausex20;
|
|
}
|
|
else if (gBattlescriptCurrInstr[2] == B_ANIM_RAIN_CONTINUES
|
|
|| gBattlescriptCurrInstr[2] == B_ANIM_SUN_CONTINUES
|
|
|| gBattlescriptCurrInstr[2] == B_ANIM_SANDSTORM_CONTINUES
|
|
|| gBattlescriptCurrInstr[2] == B_ANIM_HAIL_CONTINUES)
|
|
{
|
|
BtlController_EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
else if (gStatuses3[gActiveBattler] & STATUS3_SEMI_INVULNERABLE)
|
|
{
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
else
|
|
{
|
|
BtlController_EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
}
|
|
|
|
static void atk46_playanimation2(void) // animation Id is stored in the first pointer
|
|
{
|
|
const u16* argumentPtr;
|
|
const u8* animationIdPtr;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
animationIdPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6);
|
|
|
|
if (*animationIdPtr == B_ANIM_STATS_CHANGE
|
|
|| *animationIdPtr == B_ANIM_SNATCH_MOVE
|
|
|| *animationIdPtr == B_ANIM_SUBSTITUTE_FADE)
|
|
{
|
|
BtlController_EmitBattleAnimation(0, *animationIdPtr, *argumentPtr);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
else if (gHitMarker & HITMARKER_NO_ANIMATIONS)
|
|
{
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
else if (*animationIdPtr == B_ANIM_RAIN_CONTINUES
|
|
|| *animationIdPtr == B_ANIM_SUN_CONTINUES
|
|
|| *animationIdPtr == B_ANIM_SANDSTORM_CONTINUES
|
|
|| *animationIdPtr == B_ANIM_HAIL_CONTINUES)
|
|
{
|
|
BtlController_EmitBattleAnimation(0, *animationIdPtr, *argumentPtr);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
else if (gStatuses3[gActiveBattler] & STATUS3_SEMI_INVULNERABLE)
|
|
{
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
else
|
|
{
|
|
BtlController_EmitBattleAnimation(0, *animationIdPtr, *argumentPtr);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
}
|
|
|
|
static void atk47_setgraphicalstatchangevalues(void)
|
|
{
|
|
u8 value = 0;
|
|
switch (gBattleScripting.statChanger & 0xF0)
|
|
{
|
|
case 0x10: // +1
|
|
value = 0xF;
|
|
break;
|
|
case 0x20: // +2
|
|
value = 0x27;
|
|
break;
|
|
case 0x90: // -1
|
|
value = 0x16;
|
|
break;
|
|
case 0xA0: // -2
|
|
value = 0x2E;
|
|
break;
|
|
}
|
|
gBattleScripting.animArg1 = (gBattleScripting.statChanger & 0xF) + value - 1;
|
|
gBattleScripting.animArg2 = 0;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
#ifdef NONMATCHING
|
|
static void atk48_playstatchangeanimation(void)
|
|
{
|
|
u32 currStat = 0;
|
|
s16 statAnimId = 0;
|
|
s16 checkingStatAnimId = 0;
|
|
s32 changeableStats = 0;
|
|
u32 statsToCheck = 0;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
statsToCheck = gBattlescriptCurrInstr[2];
|
|
|
|
if (gBattlescriptCurrInstr[3] & ATK48_STAT_NEGATIVE) // goes down
|
|
{
|
|
checkingStatAnimId = (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) ? 0x2D : 0x15;
|
|
while (statsToCheck != 0)
|
|
{
|
|
if (statsToCheck & 1)
|
|
{
|
|
if (!(gBattlescriptCurrInstr[3] & ATK48_LOWER_FAIL_CHECK))
|
|
{
|
|
if (gBattleMons[gActiveBattler].statStages[currStat] > 0)
|
|
{
|
|
statAnimId = checkingStatAnimId;
|
|
changeableStats++;
|
|
}
|
|
}
|
|
else if (!gSideTimers[GET_BATTLER_SIDE(gActiveBattler)].mistTimer
|
|
&& gBattleMons[gActiveBattler].ability != ABILITY_CLEAR_BODY
|
|
&& gBattleMons[gActiveBattler].ability != ABILITY_WHITE_SMOKE
|
|
&& !(gBattleMons[gActiveBattler].ability == ABILITY_KEEN_EYE && currStat == STAT_STAGE_ACC)
|
|
&& !(gBattleMons[gActiveBattler].ability == ABILITY_HYPER_CUTTER && currStat == STAT_STAGE_ATK))
|
|
{
|
|
if (gBattleMons[gActiveBattler].statStages[currStat] > 0)
|
|
{
|
|
statAnimId = checkingStatAnimId;
|
|
changeableStats++;
|
|
}
|
|
}
|
|
}
|
|
statsToCheck >>= 1, checkingStatAnimId++, currStat++;
|
|
}
|
|
|
|
if (changeableStats > 1) // more than one stat, so the color is gray
|
|
{
|
|
if (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO)
|
|
statAnimId = 0x3A;
|
|
else
|
|
statAnimId = 0x39;
|
|
}
|
|
}
|
|
else // goes up
|
|
{
|
|
checkingStatAnimId = (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) ? 0x26 : 0xE;
|
|
while (statsToCheck != 0)
|
|
{
|
|
if (statsToCheck & 1 && gBattleMons[gActiveBattler].statStages[currStat] < 0xC)
|
|
{
|
|
statAnimId = checkingStatAnimId;
|
|
changeableStats++;
|
|
}
|
|
statsToCheck >>= 1, checkingStatAnimId += 1, currStat++;
|
|
}
|
|
|
|
if (changeableStats > 1) // more than one stat, so the color is gray
|
|
{
|
|
if (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO)
|
|
statAnimId = 0x38;
|
|
else
|
|
statAnimId = 0x37;
|
|
}
|
|
}
|
|
|
|
if (gBattlescriptCurrInstr[3] & ATK48_BIT_x4 && changeableStats < 2)
|
|
{
|
|
gBattlescriptCurrInstr += 4;
|
|
}
|
|
else if (changeableStats != 0 && gBattleScripting.field_1B == 0)
|
|
{
|
|
BtlController_EmitBattleAnimation(0, B_ANIM_STATS_CHANGE, statAnimId);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
if (gBattlescriptCurrInstr[3] & ATK48_BIT_x4 && changeableStats > 1)
|
|
gBattleScripting.field_1B = 1;
|
|
gBattlescriptCurrInstr += 4;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 4;
|
|
}
|
|
}
|
|
#else
|
|
__attribute__((naked))
|
|
static void atk48_playstatchangeanimation(void)
|
|
{
|
|
asm("\n\
|
|
.syntax unified\n\
|
|
push {r4-r7,lr}\n\
|
|
mov r7, r10\n\
|
|
mov r6, r9\n\
|
|
mov r5, r8\n\
|
|
push {r5-r7}\n\
|
|
sub sp, 0x4\n\
|
|
movs r7, 0\n\
|
|
movs r0, 0\n\
|
|
mov r8, r0\n\
|
|
movs r3, 0\n\
|
|
ldr r5, =gBattlescriptCurrInstr\n\
|
|
ldr r0, [r5]\n\
|
|
ldrb r0, [r0, 0x1]\n\
|
|
str r3, [sp]\n\
|
|
bl GetBattleBank\n\
|
|
ldr r2, =gActiveBattler\n\
|
|
strb r0, [r2]\n\
|
|
ldr r0, [r5]\n\
|
|
ldrb r4, [r0, 0x2]\n\
|
|
ldrb r1, [r0, 0x3]\n\
|
|
movs r0, 0x1\n\
|
|
ands r0, r1\n\
|
|
ldr r3, [sp]\n\
|
|
cmp r0, 0\n\
|
|
beq _0804BAEC\n\
|
|
movs r0, 0x2\n\
|
|
ands r0, r1\n\
|
|
movs r1, 0x15\n\
|
|
cmp r0, 0\n\
|
|
beq _0804BA18\n\
|
|
movs r1, 0x2D\n\
|
|
_0804BA18:\n\
|
|
cmp r4, 0\n\
|
|
beq _0804BAC0\n\
|
|
movs r0, 0x1\n\
|
|
mov r10, r0\n\
|
|
ldr r0, =gBattleMons + 0x18\n\
|
|
mov r9, r0\n\
|
|
lsls r5, r1, 16\n\
|
|
_0804BA26:\n\
|
|
adds r0, r4, 0\n\
|
|
mov r1, r10\n\
|
|
ands r0, r1\n\
|
|
cmp r0, 0\n\
|
|
beq _0804BAB2\n\
|
|
ldr r0, =gBattlescriptCurrInstr\n\
|
|
ldr r0, [r0]\n\
|
|
ldrb r1, [r0, 0x3]\n\
|
|
movs r0, 0x8\n\
|
|
ands r0, r1\n\
|
|
cmp r0, 0\n\
|
|
beq _0804BA58\n\
|
|
ldr r0, =gActiveBattler\n\
|
|
ldrb r1, [r0]\n\
|
|
movs r0, 0x58\n\
|
|
muls r0, r1\n\
|
|
adds r0, r7, r0\n\
|
|
b _0804BAA0\n\
|
|
.pool\n\
|
|
_0804BA58:\n\
|
|
ldr r6, =gActiveBattler\n\
|
|
ldrb r0, [r6]\n\
|
|
str r3, [sp]\n\
|
|
bl GetBattlerPosition\n\
|
|
mov r1, r10\n\
|
|
ands r1, r0\n\
|
|
lsls r0, r1, 1\n\
|
|
adds r0, r1\n\
|
|
lsls r0, 2\n\
|
|
ldr r1, =gSideTimers\n\
|
|
adds r0, r1\n\
|
|
ldrb r0, [r0, 0x4]\n\
|
|
ldr r3, [sp]\n\
|
|
cmp r0, 0\n\
|
|
bne _0804BAB2\n\
|
|
ldr r0, =gBattleMons\n\
|
|
ldrb r2, [r6]\n\
|
|
movs r1, 0x58\n\
|
|
muls r2, r1\n\
|
|
adds r0, r2, r0\n\
|
|
adds r0, 0x20\n\
|
|
ldrb r0, [r0]\n\
|
|
cmp r0, 0x1D\n\
|
|
beq _0804BAB2\n\
|
|
cmp r0, 0x49\n\
|
|
beq _0804BAB2\n\
|
|
cmp r0, 0x33\n\
|
|
bne _0804BA96\n\
|
|
cmp r7, 0x6\n\
|
|
beq _0804BAB2\n\
|
|
_0804BA96:\n\
|
|
cmp r0, 0x34\n\
|
|
bne _0804BA9E\n\
|
|
cmp r7, 0x1\n\
|
|
beq _0804BAB2\n\
|
|
_0804BA9E:\n\
|
|
adds r0, r7, r2\n\
|
|
_0804BAA0:\n\
|
|
add r0, r9\n\
|
|
ldrb r0, [r0]\n\
|
|
lsls r0, 24\n\
|
|
asrs r0, 24\n\
|
|
cmp r0, 0\n\
|
|
ble _0804BAB2\n\
|
|
lsrs r0, r5, 16\n\
|
|
mov r8, r0\n\
|
|
adds r3, 0x1\n\
|
|
_0804BAB2:\n\
|
|
lsrs r4, 1\n\
|
|
movs r1, 0x80\n\
|
|
lsls r1, 9\n\
|
|
adds r5, r1\n\
|
|
adds r7, 0x1\n\
|
|
cmp r4, 0\n\
|
|
bne _0804BA26\n\
|
|
_0804BAC0:\n\
|
|
ldr r0, =gBattlescriptCurrInstr\n\
|
|
mov r9, r0\n\
|
|
cmp r3, 0x1\n\
|
|
ble _0804BB4E\n\
|
|
ldr r0, [r0]\n\
|
|
ldrb r1, [r0, 0x3]\n\
|
|
movs r0, 0x2\n\
|
|
ands r0, r1\n\
|
|
movs r1, 0x39\n\
|
|
mov r8, r1\n\
|
|
cmp r0, 0\n\
|
|
beq _0804BB4E\n\
|
|
movs r0, 0x3A\n\
|
|
b _0804BB4C\n\
|
|
.pool\n\
|
|
_0804BAEC:\n\
|
|
movs r0, 0x2\n\
|
|
ands r0, r1\n\
|
|
movs r1, 0xE\n\
|
|
cmp r0, 0\n\
|
|
beq _0804BAF8\n\
|
|
movs r1, 0x26\n\
|
|
_0804BAF8:\n\
|
|
mov r9, r5\n\
|
|
cmp r4, 0\n\
|
|
beq _0804BB34\n\
|
|
ldr r6, =gBattleMons + 0x18\n\
|
|
adds r5, r2, 0\n\
|
|
lsls r2, r1, 16\n\
|
|
_0804BB04:\n\
|
|
movs r0, 0x1\n\
|
|
ands r0, r4\n\
|
|
cmp r0, 0\n\
|
|
beq _0804BB26\n\
|
|
ldrb r1, [r5]\n\
|
|
movs r0, 0x58\n\
|
|
muls r0, r1\n\
|
|
adds r0, r7, r0\n\
|
|
adds r0, r6\n\
|
|
ldrb r0, [r0]\n\
|
|
lsls r0, 24\n\
|
|
asrs r0, 24\n\
|
|
cmp r0, 0xB\n\
|
|
bgt _0804BB26\n\
|
|
lsrs r1, r2, 16\n\
|
|
mov r8, r1\n\
|
|
adds r3, 0x1\n\
|
|
_0804BB26:\n\
|
|
lsrs r4, 1\n\
|
|
movs r0, 0x80\n\
|
|
lsls r0, 9\n\
|
|
adds r2, r0\n\
|
|
adds r7, 0x1\n\
|
|
cmp r4, 0\n\
|
|
bne _0804BB04\n\
|
|
_0804BB34:\n\
|
|
cmp r3, 0x1\n\
|
|
ble _0804BB4E\n\
|
|
mov r1, r9\n\
|
|
ldr r0, [r1]\n\
|
|
ldrb r1, [r0, 0x3]\n\
|
|
movs r0, 0x2\n\
|
|
ands r0, r1\n\
|
|
movs r1, 0x37\n\
|
|
mov r8, r1\n\
|
|
cmp r0, 0\n\
|
|
beq _0804BB4E\n\
|
|
movs r0, 0x38\n\
|
|
_0804BB4C:\n\
|
|
mov r8, r0\n\
|
|
_0804BB4E:\n\
|
|
mov r1, r9\n\
|
|
ldr r2, [r1]\n\
|
|
ldrb r1, [r2, 0x3]\n\
|
|
movs r0, 0x4\n\
|
|
ands r0, r1\n\
|
|
cmp r0, 0\n\
|
|
beq _0804BB6C\n\
|
|
cmp r3, 0x1\n\
|
|
bgt _0804BB6C\n\
|
|
adds r0, r2, 0x4\n\
|
|
mov r1, r9\n\
|
|
b _0804BBBA\n\
|
|
.pool\n\
|
|
_0804BB6C:\n\
|
|
cmp r3, 0\n\
|
|
beq _0804BBB4\n\
|
|
ldr r4, =gBattleScripting\n\
|
|
ldrb r0, [r4, 0x1B]\n\
|
|
cmp r0, 0\n\
|
|
bne _0804BBB4\n\
|
|
movs r0, 0\n\
|
|
movs r1, 0x1\n\
|
|
mov r2, r8\n\
|
|
str r3, [sp]\n\
|
|
bl BtlController_EmitBattleAnimation\n\
|
|
ldr r0, =gActiveBattler\n\
|
|
ldrb r0, [r0]\n\
|
|
bl MarkBattlerForControllerExec\n\
|
|
ldr r0, =gBattlescriptCurrInstr\n\
|
|
ldr r0, [r0]\n\
|
|
ldrb r1, [r0, 0x3]\n\
|
|
movs r0, 0x4\n\
|
|
ands r0, r1\n\
|
|
ldr r3, [sp]\n\
|
|
cmp r0, 0\n\
|
|
beq _0804BBA4\n\
|
|
cmp r3, 0x1\n\
|
|
ble _0804BBA4\n\
|
|
movs r0, 0x1\n\
|
|
strb r0, [r4, 0x1B]\n\
|
|
_0804BBA4:\n\
|
|
ldr r1, =gBattlescriptCurrInstr\n\
|
|
b _0804BBB6\n\
|
|
.pool\n\
|
|
_0804BBB4:\n\
|
|
mov r1, r9\n\
|
|
_0804BBB6:\n\
|
|
ldr r0, [r1]\n\
|
|
adds r0, 0x4\n\
|
|
_0804BBBA:\n\
|
|
str r0, [r1]\n\
|
|
add sp, 0x4\n\
|
|
pop {r3-r5}\n\
|
|
mov r8, r3\n\
|
|
mov r9, r4\n\
|
|
mov r10, r5\n\
|
|
pop {r4-r7}\n\
|
|
pop {r0}\n\
|
|
bx r0\n\
|
|
.syntax divided");
|
|
}
|
|
#endif // NONMATCHING
|
|
|
|
#define ATK49_LAST_CASE 17
|
|
|
|
static void atk49_moveend(void)
|
|
{
|
|
s32 i;
|
|
bool32 effect;
|
|
u8 moveType;
|
|
u8 holdEffectAtk;
|
|
u16 *choicedMoveAtk;
|
|
u8 arg1, arg2;
|
|
u16 originallyUsedMove;
|
|
|
|
effect = FALSE;
|
|
|
|
if (gChosenMove == 0xFFFF)
|
|
originallyUsedMove = 0;
|
|
else
|
|
originallyUsedMove = gChosenMove;
|
|
|
|
arg1 = gBattlescriptCurrInstr[1];
|
|
arg2 = gBattlescriptCurrInstr[2];
|
|
|
|
if (gBattleMons[gBattlerAttacker].item == ITEM_ENIGMA_BERRY)
|
|
holdEffectAtk = gEnigmaBerries[gBattlerAttacker].holdEffect;
|
|
else
|
|
holdEffectAtk = ItemId_GetHoldEffect(gBattleMons[gBattlerAttacker].item);
|
|
|
|
choicedMoveAtk = &gBattleStruct->choicedMove[gBattlerAttacker];
|
|
|
|
GET_MOVE_TYPE(gCurrentMove, moveType);
|
|
|
|
do
|
|
{
|
|
switch (gBattleScripting.atk49_state)
|
|
{
|
|
case 0: // rage check
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_RAGE
|
|
&& gBattleMons[gBattlerTarget].hp != 0 && gBattlerAttacker != gBattlerTarget
|
|
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)
|
|
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && TARGET_TURN_DAMAGED
|
|
&& gBattleMoves[gCurrentMove].power && gBattleMons[gBattlerTarget].statStages[STAT_STAGE_ATK] <= 0xB)
|
|
{
|
|
gBattleMons[gBattlerTarget].statStages[STAT_STAGE_ATK]++;
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_RageIsBuilding;
|
|
effect = TRUE;
|
|
}
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 1: // defrosting check
|
|
if (gBattleMons[gBattlerTarget].status1 & STATUS1_FREEZE
|
|
&& gBattleMons[gBattlerTarget].hp != 0 && gBattlerAttacker != gBattlerTarget
|
|
&& gSpecialStatuses[gBattlerTarget].moveturnLostHP_special
|
|
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && moveType == TYPE_FIRE)
|
|
{
|
|
gBattleMons[gBattlerTarget].status1 &= ~(STATUS1_FREEZE);
|
|
gActiveBattler = gBattlerTarget;
|
|
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBattlerTarget].status1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_DefrostedViaFireMove;
|
|
effect = TRUE;
|
|
}
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 2: // target synchronize
|
|
if (AbilityBattleEffects(ABILITYEFFECT_SYNCHRONIZE, gBattlerTarget, 0, 0, 0))
|
|
effect = TRUE;
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 3: // contact abilities
|
|
if (AbilityBattleEffects(ABILITYEFFECT_CONTACT, gBattlerTarget, 0, 0, 0))
|
|
effect = TRUE;
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 4: // status immunities
|
|
if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, 0, 0, 0, 0))
|
|
effect = TRUE; // it loops through all banks, so we increment after its done with all banks
|
|
else
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 5: // attacker synchronize
|
|
if (AbilityBattleEffects(ABILITYEFFECT_ATK_SYNCHRONIZE, gBattlerAttacker, 0, 0, 0))
|
|
effect = TRUE;
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 6: // update choice band move
|
|
if (!(gHitMarker & HITMARKER_OBEYS) || holdEffectAtk != HOLD_EFFECT_CHOICE_BAND
|
|
|| gChosenMove == MOVE_STRUGGLE || (*choicedMoveAtk != 0 && *choicedMoveAtk != 0xFFFF))
|
|
goto LOOP;
|
|
if (gChosenMove == MOVE_BATON_PASS && !(gMoveResultFlags & MOVE_RESULT_FAILED))
|
|
{
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
}
|
|
*choicedMoveAtk = gChosenMove;
|
|
LOOP:
|
|
{
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].moves[i] == *choicedMoveAtk)
|
|
break;
|
|
}
|
|
if (i == 4)
|
|
*choicedMoveAtk = 0;
|
|
|
|
gBattleScripting.atk49_state++;
|
|
}
|
|
break;
|
|
case 7: // changed held items
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
u16* changedItem = &gBattleStruct->changedItems[i];
|
|
if (*changedItem != 0)
|
|
{
|
|
gBattleMons[i].item = *changedItem;
|
|
*changedItem = 0;
|
|
}
|
|
}
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 11: // item effects for all banks
|
|
if (ItemBattleEffects(3, 0, FALSE))
|
|
effect = TRUE;
|
|
else
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 12: // king's rock and shell bell
|
|
if (ItemBattleEffects(4, 0, FALSE))
|
|
effect = TRUE;
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 8: // make attacker sprite invisible
|
|
if (gStatuses3[gBattlerAttacker] & (STATUS3_SEMI_INVULNERABLE)
|
|
&& gHitMarker & HITMARKER_NO_ANIMATIONS)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitSpriteInvisibility(0, TRUE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattleScripting.atk49_state++;
|
|
return;
|
|
}
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 9: // make attacker sprite visible
|
|
if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT
|
|
|| !(gStatuses3[gBattlerAttacker] & (STATUS3_SEMI_INVULNERABLE))
|
|
|| WasUnableToUseMove(gBattlerAttacker))
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitSpriteInvisibility(0, FALSE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gStatuses3[gBattlerAttacker] &= ~(STATUS3_SEMI_INVULNERABLE);
|
|
gSpecialStatuses[gBattlerAttacker].restoredBankSprite = 1;
|
|
gBattleScripting.atk49_state++;
|
|
return;
|
|
}
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 10: // make target sprite visible
|
|
if (!gSpecialStatuses[gBattlerTarget].restoredBankSprite && gBattlerTarget < gBattlersCount
|
|
&& !(gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE))
|
|
{
|
|
gActiveBattler = gBattlerTarget;
|
|
BtlController_EmitSpriteInvisibility(0, FALSE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gStatuses3[gBattlerTarget] &= ~(STATUS3_SEMI_INVULNERABLE);
|
|
gBattleScripting.atk49_state++;
|
|
return;
|
|
}
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 13: // update substitute
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gDisableStructs[i].substituteHP == 0)
|
|
gBattleMons[i].status2 &= ~(STATUS2_SUBSTITUTE);
|
|
}
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 14: // This case looks interesting, although I am not certain what it does. Probably fine tunes edge cases.
|
|
if (gHitMarker & HITMARKER_PURSUIT_TRAP)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
gBattlerAttacker = gBattlerTarget;
|
|
gBattlerTarget = gActiveBattler;
|
|
gHitMarker &= ~(HITMARKER_PURSUIT_TRAP);
|
|
}
|
|
if (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED)
|
|
{
|
|
gLastPrintedMoves[gBattlerAttacker] = gChosenMove;
|
|
}
|
|
if (!(gAbsentBattlerFlags & gBitTable[gBattlerAttacker])
|
|
&& !(gBattleStruct->field_91 & gBitTable[gBattlerAttacker])
|
|
&& gBattleMoves[originallyUsedMove].effect != EFFECT_BATON_PASS)
|
|
{
|
|
if (gHitMarker & HITMARKER_OBEYS)
|
|
{
|
|
gLastMoves[gBattlerAttacker] = gChosenMove;
|
|
gLastResultingMoves[gBattlerAttacker] = gCurrentMove;
|
|
}
|
|
else
|
|
{
|
|
gLastMoves[gBattlerAttacker] = 0xFFFF;
|
|
gLastResultingMoves[gBattlerAttacker] = 0xFFFF;
|
|
}
|
|
|
|
if (!(gHitMarker & HITMARKER_FAINTED(gBattlerTarget)))
|
|
gLastHitBy[gBattlerTarget] = gBattlerAttacker;
|
|
|
|
if (gHitMarker & HITMARKER_OBEYS && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
|
|
{
|
|
if (gChosenMove == 0xFFFF)
|
|
{
|
|
gLastLandedMoves[gBattlerTarget] = gChosenMove;
|
|
}
|
|
else
|
|
{
|
|
gLastLandedMoves[gBattlerTarget] = gCurrentMove;
|
|
GET_MOVE_TYPE(gCurrentMove, gLastHitByType[gBattlerTarget]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gLastLandedMoves[gBattlerTarget] = 0xFFFF;
|
|
}
|
|
}
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 15: // mirror move
|
|
if (!(gAbsentBattlerFlags & gBitTable[gBattlerAttacker]) && !(gBattleStruct->field_91 & gBitTable[gBattlerAttacker])
|
|
&& gBattleMoves[originallyUsedMove].flags & FLAG_MIRROR_MOVE_AFFECTED && gHitMarker & HITMARKER_OBEYS
|
|
&& gBattlerAttacker != gBattlerTarget && !(gHitMarker & HITMARKER_FAINTED(gBattlerTarget))
|
|
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
|
|
{
|
|
u8 target, attacker;
|
|
|
|
*(gBattleStruct->mirrorMoves + gBattlerTarget * 2 + 0) = gChosenMove;
|
|
*(gBattleStruct->mirrorMoves + gBattlerTarget * 2 + 1) = gChosenMove >> 8;
|
|
|
|
target = gBattlerTarget;
|
|
attacker = gBattlerAttacker;
|
|
*(attacker * 2 + target * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = gChosenMove;
|
|
|
|
target = gBattlerTarget;
|
|
attacker = gBattlerAttacker;
|
|
*(attacker * 2 + target * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = gChosenMove >> 8;
|
|
}
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case 16: //
|
|
if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
|
&& !gProtectStructs[gBattlerAttacker].chargingTurn && gBattleMoves[gCurrentMove].target == MOVE_TARGET_BOTH
|
|
&& !(gHitMarker & HITMARKER_NO_ATTACKSTRING))
|
|
{
|
|
u8 bank = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget)));
|
|
if (gBattleMons[bank].hp != 0)
|
|
{
|
|
gBattlerTarget = bank;
|
|
gHitMarker |= HITMARKER_NO_ATTACKSTRING;
|
|
gBattleScripting.atk49_state = 0;
|
|
MoveValuesCleanUp();
|
|
BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]);
|
|
gBattlescriptCurrInstr = BattleScript_82DB87D;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
gHitMarker |= HITMARKER_NO_ATTACKSTRING;
|
|
}
|
|
}
|
|
gBattleScripting.atk49_state++;
|
|
break;
|
|
case ATK49_LAST_CASE:
|
|
break;
|
|
}
|
|
|
|
if (arg1 == 1 && effect == FALSE)
|
|
gBattleScripting.atk49_state = ATK49_LAST_CASE;
|
|
if (arg1 == 2 && arg2 == gBattleScripting.atk49_state)
|
|
gBattleScripting.atk49_state = ATK49_LAST_CASE;
|
|
|
|
} while (gBattleScripting.atk49_state != ATK49_LAST_CASE && effect == FALSE);
|
|
|
|
if (gBattleScripting.atk49_state == ATK49_LAST_CASE && effect == FALSE)
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
|
|
static void atk4A_typecalc2(void)
|
|
{
|
|
u8 flags = 0;
|
|
s32 i = 0;
|
|
u8 moveType = gBattleMoves[gCurrentMove].type;
|
|
|
|
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;
|
|
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;
|
|
}
|
|
else
|
|
{
|
|
i += 3;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (TYPE_EFFECT_ATK_TYPE(i) == moveType)
|
|
{
|
|
// check type1
|
|
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type1)
|
|
{
|
|
if (TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_NO_EFFECT)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE;
|
|
break;
|
|
}
|
|
if (TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_NOT_EFFECTIVE)
|
|
{
|
|
flags |= MOVE_RESULT_NOT_VERY_EFFECTIVE;
|
|
}
|
|
if (TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_SUPER_EFFECTIVE)
|
|
{
|
|
flags |= MOVE_RESULT_SUPER_EFFECTIVE;
|
|
}
|
|
}
|
|
// check type2
|
|
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2
|
|
&& TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_NO_EFFECT)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE;
|
|
break;
|
|
}
|
|
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2
|
|
&& gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2
|
|
&& TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_NOT_EFFECTIVE)
|
|
{
|
|
flags |= MOVE_RESULT_NOT_VERY_EFFECTIVE;
|
|
}
|
|
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2
|
|
&& gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2
|
|
&& TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_SUPER_EFFECTIVE)
|
|
{
|
|
flags |= MOVE_RESULT_SUPER_EFFECTIVE;
|
|
}
|
|
}
|
|
}
|
|
i += 3;
|
|
}
|
|
}
|
|
|
|
if (gBattleMons[gBattlerTarget].ability == ABILITY_WONDER_GUARD
|
|
&& !(flags & MOVE_RESULT_NO_EFFECT)
|
|
&& AttacksThisTurn(gBattlerAttacker, gCurrentMove) == 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[gCurrentMove].power)
|
|
{
|
|
gLastUsedAbility = ABILITY_WONDER_GUARD;
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gLastLandedMoves[gBattlerTarget] = 0;
|
|
gBattleCommunication[6] = 3;
|
|
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
|
|
}
|
|
if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE)
|
|
gProtectStructs[gBattlerAttacker].targetNotAffected = 1;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk4B_returnatktoball(void)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
if (!(gHitMarker & HITMARKER_FAINTED(gActiveBattler)))
|
|
{
|
|
BtlController_EmitReturnMonToBall(0, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk4C_getswitchedmondata(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
gBattlerPartyIndexes[gActiveBattler] = *(gBattleStruct->monToSwitchIntoId + gActiveBattler);
|
|
|
|
BtlController_EmitGetMonData(0, REQUEST_ALL_BATTLE, gBitTable[gBattlerPartyIndexes[gActiveBattler]]);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk4D_switchindataupdate(void)
|
|
{
|
|
struct BattlePokemon oldData;
|
|
s32 i;
|
|
u8 *monData;
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
oldData = gBattleMons[gActiveBattler];
|
|
monData = (u8*)(&gBattleMons[gActiveBattler]);
|
|
|
|
for (i = 0; i < sizeof(struct BattlePokemon); i++)
|
|
{
|
|
monData[i] = gBattleBufferB[gActiveBattler][4 + i];
|
|
}
|
|
|
|
gBattleMons[gActiveBattler].type1 = gBaseStats[gBattleMons[gActiveBattler].species].type1;
|
|
gBattleMons[gActiveBattler].type2 = gBaseStats[gBattleMons[gActiveBattler].species].type2;
|
|
gBattleMons[gActiveBattler].ability = GetAbilityBySpecies(gBattleMons[gActiveBattler].species, gBattleMons[gActiveBattler].altAbility);
|
|
|
|
// check knocked off item
|
|
i = GetBattlerSide(gActiveBattler);
|
|
if (gWishFutureKnock.knockedOffPokes[i] & gBitTable[gBattlerPartyIndexes[gActiveBattler]])
|
|
{
|
|
gBattleMons[gActiveBattler].item = 0;
|
|
}
|
|
|
|
if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS)
|
|
{
|
|
for (i = 0; i < BATTLE_STATS_NO; i++)
|
|
{
|
|
gBattleMons[gActiveBattler].statStages[i] = oldData.statStages[i];
|
|
}
|
|
gBattleMons[gActiveBattler].status2 = oldData.status2;
|
|
}
|
|
|
|
SwitchInClearSetData();
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_PALACE && gBattleMons[gActiveBattler].maxHP / 2 >= gBattleMons[gActiveBattler].hp
|
|
&& gBattleMons[gActiveBattler].hp != 0 && !(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP))
|
|
{
|
|
gBattleStruct->field_92 |= gBitTable[gActiveBattler];
|
|
}
|
|
|
|
gBattleScripting.battler = gActiveBattler;
|
|
|
|
PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gActiveBattler, gBattlerPartyIndexes[gActiveBattler]);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk4E_switchinanim(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT
|
|
&& !(gBattleTypeFlags & (BATTLE_TYPE_LINK
|
|
| BATTLE_TYPE_EREADER_TRAINER
|
|
| BATTLE_TYPE_x2000000
|
|
| BATTLE_TYPE_x4000000
|
|
| BATTLE_TYPE_FRONTIER)))
|
|
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality);
|
|
|
|
gAbsentBattlerFlags &= ~(gBitTable[gActiveBattler]);
|
|
|
|
BtlController_EmitSwitchInAnim(0, gBattlerPartyIndexes[gActiveBattler], gBattlescriptCurrInstr[2]);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
|
sub_81A56B4();
|
|
}
|
|
|
|
static void atk4F_jumpifcantswitch(void)
|
|
{
|
|
s32 val = 0;
|
|
s32 compareVar = 0;
|
|
struct Pokemon *party = NULL;
|
|
s32 r7 = 0;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1] & ~(ATK4F_DONT_CHECK_STATUSES));
|
|
|
|
if (!(gBattlescriptCurrInstr[1] & ATK4F_DONT_CHECK_STATUSES)
|
|
&& ((gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
|
|
|| (gStatuses3[gActiveBattler] & STATUS3_ROOTED)))
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
|
{
|
|
#ifndef NONMATCHING
|
|
asm("":::"r5");
|
|
#endif // NONMATCHING
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT)
|
|
party = gEnemyParty;
|
|
else
|
|
party = gPlayerParty;
|
|
|
|
val = 0;
|
|
if (2 & gActiveBattler)
|
|
val = 3;
|
|
|
|
for (compareVar = val + 3; val < compareVar; val++)
|
|
{
|
|
if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE
|
|
&& !GetMonData(&party[val], MON_DATA_IS_EGG)
|
|
&& GetMonData(&party[val], MON_DATA_HP) != 0
|
|
&& gBattlerPartyIndexes[gActiveBattler] != val)
|
|
break;
|
|
}
|
|
|
|
if (val == compareVar)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_x800000)
|
|
{
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
|
|
{
|
|
party = gPlayerParty;
|
|
|
|
val = 0;
|
|
if (sub_806D82C(GetBattlerMultiplayerId(gActiveBattler)) == TRUE)
|
|
val = 3;
|
|
}
|
|
else
|
|
{
|
|
party = gEnemyParty;
|
|
|
|
if (gActiveBattler == 1)
|
|
val = 0;
|
|
else
|
|
val = 3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT)
|
|
party = gEnemyParty;
|
|
else
|
|
party = gPlayerParty;
|
|
|
|
|
|
val = 0;
|
|
if (sub_806D82C(GetBattlerMultiplayerId(gActiveBattler)) == TRUE)
|
|
val = 3;
|
|
}
|
|
|
|
for (compareVar = val + 3; val < compareVar; val++)
|
|
{
|
|
if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE
|
|
&& !GetMonData(&party[val], MON_DATA_IS_EGG)
|
|
&& GetMonData(&party[val], MON_DATA_HP) != 0
|
|
&& gBattlerPartyIndexes[gActiveBattler] != val)
|
|
break;
|
|
}
|
|
|
|
if (val == compareVar)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT)
|
|
{
|
|
party = gEnemyParty;
|
|
|
|
val = 0;
|
|
if (gActiveBattler == 3)
|
|
val = 3;
|
|
|
|
for (compareVar = val + 3; val < compareVar; val++)
|
|
{
|
|
if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE
|
|
&& !GetMonData(&party[val], MON_DATA_IS_EGG)
|
|
&& GetMonData(&party[val], MON_DATA_HP) != 0
|
|
&& gBattlerPartyIndexes[gActiveBattler] != val)
|
|
break;
|
|
}
|
|
|
|
if (val == compareVar)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else
|
|
{
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT)
|
|
{
|
|
r7 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
compareVar = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
|
else
|
|
compareVar = r7;
|
|
|
|
party = gEnemyParty;
|
|
}
|
|
else
|
|
{
|
|
r7 = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
compareVar = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
|
else
|
|
compareVar = r7;
|
|
|
|
party = gPlayerParty;
|
|
}
|
|
for (val = 0; val < 6; val++)
|
|
{
|
|
if (GetMonData(&party[val], MON_DATA_HP) != 0
|
|
&& GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE
|
|
&& !GetMonData(&party[val], MON_DATA_IS_EGG)
|
|
&& val != gBattlerPartyIndexes[r7] && val != gBattlerPartyIndexes[compareVar])
|
|
break;
|
|
}
|
|
|
|
if (val == 6)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
}
|
|
|
|
static void sub_804CF10(u8 arg0)
|
|
{
|
|
*(gBattleStruct->field_58 + gActiveBattler) = gBattlerPartyIndexes[gActiveBattler];
|
|
*(gBattleStruct->monToSwitchIntoId + gActiveBattler) = 6;
|
|
gBattleStruct->field_93 &= ~(gBitTable[gActiveBattler]);
|
|
|
|
BtlController_EmitChoosePokemon(0, 1, arg0, 0, gBattleStruct->field_60[gActiveBattler]);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
|
|
static void atk50_openpartyscreen(void)
|
|
{
|
|
u32 flags;
|
|
u8 hitmarkerFaintBits;
|
|
u8 bank;
|
|
const u8 *jumpPtr;
|
|
|
|
bank = 0;
|
|
flags = 0;
|
|
jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
|
|
if (gBattlescriptCurrInstr[1] == 5)
|
|
{
|
|
if ((gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI)) != BATTLE_TYPE_DOUBLE)
|
|
{
|
|
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
|
|
{
|
|
if (gHitMarker & HITMARKER_FAINTED(gActiveBattler))
|
|
{
|
|
if (sub_80423F4(gActiveBattler, 6, 6))
|
|
{
|
|
gAbsentBattlerFlags |= gBitTable[gActiveBattler];
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else if (!gSpecialStatuses[gActiveBattler].flag40)
|
|
{
|
|
sub_804CF10(6);
|
|
gSpecialStatuses[gActiveBattler].flag40 = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
{
|
|
u8 flag40_0, flag40_1, flag40_2, flag40_3;
|
|
|
|
hitmarkerFaintBits = gHitMarker >> 0x1C;
|
|
|
|
if (gBitTable[0] & hitmarkerFaintBits)
|
|
{
|
|
gActiveBattler = 0;
|
|
if (sub_80423F4(0, 6, 6))
|
|
{
|
|
gAbsentBattlerFlags |= gBitTable[gActiveBattler];
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
BtlController_EmitCmd42(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else if (!gSpecialStatuses[gActiveBattler].flag40)
|
|
{
|
|
sub_804CF10(gBattleStruct->monToSwitchIntoId[2]);
|
|
gSpecialStatuses[gActiveBattler].flag40 = 1;
|
|
}
|
|
else
|
|
{
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
flags |= 1;
|
|
}
|
|
}
|
|
if (gBitTable[2] & hitmarkerFaintBits && !(gBitTable[0] & hitmarkerFaintBits))
|
|
{
|
|
gActiveBattler = 2;
|
|
if (sub_80423F4(2, 6, 6))
|
|
{
|
|
gAbsentBattlerFlags |= gBitTable[gActiveBattler];
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
BtlController_EmitCmd42(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else if (!gSpecialStatuses[gActiveBattler].flag40)
|
|
{
|
|
sub_804CF10(gBattleStruct->monToSwitchIntoId[0]);
|
|
gSpecialStatuses[gActiveBattler].flag40 = 1;
|
|
}
|
|
else if (!(flags & 1))
|
|
{
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
if (gBitTable[1] & hitmarkerFaintBits)
|
|
{
|
|
gActiveBattler = 1;
|
|
if (sub_80423F4(1, 6, 6))
|
|
{
|
|
gAbsentBattlerFlags |= gBitTable[gActiveBattler];
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
BtlController_EmitCmd42(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else if (!gSpecialStatuses[gActiveBattler].flag40)
|
|
{
|
|
sub_804CF10(gBattleStruct->monToSwitchIntoId[3]);
|
|
gSpecialStatuses[gActiveBattler].flag40 = 1;
|
|
}
|
|
else
|
|
{
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
flags |= 2;
|
|
}
|
|
}
|
|
if (gBitTable[3] & hitmarkerFaintBits && !(gBitTable[1] & hitmarkerFaintBits))
|
|
{
|
|
gActiveBattler = 3;
|
|
if (sub_80423F4(3, 6, 6))
|
|
{
|
|
gAbsentBattlerFlags |= gBitTable[gActiveBattler];
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
BtlController_EmitCmd42(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else if (!gSpecialStatuses[gActiveBattler].flag40)
|
|
{
|
|
sub_804CF10(gBattleStruct->monToSwitchIntoId[1]);
|
|
gSpecialStatuses[gActiveBattler].flag40 = 1;
|
|
}
|
|
else if (!(flags & 2))
|
|
{
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
|
|
flag40_0 = gSpecialStatuses[0].flag40;
|
|
if (!flag40_0)
|
|
{
|
|
flag40_2 = gSpecialStatuses[2].flag40;
|
|
if (!flag40_2 && hitmarkerFaintBits != 0)
|
|
{
|
|
if (gAbsentBattlerFlags & gBitTable[0])
|
|
gActiveBattler = 2;
|
|
else
|
|
gActiveBattler = 0;
|
|
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
|
|
}
|
|
flag40_1 = gSpecialStatuses[1].flag40;
|
|
if (!flag40_1)
|
|
{
|
|
flag40_3 = gSpecialStatuses[3].flag40;
|
|
if (!flag40_3 && hitmarkerFaintBits != 0)
|
|
{
|
|
if (gAbsentBattlerFlags & gBitTable[1])
|
|
gActiveBattler = 3;
|
|
else
|
|
gActiveBattler = 1;
|
|
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
}
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else if (gBattlescriptCurrInstr[1] == 6)
|
|
{
|
|
if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
{
|
|
hitmarkerFaintBits = gHitMarker >> 0x1C;
|
|
if (gBitTable[2] & hitmarkerFaintBits && gBitTable[0] & hitmarkerFaintBits)
|
|
{
|
|
gActiveBattler = 2;
|
|
if (sub_80423F4(2, gBattleBufferB[0][1], 6))
|
|
{
|
|
gAbsentBattlerFlags |= gBitTable[gActiveBattler];
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
BtlController_EmitCmd42(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else if (!gSpecialStatuses[gActiveBattler].flag40)
|
|
{
|
|
sub_804CF10(gBattleStruct->monToSwitchIntoId[0]);
|
|
gSpecialStatuses[gActiveBattler].flag40 = 1;
|
|
}
|
|
}
|
|
if (gBitTable[3] & hitmarkerFaintBits && hitmarkerFaintBits & gBitTable[1])
|
|
{
|
|
gActiveBattler = 3;
|
|
if (sub_80423F4(3, gBattleBufferB[1][1], 6))
|
|
{
|
|
gAbsentBattlerFlags |= gBitTable[gActiveBattler];
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
BtlController_EmitCmd42(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else if (!gSpecialStatuses[gActiveBattler].flag40)
|
|
{
|
|
sub_804CF10(gBattleStruct->monToSwitchIntoId[1]);
|
|
gSpecialStatuses[gActiveBattler].flag40 = 1;
|
|
}
|
|
}
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
hitmarkerFaintBits = gHitMarker >> 0x1C;
|
|
|
|
gBank1 = 0;
|
|
while (1)
|
|
{
|
|
if (gBitTable[gBank1] & hitmarkerFaintBits)
|
|
break;
|
|
if (gBank1 >= gBattlersCount)
|
|
break;
|
|
gBank1++;
|
|
}
|
|
|
|
if (gBank1 == gBattlersCount)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
}
|
|
else
|
|
{
|
|
if (gBattlescriptCurrInstr[1] & 0x80)
|
|
hitmarkerFaintBits = 0; // used here as the caseId for the EmitChoose function
|
|
else
|
|
hitmarkerFaintBits = 1;
|
|
|
|
bank = GetBattleBank(gBattlescriptCurrInstr[1] & ~(0x80));
|
|
if (gSpecialStatuses[bank].flag40)
|
|
{
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else if (sub_80423F4(bank, 6, 6))
|
|
{
|
|
gActiveBattler = bank;
|
|
gAbsentBattlerFlags |= gBitTable[gActiveBattler];
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = bank;
|
|
*(gBattleStruct->field_58 + gActiveBattler) = gBattlerPartyIndexes[gActiveBattler];
|
|
*(gBattleStruct->monToSwitchIntoId + gActiveBattler) = 6;
|
|
gBattleStruct->field_93 &= ~(gBitTable[gActiveBattler]);
|
|
|
|
BtlController_EmitChoosePokemon(0, hitmarkerFaintBits, *(gBattleStruct->monToSwitchIntoId + (gActiveBattler ^ 2)), 0, gBattleStruct->field_60[gActiveBattler]);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 6;
|
|
|
|
if (GetBattlerPosition(gActiveBattler) == 0 && gBattleResults.playerSwitchesCounter < 0xFF)
|
|
gBattleResults.playerSwitchesCounter++;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
|
{
|
|
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
|
|
{
|
|
if (gActiveBattler != bank)
|
|
{
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(GetBattlerPosition(bank) ^ BIT_SIDE);
|
|
if (gAbsentBattlerFlags & gBitTable[gActiveBattler])
|
|
gActiveBattler ^= BIT_FLANK;
|
|
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atk51_switchhandleorder(void)
|
|
{
|
|
s32 i;
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
switch (gBattlescriptCurrInstr[2])
|
|
{
|
|
case 0:
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gBattleBufferB[i][0] == 0x22)
|
|
{
|
|
*(gBattleStruct->monToSwitchIntoId + i) = gBattleBufferB[i][1];
|
|
if (!(gBattleStruct->field_93 & gBitTable[i]))
|
|
{
|
|
RecordedBattle_SetBattlerAction(i, gBattleBufferB[i][1]);
|
|
gBattleStruct->field_93 |= gBitTable[i];
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
|
sub_803BDA0(gActiveBattler);
|
|
break;
|
|
case 2:
|
|
if (!(gBattleStruct->field_93 & gBitTable[gActiveBattler]))
|
|
{
|
|
RecordedBattle_SetBattlerAction(gActiveBattler, gBattleBufferB[gActiveBattler][1]);
|
|
gBattleStruct->field_93 |= gBitTable[gActiveBattler];
|
|
}
|
|
// fall through
|
|
case 3:
|
|
gBattleCommunication[0] = gBattleBufferB[gActiveBattler][1];
|
|
*(gBattleStruct->monToSwitchIntoId + gActiveBattler) = gBattleBufferB[gActiveBattler][1];
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
|
{
|
|
*(gActiveBattler * 3 + (u8*)(gBattleStruct->field_60) + 0) &= 0xF;
|
|
*(gActiveBattler * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBattler][2] & 0xF0);
|
|
*(gActiveBattler * 3 + (u8*)(gBattleStruct->field_60) + 1) = gBattleBufferB[gActiveBattler][3];
|
|
|
|
*((gActiveBattler ^ BIT_FLANK) * 3 + (u8*)(gBattleStruct->field_60) + 0) &= (0xF0);
|
|
*((gActiveBattler ^ BIT_FLANK) * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBattler][2] & 0xF0) >> 4;
|
|
*((gActiveBattler ^ BIT_FLANK) * 3 + (u8*)(gBattleStruct->field_60) + 2) = gBattleBufferB[gActiveBattler][3];
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
|
{
|
|
sub_80571DC(gActiveBattler, *(gBattleStruct->monToSwitchIntoId + gActiveBattler));
|
|
}
|
|
else
|
|
{
|
|
sub_803BDA0(gActiveBattler);
|
|
}
|
|
|
|
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].species)
|
|
PREPARE_MON_NICK_BUFFER(gBattleTextBuff2, gActiveBattler, gBattleBufferB[gActiveBattler][1])
|
|
|
|
break;
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
|
|
static void atk52_switchineffects(void)
|
|
{
|
|
s32 i;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
sub_803FA70(gActiveBattler);
|
|
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
gSpecialStatuses[gActiveBattler].flag40 = 0;
|
|
|
|
if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES_DAMAGED)
|
|
&& (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES)
|
|
&& gBattleMons[gActiveBattler].type1 != TYPE_FLYING
|
|
&& gBattleMons[gActiveBattler].type2 != TYPE_FLYING
|
|
&& gBattleMons[gActiveBattler].ability != ABILITY_LEVITATE)
|
|
{
|
|
u8 spikesDmg;
|
|
|
|
gSideStatuses[GetBattlerSide(gActiveBattler)] |= SIDE_STATUS_SPIKES_DAMAGED;
|
|
|
|
gBattleMons[gActiveBattler].status2 &= ~(STATUS2_DESTINY_BOND);
|
|
gHitMarker &= ~(HITMARKER_DESTINYBOND);
|
|
|
|
spikesDmg = (5 - gSideTimers[GetBattlerSide(gActiveBattler)].spikesAmount) * 2;
|
|
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / (spikesDmg);
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
|
|
gBattleScripting.battler = gActiveBattler;
|
|
BattleScriptPushCursor();
|
|
|
|
if (gBattlescriptCurrInstr[1] == BS_GET_TARGET)
|
|
gBattlescriptCurrInstr = BattleScript_SpikesOnTarget;
|
|
else if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER)
|
|
gBattlescriptCurrInstr = BattleScript_SpikesOnAttacker;
|
|
else
|
|
gBattlescriptCurrInstr = BattleScript_SpikesOngBank1;
|
|
}
|
|
else
|
|
{
|
|
if (gBattleMons[gActiveBattler].ability == ABILITY_TRUANT && !gDisableStructs[gActiveBattler].truantUnknownBit)
|
|
gDisableStructs[gActiveBattler].truantCounter = 1;
|
|
|
|
gDisableStructs[gActiveBattler].truantUnknownBit = 0;
|
|
|
|
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBattler, 0, 0, 0) == 0 &&
|
|
ItemBattleEffects(0, gActiveBattler, 0) == 0)
|
|
{
|
|
gSideStatuses[GetBattlerSide(gActiveBattler)] &= ~(SIDE_STATUS_SPIKES_DAMAGED);
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gBattleTurnOrder[i] == gActiveBattler)
|
|
gActionsByTurnOrder[i] = B_ACTION_CANCEL_PARTNER;
|
|
}
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
u16* hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBattlerSide(i)];
|
|
*hpOnSwitchout = gBattleMons[i].hp;
|
|
}
|
|
|
|
if (gBattlescriptCurrInstr[1] == 5)
|
|
{
|
|
u32 hitmarkerFaintBits = gHitMarker >> 0x1C;
|
|
|
|
gBank1++;
|
|
while (1)
|
|
{
|
|
if (hitmarkerFaintBits & gBitTable[gBank1] && !(gAbsentBattlerFlags & gBitTable[gBank1]))
|
|
break;
|
|
if (gBank1 >= gBattlersCount)
|
|
break;
|
|
gBank1++;
|
|
}
|
|
}
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atk53_trainerslidein(void)
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitTrainerSlide(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk54_playse(void)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitPlaySE(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1));
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
|
|
static void atk55_fanfare(void)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitPlayFanfareOrBGM(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1), FALSE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
|
|
static void atk56_playfaintcry(void)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitFaintingCry(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk57(void)
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
BtlController_EmitCmd55(0, gBattleOutcome);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 1;
|
|
}
|
|
|
|
static void atk58_returntoball(void)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitReturnMonToBall(0, 1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk59_handlelearnnewmove(void)
|
|
{
|
|
const u8 *jumpPtr1 = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
const u8 *jumpPtr2 = BSScriptReadPtr(gBattlescriptCurrInstr + 5);
|
|
|
|
u16 ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], gBattlescriptCurrInstr[9]);
|
|
while (ret == 0xFFFE)
|
|
ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], 0);
|
|
|
|
if (ret == 0)
|
|
{
|
|
gBattlescriptCurrInstr = jumpPtr2;
|
|
}
|
|
else if (ret == 0xFFFF)
|
|
{
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
|
|
if (gBattlerPartyIndexes[gActiveBattler] == gBattleStruct->expGetterId
|
|
&& !(gBattleMons[gActiveBattler].status2 & STATUS2_TRANSFORMED))
|
|
{
|
|
GiveMoveToBattleMon(&gBattleMons[gActiveBattler], ret);
|
|
}
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
|
if (gBattlerPartyIndexes[gActiveBattler] == gBattleStruct->expGetterId
|
|
&& !(gBattleMons[gActiveBattler].status2 & STATUS2_TRANSFORMED))
|
|
{
|
|
GiveMoveToBattleMon(&gBattleMons[gActiveBattler], ret);
|
|
}
|
|
}
|
|
|
|
gBattlescriptCurrInstr = jumpPtr1;
|
|
}
|
|
}
|
|
|
|
static void atk5A_yesnoboxlearnmove(void)
|
|
{
|
|
gActiveBattler = 0;
|
|
|
|
switch (gBattleScripting.learnMoveState)
|
|
{
|
|
case 0:
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
|
|
BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
|
|
gBattleScripting.learnMoveState++;
|
|
gBattleCommunication[CURSOR_POSITION] = 0;
|
|
BattleCreateYesNoCursorAt(0);
|
|
break;
|
|
case 1:
|
|
if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
|
gBattleCommunication[CURSOR_POSITION] = 0;
|
|
BattleCreateYesNoCursorAt(0);
|
|
}
|
|
if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
|
gBattleCommunication[CURSOR_POSITION] = 1;
|
|
BattleCreateYesNoCursorAt(1);
|
|
}
|
|
if (gMain.newKeys & A_BUTTON)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
if (gBattleCommunication[1] == 0)
|
|
{
|
|
HandleBattleWindow(0x18, 0x8, 0x1D, 0xD, WINDOW_CLEAR);
|
|
BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
|
|
gBattleScripting.learnMoveState++;
|
|
}
|
|
else
|
|
{
|
|
gBattleScripting.learnMoveState = 5;
|
|
}
|
|
}
|
|
else if (gMain.newKeys & B_BUTTON)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
gBattleScripting.learnMoveState = 5;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (!gPaletteFade.active)
|
|
{
|
|
FreeAllWindowBuffers();
|
|
sub_81BFA38(gPlayerParty, gBattleStruct->expGetterId, gPlayerPartyCount - 1, ReshowBattleScreenAfterMenu, gMoveToLearn);
|
|
gBattleScripting.learnMoveState++;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (!gPaletteFade.active && gMain.callback2 == BattleMainCB2)
|
|
{
|
|
gBattleScripting.learnMoveState++;
|
|
}
|
|
break;
|
|
case 4:
|
|
if (!gPaletteFade.active && gMain.callback2 == BattleMainCB2)
|
|
{
|
|
u8 movePosition = sub_81C1B94();
|
|
if (movePosition == 4)
|
|
{
|
|
gBattleScripting.learnMoveState = 5;
|
|
}
|
|
else
|
|
{
|
|
u16 moveId = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MOVE1 + movePosition);
|
|
if (IsHMMove2(moveId))
|
|
{
|
|
PrepareStringBattle(STRINGID_HMMOVESCANTBEFORGOTTEN, gActiveBattler);
|
|
gBattleScripting.learnMoveState = 6;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff2, moveId)
|
|
|
|
RemoveMonPPBonus(&gPlayerParty[gBattleStruct->expGetterId], movePosition);
|
|
SetMonMoveSlot(&gPlayerParty[gBattleStruct->expGetterId], gMoveToLearn, movePosition);
|
|
|
|
if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterId
|
|
&& !(gBattleMons[0].status2 & STATUS2_TRANSFORMED)
|
|
&& !(gDisableStructs[0].unk18_b & gBitTable[movePosition]))
|
|
{
|
|
RemoveBattleMonPPBonus(&gBattleMons[0], movePosition);
|
|
SetBattleMonMoveSlot(&gBattleMons[0], gMoveToLearn, movePosition);
|
|
}
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
|
&& gBattlerPartyIndexes[2] == gBattleStruct->expGetterId
|
|
&& !(gBattleMons[2].status2 & STATUS2_TRANSFORMED)
|
|
&& !(gDisableStructs[2].unk18_b & gBitTable[movePosition]))
|
|
{
|
|
RemoveBattleMonPPBonus(&gBattleMons[2], movePosition);
|
|
SetBattleMonMoveSlot(&gBattleMons[2], gMoveToLearn, movePosition);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 5:
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
|
|
gBattlescriptCurrInstr += 5;
|
|
break;
|
|
case 6:
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gBattleScripting.learnMoveState = 2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void atk5B_yesnoboxstoplearningmove(void)
|
|
{
|
|
switch (gBattleScripting.learnMoveState)
|
|
{
|
|
case 0:
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
|
|
BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
|
|
gBattleScripting.learnMoveState++;
|
|
gBattleCommunication[CURSOR_POSITION] = 0;
|
|
BattleCreateYesNoCursorAt(0);
|
|
break;
|
|
case 1:
|
|
if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
|
gBattleCommunication[CURSOR_POSITION] = 0;
|
|
BattleCreateYesNoCursorAt(0);
|
|
}
|
|
if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
|
gBattleCommunication[CURSOR_POSITION] = 1;
|
|
BattleCreateYesNoCursorAt(1);
|
|
}
|
|
if (gMain.newKeys & A_BUTTON)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
|
|
if (gBattleCommunication[1] != 0)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
|
|
HandleBattleWindow(0x18, 0x8, 0x1D, 0xD, WINDOW_CLEAR);
|
|
}
|
|
else if (gMain.newKeys & B_BUTTON)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
HandleBattleWindow(0x18, 0x8, 0x1D, 0xD, WINDOW_CLEAR);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void atk5C_hitanimation(void)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
|
{
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
else if (!(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE) || !(gBattleMons[gActiveBattler].status2 & STATUS2_SUBSTITUTE) || gDisableStructs[gActiveBattler].substituteHP == 0)
|
|
{
|
|
BtlController_EmitHitAnimation(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
}
|
|
|
|
static u32 GetTrainerMoneyToGive(u16 trainerId)
|
|
{
|
|
u32 i = 0;
|
|
u32 lastMonLevel = 0;
|
|
u32 moneyReward = 0;
|
|
|
|
if (trainerId == SECRET_BASE_OPPONENT)
|
|
{
|
|
moneyReward = 20 * gBattleResources->secretBase->party.levels[0] * gBattleStruct->moneyMultiplier;
|
|
}
|
|
else
|
|
{
|
|
switch (gTrainers[trainerId].partyFlags)
|
|
{
|
|
case 0:
|
|
{
|
|
const struct TrainerMonNoItemDefaultMoves *party = gTrainers[trainerId].party.NoItemDefaultMoves;
|
|
lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl;
|
|
}
|
|
break;
|
|
case F_TRAINER_PARTY_CUSTOM_MOVESET:
|
|
{
|
|
const struct TrainerMonNoItemCustomMoves *party = gTrainers[trainerId].party.NoItemCustomMoves;
|
|
lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl;
|
|
}
|
|
break;
|
|
case F_TRAINER_PARTY_HELD_ITEM:
|
|
{
|
|
const struct TrainerMonItemDefaultMoves *party = gTrainers[trainerId].party.ItemDefaultMoves;
|
|
lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl;
|
|
}
|
|
break;
|
|
case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM:
|
|
{
|
|
const struct TrainerMonItemCustomMoves *party = gTrainers[trainerId].party.ItemCustomMoves;
|
|
lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl;
|
|
}
|
|
break;
|
|
}
|
|
|
|
for (; gTrainerMoneyTable[i].classId != 0xFF; i++)
|
|
{
|
|
if (gTrainerMoneyTable[i].classId == gTrainers[trainerId].trainerClass)
|
|
break;
|
|
}
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
|
|
moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * gTrainerMoneyTable[i].value;
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * 2 * gTrainerMoneyTable[i].value;
|
|
else
|
|
moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * gTrainerMoneyTable[i].value;
|
|
}
|
|
|
|
return moneyReward;
|
|
}
|
|
|
|
static void atk5D_getmoneyreward(void)
|
|
{
|
|
u32 moneyReward = GetTrainerMoneyToGive(gTrainerBattleOpponent_A);
|
|
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
|
|
moneyReward += GetTrainerMoneyToGive(gTrainerBattleOpponent_B);
|
|
|
|
AddMoney(&gSaveBlock1Ptr->money, moneyReward);
|
|
|
|
PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, moneyReward)
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk5E(void)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
switch (gBattleCommunication[0])
|
|
{
|
|
case 0:
|
|
BtlController_EmitGetMonData(0, REQUEST_ALL_BATTLE, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattleCommunication[0]++;
|
|
break;
|
|
case 1:
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
s32 i;
|
|
struct BattlePokemon* bufferPoke = (struct BattlePokemon*) &gBattleBufferB[gActiveBattler][4];
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
gBattleMons[gActiveBattler].moves[i] = bufferPoke->moves[i];
|
|
gBattleMons[gActiveBattler].pp[i] = bufferPoke->pp[i];
|
|
}
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void atk5F(void)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
gBattlerAttacker = gBattlerTarget;
|
|
gBattlerTarget = gActiveBattler;
|
|
|
|
if (gHitMarker & HITMARKER_PURSUIT_TRAP)
|
|
gHitMarker &= ~(HITMARKER_PURSUIT_TRAP);
|
|
else
|
|
gHitMarker |= HITMARKER_PURSUIT_TRAP;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk60_incrementgamestat(void)
|
|
{
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
|
IncrementGameStat(gBattlescriptCurrInstr[1]);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk61_drawpartystatussummary(void)
|
|
{
|
|
s32 i;
|
|
struct Pokemon* party;
|
|
struct HpAndStatus hpStatuses[6];
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
|
|
party = gPlayerParty;
|
|
else
|
|
party = gEnemyParty;
|
|
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_NONE
|
|
|| GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_EGG)
|
|
{
|
|
hpStatuses[i].hp = 0xFFFF;
|
|
hpStatuses[i].status = 0;
|
|
}
|
|
else
|
|
{
|
|
hpStatuses[i].hp = GetMonData(&party[i], MON_DATA_HP);
|
|
hpStatuses[i].status = GetMonData(&party[i], MON_DATA_STATUS);
|
|
}
|
|
}
|
|
|
|
BtlController_EmitDrawPartyStatusSummary(0, hpStatuses, 1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk62(void)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitCmd49(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk63_jumptorandomattack(void)
|
|
{
|
|
if (gBattlescriptCurrInstr[1])
|
|
gCurrentMove = gRandomMove;
|
|
else
|
|
gChosenMove = gCurrentMove = gRandomMove;
|
|
|
|
gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect];
|
|
}
|
|
|
|
static void atk64_statusanimation(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
if (!(gStatuses3[gActiveBattler] & STATUS3_SEMI_INVULNERABLE)
|
|
&& gDisableStructs[gActiveBattler].substituteHP == 0
|
|
&& !(gHitMarker & HITMARKER_NO_ANIMATIONS))
|
|
{
|
|
BtlController_EmitStatusAnimation(0, FALSE, gBattleMons[gActiveBattler].status1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
}
|
|
|
|
static void atk65_status2animation(void)
|
|
{
|
|
u32 wantedToAnimate;
|
|
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
wantedToAnimate = BSScriptRead32(gBattlescriptCurrInstr + 2);
|
|
if (!(gStatuses3[gActiveBattler] & STATUS3_SEMI_INVULNERABLE)
|
|
&& gDisableStructs[gActiveBattler].substituteHP == 0
|
|
&& !(gHitMarker & HITMARKER_NO_ANIMATIONS))
|
|
{
|
|
BtlController_EmitStatusAnimation(0, TRUE, gBattleMons[gActiveBattler].status2 & wantedToAnimate);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
}
|
|
|
|
static void atk66_chosenstatusanimation(void)
|
|
{
|
|
u32 wantedStatus;
|
|
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
wantedStatus = BSScriptRead32(gBattlescriptCurrInstr + 3);
|
|
if (!(gStatuses3[gActiveBattler] & STATUS3_SEMI_INVULNERABLE)
|
|
&& gDisableStructs[gActiveBattler].substituteHP == 0
|
|
&& !(gHitMarker & HITMARKER_NO_ANIMATIONS))
|
|
{
|
|
BtlController_EmitStatusAnimation(0, gBattlescriptCurrInstr[2], wantedStatus);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
}
|
|
|
|
static void atk67_yesnobox(void)
|
|
{
|
|
switch (gBattleCommunication[0])
|
|
{
|
|
case 0:
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
|
|
BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
|
|
gBattleCommunication[0]++;
|
|
gBattleCommunication[CURSOR_POSITION] = 0;
|
|
BattleCreateYesNoCursorAt(0);
|
|
break;
|
|
case 1:
|
|
if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
|
gBattleCommunication[CURSOR_POSITION] = 0;
|
|
BattleCreateYesNoCursorAt(0);
|
|
}
|
|
if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
|
gBattleCommunication[CURSOR_POSITION] = 1;
|
|
BattleCreateYesNoCursorAt(1);
|
|
}
|
|
if (gMain.newKeys & B_BUTTON)
|
|
{
|
|
gBattleCommunication[CURSOR_POSITION] = 1;
|
|
PlaySE(SE_SELECT);
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else if (gMain.newKeys & A_BUTTON)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void atk68_cancelallactions(void)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
gActionsByTurnOrder[i] = B_ACTION_CANCEL_PARTNER;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk69_adjustsetdamage(void) // The same as 0x7, except there's no random damage multiplier.
|
|
{
|
|
u8 holdEffect, quality;
|
|
|
|
if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY)
|
|
{
|
|
holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect, quality = gEnigmaBerries[gBattlerTarget].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item);
|
|
quality = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item);
|
|
}
|
|
|
|
gStringBattler = gBattlerTarget;
|
|
|
|
if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality)
|
|
{
|
|
RecordItemEffectBattle(gBattlerTarget, holdEffect);
|
|
gSpecialStatuses[gBattlerTarget].focusBanded = 1;
|
|
}
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE)
|
|
goto END;
|
|
if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBattlerTarget].endured
|
|
&& !gSpecialStatuses[gBattlerTarget].focusBanded)
|
|
goto END;
|
|
|
|
if (gBattleMons[gBattlerTarget].hp > gBattleMoveDamage)
|
|
goto END;
|
|
|
|
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;
|
|
}
|
|
|
|
END:
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk6A_removeitem(void)
|
|
{
|
|
u16* usedHeldItem;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBattler];
|
|
*usedHeldItem = gBattleMons[gActiveBattler].item;
|
|
gBattleMons[gActiveBattler].item = 0;
|
|
|
|
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBattler].item);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk6B_atknameinbuff1(void)
|
|
{
|
|
PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattlerPartyIndexes[gBattlerAttacker])
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk6C_drawlvlupbox(void)
|
|
{
|
|
if (gBattleScripting.atk6C_state == 0)
|
|
{
|
|
if (IsMonGettingExpSentOut())
|
|
gBattleScripting.atk6C_state = 3;
|
|
else
|
|
gBattleScripting.atk6C_state = 1;
|
|
}
|
|
|
|
switch (gBattleScripting.atk6C_state)
|
|
{
|
|
case 1:
|
|
gBattle_BG2_Y = 0x60;
|
|
SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, 0);
|
|
ShowBg(2);
|
|
sub_804F17C();
|
|
gBattleScripting.atk6C_state = 2;
|
|
break;
|
|
case 2:
|
|
if (!sub_804F1CC())
|
|
gBattleScripting.atk6C_state = 3;
|
|
break;
|
|
case 3:
|
|
gBattle_BG1_X = 0;
|
|
gBattle_BG1_Y = 0x100;
|
|
SetBgAttribute(0, BG_CTRL_ATTR_MOSAIC, 1);
|
|
SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 0);
|
|
ShowBg(0);
|
|
ShowBg(1);
|
|
HandleBattleWindow(0x12, 7, 0x1D, 0x13, WINDOW_x80);
|
|
gBattleScripting.atk6C_state = 4;
|
|
break;
|
|
case 4:
|
|
sub_804F100();
|
|
PutWindowTilemap(13);
|
|
CopyWindowToVram(13, 3);
|
|
gBattleScripting.atk6C_state++;
|
|
break;
|
|
case 5:
|
|
case 7:
|
|
if (!IsDma3ManagerBusyWithBgCopy())
|
|
{
|
|
gBattle_BG1_Y = 0;
|
|
gBattleScripting.atk6C_state++;
|
|
}
|
|
break;
|
|
case 6:
|
|
if (gMain.newKeys != 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
sub_804F144();
|
|
CopyWindowToVram(13, 2);
|
|
gBattleScripting.atk6C_state++;
|
|
}
|
|
break;
|
|
case 8:
|
|
if (gMain.newKeys != 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
HandleBattleWindow(0x12, 7, 0x1D, 0x13, WINDOW_x80 | WINDOW_CLEAR);
|
|
gBattleScripting.atk6C_state++;
|
|
}
|
|
break;
|
|
case 9:
|
|
if (!sub_804F344())
|
|
{
|
|
ClearWindowTilemap(14);
|
|
CopyWindowToVram(14, 1);
|
|
|
|
ClearWindowTilemap(13);
|
|
CopyWindowToVram(13, 1);
|
|
|
|
SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, 2);
|
|
ShowBg(2);
|
|
|
|
gBattleScripting.atk6C_state = 10;
|
|
}
|
|
break;
|
|
case 10:
|
|
if (!IsDma3ManagerBusyWithBgCopy())
|
|
{
|
|
SetBgAttribute(0, BG_CTRL_ATTR_MOSAIC, 0);
|
|
SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 1);
|
|
ShowBg(0);
|
|
ShowBg(1);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void sub_804F100(void)
|
|
{
|
|
struct StatsArray currentStats;
|
|
|
|
sub_81D388C(&gPlayerParty[gBattleStruct->expGetterId], ¤tStats);
|
|
sub_81D3640(0xD, gBattleResources->statsBeforeLvlUp, ¤tStats, 0xE, 0xD, 0xF);
|
|
}
|
|
|
|
static void sub_804F144(void)
|
|
{
|
|
struct StatsArray currentStats;
|
|
|
|
sub_81D388C(&gPlayerParty[gBattleStruct->expGetterId], ¤tStats);
|
|
sub_81D3784(0xD, ¤tStats, 0xE, 0xD, 0xF);
|
|
}
|
|
|
|
static void sub_804F17C(void)
|
|
{
|
|
gBattle_BG2_Y = 0;
|
|
gBattle_BG2_X = 0x1A0;
|
|
|
|
LoadPalette(sUnknown_0831C2C8, 0x60, 0x20);
|
|
CopyToWindowPixelBuffer(14, sUnknown_0831C2E8, 0, 0);
|
|
PutWindowTilemap(14);
|
|
CopyWindowToVram(14, 3);
|
|
|
|
PutMonIconOnLvlUpBox();
|
|
}
|
|
|
|
static bool8 sub_804F1CC(void)
|
|
{
|
|
if (IsDma3ManagerBusyWithBgCopy())
|
|
return TRUE;
|
|
|
|
if (gBattle_BG2_X == 0x200)
|
|
return FALSE;
|
|
|
|
if (gBattle_BG2_X == 0x1A0)
|
|
PutLevelAndGenderOnLvlUpBox();
|
|
|
|
gBattle_BG2_X += 8;
|
|
if (gBattle_BG2_X >= 0x200)
|
|
gBattle_BG2_X = 0x200;
|
|
|
|
return (gBattle_BG2_X != 0x200);
|
|
}
|
|
|
|
static void PutLevelAndGenderOnLvlUpBox(void)
|
|
{
|
|
u16 monLevel;
|
|
u8 monGender;
|
|
struct TextSubPrinter subPrinter;
|
|
u8 *txtPtr;
|
|
u32 var;
|
|
|
|
monLevel = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL);
|
|
monGender = GetMonGender(&gPlayerParty[gBattleStruct->expGetterId]);
|
|
GetMonNickname(&gPlayerParty[gBattleStruct->expGetterId], gStringVar4);
|
|
|
|
subPrinter.current_text_offset = gStringVar4;
|
|
subPrinter.windowId = 14;
|
|
subPrinter.fontId = 0;
|
|
subPrinter.x = 32;
|
|
subPrinter.y = 0;
|
|
subPrinter.currentX = 32;
|
|
subPrinter.currentY = 0;
|
|
subPrinter.letterSpacing = 0;
|
|
subPrinter.lineSpacing = 0;
|
|
subPrinter.fontColor_l = TEXT_COLOR_TRANSPARENT;
|
|
subPrinter.fgColor = TEXT_COLOR_WHITE;
|
|
subPrinter.bgColor = TEXT_COLOR_TRANSPARENT;
|
|
subPrinter.shadowColor = TEXT_COLOR_DARK_GREY;
|
|
|
|
AddTextPrinter(&subPrinter, 0xFF, NULL);
|
|
|
|
txtPtr = gStringVar4;
|
|
gStringVar4[0] = CHAR_SPECIAL_F9;
|
|
txtPtr++;
|
|
txtPtr[0] = 5;
|
|
txtPtr++;
|
|
|
|
var = (u32)(txtPtr);
|
|
txtPtr = ConvertIntToDecimalStringN(txtPtr, monLevel, STR_CONV_MODE_LEFT_ALIGN, 3);
|
|
var = (u32)(txtPtr) - var;
|
|
txtPtr = StringFill(txtPtr, 0x77, 4 - var);
|
|
|
|
if (monGender != MON_GENDERLESS)
|
|
{
|
|
if (monGender == MON_MALE)
|
|
{
|
|
txtPtr = WriteColorChangeControlCode(txtPtr, 0, 0xC);
|
|
txtPtr = WriteColorChangeControlCode(txtPtr, 1, 0xD);
|
|
*(txtPtr++) = CHAR_MALE;
|
|
}
|
|
else
|
|
{
|
|
txtPtr = WriteColorChangeControlCode(txtPtr, 0, 0xE);
|
|
txtPtr = WriteColorChangeControlCode(txtPtr, 1, 0xF);
|
|
*(txtPtr++) = CHAR_FEMALE;
|
|
}
|
|
*(txtPtr++) = EOS;
|
|
}
|
|
|
|
subPrinter.y = 10;
|
|
subPrinter.currentY = 10;
|
|
AddTextPrinter(&subPrinter, 0xFF, NULL);
|
|
|
|
CopyWindowToVram(14, 2);
|
|
}
|
|
|
|
static bool8 sub_804F344(void)
|
|
{
|
|
if (gBattle_BG2_X == 0x1A0)
|
|
return FALSE;
|
|
|
|
if (gBattle_BG2_X - 16 < 0x1A0)
|
|
gBattle_BG2_X = 0x1A0;
|
|
else
|
|
gBattle_BG2_X -= 16;
|
|
|
|
return (gBattle_BG2_X != 0x1A0);
|
|
}
|
|
|
|
#define sDestroy data[0]
|
|
#define sSavedLvlUpBoxXPosition data[1]
|
|
|
|
static void PutMonIconOnLvlUpBox(void)
|
|
{
|
|
u8 spriteId;
|
|
const u16* iconPal;
|
|
struct SpriteSheet iconSheet;
|
|
struct SpritePalette iconPalSheet;
|
|
|
|
u16 species = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPECIES);
|
|
u32 personality = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_PERSONALITY);
|
|
|
|
const u8* iconPtr = GetMonIconPtr(species, personality, 1);
|
|
iconSheet.data = iconPtr;
|
|
iconSheet.size = 0x200;
|
|
iconSheet.tag = MON_ICON_LVLUP_BOX_TAG;
|
|
|
|
iconPal = GetValidMonIconPalettePtr(species);
|
|
iconPalSheet.data = iconPal;
|
|
iconPalSheet.tag = MON_ICON_LVLUP_BOX_TAG;
|
|
|
|
LoadSpriteSheet(&iconSheet);
|
|
LoadSpritePalette(&iconPalSheet);
|
|
|
|
spriteId = CreateSprite(&sSpriteTemplate_MonIconOnLvlUpBox, 256, 10, 0);
|
|
gSprites[spriteId].sDestroy = FALSE;
|
|
gSprites[spriteId].sSavedLvlUpBoxXPosition = gBattle_BG2_X;
|
|
}
|
|
|
|
static void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite)
|
|
{
|
|
sprite->pos2.x = sprite->sSavedLvlUpBoxXPosition - gBattle_BG2_X;
|
|
|
|
if (sprite->pos2.x != 0)
|
|
{
|
|
sprite->sDestroy = TRUE;
|
|
}
|
|
else if (sprite->sDestroy)
|
|
{
|
|
DestroySprite(sprite);
|
|
FreeSpriteTilesByTag(MON_ICON_LVLUP_BOX_TAG);
|
|
FreeSpritePaletteByTag(MON_ICON_LVLUP_BOX_TAG);
|
|
}
|
|
}
|
|
|
|
#undef sDestroy
|
|
#undef sSavedLvlUpBoxXPosition
|
|
|
|
static bool32 IsMonGettingExpSentOut(void)
|
|
{
|
|
if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterId)
|
|
return TRUE;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattlerPartyIndexes[2] == gBattleStruct->expGetterId)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void atk6D_resetsentmonsvalue(void)
|
|
{
|
|
ResetSentPokesToOpponentValue();
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk6E_setatktoplayer0(void)
|
|
{
|
|
gBattlerAttacker = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk6F_makevisible(void)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitSpriteInvisibility(0, FALSE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk70_recordlastability(void)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
|
|
gBattlescriptCurrInstr += 1; // UB: Should be + 2, one byte for command and one byte for bank argument.
|
|
}
|
|
|
|
void BufferMoveToLearnIntoBattleTextBuff2(void)
|
|
{
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff2, gMoveToLearn);
|
|
}
|
|
|
|
static void atk71_buffermovetolearn(void)
|
|
{
|
|
BufferMoveToLearnIntoBattleTextBuff2();
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk72_jumpifplayerran(void)
|
|
{
|
|
if (TryRunFromBattle(gBank1))
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
|
|
static void atk73_hpthresholds(void)
|
|
{
|
|
u8 opposingBank;
|
|
s32 result;
|
|
|
|
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
opposingBank = gActiveBattler ^ BIT_SIDE;
|
|
|
|
result = gBattleMons[opposingBank].hp * 100 / gBattleMons[opposingBank].maxHP;
|
|
if (result == 0)
|
|
result = 1;
|
|
|
|
if (result > 69 || !gBattleMons[opposingBank].hp)
|
|
gBattleStruct->hpScale = 0;
|
|
else if (result > 39)
|
|
gBattleStruct->hpScale = 1;
|
|
else if (result > 9)
|
|
gBattleStruct->hpScale = 2;
|
|
else
|
|
gBattleStruct->hpScale = 3;
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk74_hpthresholds2(void)
|
|
{
|
|
u8 opposingBank;
|
|
s32 result;
|
|
u8 hpSwitchout;
|
|
|
|
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
opposingBank = gActiveBattler ^ BIT_SIDE;
|
|
hpSwitchout = *(gBattleStruct->hpOnSwitchout + GetBattlerSide(opposingBank));
|
|
result = (hpSwitchout - gBattleMons[opposingBank].hp) * 100 / hpSwitchout;
|
|
|
|
if (gBattleMons[opposingBank].hp >= hpSwitchout)
|
|
gBattleStruct->hpScale = 0;
|
|
else if (result <= 29)
|
|
gBattleStruct->hpScale = 1;
|
|
else if (result <= 69)
|
|
gBattleStruct->hpScale = 2;
|
|
else
|
|
gBattleStruct->hpScale = 3;
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk75_useitemonopponent(void)
|
|
{
|
|
gBankInMenu = gBattlerAttacker;
|
|
PokemonUseItemEffects(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker]], gLastUsedItem, gBattlerPartyIndexes[gBattlerAttacker], 0, 1);
|
|
|
|
gBattlescriptCurrInstr += 1;
|
|
}
|
|
|
|
static void atk76_various(void)
|
|
{
|
|
u8 side;
|
|
s32 i;
|
|
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
switch (gBattlescriptCurrInstr[2])
|
|
{
|
|
case VARIOUS_CANCEL_MULTI_TURN_MOVES:
|
|
CancelMultiTurnMoves(gActiveBattler);
|
|
break;
|
|
case VARIOUS_SET_MAGIC_COAT_TARGET:
|
|
gBattlerAttacker = gBattlerTarget;
|
|
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
|
|
if (gSideTimers[side].followmeTimer != 0 && gBattleMons[gSideTimers[side].followmeTarget].hp != 0)
|
|
gBattlerTarget = gSideTimers[side].followmeTarget;
|
|
else
|
|
gBattlerTarget = gActiveBattler;
|
|
break;
|
|
case VARIOUS_IS_RUNNING_IMPOSSIBLE:
|
|
gBattleCommunication[0] = IsRunningFromBattleImpossible();
|
|
break;
|
|
case VARIOUS_GET_MOVE_TARGET:
|
|
gBattlerTarget = GetMoveTarget(gCurrentMove, 0);
|
|
break;
|
|
case 4:
|
|
if (gHitMarker & HITMARKER_FAINTED(gActiveBattler))
|
|
gBattleCommunication[0] = 1;
|
|
else
|
|
gBattleCommunication[0] = 0;
|
|
break;
|
|
case VARIOUS_RESET_INTIMIDATE_TRACE_BITS:
|
|
gSpecialStatuses[gActiveBattler].intimidatedPoke = 0;
|
|
gSpecialStatuses[gActiveBattler].traced = 0;
|
|
break;
|
|
case VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP:
|
|
if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterId || gBattlerPartyIndexes[2] == gBattleStruct->expGetterId)
|
|
{
|
|
u16 *choicedMove;
|
|
|
|
if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterId)
|
|
gActiveBattler = 0;
|
|
else
|
|
gActiveBattler = 2;
|
|
|
|
choicedMove = &gBattleStruct->choicedMove[gActiveBattler];
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gBattleMons[gActiveBattler].moves[i] == *choicedMove)
|
|
break;
|
|
}
|
|
if (i == 4)
|
|
*choicedMove = 0;
|
|
}
|
|
break;
|
|
case 7:
|
|
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE))
|
|
&& gBattleTypeFlags & BATTLE_TYPE_TRAINER
|
|
&& gBattleMons[0].hp != 0
|
|
&& gBattleMons[1].hp != 0)
|
|
{
|
|
gHitMarker &= ~(HITMARKER_x400000);
|
|
}
|
|
break;
|
|
case 8:
|
|
gBattleCommunication[0] = 0;
|
|
gBattleScripting.battler = gActiveBattler = gBattleCommunication[1];
|
|
if (!(gBattleStruct->field_92 & gBitTable[gActiveBattler])
|
|
&& gBattleMons[gActiveBattler].maxHP / 2 >= gBattleMons[gActiveBattler].hp
|
|
&& gBattleMons[gActiveBattler].hp != 0
|
|
&& !(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP))
|
|
{
|
|
gBattleStruct->field_92 |= gBitTable[gActiveBattler];
|
|
gBattleCommunication[0] = 1;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = sUnknown_0831C4F8[GetNatureFromPersonality(gBattleMons[gActiveBattler].personality)];
|
|
}
|
|
break;
|
|
case 9:
|
|
i = sub_81A5258(gBattleCommunication);
|
|
if (i == 0)
|
|
return;
|
|
|
|
gBattleCommunication[1] = i;
|
|
break;
|
|
case 10:
|
|
gBattleMons[1].hp = 0;
|
|
gHitMarker |= HITMARKER_FAINTED(1);
|
|
gBattleStruct->field_2A1 |= gBitTable[gBattlerPartyIndexes[1]];
|
|
gDisableStructs[1].truantUnknownBit = 1;
|
|
break;
|
|
case 11:
|
|
gBattleMons[0].hp = 0;
|
|
gHitMarker |= HITMARKER_FAINTED(0);
|
|
gHitMarker |= HITMARKER_x400000;
|
|
gBattleStruct->field_2A0 |= gBitTable[gBattlerPartyIndexes[0]];
|
|
gDisableStructs[0].truantUnknownBit = 1;
|
|
break;
|
|
case 12:
|
|
gBattleMons[0].hp = 0;
|
|
gBattleMons[1].hp = 0;
|
|
gHitMarker |= HITMARKER_FAINTED(0);
|
|
gHitMarker |= HITMARKER_FAINTED(1);
|
|
gHitMarker |= HITMARKER_x400000;
|
|
gBattleStruct->field_2A0 |= gBitTable[gBattlerPartyIndexes[0]];
|
|
gBattleStruct->field_2A1 |= gBitTable[gBattlerPartyIndexes[1]];
|
|
gDisableStructs[0].truantUnknownBit = 1;
|
|
gDisableStructs[1].truantUnknownBit = 1;
|
|
break;
|
|
case VARIOUS_EMIT_YESNOBOX:
|
|
BtlController_EmitUnknownYesNoBox(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
break;
|
|
case 14:
|
|
sub_81A5BF8();
|
|
break;
|
|
case 15:
|
|
sub_81A5D44();
|
|
break;
|
|
case 16:
|
|
BattleStringExpandPlaceholdersToDisplayedString(gRefereeStringsTable[gBattlescriptCurrInstr[1]]);
|
|
BattleHandleAddTextPrinter(gDisplayedStringBattle, 0x16);
|
|
break;
|
|
case 17:
|
|
if (IsTextPrinterActive(0x16))
|
|
return;
|
|
break;
|
|
case VARIOUS_WAIT_CRY:
|
|
if (!IsCryFinished())
|
|
return;
|
|
break;
|
|
case VARIOUS_RETURN_OPPONENT_MON1:
|
|
gActiveBattler = 1;
|
|
if (gBattleMons[gActiveBattler].hp != 0)
|
|
{
|
|
BtlController_EmitReturnMonToBall(0, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
break;
|
|
case VARIOUS_RETURN_OPPONENT_MON2:
|
|
if (gBattlersCount > 3)
|
|
{
|
|
gActiveBattler = 3;
|
|
if (gBattleMons[gActiveBattler].hp != 0)
|
|
{
|
|
BtlController_EmitReturnMonToBall(0, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
break;
|
|
case 21:
|
|
m4aMPlayVolumeControl(&gMPlayInfo_BGM, 0xFFFF, 0x55);
|
|
break;
|
|
case 22:
|
|
m4aMPlayVolumeControl(&gMPlayInfo_BGM, 0xFFFF, 0x100);
|
|
break;
|
|
case 23:
|
|
gBattleStruct->field_2A2 |= gBitTable[gActiveBattler];
|
|
break;
|
|
case 24:
|
|
if (sub_805725C(gActiveBattler))
|
|
return;
|
|
break;
|
|
case VARIOUS_SET_TELEPORT_OUTCOME:
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
|
|
gBattleOutcome = B_OUTCOME_PLAYER_TELEPORTED;
|
|
else
|
|
gBattleOutcome = B_OUTCOME_POKE_TELEPORTED;
|
|
break;
|
|
case VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC:
|
|
BtlController_EmitPlayFanfareOrBGM(0, MUS_KACHI1, TRUE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
break;
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
|
|
static void atk77_setprotectlike(void) // protect and endure
|
|
{
|
|
bool8 notLastTurn = TRUE;
|
|
u16 lastMove = gLastResultingMoves[gBattlerAttacker];
|
|
|
|
if (lastMove != MOVE_PROTECT && lastMove != MOVE_DETECT && lastMove != MOVE_ENDURE)
|
|
gDisableStructs[gBattlerAttacker].protectUses = 0;
|
|
|
|
if (gCurrentTurnActionNumber == (gBattlersCount - 1))
|
|
notLastTurn = FALSE;
|
|
|
|
if (sProtectSuccessRates[gDisableStructs[gBattlerAttacker].protectUses] >= Random() && notLastTurn)
|
|
{
|
|
if (gBattleMoves[gCurrentMove].effect == EFFECT_PROTECT)
|
|
{
|
|
gProtectStructs[gBattlerAttacker].protected = 1;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
if (gBattleMoves[gCurrentMove].effect == EFFECT_ENDURE)
|
|
{
|
|
gProtectStructs[gBattlerAttacker].endured = 1;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
gDisableStructs[gBattlerAttacker].protectUses++;
|
|
}
|
|
else
|
|
{
|
|
gDisableStructs[gBattlerAttacker].protectUses = 0;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk78_faintifabilitynotdamp(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].ability == ABILITY_DAMP)
|
|
break;
|
|
}
|
|
|
|
if (gBattlerTarget == gBattlersCount)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
gBattleMoveDamage = gBattleMons[gActiveBattler].hp;
|
|
BtlController_EmitHealthBarUpdate(0, INSTANT_HP_BAR_DROP);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr++;
|
|
|
|
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
|
|
{
|
|
if (gBattlerTarget == gBattlerAttacker)
|
|
continue;
|
|
if (!(gAbsentBattlerFlags & gBitTable[gBattlerTarget]))
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gLastUsedAbility = ABILITY_DAMP;
|
|
RecordAbilityBattle(gBattlerTarget, gBattleMons[gBattlerTarget].ability);
|
|
gBattlescriptCurrInstr = BattleScript_DampStopsExplosion;
|
|
}
|
|
}
|
|
|
|
static void atk79_setatkhptozero(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = gBattlerAttacker;
|
|
gBattleMons[gActiveBattler].hp = 0;
|
|
BtlController_EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBattler].hp);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk7A_jumpifnexttargetvalid(void)
|
|
{
|
|
const u8 *jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
{
|
|
for (gBattlerTarget++; ; gBattlerTarget++)
|
|
{
|
|
if (gBattlerTarget == gBattlerAttacker)
|
|
continue;
|
|
if (!(gAbsentBattlerFlags & gBitTable[gBattlerTarget]))
|
|
break;
|
|
}
|
|
|
|
if (gBattlerTarget >= gBattlersCount)
|
|
gBattlescriptCurrInstr += 5;
|
|
else
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atk7B_tryhealhalfhealth(void)
|
|
{
|
|
const u8* failPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
|
|
if (gBattlescriptCurrInstr[5] == BS_GET_ATTACKER)
|
|
gBattlerTarget = gBattlerAttacker;
|
|
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
gBattleMoveDamage *= -1;
|
|
|
|
if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP)
|
|
gBattlescriptCurrInstr = failPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void atk7C_trymirrormove(void)
|
|
{
|
|
s32 validMovesCount;
|
|
s32 i;
|
|
u16 move;
|
|
u16 movesArray[4];
|
|
|
|
for (i = 0; i < 3; i++)
|
|
movesArray[i] = 0;
|
|
|
|
for (validMovesCount = 0, i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (i != gBattlerAttacker)
|
|
{
|
|
move = *(i * 2 + gBattlerAttacker * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0)
|
|
| (*(i * 2 + gBattlerAttacker * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) << 8);
|
|
|
|
if (move != 0 && move != 0xFFFF)
|
|
{
|
|
movesArray[validMovesCount] = move;
|
|
validMovesCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
move = *(gBattleStruct->mirrorMoves + gBattlerAttacker * 2 + 0)
|
|
| (*(gBattleStruct->mirrorMoves + gBattlerAttacker * 2 + 1) << 8);
|
|
|
|
if (move != 0 && move != 0xFFFF)
|
|
{
|
|
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
|
|
gCurrentMove = move;
|
|
gBattlerTarget = GetMoveTarget(gCurrentMove, 0);
|
|
gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect];
|
|
}
|
|
else if (validMovesCount)
|
|
{
|
|
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
|
|
i = Random() % validMovesCount;
|
|
gCurrentMove = movesArray[i];
|
|
gBattlerTarget = GetMoveTarget(gCurrentMove, 0);
|
|
gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect];
|
|
}
|
|
else
|
|
{
|
|
gSpecialStatuses[gBattlerAttacker].flag20 = 1;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
|
|
static void atk7D_setrain(void)
|
|
{
|
|
if (gBattleWeather & WEATHER_RAIN_ANY)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
}
|
|
else
|
|
{
|
|
gBattleWeather = WEATHER_RAIN_TEMPORARY;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
gWishFutureKnock.weatherDuration = 5;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk7E_setreflect(void)
|
|
{
|
|
if (gSideStatuses[GET_BATTLER_SIDE(gBattlerAttacker)] & SIDE_STATUS_REFLECT)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
else
|
|
{
|
|
gSideStatuses[GET_BATTLER_SIDE(gBattlerAttacker)] |= SIDE_STATUS_REFLECT;
|
|
gSideTimers[GET_BATTLER_SIDE(gBattlerAttacker)].reflectTimer = 5;
|
|
gSideTimers[GET_BATTLER_SIDE(gBattlerAttacker)].reflectBank = gBattlerAttacker;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk7F_setseeded(void)
|
|
{
|
|
if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT || gStatuses3[gBattlerTarget] & STATUS3_LEECHSEED)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else if (gBattleMons[gBattlerTarget].type1 == TYPE_GRASS || gBattleMons[gBattlerTarget].type2 == TYPE_GRASS)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
}
|
|
else
|
|
{
|
|
gStatuses3[gBattlerTarget] |= gBattlerAttacker;
|
|
gStatuses3[gBattlerTarget] |= STATUS3_LEECHSEED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk80_manipulatedamage(void)
|
|
{
|
|
switch (gBattlescriptCurrInstr[1])
|
|
{
|
|
case ATK80_DMG_CHANGE_SIGN:
|
|
gBattleMoveDamage *= -1;
|
|
break;
|
|
case ATK80_DMG_HALF_BY_TWO_NOT_MORE_THAN_HALF_MAX_HP:
|
|
gBattleMoveDamage /= 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
if ((gBattleMons[gBattlerTarget].maxHP / 2) < gBattleMoveDamage)
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2;
|
|
break;
|
|
case ATK80_DMG_DOUBLED:
|
|
gBattleMoveDamage *= 2;
|
|
break;
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk81_trysetrest(void)
|
|
{
|
|
const u8 *failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
gActiveBattler = gBattlerTarget = gBattlerAttacker;
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP * (-1);
|
|
|
|
if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP)
|
|
{
|
|
gBattlescriptCurrInstr = failJump;
|
|
}
|
|
else
|
|
{
|
|
if (gBattleMons[gBattlerTarget].status1 & ((u8)(~STATUS1_SLEEP)))
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
|
|
gBattleMons[gBattlerTarget].status1 = 3;
|
|
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atk82_jumpifnotfirstturn(void)
|
|
{
|
|
const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
|
|
if (gDisableStructs[gBattlerAttacker].isFirstTurn)
|
|
gBattlescriptCurrInstr += 5;
|
|
else
|
|
gBattlescriptCurrInstr = failJump;
|
|
}
|
|
|
|
static void atk83_nop(void)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
bool8 UproarWakeUpCheck(u8 bank)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || gBattleMons[bank].ability == ABILITY_SOUNDPROOF)
|
|
continue;
|
|
|
|
gBattleScripting.battler = i;
|
|
|
|
if (gBattlerTarget == 0xFF)
|
|
gBattlerTarget = i;
|
|
else if (gBattlerTarget == i)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
|
|
break;
|
|
}
|
|
|
|
if (i == gBattlersCount)
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
static void atk84_jumpifcantmakeasleep(void)
|
|
{
|
|
const u8 *jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
|
|
if (UproarWakeUpCheck(gBattlerTarget))
|
|
{
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
}
|
|
else if (gBattleMons[gBattlerTarget].ability == ABILITY_INSOMNIA
|
|
|| gBattleMons[gBattlerTarget].ability == ABILITY_VITAL_SPIRIT)
|
|
{
|
|
gLastUsedAbility = gBattleMons[gBattlerTarget].ability;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atk85_stockpile(void)
|
|
{
|
|
if (gDisableStructs[gBattlerAttacker].stockpileCounter == 3)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else
|
|
{
|
|
gDisableStructs[gBattlerAttacker].stockpileCounter++;
|
|
|
|
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBattlerAttacker].stockpileCounter)
|
|
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk86_stockpiletobasedamage(void)
|
|
{
|
|
const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0)
|
|
{
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
}
|
|
else
|
|
{
|
|
if (gBattleCommunication[6] != 1)
|
|
{
|
|
gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerTarget], gCurrentMove,
|
|
gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)], 0,
|
|
0, gBattlerAttacker, gBattlerTarget)
|
|
* gDisableStructs[gBattlerAttacker].stockpileCounter;
|
|
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
|
|
|
|
if (gProtectStructs[gBattlerAttacker].helpingHand)
|
|
gBattleMoveDamage = gBattleMoveDamage * 15 / 10;
|
|
}
|
|
|
|
gDisableStructs[gBattlerAttacker].stockpileCounter = 0;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atk87_stockpiletohpheal(void)
|
|
{
|
|
const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
|
|
if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0)
|
|
{
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
else if (gBattleMons[gBattlerAttacker].maxHP == gBattleMons[gBattlerAttacker].hp)
|
|
{
|
|
gDisableStructs[gBattlerAttacker].stockpileCounter = 0;
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
gBattlerTarget = gBattlerAttacker;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter));
|
|
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
gBattleMoveDamage *= -1;
|
|
|
|
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
|
|
gDisableStructs[gBattlerAttacker].stockpileCounter = 0;
|
|
gBattlescriptCurrInstr += 5;
|
|
gBattlerTarget = gBattlerAttacker;
|
|
}
|
|
}
|
|
|
|
static void atk88_negativedamage(void)
|
|
{
|
|
gBattleMoveDamage = -(gHpDealt / 2);
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = -1;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static u8 ChangeStatBuffs(s8 statValue, u8 statId, u8 flags, const u8 *BS_ptr)
|
|
{
|
|
bool8 certain = FALSE;
|
|
bool8 notProtectAffected = FALSE;
|
|
u32 index;
|
|
|
|
if (flags & MOVE_EFFECT_AFFECTS_USER)
|
|
gActiveBattler = gBattlerAttacker;
|
|
else
|
|
gActiveBattler = gBattlerTarget;
|
|
|
|
flags &= ~(MOVE_EFFECT_AFFECTS_USER);
|
|
|
|
if (flags & MOVE_EFFECT_CERTAIN)
|
|
certain++;
|
|
flags &= ~(MOVE_EFFECT_CERTAIN);
|
|
|
|
if (flags & STAT_CHANGE_NOT_PROTECT_AFFECTED)
|
|
notProtectAffected++;
|
|
flags &= ~(STAT_CHANGE_NOT_PROTECT_AFFECTED);
|
|
|
|
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId)
|
|
|
|
if ((statValue << 0x18) < 0) // stat decrease
|
|
{
|
|
if (gSideTimers[GET_BATTLER_SIDE(gActiveBattler)].mistTimer
|
|
&& !certain && gCurrentMove != MOVE_CURSE)
|
|
{
|
|
if (flags == STAT_CHANGE_BS_PTR)
|
|
{
|
|
if (gSpecialStatuses[gActiveBattler].statLowered)
|
|
{
|
|
gBattlescriptCurrInstr = BS_ptr;
|
|
}
|
|
else
|
|
{
|
|
BattleScriptPush(BS_ptr);
|
|
gBattleScripting.battler = gActiveBattler;
|
|
gBattlescriptCurrInstr = BattleScript_MistProtected;
|
|
gSpecialStatuses[gActiveBattler].statLowered = 1;
|
|
}
|
|
}
|
|
return STAT_CHANGE_DIDNT_WORK;
|
|
}
|
|
else if (gCurrentMove != MOVE_CURSE
|
|
&& notProtectAffected != TRUE && JumpIfMoveAffectedByProtect(0))
|
|
{
|
|
gBattlescriptCurrInstr = BattleScript_ButItFailed;
|
|
return STAT_CHANGE_DIDNT_WORK;
|
|
}
|
|
else if ((gBattleMons[gActiveBattler].ability == ABILITY_CLEAR_BODY
|
|
|| gBattleMons[gActiveBattler].ability == ABILITY_WHITE_SMOKE)
|
|
&& !certain && gCurrentMove != MOVE_CURSE)
|
|
{
|
|
if (flags == STAT_CHANGE_BS_PTR)
|
|
{
|
|
if (gSpecialStatuses[gActiveBattler].statLowered)
|
|
{
|
|
gBattlescriptCurrInstr = BS_ptr;
|
|
}
|
|
else
|
|
{
|
|
BattleScriptPush(BS_ptr);
|
|
gBattleScripting.battler = gActiveBattler;
|
|
gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss;
|
|
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
|
|
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
|
|
gSpecialStatuses[gActiveBattler].statLowered = 1;
|
|
}
|
|
}
|
|
return STAT_CHANGE_DIDNT_WORK;
|
|
}
|
|
else if (gBattleMons[gActiveBattler].ability == ABILITY_KEEN_EYE
|
|
&& !certain && statId == STAT_STAGE_ACC)
|
|
{
|
|
if (flags == STAT_CHANGE_BS_PTR)
|
|
{
|
|
BattleScriptPush(BS_ptr);
|
|
gBattleScripting.battler = gActiveBattler;
|
|
gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss;
|
|
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
|
|
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
|
|
}
|
|
return STAT_CHANGE_DIDNT_WORK;
|
|
}
|
|
else if (gBattleMons[gActiveBattler].ability == ABILITY_HYPER_CUTTER
|
|
&& !certain && statId == STAT_STAGE_ATK)
|
|
{
|
|
if (flags == STAT_CHANGE_BS_PTR)
|
|
{
|
|
BattleScriptPush(BS_ptr);
|
|
gBattleScripting.battler = gActiveBattler;
|
|
gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss;
|
|
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
|
|
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
|
|
}
|
|
return STAT_CHANGE_DIDNT_WORK;
|
|
}
|
|
else if (gBattleMons[gActiveBattler].ability == ABILITY_SHIELD_DUST && flags == 0)
|
|
{
|
|
return STAT_CHANGE_DIDNT_WORK;
|
|
}
|
|
else // try to decrease
|
|
{
|
|
statValue = -GET_STAT_BUFF_VALUE(statValue);
|
|
gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN;
|
|
index = 1;
|
|
if (statValue == -2)
|
|
{
|
|
gBattleTextBuff2[1] = B_BUFF_STRING;
|
|
gBattleTextBuff2[2] = STRINGID_STATHARSHLY;
|
|
gBattleTextBuff2[3] = STRINGID_STATHARSHLY >> 8;
|
|
index = 4;
|
|
}
|
|
gBattleTextBuff2[index] = B_BUFF_STRING;
|
|
index++;
|
|
gBattleTextBuff2[index] = STRINGID_STATFELL;
|
|
index++;
|
|
gBattleTextBuff2[index] = STRINGID_STATFELL >> 8;
|
|
index++;
|
|
gBattleTextBuff2[index] = B_BUFF_EOS;
|
|
|
|
if (gBattleMons[gActiveBattler].statStages[statId] == 0)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler);
|
|
|
|
}
|
|
}
|
|
else // stat increase
|
|
{
|
|
statValue = GET_STAT_BUFF_VALUE(statValue);
|
|
gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN;
|
|
index = 1;
|
|
if (statValue == 2)
|
|
{
|
|
gBattleTextBuff2[1] = B_BUFF_STRING;
|
|
gBattleTextBuff2[2] = STRINGID_STATSHARPLY;
|
|
gBattleTextBuff2[3] = STRINGID_STATSHARPLY >> 8;
|
|
index = 4;
|
|
}
|
|
gBattleTextBuff2[index] = B_BUFF_STRING;
|
|
index++;
|
|
gBattleTextBuff2[index] = STRINGID_STATROSE;
|
|
index++;
|
|
gBattleTextBuff2[index] = STRINGID_STATROSE >> 8;
|
|
index++;
|
|
gBattleTextBuff2[index] = B_BUFF_EOS;
|
|
|
|
if (gBattleMons[gActiveBattler].statStages[statId] == 0xC)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler);
|
|
}
|
|
|
|
gBattleMons[gActiveBattler].statStages[statId] += statValue;
|
|
if (gBattleMons[gActiveBattler].statStages[statId] < 0)
|
|
gBattleMons[gActiveBattler].statStages[statId] = 0;
|
|
if (gBattleMons[gActiveBattler].statStages[statId] > 0xC)
|
|
gBattleMons[gActiveBattler].statStages[statId] = 0xC;
|
|
|
|
if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && flags & STAT_CHANGE_BS_PTR)
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
|
|
if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && !(flags & STAT_CHANGE_BS_PTR))
|
|
return STAT_CHANGE_DIDNT_WORK;
|
|
|
|
return STAT_CHANGE_WORKED;
|
|
}
|
|
|
|
static void atk89_statbuffchange(void)
|
|
{
|
|
const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
if (ChangeStatBuffs(gBattleScripting.statChanger & 0xF0, GET_STAT_BUFF_ID(gBattleScripting.statChanger), gBattlescriptCurrInstr[1], jumpPtr) == STAT_CHANGE_WORKED)
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void atk8A_normalisebuffs(void) // haze
|
|
{
|
|
s32 i, j;
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
for (j = 0; j < BATTLE_STATS_NO; j++)
|
|
gBattleMons[i].statStages[j] = 6;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk8B_setbide(void)
|
|
{
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_MULTIPLETURNS;
|
|
gLockedMoves[gBattlerAttacker] = gCurrentMove;
|
|
gTakenDmg[gBattlerAttacker] = 0;
|
|
gBattleMons[gBattlerAttacker].status2 |= (STATUS2_BIDE - 0x100); // 2 turns
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk8C_confuseifrepeatingattackends(void)
|
|
{
|
|
if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE))
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = (MOVE_EFFECT_THRASH | MOVE_EFFECT_AFFECTS_USER);
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk8D_setmultihitcounter(void)
|
|
{
|
|
if (gBattlescriptCurrInstr[1])
|
|
{
|
|
gMultiHitCounter = gBattlescriptCurrInstr[1];
|
|
}
|
|
else
|
|
{
|
|
gMultiHitCounter = Random() & 3;
|
|
if (gMultiHitCounter > 1)
|
|
gMultiHitCounter = (Random() & 3) + 2;
|
|
else
|
|
gMultiHitCounter += 2;
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atk8E_initmultihitstring(void)
|
|
{
|
|
PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0)
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static bool8 TryDoForceSwitchOut(void)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level)
|
|
{
|
|
*(gBattleStruct->field_58 + gBattlerTarget) = gBattlerPartyIndexes[gBattlerTarget];
|
|
}
|
|
else
|
|
{
|
|
u16 random = Random() & 0xFF;
|
|
if ((u32)((random * (gBattleMons[gBattlerAttacker].level + gBattleMons[gBattlerTarget].level) >> 8) + 1) <= (gBattleMons[gBattlerTarget].level / 4))
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
return FALSE;
|
|
}
|
|
*(gBattleStruct->field_58 + gBattlerTarget) = gBattlerPartyIndexes[gBattlerTarget];
|
|
}
|
|
|
|
gBattlescriptCurrInstr = BattleScript_SuccessForceOut;
|
|
return TRUE;
|
|
}
|
|
|
|
static void atk8F_forcerandomswitch(void)
|
|
{
|
|
s32 i;
|
|
s32 bank1PartyId = 0;
|
|
s32 bank2PartyId = 0;
|
|
|
|
#ifdef NONMATCHING
|
|
s32 lastMonId = 0; // + 1
|
|
#else
|
|
register s32 lastMonId asm("r8") = 0; // + 1
|
|
#endif // NONMATCHING
|
|
|
|
s32 firstMonId = 0;
|
|
s32 monsCount = 0;
|
|
struct Pokemon* party = NULL;
|
|
s32 validMons = 0;
|
|
s32 minNeeded = 0;
|
|
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER))
|
|
{
|
|
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
|
|
party = gPlayerParty;
|
|
else
|
|
party = gEnemyParty;
|
|
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_LINK)
|
|
|| (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_x2000000)
|
|
|| (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER))
|
|
{
|
|
if ((gBattlerTarget & BIT_FLANK) != 0)
|
|
{
|
|
firstMonId = 3;
|
|
lastMonId = 6;
|
|
}
|
|
else
|
|
{
|
|
firstMonId = 0;
|
|
lastMonId = 3;
|
|
}
|
|
monsCount = 3;
|
|
minNeeded = 1;
|
|
bank2PartyId = gBattlerPartyIndexes[gBattlerTarget];
|
|
bank1PartyId = gBattlerPartyIndexes[gBattlerTarget ^ BIT_FLANK];
|
|
}
|
|
else if ((gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK)
|
|
|| (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_x2000000))
|
|
{
|
|
if (sub_806D82C(GetBattlerMultiplayerId(gBattlerTarget)) == 1)
|
|
{
|
|
firstMonId = 3;
|
|
lastMonId = 6;
|
|
}
|
|
else
|
|
{
|
|
firstMonId = 0;
|
|
lastMonId = 3;
|
|
}
|
|
monsCount = 3;
|
|
minNeeded = 1;
|
|
bank2PartyId = gBattlerPartyIndexes[gBattlerTarget];
|
|
bank1PartyId = gBattlerPartyIndexes[gBattlerTarget ^ BIT_FLANK];
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
|
|
{
|
|
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
|
|
{
|
|
firstMonId = 0;
|
|
lastMonId = 6;
|
|
monsCount = 6;
|
|
minNeeded = 2; // since there are two opponents, it has to be a double battle
|
|
}
|
|
else
|
|
{
|
|
if ((gBattlerTarget & BIT_FLANK) != 0)
|
|
{
|
|
firstMonId = 3;
|
|
lastMonId = 6;
|
|
}
|
|
else
|
|
{
|
|
firstMonId = 0;
|
|
lastMonId = 3;
|
|
}
|
|
monsCount = 3;
|
|
minNeeded = 1;
|
|
}
|
|
bank2PartyId = gBattlerPartyIndexes[gBattlerTarget];
|
|
bank1PartyId = gBattlerPartyIndexes[gBattlerTarget ^ BIT_FLANK];
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
{
|
|
firstMonId = 0;
|
|
lastMonId = 6;
|
|
monsCount = 6;
|
|
minNeeded = 2;
|
|
bank2PartyId = gBattlerPartyIndexes[gBattlerTarget];
|
|
bank1PartyId = gBattlerPartyIndexes[gBattlerTarget ^ BIT_FLANK];
|
|
}
|
|
else
|
|
{
|
|
firstMonId = 0;
|
|
lastMonId = 6;
|
|
monsCount = 6;
|
|
minNeeded = 1;
|
|
bank2PartyId = gBattlerPartyIndexes[gBattlerTarget]; // there is only one pokemon out in single battles
|
|
bank1PartyId = gBattlerPartyIndexes[gBattlerTarget];
|
|
}
|
|
|
|
for (i = firstMonId; i < lastMonId; i++)
|
|
{
|
|
if (GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE
|
|
&& !GetMonData(&party[i], MON_DATA_IS_EGG)
|
|
&& GetMonData(&party[i], MON_DATA_HP) != 0)
|
|
{
|
|
validMons++;
|
|
}
|
|
}
|
|
|
|
if (validMons <= minNeeded)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
if (TryDoForceSwitchOut())
|
|
{
|
|
do
|
|
{
|
|
i = Random() % monsCount;
|
|
i += firstMonId;
|
|
}
|
|
while (i == bank2PartyId
|
|
|| i == bank1PartyId
|
|
|| GetMonData(&party[i], MON_DATA_SPECIES) == SPECIES_NONE
|
|
|| GetMonData(&party[i], MON_DATA_IS_EGG) == TRUE
|
|
|| GetMonData(&party[i], MON_DATA_HP) == 0);
|
|
}
|
|
*(gBattleStruct->monToSwitchIntoId + gBattlerTarget) = i;
|
|
|
|
if (!sub_81B1250())
|
|
sub_803BDA0(gBattlerTarget);
|
|
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
|
|
|| (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
|
|| (gBattleTypeFlags & BATTLE_TYPE_x2000000 && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
|
|
|| (gBattleTypeFlags & BATTLE_TYPE_x2000000 && gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
|
{
|
|
sub_81B8E80(gBattlerTarget, i, 0);
|
|
sub_81B8E80(gBattlerTarget ^ BIT_FLANK, i, 1);
|
|
}
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
|
sub_80571DC(gBattlerTarget, i);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TryDoForceSwitchOut();
|
|
}
|
|
}
|
|
|
|
static void atk90_tryconversiontypechange(void) // randomly changes user's type to one of its moves' type
|
|
{
|
|
u8 validMoves = 0;
|
|
u8 moveChecked;
|
|
u8 moveType;
|
|
|
|
while (validMoves < 4)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].moves[validMoves] == 0)
|
|
break;
|
|
|
|
validMoves++;
|
|
}
|
|
|
|
for (moveChecked = 0; moveChecked < validMoves; moveChecked++)
|
|
{
|
|
moveType = gBattleMoves[gBattleMons[gBattlerAttacker].moves[moveChecked]].type;
|
|
|
|
if (moveType == TYPE_MYSTERY)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].type1 == TYPE_GHOST || gBattleMons[gBattlerAttacker].type2 == TYPE_GHOST)
|
|
moveType = TYPE_GHOST;
|
|
else
|
|
moveType = TYPE_NORMAL;
|
|
}
|
|
if (moveType != gBattleMons[gBattlerAttacker].type1
|
|
&& moveType != gBattleMons[gBattlerAttacker].type2)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (moveChecked == validMoves)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
|
|
while ((moveChecked = Random() & 3) >= validMoves);
|
|
|
|
moveType = gBattleMoves[gBattleMons[gBattlerAttacker].moves[moveChecked]].type;
|
|
|
|
if (moveType == TYPE_MYSTERY)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].type1 == TYPE_GHOST || gBattleMons[gBattlerAttacker].type2 == TYPE_GHOST)
|
|
moveType = TYPE_GHOST;
|
|
else
|
|
moveType = TYPE_NORMAL;
|
|
}
|
|
}
|
|
while (moveType == gBattleMons[gBattlerAttacker].type1 || moveType == gBattleMons[gBattlerAttacker].type2);
|
|
|
|
gBattleMons[gBattlerAttacker].type1 = moveType;
|
|
gBattleMons[gBattlerAttacker].type2 = moveType;
|
|
|
|
PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType)
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atk91_givepaydaymoney(void)
|
|
{
|
|
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) && gPaydayMoney != 0)
|
|
{
|
|
u32 bonusMoney = gPaydayMoney * gBattleStruct->moneyMultiplier;
|
|
AddMoney(&gSaveBlock1Ptr->money, bonusMoney);
|
|
|
|
PREPARE_HWORD_NUMBER_BUFFER(gBattleTextBuff1, 5, bonusMoney)
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_PrintPayDayMoneyString;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
|
|
static void atk92_setlightscreen(void)
|
|
{
|
|
if (gSideStatuses[GET_BATTLER_SIDE(gBattlerAttacker)] & SIDE_STATUS_LIGHTSCREEN)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
else
|
|
{
|
|
gSideStatuses[GET_BATTLER_SIDE(gBattlerAttacker)] |= SIDE_STATUS_LIGHTSCREEN;
|
|
gSideTimers[GET_BATTLER_SIDE(gBattlerAttacker)].lightscreenTimer = 5;
|
|
gSideTimers[GET_BATTLER_SIDE(gBattlerAttacker)].lightscreenBank = gBattlerAttacker;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk93_tryKO(void)
|
|
{
|
|
u8 holdEffect, param;
|
|
|
|
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);
|
|
}
|
|
|
|
gStringBattler = gBattlerTarget;
|
|
|
|
if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param)
|
|
{
|
|
RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_FOCUS_BAND);
|
|
gSpecialStatuses[gBattlerTarget].focusBanded = 1;
|
|
}
|
|
|
|
if (gBattleMons[gBattlerTarget].ability == ABILITY_STURDY)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gLastUsedAbility = ABILITY_STURDY;
|
|
gBattlescriptCurrInstr = BattleScript_SturdyPreventsOHKO;
|
|
RecordAbilityBattle(gBattlerTarget, ABILITY_STURDY);
|
|
}
|
|
else
|
|
{
|
|
u16 chance;
|
|
if (!(gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS))
|
|
{
|
|
chance = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBattlerAttacker].level - gBattleMons[gBattlerTarget].level);
|
|
if (Random() % 100 + 1 < chance && gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level)
|
|
chance = TRUE;
|
|
else
|
|
chance = FALSE;
|
|
}
|
|
else if (gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker
|
|
&& gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level)
|
|
{
|
|
chance = TRUE;
|
|
}
|
|
else
|
|
{
|
|
chance = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBattlerAttacker].level - gBattleMons[gBattlerTarget].level);
|
|
if (Random() % 100 + 1 < chance && gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level)
|
|
chance = TRUE;
|
|
else
|
|
chance = FALSE;
|
|
}
|
|
if (chance)
|
|
{
|
|
if (gProtectStructs[gBattlerTarget].endured)
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - 1;
|
|
gMoveResultFlags |= MOVE_RESULT_FOE_ENDURED;
|
|
}
|
|
else if (gSpecialStatuses[gBattlerTarget].focusBanded)
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - 1;
|
|
gMoveResultFlags |= MOVE_RESULT_FOE_HUNG_ON;
|
|
gLastUsedItem = gBattleMons[gBattlerTarget].item;
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp;
|
|
gMoveResultFlags |= MOVE_RESULT_ONE_HIT_KO;
|
|
}
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
if (gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atk94_damagetohalftargethp(void) // super fang
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp / 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk95_setsandstorm(void)
|
|
{
|
|
if (gBattleWeather & WEATHER_SANDSTORM_ANY)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
}
|
|
else
|
|
{
|
|
gBattleWeather = WEATHER_SANDSTORM_TEMPORARY;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
|
|
gWishFutureKnock.weatherDuration = 5;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk96_weatherdamage(void)
|
|
{
|
|
if (WEATHER_HAS_EFFECT)
|
|
{
|
|
if (gBattleWeather & WEATHER_SANDSTORM_ANY)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].type1 != TYPE_ROCK
|
|
&& gBattleMons[gBattlerAttacker].type1 != TYPE_STEEL
|
|
&& gBattleMons[gBattlerAttacker].type1 != TYPE_GROUND
|
|
&& gBattleMons[gBattlerAttacker].type2 != TYPE_ROCK
|
|
&& gBattleMons[gBattlerAttacker].type2 != TYPE_STEEL
|
|
&& gBattleMons[gBattlerAttacker].type2 != TYPE_GROUND
|
|
&& gBattleMons[gBattlerAttacker].ability != ABILITY_SAND_VEIL
|
|
&& !(gStatuses3[gBattlerAttacker] & STATUS3_UNDERGROUND)
|
|
&& !(gStatuses3[gBattlerAttacker] & STATUS3_UNDERWATER))
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = 0;
|
|
}
|
|
}
|
|
if (gBattleWeather & WEATHER_HAIL)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].type1 != TYPE_ICE
|
|
&& gBattleMons[gBattlerAttacker].type2 != TYPE_ICE
|
|
&& !(gStatuses3[gBattlerAttacker] & STATUS3_UNDERGROUND)
|
|
&& !(gStatuses3[gBattlerAttacker] & STATUS3_UNDERWATER))
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = 0;
|
|
}
|
|
|
|
if (gAbsentBattlerFlags & gBitTable[gBattlerAttacker])
|
|
gBattleMoveDamage = 0;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk97_tryinfatuating(void)
|
|
{
|
|
struct Pokemon *monAttacker, *monTarget;
|
|
u16 speciesAttacker, speciesTarget;
|
|
u32 personalityAttacker, personalityTarget;
|
|
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
|
monAttacker = &gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]];
|
|
else
|
|
monAttacker = &gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker]];
|
|
|
|
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
|
|
monTarget = &gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]];
|
|
else
|
|
monTarget = &gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]];
|
|
|
|
speciesAttacker = GetMonData(monAttacker, MON_DATA_SPECIES);
|
|
personalityAttacker = GetMonData(monAttacker, MON_DATA_PERSONALITY);
|
|
|
|
speciesTarget = GetMonData(monTarget, MON_DATA_SPECIES);
|
|
personalityTarget = GetMonData(monTarget, MON_DATA_PERSONALITY);
|
|
|
|
if (gBattleMons[gBattlerTarget].ability == ABILITY_OBLIVIOUS)
|
|
{
|
|
gBattlescriptCurrInstr = BattleScript_ObliviousPreventsAttraction;
|
|
gLastUsedAbility = ABILITY_OBLIVIOUS;
|
|
RecordAbilityBattle(gBattlerTarget, ABILITY_OBLIVIOUS);
|
|
}
|
|
else
|
|
{
|
|
if (GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget)
|
|
|| gBattleMons[gBattlerTarget].status2 & STATUS2_INFATUATION
|
|
|| GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == MON_GENDERLESS
|
|
|| GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget) == MON_GENDERLESS)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gBattlerTarget].status2 |= STATUS2_INFATUATED_WITH(gBattlerAttacker);
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atk98_updatestatusicon(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
if (gBattlescriptCurrInstr[1] != BS_ATTACKER_WITH_PARTNER)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitStatusIconUpdate(0, gBattleMons[gActiveBattler].status1, gBattleMons[gActiveBattler].status2);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
if (!(gAbsentBattlerFlags & gBitTable[gActiveBattler]))
|
|
{
|
|
BtlController_EmitStatusIconUpdate(0, gBattleMons[gActiveBattler].status1, gBattleMons[gActiveBattler].status2);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_FLANK);
|
|
if (!(gAbsentBattlerFlags & gBitTable[gActiveBattler]))
|
|
{
|
|
BtlController_EmitStatusIconUpdate(0, gBattleMons[gActiveBattler].status1, gBattleMons[gActiveBattler].status2);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
}
|
|
|
|
static void atk99_setmist(void)
|
|
{
|
|
if (gSideTimers[GET_BATTLER_SIDE(gBattlerAttacker)].mistTimer)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_FAILED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else
|
|
{
|
|
gSideTimers[GET_BATTLER_SIDE(gBattlerAttacker)].mistTimer = 5;
|
|
gSideTimers[GET_BATTLER_SIDE(gBattlerAttacker)].mistBank = gBattlerAttacker;
|
|
gSideStatuses[GET_BATTLER_SIDE(gBattlerAttacker)] |= SIDE_STATUS_MIST;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk9A_setfocusenergy(void)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_FAILED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_FOCUS_ENERGY;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atk9B_transformdataexecution(void)
|
|
{
|
|
gChosenMove = 0xFFFF;
|
|
gBattlescriptCurrInstr++;
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_TRANSFORMED
|
|
|| gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_FAILED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else
|
|
{
|
|
s32 i;
|
|
u8 *battleMonAttacker, *battleMonTarget;
|
|
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_TRANSFORMED;
|
|
gDisableStructs[gBattlerAttacker].disabledMove = 0;
|
|
gDisableStructs[gBattlerAttacker].disableTimer1 = 0;
|
|
gDisableStructs[gBattlerAttacker].transformedMonPersonality = gBattleMons[gBattlerTarget].personality;
|
|
gDisableStructs[gBattlerAttacker].unk18_b = 0;
|
|
|
|
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerTarget].species)
|
|
|
|
battleMonAttacker = (u8*)(&gBattleMons[gBattlerAttacker]);
|
|
battleMonTarget = (u8*)(&gBattleMons[gBattlerTarget]);
|
|
|
|
for (i = 0; i < offsetof(struct BattlePokemon, pp); i++)
|
|
battleMonAttacker[i] = battleMonTarget[i];
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gBattleMoves[gBattleMons[gBattlerAttacker].moves[i]].pp < 5)
|
|
gBattleMons[gBattlerAttacker].pp[i] = gBattleMoves[gBattleMons[gBattlerAttacker].moves[i]].pp;
|
|
else
|
|
gBattleMons[gBattlerAttacker].pp[i] = 5;
|
|
}
|
|
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitResetActionMoveSelection(0, RESET_MOVE_SELECTION);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
}
|
|
|
|
static void atk9C_setsubstitute(void)
|
|
{
|
|
u32 hp = gBattleMons[gBattlerAttacker].maxHP / 4;
|
|
if (gBattleMons[gBattlerAttacker].maxHP / 4 == 0)
|
|
hp = 1;
|
|
|
|
if (gBattleMons[gBattlerAttacker].hp <= hp)
|
|
{
|
|
gBattleMoveDamage = 0;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4; // one bit value will only work for pokemon which max hp can go to 1020(which is more than possible in games)
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_SUBSTITUTE;
|
|
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_WRAPPED);
|
|
gDisableStructs[gBattlerAttacker].substituteHP = gBattleMoveDamage;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static bool8 IsMoveUncopyableByMimic(u16 move)
|
|
{
|
|
s32 i;
|
|
for (i = 0; sMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END
|
|
&& sMovesForbiddenToCopy[i] != move; i++);
|
|
|
|
return (sMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END);
|
|
}
|
|
|
|
static void atk9D_mimicattackcopy(void)
|
|
{
|
|
gChosenMove = 0xFFFF;
|
|
|
|
if (IsMoveUncopyableByMimic(gLastMoves[gBattlerTarget])
|
|
|| gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED
|
|
|| gLastMoves[gBattlerTarget] == 0
|
|
|| gLastMoves[gBattlerTarget] == 0xFFFF)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].moves[i] == gLastMoves[gBattlerTarget])
|
|
break;
|
|
}
|
|
|
|
if (i == 4)
|
|
{
|
|
gBattleMons[gBattlerAttacker].moves[gCurrMovePos] = gLastMoves[gBattlerTarget];
|
|
if (gBattleMoves[gLastMoves[gBattlerTarget]].pp < 5)
|
|
gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = gBattleMoves[gLastMoves[gBattlerTarget]].pp;
|
|
else
|
|
gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = 5;
|
|
|
|
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastMoves[gBattlerTarget])
|
|
|
|
gDisableStructs[gBattlerAttacker].unk18_b |= gBitTable[gCurrMovePos];
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atk9E_metronome(void)
|
|
{
|
|
while (1)
|
|
{
|
|
s32 i;
|
|
|
|
gCurrentMove = (Random() & 0x1FF) + 1;
|
|
if (gCurrentMove > LAST_MOVE_INDEX)
|
|
continue;
|
|
|
|
for (i = 0; i < 4; i++); // ?
|
|
|
|
i = -1;
|
|
while (1)
|
|
{
|
|
i++;
|
|
if (sMovesForbiddenToCopy[i] == gCurrentMove)
|
|
break;
|
|
if (sMovesForbiddenToCopy[i] == METRONOME_FORBIDDEN_END)
|
|
break;
|
|
}
|
|
|
|
if (sMovesForbiddenToCopy[i] == METRONOME_FORBIDDEN_END)
|
|
{
|
|
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
|
|
gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect];
|
|
gBattlerTarget = GetMoveTarget(gCurrentMove, 0);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atk9F_dmgtolevel(void)
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].level;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkA0_psywavedamageeffect(void)
|
|
{
|
|
s32 randDamage;
|
|
|
|
while ((randDamage = (Random() & 0xF)) > 10);
|
|
|
|
randDamage *= 10;
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].level * (randDamage + 50) / 100;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkA1_counterdamagecalculator(void)
|
|
{
|
|
u8 sideAttacker = GetBattlerSide(gBattlerAttacker);
|
|
u8 sideTarget = GetBattlerSide(gProtectStructs[gBattlerAttacker].physicalBank);
|
|
|
|
if (gProtectStructs[gBattlerAttacker].physicalDmg
|
|
&& sideAttacker != sideTarget
|
|
&& gBattleMons[gProtectStructs[gBattlerAttacker].physicalBank].hp)
|
|
{
|
|
gBattleMoveDamage = gProtectStructs[gBattlerAttacker].physicalDmg * 2;
|
|
|
|
if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp)
|
|
gBattlerTarget = gSideTimers[sideTarget].followmeTarget;
|
|
else
|
|
gBattlerTarget = gProtectStructs[gBattlerAttacker].physicalBank;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gSpecialStatuses[gBattlerAttacker].flag20 = 1;
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkA2_mirrorcoatdamagecalculator(void) // a copy of atkA1 with the physical -> special field changes
|
|
{
|
|
u8 sideAttacker = GetBattlerSide(gBattlerAttacker);
|
|
u8 sideTarget = GetBattlerSide(gProtectStructs[gBattlerAttacker].specialBank);
|
|
|
|
if (gProtectStructs[gBattlerAttacker].specialDmg && sideAttacker != sideTarget && gBattleMons[gProtectStructs[gBattlerAttacker].specialBank].hp)
|
|
{
|
|
gBattleMoveDamage = gProtectStructs[gBattlerAttacker].specialDmg * 2;
|
|
|
|
if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp)
|
|
gBattlerTarget = gSideTimers[sideTarget].followmeTarget;
|
|
else
|
|
gBattlerTarget = gProtectStructs[gBattlerAttacker].specialBank;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gSpecialStatuses[gBattlerAttacker].flag20 = 1;
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkA3_disablelastusedattack(void)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].moves[i] == gLastMoves[gBattlerTarget])
|
|
break;
|
|
}
|
|
if (gDisableStructs[gBattlerTarget].disabledMove == 0
|
|
&& i != 4 && gBattleMons[gBattlerTarget].pp[i] != 0)
|
|
{
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerTarget].moves[i])
|
|
|
|
gDisableStructs[gBattlerTarget].disabledMove = gBattleMons[gBattlerTarget].moves[i];
|
|
gDisableStructs[gBattlerTarget].disableTimer1 = (Random() & 3) + 2;
|
|
gDisableStructs[gBattlerTarget].disableTimer2 = gDisableStructs[gBattlerTarget].disableTimer1; // used to save the random amount of turns?
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkA4_trysetencore(void)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].moves[i] == gLastMoves[gBattlerTarget])
|
|
break;
|
|
}
|
|
|
|
if (gLastMoves[gBattlerTarget] == MOVE_STRUGGLE
|
|
|| gLastMoves[gBattlerTarget] == MOVE_ENCORE
|
|
|| gLastMoves[gBattlerTarget] == MOVE_MIRROR_MOVE)
|
|
{
|
|
i = 4;
|
|
}
|
|
|
|
if (gDisableStructs[gBattlerTarget].encoredMove == 0
|
|
&& i != 4 && gBattleMons[gBattlerTarget].pp[i] != 0)
|
|
{
|
|
gDisableStructs[gBattlerTarget].encoredMove = gBattleMons[gBattlerTarget].moves[i];
|
|
gDisableStructs[gBattlerTarget].encoredMovePos = i;
|
|
gDisableStructs[gBattlerTarget].encoreTimer1 = (Random() & 3) + 3;
|
|
gDisableStructs[gBattlerTarget].encoreTimer2 = gDisableStructs[gBattlerTarget].encoreTimer1;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkA5_painsplitdmgcalc(void)
|
|
{
|
|
if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE))
|
|
{
|
|
s32 hpDiff = (gBattleMons[gBattlerAttacker].hp + gBattleMons[gBattlerTarget].hp) / 2;
|
|
s32 painSplitHp = gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - hpDiff;
|
|
u8* storeLoc = (void*)(&gBattleScripting.painSplitHp);
|
|
|
|
storeLoc[0] = (painSplitHp);
|
|
storeLoc[1] = (painSplitHp & 0x0000FF00) >> 8;
|
|
storeLoc[2] = (painSplitHp & 0x00FF0000) >> 16;
|
|
storeLoc[3] = (painSplitHp & 0xFF000000) >> 24;
|
|
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].hp - hpDiff;
|
|
gSpecialStatuses[gBattlerTarget].moveturnLostHP = 0xFFFF;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkA6_settypetorandomresistance(void) // conversion 2
|
|
{
|
|
if (gLastLandedMoves[gBattlerAttacker] == 0
|
|
|| gLastLandedMoves[gBattlerAttacker] == 0xFFFF)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else if (IsTwoTurnsMove(gLastLandedMoves[gBattlerAttacker])
|
|
&& gBattleMons[gLastHitBy[gBattlerAttacker]].status2 & STATUS2_MULTIPLETURNS)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
s32 i, j, rands;
|
|
|
|
for (rands = 0; rands < 1000; rands++)
|
|
{
|
|
while (((i = (Random() & 0x7F)) > sizeof(gTypeEffectiveness) / 3));
|
|
|
|
i *= 3;
|
|
|
|
if (TYPE_EFFECT_ATK_TYPE(i) == gLastHitByType[gBattlerAttacker]
|
|
&& TYPE_EFFECT_MULTIPLIER(i) <= TYPE_MUL_NOT_EFFECTIVE
|
|
&& gBattleMons[gBattlerAttacker].type1 != TYPE_EFFECT_DEF_TYPE(i)
|
|
&& gBattleMons[gBattlerAttacker].type2 != TYPE_EFFECT_DEF_TYPE(i))
|
|
{
|
|
gBattleMons[gBattlerAttacker].type1 = TYPE_EFFECT_DEF_TYPE(i);
|
|
gBattleMons[gBattlerAttacker].type2 = TYPE_EFFECT_DEF_TYPE(i);
|
|
|
|
PREPARE_TYPE_BUFFER(gBattleTextBuff1, TYPE_EFFECT_DEF_TYPE(i))
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (j = 0, rands = 0; rands < sizeof(gTypeEffectiveness); j += 3, rands += 3)
|
|
{
|
|
switch (TYPE_EFFECT_ATK_TYPE(j))
|
|
{
|
|
case TYPE_ENDTABLE:
|
|
case TYPE_FORESIGHT:
|
|
break;
|
|
default:
|
|
if (TYPE_EFFECT_ATK_TYPE(j) == gLastHitByType[gBattlerAttacker]
|
|
&& TYPE_EFFECT_MULTIPLIER(j) <= 5
|
|
&& gBattleMons[gBattlerAttacker].type1 != TYPE_EFFECT_DEF_TYPE(i)
|
|
&& gBattleMons[gBattlerAttacker].type2 != TYPE_EFFECT_DEF_TYPE(i))
|
|
{
|
|
gBattleMons[gBattlerAttacker].type1 = TYPE_EFFECT_DEF_TYPE(rands);
|
|
gBattleMons[gBattlerAttacker].type2 = TYPE_EFFECT_DEF_TYPE(rands);
|
|
|
|
PREPARE_TYPE_BUFFER(gBattleTextBuff1, TYPE_EFFECT_DEF_TYPE(rands))
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkA7_setalwayshitflag(void)
|
|
{
|
|
gStatuses3[gBattlerTarget] &= ~(STATUS3_ALWAYS_HITS);
|
|
gStatuses3[gBattlerTarget] |= 0x10;
|
|
gDisableStructs[gBattlerTarget].battlerWithSureHit = gBattlerAttacker;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkA8_copymovepermanently(void) // sketch
|
|
{
|
|
gChosenMove = 0xFFFF;
|
|
|
|
if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED)
|
|
&& gLastPrintedMoves[gBattlerTarget] != MOVE_STRUGGLE
|
|
&& gLastPrintedMoves[gBattlerTarget] != 0
|
|
&& gLastPrintedMoves[gBattlerTarget] != 0xFFFF
|
|
&& gLastPrintedMoves[gBattlerTarget] != MOVE_SKETCH)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].moves[i] == MOVE_SKETCH)
|
|
continue;
|
|
if (gBattleMons[gBattlerAttacker].moves[i] == gLastPrintedMoves[gBattlerTarget])
|
|
break;
|
|
}
|
|
|
|
if (i != 4)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else // sketch worked
|
|
{
|
|
struct MovePpInfo movePpData;
|
|
|
|
gBattleMons[gBattlerAttacker].moves[gCurrMovePos] = gLastPrintedMoves[gBattlerTarget];
|
|
gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = gBattleMoves[gLastPrintedMoves[gBattlerTarget]].pp;
|
|
gActiveBattler = gBattlerAttacker;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
movePpData.moves[i] = gBattleMons[gBattlerAttacker].moves[i];
|
|
movePpData.pp[i] = gBattleMons[gBattlerAttacker].pp[i];
|
|
}
|
|
movePpData.ppBonuses = gBattleMons[gBattlerAttacker].ppBonuses;
|
|
|
|
BtlController_EmitSetMonData(0, REQUEST_MOVES_PP_BATTLE, 0, sizeof(struct MovePpInfo), &movePpData);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastPrintedMoves[gBattlerTarget])
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static bool8 IsTwoTurnsMove(u16 move)
|
|
{
|
|
if (gBattleMoves[move].effect == EFFECT_SKULL_BASH
|
|
|| gBattleMoves[move].effect == EFFECT_RAZOR_WIND
|
|
|| gBattleMoves[move].effect == EFFECT_SKY_ATTACK
|
|
|| gBattleMoves[move].effect == EFFECT_SOLARBEAM
|
|
|| gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE
|
|
|| gBattleMoves[move].effect == EFFECT_BIDE)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static bool8 IsInvalidForSleepTalkOrAssist(u16 move)
|
|
{
|
|
if (move == 0 || move == MOVE_SLEEP_TALK || move == MOVE_ASSIST
|
|
|| move == MOVE_MIRROR_MOVE || move == MOVE_METRONOME)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static u8 AttacksThisTurn(u8 bank, u16 move) // Note: returns 1 if it's a charging turn, otherwise 2
|
|
{
|
|
// first argument is unused
|
|
if (gBattleMoves[move].effect == EFFECT_SOLARBEAM
|
|
&& (gBattleWeather & WEATHER_SUN_ANY))
|
|
return 2;
|
|
|
|
if (gBattleMoves[move].effect == EFFECT_SKULL_BASH
|
|
|| gBattleMoves[move].effect == EFFECT_RAZOR_WIND
|
|
|| gBattleMoves[move].effect == EFFECT_SKY_ATTACK
|
|
|| gBattleMoves[move].effect == EFFECT_SOLARBEAM
|
|
|| gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE
|
|
|| gBattleMoves[move].effect == EFFECT_BIDE)
|
|
{
|
|
if ((gHitMarker & HITMARKER_x8000000))
|
|
return 1;
|
|
}
|
|
return 2;
|
|
}
|
|
|
|
static void atkA9_trychoosesleeptalkmove(void)
|
|
{
|
|
s32 i;
|
|
u8 unusableMovesBits = 0;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (IsInvalidForSleepTalkOrAssist(gBattleMons[gBattlerAttacker].moves[i])
|
|
|| gBattleMons[gBattlerAttacker].moves[i] == MOVE_FOCUS_PUNCH
|
|
|| gBattleMons[gBattlerAttacker].moves[i] == MOVE_UPROAR
|
|
|| IsTwoTurnsMove(gBattleMons[gBattlerAttacker].moves[i]))
|
|
{
|
|
unusableMovesBits |= gBitTable[i];
|
|
}
|
|
|
|
}
|
|
|
|
unusableMovesBits = CheckMoveLimitations(gBattlerAttacker, unusableMovesBits, ~(MOVE_LIMITATION_PP));
|
|
if (unusableMovesBits == 0xF) // all 4 moves cannot be chosen
|
|
{
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else // at least one move can be chosen
|
|
{
|
|
u32 movePosition;
|
|
|
|
do
|
|
{
|
|
movePosition = Random() & 3;
|
|
} while ((gBitTable[movePosition] & unusableMovesBits));
|
|
|
|
gRandomMove = gBattleMons[gBattlerAttacker].moves[movePosition];
|
|
gCurrMovePos = movePosition;
|
|
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
|
|
gBattlerTarget = GetMoveTarget(gRandomMove, 0);
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkAA_setdestinybond(void)
|
|
{
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_DESTINY_BOND;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void TrySetDestinyBondToHappen(void)
|
|
{
|
|
u8 sideAttacker = GetBattlerSide(gBattlerAttacker);
|
|
u8 sideTarget = GetBattlerSide(gBattlerTarget);
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_DESTINY_BOND
|
|
&& sideAttacker != sideTarget
|
|
&& !(gHitMarker & HITMARKER_GRUDGE))
|
|
{
|
|
gHitMarker |= HITMARKER_DESTINYBOND;
|
|
}
|
|
}
|
|
|
|
static void atkAB_trysetdestinybondtohappen(void)
|
|
{
|
|
TrySetDestinyBondToHappen();
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkAC_remaininghptopower(void)
|
|
{
|
|
s32 i;
|
|
s32 hpFraction = GetScaledHPFraction(gBattleMons[gBattlerAttacker].hp, gBattleMons[gBattlerAttacker].maxHP, 48);
|
|
|
|
for (i = 0; i < (s32) sizeof(sFlailHpScaleToPowerTable); i += 2)
|
|
{
|
|
if (hpFraction <= sFlailHpScaleToPowerTable[i])
|
|
break;
|
|
}
|
|
|
|
gDynamicBasePower = sFlailHpScaleToPowerTable[i + 1];
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkAD_tryspiteppreduce(void)
|
|
{
|
|
if (gLastMoves[gBattlerTarget] != 0
|
|
&& gLastMoves[gBattlerTarget] != 0xFFFF)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gLastMoves[gBattlerTarget] == gBattleMons[gBattlerTarget].moves[i])
|
|
break;
|
|
}
|
|
|
|
if (i != 4 && gBattleMons[gBattlerTarget].pp[i] > 1)
|
|
{
|
|
s32 ppToDeduct = (Random() & 3) + 2;
|
|
if (gBattleMons[gBattlerTarget].pp[i] < ppToDeduct)
|
|
ppToDeduct = gBattleMons[gBattlerTarget].pp[i];
|
|
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastMoves[gBattlerTarget])
|
|
|
|
ConvertIntToDecimalStringN(gBattleTextBuff2, ppToDeduct, 0, 1);
|
|
|
|
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct)
|
|
|
|
gBattleMons[gBattlerTarget].pp[i] -= ppToDeduct;
|
|
gActiveBattler = gBattlerTarget;
|
|
|
|
if (!(gDisableStructs[gActiveBattler].unk18_b & gBitTable[i])
|
|
&& !(gBattleMons[gActiveBattler].status2 & STATUS2_TRANSFORMED))
|
|
{
|
|
BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBattler].pp[i]);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
|
|
if (gBattleMons[gBattlerTarget].pp[i] == 0)
|
|
CancelMultiTurnMoves(gBattlerTarget);
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkAE_healpartystatus(void)
|
|
{
|
|
u32 zero = 0;
|
|
u8 toHeal = 0;
|
|
|
|
if (gCurrentMove == MOVE_HEAL_BELL)
|
|
{
|
|
struct Pokemon* party;
|
|
s32 i;
|
|
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
|
party = gPlayerParty;
|
|
else
|
|
party = gEnemyParty;
|
|
|
|
if (gBattleMons[gBattlerAttacker].ability != ABILITY_SOUNDPROOF)
|
|
{
|
|
gBattleMons[gBattlerAttacker].status1 = 0;
|
|
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE);
|
|
}
|
|
else
|
|
{
|
|
RecordAbilityBattle(gBattlerAttacker, gBattleMons[gBattlerAttacker].ability);
|
|
gBattleCommunication[MULTISTRING_CHOOSER] |= 1;
|
|
}
|
|
|
|
gActiveBattler = gBattleScripting.battler = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_FLANK);
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
|
&& !(gAbsentBattlerFlags & gBitTable[gActiveBattler]))
|
|
{
|
|
if (gBattleMons[gActiveBattler].ability != ABILITY_SOUNDPROOF)
|
|
{
|
|
gBattleMons[gActiveBattler].status1 = 0;
|
|
gBattleMons[gActiveBattler].status2 &= ~(STATUS2_NIGHTMARE);
|
|
}
|
|
else
|
|
{
|
|
RecordAbilityBattle(gActiveBattler, gBattleMons[gActiveBattler].ability);
|
|
gBattleCommunication[MULTISTRING_CHOOSER] |= 2;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
u16 species = GetMonData(&party[i], MON_DATA_SPECIES2);
|
|
u8 abilityBit = GetMonData(&party[i], MON_DATA_ALT_ABILITY);
|
|
|
|
if (species != 0 && species != SPECIES_EGG)
|
|
{
|
|
u8 ability;
|
|
|
|
if (gBattlerPartyIndexes[gBattlerAttacker] == i)
|
|
ability = gBattleMons[gBattlerAttacker].ability;
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
|
&& gBattlerPartyIndexes[gActiveBattler] == i
|
|
&& !(gAbsentBattlerFlags & gBitTable[gActiveBattler]))
|
|
ability = gBattleMons[gActiveBattler].ability;
|
|
else
|
|
ability = GetAbilityBySpecies(species, abilityBit);
|
|
|
|
if (ability != ABILITY_SOUNDPROOF)
|
|
toHeal |= (1 << i);
|
|
}
|
|
}
|
|
}
|
|
else // Aromatherapy
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
|
|
toHeal = 0x3F;
|
|
|
|
gBattleMons[gBattlerAttacker].status1 = 0;
|
|
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE);
|
|
|
|
gActiveBattler = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_FLANK);
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
|
&& !(gAbsentBattlerFlags & gBitTable[gActiveBattler]))
|
|
{
|
|
gBattleMons[gActiveBattler].status1 = 0;
|
|
gBattleMons[gActiveBattler].status2 &= ~(STATUS2_NIGHTMARE);
|
|
}
|
|
|
|
}
|
|
|
|
if (toHeal)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, toHeal, 4, &zero);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkAF_cursetarget(void)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_CURSED)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gBattlerTarget].status2 |= STATUS2_CURSED;
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkB0_trysetspikes(void)
|
|
{
|
|
u8 targetSide = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
|
|
|
|
if (gSideTimers[targetSide].spikesAmount == 3)
|
|
{
|
|
gSpecialStatuses[gBattlerAttacker].flag20 = 1;
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gSideStatuses[targetSide] |= SIDE_STATUS_SPIKES;
|
|
gSideTimers[targetSide].spikesAmount++;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkB1_setforesight(void)
|
|
{
|
|
gBattleMons[gBattlerTarget].status2 |= STATUS2_FORESIGHT;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkB2_trysetperishsong(void)
|
|
{
|
|
s32 i;
|
|
s32 notAffectedCount = 0;
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gStatuses3[i] & STATUS3_PERISH_SONG
|
|
|| gBattleMons[i].ability == ABILITY_SOUNDPROOF)
|
|
{
|
|
notAffectedCount++;
|
|
}
|
|
else
|
|
{
|
|
gStatuses3[i] |= STATUS3_PERISH_SONG;
|
|
gDisableStructs[i].perishSongTimer1 = 3;
|
|
gDisableStructs[i].perishSongTimer2 = 3;
|
|
}
|
|
}
|
|
|
|
PressurePPLoseOnUsingPerishSong(gBattlerAttacker);
|
|
|
|
if (notAffectedCount == gBattlersCount)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
|
|
static void atkB3_rolloutdamagecalculation(void)
|
|
{
|
|
if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
|
{
|
|
CancelMultiTurnMoves(gBattlerAttacker);
|
|
gBattlescriptCurrInstr = BattleScript_MoveMissedPause;
|
|
}
|
|
else
|
|
{
|
|
s32 i;
|
|
|
|
if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) // first hit
|
|
{
|
|
gDisableStructs[gBattlerAttacker].rolloutCounter1 = 5;
|
|
gDisableStructs[gBattlerAttacker].rolloutCounter2 = 5;
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_MULTIPLETURNS;
|
|
gLockedMoves[gBattlerAttacker] = gCurrentMove;
|
|
}
|
|
if (--gDisableStructs[gBattlerAttacker].rolloutCounter1 == 0) // last hit
|
|
{
|
|
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_MULTIPLETURNS);
|
|
}
|
|
|
|
gDynamicBasePower = gBattleMoves[gCurrentMove].power;
|
|
|
|
for (i = 1; i < (5 - gDisableStructs[gBattlerAttacker].rolloutCounter1); i++)
|
|
gDynamicBasePower *= 2;
|
|
|
|
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_DEFENSE_CURL)
|
|
gDynamicBasePower *= 2;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
|
|
static void atkB4_jumpifconfusedandstatmaxed(void)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_CONFUSION
|
|
&& gBattleMons[gBattlerTarget].statStages[gBattlescriptCurrInstr[1]] == 0xC)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void atkB5_furycuttercalc(void)
|
|
{
|
|
if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
|
{
|
|
gDisableStructs[gBattlerAttacker].furyCutterCounter = 0;
|
|
gBattlescriptCurrInstr = BattleScript_MoveMissedPause;
|
|
}
|
|
else
|
|
{
|
|
s32 i;
|
|
|
|
if (gDisableStructs[gBattlerAttacker].furyCutterCounter != 5)
|
|
gDisableStructs[gBattlerAttacker].furyCutterCounter++;
|
|
|
|
gDynamicBasePower = gBattleMoves[gCurrentMove].power;
|
|
|
|
for (i = 1; i < gDisableStructs[gBattlerAttacker].furyCutterCounter; i++)
|
|
gDynamicBasePower *= 2;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
|
|
static void atkB6_happinesstodamagecalculation(void)
|
|
{
|
|
if (gBattleMoves[gCurrentMove].effect == EFFECT_RETURN)
|
|
gDynamicBasePower = 10 * (gBattleMons[gBattlerAttacker].friendship) / 25;
|
|
else // EFFECT_FRUSTRATION
|
|
gDynamicBasePower = 10 * (255 - gBattleMons[gBattlerAttacker].friendship) / 25;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkB7_presentdamagecalculation(void)
|
|
{
|
|
s32 rand = Random() & 0xFF;
|
|
|
|
if (rand < 102)
|
|
gDynamicBasePower = 40;
|
|
else if (rand < 178)
|
|
gDynamicBasePower = 80;
|
|
else if (rand < 204)
|
|
gDynamicBasePower = 120;
|
|
else
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 4;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
gBattleMoveDamage *= -1;
|
|
}
|
|
if (rand < 204)
|
|
gBattlescriptCurrInstr = BattleScript_HitFromCritCalc;
|
|
else if (gBattleMons[gBattlerTarget].maxHP == gBattleMons[gBattlerTarget].hp)
|
|
gBattlescriptCurrInstr = BattleScript_AlreadyAtFullHp;
|
|
else
|
|
{
|
|
gMoveResultFlags &= ~(MOVE_RESULT_DOESNT_AFFECT_FOE);
|
|
gBattlescriptCurrInstr = BattleScript_PresentHealTarget;
|
|
}
|
|
}
|
|
|
|
static void atkB8_setsafeguard(void)
|
|
{
|
|
if (gSideStatuses[GET_BATTLER_SIDE(gBattlerAttacker)] & SIDE_STATUS_SAFEGUARD)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
else
|
|
{
|
|
gSideStatuses[GET_BATTLER_SIDE(gBattlerAttacker)] |= SIDE_STATUS_SAFEGUARD;
|
|
gSideTimers[GET_BATTLER_SIDE(gBattlerAttacker)].safeguardTimer = 5;
|
|
gSideTimers[GET_BATTLER_SIDE(gBattlerAttacker)].safeguardBank = gBattlerAttacker;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 5;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkB9_magnitudedamagecalculation(void)
|
|
{
|
|
s32 magnitude = Random() % 100;
|
|
|
|
if (magnitude < 5)
|
|
{
|
|
gDynamicBasePower = 10;
|
|
magnitude = 4;
|
|
}
|
|
else if (magnitude < 15)
|
|
{
|
|
gDynamicBasePower = 30;
|
|
magnitude = 5;
|
|
}
|
|
else if (magnitude < 35)
|
|
{
|
|
gDynamicBasePower = 50;
|
|
magnitude = 6;
|
|
}
|
|
else if (magnitude < 65)
|
|
{
|
|
gDynamicBasePower = 70;
|
|
magnitude = 7;
|
|
}
|
|
else if (magnitude < 85)
|
|
{
|
|
gDynamicBasePower = 90;
|
|
magnitude = 8;
|
|
}
|
|
else if (magnitude < 95)
|
|
{
|
|
gDynamicBasePower = 110;
|
|
magnitude = 9;
|
|
}
|
|
else
|
|
{
|
|
gDynamicBasePower = 150;
|
|
magnitude = 10;
|
|
}
|
|
|
|
|
|
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 2, magnitude)
|
|
|
|
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
|
|
{
|
|
if (gBattlerTarget == gBattlerAttacker)
|
|
continue;
|
|
if (!(gAbsentBattlerFlags & gBitTable[gBattlerTarget])) // a valid target was found
|
|
break;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkBA_jumpifnopursuitswitchdmg(void)
|
|
{
|
|
if (gMultiHitCounter == 1)
|
|
{
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
|
gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
|
else
|
|
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
}
|
|
else
|
|
{
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
|
gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
|
else
|
|
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
|
}
|
|
|
|
if (gChosenActionByBattler[gBattlerTarget] == B_ACTION_USE_MOVE
|
|
&& gBattlerAttacker == *(gBattleStruct->moveTarget + gBattlerTarget)
|
|
&& !(gBattleMons[gBattlerTarget].status1 & (STATUS1_SLEEP | STATUS1_FREEZE))
|
|
&& gBattleMons[gBattlerAttacker].hp
|
|
&& !gDisableStructs[gBattlerTarget].truantCounter
|
|
&& gChosenMoveByBattler[gBattlerTarget] == MOVE_PURSUIT)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gBattleTurnOrder[i] == gBattlerTarget)
|
|
gActionsByTurnOrder[i] = 11;
|
|
}
|
|
|
|
gCurrentMove = MOVE_PURSUIT;
|
|
gCurrMovePos = gUnknown_020241E9 = *(gBattleStruct->chosenMovePositions + gBattlerTarget);
|
|
gBattlescriptCurrInstr += 5;
|
|
gBattleScripting.animTurn = 1;
|
|
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkBB_setsunny(void)
|
|
{
|
|
if (gBattleWeather & WEATHER_SUN_ANY)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
}
|
|
else
|
|
{
|
|
gBattleWeather = WEATHER_SUN_TEMPORARY;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
|
|
gWishFutureKnock.weatherDuration = 5;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkBC_maxattackhalvehp(void) // belly drum
|
|
{
|
|
u32 halfHp = gBattleMons[gBattlerAttacker].maxHP / 2;
|
|
|
|
if (!(gBattleMons[gBattlerAttacker].maxHP / 2))
|
|
halfHp = 1;
|
|
|
|
if (gBattleMons[gBattlerAttacker].statStages[STAT_STAGE_ATK] < 12
|
|
&& gBattleMons[gBattlerAttacker].hp > halfHp)
|
|
{
|
|
gBattleMons[gBattlerAttacker].statStages[STAT_STAGE_ATK] = 12;
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkBD_copyfoestats(void) // psych up
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < BATTLE_STATS_NO; i++)
|
|
{
|
|
gBattleMons[gBattlerAttacker].statStages[i] = gBattleMons[gBattlerTarget].statStages[i];
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 5; // Has an unused jump ptr(possibly for a failed attempt) parameter.
|
|
}
|
|
|
|
static void atkBE_rapidspinfree(void)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_WRAPPED)
|
|
{
|
|
gBattleScripting.battler = gBattlerTarget;
|
|
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_WRAPPED);
|
|
gBattlerTarget = *(gBattleStruct->wrappedBy + gBattlerAttacker);
|
|
|
|
gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN;
|
|
gBattleTextBuff1[1] = B_BUFF_MOVE;
|
|
gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gBattlerAttacker * 2 + 0);
|
|
gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gBattlerAttacker * 2 + 1);
|
|
gBattleTextBuff1[4] = B_BUFF_EOS;
|
|
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_WrapFree;
|
|
}
|
|
else if (gStatuses3[gBattlerAttacker] & STATUS3_LEECHSEED)
|
|
{
|
|
gStatuses3[gBattlerAttacker] &= ~(STATUS3_LEECHSEED);
|
|
gStatuses3[gBattlerAttacker] &= ~(STATUS3_LEECHSEED_BANK);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_LeechSeedFree;
|
|
}
|
|
else if (gSideStatuses[GetBattlerSide(gBattlerAttacker)] & SIDE_STATUS_SPIKES)
|
|
{
|
|
gSideStatuses[GetBattlerSide(gBattlerAttacker)] &= ~(SIDE_STATUS_SPIKES);
|
|
gSideTimers[GetBattlerSide(gBattlerAttacker)].spikesAmount = 0;
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_SpikesFree;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
|
|
static void atkBF_setdefensecurlbit(void)
|
|
{
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_DEFENSE_CURL;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkC0_recoverbasedonsunlight(void)
|
|
{
|
|
gBattlerTarget = gBattlerAttacker;
|
|
|
|
if (gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP)
|
|
{
|
|
if (gBattleWeather == 0 || !WEATHER_HAS_EFFECT)
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
|
|
else if (gBattleWeather & WEATHER_SUN_ANY)
|
|
gBattleMoveDamage = 20 * gBattleMons[gBattlerAttacker].maxHP / 30;
|
|
else // not sunny weather
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4;
|
|
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
gBattleMoveDamage *= -1;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
#ifdef NONMATCHING
|
|
static void atkC1_hiddenpowercalc(void)
|
|
{
|
|
u32 powerBits = 0;
|
|
u32 typeBits = 0;
|
|
|
|
powerBits |= ((gBattleMons[gBattlerAttacker].hpIV & 2) >> 1);
|
|
powerBits |= ((gBattleMons[gBattlerAttacker].attackIV & 2) << 0);
|
|
powerBits |= ((gBattleMons[gBattlerAttacker].defenseIV & 2) << 1);
|
|
powerBits |= ((gBattleMons[gBattlerAttacker].speedIV & 2) << 2);
|
|
powerBits |= ((gBattleMons[gBattlerAttacker].spAttackIV & 2) << 3);
|
|
powerBits |= ((gBattleMons[gBattlerAttacker].spDefenseIV & 2) << 4);
|
|
|
|
typeBits |= ((gBattleMons[gBattlerAttacker].hpIV & 1) << 0);
|
|
typeBits |= ((gBattleMons[gBattlerAttacker].attackIV & 1) << 1);
|
|
typeBits |= ((gBattleMons[gBattlerAttacker].defenseIV & 1) << 2);
|
|
typeBits |= ((gBattleMons[gBattlerAttacker].speedIV & 1) << 3);
|
|
typeBits |= ((gBattleMons[gBattlerAttacker].spAttackIV & 1) << 4);
|
|
typeBits |= ((gBattleMons[gBattlerAttacker].spDefenseIV & 1) << 5);
|
|
|
|
gDynamicBasePower = (40 * powerBits) / 63 + 30;
|
|
|
|
gBattleStruct->dynamicMoveType = (15 * typeBits) / 63 + 1;
|
|
if (gBattleStruct->dynamicMoveType > 8)
|
|
gBattleStruct->dynamicMoveType++;
|
|
gBattleStruct->dynamicMoveType |= 0xC0;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
#else
|
|
__attribute__((naked))
|
|
static void atkC1_hiddenpowercalc(void)
|
|
{
|
|
asm(".syntax unified\n\
|
|
push {r4-r7,lr}\n\
|
|
mov r7, r10\n\
|
|
mov r6, r9\n\
|
|
mov r5, r8\n\
|
|
push {r5-r7}\n\
|
|
ldr r2, =gBattleMons\n\
|
|
ldr r0, =gBattlerAttacker\n\
|
|
ldrb r1, [r0]\n\
|
|
movs r0, 0x58\n\
|
|
adds r4, r1, 0\n\
|
|
muls r4, r0\n\
|
|
adds r4, r2\n\
|
|
ldrb r0, [r4, 0x14]\n\
|
|
mov r10, r0\n\
|
|
mov r7, r10\n\
|
|
lsls r7, 27\n\
|
|
adds r0, r7, 0\n\
|
|
lsrs r0, 27\n\
|
|
mov r10, r0\n\
|
|
movs r1, 0x2\n\
|
|
mov r2, r10\n\
|
|
ands r2, r1\n\
|
|
asrs r2, 1\n\
|
|
ldrh r7, [r4, 0x14]\n\
|
|
mov r9, r7\n\
|
|
mov r0, r9\n\
|
|
lsls r0, 22\n\
|
|
mov r9, r0\n\
|
|
lsrs r3, r0, 27\n\
|
|
adds r0, r1, 0\n\
|
|
ands r0, r3\n\
|
|
orrs r2, r0\n\
|
|
ldrb r7, [r4, 0x15]\n\
|
|
mov r8, r7\n\
|
|
mov r0, r8\n\
|
|
lsls r0, 25\n\
|
|
mov r8, r0\n\
|
|
lsrs r3, r0, 27\n\
|
|
adds r0, r1, 0\n\
|
|
ands r0, r3\n\
|
|
lsls r0, 1\n\
|
|
orrs r2, r0\n\
|
|
ldr r6, [r4, 0x14]\n\
|
|
lsls r6, 12\n\
|
|
lsrs r3, r6, 27\n\
|
|
adds r0, r1, 0\n\
|
|
ands r0, r3\n\
|
|
lsls r0, 2\n\
|
|
orrs r2, r0\n\
|
|
ldrh r5, [r4, 0x16]\n\
|
|
lsls r5, 23\n\
|
|
lsrs r3, r5, 27\n\
|
|
adds r0, r1, 0\n\
|
|
ands r0, r3\n\
|
|
lsls r0, 3\n\
|
|
orrs r2, r0\n\
|
|
ldrb r3, [r4, 0x17]\n\
|
|
lsls r3, 26\n\
|
|
lsrs r0, r3, 27\n\
|
|
ands r1, r0\n\
|
|
lsls r1, 4\n\
|
|
orrs r2, r1\n\
|
|
movs r1, 0x1\n\
|
|
adds r4, r1, 0\n\
|
|
mov r7, r10\n\
|
|
ands r4, r7\n\
|
|
mov r0, r9\n\
|
|
lsrs r0, 27\n\
|
|
mov r9, r0\n\
|
|
adds r0, r1, 0\n\
|
|
mov r7, r9\n\
|
|
ands r0, r7\n\
|
|
lsls r0, 1\n\
|
|
orrs r4, r0\n\
|
|
mov r0, r8\n\
|
|
lsrs r0, 27\n\
|
|
mov r8, r0\n\
|
|
adds r0, r1, 0\n\
|
|
mov r7, r8\n\
|
|
ands r0, r7\n\
|
|
lsls r0, 2\n\
|
|
orrs r4, r0\n\
|
|
lsrs r6, 27\n\
|
|
adds r0, r1, 0\n\
|
|
ands r0, r6\n\
|
|
lsls r0, 3\n\
|
|
orrs r4, r0\n\
|
|
lsrs r5, 27\n\
|
|
adds r0, r1, 0\n\
|
|
ands r0, r5\n\
|
|
lsls r0, 4\n\
|
|
orrs r4, r0\n\
|
|
lsrs r3, 27\n\
|
|
ands r1, r3\n\
|
|
lsls r1, 5\n\
|
|
orrs r4, r1\n\
|
|
ldr r5, =gDynamicBasePower\n\
|
|
lsls r0, r2, 2\n\
|
|
adds r0, r2\n\
|
|
lsls r0, 3\n\
|
|
movs r1, 0x3F\n\
|
|
bl __divsi3\n\
|
|
adds r0, 0x1E\n\
|
|
strh r0, [r5]\n\
|
|
ldr r6, =gBattleStruct\n\
|
|
ldr r5, [r6]\n\
|
|
lsls r0, r4, 4\n\
|
|
subs r0, r4\n\
|
|
movs r1, 0x3F\n\
|
|
bl __divsi3\n\
|
|
adds r0, 0x1\n\
|
|
strb r0, [r5, 0x13]\n\
|
|
ldr r1, [r6]\n\
|
|
ldrb r0, [r1, 0x13]\n\
|
|
cmp r0, 0x8\n\
|
|
bls _080544F0\n\
|
|
adds r0, 0x1\n\
|
|
strb r0, [r1, 0x13]\n\
|
|
_080544F0:\n\
|
|
ldr r2, [r6]\n\
|
|
ldrb r0, [r2, 0x13]\n\
|
|
movs r1, 0xC0\n\
|
|
orrs r0, r1\n\
|
|
strb r0, [r2, 0x13]\n\
|
|
ldr r1, =gBattlescriptCurrInstr\n\
|
|
ldr r0, [r1]\n\
|
|
adds r0, 0x1\n\
|
|
str r0, [r1]\n\
|
|
pop {r3-r5}\n\
|
|
mov r8, r3\n\
|
|
mov r9, r4\n\
|
|
mov r10, r5\n\
|
|
pop {r4-r7}\n\
|
|
pop {r0}\n\
|
|
bx r0\n\
|
|
.pool\n\
|
|
.syntax divided");
|
|
}
|
|
#endif // NONMATCHING
|
|
|
|
static void atkC2_selectfirstvalidtarget(void)
|
|
{
|
|
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
|
|
{
|
|
if (gBattlerTarget == gBattlerAttacker)
|
|
continue;
|
|
if (!(gAbsentBattlerFlags & gBitTable[gBattlerTarget]))
|
|
break;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkC3_trysetfutureattack(void)
|
|
{
|
|
if (gWishFutureKnock.futureSightCounter[gBattlerTarget] != 0)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)] |= SIDE_STATUS_FUTUREATTACK;
|
|
gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove;
|
|
gWishFutureKnock.futureSightAttacker[gBattlerTarget] = gBattlerAttacker;
|
|
gWishFutureKnock.futureSightCounter[gBattlerTarget] = 3;
|
|
gWishFutureKnock.futureSightDmg[gBattlerTarget] = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerTarget], gCurrentMove,
|
|
gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)], 0,
|
|
0, gBattlerAttacker, gBattlerTarget);
|
|
|
|
if (gProtectStructs[gBattlerAttacker].helpingHand)
|
|
gWishFutureKnock.futureSightDmg[gBattlerTarget] = gWishFutureKnock.futureSightDmg[gBattlerTarget] * 15 / 10;
|
|
|
|
if (gCurrentMove == MOVE_DOOM_DESIRE)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkC4_trydobeatup(void)
|
|
{
|
|
struct Pokemon *party;
|
|
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
|
party = gPlayerParty;
|
|
else
|
|
party = gEnemyParty;
|
|
|
|
if (gBattleMons[gBattlerTarget].hp == 0)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
u8 beforeLoop = gBattleCommunication[0];
|
|
for (;gBattleCommunication[0] < 6; gBattleCommunication[0]++)
|
|
{
|
|
if (GetMonData(&party[gBattleCommunication[0]], MON_DATA_HP)
|
|
&& GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES2)
|
|
&& GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES2) != SPECIES_EGG
|
|
&& !GetMonData(&party[gBattleCommunication[0]], MON_DATA_STATUS))
|
|
break;
|
|
}
|
|
if (gBattleCommunication[0] < 6)
|
|
{
|
|
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattleCommunication[0])
|
|
|
|
gBattlescriptCurrInstr += 9;
|
|
|
|
gBattleMoveDamage = gBaseStats[GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES)].baseAttack;
|
|
gBattleMoveDamage *= gBattleMoves[gCurrentMove].power;
|
|
gBattleMoveDamage *= (GetMonData(&party[gBattleCommunication[0]], MON_DATA_LEVEL) * 2 / 5 + 2);
|
|
gBattleMoveDamage /= gBaseStats[gBattleMons[gBattlerTarget].species].baseDefense;
|
|
gBattleMoveDamage = (gBattleMoveDamage / 50) + 2;
|
|
if (gProtectStructs[gBattlerAttacker].helpingHand)
|
|
gBattleMoveDamage = gBattleMoveDamage * 15 / 10;
|
|
|
|
gBattleCommunication[0]++;
|
|
}
|
|
else if (beforeLoop != 0)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 5);
|
|
}
|
|
}
|
|
|
|
static void atkC5_setsemiinvulnerablebit(void)
|
|
{
|
|
switch (gCurrentMove)
|
|
{
|
|
case MOVE_FLY:
|
|
case MOVE_BOUNCE:
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_ON_AIR;
|
|
break;
|
|
case MOVE_DIG:
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_UNDERGROUND;
|
|
break;
|
|
case MOVE_DIVE:
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_UNDERWATER;
|
|
break;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkC6_clearsemiinvulnerablebit(void)
|
|
{
|
|
switch (gCurrentMove)
|
|
{
|
|
case MOVE_FLY:
|
|
case MOVE_BOUNCE:
|
|
gStatuses3[gBattlerAttacker] &= ~STATUS3_ON_AIR;
|
|
break;
|
|
case MOVE_DIG:
|
|
gStatuses3[gBattlerAttacker] &= ~STATUS3_UNDERGROUND;
|
|
break;
|
|
case MOVE_DIVE:
|
|
gStatuses3[gBattlerAttacker] &= ~STATUS3_UNDERWATER;
|
|
break;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkC7_setminimize(void)
|
|
{
|
|
if (gHitMarker & HITMARKER_OBEYS)
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_MINIMIZED;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkC8_sethail(void)
|
|
{
|
|
if (gBattleWeather & WEATHER_HAIL_ANY)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
}
|
|
else
|
|
{
|
|
gBattleWeather = WEATHER_HAIL;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 5;
|
|
gWishFutureKnock.weatherDuration = 5;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkC9_jumpifattackandspecialattackcannotfall(void) // memento
|
|
{
|
|
if (gBattleMons[gBattlerTarget].statStages[STAT_STAGE_ATK] == 0
|
|
&& gBattleMons[gBattlerTarget].statStages[STAT_STAGE_SPATK] == 0
|
|
&& gBattleCommunication[6] != 1)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
gBattleMoveDamage = gBattleMons[gActiveBattler].hp;
|
|
BtlController_EmitHealthBarUpdate(0, INSTANT_HP_BAR_DROP);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkCA_setforcedtarget(void) // follow me
|
|
{
|
|
gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTimer = 1;
|
|
gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTarget = gBattlerAttacker;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkCB_setcharge(void)
|
|
{
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_CHARGED_UP;
|
|
gDisableStructs[gBattlerAttacker].chargeTimer1 = 2;
|
|
gDisableStructs[gBattlerAttacker].chargeTimer2 = 2;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkCC_callterrainattack(void) // nature power
|
|
{
|
|
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
|
|
gCurrentMove = sNaturePowerMoves[gBattleTerrain];
|
|
gBattlerTarget = GetMoveTarget(gCurrentMove, 0);
|
|
BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkCD_cureifburnedparalysedorpoisoned(void) // refresh
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON))
|
|
{
|
|
gBattleMons[gBattlerAttacker].status1 = 0;
|
|
gBattlescriptCurrInstr += 5;
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkCE_settorment(void)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_TORMENT)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gBattlerTarget].status2 |= STATUS2_TORMENT;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkCF_jumpifnodamage(void)
|
|
{
|
|
if (gProtectStructs[gBattlerAttacker].physicalDmg || gProtectStructs[gBattlerAttacker].specialDmg)
|
|
gBattlescriptCurrInstr += 5;
|
|
else
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
|
|
static void atkD0_settaunt(void)
|
|
{
|
|
if (gDisableStructs[gBattlerTarget].tauntTimer1 == 0)
|
|
{
|
|
gDisableStructs[gBattlerTarget].tauntTimer1 = 2;
|
|
gDisableStructs[gBattlerTarget].tauntTimer2 = 2;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkD1_trysethelpinghand(void)
|
|
{
|
|
gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_FLANK);
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
|
&& !(gAbsentBattlerFlags & gBitTable[gBattlerTarget])
|
|
&& !gProtectStructs[gBattlerAttacker].helpingHand
|
|
&& !gProtectStructs[gBattlerTarget].helpingHand)
|
|
{
|
|
gProtectStructs[gBattlerTarget].helpingHand = 1;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkD2_tryswapitems(void) // trick
|
|
{
|
|
// opponent can't swap items with player in regular battles
|
|
if (gBattleTypeFlags & BATTLE_TYPE_x4000000
|
|
|| (GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT
|
|
&& !(gBattleTypeFlags & (BATTLE_TYPE_LINK
|
|
| BATTLE_TYPE_EREADER_TRAINER
|
|
| BATTLE_TYPE_FRONTIER
|
|
| BATTLE_TYPE_SECRET_BASE
|
|
| BATTLE_TYPE_x2000000))))
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
u8 sideAttacker = GetBattlerSide(gBattlerAttacker);
|
|
u8 sideTarget = GetBattlerSide(gBattlerTarget);
|
|
|
|
// you can't swap items if they were knocked off in regular battles
|
|
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
|
|
| BATTLE_TYPE_EREADER_TRAINER
|
|
| BATTLE_TYPE_FRONTIER
|
|
| BATTLE_TYPE_SECRET_BASE
|
|
| BATTLE_TYPE_x2000000))
|
|
&& (gWishFutureKnock.knockedOffPokes[sideAttacker] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]]
|
|
|| gWishFutureKnock.knockedOffPokes[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]]))
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
// can't swap if two pokemon don't have an item
|
|
// or if either of them is an enigma berry or a mail
|
|
else if ((gBattleMons[gBattlerAttacker].item == 0 && gBattleMons[gBattlerTarget].item == 0)
|
|
|| gBattleMons[gBattlerAttacker].item == ITEM_ENIGMA_BERRY
|
|
|| gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY
|
|
|| IS_ITEM_MAIL(gBattleMons[gBattlerAttacker].item)
|
|
|| IS_ITEM_MAIL(gBattleMons[gBattlerTarget].item))
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
// check if ability prevents swapping
|
|
else if (gBattleMons[gBattlerTarget].ability == ABILITY_STICKY_HOLD)
|
|
{
|
|
gBattlescriptCurrInstr = BattleScript_StickyHoldActivates;
|
|
gLastUsedAbility = gBattleMons[gBattlerTarget].ability;
|
|
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
|
|
}
|
|
// took a while, but all checks passed and items can be safely swapped
|
|
else
|
|
{
|
|
u16 oldItemAtk, *newItemAtk;
|
|
|
|
newItemAtk = &gBattleStruct->changedItems[gBattlerAttacker];
|
|
oldItemAtk = gBattleMons[gBattlerAttacker].item;
|
|
*newItemAtk = gBattleMons[gBattlerTarget].item;
|
|
|
|
gBattleMons[gBattlerAttacker].item = 0;
|
|
gBattleMons[gBattlerTarget].item = oldItemAtk;
|
|
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, newItemAtk);
|
|
MarkBattlerForControllerExec(gBattlerAttacker);
|
|
|
|
gActiveBattler = gBattlerTarget;
|
|
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBattlerTarget].item);
|
|
MarkBattlerForControllerExec(gBattlerTarget);
|
|
|
|
*(u8*)((u8*)(&gBattleStruct->choicedMove[gBattlerTarget]) + 0) = 0;
|
|
*(u8*)((u8*)(&gBattleStruct->choicedMove[gBattlerTarget]) + 1) = 0;
|
|
|
|
*(u8*)((u8*)(&gBattleStruct->choicedMove[gBattlerAttacker]) + 0) = 0;
|
|
*(u8*)((u8*)(&gBattleStruct->choicedMove[gBattlerAttacker]) + 1) = 0;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
|
|
PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk)
|
|
PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk)
|
|
|
|
if (oldItemAtk != 0 && *newItemAtk != 0)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2; // attacker's item -> <- target's item
|
|
else if (oldItemAtk == 0 && *newItemAtk != 0)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0; // nothing -> <- target's item
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1; // attacker's item -> <- nothing
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atkD3_trycopyability(void) // role play
|
|
{
|
|
if (gBattleMons[gBattlerTarget].ability != 0
|
|
&& gBattleMons[gBattlerTarget].ability != ABILITY_WONDER_GUARD)
|
|
{
|
|
gBattleMons[gBattlerAttacker].ability = gBattleMons[gBattlerTarget].ability;
|
|
gLastUsedAbility = gBattleMons[gBattlerTarget].ability;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkD4_trywish(void)
|
|
{
|
|
switch (gBattlescriptCurrInstr[1])
|
|
{
|
|
case 0: // use wish
|
|
if (gWishFutureKnock.wishCounter[gBattlerAttacker] == 0)
|
|
{
|
|
gWishFutureKnock.wishCounter[gBattlerAttacker] = 2;
|
|
gWishFutureKnock.wishUserID[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker];
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
}
|
|
break;
|
|
case 1: // heal effect
|
|
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerTarget, gWishFutureKnock.wishUserID[gBattlerTarget])
|
|
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
gBattleMoveDamage *= -1;
|
|
|
|
if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void atkD5_trysetroots(void) // ingrain
|
|
{
|
|
if (gStatuses3[gBattlerAttacker] & STATUS3_ROOTED)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_ROOTED;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkD6_doubledamagedealtifdamaged(void)
|
|
{
|
|
if ((gProtectStructs[gBattlerAttacker].physicalDmg
|
|
&& gProtectStructs[gBattlerAttacker].physicalBank == gBattlerTarget)
|
|
|| (gProtectStructs[gBattlerAttacker].specialDmg
|
|
&& gProtectStructs[gBattlerAttacker].specialBank == gBattlerTarget))
|
|
{
|
|
gBattleScripting.dmgMultiplier = 2;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkD7_setyawn(void)
|
|
{
|
|
if (gStatuses3[gBattlerTarget] & STATUS3_YAWN
|
|
|| gBattleMons[gBattlerTarget].status1 & STATUS1_ANY)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gStatuses3[gBattlerTarget] |= 0x1000;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkD8_setdamagetohealthdifference(void)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].hp <= gBattleMons[gBattlerAttacker].hp)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - gBattleMons[gBattlerAttacker].hp;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkD9_scaledamagebyhealthratio(void)
|
|
{
|
|
if (gDynamicBasePower == 0)
|
|
{
|
|
u8 power = gBattleMoves[gCurrentMove].power;
|
|
gDynamicBasePower = gBattleMons[gBattlerAttacker].hp * power / gBattleMons[gBattlerAttacker].maxHP;
|
|
if (gDynamicBasePower == 0)
|
|
gDynamicBasePower = 1;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkDA_tryswapabilities(void) // skill swap
|
|
{
|
|
if ((gBattleMons[gBattlerAttacker].ability == 0
|
|
&& gBattleMons[gBattlerTarget].ability == 0)
|
|
|| gBattleMons[gBattlerAttacker].ability == ABILITY_WONDER_GUARD
|
|
|| gBattleMons[gBattlerTarget].ability == ABILITY_WONDER_GUARD
|
|
|| gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
u8 abilityAtk = gBattleMons[gBattlerAttacker].ability;
|
|
gBattleMons[gBattlerAttacker].ability = gBattleMons[gBattlerTarget].ability;
|
|
gBattleMons[gBattlerTarget].ability = abilityAtk;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkDB_tryimprision(void)
|
|
{
|
|
if ((gStatuses3[gBattlerAttacker] & STATUS3_IMPRISONED_OTHERS))
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
u8 bank, sideAttacker;
|
|
|
|
sideAttacker = GetBattlerSide(gBattlerAttacker);
|
|
PressurePPLoseOnUsingImprision(gBattlerAttacker);
|
|
for (bank = 0; bank < gBattlersCount; bank++)
|
|
{
|
|
if (sideAttacker != GetBattlerSide(bank))
|
|
{
|
|
s32 attackerMoveId;
|
|
for (attackerMoveId = 0; attackerMoveId < 4; attackerMoveId++)
|
|
{
|
|
s32 i;
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].moves[attackerMoveId] == gBattleMons[bank].moves[i]
|
|
&& gBattleMons[gBattlerAttacker].moves[attackerMoveId] != MOVE_NONE)
|
|
break;
|
|
}
|
|
if (i != 4)
|
|
break;
|
|
}
|
|
if (attackerMoveId != 4)
|
|
{
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_IMPRISONED_OTHERS;
|
|
gBattlescriptCurrInstr += 5;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (bank == gBattlersCount) // In Generation 3 games, Imprison fails if the user doesn't share any moves with any of the foes
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkDC_trysetgrudge(void)
|
|
{
|
|
if (gStatuses3[gBattlerAttacker] & STATUS3_GRUDGE)
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_GRUDGE;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkDD_weightdamagecalculation(void)
|
|
{
|
|
s32 i;
|
|
for (i = 0; sWeightToDamageTable[i] != 0xFFFF; i += 2)
|
|
{
|
|
if (sWeightToDamageTable[i] > GetPokedexHeightWeight(SpeciesToNationalPokedexNum(gBattleMons[gBattlerTarget].species), 1))
|
|
break;
|
|
}
|
|
|
|
if (sWeightToDamageTable[i] != 0xFFFF)
|
|
gDynamicBasePower = sWeightToDamageTable[i + 1];
|
|
else
|
|
gDynamicBasePower = 120;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkDE_asistattackselect(void)
|
|
{
|
|
s32 chooseableMovesNo = 0;
|
|
struct Pokemon* party;
|
|
s32 monId, moveId;
|
|
u16* movesArray = gBattleStruct->assistPossibleMoves;
|
|
|
|
if (GET_BATTLER_SIDE(gBattlerAttacker) != B_SIDE_PLAYER)
|
|
party = gEnemyParty;
|
|
else
|
|
party = gPlayerParty;
|
|
|
|
for (monId = 0; monId < 6; monId++)
|
|
{
|
|
if (monId == gBattlerPartyIndexes[gBattlerAttacker])
|
|
continue;
|
|
if (GetMonData(&party[monId], MON_DATA_SPECIES2) == SPECIES_NONE)
|
|
continue;
|
|
if (GetMonData(&party[monId], MON_DATA_SPECIES2) == SPECIES_EGG)
|
|
continue;
|
|
|
|
for (moveId = 0; moveId < 4; moveId++)
|
|
{
|
|
s32 i = 0;
|
|
u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId);
|
|
|
|
if (IsInvalidForSleepTalkOrAssist(move))
|
|
continue;
|
|
|
|
for (; sMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END && move != sMovesForbiddenToCopy[i]; i++);
|
|
|
|
if (sMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END)
|
|
continue;
|
|
if (move == MOVE_NONE)
|
|
continue;
|
|
|
|
movesArray[chooseableMovesNo] = move;
|
|
chooseableMovesNo++;
|
|
}
|
|
}
|
|
if (chooseableMovesNo)
|
|
{
|
|
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
|
|
gRandomMove = movesArray[((Random() & 0xFF) * chooseableMovesNo) >> 8];
|
|
gBattlerTarget = GetMoveTarget(gRandomMove, 0);
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkDF_trysetmagiccoat(void)
|
|
{
|
|
gBattlerTarget = gBattlerAttacker;
|
|
gSpecialStatuses[gBattlerAttacker].flag20 = 1;
|
|
if (gCurrentTurnActionNumber == gBattlersCount - 1) // moves last turn
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gProtectStructs[gBattlerAttacker].bounceMove = 1;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkE0_trysetsnatch(void) // snatch
|
|
{
|
|
gSpecialStatuses[gBattlerAttacker].flag20 = 1;
|
|
if (gCurrentTurnActionNumber == gBattlersCount - 1) // moves last turn
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gProtectStructs[gBattlerAttacker].stealMove = 1;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkE1_trygetintimidatetarget(void)
|
|
{
|
|
u8 side;
|
|
|
|
gBattleScripting.battler = gBattleStruct->intimidateBank;
|
|
side = GetBattlerSide(gBattleScripting.battler);
|
|
|
|
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gBattleMons[gBattleScripting.battler].ability)
|
|
|
|
for (;gBattlerTarget < gBattlersCount; gBattlerTarget++)
|
|
{
|
|
if (GetBattlerSide(gBattlerTarget) == side)
|
|
continue;
|
|
if (!(gAbsentBattlerFlags & gBitTable[gBattlerTarget]))
|
|
break;
|
|
}
|
|
|
|
if (gBattlerTarget >= gBattlersCount)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
|
|
static void atkE2_switchoutabilities(void)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
switch (gBattleMons[gActiveBattler].ability)
|
|
{
|
|
case ABILITY_NATURAL_CURE:
|
|
gBattleMons[gActiveBattler].status1 = 0;
|
|
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 4, &gBattleMons[gActiveBattler].status1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
break;
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void atkE3_jumpifhasnohp(void)
|
|
{
|
|
gActiveBattler = GetBattleBank(gBattlescriptCurrInstr[1]);
|
|
|
|
if (gBattleMons[gActiveBattler].hp == 0)
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void atkE4_getsecretpowereffect(void)
|
|
{
|
|
switch (gBattleTerrain)
|
|
{
|
|
case BATTLE_TERRAIN_GRASS:
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_POISON;
|
|
break;
|
|
case BATTLE_TERRAIN_LONG_GRASS:
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SLEEP;
|
|
break;
|
|
case BATTLE_TERRAIN_SAND:
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_ACC_MINUS_1;
|
|
break;
|
|
case BATTLE_TERRAIN_UNDERWATER:
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_DEF_MINUS_1;
|
|
break;
|
|
case BATTLE_TERRAIN_WATER:
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_ATK_MINUS_1;
|
|
break;
|
|
case BATTLE_TERRAIN_POND:
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SPD_MINUS_1;
|
|
break;
|
|
case BATTLE_TERRAIN_MOUNTAIN:
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_CONFUSION;
|
|
break;
|
|
case BATTLE_TERRAIN_CAVE:
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_FLINCH;
|
|
break;
|
|
default:
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_PARALYSIS;
|
|
break;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkE5_pickup(void)
|
|
{
|
|
if (!InBattlePike())
|
|
{
|
|
s32 i;
|
|
u16 species, heldItem;
|
|
u8 ability;
|
|
|
|
if (InBattlePyramid())
|
|
{
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2);
|
|
heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
|
|
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_ALT_ABILITY))
|
|
ability = gBaseStats[species].ability2;
|
|
else
|
|
ability = gBaseStats[species].ability1;
|
|
|
|
if (ability == ABILITY_PICKUP
|
|
&& species != 0
|
|
&& species != SPECIES_EGG
|
|
&& heldItem == ITEM_NONE
|
|
&& (Random() % 10) == 0)
|
|
{
|
|
heldItem = GetBattlePyramidPickupItemId();
|
|
SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &heldItem);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2);
|
|
heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
|
|
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_ALT_ABILITY))
|
|
ability = gBaseStats[species].ability2;
|
|
else
|
|
ability = gBaseStats[species].ability1;
|
|
|
|
if (ability == ABILITY_PICKUP
|
|
&& species != 0
|
|
&& species != SPECIES_EGG
|
|
&& heldItem == ITEM_NONE
|
|
&& (Random() % 10) == 0)
|
|
{
|
|
s32 j;
|
|
s32 rand = Random() % 100;
|
|
u8 lvlDivBy10 = (GetMonData(&gPlayerParty[i], MON_DATA_LEVEL) - 1) / 10;
|
|
if (lvlDivBy10 > 9)
|
|
lvlDivBy10 = 9;
|
|
|
|
for (j = 0; j < 9; j++)
|
|
{
|
|
if (sPickupProbabilities[j] > rand)
|
|
{
|
|
SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &sPickupItems[lvlDivBy10 + j]);
|
|
break;
|
|
}
|
|
else if (rand == 99 || rand == 98)
|
|
{
|
|
SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &sRarePickupItems[lvlDivBy10 + (99 - rand)]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkE6_docastformchangeanimation(void)
|
|
{
|
|
gActiveBattler = gBattleScripting.battler;
|
|
|
|
if (gBattleMons[gActiveBattler].status2 & STATUS2_SUBSTITUTE)
|
|
*(&gBattleStruct->formToChangeInto) |= 0x80;
|
|
|
|
BtlController_EmitBattleAnimation(0, B_ANIM_CASTFORM_CHANGE, gBattleStruct->formToChangeInto);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkE7_trycastformdatachange(void)
|
|
{
|
|
u8 form;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
form = CastformDataTypeChange(gBattleScripting.battler);
|
|
if (form)
|
|
{
|
|
BattleScriptPushCursorAndCallback(BattleScript_CastformChange);
|
|
*(&gBattleStruct->formToChangeInto) = form - 1;
|
|
}
|
|
}
|
|
|
|
static void atkE8_settypebasedhalvers(void) // water and mud sport
|
|
{
|
|
bool8 worked = FALSE;
|
|
|
|
if (gBattleMoves[gCurrentMove].effect == EFFECT_MUD_SPORT)
|
|
{
|
|
if (!(gStatuses3[gBattlerAttacker] & STATUS3_MUDSPORT))
|
|
{
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_MUDSPORT;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
worked = TRUE;
|
|
}
|
|
}
|
|
else // water sport
|
|
{
|
|
if (!(gStatuses3[gBattlerAttacker] & STATUS3_WATERSPORT))
|
|
{
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_WATERSPORT;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
worked = TRUE;
|
|
}
|
|
}
|
|
|
|
if (worked)
|
|
gBattlescriptCurrInstr += 5;
|
|
else
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
|
|
static void atkE9_setweatherballtype(void)
|
|
{
|
|
if (WEATHER_HAS_EFFECT)
|
|
{
|
|
if (gBattleWeather & WEATHER_ANY)
|
|
gBattleScripting.dmgMultiplier = 2;
|
|
if (gBattleWeather & WEATHER_RAIN_ANY)
|
|
*(&gBattleStruct->dynamicMoveType) = TYPE_WATER | 0x80;
|
|
else if (gBattleWeather & WEATHER_SANDSTORM_ANY)
|
|
*(&gBattleStruct->dynamicMoveType) = TYPE_ROCK | 0x80;
|
|
else if (gBattleWeather & WEATHER_SUN_ANY)
|
|
*(&gBattleStruct->dynamicMoveType) = TYPE_FIRE | 0x80;
|
|
else if (gBattleWeather & WEATHER_HAIL_ANY)
|
|
*(&gBattleStruct->dynamicMoveType) = TYPE_ICE | 0x80;
|
|
else
|
|
*(&gBattleStruct->dynamicMoveType) = TYPE_NORMAL | 0x80;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkEA_tryrecycleitem(void)
|
|
{
|
|
u16 *usedHeldItem;
|
|
|
|
gActiveBattler = gBattlerAttacker;
|
|
usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBattler];
|
|
if (*usedHeldItem != 0 && gBattleMons[gActiveBattler].item == 0)
|
|
{
|
|
gLastUsedItem = *usedHeldItem;
|
|
*usedHeldItem = 0;
|
|
gBattleMons[gActiveBattler].item = gLastUsedItem;
|
|
|
|
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBattler].item);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkEB_settypetoterrain(void)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].type1 != sTerrainToType[gBattleTerrain]
|
|
&& gBattleMons[gBattlerAttacker].type2 != sTerrainToType[gBattleTerrain])
|
|
{
|
|
gBattleMons[gBattlerAttacker].type1 = sTerrainToType[gBattleTerrain];
|
|
gBattleMons[gBattlerAttacker].type2 = sTerrainToType[gBattleTerrain];
|
|
|
|
PREPARE_TYPE_BUFFER(gBattleTextBuff1, sTerrainToType[gBattleTerrain])
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkEC_pursuitrelated(void)
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_FLANK);
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
|
&& !(gAbsentBattlerFlags & gBitTable[gActiveBattler])
|
|
&& gChosenActionByBattler[gActiveBattler] == 0
|
|
&& gChosenMoveByBattler[gActiveBattler] == MOVE_PURSUIT)
|
|
{
|
|
gActionsByTurnOrder[gActiveBattler] = 11;
|
|
gCurrentMove = MOVE_PURSUIT;
|
|
gBattlescriptCurrInstr += 5;
|
|
gBattleScripting.animTurn = 1;
|
|
gBattleScripting.field_20 = gBattlerAttacker;
|
|
gBattlerAttacker = gActiveBattler;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void atkEF_snatchsetbanks(void)
|
|
{
|
|
gEffectBank = gBattlerAttacker;
|
|
|
|
if (gBattlerAttacker == gBattlerTarget)
|
|
gBattlerAttacker = gBattlerTarget = gBattleScripting.battler;
|
|
else
|
|
gBattlerTarget = gBattleScripting.battler;
|
|
|
|
gBattleScripting.battler = gEffectBank;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkEE_removelightscreenreflect(void) // brick break
|
|
{
|
|
u8 opposingSide = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
|
|
|
|
if (gSideTimers[opposingSide].reflectTimer || gSideTimers[opposingSide].lightscreenTimer)
|
|
{
|
|
gSideStatuses[opposingSide] &= ~(SIDE_STATUS_REFLECT);
|
|
gSideStatuses[opposingSide] &= ~(SIDE_STATUS_LIGHTSCREEN);
|
|
gSideTimers[opposingSide].reflectTimer = 0;
|
|
gSideTimers[opposingSide].lightscreenTimer = 0;
|
|
gBattleScripting.animTurn = 1;
|
|
gBattleScripting.animTargetsHit = 1;
|
|
}
|
|
else
|
|
{
|
|
gBattleScripting.animTurn = 0;
|
|
gBattleScripting.animTargetsHit = 0;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkEF_handleballthrow(void)
|
|
{
|
|
u8 ballMultiplier = 0;
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = gBattlerAttacker;
|
|
gBattlerTarget = gBattlerAttacker ^ BIT_SIDE;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
|
|
{
|
|
BtlController_EmitBallThrowAnim(0, BALL_TRAINER_BLOCK);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr = BattleScript_TrainerBallBlock;
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL)
|
|
{
|
|
BtlController_EmitBallThrowAnim(0, BALL_3_SHAKES_SUCCESS);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr = BattleScript_WallyBallThrow;
|
|
}
|
|
else
|
|
{
|
|
u32 odds;
|
|
u8 catchRate;
|
|
|
|
if (gLastUsedItem == ITEM_SAFARI_BALL)
|
|
catchRate = gBattleStruct->field_7C * 1275 / 100;
|
|
else
|
|
catchRate = gBaseStats[gBattleMons[gBattlerTarget].species].catchRate;
|
|
|
|
if (gLastUsedItem > ITEM_SAFARI_BALL)
|
|
{
|
|
switch (gLastUsedItem)
|
|
{
|
|
case ITEM_NET_BALL:
|
|
if (gBattleMons[gBattlerTarget].type1 == TYPE_WATER
|
|
|| gBattleMons[gBattlerTarget].type2 == TYPE_WATER
|
|
|| gBattleMons[gBattlerTarget].type1 == TYPE_BUG
|
|
|| gBattleMons[gBattlerTarget].type2 == TYPE_BUG)
|
|
ballMultiplier = 30;
|
|
else
|
|
ballMultiplier = 10;
|
|
break;
|
|
case ITEM_DIVE_BALL:
|
|
if (sav1_map_get_light_level() == 5)
|
|
ballMultiplier = 35;
|
|
else
|
|
ballMultiplier = 10;
|
|
break;
|
|
case ITEM_NEST_BALL:
|
|
if (gBattleMons[gBattlerTarget].level < 40)
|
|
{
|
|
ballMultiplier = 40 - gBattleMons[gBattlerTarget].level;
|
|
if (ballMultiplier <= 9)
|
|
ballMultiplier = 10;
|
|
}
|
|
else
|
|
{
|
|
ballMultiplier = 10;
|
|
}
|
|
break;
|
|
case ITEM_REPEAT_BALL:
|
|
if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gBattlerTarget].species), FLAG_GET_CAUGHT))
|
|
ballMultiplier = 30;
|
|
else
|
|
ballMultiplier = 10;
|
|
break;
|
|
case ITEM_TIMER_BALL:
|
|
ballMultiplier = gBattleResults.battleTurnCounter + 10;
|
|
if (ballMultiplier > 40)
|
|
ballMultiplier = 40;
|
|
break;
|
|
case ITEM_LUXURY_BALL:
|
|
case ITEM_PREMIER_BALL:
|
|
ballMultiplier = 10;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
ballMultiplier = sBallCatchBonuses[gLastUsedItem - 2];
|
|
|
|
odds = (catchRate * ballMultiplier / 10)
|
|
* (gBattleMons[gBattlerTarget].maxHP * 3 - gBattleMons[gBattlerTarget].hp * 2)
|
|
/ (3 * gBattleMons[gBattlerTarget].maxHP);
|
|
|
|
if (gBattleMons[gBattlerTarget].status1 & (STATUS1_SLEEP | STATUS1_FREEZE))
|
|
odds *= 2;
|
|
if (gBattleMons[gBattlerTarget].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON))
|
|
odds = (odds * 15) / 10;
|
|
|
|
if (gLastUsedItem != ITEM_SAFARI_BALL)
|
|
{
|
|
if (gLastUsedItem == ITEM_MASTER_BALL)
|
|
{
|
|
gBattleResults.usedMasterBall = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL] < 0xFF)
|
|
gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL]++;
|
|
}
|
|
}
|
|
|
|
if (odds > 254) // mon caught
|
|
{
|
|
BtlController_EmitBallThrowAnim(0, BALL_3_SHAKES_SUCCESS);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr = BattleScript_SuccessBallThrow;
|
|
SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, &gLastUsedItem);
|
|
|
|
if (CalculatePlayerPartyCount() == 6)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else // mon may be caught, calculate shakes
|
|
{
|
|
u8 shakes;
|
|
|
|
odds = Sqrt(Sqrt(16711680 / odds));
|
|
odds = 1048560 / odds;
|
|
|
|
for (shakes = 0; shakes < 4 && Random() < odds; shakes++);
|
|
|
|
if (gLastUsedItem == ITEM_MASTER_BALL)
|
|
shakes = BALL_3_SHAKES_SUCCESS; // why calculate the shakes before that check?
|
|
|
|
BtlController_EmitBallThrowAnim(0, shakes);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
if (shakes == BALL_3_SHAKES_SUCCESS) // mon caught, copy of the code above
|
|
{
|
|
gBattlescriptCurrInstr = BattleScript_SuccessBallThrow;
|
|
SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, &gLastUsedItem);
|
|
|
|
if (CalculatePlayerPartyCount() == 6)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else // not caught
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = shakes;
|
|
gBattlescriptCurrInstr = BattleScript_ShakeBallThrow;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void atkF0_givecaughtmon(void)
|
|
{
|
|
if (GiveMonToPlayer(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]]) != MON_GIVEN_TO_PARTY)
|
|
{
|
|
if (!sub_813B21C())
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN)));
|
|
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2);
|
|
}
|
|
else
|
|
{
|
|
StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN)));
|
|
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2);
|
|
StringCopy(gStringVar3, GetBoxNamePtr(get_unknown_box_id()));
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
}
|
|
|
|
if (FlagGet(FLAG_SYS_PC_LANETTE))
|
|
gBattleCommunication[MULTISTRING_CHOOSER]++;
|
|
}
|
|
|
|
gBattleResults.caughtMonSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_SPECIES, NULL);
|
|
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleResults.caughtMonNick);
|
|
gBattleResults.caughtMonBall = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_POKEBALL, NULL);
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkF1_trysetcaughtmondexflags(void)
|
|
{
|
|
u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL);
|
|
u32 personality = GetMonData(&gEnemyParty[0], MON_DATA_PERSONALITY, NULL);
|
|
|
|
if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT))
|
|
{
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_SET_CAUGHT, personality);
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void atkF2_displaydexinfo(void)
|
|
{
|
|
u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL);
|
|
|
|
switch (gBattleCommunication[0])
|
|
{
|
|
case 0:
|
|
BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
|
|
gBattleCommunication[0]++;
|
|
break;
|
|
case 1:
|
|
if (!gPaletteFade.active)
|
|
{
|
|
FreeAllWindowBuffers();
|
|
gBattleCommunication[TASK_ID] = CreateDexDisplayMonDataTask(SpeciesToNationalPokedexNum(species),
|
|
gBattleMons[gBattlerTarget].otId,
|
|
gBattleMons[gBattlerTarget].personality);
|
|
gBattleCommunication[0]++;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (!gPaletteFade.active
|
|
&& gMain.callback2 == BattleMainCB2
|
|
&& !gTasks[gBattleCommunication[TASK_ID]].isActive)
|
|
{
|
|
SetVBlankCallback(VBlankCB_Battle);
|
|
gBattleCommunication[0]++;
|
|
}
|
|
break;
|
|
case 3:
|
|
sub_80356D0();
|
|
LoadBattleTextboxAndBackground();
|
|
gBattle_BG3_X = 0x100;
|
|
gBattleCommunication[0]++;
|
|
break;
|
|
case 4:
|
|
if (!IsDma3ManagerBusyWithBgCopy())
|
|
{
|
|
BeginNormalPaletteFade(0xFFFF, 0, 0x10, 0, 0);
|
|
ShowBg(0);
|
|
ShowBg(3);
|
|
gBattleCommunication[0]++;
|
|
}
|
|
break;
|
|
case 5:
|
|
if (!gPaletteFade.active)
|
|
gBattlescriptCurrInstr++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HandleBattleWindow(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags)
|
|
{
|
|
s32 destY, destX;
|
|
u16 var = 0;
|
|
|
|
for (destY = yStart; destY <= yEnd; destY++)
|
|
{
|
|
for (destX = xStart; destX <= xEnd; destX++)
|
|
{
|
|
if (destY == yStart)
|
|
{
|
|
if (destX == xStart)
|
|
var = 0x1022;
|
|
else if (destX == xEnd)
|
|
var = 0x1024;
|
|
else
|
|
var = 0x1023;
|
|
}
|
|
else if (destY == yEnd)
|
|
{
|
|
if (destX == xStart)
|
|
var = 0x1028;
|
|
else if (destX == xEnd)
|
|
var = 0x102A;
|
|
else
|
|
var = 0x1029;
|
|
}
|
|
else
|
|
{
|
|
if (destX == xStart)
|
|
var = 0x1025;
|
|
else if (destX == xEnd)
|
|
var = 0x1027;
|
|
else
|
|
var = 0x1026;
|
|
}
|
|
|
|
if (flags & WINDOW_CLEAR)
|
|
var = 0;
|
|
|
|
if (flags & WINDOW_x80)
|
|
CopyToBgTilemapBufferRect_ChangePalette(1, &var, destX, destY, 1, 1, 0x11);
|
|
else
|
|
CopyToBgTilemapBufferRect_ChangePalette(0, &var, destX, destY, 1, 1, 0x11);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BattleCreateYesNoCursorAt(u8 cursorPosition)
|
|
{
|
|
u16 src[2];
|
|
src[0] = 1;
|
|
src[1] = 2;
|
|
|
|
CopyToBgTilemapBufferRect_ChangePalette(0, src, 0x19, 9 + (2 * cursorPosition), 1, 2, 0x11);
|
|
CopyBgTilemapBufferToVram(0);
|
|
}
|
|
|
|
void BattleDestroyYesNoCursorAt(u8 cursorPosition)
|
|
{
|
|
u16 src[2];
|
|
src[0] = 0x1016;
|
|
src[1] = 0x1016;
|
|
|
|
CopyToBgTilemapBufferRect_ChangePalette(0, src, 0x19, 9 + (2 * cursorPosition), 1, 2, 0x11);
|
|
CopyBgTilemapBufferToVram(0);
|
|
}
|
|
|
|
static void atkF3_trygivecaughtmonnick(void)
|
|
{
|
|
switch (gBattleCommunication[MULTIUSE_STATE])
|
|
{
|
|
case 0:
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
|
|
BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
|
|
gBattleCommunication[MULTIUSE_STATE]++;
|
|
gBattleCommunication[CURSOR_POSITION] = 0;
|
|
BattleCreateYesNoCursorAt(0);
|
|
break;
|
|
case 1:
|
|
if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
|
gBattleCommunication[CURSOR_POSITION] = 0;
|
|
BattleCreateYesNoCursorAt(0);
|
|
}
|
|
if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
|
gBattleCommunication[CURSOR_POSITION] = 1;
|
|
BattleCreateYesNoCursorAt(1);
|
|
}
|
|
if (gMain.newKeys & A_BUTTON)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
if (gBattleCommunication[CURSOR_POSITION] == 0)
|
|
{
|
|
gBattleCommunication[MULTIUSE_STATE]++;
|
|
BeginFastPaletteFade(3);
|
|
}
|
|
else
|
|
{
|
|
gBattleCommunication[MULTIUSE_STATE] = 4;
|
|
}
|
|
}
|
|
else if (gMain.newKeys & B_BUTTON)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
gBattleCommunication[MULTIUSE_STATE] = 4;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (!gPaletteFade.active)
|
|
{
|
|
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleStruct->caughtMonNick);
|
|
FreeAllWindowBuffers();
|
|
|
|
DoNamingScreen(NAMING_SCREEN_CAUGHT_MON, gBattleStruct->caughtMonNick,
|
|
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_SPECIES),
|
|
GetMonGender(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]]),
|
|
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_PERSONALITY, NULL),
|
|
BattleMainCB2);
|
|
|
|
gBattleCommunication[MULTIUSE_STATE]++;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active )
|
|
{
|
|
SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleStruct->caughtMonNick);
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
}
|
|
break;
|
|
case 4:
|
|
if (CalculatePlayerPartyCount() == 6)
|
|
gBattlescriptCurrInstr += 5;
|
|
else
|
|
gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void atkF4_subattackerhpbydmg(void)
|
|
{
|
|
gBattleMons[gBattlerAttacker].hp -= gBattleMoveDamage;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkF5_removeattackerstatus1(void)
|
|
{
|
|
gBattleMons[gBattlerAttacker].status1 = 0;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void atkF6_finishaction(void)
|
|
{
|
|
gCurrentActionFuncId = B_ACTION_FINISHED;
|
|
}
|
|
|
|
static void atkF7_finishturn(void)
|
|
{
|
|
gCurrentActionFuncId = B_ACTION_FINISHED;
|
|
gCurrentTurnActionNumber = gBattlersCount;
|
|
}
|
|
|
|
static void atkF8_trainerslideout(void)
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitTrainerSlideBack(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|