This commit undoes most of PokeCodec's PRs after the debate in chat. Some harmless or completely superseded PRs have been left alone, as there is not much benefit in attempting to undo them. Reverts #1104, #1108, #1115, #1118, #1119, #1124, #1126, #1127, #1132, #1136, #1137, #1139, #1140, #1144, #1148, #1149, #1150, #1153, #1155, #1177, #1179, #1180, #1181, #1182 and #1183.
10470 lines
358 KiB
C
10470 lines
358 KiB
C
#include "global.h"
|
|
#include "battle.h"
|
|
#include "constants/battle_move_effects.h"
|
|
#include "constants/battle_script_commands.h"
|
|
#include "battle_message.h"
|
|
#include "battle_anim.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 "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 "constants/map_types.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 "m4a.h"
|
|
#include "mail.h"
|
|
#include "event_data.h"
|
|
#include "pokemon_storage_system.h"
|
|
#include "task.h"
|
|
#include "naming_screen.h"
|
|
#include "constants/battle_string_ids.h"
|
|
#include "battle_setup.h"
|
|
#include "overworld.h"
|
|
#include "party_menu.h"
|
|
#include "battle_arena.h"
|
|
#include "battle_pike.h"
|
|
#include "battle_pyramid.h"
|
|
#include "field_specials.h"
|
|
#include "pokemon_summary_screen.h"
|
|
#include "pokenav.h"
|
|
#include "menu_specialized.h"
|
|
#include "constants/rgb.h"
|
|
#include "data.h"
|
|
#include "constants/party_menu.h"
|
|
|
|
extern struct MusicPlayerInfo gMPlayInfo_BGM;
|
|
|
|
extern const u8* const gBattleScriptsForMoveEffects[];
|
|
|
|
#define DEFENDER_IS_PROTECTED ((gProtectStructs[gBattlerTarget].protected) && (gBattleMoves[gCurrentMove].flags & FLAG_PROTECT_AFFECTED))
|
|
|
|
// this file's functions
|
|
static bool8 IsTwoTurnsMove(u16 move);
|
|
static void TrySetDestinyBondToHappen(void);
|
|
static u8 AttacksThisTurn(u8 battlerId, 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 DrawLevelUpWindow1(void);
|
|
static void DrawLevelUpWindow2(void);
|
|
static bool8 sub_804F344(void);
|
|
static void PutMonIconOnLvlUpBox(void);
|
|
static void PutLevelAndGenderOnLvlUpBox(void);
|
|
|
|
static void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite);
|
|
|
|
static void Cmd_attackcanceler(void);
|
|
static void Cmd_accuracycheck(void);
|
|
static void Cmd_attackstring(void);
|
|
static void Cmd_ppreduce(void);
|
|
static void Cmd_critcalc(void);
|
|
static void Cmd_damagecalc(void);
|
|
static void Cmd_typecalc(void);
|
|
static void Cmd_adjustnormaldamage(void);
|
|
static void Cmd_adjustnormaldamage2(void);
|
|
static void Cmd_attackanimation(void);
|
|
static void Cmd_waitanimation(void);
|
|
static void Cmd_healthbarupdate(void);
|
|
static void Cmd_datahpupdate(void);
|
|
static void Cmd_critmessage(void);
|
|
static void Cmd_effectivenesssound(void);
|
|
static void Cmd_resultmessage(void);
|
|
static void Cmd_printstring(void);
|
|
static void Cmd_printselectionstring(void);
|
|
static void Cmd_waitmessage(void);
|
|
static void Cmd_printfromtable(void);
|
|
static void Cmd_printselectionstringfromtable(void);
|
|
static void Cmd_seteffectwithchance(void);
|
|
static void Cmd_seteffectprimary(void);
|
|
static void Cmd_seteffectsecondary(void);
|
|
static void Cmd_clearstatusfromeffect(void);
|
|
static void Cmd_tryfaintmon(void);
|
|
static void Cmd_dofaintanimation(void);
|
|
static void Cmd_cleareffectsonfaint(void);
|
|
static void Cmd_jumpifstatus(void);
|
|
static void Cmd_jumpifstatus2(void);
|
|
static void Cmd_jumpifability(void);
|
|
static void Cmd_jumpifsideaffecting(void);
|
|
static void Cmd_jumpifstat(void);
|
|
static void Cmd_jumpifstatus3condition(void);
|
|
static void Cmd_jumpiftype(void);
|
|
static void Cmd_getexp(void);
|
|
static void Cmd_unknown_24(void);
|
|
static void Cmd_movevaluescleanup(void);
|
|
static void Cmd_setmultihit(void);
|
|
static void Cmd_decrementmultihit(void);
|
|
static void Cmd_goto(void);
|
|
static void Cmd_jumpifbyte(void);
|
|
static void Cmd_jumpifhalfword(void);
|
|
static void Cmd_jumpifword(void);
|
|
static void Cmd_jumpifarrayequal(void);
|
|
static void Cmd_jumpifarraynotequal(void);
|
|
static void Cmd_setbyte(void);
|
|
static void Cmd_addbyte(void);
|
|
static void Cmd_subbyte(void);
|
|
static void Cmd_copyarray(void);
|
|
static void Cmd_copyarraywithindex(void);
|
|
static void Cmd_orbyte(void);
|
|
static void Cmd_orhalfword(void);
|
|
static void Cmd_orword(void);
|
|
static void Cmd_bicbyte(void);
|
|
static void Cmd_bichalfword(void);
|
|
static void Cmd_bicword(void);
|
|
static void Cmd_pause(void);
|
|
static void Cmd_waitstate(void);
|
|
static void Cmd_healthbar_update(void);
|
|
static void Cmd_return(void);
|
|
static void Cmd_end(void);
|
|
static void Cmd_end2(void);
|
|
static void Cmd_end3(void);
|
|
static void Cmd_jumpifaffectedbyprotect(void);
|
|
static void Cmd_call(void);
|
|
static void Cmd_jumpiftype2(void);
|
|
static void Cmd_jumpifabilitypresent(void);
|
|
static void Cmd_endselectionscript(void);
|
|
static void Cmd_playanimation(void);
|
|
static void Cmd_playanimation2(void);
|
|
static void Cmd_setgraphicalstatchangevalues(void);
|
|
static void Cmd_playstatchangeanimation(void);
|
|
static void Cmd_moveend(void);
|
|
static void Cmd_typecalc2(void);
|
|
static void Cmd_returnatktoball(void);
|
|
static void Cmd_getswitchedmondata(void);
|
|
static void Cmd_switchindataupdate(void);
|
|
static void Cmd_switchinanim(void);
|
|
static void Cmd_jumpifcantswitch(void);
|
|
static void Cmd_openpartyscreen(void);
|
|
static void Cmd_switchhandleorder(void);
|
|
static void Cmd_switchineffects(void);
|
|
static void Cmd_trainerslidein(void);
|
|
static void Cmd_playse(void);
|
|
static void Cmd_fanfare(void);
|
|
static void Cmd_playfaintcry(void);
|
|
static void Cmd_unknown_57(void);
|
|
static void Cmd_returntoball(void);
|
|
static void Cmd_handlelearnnewmove(void);
|
|
static void Cmd_yesnoboxlearnmove(void);
|
|
static void Cmd_yesnoboxstoplearningmove(void);
|
|
static void Cmd_hitanimation(void);
|
|
static void Cmd_getmoneyreward(void);
|
|
static void Cmd_unknown_5E(void);
|
|
static void Cmd_swapattackerwithtarget(void);
|
|
static void Cmd_incrementgamestat(void);
|
|
static void Cmd_drawpartystatussummary(void);
|
|
static void Cmd_hidepartystatussummary(void);
|
|
static void Cmd_jumptocalledmove(void);
|
|
static void Cmd_statusanimation(void);
|
|
static void Cmd_status2animation(void);
|
|
static void Cmd_chosenstatusanimation(void);
|
|
static void Cmd_yesnobox(void);
|
|
static void Cmd_cancelallactions(void);
|
|
static void Cmd_adjustsetdamage(void);
|
|
static void Cmd_removeitem(void);
|
|
static void Cmd_atknameinbuff1(void);
|
|
static void Cmd_drawlvlupbox(void);
|
|
static void Cmd_resetsentmonsvalue(void);
|
|
static void Cmd_setatktoplayer0(void);
|
|
static void Cmd_makevisible(void);
|
|
static void Cmd_recordlastability(void);
|
|
static void Cmd_buffermovetolearn(void);
|
|
static void Cmd_jumpifplayerran(void);
|
|
static void Cmd_hpthresholds(void);
|
|
static void Cmd_hpthresholds2(void);
|
|
static void Cmd_useitemonopponent(void);
|
|
static void Cmd_various(void);
|
|
static void Cmd_setprotectlike(void);
|
|
static void Cmd_faintifabilitynotdamp(void);
|
|
static void Cmd_setatkhptozero(void);
|
|
static void Cmd_jumpifnexttargetvalid(void);
|
|
static void Cmd_tryhealhalfhealth(void);
|
|
static void Cmd_trymirrormove(void);
|
|
static void Cmd_setrain(void);
|
|
static void Cmd_setreflect(void);
|
|
static void Cmd_setseeded(void);
|
|
static void Cmd_manipulatedamage(void);
|
|
static void Cmd_trysetrest(void);
|
|
static void Cmd_jumpifnotfirstturn(void);
|
|
static void Cmd_nop(void);
|
|
static void Cmd_jumpifcantmakeasleep(void);
|
|
static void Cmd_stockpile(void);
|
|
static void Cmd_stockpiletobasedamage(void);
|
|
static void Cmd_stockpiletohpheal(void);
|
|
static void Cmd_negativedamage(void);
|
|
static void Cmd_statbuffchange(void);
|
|
static void Cmd_normalisebuffs(void);
|
|
static void Cmd_setbide(void);
|
|
static void Cmd_confuseifrepeatingattackends(void);
|
|
static void Cmd_setmultihitcounter(void);
|
|
static void Cmd_initmultihitstring(void);
|
|
static void Cmd_forcerandomswitch(void);
|
|
static void Cmd_tryconversiontypechange(void);
|
|
static void Cmd_givepaydaymoney(void);
|
|
static void Cmd_setlightscreen(void);
|
|
static void Cmd_tryKO(void);
|
|
static void Cmd_damagetohalftargethp(void);
|
|
static void Cmd_setsandstorm(void);
|
|
static void Cmd_weatherdamage(void);
|
|
static void Cmd_tryinfatuating(void);
|
|
static void Cmd_updatestatusicon(void);
|
|
static void Cmd_setmist(void);
|
|
static void Cmd_setfocusenergy(void);
|
|
static void Cmd_transformdataexecution(void);
|
|
static void Cmd_setsubstitute(void);
|
|
static void Cmd_mimicattackcopy(void);
|
|
static void Cmd_metronome(void);
|
|
static void Cmd_dmgtolevel(void);
|
|
static void Cmd_psywavedamageeffect(void);
|
|
static void Cmd_counterdamagecalculator(void);
|
|
static void Cmd_mirrorcoatdamagecalculator(void);
|
|
static void Cmd_disablelastusedattack(void);
|
|
static void Cmd_trysetencore(void);
|
|
static void Cmd_painsplitdmgcalc(void);
|
|
static void Cmd_settypetorandomresistance(void);
|
|
static void Cmd_setalwayshitflag(void);
|
|
static void Cmd_copymovepermanently(void);
|
|
static void Cmd_trychoosesleeptalkmove(void);
|
|
static void Cmd_setdestinybond(void);
|
|
static void Cmd_trysetdestinybondtohappen(void);
|
|
static void Cmd_remaininghptopower(void);
|
|
static void Cmd_tryspiteppreduce(void);
|
|
static void Cmd_healpartystatus(void);
|
|
static void Cmd_cursetarget(void);
|
|
static void Cmd_trysetspikes(void);
|
|
static void Cmd_setforesight(void);
|
|
static void Cmd_trysetperishsong(void);
|
|
static void Cmd_rolloutdamagecalculation(void);
|
|
static void Cmd_jumpifconfusedandstatmaxed(void);
|
|
static void Cmd_furycuttercalc(void);
|
|
static void Cmd_happinesstodamagecalculation(void);
|
|
static void Cmd_presentdamagecalculation(void);
|
|
static void Cmd_setsafeguard(void);
|
|
static void Cmd_magnitudedamagecalculation(void);
|
|
static void Cmd_jumpifnopursuitswitchdmg(void);
|
|
static void Cmd_setsunny(void);
|
|
static void Cmd_maxattackhalvehp(void);
|
|
static void Cmd_copyfoestats(void);
|
|
static void Cmd_rapidspinfree(void);
|
|
static void Cmd_setdefensecurlbit(void);
|
|
static void Cmd_recoverbasedonsunlight(void);
|
|
static void Cmd_hiddenpowercalc(void);
|
|
static void Cmd_selectfirstvalidtarget(void);
|
|
static void Cmd_trysetfutureattack(void);
|
|
static void Cmd_trydobeatup(void);
|
|
static void Cmd_setsemiinvulnerablebit(void);
|
|
static void Cmd_clearsemiinvulnerablebit(void);
|
|
static void Cmd_setminimize(void);
|
|
static void Cmd_sethail(void);
|
|
static void Cmd_jumpifattackandspecialattackcannotfall(void);
|
|
static void Cmd_setforcedtarget(void);
|
|
static void Cmd_setcharge(void);
|
|
static void Cmd_callterrainattack(void);
|
|
static void Cmd_cureifburnedparalysedorpoisoned(void);
|
|
static void Cmd_settorment(void);
|
|
static void Cmd_jumpifnodamage(void);
|
|
static void Cmd_settaunt(void);
|
|
static void Cmd_trysethelpinghand(void);
|
|
static void Cmd_tryswapitems(void);
|
|
static void Cmd_trycopyability(void);
|
|
static void Cmd_trywish(void);
|
|
static void Cmd_trysetroots(void);
|
|
static void Cmd_doubledamagedealtifdamaged(void);
|
|
static void Cmd_setyawn(void);
|
|
static void Cmd_setdamagetohealthdifference(void);
|
|
static void Cmd_scaledamagebyhealthratio(void);
|
|
static void Cmd_tryswapabilities(void);
|
|
static void Cmd_tryimprison(void);
|
|
static void Cmd_trysetgrudge(void);
|
|
static void Cmd_weightdamagecalculation(void);
|
|
static void Cmd_assistattackselect(void);
|
|
static void Cmd_trysetmagiccoat(void);
|
|
static void Cmd_trysetsnatch(void);
|
|
static void Cmd_trygetintimidatetarget(void);
|
|
static void Cmd_switchoutabilities(void);
|
|
static void Cmd_jumpifhasnohp(void);
|
|
static void Cmd_getsecretpowereffect(void);
|
|
static void Cmd_pickup(void);
|
|
static void Cmd_docastformchangeanimation(void);
|
|
static void Cmd_trycastformdatachange(void);
|
|
static void Cmd_settypebasedhalvers(void);
|
|
static void Cmd_setweatherballtype(void);
|
|
static void Cmd_tryrecycleitem(void);
|
|
static void Cmd_settypetoterrain(void);
|
|
static void Cmd_pursuitrelated(void);
|
|
static void Cmd_snatchsetbattlers(void);
|
|
static void Cmd_removelightscreenreflect(void);
|
|
static void Cmd_handleballthrow(void);
|
|
static void Cmd_givecaughtmon(void);
|
|
static void Cmd_trysetcaughtmondexflags(void);
|
|
static void Cmd_displaydexinfo(void);
|
|
static void Cmd_trygivecaughtmonnick(void);
|
|
static void Cmd_subattackerhpbydmg(void);
|
|
static void Cmd_removeattackerstatus1(void);
|
|
static void Cmd_finishaction(void);
|
|
static void Cmd_finishturn(void);
|
|
static void Cmd_trainerslideout(void);
|
|
|
|
void (* const gBattleScriptingCommandsTable[])(void) =
|
|
{
|
|
Cmd_attackcanceler, //0x0
|
|
Cmd_accuracycheck, //0x1
|
|
Cmd_attackstring, //0x2
|
|
Cmd_ppreduce, //0x3
|
|
Cmd_critcalc, //0x4
|
|
Cmd_damagecalc, //0x5
|
|
Cmd_typecalc, //0x6
|
|
Cmd_adjustnormaldamage, //0x7
|
|
Cmd_adjustnormaldamage2, //0x8
|
|
Cmd_attackanimation, //0x9
|
|
Cmd_waitanimation, //0xA
|
|
Cmd_healthbarupdate, //0xB
|
|
Cmd_datahpupdate, //0xC
|
|
Cmd_critmessage, //0xD
|
|
Cmd_effectivenesssound, //0xE
|
|
Cmd_resultmessage, //0xF
|
|
Cmd_printstring, //0x10
|
|
Cmd_printselectionstring, //0x11
|
|
Cmd_waitmessage, //0x12
|
|
Cmd_printfromtable, //0x13
|
|
Cmd_printselectionstringfromtable, //0x14
|
|
Cmd_seteffectwithchance, //0x15
|
|
Cmd_seteffectprimary, //0x16
|
|
Cmd_seteffectsecondary, //0x17
|
|
Cmd_clearstatusfromeffect, //0x18
|
|
Cmd_tryfaintmon, //0x19
|
|
Cmd_dofaintanimation, //0x1A
|
|
Cmd_cleareffectsonfaint, //0x1B
|
|
Cmd_jumpifstatus, //0x1C
|
|
Cmd_jumpifstatus2, //0x1D
|
|
Cmd_jumpifability, //0x1E
|
|
Cmd_jumpifsideaffecting, //0x1F
|
|
Cmd_jumpifstat, //0x20
|
|
Cmd_jumpifstatus3condition, //0x21
|
|
Cmd_jumpiftype, //0x22
|
|
Cmd_getexp, //0x23
|
|
Cmd_unknown_24, //0x24
|
|
Cmd_movevaluescleanup, //0x25
|
|
Cmd_setmultihit, //0x26
|
|
Cmd_decrementmultihit, //0x27
|
|
Cmd_goto, //0x28
|
|
Cmd_jumpifbyte, //0x29
|
|
Cmd_jumpifhalfword, //0x2A
|
|
Cmd_jumpifword, //0x2B
|
|
Cmd_jumpifarrayequal, //0x2C
|
|
Cmd_jumpifarraynotequal, //0x2D
|
|
Cmd_setbyte, //0x2E
|
|
Cmd_addbyte, //0x2F
|
|
Cmd_subbyte, //0x30
|
|
Cmd_copyarray, //0x31
|
|
Cmd_copyarraywithindex, //0x32
|
|
Cmd_orbyte, //0x33
|
|
Cmd_orhalfword, //0x34
|
|
Cmd_orword, //0x35
|
|
Cmd_bicbyte, //0x36
|
|
Cmd_bichalfword, //0x37
|
|
Cmd_bicword, //0x38
|
|
Cmd_pause, //0x39
|
|
Cmd_waitstate, //0x3A
|
|
Cmd_healthbar_update, //0x3B
|
|
Cmd_return, //0x3C
|
|
Cmd_end, //0x3D
|
|
Cmd_end2, //0x3E
|
|
Cmd_end3, //0x3F
|
|
Cmd_jumpifaffectedbyprotect, //0x40
|
|
Cmd_call, //0x41
|
|
Cmd_jumpiftype2, //0x42
|
|
Cmd_jumpifabilitypresent, //0x43
|
|
Cmd_endselectionscript, //0x44
|
|
Cmd_playanimation, //0x45
|
|
Cmd_playanimation2, //0x46
|
|
Cmd_setgraphicalstatchangevalues, //0x47
|
|
Cmd_playstatchangeanimation, //0x48
|
|
Cmd_moveend, //0x49
|
|
Cmd_typecalc2, //0x4A
|
|
Cmd_returnatktoball, //0x4B
|
|
Cmd_getswitchedmondata, //0x4C
|
|
Cmd_switchindataupdate, //0x4D
|
|
Cmd_switchinanim, //0x4E
|
|
Cmd_jumpifcantswitch, //0x4F
|
|
Cmd_openpartyscreen, //0x50
|
|
Cmd_switchhandleorder, //0x51
|
|
Cmd_switchineffects, //0x52
|
|
Cmd_trainerslidein, //0x53
|
|
Cmd_playse, //0x54
|
|
Cmd_fanfare, //0x55
|
|
Cmd_playfaintcry, //0x56
|
|
Cmd_unknown_57, //0x57
|
|
Cmd_returntoball, //0x58
|
|
Cmd_handlelearnnewmove, //0x59
|
|
Cmd_yesnoboxlearnmove, //0x5A
|
|
Cmd_yesnoboxstoplearningmove, //0x5B
|
|
Cmd_hitanimation, //0x5C
|
|
Cmd_getmoneyreward, //0x5D
|
|
Cmd_unknown_5E, //0x5E
|
|
Cmd_swapattackerwithtarget, //0x5F
|
|
Cmd_incrementgamestat, //0x60
|
|
Cmd_drawpartystatussummary, //0x61
|
|
Cmd_hidepartystatussummary, //0x62
|
|
Cmd_jumptocalledmove, //0x63
|
|
Cmd_statusanimation, //0x64
|
|
Cmd_status2animation, //0x65
|
|
Cmd_chosenstatusanimation, //0x66
|
|
Cmd_yesnobox, //0x67
|
|
Cmd_cancelallactions, //0x68
|
|
Cmd_adjustsetdamage, //0x69
|
|
Cmd_removeitem, //0x6A
|
|
Cmd_atknameinbuff1, //0x6B
|
|
Cmd_drawlvlupbox, //0x6C
|
|
Cmd_resetsentmonsvalue, //0x6D
|
|
Cmd_setatktoplayer0, //0x6E
|
|
Cmd_makevisible, //0x6F
|
|
Cmd_recordlastability, //0x70
|
|
Cmd_buffermovetolearn, //0x71
|
|
Cmd_jumpifplayerran, //0x72
|
|
Cmd_hpthresholds, //0x73
|
|
Cmd_hpthresholds2, //0x74
|
|
Cmd_useitemonopponent, //0x75
|
|
Cmd_various, //0x76
|
|
Cmd_setprotectlike, //0x77
|
|
Cmd_faintifabilitynotdamp, //0x78
|
|
Cmd_setatkhptozero, //0x79
|
|
Cmd_jumpifnexttargetvalid, //0x7A
|
|
Cmd_tryhealhalfhealth, //0x7B
|
|
Cmd_trymirrormove, //0x7C
|
|
Cmd_setrain, //0x7D
|
|
Cmd_setreflect, //0x7E
|
|
Cmd_setseeded, //0x7F
|
|
Cmd_manipulatedamage, //0x80
|
|
Cmd_trysetrest, //0x81
|
|
Cmd_jumpifnotfirstturn, //0x82
|
|
Cmd_nop, //0x83
|
|
Cmd_jumpifcantmakeasleep, //0x84
|
|
Cmd_stockpile, //0x85
|
|
Cmd_stockpiletobasedamage, //0x86
|
|
Cmd_stockpiletohpheal, //0x87
|
|
Cmd_negativedamage, //0x88
|
|
Cmd_statbuffchange, //0x89
|
|
Cmd_normalisebuffs, //0x8A
|
|
Cmd_setbide, //0x8B
|
|
Cmd_confuseifrepeatingattackends, //0x8C
|
|
Cmd_setmultihitcounter, //0x8D
|
|
Cmd_initmultihitstring, //0x8E
|
|
Cmd_forcerandomswitch, //0x8F
|
|
Cmd_tryconversiontypechange, //0x90
|
|
Cmd_givepaydaymoney, //0x91
|
|
Cmd_setlightscreen, //0x92
|
|
Cmd_tryKO, //0x93
|
|
Cmd_damagetohalftargethp, //0x94
|
|
Cmd_setsandstorm, //0x95
|
|
Cmd_weatherdamage, //0x96
|
|
Cmd_tryinfatuating, //0x97
|
|
Cmd_updatestatusicon, //0x98
|
|
Cmd_setmist, //0x99
|
|
Cmd_setfocusenergy, //0x9A
|
|
Cmd_transformdataexecution, //0x9B
|
|
Cmd_setsubstitute, //0x9C
|
|
Cmd_mimicattackcopy, //0x9D
|
|
Cmd_metronome, //0x9E
|
|
Cmd_dmgtolevel, //0x9F
|
|
Cmd_psywavedamageeffect, //0xA0
|
|
Cmd_counterdamagecalculator, //0xA1
|
|
Cmd_mirrorcoatdamagecalculator, //0xA2
|
|
Cmd_disablelastusedattack, //0xA3
|
|
Cmd_trysetencore, //0xA4
|
|
Cmd_painsplitdmgcalc, //0xA5
|
|
Cmd_settypetorandomresistance, //0xA6
|
|
Cmd_setalwayshitflag, //0xA7
|
|
Cmd_copymovepermanently, //0xA8
|
|
Cmd_trychoosesleeptalkmove, //0xA9
|
|
Cmd_setdestinybond, //0xAA
|
|
Cmd_trysetdestinybondtohappen, //0xAB
|
|
Cmd_remaininghptopower, //0xAC
|
|
Cmd_tryspiteppreduce, //0xAD
|
|
Cmd_healpartystatus, //0xAE
|
|
Cmd_cursetarget, //0xAF
|
|
Cmd_trysetspikes, //0xB0
|
|
Cmd_setforesight, //0xB1
|
|
Cmd_trysetperishsong, //0xB2
|
|
Cmd_rolloutdamagecalculation, //0xB3
|
|
Cmd_jumpifconfusedandstatmaxed, //0xB4
|
|
Cmd_furycuttercalc, //0xB5
|
|
Cmd_happinesstodamagecalculation, //0xB6
|
|
Cmd_presentdamagecalculation, //0xB7
|
|
Cmd_setsafeguard, //0xB8
|
|
Cmd_magnitudedamagecalculation, //0xB9
|
|
Cmd_jumpifnopursuitswitchdmg, //0xBA
|
|
Cmd_setsunny, //0xBB
|
|
Cmd_maxattackhalvehp, //0xBC
|
|
Cmd_copyfoestats, //0xBD
|
|
Cmd_rapidspinfree, //0xBE
|
|
Cmd_setdefensecurlbit, //0xBF
|
|
Cmd_recoverbasedonsunlight, //0xC0
|
|
Cmd_hiddenpowercalc, //0xC1
|
|
Cmd_selectfirstvalidtarget, //0xC2
|
|
Cmd_trysetfutureattack, //0xC3
|
|
Cmd_trydobeatup, //0xC4
|
|
Cmd_setsemiinvulnerablebit, //0xC5
|
|
Cmd_clearsemiinvulnerablebit, //0xC6
|
|
Cmd_setminimize, //0xC7
|
|
Cmd_sethail, //0xC8
|
|
Cmd_jumpifattackandspecialattackcannotfall, //0xC9
|
|
Cmd_setforcedtarget, //0xCA
|
|
Cmd_setcharge, //0xCB
|
|
Cmd_callterrainattack, //0xCC
|
|
Cmd_cureifburnedparalysedorpoisoned, //0xCD
|
|
Cmd_settorment, //0xCE
|
|
Cmd_jumpifnodamage, //0xCF
|
|
Cmd_settaunt, //0xD0
|
|
Cmd_trysethelpinghand, //0xD1
|
|
Cmd_tryswapitems, //0xD2
|
|
Cmd_trycopyability, //0xD3
|
|
Cmd_trywish, //0xD4
|
|
Cmd_trysetroots, //0xD5
|
|
Cmd_doubledamagedealtifdamaged, //0xD6
|
|
Cmd_setyawn, //0xD7
|
|
Cmd_setdamagetohealthdifference, //0xD8
|
|
Cmd_scaledamagebyhealthratio, //0xD9
|
|
Cmd_tryswapabilities, //0xDA
|
|
Cmd_tryimprison, //0xDB
|
|
Cmd_trysetgrudge, //0xDC
|
|
Cmd_weightdamagecalculation, //0xDD
|
|
Cmd_assistattackselect, //0xDE
|
|
Cmd_trysetmagiccoat, //0xDF
|
|
Cmd_trysetsnatch, //0xE0
|
|
Cmd_trygetintimidatetarget, //0xE1
|
|
Cmd_switchoutabilities, //0xE2
|
|
Cmd_jumpifhasnohp, //0xE3
|
|
Cmd_getsecretpowereffect, //0xE4
|
|
Cmd_pickup, //0xE5
|
|
Cmd_docastformchangeanimation, //0xE6
|
|
Cmd_trycastformdatachange, //0xE7
|
|
Cmd_settypebasedhalvers, //0xE8
|
|
Cmd_setweatherballtype, //0xE9
|
|
Cmd_tryrecycleitem, //0xEA
|
|
Cmd_settypetoterrain, //0xEB
|
|
Cmd_pursuitrelated, //0xEC
|
|
Cmd_snatchsetbattlers, //0xED
|
|
Cmd_removelightscreenreflect, //0xEE
|
|
Cmd_handleballthrow, //0xEF
|
|
Cmd_givecaughtmon, //0xF0
|
|
Cmd_trysetcaughtmondexflags, //0xF1
|
|
Cmd_displaydexinfo, //0xF2
|
|
Cmd_trygivecaughtmonnick, //0xF3
|
|
Cmd_subattackerhpbydmg, //0xF4
|
|
Cmd_removeattackerstatus1, //0xF5
|
|
Cmd_finishaction, //0xF6
|
|
Cmd_finishturn, //0xF7
|
|
Cmd_trainerslideout //0xF8
|
|
};
|
|
|
|
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[NUM_MOVE_EFFECTS] =
|
|
{
|
|
[MOVE_EFFECT_SLEEP] = STATUS1_SLEEP,
|
|
[MOVE_EFFECT_POISON] = STATUS1_POISON,
|
|
[MOVE_EFFECT_BURN] = STATUS1_BURN,
|
|
[MOVE_EFFECT_FREEZE] = STATUS1_FREEZE,
|
|
[MOVE_EFFECT_PARALYSIS] = STATUS1_PARALYSIS,
|
|
[MOVE_EFFECT_TOXIC] = STATUS1_TOXIC_POISON,
|
|
[MOVE_EFFECT_CONFUSION] = STATUS2_CONFUSION,
|
|
[MOVE_EFFECT_FLINCH] = STATUS2_FLINCHED,
|
|
[MOVE_EFFECT_UPROAR] = STATUS2_UPROAR,
|
|
[MOVE_EFFECT_CHARGING] = STATUS2_MULTIPLETURNS,
|
|
[MOVE_EFFECT_WRAP] = STATUS2_WRAPPED,
|
|
[MOVE_EFFECT_RECHARGE] = STATUS2_RECHARGE,
|
|
[MOVE_EFFECT_PREVENT_ESCAPE] = STATUS2_ESCAPE_PREVENTION,
|
|
[MOVE_EFFECT_NIGHTMARE] = STATUS2_NIGHTMARE,
|
|
[MOVE_EFFECT_THRASH] = STATUS2_LOCK_CONFUSE,
|
|
};
|
|
|
|
static const u8* const sMoveEffectBS_Ptrs[] =
|
|
{
|
|
[0] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_SLEEP] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_POISON] = BattleScript_MoveEffectPoison,
|
|
[MOVE_EFFECT_BURN] = BattleScript_MoveEffectBurn,
|
|
[MOVE_EFFECT_FREEZE] = BattleScript_MoveEffectFreeze,
|
|
[MOVE_EFFECT_PARALYSIS] = BattleScript_MoveEffectParalysis,
|
|
[MOVE_EFFECT_TOXIC] = BattleScript_MoveEffectToxic,
|
|
[MOVE_EFFECT_CONFUSION] = BattleScript_MoveEffectConfusion,
|
|
[MOVE_EFFECT_FLINCH] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_TRI_ATTACK] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_UPROAR] = BattleScript_MoveEffectUproar,
|
|
[MOVE_EFFECT_PAYDAY] = BattleScript_MoveEffectPayDay,
|
|
[MOVE_EFFECT_CHARGING] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_WRAP] = BattleScript_MoveEffectWrap,
|
|
[MOVE_EFFECT_RECOIL_25] = BattleScript_MoveEffectRecoil,
|
|
[MOVE_EFFECT_ATK_PLUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_DEF_PLUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_SPD_PLUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_SP_ATK_PLUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_SP_DEF_PLUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_ACC_PLUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_EVS_PLUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_ATK_MINUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_DEF_MINUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_SPD_MINUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_SP_ATK_MINUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_SP_DEF_MINUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_ACC_MINUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_EVS_MINUS_1] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_RECHARGE] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_RAGE] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_STEAL_ITEM] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_PREVENT_ESCAPE] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_NIGHTMARE] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_ALL_STATS_UP] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_RAPIDSPIN] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_REMOVE_PARALYSIS] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_ATK_DEF_DOWN] = BattleScript_MoveEffectSleep,
|
|
[MOVE_EFFECT_RECOIL_33] = BattleScript_MoveEffectRecoil,
|
|
};
|
|
|
|
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 u32 sUnknown_0831C2E8[] = INCBIN_U32("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 = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = 0,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(32x32),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(32x32),
|
|
.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[] =
|
|
{
|
|
[BATTLE_TERRAIN_GRASS] = MOVE_STUN_SPORE,
|
|
[BATTLE_TERRAIN_LONG_GRASS] = MOVE_RAZOR_LEAF,
|
|
[BATTLE_TERRAIN_SAND] = MOVE_EARTHQUAKE,
|
|
[BATTLE_TERRAIN_UNDERWATER] = MOVE_HYDRO_PUMP,
|
|
[BATTLE_TERRAIN_WATER] = MOVE_SURF,
|
|
[BATTLE_TERRAIN_POND] = MOVE_BUBBLE_BEAM,
|
|
[BATTLE_TERRAIN_MOUNTAIN] = MOVE_ROCK_SLIDE,
|
|
[BATTLE_TERRAIN_CAVE] = MOVE_SHADOW_BALL,
|
|
[BATTLE_TERRAIN_BUILDING] = MOVE_SWIFT,
|
|
[BATTLE_TERRAIN_PLAIN] = 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[] =
|
|
{
|
|
[BATTLE_TERRAIN_GRASS] = TYPE_GRASS,
|
|
[BATTLE_TERRAIN_LONG_GRASS] = TYPE_GRASS,
|
|
[BATTLE_TERRAIN_SAND] = TYPE_GROUND,
|
|
[BATTLE_TERRAIN_UNDERWATER] = TYPE_WATER,
|
|
[BATTLE_TERRAIN_WATER] = TYPE_WATER,
|
|
[BATTLE_TERRAIN_POND] = TYPE_WATER,
|
|
[BATTLE_TERRAIN_MOUNTAIN] = TYPE_ROCK,
|
|
[BATTLE_TERRAIN_CAVE] = TYPE_ROCK,
|
|
[BATTLE_TERRAIN_BUILDING] = TYPE_NORMAL,
|
|
[BATTLE_TERRAIN_PLAIN] = TYPE_NORMAL,
|
|
};
|
|
|
|
// - ITEM_ULTRA_BALL skips Master Ball and ITEM_NONE
|
|
static const u8 sBallCatchBonuses[] =
|
|
{
|
|
[ITEM_ULTRA_BALL - ITEM_ULTRA_BALL] = 20,
|
|
[ITEM_GREAT_BALL - ITEM_ULTRA_BALL] = 15,
|
|
[ITEM_POKE_BALL - ITEM_ULTRA_BALL] = 10,
|
|
[ITEM_SAFARI_BALL - ITEM_ULTRA_BALL] = 15
|
|
};
|
|
|
|
// In Battle Palace, moves are chosen based on the pokemons nature rather than by the player
|
|
// Moves are grouped into "Attack", "Defense", or "Support" (see PALACE_MOVE_GROUP_*)
|
|
// Each nature has a certain percent chance of selecting a move from a particular group
|
|
// and a separate percent chance for each group when below 50% HP
|
|
// The table below doesn't list percentages for Support because you can subtract the other two
|
|
// Support percentages are listed in comments off to the side instead
|
|
#define PALACE_STYLE(atk, def, atkLow, defLow) {atk, atk + def, atkLow, atkLow + defLow}
|
|
|
|
const ALIGNED(4) u8 gBattlePalaceNatureToMoveGroupLikelihood[NUM_NATURES][4] =
|
|
{
|
|
[NATURE_HARDY] = PALACE_STYLE(61, 7, 61, 7), // 32% support >= 50% HP, 32% support < 50% HP
|
|
[NATURE_LONELY] = PALACE_STYLE(20, 25, 84, 8), // 55%, 8%
|
|
[NATURE_BRAVE] = PALACE_STYLE(70, 15, 32, 60), // 15%, 8%
|
|
[NATURE_ADAMANT] = PALACE_STYLE(38, 31, 70, 15), // 31%, 15%
|
|
[NATURE_NAUGHTY] = PALACE_STYLE(20, 70, 70, 22), // 10%, 8%
|
|
[NATURE_BOLD] = PALACE_STYLE(30, 20, 32, 58), // 50%, 10%
|
|
[NATURE_DOCILE] = PALACE_STYLE(56, 22, 56, 22), // 22%, 22%
|
|
[NATURE_RELAXED] = PALACE_STYLE(25, 15, 75, 15), // 60%, 10%
|
|
[NATURE_IMPISH] = PALACE_STYLE(69, 6, 28, 55), // 25%, 17%
|
|
[NATURE_LAX] = PALACE_STYLE(35, 10, 29, 6), // 55%, 65%
|
|
[NATURE_TIMID] = PALACE_STYLE(62, 10, 30, 20), // 28%, 50%
|
|
[NATURE_HASTY] = PALACE_STYLE(58, 37, 88, 6), // 5%, 6%
|
|
[NATURE_SERIOUS] = PALACE_STYLE(34, 11, 29, 11), // 55%, 60%
|
|
[NATURE_JOLLY] = PALACE_STYLE(35, 5, 35, 60), // 60%, 5%
|
|
[NATURE_NAIVE] = PALACE_STYLE(56, 22, 56, 22), // 22%, 22%
|
|
[NATURE_MODEST] = PALACE_STYLE(35, 45, 34, 60), // 20%, 6%
|
|
[NATURE_MILD] = PALACE_STYLE(44, 50, 34, 6), // 6%, 60%
|
|
[NATURE_QUIET] = PALACE_STYLE(56, 22, 56, 22), // 22%, 22%
|
|
[NATURE_BASHFUL] = PALACE_STYLE(30, 58, 30, 58), // 12%, 12%
|
|
[NATURE_RASH] = PALACE_STYLE(30, 13, 27, 6), // 57%, 67%
|
|
[NATURE_CALM] = PALACE_STYLE(40, 50, 25, 62), // 10%, 13%
|
|
[NATURE_GENTLE] = PALACE_STYLE(18, 70, 90, 5), // 12%, 5%
|
|
[NATURE_SASSY] = PALACE_STYLE(88, 6, 22, 20), // 6%, 58%
|
|
[NATURE_CAREFUL] = PALACE_STYLE(42, 50, 42, 5), // 8%, 53%
|
|
[NATURE_QUIRKY] = PALACE_STYLE(56, 22, 56, 22) // 22%, 22%
|
|
};
|
|
|
|
// Indices into gBattlePalaceFlavorTextTable
|
|
static const u8 sBattlePalaceNatureToFlavorTextId[NUM_NATURES] =
|
|
{
|
|
[NATURE_HARDY] = 3,
|
|
[NATURE_LONELY] = 0,
|
|
[NATURE_BRAVE] = 1,
|
|
[NATURE_ADAMANT] = 0,
|
|
[NATURE_NAUGHTY] = 0,
|
|
[NATURE_BOLD] = 1,
|
|
[NATURE_DOCILE] = 3,
|
|
[NATURE_RELAXED] = 0,
|
|
[NATURE_IMPISH] = 1,
|
|
[NATURE_LAX] = 2,
|
|
[NATURE_TIMID] = 2,
|
|
[NATURE_HASTY] = 0,
|
|
[NATURE_SERIOUS] = 3,
|
|
[NATURE_JOLLY] = 1,
|
|
[NATURE_NAIVE] = 3,
|
|
[NATURE_MODEST] = 1,
|
|
[NATURE_MILD] = 2,
|
|
[NATURE_QUIET] = 3,
|
|
[NATURE_BASHFUL] = 3,
|
|
[NATURE_RASH] = 2,
|
|
[NATURE_CALM] = 1,
|
|
[NATURE_GENTLE] = 0,
|
|
[NATURE_SASSY] = 2,
|
|
[NATURE_CAREFUL] = 2,
|
|
[NATURE_QUIRKY] = 3,
|
|
};
|
|
|
|
static void Cmd_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 & (HITMARKER_x800000 | HITMARKER_NO_ATTACKSTRING))
|
|
&& !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
|
|
{
|
|
gBattlescriptCurrInstr = BattleScript_NoPPForMove;
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
return;
|
|
}
|
|
|
|
gHitMarker &= ~(HITMARKER_x800000);
|
|
|
|
if (!(gHitMarker & HITMARKER_OBEYS) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
|
|
{
|
|
i = IsMonDisobedient(); // 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[gBattlerByTurnOrder[i]].stealMove) && gBattleMoves[gCurrentMove].flags & FLAG_SNATCH_AFFECTED)
|
|
{
|
|
PressurePPLose(gBattlerAttacker, gBattlerByTurnOrder[i], MOVE_SNATCH);
|
|
gProtectStructs[gBattlerByTurnOrder[i]].stealMove = 0;
|
|
gBattleScripting.battler = gBattlerByTurnOrder[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 || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST))
|
|
&& ((!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))))
|
|
{
|
|
CancelMultiTurnMoves(gBattlerAttacker);
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gLastLandedMoves[gBattlerTarget] = 0;
|
|
gLastHitByType[gBattlerTarget] = 0;
|
|
gBattleCommunication[6] = 1;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
|
|
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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
TrySetDestinyBondToHappen();
|
|
if (AbilityBattleEffects(ABILITYEFFECT_ABSORBING, gBattlerTarget, 0, 0, move))
|
|
return;
|
|
}
|
|
gBattlescriptCurrInstr = BS_ptr;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_accuracycheck(void)
|
|
{
|
|
u16 move = T2_READ_16(gBattlescriptCurrInstr + 5);
|
|
|
|
if (move == NO_ACC_CALC || move == NO_ACC_CALC_CHECK_LOCK_ON)
|
|
{
|
|
if (gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && move == NO_ACC_CALC_CHECK_LOCK_ON && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker)
|
|
gBattlescriptCurrInstr += 7;
|
|
else if (gStatuses3[gBattlerTarget] & (STATUS3_ON_AIR | STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
else if (!JumpIfMoveAffectedByProtect(0))
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
else
|
|
{
|
|
u8 type, moveAcc, holdEffect, param;
|
|
s8 buff;
|
|
u16 calc;
|
|
|
|
if (move == 0)
|
|
move = gCurrentMove;
|
|
|
|
GET_MOVE_TYPE(move, type);
|
|
|
|
if (JumpIfMoveAffectedByProtect(move))
|
|
return;
|
|
if (AccuracyCalcHelper(move))
|
|
return;
|
|
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_FORESIGHT)
|
|
{
|
|
u8 acc = gBattleMons[gBattlerAttacker].statStages[STAT_ACC];
|
|
buff = acc;
|
|
}
|
|
else
|
|
{
|
|
u8 acc = gBattleMons[gBattlerAttacker].statStages[STAT_ACC];
|
|
buff = acc + DEFAULT_STAT_STAGE - gBattleMons[gBattlerTarget].statStages[STAT_EVASION];
|
|
}
|
|
|
|
if (buff < MIN_STAT_STAGE)
|
|
buff = MIN_STAT_STAGE;
|
|
if (buff > MAX_STAT_STAGE)
|
|
buff = MAX_STAT_STAGE;
|
|
|
|
moveAcc = gBattleMoves[move].accuracy;
|
|
// check Thunder on sunny weather
|
|
if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY && gBattleMoves[move].effect == EFFECT_THUNDER)
|
|
moveAcc = 50;
|
|
|
|
calc = sAccuracyStageRatios[buff].dividend * moveAcc;
|
|
calc /= sAccuracyStageRatios[buff].divisor;
|
|
|
|
if (gBattleMons[gBattlerAttacker].ability == ABILITY_COMPOUND_EYES)
|
|
calc = (calc * 130) / 100; // 1.3 compound eyes boost
|
|
if (WEATHER_HAS_EFFECT && gBattleMons[gBattlerTarget].ability == ABILITY_SAND_VEIL && gBattleWeather & WEATHER_SANDSTORM_ANY)
|
|
calc = (calc * 80) / 100; // 1.2 sand veil loss
|
|
if (gBattleMons[gBattlerAttacker].ability == ABILITY_HUSTLE && IS_TYPE_PHYSICAL(type))
|
|
calc = (calc * 80) / 100; // 1.2 hustle loss
|
|
|
|
if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY)
|
|
{
|
|
holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect;
|
|
param = gEnigmaBerries[gBattlerTarget].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item);
|
|
param = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item);
|
|
}
|
|
|
|
gPotentialItemEffectBattler = gBattlerTarget;
|
|
|
|
if (holdEffect == HOLD_EFFECT_EVASION_UP)
|
|
calc = (calc * (100 - param)) / 100;
|
|
|
|
// final calculation
|
|
if ((Random() % 100 + 1) > calc)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE &&
|
|
(gBattleMoves[move].target == MOVE_TARGET_BOTH || gBattleMoves[move].target == MOVE_TARGET_FOES_AND_ALLY))
|
|
gBattleCommunication[6] = 2;
|
|
else
|
|
gBattleCommunication[6] = 0;
|
|
|
|
CheckWonderGuardAndLevitate();
|
|
}
|
|
JumpIfMoveFailed(7, move);
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 Cmd_ppreduce(void)
|
|
{
|
|
s32 ppToDeduct = 1;
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
if (!gSpecialStatuses[gBattlerAttacker].ppNotAffectedByPressure)
|
|
{
|
|
switch (gBattleMoves[gCurrentMove].target)
|
|
{
|
|
case MOVE_TARGET_FOES_AND_ALLY:
|
|
ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_ON_FIELD, gBattlerAttacker, ABILITY_PRESSURE, 0, 0);
|
|
break;
|
|
case MOVE_TARGET_BOTH:
|
|
case MOVE_TARGET_OPPONENTS_FIELD:
|
|
ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBattlerAttacker, ABILITY_PRESSURE, 0, 0);
|
|
break;
|
|
default:
|
|
if (gBattlerAttacker != gBattlerTarget && gBattleMons[gBattlerTarget].ability == ABILITY_PRESSURE)
|
|
ppToDeduct++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!(gHitMarker & (HITMARKER_NO_PPDEDUCT | HITMARKER_NO_ATTACKSTRING)) && gBattleMons[gBattlerAttacker].pp[gCurrMovePos])
|
|
{
|
|
gProtectStructs[gBattlerAttacker].notFirstStrike = 1;
|
|
|
|
if (gBattleMons[gBattlerAttacker].pp[gCurrMovePos] > ppToDeduct)
|
|
gBattleMons[gBattlerAttacker].pp[gCurrMovePos] -= ppToDeduct;
|
|
else
|
|
gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = 0;
|
|
|
|
if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED)
|
|
&& !((gDisableStructs[gBattlerAttacker].mimickedMoves) & gBitTable[gCurrMovePos]))
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0, 1, &gBattleMons[gBattlerAttacker].pp[gCurrMovePos]);
|
|
MarkBattlerForControllerExec(gBattlerAttacker);
|
|
}
|
|
}
|
|
|
|
gHitMarker &= ~(HITMARKER_NO_PPDEDUCT);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_critcalc(void)
|
|
{
|
|
u8 holdEffect;
|
|
u16 item, critChance;
|
|
|
|
item = gBattleMons[gBattlerAttacker].item;
|
|
|
|
if (item == ITEM_ENIGMA_BERRY)
|
|
holdEffect = gEnigmaBerries[gBattlerAttacker].holdEffect;
|
|
else
|
|
holdEffect = ItemId_GetHoldEffect(item);
|
|
|
|
gPotentialItemEffectBattler = gBattlerAttacker;
|
|
|
|
critChance = 2 * ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0)
|
|
+ (gBattleMoves[gCurrentMove].effect == EFFECT_HIGH_CRITICAL)
|
|
+ (gBattleMoves[gCurrentMove].effect == EFFECT_SKY_ATTACK)
|
|
+ (gBattleMoves[gCurrentMove].effect == EFFECT_BLAZE_KICK)
|
|
+ (gBattleMoves[gCurrentMove].effect == EFFECT_POISON_TAIL)
|
|
+ (holdEffect == HOLD_EFFECT_SCOPE_LENS)
|
|
+ 2 * (holdEffect == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY)
|
|
+ 2 * (holdEffect == HOLD_EFFECT_STICK && gBattleMons[gBattlerAttacker].species == SPECIES_FARFETCHD);
|
|
|
|
if (critChance >= ARRAY_COUNT(sCriticalHitChance))
|
|
critChance = ARRAY_COUNT(sCriticalHitChance) - 1;
|
|
|
|
if ((gBattleMons[gBattlerTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBattlerTarget].ability != ABILITY_SHELL_ARMOR)
|
|
&& !(gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT)
|
|
&& !(gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE))
|
|
&& !(Random() % sCriticalHitChance[critChance]))
|
|
gCritMultiplier = 2;
|
|
else
|
|
gCritMultiplier = 1;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_typecalc(void)
|
|
{
|
|
s32 i = 0;
|
|
u8 moveType;
|
|
|
|
if (gCurrentMove == MOVE_STRUGGLE)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
return;
|
|
}
|
|
|
|
GET_MOVE_TYPE(gCurrentMove, moveType);
|
|
|
|
// check stab
|
|
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, moveType))
|
|
{
|
|
gBattleMoveDamage = gBattleMoveDamage * 15;
|
|
gBattleMoveDamage = gBattleMoveDamage / 10;
|
|
}
|
|
|
|
if (gBattleMons[gBattlerTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND)
|
|
{
|
|
gLastUsedAbility = gBattleMons[gBattlerTarget].ability;
|
|
gMoveResultFlags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE);
|
|
gLastLandedMoves[gBattlerTarget] = 0;
|
|
gLastHitByType[gBattlerTarget] = 0;
|
|
gBattleCommunication[6] = moveType;
|
|
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
|
|
}
|
|
else
|
|
{
|
|
while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE)
|
|
{
|
|
if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_FORESIGHT)
|
|
break;
|
|
i += 3;
|
|
continue;
|
|
}
|
|
else if (TYPE_EFFECT_ATK_TYPE(i) == moveType)
|
|
{
|
|
// check type1
|
|
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type1)
|
|
ModulateDmgByType(TYPE_EFFECT_MULTIPLIER(i));
|
|
// check type2
|
|
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2 &&
|
|
gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2)
|
|
ModulateDmgByType(TYPE_EFFECT_MULTIPLIER(i));
|
|
}
|
|
i += 3;
|
|
}
|
|
}
|
|
|
|
if (gBattleMons[gBattlerTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBattlerAttacker, gCurrentMove) == 2
|
|
&& (!(gMoveResultFlags & MOVE_RESULT_SUPER_EFFECTIVE) || ((gMoveResultFlags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)))
|
|
&& gBattleMoves[gCurrentMove].power)
|
|
{
|
|
gLastUsedAbility = ABILITY_WONDER_GUARD;
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gLastLandedMoves[gBattlerTarget] = 0;
|
|
gLastHitByType[gBattlerTarget] = 0;
|
|
gBattleCommunication[6] = 3;
|
|
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
|
|
}
|
|
if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE)
|
|
gProtectStructs[gBattlerAttacker].targetNotAffected = 1;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
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 (IS_BATTLER_OF_TYPE(attacker, moveType))
|
|
{
|
|
gBattleMoveDamage = gBattleMoveDamage * 15;
|
|
gBattleMoveDamage = gBattleMoveDamage / 10;
|
|
}
|
|
|
|
if (gBattleMons[defender].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND)
|
|
{
|
|
flags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE);
|
|
}
|
|
else
|
|
{
|
|
while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE)
|
|
{
|
|
if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT)
|
|
{
|
|
if (gBattleMons[defender].status2 & STATUS2_FORESIGHT)
|
|
break;
|
|
i += 3;
|
|
continue;
|
|
}
|
|
|
|
else if (TYPE_EFFECT_ATK_TYPE(i) == moveType)
|
|
{
|
|
// check type1
|
|
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[defender].type1)
|
|
ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags);
|
|
// check type2
|
|
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[defender].type2 &&
|
|
gBattleMons[defender].type1 != gBattleMons[defender].type2)
|
|
ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags);
|
|
}
|
|
i += 3;
|
|
}
|
|
}
|
|
|
|
if (gBattleMons[defender].ability == ABILITY_WONDER_GUARD && !(flags & MOVE_RESULT_MISSED)
|
|
&& AttacksThisTurn(attacker, move) == 2
|
|
&& (!(flags & MOVE_RESULT_SUPER_EFFECTIVE) || ((flags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)))
|
|
&& gBattleMoves[move].power)
|
|
{
|
|
flags |= MOVE_RESULT_MISSED;
|
|
}
|
|
return flags;
|
|
}
|
|
|
|
u8 AI_TypeCalc(u16 move, u16 targetSpecies, u8 targetAbility)
|
|
{
|
|
s32 i = 0;
|
|
u8 flags = 0;
|
|
u8 type1 = gBaseStats[targetSpecies].type1, type2 = gBaseStats[targetSpecies].type2;
|
|
u8 moveType;
|
|
|
|
if (move == MOVE_STRUGGLE)
|
|
return 0;
|
|
|
|
moveType = gBattleMoves[move].type;
|
|
|
|
if (targetAbility == ABILITY_LEVITATE && moveType == TYPE_GROUND)
|
|
{
|
|
flags = MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE;
|
|
}
|
|
else
|
|
{
|
|
while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE)
|
|
{
|
|
if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT)
|
|
{
|
|
i += 3;
|
|
continue;
|
|
}
|
|
if (TYPE_EFFECT_ATK_TYPE(i) == moveType)
|
|
{
|
|
// check type1
|
|
if (TYPE_EFFECT_DEF_TYPE(i) == type1)
|
|
ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags);
|
|
// check type2
|
|
if (TYPE_EFFECT_DEF_TYPE(i) == type2 && type1 != type2)
|
|
ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags);
|
|
}
|
|
i += 3;
|
|
}
|
|
}
|
|
if (targetAbility == ABILITY_WONDER_GUARD
|
|
&& (!(flags & MOVE_RESULT_SUPER_EFFECTIVE) || ((flags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)))
|
|
&& gBattleMoves[move].power)
|
|
flags |= MOVE_RESULT_DOESNT_AFFECT_FOE;
|
|
return flags;
|
|
}
|
|
|
|
// 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 Cmd_adjustnormaldamage(void)
|
|
{
|
|
u8 holdEffect, param;
|
|
|
|
ApplyRandomDmgMultiplier();
|
|
|
|
if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY)
|
|
{
|
|
holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect;
|
|
param = gEnigmaBerries[gBattlerTarget].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item);
|
|
param = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item);
|
|
}
|
|
|
|
gPotentialItemEffectBattler = gBattlerTarget;
|
|
|
|
if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param)
|
|
{
|
|
RecordItemEffectBattle(gBattlerTarget, holdEffect);
|
|
gSpecialStatuses[gBattlerTarget].focusBanded = 1;
|
|
}
|
|
if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE)
|
|
&& (gBattleMoves[gCurrentMove].effect == EFFECT_FALSE_SWIPE || gProtectStructs[gBattlerTarget].endured || gSpecialStatuses[gBattlerTarget].focusBanded)
|
|
&& gBattleMons[gBattlerTarget].hp <= gBattleMoveDamage)
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - 1;
|
|
if (gProtectStructs[gBattlerTarget].endured)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_FOE_ENDURED;
|
|
}
|
|
else if (gSpecialStatuses[gBattlerTarget].focusBanded)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_FOE_HUNG_ON;
|
|
gLastUsedItem = gBattleMons[gBattlerTarget].item;
|
|
}
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_adjustnormaldamage2(void) // The same as adjustnormaldamage except it doesn't check for false swipe move effect.
|
|
{
|
|
u8 holdEffect, param;
|
|
|
|
ApplyRandomDmgMultiplier();
|
|
|
|
if (gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY)
|
|
{
|
|
holdEffect = gEnigmaBerries[gBattlerTarget].holdEffect;
|
|
param = gEnigmaBerries[gBattlerTarget].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
holdEffect = ItemId_GetHoldEffect(gBattleMons[gBattlerTarget].item);
|
|
param = ItemId_GetHoldEffectParam(gBattleMons[gBattlerTarget].item);
|
|
}
|
|
|
|
gPotentialItemEffectBattler = gBattlerTarget;
|
|
|
|
if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param)
|
|
{
|
|
RecordItemEffectBattle(gBattlerTarget, holdEffect);
|
|
gSpecialStatuses[gBattlerTarget].focusBanded = 1;
|
|
}
|
|
if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE)
|
|
&& (gProtectStructs[gBattlerTarget].endured || gSpecialStatuses[gBattlerTarget].focusBanded)
|
|
&& gBattleMons[gBattlerTarget].hp <= gBattleMoveDamage)
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - 1;
|
|
if (gProtectStructs[gBattlerTarget].endured)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_FOE_ENDURED;
|
|
}
|
|
else if (gSpecialStatuses[gBattlerTarget].focusBanded)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_FOE_HUNG_ON;
|
|
gLastUsedItem = gBattleMons[gBattlerTarget].item;
|
|
}
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_waitanimation(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_healthbarupdate(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
|
|
if (gBattleMons[gActiveBattler].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBattler].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE))
|
|
{
|
|
PrepareStringBattle(STRINGID_SUBSTITUTEDAMAGED, gActiveBattler);
|
|
}
|
|
else
|
|
{
|
|
s16 healthValue;
|
|
|
|
s32 currDmg = gBattleMoveDamage;
|
|
s32 maxPossibleDmgValue = 10000; // not present in R/S, ensures that huge damage values don't change sign
|
|
|
|
if (currDmg <= maxPossibleDmgValue)
|
|
healthValue = currDmg;
|
|
else
|
|
healthValue = maxPossibleDmgValue;
|
|
|
|
BtlController_EmitHealthBarUpdate(0, healthValue);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER && gBattleMoveDamage > 0)
|
|
gBattleResults.playerMonWasDamaged = TRUE;
|
|
}
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_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 = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
if (gBattleMons[gActiveBattler].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBattler].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE))
|
|
{
|
|
if (gDisableStructs[gActiveBattler].substituteHP >= gBattleMoveDamage)
|
|
{
|
|
if (gSpecialStatuses[gActiveBattler].dmg == 0)
|
|
gSpecialStatuses[gActiveBattler].dmg = gBattleMoveDamage;
|
|
gDisableStructs[gActiveBattler].substituteHP -= gBattleMoveDamage;
|
|
gHpDealt = gBattleMoveDamage;
|
|
}
|
|
else
|
|
{
|
|
if (gSpecialStatuses[gActiveBattler].dmg == 0)
|
|
gSpecialStatuses[gActiveBattler].dmg = gDisableStructs[gActiveBattler].substituteHP;
|
|
gHpDealt = gDisableStructs[gActiveBattler].substituteHP;
|
|
gDisableStructs[gActiveBattler].substituteHP = 0;
|
|
}
|
|
// check substitute fading
|
|
if (gDisableStructs[gActiveBattler].substituteHP == 0)
|
|
{
|
|
gBattlescriptCurrInstr += 2;
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_SubstituteFade;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gHitMarker &= ~(HITMARKER_IGNORE_SUBSTITUTE);
|
|
if (gBattleMoveDamage < 0) // hp goes up
|
|
{
|
|
gBattleMons[gActiveBattler].hp -= gBattleMoveDamage;
|
|
if (gBattleMons[gActiveBattler].hp > gBattleMons[gActiveBattler].maxHP)
|
|
gBattleMons[gActiveBattler].hp = gBattleMons[gActiveBattler].maxHP;
|
|
|
|
}
|
|
else // hp goes down
|
|
{
|
|
if (gHitMarker & HITMARKER_x20)
|
|
{
|
|
gHitMarker &= ~(HITMARKER_x20);
|
|
}
|
|
else
|
|
{
|
|
gTakenDmg[gActiveBattler] += gBattleMoveDamage;
|
|
if (gBattlescriptCurrInstr[1] == BS_TARGET)
|
|
gTakenDmgByBattler[gActiveBattler] = gBattlerAttacker;
|
|
else
|
|
gTakenDmgByBattler[gActiveBattler] = gBattlerTarget;
|
|
}
|
|
|
|
if (gBattleMons[gActiveBattler].hp > gBattleMoveDamage)
|
|
{
|
|
gBattleMons[gActiveBattler].hp -= gBattleMoveDamage;
|
|
gHpDealt = gBattleMoveDamage;
|
|
}
|
|
else
|
|
{
|
|
gHpDealt = gBattleMons[gActiveBattler].hp;
|
|
gBattleMons[gActiveBattler].hp = 0;
|
|
}
|
|
|
|
if (!gSpecialStatuses[gActiveBattler].dmg && !(gHitMarker & HITMARKER_x100000))
|
|
gSpecialStatuses[gActiveBattler].dmg = gHpDealt;
|
|
|
|
if (IS_TYPE_PHYSICAL(moveType) && !(gHitMarker & HITMARKER_x100000) && gCurrentMove != MOVE_PAIN_SPLIT)
|
|
{
|
|
gProtectStructs[gActiveBattler].physicalDmg = gHpDealt;
|
|
gSpecialStatuses[gActiveBattler].physicalDmg = gHpDealt;
|
|
if (gBattlescriptCurrInstr[1] == BS_TARGET)
|
|
{
|
|
gProtectStructs[gActiveBattler].physicalBattlerId = gBattlerAttacker;
|
|
gSpecialStatuses[gActiveBattler].physicalBattlerId = gBattlerAttacker;
|
|
}
|
|
else
|
|
{
|
|
gProtectStructs[gActiveBattler].physicalBattlerId = gBattlerTarget;
|
|
gSpecialStatuses[gActiveBattler].physicalBattlerId = gBattlerTarget;
|
|
}
|
|
}
|
|
else if (!IS_TYPE_PHYSICAL(moveType) && !(gHitMarker & HITMARKER_x100000))
|
|
{
|
|
gProtectStructs[gActiveBattler].specialDmg = gHpDealt;
|
|
gSpecialStatuses[gActiveBattler].specialDmg = gHpDealt;
|
|
if (gBattlescriptCurrInstr[1] == BS_TARGET)
|
|
{
|
|
gProtectStructs[gActiveBattler].specialBattlerId = gBattlerAttacker;
|
|
gSpecialStatuses[gActiveBattler].specialBattlerId = gBattlerAttacker;
|
|
}
|
|
else
|
|
{
|
|
gProtectStructs[gActiveBattler].specialBattlerId = gBattlerTarget;
|
|
gSpecialStatuses[gActiveBattler].specialBattlerId = gBattlerTarget;
|
|
}
|
|
}
|
|
}
|
|
gHitMarker &= ~(HITMARKER_x100000);
|
|
BtlController_EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBattler].hp);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
if (gSpecialStatuses[gActiveBattler].dmg == 0)
|
|
gSpecialStatuses[gActiveBattler].dmg = 0xFFFF;
|
|
}
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_critmessage(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
if (gCritMultiplier == 2 && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
|
|
{
|
|
PrepareStringBattle(STRINGID_CRITICALHIT, gBattlerAttacker);
|
|
gBattleCommunication[MSG_DISPLAY] = 1;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
|
|
static void Cmd_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_SUPER_EFFECTIVE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
break;
|
|
case MOVE_RESULT_NOT_VERY_EFFECTIVE:
|
|
BtlController_EmitPlaySE(0, SE_NOT_EFFECTIVE);
|
|
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_SUPER_EFFECTIVE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else if (gMoveResultFlags & MOVE_RESULT_NOT_VERY_EFFECTIVE)
|
|
{
|
|
BtlController_EmitPlaySE(0, SE_NOT_EFFECTIVE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else if (!(gMoveResultFlags & (MOVE_RESULT_DOESNT_AFFECT_FOE | MOVE_RESULT_FAILED)))
|
|
{
|
|
BtlController_EmitPlaySE(0, SE_EFFECTIVE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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;
|
|
gPotentialItemEffectBattler = gBattlerTarget;
|
|
gMoveResultFlags &= ~(MOVE_RESULT_FOE_ENDURED | MOVE_RESULT_FOE_HUNG_ON);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_FocusBandActivates;
|
|
return;
|
|
default:
|
|
if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE)
|
|
{
|
|
stringId = STRINGID_ITDOESNTAFFECT;
|
|
}
|
|
else if (gMoveResultFlags & MOVE_RESULT_ONE_HIT_KO)
|
|
{
|
|
gMoveResultFlags &= ~(MOVE_RESULT_ONE_HIT_KO);
|
|
gMoveResultFlags &= ~(MOVE_RESULT_SUPER_EFFECTIVE);
|
|
gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_OneHitKOMsg;
|
|
return;
|
|
}
|
|
else if (gMoveResultFlags & MOVE_RESULT_FOE_ENDURED)
|
|
{
|
|
gMoveResultFlags &= ~(MOVE_RESULT_FOE_ENDURED | MOVE_RESULT_FOE_HUNG_ON);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_EnduredMsg;
|
|
return;
|
|
}
|
|
else if (gMoveResultFlags & MOVE_RESULT_FOE_HUNG_ON)
|
|
{
|
|
gLastUsedItem = gBattleMons[gBattlerTarget].item;
|
|
gPotentialItemEffectBattler = gBattlerTarget;
|
|
gMoveResultFlags &= ~(MOVE_RESULT_FOE_ENDURED | MOVE_RESULT_FOE_HUNG_ON);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_FocusBandActivates;
|
|
return;
|
|
}
|
|
else if (gMoveResultFlags & MOVE_RESULT_FAILED)
|
|
{
|
|
stringId = STRINGID_BUTITFAILED;
|
|
}
|
|
else
|
|
{
|
|
gBattleCommunication[MSG_DISPLAY] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (stringId)
|
|
PrepareStringBattle(stringId, gBattlerAttacker);
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_printstring(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
u16 var = T2_READ_16(gBattlescriptCurrInstr + 1);
|
|
PrepareStringBattle(var, gBattlerAttacker);
|
|
gBattlescriptCurrInstr += 3;
|
|
gBattleCommunication[MSG_DISPLAY] = 1;
|
|
}
|
|
}
|
|
|
|
static void Cmd_printselectionstring(void)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
|
|
BtlController_EmitPrintSelectionString(0, T2_READ_16(gBattlescriptCurrInstr + 1));
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
gBattleCommunication[MSG_DISPLAY] = 1;
|
|
}
|
|
|
|
static void Cmd_waitmessage(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
if (!gBattleCommunication[MSG_DISPLAY])
|
|
{
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
else
|
|
{
|
|
u16 toWait = T2_READ_16(gBattlescriptCurrInstr + 1);
|
|
if (++gPauseCounterBattle >= toWait)
|
|
{
|
|
gPauseCounterBattle = 0;
|
|
gBattlescriptCurrInstr += 3;
|
|
gBattleCommunication[MSG_DISPLAY] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Cmd_printfromtable(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
const u16 *ptr = (const u16*) T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
ptr += gBattleCommunication[MULTISTRING_CHOOSER];
|
|
|
|
PrepareStringBattle(*ptr, gBattlerAttacker);
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
gBattleCommunication[MSG_DISPLAY] = 1;
|
|
}
|
|
}
|
|
|
|
static void Cmd_printselectionstringfromtable(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
const u16 *ptr = (const u16*) T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
ptr += gBattleCommunication[MULTISTRING_CHOOSER];
|
|
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitPrintSelectionString(0, *ptr);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
gBattleCommunication[MSG_DISPLAY] = 1;
|
|
}
|
|
}
|
|
|
|
u8 GetBattlerTurnOrderNum(u8 battlerId)
|
|
{
|
|
s32 i;
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gBattlerByTurnOrder[i] == battlerId)
|
|
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)
|
|
{
|
|
gEffectBattler = gBattlerAttacker; // battlerId that effects get applied on
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_AFFECTS_USER);
|
|
affectsUser = MOVE_EFFECT_AFFECTS_USER;
|
|
gBattleScripting.battler = gBattlerTarget; // theoretically the attacker
|
|
}
|
|
else
|
|
{
|
|
gEffectBattler = gBattlerTarget;
|
|
gBattleScripting.battler = gBattlerAttacker;
|
|
}
|
|
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_SHIELD_DUST && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
&& !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 9)
|
|
INCREMENT_RESET_RETURN
|
|
|
|
if (gSideStatuses[GET_BATTLER_SIDE(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
&& !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 7)
|
|
INCREMENT_RESET_RETURN
|
|
|
|
if (gBattleMons[gEffectBattler].hp == 0
|
|
&& gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_PAYDAY
|
|
&& gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_STEAL_ITEM)
|
|
INCREMENT_RESET_RETURN
|
|
|
|
if (gBattleMons[gEffectBattler].status2 & STATUS2_SUBSTITUTE && affectsUser != MOVE_EFFECT_AFFECTS_USER)
|
|
INCREMENT_RESET_RETURN
|
|
|
|
if (gBattleCommunication[MOVE_EFFECT_BYTE] <= PRIMARY_STATUS_MOVE_EFFECT)
|
|
{
|
|
switch (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]])
|
|
{
|
|
case STATUS1_SLEEP:
|
|
// check active uproar
|
|
if (gBattleMons[gEffectBattler].ability != ABILITY_SOUNDPROOF)
|
|
{
|
|
for (gActiveBattler = 0;
|
|
gActiveBattler < gBattlersCount && !(gBattleMons[gActiveBattler].status2 & STATUS2_UPROAR);
|
|
gActiveBattler++)
|
|
{}
|
|
}
|
|
else
|
|
gActiveBattler = gBattlersCount;
|
|
|
|
if (gBattleMons[gEffectBattler].status1)
|
|
break;
|
|
if (gActiveBattler != gBattlersCount)
|
|
break;
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_VITAL_SPIRIT)
|
|
break;
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_INSOMNIA)
|
|
break;
|
|
|
|
CancelMultiTurnMoves(gEffectBattler);
|
|
statusChanged = TRUE;
|
|
break;
|
|
case STATUS1_POISON:
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY
|
|
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
gLastUsedAbility = ABILITY_IMMUNITY;
|
|
RecordAbilityBattle(gEffectBattler, ABILITY_IMMUNITY);
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_PSNPrevention;
|
|
|
|
if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD);
|
|
}
|
|
else
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
RESET_RETURN
|
|
}
|
|
if ((IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_POISON) || IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_STEEL))
|
|
&& (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_PSNPrevention;
|
|
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
RESET_RETURN
|
|
}
|
|
if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_POISON))
|
|
break;
|
|
if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_STEEL))
|
|
break;
|
|
if (gBattleMons[gEffectBattler].status1)
|
|
break;
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY)
|
|
break;
|
|
|
|
statusChanged = TRUE;
|
|
break;
|
|
case STATUS1_BURN:
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_WATER_VEIL
|
|
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
gLastUsedAbility = ABILITY_WATER_VEIL;
|
|
RecordAbilityBattle(gEffectBattler, ABILITY_WATER_VEIL);
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_BRNPrevention;
|
|
if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD);
|
|
}
|
|
else
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
RESET_RETURN
|
|
}
|
|
if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_FIRE)
|
|
&& (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_BRNPrevention;
|
|
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
RESET_RETURN
|
|
}
|
|
if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_FIRE))
|
|
break;
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_WATER_VEIL)
|
|
break;
|
|
if (gBattleMons[gEffectBattler].status1)
|
|
break;
|
|
|
|
statusChanged = TRUE;
|
|
break;
|
|
case STATUS1_FREEZE:
|
|
if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY)
|
|
noSunCanFreeze = FALSE;
|
|
if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_ICE))
|
|
break;
|
|
if (gBattleMons[gEffectBattler].status1)
|
|
break;
|
|
if (noSunCanFreeze == 0)
|
|
break;
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_MAGMA_ARMOR)
|
|
break;
|
|
|
|
CancelMultiTurnMoves(gEffectBattler);
|
|
statusChanged = TRUE;
|
|
break;
|
|
case STATUS1_PARALYSIS:
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_LIMBER)
|
|
{
|
|
if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)
|
|
{
|
|
gLastUsedAbility = ABILITY_LIMBER;
|
|
RecordAbilityBattle(gEffectBattler, ABILITY_LIMBER);
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_PRLZPrevention;
|
|
|
|
if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD);
|
|
}
|
|
else
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
RESET_RETURN
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
if (gBattleMons[gEffectBattler].status1)
|
|
break;
|
|
|
|
statusChanged = TRUE;
|
|
break;
|
|
case STATUS1_TOXIC_POISON:
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
gLastUsedAbility = ABILITY_IMMUNITY;
|
|
RecordAbilityBattle(gEffectBattler, ABILITY_IMMUNITY);
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_PSNPrevention;
|
|
|
|
if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD);
|
|
}
|
|
else
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
RESET_RETURN
|
|
}
|
|
if ((IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_POISON) || IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_STEEL))
|
|
&& (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_PSNPrevention;
|
|
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
RESET_RETURN
|
|
}
|
|
if (gBattleMons[gEffectBattler].status1)
|
|
break;
|
|
if (!IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_POISON) && !IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_STEEL))
|
|
{
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY)
|
|
break;
|
|
|
|
// It's redundant, because at this point we know the status1 value is 0.
|
|
gBattleMons[gEffectBattler].status1 &= ~(STATUS1_TOXIC_POISON);
|
|
gBattleMons[gEffectBattler].status1 &= ~(STATUS1_POISON);
|
|
statusChanged = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE;
|
|
}
|
|
break;
|
|
}
|
|
if (statusChanged == TRUE)
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
|
|
if (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]] == STATUS1_SLEEP)
|
|
gBattleMons[gEffectBattler].status1 |= STATUS1_SLEEP_TURN((Random() & 3) + 2); // 2-5 turns
|
|
else
|
|
gBattleMons[gEffectBattler].status1 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
|
|
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
|
|
gActiveBattler = gEffectBattler;
|
|
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBattler].status1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD)
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD);
|
|
}
|
|
else
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
|
|
// for synchronize
|
|
|
|
if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_POISON
|
|
|| gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_TOXIC
|
|
|| gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_PARALYSIS
|
|
|| gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN)
|
|
{
|
|
u8* synchronizeEffect = &gBattleStruct->synchronizeMoveEffect;
|
|
*synchronizeEffect = gBattleCommunication[MOVE_EFFECT_BYTE];
|
|
gHitMarker |= HITMARKER_SYNCHRONISE_EFFECT;
|
|
}
|
|
return;
|
|
}
|
|
else if (statusChanged == FALSE)
|
|
{
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = 0;
|
|
gBattlescriptCurrInstr++;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (gBattleMons[gEffectBattler].status2 & sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]])
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
u8 side;
|
|
switch (gBattleCommunication[MOVE_EFFECT_BYTE])
|
|
{
|
|
case MOVE_EFFECT_CONFUSION:
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_OWN_TEMPO
|
|
|| gBattleMons[gEffectBattler].status2 & STATUS2_CONFUSION)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gEffectBattler].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2); // 2-5 turns
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_FLINCH:
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_INNER_FOCUS)
|
|
{
|
|
if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)
|
|
{
|
|
gLastUsedAbility = ABILITY_INNER_FOCUS;
|
|
RecordAbilityBattle(gEffectBattler, ABILITY_INNER_FOCUS);
|
|
gBattlescriptCurrInstr = BattleScript_FlinchPrevention;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GetBattlerTurnOrderNum(gEffectBattler) > gCurrentTurnActionNumber)
|
|
gBattleMons[gEffectBattler].status2 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_UPROAR:
|
|
if (!(gBattleMons[gEffectBattler].status2 & STATUS2_UPROAR))
|
|
{
|
|
|
|
gBattleMons[gEffectBattler].status2 |= STATUS2_MULTIPLETURNS;
|
|
gLockedMoves[gEffectBattler] = gCurrentMove;
|
|
gBattleMons[gEffectBattler].status2 |= STATUS2_UPROAR_TURN((Random() & 3) + 2); // 2-5 turns
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_PAYDAY:
|
|
if (GET_BATTLER_SIDE(gBattlerAttacker) == B_SIDE_PLAYER)
|
|
{
|
|
u16 PayDay = gPaydayMoney;
|
|
gPaydayMoney += (gBattleMons[gBattlerAttacker].level * 5);
|
|
if (PayDay > gPaydayMoney)
|
|
gPaydayMoney = 0xFFFF;
|
|
}
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
break;
|
|
case MOVE_EFFECT_TRI_ATTACK:
|
|
if (gBattleMons[gEffectBattler].status1)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = Random() % 3 + 3;
|
|
SetMoveEffect(FALSE, 0);
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_CHARGING:
|
|
gBattleMons[gEffectBattler].status2 |= STATUS2_MULTIPLETURNS;
|
|
gLockedMoves[gEffectBattler] = gCurrentMove;
|
|
gProtectStructs[gEffectBattler].chargingTurn = 1;
|
|
gBattlescriptCurrInstr++;
|
|
break;
|
|
case MOVE_EFFECT_WRAP:
|
|
if (gBattleMons[gEffectBattler].status2 & STATUS2_WRAPPED)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gEffectBattler].status2 |= STATUS2_WRAPPED_TURN((Random() & 3) + 3); // 3-6 turns
|
|
|
|
*(gBattleStruct->wrappedMove + gEffectBattler * 2 + 0) = gCurrentMove;
|
|
*(gBattleStruct->wrappedMove + gEffectBattler * 2 + 1) = gCurrentMove >> 8;
|
|
*(gBattleStruct->wrappedBy + gEffectBattler) = gBattlerAttacker;
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
|
|
for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; gBattleCommunication[MULTISTRING_CHOOSER]++)
|
|
{
|
|
if (gBattleCommunication[MULTISTRING_CHOOSER] > 4)
|
|
break;
|
|
if (gTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove)
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_RECOIL_25: // 25% recoil
|
|
gBattleMoveDamage = (gHpDealt) / 4;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
break;
|
|
case MOVE_EFFECT_ATK_PLUS_1:
|
|
case MOVE_EFFECT_DEF_PLUS_1:
|
|
case MOVE_EFFECT_SPD_PLUS_1:
|
|
case MOVE_EFFECT_SP_ATK_PLUS_1:
|
|
case MOVE_EFFECT_SP_DEF_PLUS_1:
|
|
case MOVE_EFFECT_ACC_PLUS_1:
|
|
case MOVE_EFFECT_EVS_PLUS_1:
|
|
if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1),
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_1 + 1,
|
|
affectsUser, 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[gEffectBattler].status2 |= STATUS2_RECHARGE;
|
|
gDisableStructs[gEffectBattler].rechargeTimer = 2;
|
|
gLockedMoves[gEffectBattler] = gCurrentMove;
|
|
gBattlescriptCurrInstr++;
|
|
break;
|
|
case MOVE_EFFECT_RAGE:
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_RAGE;
|
|
gBattlescriptCurrInstr++;
|
|
break;
|
|
case MOVE_EFFECT_STEAL_ITEM:
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL)
|
|
{
|
|
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.knockedOffMons[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: // Double Edge
|
|
gBattleMoveDamage = gHpDealt / 3;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]];
|
|
break;
|
|
case MOVE_EFFECT_THRASH:
|
|
if (gBattleMons[gEffectBattler].status2 & STATUS2_LOCK_CONFUSE)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gEffectBattler].status2 |= STATUS2_MULTIPLETURNS;
|
|
gLockedMoves[gEffectBattler] = gCurrentMove;
|
|
gBattleMons[gEffectBattler].status2 |= STATUS2_LOCK_CONFUSE_TURN((Random() & 1) + 2); // thrash for 2-3 turns
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_KNOCK_OFF:
|
|
if (gBattleMons[gEffectBattler].ability == ABILITY_STICKY_HOLD)
|
|
{
|
|
if (gBattleMons[gEffectBattler].item == 0)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
else
|
|
{
|
|
gLastUsedAbility = ABILITY_STICKY_HOLD;
|
|
gBattlescriptCurrInstr = BattleScript_StickyHoldActivates;
|
|
RecordAbilityBattle(gEffectBattler, ABILITY_STICKY_HOLD);
|
|
}
|
|
break;
|
|
}
|
|
if (gBattleMons[gEffectBattler].item)
|
|
{
|
|
side = GetBattlerSide(gEffectBattler);
|
|
|
|
gLastUsedItem = gBattleMons[gEffectBattler].item;
|
|
gBattleMons[gEffectBattler].item = 0;
|
|
gWishFutureKnock.knockedOffMons[side] |= gBitTable[gBattlerPartyIndexes[gEffectBattler]];
|
|
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_KnockedOff;
|
|
|
|
*(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBattler]) + 0) = 0;
|
|
*(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBattler]) + 1) = 0;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
break;
|
|
case MOVE_EFFECT_SP_ATK_TWO_DOWN: // Overheat
|
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
|
gBattlescriptCurrInstr = BattleScript_SAtkDown2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = 0;
|
|
}
|
|
|
|
static void Cmd_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(FALSE, MOVE_EFFECT_CERTAIN);
|
|
}
|
|
else if (Random() % 100 < percentChance
|
|
&& gBattleCommunication[MOVE_EFFECT_BYTE]
|
|
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
|
|
{
|
|
if (percentChance >= 100)
|
|
SetMoveEffect(FALSE, MOVE_EFFECT_CERTAIN);
|
|
else
|
|
SetMoveEffect(FALSE, 0);
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = 0;
|
|
gBattleScripting.multihitMoveEffect = 0;
|
|
}
|
|
|
|
static void Cmd_seteffectprimary(void)
|
|
{
|
|
SetMoveEffect(TRUE, 0);
|
|
}
|
|
|
|
static void Cmd_seteffectsecondary(void)
|
|
{
|
|
SetMoveEffect(FALSE, 0);
|
|
}
|
|
|
|
static void Cmd_clearstatusfromeffect(void)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
|
|
if (gBattleCommunication[MOVE_EFFECT_BYTE] <= PRIMARY_STATUS_MOVE_EFFECT)
|
|
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 Cmd_tryfaintmon(void)
|
|
{
|
|
const u8 *BS_ptr;
|
|
|
|
if (gBattlescriptCurrInstr[2] != 0)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
if (gHitMarker & HITMARKER_FAINTED(gActiveBattler))
|
|
{
|
|
BS_ptr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
|
|
|
|
BattleScriptPop();
|
|
gBattlescriptCurrInstr = BS_ptr;
|
|
gSideStatuses[GetBattlerSide(gActiveBattler)] &= ~(SIDE_STATUS_SPIKES_DAMAGED);
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
u8 battlerId;
|
|
|
|
if (gBattlescriptCurrInstr[1] == BS_ATTACKER)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
battlerId = gBattlerTarget;
|
|
BS_ptr = BattleScript_FaintAttacker;
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = gBattlerTarget;
|
|
battlerId = gBattlerAttacker;
|
|
BS_ptr = BattleScript_FaintTarget;
|
|
}
|
|
if (!(gAbsentBattlerFlags & gBitTable[gActiveBattler])
|
|
&& gBattleMons[gActiveBattler].hp == 0)
|
|
{
|
|
gHitMarker |= HITMARKER_FAINTED(gActiveBattler);
|
|
BattleScriptPush(gBattlescriptCurrInstr + 7);
|
|
gBattlescriptCurrInstr = BS_ptr;
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
|
|
{
|
|
gHitMarker |= HITMARKER_x400000;
|
|
if (gBattleResults.playerFaintCounter < 0xFF)
|
|
gBattleResults.playerFaintCounter++;
|
|
AdjustFriendshipOnBattleFaint(gActiveBattler);
|
|
}
|
|
else
|
|
{
|
|
if (gBattleResults.opponentFaintCounter < 0xFF)
|
|
gBattleResults.opponentFaintCounter++;
|
|
gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES, NULL);
|
|
}
|
|
if ((gHitMarker & HITMARKER_DESTINYBOND) && gBattleMons[gBattlerAttacker].hp != 0)
|
|
{
|
|
gHitMarker &= ~(HITMARKER_DESTINYBOND);
|
|
BattleScriptPush(gBattlescriptCurrInstr);
|
|
gBattleMoveDamage = gBattleMons[battlerId].hp;
|
|
gBattlescriptCurrInstr = BattleScript_DestinyBondTakesLife;
|
|
}
|
|
if ((gStatuses3[gBattlerTarget] & STATUS3_GRUDGE)
|
|
&& !(gHitMarker & HITMARKER_GRUDGE)
|
|
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)
|
|
&& gBattleMons[gBattlerAttacker].hp != 0
|
|
&& gCurrentMove != MOVE_STRUGGLE)
|
|
{
|
|
u8 moveIndex = *(gBattleStruct->chosenMovePositions + gBattlerAttacker);
|
|
|
|
gBattleMons[gBattlerAttacker].pp[moveIndex] = 0;
|
|
BattleScriptPush(gBattlescriptCurrInstr);
|
|
gBattlescriptCurrInstr = BattleScript_GrudgeTakesPp;
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitSetMonData(0, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, 1, &gBattleMons[gActiveBattler].pp[moveIndex]);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].moves[moveIndex])
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Cmd_dofaintanimation(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitFaintAnimation(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
}
|
|
|
|
static void Cmd_cleareffectsonfaint(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(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 Cmd_jumpifstatus(void)
|
|
{
|
|
u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
u32 flags = T2_READ_32(gBattlescriptCurrInstr + 2);
|
|
const u8* jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 6);
|
|
|
|
if (gBattleMons[battlerId].status1 & flags && gBattleMons[battlerId].hp)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
|
|
static void Cmd_jumpifstatus2(void)
|
|
{
|
|
u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
u32 flags = T2_READ_32(gBattlescriptCurrInstr + 2);
|
|
const u8* jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 6);
|
|
|
|
if (gBattleMons[battlerId].status2 & flags && gBattleMons[battlerId].hp)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
|
|
static void Cmd_jumpifability(void)
|
|
{
|
|
u8 battlerId;
|
|
u8 ability = gBattlescriptCurrInstr[2];
|
|
const u8* jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 3);
|
|
|
|
if (gBattlescriptCurrInstr[1] == BS_ATTACKER_SIDE)
|
|
{
|
|
battlerId = AbilityBattleEffects(ABILITYEFFECT_CHECK_BATTLER_SIDE, gBattlerAttacker, ability, 0, 0);
|
|
if (battlerId)
|
|
{
|
|
gLastUsedAbility = ability;
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
RecordAbilityBattle(battlerId - 1, gLastUsedAbility);
|
|
gBattleScripting.battlerWithAbility = battlerId - 1;
|
|
}
|
|
else
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
else if (gBattlescriptCurrInstr[1] == BS_NOT_ATTACKER_SIDE)
|
|
{
|
|
battlerId = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gBattlerAttacker, ability, 0, 0);
|
|
if (battlerId)
|
|
{
|
|
gLastUsedAbility = ability;
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
RecordAbilityBattle(battlerId - 1, gLastUsedAbility);
|
|
gBattleScripting.battlerWithAbility = battlerId - 1;
|
|
}
|
|
else
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
else
|
|
{
|
|
battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
if (gBattleMons[battlerId].ability == ability)
|
|
{
|
|
gLastUsedAbility = ability;
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
RecordAbilityBattle(battlerId, gLastUsedAbility);
|
|
gBattleScripting.battlerWithAbility = battlerId;
|
|
}
|
|
else
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
}
|
|
|
|
static void Cmd_jumpifsideaffecting(void)
|
|
{
|
|
u8 side;
|
|
u16 flags;
|
|
const u8* jumpPtr;
|
|
|
|
if (gBattlescriptCurrInstr[1] == BS_ATTACKER)
|
|
side = GET_BATTLER_SIDE(gBattlerAttacker);
|
|
else
|
|
side = GET_BATTLER_SIDE(gBattlerTarget);
|
|
|
|
flags = T2_READ_16(gBattlescriptCurrInstr + 2);
|
|
jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 4);
|
|
|
|
if (gSideStatuses[side] & flags)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 8;
|
|
}
|
|
|
|
static void Cmd_jumpifstat(void)
|
|
{
|
|
u8 ret = 0;
|
|
u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
u8 value = gBattleMons[battlerId].statStages[gBattlescriptCurrInstr[3]];
|
|
|
|
switch (gBattlescriptCurrInstr[2])
|
|
{
|
|
case CMP_EQUAL:
|
|
if (value == gBattlescriptCurrInstr[4])
|
|
ret++;
|
|
break;
|
|
case CMP_NOT_EQUAL:
|
|
if (value != gBattlescriptCurrInstr[4])
|
|
ret++;
|
|
break;
|
|
case CMP_GREATER_THAN:
|
|
if (value > gBattlescriptCurrInstr[4])
|
|
ret++;
|
|
break;
|
|
case CMP_LESS_THAN:
|
|
if (value < gBattlescriptCurrInstr[4])
|
|
ret++;
|
|
break;
|
|
case CMP_COMMON_BITS:
|
|
if (value & gBattlescriptCurrInstr[4])
|
|
ret++;
|
|
break;
|
|
case CMP_NO_COMMON_BITS:
|
|
if (!(value & gBattlescriptCurrInstr[4]))
|
|
ret++;
|
|
break;
|
|
}
|
|
|
|
if (ret)
|
|
gBattlescriptCurrInstr = T2_READ_PTR(gBattlescriptCurrInstr + 5);
|
|
else
|
|
gBattlescriptCurrInstr += 9;
|
|
}
|
|
|
|
static void Cmd_jumpifstatus3condition(void)
|
|
{
|
|
u32 flags;
|
|
const u8 *jumpPtr;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
flags = T2_READ_32(gBattlescriptCurrInstr + 2);
|
|
jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 7);
|
|
|
|
if (gBattlescriptCurrInstr[6])
|
|
{
|
|
if ((gStatuses3[gActiveBattler] & flags) != 0)
|
|
gBattlescriptCurrInstr += 11;
|
|
else
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
}
|
|
else
|
|
{
|
|
if ((gStatuses3[gActiveBattler] & flags) != 0)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 11;
|
|
}
|
|
}
|
|
|
|
static void Cmd_jumpiftype(void)
|
|
{
|
|
u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
u8 type = gBattlescriptCurrInstr[2];
|
|
const u8* jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 3);
|
|
|
|
if (IS_BATTLER_OF_TYPE(battlerId, type))
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
else
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
|
|
static void Cmd_getexp(void)
|
|
{
|
|
u16 item;
|
|
s32 i; // also used as stringId
|
|
u8 holdEffect;
|
|
s32 sentIn;
|
|
s32 viaExpShare = 0;
|
|
u16 *exp = &gBattleStruct->expValue;
|
|
|
|
gBattlerFainted = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
sentIn = gSentPokesToOpponent[(gBattlerFainted & 2) >> 1];
|
|
|
|
switch (gBattleScripting.getexpState)
|
|
{
|
|
case 0: // check if should receive exp at all
|
|
if (GetBattlerSide(gBattlerFainted) != B_SIDE_OPPONENT || (gBattleTypeFlags &
|
|
(BATTLE_TYPE_LINK
|
|
| BATTLE_TYPE_x2000000
|
|
| BATTLE_TYPE_TRAINER_HILL
|
|
| BATTLE_TYPE_FRONTIER
|
|
| BATTLE_TYPE_SAFARI
|
|
| BATTLE_TYPE_BATTLE_TOWER
|
|
| BATTLE_TYPE_EREADER_TRAINER)))
|
|
{
|
|
gBattleScripting.getexpState = 6; // goto last case
|
|
}
|
|
else
|
|
{
|
|
gBattleScripting.getexpState++;
|
|
gBattleStruct->givenExpMons |= gBitTable[gBattlerPartyIndexes[gBattlerFainted]];
|
|
}
|
|
break;
|
|
case 1: // calculate experience points to redistribute
|
|
{
|
|
u16 calculatedExp;
|
|
s32 viaSentIn;
|
|
|
|
for (viaSentIn = 0, i = 0; i < PARTY_SIZE; i++)
|
|
{
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) == SPECIES_NONE || GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0)
|
|
continue;
|
|
if (gBitTable[i] & sentIn)
|
|
viaSentIn++;
|
|
|
|
item = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
|
|
|
|
if (item == ITEM_ENIGMA_BERRY)
|
|
holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect;
|
|
else
|
|
holdEffect = ItemId_GetHoldEffect(item);
|
|
|
|
if (holdEffect == HOLD_EFFECT_EXP_SHARE)
|
|
viaExpShare++;
|
|
}
|
|
|
|
calculatedExp = gBaseStats[gBattleMons[gBattlerFainted].species].expYield * gBattleMons[gBattlerFainted].level / 7;
|
|
|
|
if (viaExpShare) // at least one mon is getting exp via exp share
|
|
{
|
|
*exp = calculatedExp / 2 / viaSentIn;
|
|
if (*exp == 0)
|
|
*exp = 1;
|
|
|
|
gExpShareExp = calculatedExp / 2 / viaExpShare;
|
|
if (gExpShareExp == 0)
|
|
gExpShareExp = 1;
|
|
}
|
|
else
|
|
{
|
|
*exp = calculatedExp / viaSentIn;
|
|
if (*exp == 0)
|
|
*exp = 1;
|
|
gExpShareExp = 0;
|
|
}
|
|
|
|
gBattleScripting.getexpState++;
|
|
gBattleStruct->expGetterMonId = 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->expGetterMonId], MON_DATA_HELD_ITEM);
|
|
|
|
if (item == ITEM_ENIGMA_BERRY)
|
|
holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect;
|
|
else
|
|
holdEffect = ItemId_GetHoldEffect(item);
|
|
|
|
if (holdEffect != HOLD_EFFECT_EXP_SHARE && !(gBattleStruct->sentInPokes & 1))
|
|
{
|
|
*(&gBattleStruct->sentInPokes) >>= 1;
|
|
gBattleScripting.getexpState = 5;
|
|
gBattleMoveDamage = 0; // used for exp
|
|
}
|
|
else if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) == MAX_LEVEL)
|
|
{
|
|
*(&gBattleStruct->sentInPokes) >>= 1;
|
|
gBattleScripting.getexpState = 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(MUS_VICTORY_WILD);
|
|
gBattleStruct->wildVictorySong++;
|
|
}
|
|
|
|
if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP))
|
|
{
|
|
if (gBattleStruct->sentInPokes & 1)
|
|
gBattleMoveDamage = *exp;
|
|
else
|
|
gBattleMoveDamage = 0;
|
|
|
|
if (holdEffect == HOLD_EFFECT_EXP_SHARE)
|
|
gBattleMoveDamage += gExpShareExp;
|
|
if (holdEffect == HOLD_EFFECT_LUCKY_EGG)
|
|
gBattleMoveDamage = (gBattleMoveDamage * 150) / 100;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
|
|
gBattleMoveDamage = (gBattleMoveDamage * 150) / 100;
|
|
|
|
if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterMonId]))
|
|
{
|
|
// check if the pokemon doesn't belong to the player
|
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gBattleStruct->expGetterMonId >= 3)
|
|
{
|
|
i = STRINGID_EMPTYSTRING4;
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = (gBattleMoveDamage * 150) / 100;
|
|
i = STRINGID_ABOOSTED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
i = STRINGID_EMPTYSTRING4;
|
|
}
|
|
|
|
// get exp getter battlerId
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
{
|
|
if (!(gBattlerPartyIndexes[2] != gBattleStruct->expGetterMonId) && !(gAbsentBattlerFlags & gBitTable[2]))
|
|
gBattleStruct->expGetterBattlerId = 2;
|
|
else
|
|
{
|
|
if (!(gAbsentBattlerFlags & gBitTable[0]))
|
|
gBattleStruct->expGetterBattlerId = 0;
|
|
else
|
|
gBattleStruct->expGetterBattlerId = 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gBattleStruct->expGetterBattlerId = 0;
|
|
}
|
|
|
|
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattleStruct->expGetterBattlerId, gBattleStruct->expGetterMonId);
|
|
// buffer 'gained' or 'gained a boosted'
|
|
PREPARE_STRING_BUFFER(gBattleTextBuff2, i);
|
|
PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff3, 5, gBattleMoveDamage);
|
|
|
|
PrepareStringBattle(STRINGID_PKMNGAINEDEXP, gBattleStruct->expGetterBattlerId);
|
|
MonGainEVs(&gPlayerParty[gBattleStruct->expGetterMonId], gBattleMons[gBattlerFainted].species);
|
|
}
|
|
gBattleStruct->sentInPokes >>= 1;
|
|
gBattleScripting.getexpState++;
|
|
}
|
|
}
|
|
break;
|
|
case 3: // Set stats and give exp
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gBattleBufferB[gBattleStruct->expGetterBattlerId][0] = 0;
|
|
if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP) && GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) != MAX_LEVEL)
|
|
{
|
|
gBattleResources->beforeLvlUp->stats[STAT_HP] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MAX_HP);
|
|
gBattleResources->beforeLvlUp->stats[STAT_ATK] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_ATK);
|
|
gBattleResources->beforeLvlUp->stats[STAT_DEF] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_DEF);
|
|
gBattleResources->beforeLvlUp->stats[STAT_SPEED] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED);
|
|
gBattleResources->beforeLvlUp->stats[STAT_SPATK] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPATK);
|
|
gBattleResources->beforeLvlUp->stats[STAT_SPDEF] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPDEF);
|
|
|
|
gActiveBattler = gBattleStruct->expGetterBattlerId;
|
|
BtlController_EmitExpUpdate(0, gBattleStruct->expGetterMonId, gBattleMoveDamage);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
gBattleScripting.getexpState++;
|
|
}
|
|
break;
|
|
case 4: // lvl up if necessary
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = gBattleStruct->expGetterBattlerId;
|
|
if (gBattleBufferB[gActiveBattler][0] == CONTROLLER_TWORETURNVALUES && gBattleBufferB[gActiveBattler][1] == RET_VALUE_LEVELED_UP)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattlerPartyIndexes[gActiveBattler] == gBattleStruct->expGetterMonId)
|
|
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
|
|
|
|
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBattler, gBattleStruct->expGetterMonId);
|
|
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 3, GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL));
|
|
|
|
BattleScriptPushCursor();
|
|
gLeveledUpInBattle |= gBitTable[gBattleStruct->expGetterMonId];
|
|
gBattlescriptCurrInstr = BattleScript_LevelUp;
|
|
gBattleMoveDamage = (gBattleBufferB[gActiveBattler][2] | (gBattleBufferB[gActiveBattler][3] << 8));
|
|
AdjustFriendship(&gPlayerParty[gBattleStruct->expGetterMonId], FRIENDSHIP_EVENT_GROW_LEVEL);
|
|
|
|
// update battle mon structure after level up
|
|
if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId && gBattleMons[0].hp)
|
|
{
|
|
gBattleMons[0].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL);
|
|
gBattleMons[0].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP);
|
|
gBattleMons[0].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MAX_HP);
|
|
gBattleMons[0].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_ATK);
|
|
gBattleMons[0].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_DEF);
|
|
// Why is this duplicated?
|
|
gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED);
|
|
gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED);
|
|
|
|
gBattleMons[0].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPATK);
|
|
gBattleMons[0].spDefense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPDEF);
|
|
}
|
|
// What is else if?
|
|
if (gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId && gBattleMons[2].hp && (gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
|
{
|
|
gBattleMons[2].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL);
|
|
gBattleMons[2].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP);
|
|
gBattleMons[2].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MAX_HP);
|
|
gBattleMons[2].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_ATK);
|
|
gBattleMons[2].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_DEF);
|
|
// Duplicated again, but this time there's no Sp Defense
|
|
gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED);
|
|
gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED);
|
|
|
|
gBattleMons[2].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPATK);
|
|
}
|
|
gBattleScripting.getexpState = 5;
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = 0;
|
|
gBattleScripting.getexpState = 5;
|
|
}
|
|
}
|
|
break;
|
|
case 5: // looper increment
|
|
if (gBattleMoveDamage) // there is exp to give, goto case 3 that gives exp
|
|
{
|
|
gBattleScripting.getexpState = 3;
|
|
}
|
|
else
|
|
{
|
|
gBattleStruct->expGetterMonId++;
|
|
if (gBattleStruct->expGetterMonId < PARTY_SIZE)
|
|
gBattleScripting.getexpState = 2; // loop again
|
|
else
|
|
gBattleScripting.getexpState = 6; // we're done
|
|
}
|
|
break;
|
|
case 6: // increment instruction
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
// not sure why gf clears the item and ability here
|
|
gBattleMons[gBattlerFainted].item = 0;
|
|
gBattleMons[gBattlerFainted].ability = 0;
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef NONMATCHING
|
|
static void Cmd_unknown_24(void)
|
|
{
|
|
u16 HP_count = 0;
|
|
s32 i;
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId == TRAINER_STEVEN_PARTNER)
|
|
{
|
|
for (i = 0; i < MULTI_PARTY_SIZE; 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 < PARTY_SIZE; i++)
|
|
{
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)
|
|
&& (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->arenaLostPlayerMons & 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 < PARTY_SIZE; i++)
|
|
{
|
|
if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES) && !GetMonData(&gEnemyParty[i], MON_DATA_IS_EGG)
|
|
&& (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->arenaLostOpponentMons & 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_FAINTED2(i) & gHitMarker && !gSpecialStatuses[i].flag40)
|
|
foundPlayer++;
|
|
}
|
|
|
|
for (foundOpponent = 0, i = 1; i < gBattlersCount; i += 2)
|
|
{
|
|
if (HITMARKER_FAINTED2(i) & gHitMarker && !gSpecialStatuses[i].flag40)
|
|
foundOpponent++;
|
|
}
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
|
{
|
|
if (foundOpponent + foundPlayer > 1)
|
|
gBattlescriptCurrInstr = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
if (foundOpponent != 0 && foundPlayer != 0)
|
|
gBattlescriptCurrInstr = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
#else
|
|
NAKED
|
|
static void Cmd_unknown_24(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 Cmd_movevaluescleanup(void)
|
|
{
|
|
MoveValuesCleanUp();
|
|
gBattlescriptCurrInstr += 1;
|
|
}
|
|
|
|
static void Cmd_setmultihit(void)
|
|
{
|
|
gMultiHitCounter = gBattlescriptCurrInstr[1];
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_decrementmultihit(void)
|
|
{
|
|
if (--gMultiHitCounter == 0)
|
|
gBattlescriptCurrInstr += 5;
|
|
else
|
|
gBattlescriptCurrInstr = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
|
|
static void Cmd_goto(void)
|
|
{
|
|
gBattlescriptCurrInstr = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
|
|
static void Cmd_jumpifbyte(void)
|
|
{
|
|
u8 caseID = gBattlescriptCurrInstr[1];
|
|
const u8* memByte = T2_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
u8 value = gBattlescriptCurrInstr[6];
|
|
const u8* jumpPtr = T2_READ_PTR(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 Cmd_jumpifhalfword(void)
|
|
{
|
|
u8 caseID = gBattlescriptCurrInstr[1];
|
|
const u16* memHword = T2_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
u16 value = T2_READ_16(gBattlescriptCurrInstr + 6);
|
|
const u8* jumpPtr = T2_READ_PTR(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 Cmd_jumpifword(void)
|
|
{
|
|
u8 caseID = gBattlescriptCurrInstr[1];
|
|
const u32* memWord = T2_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
u32 value = T1_READ_32(gBattlescriptCurrInstr + 6);
|
|
const u8* jumpPtr = T2_READ_PTR(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 Cmd_jumpifarrayequal(void)
|
|
{
|
|
const u8* mem1 = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
const u8* mem2 = T2_READ_PTR(gBattlescriptCurrInstr + 5);
|
|
u32 size = gBattlescriptCurrInstr[9];
|
|
const u8* jumpPtr = T2_READ_PTR(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 Cmd_jumpifarraynotequal(void)
|
|
{
|
|
u8 equalBytes = 0;
|
|
const u8* mem1 = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
const u8* mem2 = T2_READ_PTR(gBattlescriptCurrInstr + 5);
|
|
u32 size = gBattlescriptCurrInstr[9];
|
|
const u8* jumpPtr = T2_READ_PTR(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 Cmd_setbyte(void)
|
|
{
|
|
u8* memByte = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
*memByte = gBattlescriptCurrInstr[5];
|
|
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void Cmd_addbyte(void)
|
|
{
|
|
u8* memByte = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
*memByte += gBattlescriptCurrInstr[5];
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void Cmd_subbyte(void)
|
|
{
|
|
u8* memByte = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
*memByte -= gBattlescriptCurrInstr[5];
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void Cmd_copyarray(void)
|
|
{
|
|
u8* dest = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
const u8* src = T2_READ_PTR(gBattlescriptCurrInstr + 5);
|
|
s32 size = gBattlescriptCurrInstr[9];
|
|
|
|
s32 i;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
dest[i] = src[i];
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
|
|
static void Cmd_copyarraywithindex(void)
|
|
{
|
|
u8* dest = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
const u8* src = T2_READ_PTR(gBattlescriptCurrInstr + 5);
|
|
const u8* index = T2_READ_PTR(gBattlescriptCurrInstr + 9);
|
|
s32 size = gBattlescriptCurrInstr[13];
|
|
|
|
s32 i;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
dest[i] = src[i + *index];
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 14;
|
|
}
|
|
|
|
static void Cmd_orbyte(void)
|
|
{
|
|
u8* memByte = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
*memByte |= gBattlescriptCurrInstr[5];
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void Cmd_orhalfword(void)
|
|
{
|
|
u16* memHword = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
u16 val = T2_READ_16(gBattlescriptCurrInstr + 5);
|
|
|
|
*memHword |= val;
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
|
|
static void Cmd_orword(void)
|
|
{
|
|
u32* memWord = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
u32 val = T2_READ_32(gBattlescriptCurrInstr + 5);
|
|
|
|
*memWord |= val;
|
|
gBattlescriptCurrInstr += 9;
|
|
}
|
|
|
|
static void Cmd_bicbyte(void)
|
|
{
|
|
u8* memByte = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
*memByte &= ~(gBattlescriptCurrInstr[5]);
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void Cmd_bichalfword(void)
|
|
{
|
|
u16* memHword = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
u16 val = T2_READ_16(gBattlescriptCurrInstr + 5);
|
|
|
|
*memHword &= ~val;
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
|
|
static void Cmd_bicword(void)
|
|
{
|
|
u32* memWord = T2_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
u32 val = T2_READ_32(gBattlescriptCurrInstr + 5);
|
|
|
|
*memWord &= ~val;
|
|
gBattlescriptCurrInstr += 9;
|
|
}
|
|
|
|
static void Cmd_pause(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
u16 value = T2_READ_16(gBattlescriptCurrInstr + 1);
|
|
if (++gPauseCounterBattle >= value)
|
|
{
|
|
gPauseCounterBattle = 0;
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Cmd_waitstate(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_healthbar_update(void)
|
|
{
|
|
if (gBattlescriptCurrInstr[1] == BS_TARGET)
|
|
gActiveBattler = gBattlerTarget;
|
|
else
|
|
gActiveBattler = gBattlerAttacker;
|
|
|
|
BtlController_EmitHealthBarUpdate(0, gBattleMoveDamage);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_return(void)
|
|
{
|
|
BattleScriptPop();
|
|
}
|
|
|
|
static void Cmd_end(void)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
|
BattleArena_AddSkillPoints(gBattlerAttacker);
|
|
|
|
gMoveResultFlags = 0;
|
|
gActiveBattler = 0;
|
|
gCurrentActionFuncId = B_ACTION_TRY_FINISH;
|
|
}
|
|
|
|
static void Cmd_end2(void)
|
|
{
|
|
gActiveBattler = 0;
|
|
gCurrentActionFuncId = B_ACTION_TRY_FINISH;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_call(void)
|
|
{
|
|
BattleScriptPush(gBattlescriptCurrInstr + 5);
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
|
|
static void Cmd_jumpiftype2(void)
|
|
{
|
|
u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
|
|
if (gBattlescriptCurrInstr[2] == gBattleMons[battlerId].type1 || gBattlescriptCurrInstr[2] == gBattleMons[battlerId].type2)
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
|
|
else
|
|
gBattlescriptCurrInstr += 7;
|
|
}
|
|
|
|
static void Cmd_jumpifabilitypresent(void)
|
|
{
|
|
if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, gBattlescriptCurrInstr[1], 0, 0))
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void Cmd_endselectionscript(void)
|
|
{
|
|
*(gBattlerAttacker + gBattleStruct->selectionScriptFinished) = TRUE;
|
|
}
|
|
|
|
static void Cmd_playanimation(void)
|
|
{
|
|
const u16* argumentPtr;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
argumentPtr = T2_READ_PTR(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 Cmd_playanimation2(void) // animation Id is stored in the first pointer
|
|
{
|
|
const u16* argumentPtr;
|
|
const u8* animationIdPtr;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
animationIdPtr = T2_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
argumentPtr = T2_READ_PTR(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 Cmd_setgraphicalstatchangevalues(void)
|
|
{
|
|
u8 value = 0;
|
|
switch (GET_STAT_BUFF_VALUE2(gBattleScripting.statChanger))
|
|
{
|
|
case SET_STAT_BUFF_VALUE(1): // +1
|
|
value = STAT_ANIM_PLUS1;
|
|
break;
|
|
case SET_STAT_BUFF_VALUE(2): // +2
|
|
value = STAT_ANIM_PLUS2;
|
|
break;
|
|
case SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE: // -1
|
|
value = STAT_ANIM_MINUS1;
|
|
break;
|
|
case SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE: // -2
|
|
value = STAT_ANIM_MINUS2;
|
|
break;
|
|
}
|
|
gBattleScripting.animArg1 = GET_STAT_BUFF_ID(gBattleScripting.statChanger) + value - 1;
|
|
gBattleScripting.animArg2 = 0;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_playstatchangeanimation(void)
|
|
{
|
|
u32 currStat = 0;
|
|
u16 statAnimId = 0;
|
|
s32 changeableStatsCount = 0;
|
|
u8 statsToCheck = 0;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
statsToCheck = gBattlescriptCurrInstr[2];
|
|
|
|
if (gBattlescriptCurrInstr[3] & STAT_CHANGE_NEGATIVE) // goes down
|
|
{
|
|
s16 startingStatAnimId;
|
|
if (gBattlescriptCurrInstr[3] & STAT_CHANGE_BY_TWO)
|
|
startingStatAnimId = STAT_ANIM_MINUS2 - 1;
|
|
else
|
|
startingStatAnimId = STAT_ANIM_MINUS1 - 1;
|
|
|
|
while (statsToCheck != 0)
|
|
{
|
|
if (statsToCheck & 1)
|
|
{
|
|
if (gBattlescriptCurrInstr[3] & STAT_CHANGE_CANT_PREVENT)
|
|
{
|
|
if (gBattleMons[gActiveBattler].statStages[currStat] > MIN_STAT_STAGE)
|
|
{
|
|
statAnimId = startingStatAnimId + currStat;
|
|
changeableStatsCount++;
|
|
}
|
|
}
|
|
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_ACC)
|
|
&& !(gBattleMons[gActiveBattler].ability == ABILITY_HYPER_CUTTER && currStat == STAT_ATK))
|
|
{
|
|
if (gBattleMons[gActiveBattler].statStages[currStat] > MIN_STAT_STAGE)
|
|
{
|
|
statAnimId = startingStatAnimId + currStat;
|
|
changeableStatsCount++;
|
|
}
|
|
}
|
|
}
|
|
statsToCheck >>= 1, currStat++;
|
|
}
|
|
|
|
if (changeableStatsCount > 1) // more than one stat, so the color is gray
|
|
{
|
|
if (gBattlescriptCurrInstr[3] & STAT_CHANGE_BY_TWO)
|
|
statAnimId = STAT_ANIM_MULTIPLE_MINUS2;
|
|
else
|
|
statAnimId = STAT_ANIM_MULTIPLE_MINUS1;
|
|
}
|
|
}
|
|
else // goes up
|
|
{
|
|
s16 startingStatAnimId;
|
|
if (gBattlescriptCurrInstr[3] & STAT_CHANGE_BY_TWO)
|
|
startingStatAnimId = STAT_ANIM_PLUS2 - 1;
|
|
else
|
|
startingStatAnimId = STAT_ANIM_PLUS1 - 1;
|
|
|
|
while (statsToCheck != 0)
|
|
{
|
|
if (statsToCheck & 1 && gBattleMons[gActiveBattler].statStages[currStat] < MAX_STAT_STAGE)
|
|
{
|
|
statAnimId = startingStatAnimId + currStat;
|
|
changeableStatsCount++;
|
|
}
|
|
statsToCheck >>= 1, currStat++;
|
|
}
|
|
|
|
if (changeableStatsCount > 1) // more than one stat, so the color is gray
|
|
{
|
|
if (gBattlescriptCurrInstr[3] & STAT_CHANGE_BY_TWO)
|
|
statAnimId = STAT_ANIM_MULTIPLE_PLUS2;
|
|
else
|
|
statAnimId = STAT_ANIM_MULTIPLE_PLUS1;
|
|
}
|
|
}
|
|
|
|
if (gBattlescriptCurrInstr[3] & STAT_CHANGE_MULTIPLE_STATS && changeableStatsCount < 2)
|
|
{
|
|
gBattlescriptCurrInstr += 4;
|
|
}
|
|
else if (changeableStatsCount != 0 && !gBattleScripting.statAnimPlayed)
|
|
{
|
|
BtlController_EmitBattleAnimation(0, B_ANIM_STATS_CHANGE, statAnimId);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
if (gBattlescriptCurrInstr[3] & STAT_CHANGE_MULTIPLE_STATS && changeableStatsCount > 1)
|
|
gBattleScripting.statAnimPlayed = TRUE;
|
|
gBattlescriptCurrInstr += 4;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr += 4;
|
|
}
|
|
}
|
|
|
|
static void Cmd_moveend(void)
|
|
{
|
|
s32 i;
|
|
bool32 effect = FALSE;
|
|
u8 moveType = 0;
|
|
u8 holdEffectAtk = 0;
|
|
u16 *choicedMoveAtk = NULL;
|
|
u8 arg1, arg2;
|
|
u16 originallyUsedMove;
|
|
|
|
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.moveendState)
|
|
{
|
|
case MOVEEND_RAGE: // 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_ATK] < MAX_STAT_STAGE)
|
|
{
|
|
gBattleMons[gBattlerTarget].statStages[STAT_ATK]++;
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_RageIsBuilding;
|
|
effect = TRUE;
|
|
}
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_DEFROST: // defrosting check
|
|
if (gBattleMons[gBattlerTarget].status1 & STATUS1_FREEZE
|
|
&& gBattleMons[gBattlerTarget].hp != 0 && gBattlerAttacker != gBattlerTarget
|
|
&& gSpecialStatuses[gBattlerTarget].specialDmg
|
|
&& !(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.moveendState++;
|
|
break;
|
|
case MOVEEND_SYNCHRONIZE_TARGET: // target synchronize
|
|
if (AbilityBattleEffects(ABILITYEFFECT_SYNCHRONIZE, gBattlerTarget, 0, 0, 0))
|
|
effect = TRUE;
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_ON_DAMAGE_ABILITIES: // Contact abilities and Color Change
|
|
if (AbilityBattleEffects(ABILITYEFFECT_ON_DAMAGE, gBattlerTarget, 0, 0, 0))
|
|
effect = TRUE;
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_IMMUNITY_ABILITIES: // status immunities
|
|
if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, 0, 0, 0, 0))
|
|
effect = TRUE; // it loops through all battlers, so we increment after its done with all battlers
|
|
else
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_SYNCHRONIZE_ATTACKER: // attacker synchronize
|
|
if (AbilityBattleEffects(ABILITYEFFECT_ATK_SYNCHRONIZE, gBattlerAttacker, 0, 0, 0))
|
|
effect = TRUE;
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_CHOICE_MOVE: // update choice band move
|
|
if (gHitMarker & HITMARKER_OBEYS
|
|
&& holdEffectAtk == HOLD_EFFECT_CHOICE_BAND
|
|
&& gChosenMove != MOVE_STRUGGLE
|
|
&& (*choicedMoveAtk == 0 || *choicedMoveAtk == 0xFFFF))
|
|
{
|
|
if (gChosenMove == MOVE_BATON_PASS && !(gMoveResultFlags & MOVE_RESULT_FAILED))
|
|
{
|
|
++gBattleScripting.moveendState;
|
|
break;
|
|
}
|
|
*choicedMoveAtk = gChosenMove;
|
|
}
|
|
for (i = 0; i < MAX_MON_MOVES; ++i)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].moves[i] == *choicedMoveAtk)
|
|
break;
|
|
}
|
|
if (i == MAX_MON_MOVES)
|
|
*choicedMoveAtk = 0;
|
|
++gBattleScripting.moveendState;
|
|
break;
|
|
case MOVEEND_CHANGED_ITEMS: // changed held items
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
u16* changedItem = &gBattleStruct->changedItems[i];
|
|
if (*changedItem != 0)
|
|
{
|
|
gBattleMons[i].item = *changedItem;
|
|
*changedItem = 0;
|
|
}
|
|
}
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_ITEM_EFFECTS_ALL: // item effects for all battlers
|
|
if (ItemBattleEffects(ITEMEFFECT_MOVE_END, 0, FALSE))
|
|
effect = TRUE;
|
|
else
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_KINGSROCK_SHELLBELL: // king's rock and shell bell
|
|
if (ItemBattleEffects(ITEMEFFECT_KINGSROCK_SHELLBELL, 0, FALSE))
|
|
effect = TRUE;
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_ATTACKER_INVISIBLE: // make attacker sprite invisible
|
|
if (gStatuses3[gBattlerAttacker] & (STATUS3_SEMI_INVULNERABLE)
|
|
&& gHitMarker & HITMARKER_NO_ANIMATIONS)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitSpriteInvisibility(0, TRUE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattleScripting.moveendState++;
|
|
return;
|
|
}
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_ATTACKER_VISIBLE: // 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].restoredBattlerSprite = 1;
|
|
gBattleScripting.moveendState++;
|
|
return;
|
|
}
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_TARGET_VISIBLE: // make target sprite visible
|
|
if (!gSpecialStatuses[gBattlerTarget].restoredBattlerSprite && gBattlerTarget < gBattlersCount
|
|
&& !(gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE))
|
|
{
|
|
gActiveBattler = gBattlerTarget;
|
|
BtlController_EmitSpriteInvisibility(0, FALSE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gStatuses3[gBattlerTarget] &= ~(STATUS3_SEMI_INVULNERABLE);
|
|
gBattleScripting.moveendState++;
|
|
return;
|
|
}
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_SUBSTITUTE: // update substitute
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gDisableStructs[i].substituteHP == 0)
|
|
gBattleMons[i].status2 &= ~(STATUS2_SUBSTITUTE);
|
|
}
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_UPDATE_LAST_MOVES:
|
|
if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
gBattlerAttacker = gBattlerTarget;
|
|
gBattlerTarget = gActiveBattler;
|
|
gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET);
|
|
}
|
|
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.moveendState++;
|
|
break;
|
|
case MOVEEND_MIRROR_MOVE: // 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->lastTakenMove + gBattlerTarget * 2 + 0) = gChosenMove;
|
|
*(gBattleStruct->lastTakenMove + gBattlerTarget * 2 + 1) = gChosenMove >> 8;
|
|
|
|
target = gBattlerTarget;
|
|
attacker = gBattlerAttacker;
|
|
*(attacker * 2 + target * 8 + (u8*)(gBattleStruct->lastTakenMoveFrom) + 0) = gChosenMove;
|
|
|
|
target = gBattlerTarget;
|
|
attacker = gBattlerAttacker;
|
|
*(attacker * 2 + target * 8 + (u8*)(gBattleStruct->lastTakenMoveFrom) + 1) = gChosenMove >> 8;
|
|
}
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_NEXT_TARGET: // For moves hitting two opposing Pokemon.
|
|
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 battlerId = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget)));
|
|
if (gBattleMons[battlerId].hp != 0)
|
|
{
|
|
gBattlerTarget = battlerId;
|
|
gHitMarker |= HITMARKER_NO_ATTACKSTRING;
|
|
gBattleScripting.moveendState = 0;
|
|
MoveValuesCleanUp();
|
|
BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]);
|
|
gBattlescriptCurrInstr = BattleScript_FlushMessageBox;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
gHitMarker |= HITMARKER_NO_ATTACKSTRING;
|
|
}
|
|
}
|
|
gBattleScripting.moveendState++;
|
|
break;
|
|
case MOVEEND_COUNT:
|
|
break;
|
|
}
|
|
|
|
if (arg1 == 1 && effect == FALSE)
|
|
gBattleScripting.moveendState = MOVEEND_COUNT;
|
|
if (arg1 == 2 && arg2 == gBattleScripting.moveendState)
|
|
gBattleScripting.moveendState = MOVEEND_COUNT;
|
|
|
|
} while (gBattleScripting.moveendState != MOVEEND_COUNT && effect == FALSE);
|
|
|
|
if (gBattleScripting.moveendState == MOVEEND_COUNT && effect == FALSE)
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_returnatktoball(void)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
if (!(gHitMarker & HITMARKER_FAINTED(gActiveBattler)))
|
|
{
|
|
BtlController_EmitReturnMonToBall(0, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_getswitchedmondata(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
|
|
gBattlerPartyIndexes[gActiveBattler] = *(gBattleStruct->monToSwitchIntoId + gActiveBattler);
|
|
|
|
BtlController_EmitGetMonData(0, REQUEST_ALL_BATTLE, gBitTable[gBattlerPartyIndexes[gActiveBattler]]);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_switchindataupdate(void)
|
|
{
|
|
struct BattlePokemon oldData;
|
|
s32 i;
|
|
u8 *monData;
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(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].abilityNum);
|
|
|
|
// check knocked off item
|
|
i = GetBattlerSide(gActiveBattler);
|
|
if (gWishFutureKnock.knockedOffMons[i] & gBitTable[gBattlerPartyIndexes[gActiveBattler]])
|
|
{
|
|
gBattleMons[gActiveBattler].item = 0;
|
|
}
|
|
|
|
if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS)
|
|
{
|
|
for (i = 0; i < NUM_BATTLE_STATS; 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->palaceFlags |= gBitTable[gActiveBattler];
|
|
}
|
|
|
|
gBattleScripting.battler = gActiveBattler;
|
|
|
|
PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gActiveBattler, gBattlerPartyIndexes[gActiveBattler]);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_switchinanim(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT
|
|
&& !(gBattleTypeFlags & (BATTLE_TYPE_LINK
|
|
| BATTLE_TYPE_EREADER_TRAINER
|
|
| BATTLE_TYPE_x2000000
|
|
| BATTLE_TYPE_TRAINER_HILL
|
|
| 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)
|
|
BattleArena_InitPoints();
|
|
}
|
|
|
|
static void Cmd_jumpifcantswitch(void)
|
|
{
|
|
s32 i;
|
|
s32 lastMonId;
|
|
struct Pokemon *party;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1] & ~(SWITCH_IGNORE_ESCAPE_PREVENTION));
|
|
|
|
if (!(gBattlescriptCurrInstr[1] & SWITCH_IGNORE_ESCAPE_PREVENTION)
|
|
&& ((gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
|
|
|| (gStatuses3[gActiveBattler] & STATUS3_ROOTED)))
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(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;
|
|
|
|
i = 0;
|
|
if (gActiveBattler & 2)
|
|
i = 3;
|
|
|
|
for (lastMonId = i + 3; 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
|
|
&& gBattlerPartyIndexes[gActiveBattler] != i)
|
|
break;
|
|
}
|
|
|
|
if (i == lastMonId)
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_x800000)
|
|
{
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
|
|
{
|
|
party = gPlayerParty;
|
|
|
|
i = 0;
|
|
if (GetLinkTrainerFlankId(GetBattlerMultiplayerId(gActiveBattler)) == TRUE)
|
|
i = 3;
|
|
}
|
|
else
|
|
{
|
|
party = gEnemyParty;
|
|
|
|
if (gActiveBattler == 1)
|
|
i = 0;
|
|
else
|
|
i = 3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT)
|
|
party = gEnemyParty;
|
|
else
|
|
party = gPlayerParty;
|
|
|
|
i = 0;
|
|
if (GetLinkTrainerFlankId(GetBattlerMultiplayerId(gActiveBattler)) == TRUE)
|
|
i = 3;
|
|
}
|
|
|
|
for (lastMonId = i + 3; 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
|
|
&& gBattlerPartyIndexes[gActiveBattler] != i)
|
|
break;
|
|
}
|
|
|
|
if (i == lastMonId)
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT)
|
|
{
|
|
party = gEnemyParty;
|
|
|
|
i = 0;
|
|
if (gActiveBattler == B_POSITION_OPPONENT_RIGHT)
|
|
i = 3;
|
|
|
|
for (lastMonId = i + 3; 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
|
|
&& gBattlerPartyIndexes[gActiveBattler] != i)
|
|
break;
|
|
}
|
|
|
|
if (i == lastMonId)
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else
|
|
{
|
|
u8 battlerIn1, battlerIn2;
|
|
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT)
|
|
{
|
|
battlerIn1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
battlerIn2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
|
else
|
|
battlerIn2 = battlerIn1;
|
|
|
|
party = gEnemyParty;
|
|
}
|
|
else
|
|
{
|
|
battlerIn1 = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
battlerIn2 = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
|
else
|
|
battlerIn2 = battlerIn1;
|
|
|
|
party = gPlayerParty;
|
|
}
|
|
|
|
for (i = 0; i < PARTY_SIZE; i++)
|
|
{
|
|
if (GetMonData(&party[i], MON_DATA_HP) != 0
|
|
&& GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE
|
|
&& !GetMonData(&party[i], MON_DATA_IS_EGG)
|
|
&& i != gBattlerPartyIndexes[battlerIn1] && i != gBattlerPartyIndexes[battlerIn2])
|
|
break;
|
|
}
|
|
|
|
if (i == PARTY_SIZE)
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
}
|
|
|
|
static void sub_804CF10(u8 slotId)
|
|
{
|
|
*(gBattleStruct->field_58 + gActiveBattler) = gBattlerPartyIndexes[gActiveBattler];
|
|
*(gBattleStruct->monToSwitchIntoId + gActiveBattler) = PARTY_SIZE;
|
|
gBattleStruct->field_93 &= ~(gBitTable[gActiveBattler]);
|
|
|
|
BtlController_EmitChoosePokemon(0, PARTY_ACTION_SEND_OUT, slotId, ABILITY_NONE, gBattleStruct->field_60[gActiveBattler]);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
|
|
static void Cmd_openpartyscreen(void)
|
|
{
|
|
u32 flags;
|
|
u8 hitmarkerFaintBits;
|
|
u8 battlerId;
|
|
const u8 *jumpPtr;
|
|
|
|
battlerId = 0;
|
|
flags = 0;
|
|
jumpPtr = T1_READ_PTR(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 (HasNoMonsToSwitch(gActiveBattler, 6, 6))
|
|
{
|
|
gAbsentBattlerFlags |= gBitTable[gActiveBattler];
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
else if (!gSpecialStatuses[gActiveBattler].flag40)
|
|
{
|
|
sub_804CF10(PARTY_SIZE);
|
|
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 (HasNoMonsToSwitch(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 (HasNoMonsToSwitch(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 (HasNoMonsToSwitch(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 (HasNoMonsToSwitch(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 (HasNoMonsToSwitch(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 (HasNoMonsToSwitch(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;
|
|
|
|
gBattlerFainted = 0;
|
|
while (1)
|
|
{
|
|
if (gBitTable[gBattlerFainted] & hitmarkerFaintBits)
|
|
break;
|
|
if (gBattlerFainted >= gBattlersCount)
|
|
break;
|
|
gBattlerFainted++;
|
|
}
|
|
|
|
if (gBattlerFainted == gBattlersCount)
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
}
|
|
else
|
|
{
|
|
if (gBattlescriptCurrInstr[1] & 0x80)
|
|
hitmarkerFaintBits = PARTY_ACTION_CHOOSE_MON; // Used here as the caseId for the EmitChoose function.
|
|
else
|
|
hitmarkerFaintBits = PARTY_ACTION_SEND_OUT;
|
|
|
|
battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1] & ~(0x80));
|
|
if (gSpecialStatuses[battlerId].flag40)
|
|
{
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else if (HasNoMonsToSwitch(battlerId, 6, 6))
|
|
{
|
|
gActiveBattler = battlerId;
|
|
gAbsentBattlerFlags |= gBitTable[gActiveBattler];
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
gBattlescriptCurrInstr = jumpPtr;
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = battlerId;
|
|
*(gBattleStruct->field_58 + gActiveBattler) = gBattlerPartyIndexes[gActiveBattler];
|
|
*(gBattleStruct->monToSwitchIntoId + gActiveBattler) = 6;
|
|
gBattleStruct->field_93 &= ~(gBitTable[gActiveBattler]);
|
|
|
|
BtlController_EmitChoosePokemon(0, hitmarkerFaintBits, *(gBattleStruct->monToSwitchIntoId + (gActiveBattler ^ 2)), ABILITY_NONE, 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 != battlerId)
|
|
{
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(GetBattlerPosition(battlerId) ^ BIT_SIDE);
|
|
if (gAbsentBattlerFlags & gBitTable[gActiveBattler])
|
|
gActiveBattler ^= BIT_FLANK;
|
|
|
|
BtlController_EmitLinkStandbyMsg(0, 2, 0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Cmd_switchhandleorder(void)
|
|
{
|
|
s32 i;
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(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))
|
|
SwitchPartyOrder(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)
|
|
{
|
|
SwitchPartyOrderInGameMulti(gActiveBattler, *(gBattleStruct->monToSwitchIntoId + gActiveBattler));
|
|
}
|
|
else
|
|
{
|
|
SwitchPartyOrder(gActiveBattler);
|
|
}
|
|
|
|
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].species)
|
|
PREPARE_MON_NICK_BUFFER(gBattleTextBuff2, gActiveBattler, gBattleBufferB[gActiveBattler][1])
|
|
|
|
break;
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
|
|
static void Cmd_switchineffects(void)
|
|
{
|
|
s32 i;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
UpdateSentPokesToOpponentValue(gActiveBattler);
|
|
|
|
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
|
|
gSpecialStatuses[gActiveBattler].flag40 = 0;
|
|
|
|
if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES_DAMAGED)
|
|
&& (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES)
|
|
&& !IS_BATTLER_OF_TYPE(gActiveBattler, 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_TARGET)
|
|
gBattlescriptCurrInstr = BattleScript_SpikesOnTarget;
|
|
else if (gBattlescriptCurrInstr[1] == BS_ATTACKER)
|
|
gBattlescriptCurrInstr = BattleScript_SpikesOnAttacker;
|
|
else
|
|
gBattlescriptCurrInstr = BattleScript_SpikesOnFaintedBattler;
|
|
}
|
|
else
|
|
{
|
|
// There is a hack here to ensure the truant counter will be 0 when the battler's next turn starts.
|
|
// The truant counter is not updated in the case where a mon switches in after a lost judgement in the battle arena.
|
|
if (gBattleMons[gActiveBattler].ability == ABILITY_TRUANT && !gDisableStructs[gActiveBattler].truantSwitchInHack)
|
|
gDisableStructs[gActiveBattler].truantCounter = 1;
|
|
|
|
gDisableStructs[gActiveBattler].truantSwitchInHack = 0;
|
|
|
|
if (!AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBattler, 0, 0, 0)
|
|
&& !ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gActiveBattler, FALSE))
|
|
{
|
|
gSideStatuses[GetBattlerSide(gActiveBattler)] &= ~(SIDE_STATUS_SPIKES_DAMAGED);
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gBattlerByTurnOrder[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;
|
|
|
|
gBattlerFainted++;
|
|
while (1)
|
|
{
|
|
if (hitmarkerFaintBits & gBitTable[gBattlerFainted] && !(gAbsentBattlerFlags & gBitTable[gBattlerFainted]))
|
|
break;
|
|
if (gBattlerFainted >= gBattlersCount)
|
|
break;
|
|
gBattlerFainted++;
|
|
}
|
|
}
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Cmd_trainerslidein(void)
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitTrainerSlide(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_playse(void)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitPlaySE(0, T2_READ_16(gBattlescriptCurrInstr + 1));
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
|
|
static void Cmd_fanfare(void)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
BtlController_EmitPlayFanfareOrBGM(0, T2_READ_16(gBattlescriptCurrInstr + 1), FALSE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
|
|
static void Cmd_playfaintcry(void)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitFaintingCry(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_unknown_57(void)
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
BtlController_EmitCmd55(0, gBattleOutcome);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 1;
|
|
}
|
|
|
|
static void Cmd_returntoball(void)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitReturnMonToBall(0, 1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_handlelearnnewmove(void)
|
|
{
|
|
const u8 *jumpPtr1 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
const u8 *jumpPtr2 = T1_READ_PTR(gBattlescriptCurrInstr + 5);
|
|
|
|
u16 learnMove = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterMonId], gBattlescriptCurrInstr[9]);
|
|
while (learnMove == MON_ALREADY_KNOWS_MOVE)
|
|
learnMove = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterMonId], FALSE);
|
|
|
|
if (learnMove == 0)
|
|
{
|
|
gBattlescriptCurrInstr = jumpPtr2;
|
|
}
|
|
else if (learnMove == MON_HAS_MAX_MOVES)
|
|
{
|
|
gBattlescriptCurrInstr += 10;
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
|
|
if (gBattlerPartyIndexes[gActiveBattler] == gBattleStruct->expGetterMonId
|
|
&& !(gBattleMons[gActiveBattler].status2 & STATUS2_TRANSFORMED))
|
|
{
|
|
GiveMoveToBattleMon(&gBattleMons[gActiveBattler], learnMove);
|
|
}
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
|
if (gBattlerPartyIndexes[gActiveBattler] == gBattleStruct->expGetterMonId
|
|
&& !(gBattleMons[gActiveBattler].status2 & STATUS2_TRANSFORMED))
|
|
{
|
|
GiveMoveToBattleMon(&gBattleMons[gActiveBattler], learnMove);
|
|
}
|
|
}
|
|
|
|
gBattlescriptCurrInstr = jumpPtr1;
|
|
}
|
|
}
|
|
|
|
static void Cmd_yesnoboxlearnmove(void)
|
|
{
|
|
gActiveBattler = 0;
|
|
|
|
switch (gBattleScripting.learnMoveState)
|
|
{
|
|
case 0:
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
|
|
BattlePutTextOnWindow(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(0xFFFFFFFF, 0, 0, 0x10, RGB_BLACK);
|
|
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();
|
|
ShowSelectMovePokemonSummaryScreen(gPlayerParty, gBattleStruct->expGetterMonId, 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 = GetMoveSlotToReplace();
|
|
if (movePosition == MAX_MON_MOVES)
|
|
{
|
|
gBattleScripting.learnMoveState = 5;
|
|
}
|
|
else
|
|
{
|
|
u16 moveId = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MOVE1 + movePosition);
|
|
if (IsHMMove2(moveId))
|
|
{
|
|
PrepareStringBattle(STRINGID_HMMOVESCANTBEFORGOTTEN, gActiveBattler);
|
|
gBattleScripting.learnMoveState = 6;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff2, moveId)
|
|
|
|
RemoveMonPPBonus(&gPlayerParty[gBattleStruct->expGetterMonId], movePosition);
|
|
SetMonMoveSlot(&gPlayerParty[gBattleStruct->expGetterMonId], gMoveToLearn, movePosition);
|
|
|
|
if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId
|
|
&& !(gBattleMons[0].status2 & STATUS2_TRANSFORMED)
|
|
&& !(gDisableStructs[0].mimickedMoves & gBitTable[movePosition]))
|
|
{
|
|
RemoveBattleMonPPBonus(&gBattleMons[0], movePosition);
|
|
SetBattleMonMoveSlot(&gBattleMons[0], gMoveToLearn, movePosition);
|
|
}
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
|
&& gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId
|
|
&& !(gBattleMons[2].status2 & STATUS2_TRANSFORMED)
|
|
&& !(gDisableStructs[2].mimickedMoves & 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 Cmd_yesnoboxstoplearningmove(void)
|
|
{
|
|
switch (gBattleScripting.learnMoveState)
|
|
{
|
|
case 0:
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
|
|
BattlePutTextOnWindow(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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
|
|
HandleBattleWindow(0x18, 0x8, 0x1D, 0xD, WINDOW_CLEAR);
|
|
}
|
|
else if (gMain.newKeys & B_BUTTON)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
HandleBattleWindow(0x18, 0x8, 0x1D, 0xD, WINDOW_CLEAR);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void Cmd_hitanimation(void)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(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 == TRAINER_SECRET_BASE)
|
|
{
|
|
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 Cmd_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 Cmd_unknown_5E(void)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(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 < MAX_MON_MOVES; i++)
|
|
{
|
|
gBattleMons[gActiveBattler].moves[i] = bufferPoke->moves[i];
|
|
gBattleMons[gActiveBattler].pp[i] = bufferPoke->pp[i];
|
|
}
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void Cmd_swapattackerwithtarget(void)
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
gBattlerAttacker = gBattlerTarget;
|
|
gBattlerTarget = gActiveBattler;
|
|
|
|
if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET)
|
|
gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET);
|
|
else
|
|
gHitMarker |= HITMARKER_SWAP_ATTACKER_TARGET;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_incrementgamestat(void)
|
|
{
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
|
IncrementGameStat(gBattlescriptCurrInstr[1]);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_drawpartystatussummary(void)
|
|
{
|
|
s32 i;
|
|
struct Pokemon *party;
|
|
struct HpAndStatus hpStatuses[PARTY_SIZE];
|
|
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
|
|
party = gPlayerParty;
|
|
else
|
|
party = gEnemyParty;
|
|
|
|
for (i = 0; i < PARTY_SIZE; 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 Cmd_hidepartystatussummary(void)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitHidePartyStatusSummary(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_jumptocalledmove(void)
|
|
{
|
|
if (gBattlescriptCurrInstr[1])
|
|
gCurrentMove = gCalledMove;
|
|
else
|
|
gChosenMove = gCurrentMove = gCalledMove;
|
|
|
|
gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect];
|
|
}
|
|
|
|
static void Cmd_statusanimation(void)
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(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 Cmd_status2animation(void)
|
|
{
|
|
u32 wantedToAnimate;
|
|
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
wantedToAnimate = T1_READ_32(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 Cmd_chosenstatusanimation(void)
|
|
{
|
|
u32 wantedStatus;
|
|
|
|
if (gBattleControllerExecFlags == 0)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
wantedStatus = T1_READ_32(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 Cmd_yesnobox(void)
|
|
{
|
|
switch (gBattleCommunication[0])
|
|
{
|
|
case 0:
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
|
|
BattlePutTextOnWindow(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 Cmd_cancelallactions(void)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
gActionsByTurnOrder[i] = B_ACTION_CANCEL_PARTNER;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_adjustsetdamage(void) // The same as adjustnormaldamage, except there's no random damage multiplier.
|
|
{
|
|
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);
|
|
}
|
|
|
|
gPotentialItemEffectBattler = gBattlerTarget;
|
|
|
|
if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param)
|
|
{
|
|
RecordItemEffectBattle(gBattlerTarget, holdEffect);
|
|
gSpecialStatuses[gBattlerTarget].focusBanded = 1;
|
|
}
|
|
if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE)
|
|
&& (gBattleMoves[gCurrentMove].effect == EFFECT_FALSE_SWIPE || gProtectStructs[gBattlerTarget].endured || gSpecialStatuses[gBattlerTarget].focusBanded)
|
|
&& gBattleMons[gBattlerTarget].hp <= gBattleMoveDamage)
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - 1;
|
|
if (gProtectStructs[gBattlerTarget].endured)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_FOE_ENDURED;
|
|
}
|
|
else if (gSpecialStatuses[gBattlerTarget].focusBanded)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_FOE_HUNG_ON;
|
|
gLastUsedItem = gBattleMons[gBattlerTarget].item;
|
|
}
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_removeitem(void)
|
|
{
|
|
u16* usedHeldItem;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(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 Cmd_atknameinbuff1(void)
|
|
{
|
|
PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattlerPartyIndexes[gBattlerAttacker])
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_drawlvlupbox(void)
|
|
{
|
|
if (gBattleScripting.drawlvlupboxState == 0)
|
|
{
|
|
if (IsMonGettingExpSentOut())
|
|
gBattleScripting.drawlvlupboxState = 3;
|
|
else
|
|
gBattleScripting.drawlvlupboxState = 1;
|
|
}
|
|
|
|
switch (gBattleScripting.drawlvlupboxState)
|
|
{
|
|
case 1:
|
|
gBattle_BG2_Y = 0x60;
|
|
SetBgAttribute(2, BG_ATTR_PRIORITY, 0);
|
|
ShowBg(2);
|
|
sub_804F17C();
|
|
gBattleScripting.drawlvlupboxState = 2;
|
|
break;
|
|
case 2:
|
|
if (!sub_804F1CC())
|
|
gBattleScripting.drawlvlupboxState = 3;
|
|
break;
|
|
case 3:
|
|
gBattle_BG1_X = 0;
|
|
gBattle_BG1_Y = 0x100;
|
|
SetBgAttribute(0, BG_ATTR_PRIORITY, 1);
|
|
SetBgAttribute(1, BG_ATTR_PRIORITY, 0);
|
|
ShowBg(0);
|
|
ShowBg(1);
|
|
HandleBattleWindow(0x12, 7, 0x1D, 0x13, WINDOW_x80);
|
|
gBattleScripting.drawlvlupboxState = 4;
|
|
break;
|
|
case 4:
|
|
DrawLevelUpWindow1();
|
|
PutWindowTilemap(13);
|
|
CopyWindowToVram(13, 3);
|
|
gBattleScripting.drawlvlupboxState++;
|
|
break;
|
|
case 5:
|
|
case 7:
|
|
if (!IsDma3ManagerBusyWithBgCopy())
|
|
{
|
|
gBattle_BG1_Y = 0;
|
|
gBattleScripting.drawlvlupboxState++;
|
|
}
|
|
break;
|
|
case 6:
|
|
if (gMain.newKeys != 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
DrawLevelUpWindow2();
|
|
CopyWindowToVram(13, 2);
|
|
gBattleScripting.drawlvlupboxState++;
|
|
}
|
|
break;
|
|
case 8:
|
|
if (gMain.newKeys != 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
HandleBattleWindow(0x12, 7, 0x1D, 0x13, WINDOW_x80 | WINDOW_CLEAR);
|
|
gBattleScripting.drawlvlupboxState++;
|
|
}
|
|
break;
|
|
case 9:
|
|
if (!sub_804F344())
|
|
{
|
|
ClearWindowTilemap(14);
|
|
CopyWindowToVram(14, 1);
|
|
|
|
ClearWindowTilemap(13);
|
|
CopyWindowToVram(13, 1);
|
|
|
|
SetBgAttribute(2, BG_ATTR_PRIORITY, 2);
|
|
ShowBg(2);
|
|
|
|
gBattleScripting.drawlvlupboxState = 10;
|
|
}
|
|
break;
|
|
case 10:
|
|
if (!IsDma3ManagerBusyWithBgCopy())
|
|
{
|
|
SetBgAttribute(0, BG_ATTR_PRIORITY, 0);
|
|
SetBgAttribute(1, BG_ATTR_PRIORITY, 1);
|
|
ShowBg(0);
|
|
ShowBg(1);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void DrawLevelUpWindow1(void)
|
|
{
|
|
u16 currStats[NUM_STATS];
|
|
|
|
GetMonLevelUpWindowStats(&gPlayerParty[gBattleStruct->expGetterMonId], currStats);
|
|
DrawLevelUpWindowPg1(0xD, gBattleResources->beforeLvlUp->stats, currStats, TEXT_DYNAMIC_COLOR_5, TEXT_DYNAMIC_COLOR_4, TEXT_DYNAMIC_COLOR_6);
|
|
}
|
|
|
|
static void DrawLevelUpWindow2(void)
|
|
{
|
|
u16 currStats[NUM_STATS];
|
|
|
|
GetMonLevelUpWindowStats(&gPlayerParty[gBattleStruct->expGetterMonId], currStats);
|
|
DrawLevelUpWindowPg2(0xD, currStats, TEXT_DYNAMIC_COLOR_5, TEXT_DYNAMIC_COLOR_4, TEXT_DYNAMIC_COLOR_6);
|
|
}
|
|
|
|
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 TextPrinterTemplate printerTemplate;
|
|
u8 *txtPtr;
|
|
u32 var;
|
|
|
|
monLevel = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL);
|
|
monGender = GetMonGender(&gPlayerParty[gBattleStruct->expGetterMonId]);
|
|
GetMonNickname(&gPlayerParty[gBattleStruct->expGetterMonId], gStringVar4);
|
|
|
|
printerTemplate.currentChar = gStringVar4;
|
|
printerTemplate.windowId = 14;
|
|
printerTemplate.fontId = 0;
|
|
printerTemplate.x = 32;
|
|
printerTemplate.y = 0;
|
|
printerTemplate.currentX = 32;
|
|
printerTemplate.currentY = 0;
|
|
printerTemplate.letterSpacing = 0;
|
|
printerTemplate.lineSpacing = 0;
|
|
printerTemplate.unk = 0;
|
|
printerTemplate.fgColor = TEXT_COLOR_WHITE;
|
|
printerTemplate.bgColor = TEXT_COLOR_TRANSPARENT;
|
|
printerTemplate.shadowColor = TEXT_COLOR_DARK_GREY;
|
|
|
|
AddTextPrinter(&printerTemplate, 0xFF, NULL);
|
|
|
|
txtPtr = gStringVar4;
|
|
*(txtPtr)++ = CHAR_EXTRA_SYMBOL;
|
|
*(txtPtr)++ = CHAR_LV_2;
|
|
|
|
var = (u32)(txtPtr);
|
|
txtPtr = ConvertIntToDecimalStringN(txtPtr, monLevel, STR_CONV_MODE_LEFT_ALIGN, 3);
|
|
var = (u32)(txtPtr) - var;
|
|
txtPtr = StringFill(txtPtr, CHAR_UNK_SPACER, 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;
|
|
}
|
|
|
|
printerTemplate.y = 10;
|
|
printerTemplate.currentY = 10;
|
|
AddTextPrinter(&printerTemplate, 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->expGetterMonId], MON_DATA_SPECIES);
|
|
u32 personality = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], 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->expGetterMonId)
|
|
return TRUE;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void Cmd_resetsentmonsvalue(void)
|
|
{
|
|
ResetSentPokesToOpponentValue();
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_setatktoplayer0(void)
|
|
{
|
|
gBattlerAttacker = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_makevisible(void)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitSpriteInvisibility(0, FALSE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_recordlastability(void)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
|
|
gBattlescriptCurrInstr += 1; // UB: Should be + 2, one byte for command and one byte for battlerId argument.
|
|
}
|
|
|
|
void BufferMoveToLearnIntoBattleTextBuff2(void)
|
|
{
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff2, gMoveToLearn);
|
|
}
|
|
|
|
static void Cmd_buffermovetolearn(void)
|
|
{
|
|
BufferMoveToLearnIntoBattleTextBuff2();
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_jumpifplayerran(void)
|
|
{
|
|
if (TryRunFromBattle(gBattlerFainted))
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
|
|
static void Cmd_hpthresholds(void)
|
|
{
|
|
u8 opposingBank;
|
|
s32 result;
|
|
|
|
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(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 Cmd_hpthresholds2(void)
|
|
{
|
|
u8 opposingBank;
|
|
s32 result;
|
|
u8 hpSwitchout;
|
|
|
|
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(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 Cmd_useitemonopponent(void)
|
|
{
|
|
gBattlerInMenuId = gBattlerAttacker;
|
|
PokemonUseItemEffects(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker]], gLastUsedItem, gBattlerPartyIndexes[gBattlerAttacker], 0, 1);
|
|
gBattlescriptCurrInstr += 1;
|
|
}
|
|
|
|
static void Cmd_various(void)
|
|
{
|
|
u8 side;
|
|
s32 i;
|
|
|
|
gActiveBattler = GetBattlerForBattleScript(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 VARIOUS_GET_BATTLER_FAINTED:
|
|
if (gHitMarker & HITMARKER_FAINTED(gActiveBattler))
|
|
gBattleCommunication[0] = TRUE;
|
|
else
|
|
gBattleCommunication[0] = FALSE;
|
|
break;
|
|
case VARIOUS_RESET_INTIMIDATE_TRACE_BITS:
|
|
gSpecialStatuses[gActiveBattler].intimidatedMon = 0;
|
|
gSpecialStatuses[gActiveBattler].traced = 0;
|
|
break;
|
|
case VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP:
|
|
if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId || gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId)
|
|
{
|
|
u16 *choicedMove;
|
|
|
|
if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId)
|
|
gActiveBattler = 0;
|
|
else
|
|
gActiveBattler = 2;
|
|
|
|
choicedMove = &gBattleStruct->choicedMove[gActiveBattler];
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
if (gBattleMons[gActiveBattler].moves[i] == *choicedMove)
|
|
break;
|
|
}
|
|
if (i == MAX_MON_MOVES)
|
|
*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 VARIOUS_PALACE_FLAVOR_TEXT:
|
|
// Try and print end-of-turn Battle Palace flavor text (e.g. "A glint appears in mon's eyes")
|
|
gBattleCommunication[0] = FALSE; // whether or not msg should be printed
|
|
gBattleScripting.battler = gActiveBattler = gBattleCommunication[1];
|
|
|
|
if (!(gBattleStruct->palaceFlags & gBitTable[gActiveBattler])
|
|
&& gBattleMons[gActiveBattler].maxHP / 2 >= gBattleMons[gActiveBattler].hp
|
|
&& gBattleMons[gActiveBattler].hp != 0
|
|
&& !(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP))
|
|
{
|
|
gBattleStruct->palaceFlags |= gBitTable[gActiveBattler];
|
|
gBattleCommunication[0] = TRUE;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = sBattlePalaceNatureToFlavorTextId[GetNatureFromPersonality(gBattleMons[gActiveBattler].personality)];
|
|
}
|
|
break;
|
|
case VARIOUS_ARENA_JUDGMENT_WINDOW:
|
|
i = BattleArena_ShowJudgmentWindow(&gBattleCommunication[0]);
|
|
if (i == 0)
|
|
return;
|
|
|
|
gBattleCommunication[1] = i;
|
|
break;
|
|
case VARIOUS_ARENA_OPPONENT_MON_LOST:
|
|
gBattleMons[1].hp = 0;
|
|
gHitMarker |= HITMARKER_FAINTED(1);
|
|
gBattleStruct->arenaLostOpponentMons |= gBitTable[gBattlerPartyIndexes[1]];
|
|
gDisableStructs[1].truantSwitchInHack = 1;
|
|
break;
|
|
case VARIOUS_ARENA_PLAYER_MON_LOST:
|
|
gBattleMons[0].hp = 0;
|
|
gHitMarker |= HITMARKER_FAINTED(0);
|
|
gHitMarker |= HITMARKER_x400000;
|
|
gBattleStruct->arenaLostPlayerMons |= gBitTable[gBattlerPartyIndexes[0]];
|
|
gDisableStructs[0].truantSwitchInHack = 1;
|
|
break;
|
|
case VARIOUS_ARENA_BOTH_MONS_LOST:
|
|
gBattleMons[0].hp = 0;
|
|
gBattleMons[1].hp = 0;
|
|
gHitMarker |= HITMARKER_FAINTED(0);
|
|
gHitMarker |= HITMARKER_FAINTED(1);
|
|
gHitMarker |= HITMARKER_x400000;
|
|
gBattleStruct->arenaLostPlayerMons |= gBitTable[gBattlerPartyIndexes[0]];
|
|
gBattleStruct->arenaLostOpponentMons |= gBitTable[gBattlerPartyIndexes[1]];
|
|
gDisableStructs[0].truantSwitchInHack = 1;
|
|
gDisableStructs[1].truantSwitchInHack = 1;
|
|
break;
|
|
case VARIOUS_EMIT_YESNOBOX:
|
|
BtlController_EmitUnknownYesNoBox(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
break;
|
|
case 14:
|
|
DrawArenaRefereeTextBox();
|
|
break;
|
|
case 15:
|
|
RemoveArenaRefereeTextBox();
|
|
break;
|
|
case VARIOUS_ARENA_JUDGMENT_STRING:
|
|
BattleStringExpandPlaceholdersToDisplayedString(gRefereeStringsTable[gBattlescriptCurrInstr[1]]);
|
|
BattlePutTextOnWindow(gDisplayedStringBattle, 0x16);
|
|
break;
|
|
case VARIOUS_ARENA_WAIT_STRING:
|
|
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 VARIOUS_VOLUME_DOWN:
|
|
m4aMPlayVolumeControl(&gMPlayInfo_BGM, 0xFFFF, 0x55);
|
|
break;
|
|
case VARIOUS_VOLUME_UP:
|
|
m4aMPlayVolumeControl(&gMPlayInfo_BGM, 0xFFFF, 0x100);
|
|
break;
|
|
case VARIOUS_SET_ALREADY_STATUS_MOVE_ATTEMPT:
|
|
gBattleStruct->alreadyStatusedMoveAttempt |= 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_MON_TELEPORTED;
|
|
break;
|
|
case VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC:
|
|
BtlController_EmitPlayFanfareOrBGM(0, MUS_VICTORY_TRAINER, TRUE);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
break;
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 3;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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 Cmd_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 Cmd_jumpifnexttargetvalid(void)
|
|
{
|
|
const u8 *jumpPtr = T1_READ_PTR(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 Cmd_tryhealhalfhealth(void)
|
|
{
|
|
const u8* failPtr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
|
|
if (gBattlescriptCurrInstr[5] == BS_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 Cmd_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->lastTakenMoveFrom) + 0)
|
|
| (*(i * 2 + gBattlerAttacker * 8 + (u8*)(gBattleStruct->lastTakenMoveFrom) + 1) << 8);
|
|
|
|
if (move != 0 && move != 0xFFFF)
|
|
{
|
|
movesArray[validMovesCount] = move;
|
|
validMovesCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
move = *(gBattleStruct->lastTakenMove + gBattlerAttacker * 2 + 0)
|
|
| (*(gBattleStruct->lastTakenMove + 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].ppNotAffectedByPressure = 1;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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)].reflectBattlerId = gBattlerAttacker;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_setseeded(void)
|
|
{
|
|
if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT || gStatuses3[gBattlerTarget] & STATUS3_LEECHSEED)
|
|
{
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else if (IS_BATTLER_OF_TYPE(gBattlerTarget, 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 Cmd_manipulatedamage(void)
|
|
{
|
|
switch (gBattlescriptCurrInstr[1])
|
|
{
|
|
case DMG_CHANGE_SIGN:
|
|
gBattleMoveDamage *= -1;
|
|
break;
|
|
case DMG_RECOIL_FROM_MISS:
|
|
gBattleMoveDamage /= 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
if ((gBattleMons[gBattlerTarget].maxHP / 2) < gBattleMoveDamage)
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2;
|
|
break;
|
|
case DMG_DOUBLED:
|
|
gBattleMoveDamage *= 2;
|
|
break;
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|
|
|
|
static void Cmd_trysetrest(void)
|
|
{
|
|
const u8 *failJump = T1_READ_PTR(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 Cmd_jumpifnotfirstturn(void)
|
|
{
|
|
const u8* failJump = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
|
|
if (gDisableStructs[gBattlerAttacker].isFirstTurn)
|
|
gBattlescriptCurrInstr += 5;
|
|
else
|
|
gBattlescriptCurrInstr = failJump;
|
|
}
|
|
|
|
static void Cmd_nop(void)
|
|
{
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
bool8 UproarWakeUpCheck(u8 battlerId)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || gBattleMons[battlerId].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 Cmd_jumpifcantmakeasleep(void)
|
|
{
|
|
const u8 *jumpPtr = T1_READ_PTR(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 Cmd_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 Cmd_stockpiletobasedamage(void)
|
|
{
|
|
const u8* jumpPtr = T1_READ_PTR(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 Cmd_stockpiletohpheal(void)
|
|
{
|
|
const u8* jumpPtr = T1_READ_PTR(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 Cmd_negativedamage(void)
|
|
{
|
|
gBattleMoveDamage = -(gHpDealt / 2);
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = -1;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
#define STAT_BUFF_WORKED 0
|
|
#define STAT_BUFF_DIDNT_WORK 1
|
|
|
|
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_BUFF_NOT_PROTECT_AFFECTED)
|
|
notProtectAffected++;
|
|
flags &= ~(STAT_BUFF_NOT_PROTECT_AFFECTED);
|
|
|
|
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId)
|
|
|
|
if (statValue <= -1) // Stat decrease.
|
|
{
|
|
if (gSideTimers[GET_BATTLER_SIDE(gActiveBattler)].mistTimer
|
|
&& !certain && gCurrentMove != MOVE_CURSE)
|
|
{
|
|
if (flags == STAT_BUFF_ALLOW_PTR)
|
|
{
|
|
if (gSpecialStatuses[gActiveBattler].statLowered)
|
|
{
|
|
gBattlescriptCurrInstr = BS_ptr;
|
|
}
|
|
else
|
|
{
|
|
BattleScriptPush(BS_ptr);
|
|
gBattleScripting.battler = gActiveBattler;
|
|
gBattlescriptCurrInstr = BattleScript_MistProtected;
|
|
gSpecialStatuses[gActiveBattler].statLowered = 1;
|
|
}
|
|
}
|
|
return STAT_BUFF_DIDNT_WORK;
|
|
}
|
|
else if (gCurrentMove != MOVE_CURSE
|
|
&& notProtectAffected != TRUE && JumpIfMoveAffectedByProtect(0))
|
|
{
|
|
gBattlescriptCurrInstr = BattleScript_ButItFailed;
|
|
return STAT_BUFF_DIDNT_WORK;
|
|
}
|
|
else if ((gBattleMons[gActiveBattler].ability == ABILITY_CLEAR_BODY
|
|
|| gBattleMons[gActiveBattler].ability == ABILITY_WHITE_SMOKE)
|
|
&& !certain && gCurrentMove != MOVE_CURSE)
|
|
{
|
|
if (flags == STAT_BUFF_ALLOW_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_BUFF_DIDNT_WORK;
|
|
}
|
|
else if (gBattleMons[gActiveBattler].ability == ABILITY_KEEN_EYE
|
|
&& !certain && statId == STAT_ACC)
|
|
{
|
|
if (flags == STAT_BUFF_ALLOW_PTR)
|
|
{
|
|
BattleScriptPush(BS_ptr);
|
|
gBattleScripting.battler = gActiveBattler;
|
|
gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss;
|
|
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
|
|
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
|
|
}
|
|
return STAT_BUFF_DIDNT_WORK;
|
|
}
|
|
else if (gBattleMons[gActiveBattler].ability == ABILITY_HYPER_CUTTER
|
|
&& !certain && statId == STAT_ATK)
|
|
{
|
|
if (flags == STAT_BUFF_ALLOW_PTR)
|
|
{
|
|
BattleScriptPush(BS_ptr);
|
|
gBattleScripting.battler = gActiveBattler;
|
|
gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss;
|
|
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
|
|
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
|
|
}
|
|
return STAT_BUFF_DIDNT_WORK;
|
|
}
|
|
else if (gBattleMons[gActiveBattler].ability == ABILITY_SHIELD_DUST && flags == 0)
|
|
{
|
|
return STAT_BUFF_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] == MIN_STAT_STAGE)
|
|
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] == MAX_STAT_STAGE)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler);
|
|
}
|
|
|
|
gBattleMons[gActiveBattler].statStages[statId] += statValue;
|
|
if (gBattleMons[gActiveBattler].statStages[statId] < MIN_STAT_STAGE)
|
|
gBattleMons[gActiveBattler].statStages[statId] = MIN_STAT_STAGE;
|
|
if (gBattleMons[gActiveBattler].statStages[statId] > MAX_STAT_STAGE)
|
|
gBattleMons[gActiveBattler].statStages[statId] = MAX_STAT_STAGE;
|
|
|
|
if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && flags & STAT_BUFF_ALLOW_PTR)
|
|
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
|
|
|
if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && !(flags & STAT_BUFF_ALLOW_PTR))
|
|
return STAT_BUFF_DIDNT_WORK;
|
|
|
|
return STAT_BUFF_WORKED;
|
|
}
|
|
|
|
static void Cmd_statbuffchange(void)
|
|
{
|
|
const u8* jumpPtr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
if (ChangeStatBuffs(gBattleScripting.statChanger & 0xF0, GET_STAT_BUFF_ID(gBattleScripting.statChanger), gBattlescriptCurrInstr[1], jumpPtr) == STAT_BUFF_WORKED)
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void Cmd_normalisebuffs(void) // haze
|
|
{
|
|
s32 i, j;
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
for (j = 0; j < NUM_BATTLE_STATS; j++)
|
|
gBattleMons[i].statStages[j] = DEFAULT_STAT_STAGE;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_setbide(void)
|
|
{
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_MULTIPLETURNS;
|
|
gLockedMoves[gBattlerAttacker] = gCurrentMove;
|
|
gTakenDmg[gBattlerAttacker] = 0;
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_BIDE_TURN(2);
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_confuseifrepeatingattackends(void)
|
|
{
|
|
if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE))
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = (MOVE_EFFECT_THRASH | MOVE_EFFECT_AFFECTS_USER);
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
return FALSE;
|
|
}
|
|
*(gBattleStruct->field_58 + gBattlerTarget) = gBattlerPartyIndexes[gBattlerTarget];
|
|
}
|
|
|
|
gBattlescriptCurrInstr = BattleScript_SuccessForceOut;
|
|
return TRUE;
|
|
}
|
|
|
|
static void Cmd_forcerandomswitch(void)
|
|
{
|
|
s32 i;
|
|
s32 battler1PartyId = 0;
|
|
s32 battler2PartyId = 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;
|
|
battler2PartyId = gBattlerPartyIndexes[gBattlerTarget];
|
|
battler1PartyId = gBattlerPartyIndexes[gBattlerTarget ^ BIT_FLANK];
|
|
}
|
|
else if ((gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK)
|
|
|| (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_x2000000))
|
|
{
|
|
if (GetLinkTrainerFlankId(GetBattlerMultiplayerId(gBattlerTarget)) == 1)
|
|
{
|
|
firstMonId = 3;
|
|
lastMonId = 6;
|
|
}
|
|
else
|
|
{
|
|
firstMonId = 0;
|
|
lastMonId = 3;
|
|
}
|
|
monsCount = 3;
|
|
minNeeded = 1;
|
|
battler2PartyId = gBattlerPartyIndexes[gBattlerTarget];
|
|
battler1PartyId = 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;
|
|
}
|
|
battler2PartyId = gBattlerPartyIndexes[gBattlerTarget];
|
|
battler1PartyId = gBattlerPartyIndexes[gBattlerTarget ^ BIT_FLANK];
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
{
|
|
firstMonId = 0;
|
|
lastMonId = 6;
|
|
monsCount = 6;
|
|
minNeeded = 2;
|
|
battler2PartyId = gBattlerPartyIndexes[gBattlerTarget];
|
|
battler1PartyId = gBattlerPartyIndexes[gBattlerTarget ^ BIT_FLANK];
|
|
}
|
|
else
|
|
{
|
|
firstMonId = 0;
|
|
lastMonId = 6;
|
|
monsCount = 6;
|
|
minNeeded = 1;
|
|
battler2PartyId = gBattlerPartyIndexes[gBattlerTarget]; // there is only one pokemon out in single battles
|
|
battler1PartyId = 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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
if (TryDoForceSwitchOut())
|
|
{
|
|
do
|
|
{
|
|
i = Random() % monsCount;
|
|
i += firstMonId;
|
|
}
|
|
while (i == battler2PartyId
|
|
|| i == battler1PartyId
|
|
|| 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 (!IsMultiBattle())
|
|
SwitchPartyOrder(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))
|
|
{
|
|
SwitchPartyOrderLinkMulti(gBattlerTarget, i, 0);
|
|
SwitchPartyOrderLinkMulti(gBattlerTarget ^ BIT_FLANK, i, 1);
|
|
}
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
|
SwitchPartyOrderInGameMulti(gBattlerTarget, i);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TryDoForceSwitchOut();
|
|
}
|
|
}
|
|
|
|
static void Cmd_tryconversiontypechange(void) // randomly changes user's type to one of its moves' type
|
|
{
|
|
u8 validMoves = 0;
|
|
u8 moveChecked;
|
|
u8 moveType;
|
|
|
|
while (validMoves < MAX_MON_MOVES)
|
|
{
|
|
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 (IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST))
|
|
moveType = TYPE_GHOST;
|
|
else
|
|
moveType = TYPE_NORMAL;
|
|
}
|
|
if (moveType != gBattleMons[gBattlerAttacker].type1
|
|
&& moveType != gBattleMons[gBattlerAttacker].type2)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (moveChecked == validMoves)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
|
|
while ((moveChecked = Random() & 3) >= validMoves);
|
|
|
|
moveType = gBattleMoves[gBattleMons[gBattlerAttacker].moves[moveChecked]].type;
|
|
|
|
if (moveType == TYPE_MYSTERY)
|
|
{
|
|
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST))
|
|
moveType = TYPE_GHOST;
|
|
else
|
|
moveType = TYPE_NORMAL;
|
|
}
|
|
}
|
|
while (moveType == gBattleMons[gBattlerAttacker].type1 || moveType == gBattleMons[gBattlerAttacker].type2);
|
|
|
|
SET_BATTLER_TYPE(gBattlerAttacker, moveType);
|
|
PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType);
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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)].lightscreenBattlerId = gBattlerAttacker;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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);
|
|
}
|
|
|
|
gPotentialItemEffectBattler = 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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Cmd_damagetohalftargethp(void) // super fang
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp / 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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_ANY)
|
|
{
|
|
if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, 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 Cmd_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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gBattlerTarget].status2 |= STATUS2_INFATUATED_WITH(gBattlerAttacker);
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Cmd_updatestatusicon(void)
|
|
{
|
|
if (gBattleControllerExecFlags)
|
|
return;
|
|
|
|
if (gBattlescriptCurrInstr[1] != BS_ATTACKER_WITH_PARTNER)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(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 Cmd_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)].mistBattlerId = gBattlerAttacker;
|
|
gSideStatuses[GET_BATTLER_SIDE(gBattlerAttacker)] |= SIDE_STATUS_MIST;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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].disableTimer = 0;
|
|
gDisableStructs[gBattlerAttacker].transformedMonPersonality = gBattleMons[gBattlerTarget].personality;
|
|
gDisableStructs[gBattlerAttacker].mimickedMoves = 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 < MAX_MON_MOVES; 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 Cmd_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 Cmd_mimicattackcopy(void)
|
|
{
|
|
gChosenMove = 0xFFFF;
|
|
|
|
if (IsMoveUncopyableByMimic(gLastMoves[gBattlerTarget])
|
|
|| gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED
|
|
|| gLastMoves[gBattlerTarget] == 0
|
|
|| gLastMoves[gBattlerTarget] == 0xFFFF)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].moves[i] == gLastMoves[gBattlerTarget])
|
|
break;
|
|
}
|
|
|
|
if (i == MAX_MON_MOVES)
|
|
{
|
|
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].mimickedMoves |= gBitTable[gCurrMovePos];
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Cmd_metronome(void)
|
|
{
|
|
while (1)
|
|
{
|
|
s32 i;
|
|
|
|
gCurrentMove = (Random() & 0x1FF) + 1;
|
|
if (gCurrentMove >= MOVES_COUNT)
|
|
continue;
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; 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 Cmd_dmgtolevel(void)
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].level;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_psywavedamageeffect(void)
|
|
{
|
|
s32 randDamage;
|
|
|
|
while ((randDamage = (Random() & 0xF)) > 10);
|
|
|
|
randDamage *= 10;
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].level * (randDamage + 50) / 100;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_counterdamagecalculator(void)
|
|
{
|
|
u8 sideAttacker = GetBattlerSide(gBattlerAttacker);
|
|
u8 sideTarget = GetBattlerSide(gProtectStructs[gBattlerAttacker].physicalBattlerId);
|
|
|
|
if (gProtectStructs[gBattlerAttacker].physicalDmg
|
|
&& sideAttacker != sideTarget
|
|
&& gBattleMons[gProtectStructs[gBattlerAttacker].physicalBattlerId].hp)
|
|
{
|
|
gBattleMoveDamage = gProtectStructs[gBattlerAttacker].physicalDmg * 2;
|
|
|
|
if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp)
|
|
gBattlerTarget = gSideTimers[sideTarget].followmeTarget;
|
|
else
|
|
gBattlerTarget = gProtectStructs[gBattlerAttacker].physicalBattlerId;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gSpecialStatuses[gBattlerAttacker].ppNotAffectedByPressure = 1;
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_mirrorcoatdamagecalculator(void) // a copy of Cmd with the physical -> special field changes
|
|
{
|
|
u8 sideAttacker = GetBattlerSide(gBattlerAttacker);
|
|
u8 sideTarget = GetBattlerSide(gProtectStructs[gBattlerAttacker].specialBattlerId);
|
|
|
|
if (gProtectStructs[gBattlerAttacker].specialDmg && sideAttacker != sideTarget && gBattleMons[gProtectStructs[gBattlerAttacker].specialBattlerId].hp)
|
|
{
|
|
gBattleMoveDamage = gProtectStructs[gBattlerAttacker].specialDmg * 2;
|
|
|
|
if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp)
|
|
gBattlerTarget = gSideTimers[sideTarget].followmeTarget;
|
|
else
|
|
gBattlerTarget = gProtectStructs[gBattlerAttacker].specialBattlerId;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gSpecialStatuses[gBattlerAttacker].ppNotAffectedByPressure = 1;
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_disablelastusedattack(void)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].moves[i] == gLastMoves[gBattlerTarget])
|
|
break;
|
|
}
|
|
if (gDisableStructs[gBattlerTarget].disabledMove == 0
|
|
&& i != MAX_MON_MOVES && gBattleMons[gBattlerTarget].pp[i] != 0)
|
|
{
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerTarget].moves[i])
|
|
|
|
gDisableStructs[gBattlerTarget].disabledMove = gBattleMons[gBattlerTarget].moves[i];
|
|
gDisableStructs[gBattlerTarget].disableTimer = (Random() & 3) + 2;
|
|
gDisableStructs[gBattlerTarget].disableTimerStartValue = gDisableStructs[gBattlerTarget].disableTimer; // used to save the random amount of turns?
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_trysetencore(void)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; 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].encoreTimer = (Random() & 3) + 3;
|
|
gDisableStructs[gBattlerTarget].encoreTimerStartValue = gDisableStructs[gBattlerTarget].encoreTimer;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_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].dmg = 0xFFFF;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_settypetorandomresistance(void) // conversion 2
|
|
{
|
|
if (gLastLandedMoves[gBattlerAttacker] == 0
|
|
|| gLastLandedMoves[gBattlerAttacker] == 0xFFFF)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else if (IsTwoTurnsMove(gLastLandedMoves[gBattlerAttacker])
|
|
&& gBattleMons[gLastHitBy[gBattlerAttacker]].status2 & STATUS2_MULTIPLETURNS)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(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
|
|
&& !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_EFFECT_DEF_TYPE(i)))
|
|
{
|
|
SET_BATTLER_TYPE(gBattlerAttacker, 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
|
|
&& !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_EFFECT_DEF_TYPE(i)))
|
|
{
|
|
SET_BATTLER_TYPE(gBattlerAttacker, TYPE_EFFECT_DEF_TYPE(rands));
|
|
PREPARE_TYPE_BUFFER(gBattleTextBuff1, TYPE_EFFECT_DEF_TYPE(rands))
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_setalwayshitflag(void)
|
|
{
|
|
gStatuses3[gBattlerTarget] &= ~(STATUS3_ALWAYS_HITS);
|
|
gStatuses3[gBattlerTarget] |= STATUS3_ALWAYS_HITS_TURN(2);
|
|
gDisableStructs[gBattlerTarget].battlerWithSureHit = gBattlerAttacker;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 < MAX_MON_MOVES; i++)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].moves[i] == MOVE_SKETCH)
|
|
continue;
|
|
if (gBattleMons[gBattlerAttacker].moves[i] == gLastPrintedMoves[gBattlerTarget])
|
|
break;
|
|
}
|
|
|
|
if (i != MAX_MON_MOVES)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(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 < MAX_MON_MOVES; 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 = T1_READ_PTR(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 battlerId, 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_CHARGING))
|
|
return 1;
|
|
}
|
|
return 2;
|
|
}
|
|
|
|
static void Cmd_trychoosesleeptalkmove(void)
|
|
{
|
|
s32 i;
|
|
u8 unusableMovesBits = 0;
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; 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));
|
|
|
|
gCalledMove = gBattleMons[gBattlerAttacker].moves[movePosition];
|
|
gCurrMovePos = movePosition;
|
|
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
|
|
gBattlerTarget = GetMoveTarget(gCalledMove, 0);
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 Cmd_trysetdestinybondtohappen(void)
|
|
{
|
|
TrySetDestinyBondToHappen();
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_tryspiteppreduce(void)
|
|
{
|
|
if (gLastMoves[gBattlerTarget] != 0
|
|
&& gLastMoves[gBattlerTarget] != 0xFFFF)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
if (gLastMoves[gBattlerTarget] == gBattleMons[gBattlerTarget].moves[i])
|
|
break;
|
|
}
|
|
|
|
if (i != MAX_MON_MOVES && 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, STR_CONV_MODE_LEFT_ALIGN, 1);
|
|
|
|
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct)
|
|
|
|
gBattleMons[gBattlerTarget].pp[i] -= ppToDeduct;
|
|
gActiveBattler = gBattlerTarget;
|
|
|
|
if (!(gDisableStructs[gActiveBattler].mimickedMoves & 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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 < PARTY_SIZE; i++)
|
|
{
|
|
u16 species = GetMonData(&party[i], MON_DATA_SPECIES2);
|
|
u8 abilityNum = GetMonData(&party[i], MON_DATA_ABILITY_NUM);
|
|
|
|
if (species != SPECIES_NONE && 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, abilityNum);
|
|
|
|
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 Cmd_cursetarget(void)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_CURSED)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gBattlerTarget].status2 |= STATUS2_CURSED;
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_trysetspikes(void)
|
|
{
|
|
u8 targetSide = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
|
|
|
|
if (gSideTimers[targetSide].spikesAmount == 3)
|
|
{
|
|
gSpecialStatuses[gBattlerAttacker].ppNotAffectedByPressure = 1;
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gSideStatuses[targetSide] |= SIDE_STATUS_SPIKES;
|
|
gSideTimers[targetSide].spikesAmount++;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_setforesight(void)
|
|
{
|
|
gBattleMons[gBattlerTarget].status2 |= STATUS2_FORESIGHT;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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].perishSongTimer = 3;
|
|
gDisableStructs[i].perishSongTimerStartValue = 3;
|
|
}
|
|
}
|
|
|
|
PressurePPLoseOnUsingPerishSong(gBattlerAttacker);
|
|
|
|
if (notAffectedCount == gBattlersCount)
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
|
|
static void Cmd_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].rolloutTimer = 5;
|
|
gDisableStructs[gBattlerAttacker].rolloutTimerStartValue = 5;
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_MULTIPLETURNS;
|
|
gLockedMoves[gBattlerAttacker] = gCurrentMove;
|
|
}
|
|
if (--gDisableStructs[gBattlerAttacker].rolloutTimer == 0) // last hit
|
|
{
|
|
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_MULTIPLETURNS);
|
|
}
|
|
|
|
gDynamicBasePower = gBattleMoves[gCurrentMove].power;
|
|
|
|
for (i = 1; i < (5 - gDisableStructs[gBattlerAttacker].rolloutTimer); i++)
|
|
gDynamicBasePower *= 2;
|
|
|
|
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_DEFENSE_CURL)
|
|
gDynamicBasePower *= 2;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
}
|
|
|
|
static void Cmd_jumpifconfusedandstatmaxed(void)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_CONFUSION
|
|
&& gBattleMons[gBattlerTarget].statStages[gBattlescriptCurrInstr[1]] == MAX_STAT_STAGE)
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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 Cmd_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 Cmd_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)].safeguardBattlerId = gBattlerAttacker;
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 5;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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 (gBattlerByTurnOrder[i] == gBattlerTarget)
|
|
gActionsByTurnOrder[i] = B_ACTION_TRY_FINISH;
|
|
}
|
|
|
|
gCurrentMove = MOVE_PURSUIT;
|
|
gCurrMovePos = gChosenMovePos = *(gBattleStruct->chosenMovePositions + gBattlerTarget);
|
|
gBattlescriptCurrInstr += 5;
|
|
gBattleScripting.animTurn = 1;
|
|
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 Cmd_maxattackhalvehp(void) // belly drum
|
|
{
|
|
u32 halfHp = gBattleMons[gBattlerAttacker].maxHP / 2;
|
|
|
|
if (!(gBattleMons[gBattlerAttacker].maxHP / 2))
|
|
halfHp = 1;
|
|
|
|
if (gBattleMons[gBattlerAttacker].statStages[STAT_ATK] < MAX_STAT_STAGE
|
|
&& gBattleMons[gBattlerAttacker].hp > halfHp)
|
|
{
|
|
gBattleMons[gBattlerAttacker].statStages[STAT_ATK] = MAX_STAT_STAGE;
|
|
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_copyfoestats(void) // psych up
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < NUM_BATTLE_STATS; i++)
|
|
{
|
|
gBattleMons[gBattlerAttacker].statStages[i] = gBattleMons[gBattlerTarget].statStages[i];
|
|
}
|
|
|
|
gBattlescriptCurrInstr += 5; // Has an unused jump ptr(possibly for a failed attempt) parameter.
|
|
}
|
|
|
|
static void Cmd_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_BATTLER);
|
|
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 Cmd_setdefensecurlbit(void)
|
|
{
|
|
gBattleMons[gBattlerAttacker].status2 |= STATUS2_DEFENSE_CURL;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_hiddenpowercalc(void)
|
|
{
|
|
u8 powerBits;
|
|
u8 typeBits;
|
|
|
|
powerBits = ((gBattleMons[gBattlerAttacker].hpIV & 2) >> 1)
|
|
| ((gBattleMons[gBattlerAttacker].attackIV & 2) << 0)
|
|
| ((gBattleMons[gBattlerAttacker].defenseIV & 2) << 1)
|
|
| ((gBattleMons[gBattlerAttacker].speedIV & 2) << 2)
|
|
| ((gBattleMons[gBattlerAttacker].spAttackIV & 2) << 3)
|
|
| ((gBattleMons[gBattlerAttacker].spDefenseIV & 2) << 4);
|
|
|
|
typeBits = ((gBattleMons[gBattlerAttacker].hpIV & 1) << 0)
|
|
| ((gBattleMons[gBattlerAttacker].attackIV & 1) << 1)
|
|
| ((gBattleMons[gBattlerAttacker].defenseIV & 1) << 2)
|
|
| ((gBattleMons[gBattlerAttacker].speedIV & 1) << 3)
|
|
| ((gBattleMons[gBattlerAttacker].spAttackIV & 1) << 4)
|
|
| ((gBattleMons[gBattlerAttacker].spDefenseIV & 1) << 5);
|
|
|
|
gDynamicBasePower = (40 * powerBits) / 63 + 30;
|
|
|
|
gBattleStruct->dynamicMoveType = (15 * typeBits) / 63 + 1;
|
|
if (gBattleStruct->dynamicMoveType >= TYPE_MYSTERY)
|
|
gBattleStruct->dynamicMoveType++;
|
|
gBattleStruct->dynamicMoveType |= 0xC0;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_selectfirstvalidtarget(void)
|
|
{
|
|
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
|
|
{
|
|
if (gBattlerTarget == gBattlerAttacker)
|
|
continue;
|
|
if (!(gAbsentBattlerFlags & gBitTable[gBattlerTarget]))
|
|
break;
|
|
}
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_trysetfutureattack(void)
|
|
{
|
|
if (gWishFutureKnock.futureSightCounter[gBattlerTarget] != 0)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(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 Cmd_trydobeatup(void)
|
|
{
|
|
struct Pokemon *party;
|
|
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
|
party = gPlayerParty;
|
|
else
|
|
party = gEnemyParty;
|
|
|
|
if (gBattleMons[gBattlerTarget].hp == 0)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
u8 beforeLoop = gBattleCommunication[0];
|
|
for (;gBattleCommunication[0] < PARTY_SIZE; 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] < PARTY_SIZE)
|
|
{
|
|
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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 5);
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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 Cmd_setminimize(void)
|
|
{
|
|
if (gHitMarker & HITMARKER_OBEYS)
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_MINIMIZED;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_jumpifattackandspecialattackcannotfall(void) // memento
|
|
{
|
|
if (gBattleMons[gBattlerTarget].statStages[STAT_ATK] == MIN_STAT_STAGE
|
|
&& gBattleMons[gBattlerTarget].statStages[STAT_SPATK] == MIN_STAT_STAGE
|
|
&& gBattleCommunication[6] != 1)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gActiveBattler = gBattlerAttacker;
|
|
gBattleMoveDamage = gBattleMons[gActiveBattler].hp;
|
|
BtlController_EmitHealthBarUpdate(0, INSTANT_HP_BAR_DROP);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_setforcedtarget(void) // follow me
|
|
{
|
|
gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTimer = 1;
|
|
gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTarget = gBattlerAttacker;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_setcharge(void)
|
|
{
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_CHARGED_UP;
|
|
gDisableStructs[gBattlerAttacker].chargeTimer = 2;
|
|
gDisableStructs[gBattlerAttacker].chargeTimerStartValue = 2;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_callterrainattack(void) // nature power
|
|
{
|
|
gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED);
|
|
gCurrentMove = sNaturePowerMoves[gBattleTerrain];
|
|
gBattlerTarget = GetMoveTarget(gCurrentMove, 0);
|
|
BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]);
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_settorment(void)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].status2 & STATUS2_TORMENT)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gBattleMons[gBattlerTarget].status2 |= STATUS2_TORMENT;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_jumpifnodamage(void)
|
|
{
|
|
if (gProtectStructs[gBattlerAttacker].physicalDmg || gProtectStructs[gBattlerAttacker].specialDmg)
|
|
gBattlescriptCurrInstr += 5;
|
|
else
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
|
|
static void Cmd_settaunt(void)
|
|
{
|
|
if (gDisableStructs[gBattlerTarget].tauntTimer == 0)
|
|
{
|
|
gDisableStructs[gBattlerTarget].tauntTimer = 2;
|
|
gDisableStructs[gBattlerTarget].tauntTimer2 = 2;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_tryswapitems(void) // trick
|
|
{
|
|
// opponent can't swap items with player in regular battles
|
|
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL
|
|
|| (GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT
|
|
&& !(gBattleTypeFlags & (BATTLE_TYPE_LINK
|
|
| BATTLE_TYPE_EREADER_TRAINER
|
|
| BATTLE_TYPE_FRONTIER
|
|
| BATTLE_TYPE_SECRET_BASE
|
|
| BATTLE_TYPE_x2000000))))
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(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.knockedOffMons[sideAttacker] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]]
|
|
|| gWishFutureKnock.knockedOffMons[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]]))
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(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 = T1_READ_PTR(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 Cmd_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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_trywish(void)
|
|
{
|
|
switch (gBattlescriptCurrInstr[1])
|
|
{
|
|
case 0: // use wish
|
|
if (gWishFutureKnock.wishCounter[gBattlerAttacker] == 0)
|
|
{
|
|
gWishFutureKnock.wishCounter[gBattlerAttacker] = 2;
|
|
gWishFutureKnock.wishMonId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker];
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
}
|
|
break;
|
|
case 1: // heal effect
|
|
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerTarget, gWishFutureKnock.wishMonId[gBattlerTarget])
|
|
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
gBattleMoveDamage *= -1;
|
|
|
|
if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP)
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void Cmd_trysetroots(void) // ingrain
|
|
{
|
|
if (gStatuses3[gBattlerAttacker] & STATUS3_ROOTED)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_ROOTED;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_doubledamagedealtifdamaged(void)
|
|
{
|
|
if ((gProtectStructs[gBattlerAttacker].physicalDmg
|
|
&& gProtectStructs[gBattlerAttacker].physicalBattlerId == gBattlerTarget)
|
|
|| (gProtectStructs[gBattlerAttacker].specialDmg
|
|
&& gProtectStructs[gBattlerAttacker].specialBattlerId == gBattlerTarget))
|
|
{
|
|
gBattleScripting.dmgMultiplier = 2;
|
|
}
|
|
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_setyawn(void)
|
|
{
|
|
if (gStatuses3[gBattlerTarget] & STATUS3_YAWN
|
|
|| gBattleMons[gBattlerTarget].status1 & STATUS1_ANY)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gStatuses3[gBattlerTarget] |= STATUS3_YAWN_TURN(2);
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_setdamagetohealthdifference(void)
|
|
{
|
|
if (gBattleMons[gBattlerTarget].hp <= gBattleMons[gBattlerAttacker].hp)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - gBattleMons[gBattlerAttacker].hp;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
u8 abilityAtk = gBattleMons[gBattlerAttacker].ability;
|
|
gBattleMons[gBattlerAttacker].ability = gBattleMons[gBattlerTarget].ability;
|
|
gBattleMons[gBattlerTarget].ability = abilityAtk;
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_tryimprison(void)
|
|
{
|
|
if ((gStatuses3[gBattlerAttacker] & STATUS3_IMPRISONED_OTHERS))
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
u8 battlerId, sideAttacker;
|
|
|
|
sideAttacker = GetBattlerSide(gBattlerAttacker);
|
|
PressurePPLoseOnUsingImprison(gBattlerAttacker);
|
|
for (battlerId = 0; battlerId < gBattlersCount; battlerId++)
|
|
{
|
|
if (sideAttacker != GetBattlerSide(battlerId))
|
|
{
|
|
s32 attackerMoveId;
|
|
for (attackerMoveId = 0; attackerMoveId < MAX_MON_MOVES; attackerMoveId++)
|
|
{
|
|
s32 i;
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
if (gBattleMons[gBattlerAttacker].moves[attackerMoveId] == gBattleMons[battlerId].moves[i]
|
|
&& gBattleMons[gBattlerAttacker].moves[attackerMoveId] != MOVE_NONE)
|
|
break;
|
|
}
|
|
if (i != MAX_MON_MOVES)
|
|
break;
|
|
}
|
|
if (attackerMoveId != MAX_MON_MOVES)
|
|
{
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_IMPRISONED_OTHERS;
|
|
gBattlescriptCurrInstr += 5;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (battlerId == gBattlersCount) // In Generation 3 games, Imprison fails if the user doesn't share any moves with any of the foes
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_trysetgrudge(void)
|
|
{
|
|
if (gStatuses3[gBattlerAttacker] & STATUS3_GRUDGE)
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gStatuses3[gBattlerAttacker] |= STATUS3_GRUDGE;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 Cmd_assistattackselect(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 < PARTY_SIZE; 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 < MAX_MON_MOVES; 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);
|
|
gCalledMove = movesArray[((Random() & 0xFF) * chooseableMovesNo) >> 8];
|
|
gBattlerTarget = GetMoveTarget(gCalledMove, 0);
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_trysetmagiccoat(void)
|
|
{
|
|
gBattlerTarget = gBattlerAttacker;
|
|
gSpecialStatuses[gBattlerAttacker].ppNotAffectedByPressure = 1;
|
|
if (gCurrentTurnActionNumber == gBattlersCount - 1) // moves last turn
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gProtectStructs[gBattlerAttacker].bounceMove = 1;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_trysetsnatch(void) // snatch
|
|
{
|
|
gSpecialStatuses[gBattlerAttacker].ppNotAffectedByPressure = 1;
|
|
if (gCurrentTurnActionNumber == gBattlersCount - 1) // moves last turn
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
gProtectStructs[gBattlerAttacker].stealMove = 1;
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_trygetintimidatetarget(void)
|
|
{
|
|
u8 side;
|
|
|
|
gBattleScripting.battler = gBattleStruct->intimidateBattler;
|
|
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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
else
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
|
|
static void Cmd_switchoutabilities(void)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(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 Cmd_jumpifhasnohp(void)
|
|
{
|
|
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
|
|
|
|
if (gBattleMons[gActiveBattler].hp == 0)
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
|
|
else
|
|
gBattlescriptCurrInstr += 6;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_pickup(void)
|
|
{
|
|
s32 i;
|
|
u16 species, heldItem;
|
|
u8 ability;
|
|
|
|
if (InBattlePike())
|
|
{
|
|
|
|
}
|
|
else if (InBattlePyramid())
|
|
{
|
|
for (i = 0; i < PARTY_SIZE; i++)
|
|
{
|
|
species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2);
|
|
heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
|
|
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_ABILITY_NUM))
|
|
ability = gBaseStats[species].abilities[1];
|
|
else
|
|
ability = gBaseStats[species].abilities[0];
|
|
|
|
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 < PARTY_SIZE; i++)
|
|
{
|
|
species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2);
|
|
heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
|
|
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_ABILITY_NUM))
|
|
ability = gBaseStats[species].abilities[1];
|
|
else
|
|
ability = gBaseStats[species].abilities[0];
|
|
|
|
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 < (int)ARRAY_COUNT(sPickupProbabilities); 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 Cmd_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 Cmd_trycastformdatachange(void)
|
|
{
|
|
u8 form;
|
|
|
|
gBattlescriptCurrInstr++;
|
|
form = CastformDataTypeChange(gBattleScripting.battler);
|
|
if (form)
|
|
{
|
|
BattleScriptPushCursorAndCallback(BattleScript_CastformChange);
|
|
*(&gBattleStruct->formToChangeInto) = form - 1;
|
|
}
|
|
}
|
|
|
|
static void Cmd_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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_settypetoterrain(void)
|
|
{
|
|
if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, sTerrainToType[gBattleTerrain]))
|
|
{
|
|
SET_BATTLER_TYPE(gBattlerAttacker, sTerrainToType[gBattleTerrain]);
|
|
PREPARE_TYPE_BUFFER(gBattleTextBuff1, sTerrainToType[gBattleTerrain]);
|
|
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_pursuitrelated(void)
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_FLANK);
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
|
&& !(gAbsentBattlerFlags & gBitTable[gActiveBattler])
|
|
&& gChosenActionByBattler[gActiveBattler] == B_ACTION_USE_MOVE
|
|
&& gChosenMoveByBattler[gActiveBattler] == MOVE_PURSUIT)
|
|
{
|
|
gActionsByTurnOrder[gActiveBattler] = 11;
|
|
gCurrentMove = MOVE_PURSUIT;
|
|
gBattlescriptCurrInstr += 5;
|
|
gBattleScripting.animTurn = 1;
|
|
gBattleScripting.field_20 = gBattlerAttacker;
|
|
gBattlerAttacker = gActiveBattler;
|
|
}
|
|
else
|
|
{
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
}
|
|
|
|
static void Cmd_snatchsetbattlers(void)
|
|
{
|
|
gEffectBattler = gBattlerAttacker;
|
|
|
|
if (gBattlerAttacker == gBattlerTarget)
|
|
gBattlerAttacker = gBattlerTarget = gBattleScripting.battler;
|
|
else
|
|
gBattlerTarget = gBattleScripting.battler;
|
|
|
|
gBattleScripting.battler = gEffectBattler;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_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 Cmd_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->safariCatchFactor * 1275 / 100;
|
|
else
|
|
catchRate = gBaseStats[gBattleMons[gBattlerTarget].species].catchRate;
|
|
|
|
if (gLastUsedItem > ITEM_SAFARI_BALL)
|
|
{
|
|
switch (gLastUsedItem)
|
|
{
|
|
case ITEM_NET_BALL:
|
|
if (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_WATER) || IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_BUG))
|
|
ballMultiplier = 30;
|
|
else
|
|
ballMultiplier = 10;
|
|
break;
|
|
case ITEM_DIVE_BALL:
|
|
if (GetCurrentMapType() == MAP_TYPE_UNDERWATER)
|
|
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 - ITEM_ULTRA_BALL];
|
|
|
|
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() == PARTY_SIZE)
|
|
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 < BALL_3_SHAKES_SUCCESS && 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() == PARTY_SIZE)
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
}
|
|
else // not caught
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = shakes;
|
|
// Maybe inject SpriteCB_TestBallThrow here
|
|
gBattlescriptCurrInstr = BattleScript_ShakeBallThrow;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Cmd_givecaughtmon(void)
|
|
{
|
|
if (GiveMonToPlayer(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]]) != MON_GIVEN_TO_PARTY)
|
|
{
|
|
if (!ShouldShowBoxWasFullMessage())
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_PC_BOX_TO_SEND_MON)));
|
|
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2);
|
|
}
|
|
else
|
|
{
|
|
StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_PC_BOX_TO_SEND_MON))); // box the mon was sent to
|
|
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2);
|
|
StringCopy(gStringVar3, GetBoxNamePtr(GetPCBoxToSendMon())); //box the mon was going to be sent to
|
|
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 Cmd_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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
else
|
|
{
|
|
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_SET_CAUGHT, personality);
|
|
gBattlescriptCurrInstr += 5;
|
|
}
|
|
}
|
|
|
|
static void Cmd_displaydexinfo(void)
|
|
{
|
|
u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL);
|
|
|
|
switch (gBattleCommunication[0])
|
|
{
|
|
case 0:
|
|
BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, RGB_BLACK);
|
|
gBattleCommunication[0]++;
|
|
break;
|
|
case 1:
|
|
if (!gPaletteFade.active)
|
|
{
|
|
FreeAllWindowBuffers();
|
|
gBattleCommunication[TASK_ID] = DisplayCaughtMonDexPage(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:
|
|
InitBattleBgsVideo();
|
|
LoadBattleTextboxAndBackground();
|
|
gBattle_BG3_X = 0x100;
|
|
gBattleCommunication[0]++;
|
|
break;
|
|
case 4:
|
|
if (!IsDma3ManagerBusyWithBgCopy())
|
|
{
|
|
BeginNormalPaletteFade(0xFFFF, 0, 0x10, 0, RGB_BLACK);
|
|
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 Cmd_trygivecaughtmonnick(void)
|
|
{
|
|
switch (gBattleCommunication[MULTIUSE_STATE])
|
|
{
|
|
case 0:
|
|
HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
|
|
BattlePutTextOnWindow(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 = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
}
|
|
break;
|
|
case 4:
|
|
if (CalculatePlayerPartyCount() == PARTY_SIZE)
|
|
gBattlescriptCurrInstr += 5;
|
|
else
|
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void Cmd_subattackerhpbydmg(void)
|
|
{
|
|
gBattleMons[gBattlerAttacker].hp -= gBattleMoveDamage;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_removeattackerstatus1(void)
|
|
{
|
|
gBattleMons[gBattlerAttacker].status1 = 0;
|
|
gBattlescriptCurrInstr++;
|
|
}
|
|
|
|
static void Cmd_finishaction(void)
|
|
{
|
|
gCurrentActionFuncId = B_ACTION_FINISHED;
|
|
}
|
|
|
|
static void Cmd_finishturn(void)
|
|
{
|
|
gCurrentActionFuncId = B_ACTION_FINISHED;
|
|
gCurrentTurnActionNumber = gBattlersCount;
|
|
}
|
|
|
|
static void Cmd_trainerslideout(void)
|
|
{
|
|
gActiveBattler = GetBattlerAtPosition(gBattlescriptCurrInstr[1]);
|
|
BtlController_EmitTrainerSlideBack(0);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
|
|
gBattlescriptCurrInstr += 2;
|
|
}
|