From fee81d03abd96f68809fdaf67bb2f8502c0ef86c Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 22 Jul 2018 18:40:18 +0200 Subject: [PATCH] A couple of gen4 abilities --- asm/macros/battle_script.inc | 10 +- data/battle_scripts_1.s | 64 + include/battle_scripts.h | 7 + include/constants/battle_script_commands.h | 2 + include/constants/battle_string_ids.h | 6 +- src/battle_message.c | 17 +- src/battle_script_commands.c | 47 +- src/battle_util.c | 1504 +++++++++++--------- 8 files changed, 934 insertions(+), 723 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index f3507ee79..3b67ac731 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -589,7 +589,7 @@ .byte \bank .endm - .macro recordlastability bank + .macro recordability bank .byte 0x70 .byte \bank .endm @@ -1347,6 +1347,14 @@ various \bank, VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC .endm + .macro stattextbuffer battler + various \battler, VARIOUS_STAT_TEXT_BUFFER + .endm + + .macro switchinabilities battler + various \battler, VARIOUS_SWITCHIN_ABILITIES + .endm + @ helpful macros .macro setstatchanger stat, stages, down setbyte sSTATCHANGER \stat | \stages << 4 | \down << 7 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index cea7b1d74..5d39fae94 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -4108,6 +4108,16 @@ BattleScript_DoTurnDmg:: atk24 BattleScript_DoTurnDmgEnd BattleScript_DoTurnDmgEnd:: end2 + +BattleScript_PoisonHealActivates:: + printstring STRINGID_POISONHEALHPUP + waitmessage 0x40 + recordability BS_ATTACKER + statusanimation BS_ATTACKER + orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_x100000 + healthbarupdate BS_ATTACKER + datahpupdate BS_ATTACKER + end2 BattleScript_BurnTurnDmg:: printstring STRINGID_PKMNHURTBYBURN @@ -4142,7 +4152,20 @@ BattleScript_MoveUsedIsParalyzed:: BattleScript_MoveUsedFlinched:: printstring STRINGID_PKMNFLINCHED waitmessage 0x40 + jumpifability BS_ATTACKER ABILITY_STEADFAST BattleScript_TryActivateSteadFast +BattleScript_MoveUsedFlinchedEnd: goto BattleScript_MoveEnd +BattleScript_TryActivateSteadFast: + setstatchanger STAT_SPEED, 1, FALSE + statbuffchange MOVE_EFFECT_AFFECTS_USER | 0x1, BattleScript_MoveUsedFlinchedEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, 0x2, BattleScript_MoveUsedFlinchedEnd + setgraphicalstatchangevalues + playanimation BS_ATTACKER, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 + setbyte gBattleCommunication STAT_SPEED + stattextbuffer BS_ATTACKER + printstring STRINGID_TARGETABILITYSTATRAISE + waitmessage 0x40 + goto BattleScript_MoveUsedFlinchedEnd BattleScript_PrintUproarOverTurns:: printfromtable gUproarOverTurnStringIds @@ -4354,6 +4377,7 @@ BattleScript_TraceActivates:: pause 0x20 printstring STRINGID_PKMNTRACED waitmessage 0x40 + switchinabilities BS_ATTACKER end3 BattleScript_RainDishActivates:: @@ -4470,6 +4494,18 @@ BattleScript_MoveHPDrain:: waitmessage 0x40 orhalfword gMoveResultFlags, MOVE_RESULT_DOESNT_AFFECT_FOE goto BattleScript_MoveEnd + +BattleScript_MoveStatDrain_PPLoss:: + ppreduce +BattleScript_MoveStatDrain:: + attackstring + pause 0x20 + setgraphicalstatchangevalues + playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 + waitanimation + printstring STRINGID_TARGETABILITYSTATRAISE + waitmessage 0x40 + goto BattleScript_MoveEnd BattleScript_MonMadeMoveUseless_PPLoss:: ppreduce @@ -4563,6 +4599,34 @@ BattleScript_ColorChangeActivates:: printstring STRINGID_PKMNCHANGEDTYPEWITH waitmessage 0x40 return + +BattleScript_AngryPointActivates:: + setbyte sB_ANIM_ARG1 0x38 + setbyte sB_ANIM_ARG2 0x0 + playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 + printstring STRINGID_ANGRYPOINTACTIVATES + waitmessage 0x40 + return + +BattleScript_TargetAbilityStatRaise:: + setgraphicalstatchangevalues + playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 + waitanimation + printstring STRINGID_TARGETABILITYSTATRAISE + waitmessage 0x40 + return + +BattleScript_AttackerAbilityStatRaise:: + setgraphicalstatchangevalues + playanimation BS_ATTACKER, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 + waitanimation + printstring STRINGID_ATTACKERABILITYSTATRAISE + waitmessage 0x40 + return + +BattleScript_AttackerAbilityStatRaiseEnd3:: + call BattleScript_AttackerAbilityStatRaise + end3 BattleScript_RoughSkinActivates:: orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_x100000 diff --git a/include/battle_scripts.h b/include/battle_scripts.h index a8789c0a1..520e32b00 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -305,5 +305,12 @@ extern const u8 BattleScript_MudSportEnds[]; extern const u8 BattleScript_WaterSportEnds[]; extern const u8 BattleScript_SturdiedMsg[]; extern const u8 BattleScript_GravityEnds[]; +extern const u8 BattleScript_MoveStatDrain[]; +extern const u8 BattleScript_MoveStatDrain_PPLoss[]; +extern const u8 BattleScript_TargetAbilityStatRaise[]; +extern const u8 BattleScript_AngryPointActivates[]; +extern const u8 BattleScript_AttackerAbilityStatRaise[]; +extern const u8 BattleScript_AttackerAbilityStatRaiseEnd3[]; +extern const u8 BattleScript_PoisonHealActivates[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index d13ee7d81..3e1906442 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -72,6 +72,8 @@ #define VARIOUS_RETURN_OPPONENT_MON2 20 #define VARIOUS_SET_TELEPORT_OUTCOME 25 #define VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC 26 +#define VARIOUS_STAT_TEXT_BUFFER 27 +#define VARIOUS_SWITCHIN_ABILITIES 28 // atk80, dmg manipulation #define ATK80_DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 98e8940f2..c2fc1ca10 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -450,7 +450,11 @@ #define STRINGID_MISTYTERRAINENDS 447 #define STRINGID_PSYCHICTERRAINENDS 448 #define STRINGID_GRASSYTERRAINENDS 449 +#define STRINGID_TARGETABILITYSTATRAISE 450 +#define STRINGID_ANGRYPOINTACTIVATES 451 +#define STRINGID_ATTACKERABILITYSTATRAISE 452 +#define STRINGID_POISONHEALHPUP 453 -#define BATTLESTRINGS_COUNT 438 +#define BATTLESTRINGS_COUNT 442 #endif // GUARD_CONSTANTS_BATTLE_STRING_IDS_H diff --git a/src/battle_message.c b/src/battle_message.c index cd6cb8335..213770fdd 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -431,7 +431,7 @@ static const u8 sText_FoePkmnPrefix3[] = _("Foe"); static const u8 sText_AllyPkmnPrefix2[] = _("Ally"); static const u8 sText_FoePkmnPrefix4[] = _("Foe"); static const u8 sText_AllyPkmnPrefix3[] = _("Ally"); -static const u8 sText_AttackerUsedX[] = _("{B_ATK_NAME_WITH_PREFIX} used\n{B_BUFF2}"); +static const u8 sText_AttackerUsedX[] = _("{B_ATK_NAME_WITH_PREFIX} used\n{B_BUFF3}!"); static const u8 sText_ExclamationMark[] = _("!"); static const u8 sText_ExclamationMark2[] = _("!"); static const u8 sText_ExclamationMark3[] = _("!"); @@ -586,6 +586,8 @@ static const u8 sText_MudSportEnds[] = _("The effects of Mud Sport have faded.") static const u8 sText_WaterSportEnds[] = _("The effects of Water Sport have faded."); static const u8 sText_GravityEnds[] = _("Gravity returned to normal!"); static const u8 sText_AquaRingHeal[] = _("Aqua Ring restored\n{B_ATK_NAME_WITH_PREFIX}’s HP!"); +static const u8 sText_TargetAbilityRaisedStat[] = _("{B_DEF_NAME_WITH_PREFIX}’s {B_ATK_ABILITY}\n raised its {B_BUFF1}!"); +static const u8 sText_AttackerAbilityRaisedStat[] = _("{B_ATK_NAME_WITH_PREFIX}’s {B_ATK_ABILITY}\n raised its {B_BUFF1}!"); // These strings are currently placeholders, to be fixed. static const u8 sText_AuroraVeilEnds[] = _(""); @@ -593,6 +595,8 @@ static const u8 sText_ElectricTerrainEnds[] = _(""); static const u8 sText_MistyTerrainEnds[] = _(""); static const u8 sText_PsychicTerrainEnds[] = _(""); static const u8 sText_GrassyTerrainEnds[] = _(""); +static const u8 sText_AngryPointActivates[] = _(""); +static const u8 sText_PoisonHealHpUp[] = _(""); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { @@ -1035,6 +1039,10 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = sText_MistyTerrainEnds, // 447 sText_PsychicTerrainEnds, // 448 sText_GrassyTerrainEnds, // 449 + sText_TargetAbilityRaisedStat, // 450 + sText_AngryPointActivates, // 451 + sText_AttackerAbilityRaisedStat, // 452 + sText_PoisonHealHpUp, // 453 }; const u16 gMissStringIds[] = @@ -2297,14 +2305,11 @@ void BufferStringBattle(u16 stringID) } break; case STRINGID_USEDMOVE: // pokemon used a move msg - ChooseMoveUsedParticle(gBattleTextBuff1); // buff1 doesn't appear in the string, leftover from japanese move names - if (gBattleMsgDataPtr->currentMove >= MOVES_COUNT) - StringCopy(gBattleTextBuff2, sATypeMove_Table[*(&gBattleStruct->stringMoveType)]); + StringCopy(gBattleTextBuff3, sATypeMove_Table[*(&gBattleStruct->stringMoveType)]); else - StringCopy(gBattleTextBuff2, gMoveNames[gBattleMsgDataPtr->currentMove]); + StringCopy(gBattleTextBuff3, gMoveNames[gBattleMsgDataPtr->currentMove]); - ChooseTypeOfMoveUsedString(gBattleTextBuff2); stringPtr = sText_AttackerUsedX; break; case STRINGID_BATTLEEND: // battle end diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index c97214425..fd95bbb28 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -203,7 +203,7 @@ static void atk6C_drawlvlupbox(void); static void atk6D_resetsentmonsvalue(void); static void atk6E_setatktoplayer0(void); static void atk6F_makevisible(void); -static void atk70_recordlastability(void); +static void atk70_recordability(void); static void atk71_buffermovetolearn(void); static void atk72_jumpifplayerran(void); static void atk73_hpthresholds(void); @@ -459,7 +459,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk6D_resetsentmonsvalue, atk6E_setatktoplayer0, atk6F_makevisible, - atk70_recordlastability, + atk70_recordability, atk71_buffermovetolearn, atk72_jumpifplayerran, atk73_hpthresholds, @@ -1013,22 +1013,23 @@ static void atk00_attackcanceler(void) } } -static void JumpIfMoveFailed(u8 adder, u16 move) +static bool32 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); + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + return TRUE; } else { TrySetDestinyBondToHappen(); if (AbilityBattleEffects(ABILITYEFFECT_ABSORBING, gBattlerTarget, 0, 0, move)) - return; + return TRUE; } - gBattlescriptCurrInstr = BS_ptr; + gBattlescriptCurrInstr += adder; + return FALSE; } static void atk40_jumpifaffectedbyprotect(void) @@ -1058,7 +1059,7 @@ bool8 JumpIfMoveAffectedByProtect(u16 move) return affected; } -static bool8 AccuracyCalcHelper(u16 move) +static bool32 AccuracyCalcHelper(u16 move) { if (gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker) { @@ -1070,6 +1071,18 @@ static bool8 AccuracyCalcHelper(u16 move) JumpIfMoveFailed(7, move); return TRUE; } + else if (GetBattlerAbility(gBattlerAttacker) == ABILITY_NO_GUARD) + { + if (!JumpIfMoveFailed(7, move)) + RecordAbilityBattle(gBattlerAttacker, ABILITY_NO_GUARD); + return TRUE; + } + else if (GetBattlerAbility(gBattlerTarget) == ABILITY_NO_GUARD) + { + if (!JumpIfMoveFailed(7, move)) + RecordAbilityBattle(gBattlerTarget, ABILITY_NO_GUARD); + return TRUE; + } if (!(gHitMarker & HITMARKER_IGNORE_ON_AIR) && gStatuses3[gBattlerTarget] & STATUS3_ON_AIR) { @@ -6242,11 +6255,11 @@ static void atk6F_makevisible(void) gBattlescriptCurrInstr += 2; } -static void atk70_recordlastability(void) +static void atk70_recordability(void) { - gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); - RecordAbilityBattle(gActiveBattler, gLastUsedAbility); - gBattlescriptCurrInstr += 1; // UB: Should be + 2, one byte for command and one byte for battlerId argument. + u8 battler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); + RecordAbilityBattle(battler, gBattleMons[battler].ability); + gBattlescriptCurrInstr += 2; } void BufferMoveToLearnIntoBattleTextBuff2(void) @@ -6502,6 +6515,13 @@ static void atk76_various(void) BtlController_EmitPlayFanfareOrBGM(0, MUS_KACHI1, TRUE); MarkBattlerForControllerExec(gActiveBattler); break; + case VARIOUS_STAT_TEXT_BUFFER: + PREPARE_STAT_BUFFER(gBattleTextBuff1, gBattleCommunication[0]); + break; + case VARIOUS_SWITCHIN_ABILITIES: + gBattlescriptCurrInstr += 3; + AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBattler, 0, 0, 0); + return; } gBattlescriptCurrInstr += 3; @@ -7158,6 +7178,9 @@ static void atk8D_setmultihitcounter(void) gMultiHitCounter = (Random() & 3) + 2; else gMultiHitCounter += 2; + + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_SKILL_LINK) + gMultiHitCounter = 5; } gBattlescriptCurrInstr += 2; diff --git a/src/battle_util.c b/src/battle_util.c index 841325cf3..f90f08bd6 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1230,6 +1230,7 @@ u8 DoBattlerEndTurnEffects(void) } else { + u8 ability = GetBattlerAbility(gActiveBattler); switch (gBattleStruct->turnEffectsTracker) { case ENDTURN_INGRAIN: // ingrain @@ -1294,32 +1295,68 @@ u8 DoBattlerEndTurnEffects(void) gBattleStruct->turnEffectsTracker++; break; case ENDTURN_POISON: // poison - if ((gBattleMons[gActiveBattler].status1 & STATUS1_POISON) && gBattleMons[gActiveBattler].hp != 0) + if ((gBattleMons[gActiveBattler].status1 & STATUS1_POISON) + && gBattleMons[gActiveBattler].hp != 0 + && ability != ABILITY_MAGIC_GUARD) { - gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - BattleScriptExecute(BattleScript_PoisonTurnDmg); - effect++; + if (ability == ABILITY_POISON_HEAL) + { + if (!BATTLER_MAX_HP(gActiveBattler)) + { + gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + BattleScriptExecute(BattleScript_PoisonHealActivates); + effect++; + } + } + else + { + gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + BattleScriptExecute(BattleScript_PoisonTurnDmg); + effect++; + } } gBattleStruct->turnEffectsTracker++; break; case ENDTURN_BAD_POISON: // toxic poison - if ((gBattleMons[gActiveBattler].status1 & STATUS1_TOXIC_POISON) && gBattleMons[gActiveBattler].hp != 0) + if ((gBattleMons[gActiveBattler].status1 & STATUS1_TOXIC_POISON) + && gBattleMons[gActiveBattler].hp != 0 + && ability != ABILITY_MAGIC_GUARD) { - gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - if ((gBattleMons[gActiveBattler].status1 & 0xF00) != 0xF00) // not 16 turns - gBattleMons[gActiveBattler].status1 += 0x100; - gBattleMoveDamage *= (gBattleMons[gActiveBattler].status1 & 0xF00) >> 8; - BattleScriptExecute(BattleScript_PoisonTurnDmg); - effect++; + if (ability == ABILITY_POISON_HEAL) + { + if (!BATTLER_MAX_HP(gActiveBattler)) + { + gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + BattleScriptExecute(BattleScript_PoisonHealActivates); + effect++; + } + } + else + { + gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + if ((gBattleMons[gActiveBattler].status1 & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_COUNTER) // not 16 turns + gBattleMons[gActiveBattler].status1 += 0x100; + gBattleMoveDamage *= (gBattleMons[gActiveBattler].status1 & STATUS1_TOXIC_COUNTER) >> 8; + BattleScriptExecute(BattleScript_PoisonTurnDmg); + effect++; + } } gBattleStruct->turnEffectsTracker++; break; case ENDTURN_BURN: // burn - if ((gBattleMons[gActiveBattler].status1 & STATUS1_BURN) && gBattleMons[gActiveBattler].hp != 0) + if ((gBattleMons[gActiveBattler].status1 & STATUS1_BURN) + && gBattleMons[gActiveBattler].hp != 0 + && ability != ABILITY_MAGIC_GUARD) { gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8; if (gBattleMoveDamage == 0) @@ -1330,7 +1367,9 @@ u8 DoBattlerEndTurnEffects(void) gBattleStruct->turnEffectsTracker++; break; case ENDTURN_NIGHTMARES: // spooky nightmares - if ((gBattleMons[gActiveBattler].status2 & STATUS2_NIGHTMARE) && gBattleMons[gActiveBattler].hp != 0) + if ((gBattleMons[gActiveBattler].status2 & STATUS2_NIGHTMARE) + && gBattleMons[gActiveBattler].hp != 0 + && ability != ABILITY_MAGIC_GUARD) { // R/S does not perform this sleep check, which causes the nightmare effect to // persist even after the affected Pokemon has been awakened by Shed Skin. @@ -1350,7 +1389,9 @@ u8 DoBattlerEndTurnEffects(void) gBattleStruct->turnEffectsTracker++; break; case ENDTURN_CURSE: // curse - if ((gBattleMons[gActiveBattler].status2 & STATUS2_CURSED) && gBattleMons[gActiveBattler].hp != 0) + if ((gBattleMons[gActiveBattler].status2 & STATUS2_CURSED) + && gBattleMons[gActiveBattler].hp != 0 + && ability != ABILITY_MAGIC_GUARD) { gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 4; if (gBattleMoveDamage == 0) @@ -2263,740 +2304,797 @@ u8 CastformDataTypeChange(u8 battler) u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveArg) { u8 effect = 0; - struct Pokemon *pokeAtk; - struct Pokemon *pokeDef; - u16 speciesAtk; - u16 speciesDef; - u32 pidAtk; - u32 pidDef; + u32 speciesAtk, speciesDef; + u32 pidAtk, pidDef; + u32 moveType; + u32 i; + u32 move; + u8 side; + u8 target1; + + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + return; if (gBattlerAttacker >= gBattlersCount) gBattlerAttacker = battler; - if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) - pokeAtk = &gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]]; + speciesAtk = gBattleMons[gBattlerAttacker].species; + pidAtk = gBattleMons[gBattlerAttacker].personality; + + speciesDef = gBattleMons[gBattlerTarget].species; + pidDef = gBattleMons[gBattlerTarget].personality; + + gLastUsedAbility = GetBattlerAbility(battler); + + if (moveArg) + move = moveArg; else - pokeAtk = &gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker]]; + move = gCurrentMove; - if (gBattlerTarget >= gBattlersCount) - gBattlerTarget = battler; + GET_MOVE_TYPE(move, moveType); - if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) - pokeDef = &gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]]; - else - pokeDef = &gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]]; - - speciesAtk = GetMonData(pokeAtk, MON_DATA_SPECIES); - pidAtk = GetMonData(pokeAtk, MON_DATA_PERSONALITY); - - speciesDef = GetMonData(pokeDef, MON_DATA_SPECIES); - pidDef = GetMonData(pokeDef, MON_DATA_PERSONALITY); - - if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) // Why isn't that check done at the beginning? + switch (caseID) { - u8 moveType; - s32 i; - u16 move; - u8 side; - u8 target1; - - if (special) - gLastUsedAbility = special; - else - gLastUsedAbility = gBattleMons[battler].ability; - - if (moveArg) - move = moveArg; - else - move = gCurrentMove; - - GET_MOVE_TYPE(move, moveType); - - switch (caseID) + case ABILITYEFFECT_ON_SWITCHIN: // 0 + switch (gLastUsedAbility) { - case ABILITYEFFECT_ON_SWITCHIN: // 0 - if (gBattlerAttacker >= gBattlersCount) - gBattlerAttacker = battler; - switch (gLastUsedAbility) + case ABILITYEFFECT_SWITCH_IN_WEATHER: + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) { - case ABILITYEFFECT_SWITCH_IN_WEATHER: - if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + switch (weather_get_current()) { - switch (weather_get_current()) + case 3: + case 5: + case 13: + if (!(gBattleWeather & WEATHER_RAIN_ANY)) { - case 3: - case 5: - case 13: - if (!(gBattleWeather & WEATHER_RAIN_ANY)) - { - gBattleWeather = (WEATHER_RAIN_TEMPORARY | WEATHER_RAIN_PERMANENT); - gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES; - gBattleScripting.battler = battler; - effect++; - } - break; - case 8: - if (!(gBattleWeather & WEATHER_SANDSTORM_ANY)) - { - gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); - gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES; - gBattleScripting.battler = battler; - effect++; - } - break; - case 12: - if (!(gBattleWeather & WEATHER_SUN_ANY)) - { - gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); - gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES; - gBattleScripting.battler = battler; - effect++; - } - break; - } - } - if (effect) - { - gBattleCommunication[MULTISTRING_CHOOSER] = weather_get_current(); - BattleScriptPushCursorAndCallback(BattleScript_OverworldWeatherStarts); - } - break; - case ABILITY_DRIZZLE: - if (!(gBattleWeather & WEATHER_RAIN_PERMANENT)) - { - gBattleWeather = (WEATHER_RAIN_PERMANENT | WEATHER_RAIN_TEMPORARY); - BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates); - gBattleScripting.battler = battler; - effect++; - } - break; - case ABILITY_SAND_STREAM: - if (!(gBattleWeather & WEATHER_SANDSTORM_PERMANENT)) - { - gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); - BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates); - gBattleScripting.battler = battler; - effect++; - } - break; - case ABILITY_DROUGHT: - if (!(gBattleWeather & WEATHER_SUN_PERMANENT)) - { - gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); - BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); - gBattleScripting.battler = battler; - effect++; - } - break; - case ABILITY_INTIMIDATE: - if (!(gSpecialStatuses[battler].intimidatedMon)) - { - gStatuses3[battler] |= STATUS3_INTIMIDATE_POKES; - gSpecialStatuses[battler].intimidatedMon = 1; - } - break; - case ABILITY_FORECAST: - effect = CastformDataTypeChange(battler); - if (effect != 0) - { - BattleScriptPushCursorAndCallback(BattleScript_CastformChange); - gBattleScripting.battler = battler; - *(&gBattleStruct->formToChangeInto) = effect - 1; - } - break; - case ABILITY_TRACE: - if (!(gSpecialStatuses[battler].traced)) - { - gStatuses3[battler] |= STATUS3_TRACE; - gSpecialStatuses[battler].traced = 1; - } - break; - case ABILITY_CLOUD_NINE: - case ABILITY_AIR_LOCK: - { - // that's a weird choice for a variable, why not use i or battler? - for (target1 = 0; target1 < gBattlersCount; target1++) - { - effect = CastformDataTypeChange(target1); - if (effect != 0) - { - BattleScriptPushCursorAndCallback(BattleScript_CastformChange); - gBattleScripting.battler = target1; - *(&gBattleStruct->formToChangeInto) = effect - 1; - break; - } - } - } - break; - } - break; - case ABILITYEFFECT_ENDTURN: // 1 - if (gBattleMons[battler].hp != 0) - { - gBattlerAttacker = battler; - switch (gLastUsedAbility) - { - case ABILITY_RAIN_DISH: - if (WEATHER_HAS_EFFECT && (gBattleWeather & WEATHER_RAIN_ANY) - && gBattleMons[battler].maxHP > gBattleMons[battler].hp) - { - gLastUsedAbility = ABILITY_RAIN_DISH; // why - BattleScriptPushCursorAndCallback(BattleScript_RainDishActivates); - gBattleMoveDamage = gBattleMons[battler].maxHP / 16; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - gBattleMoveDamage *= -1; - effect++; - } - break; - case ABILITY_SHED_SKIN: - if ((gBattleMons[battler].status1 & STATUS1_ANY) && (Random() % 3) == 0) - { - if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON)) - StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); - if (gBattleMons[battler].status1 & STATUS1_SLEEP) - StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) - StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); - if (gBattleMons[battler].status1 & STATUS1_BURN) - StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); - if (gBattleMons[battler].status1 & STATUS1_FREEZE) - StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); - gBattleMons[battler].status1 = 0; - gBattleMons[battler].status2 &= ~(STATUS2_NIGHTMARE); // fix nightmare glitch - gBattleScripting.battler = gActiveBattler = battler; - BattleScriptPushCursorAndCallback(BattleScript_ShedSkinActivates); - BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(gActiveBattler); - effect++; - } - break; - case ABILITY_SPEED_BOOST: - if (gBattleMons[battler].statStages[STAT_SPEED] < 0xC && gDisableStructs[battler].isFirstTurn != 2) - { - gBattleMons[battler].statStages[STAT_SPEED]++; - gBattleScripting.animArg1 = 0x11; - gBattleScripting.animArg2 = 0; - BattleScriptPushCursorAndCallback(BattleScript_SpeedBoostActivates); + gBattleWeather = (WEATHER_RAIN_TEMPORARY | WEATHER_RAIN_PERMANENT); + gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES; gBattleScripting.battler = battler; effect++; } break; - case ABILITY_TRUANT: - gDisableStructs[gBattlerAttacker].truantCounter ^= 1; + case 8: + if (!(gBattleWeather & WEATHER_SANDSTORM_ANY)) + { + gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); + gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES; + gBattleScripting.battler = battler; + effect++; + } + break; + case 12: + if (!(gBattleWeather & WEATHER_SUN_ANY)) + { + gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); + gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES; + gBattleScripting.battler = battler; + effect++; + } break; } } - break; - case ABILITYEFFECT_MOVES_BLOCK: // 2 - if (gLastUsedAbility == ABILITY_SOUNDPROOF) + if (effect) { - for (i = 0; sSoundMovesTable[i] != 0xFFFF; i++) + gBattleCommunication[MULTISTRING_CHOOSER] = weather_get_current(); + BattleScriptPushCursorAndCallback(BattleScript_OverworldWeatherStarts); + } + break; + case ABILITY_DOWNLOAD: + { + u8 statId; + u32 opposingBattler = BATTLE_OPPOSITE(battler); + u32 opposingDef = gBattleMons[opposingBattler].defense + * gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_DEF]][0] + / gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_DEF]][1]; + u32 opposingSpDef = gBattleMons[opposingBattler].spDefense + * gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_SPDEF]][0] + / gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_SPDEF]][1]; + + opposingBattler = BATTLE_PARTNER(opposingBattler); + if (IsBattlerAlive(opposingBattler)) { - if (sSoundMovesTable[i] == move) - break; + opposingDef += gBattleMons[opposingBattler].defense + * gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_DEF]][0] + / gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_DEF]][1]; + opposingSpDef += gBattleMons[opposingBattler].spDefense + * gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_SPDEF]][0] + / gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_SPDEF]][1]; } - if (sSoundMovesTable[i] != 0xFFFF) + + if (opposingSpDef > opposingDef) + statId = STAT_SPATK; + else + statId = STAT_ATK; + + if (gBattleMons[battler].statStages[statId] != 0xC) { - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS) - gHitMarker |= HITMARKER_NO_PPDEDUCT; - gBattlescriptCurrInstr = BattleScript_SoundproofProtected; - effect = 1; + gBattleMons[battler].statStages[statId]++; + SET_STATCHANGER(statId, 1, FALSE); + PREPARE_STAT_BUFFER(gBattleTextBuff1, statId); + BattleScriptPushCursorAndCallback(BattleScript_AttackerAbilityStatRaiseEnd3); + effect++; } } break; - case ABILITYEFFECT_ABSORBING: // 3 - if (move) + case ABILITY_DRIZZLE: + if (!(gBattleWeather & WEATHER_RAIN_PERMANENT)) { - switch (gLastUsedAbility) - { - case ABILITY_VOLT_ABSORB: - if (moveType == TYPE_ELECTRIC && gBattleMoves[move].power != 0) - { - if (gProtectStructs[gBattlerAttacker].notFirstStrike) - gBattlescriptCurrInstr = BattleScript_MoveHPDrain; - else - gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss; - - effect = 1; - } - break; - case ABILITY_WATER_ABSORB: - if (moveType == TYPE_WATER && gBattleMoves[move].power != 0) - { - if (gProtectStructs[gBattlerAttacker].notFirstStrike) - gBattlescriptCurrInstr = BattleScript_MoveHPDrain; - else - gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss; - - effect = 1; - } - break; - case ABILITY_FLASH_FIRE: - if (moveType == TYPE_FIRE && !(gBattleMons[battler].status1 & STATUS1_FREEZE)) - { - if (!(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_FLASH_FIRE)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - if (gProtectStructs[gBattlerAttacker].notFirstStrike) - gBattlescriptCurrInstr = BattleScript_FlashFireBoost; - else - gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss; - - gBattleResources->flags->flags[battler] |= RESOURCE_FLAG_FLASH_FIRE; - effect = 2; - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - if (gProtectStructs[gBattlerAttacker].notFirstStrike) - gBattlescriptCurrInstr = BattleScript_FlashFireBoost; - else - gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss; - - effect = 2; - } - } - break; - } - if (effect == 1) - { - if (gBattleMons[battler].maxHP == gBattleMons[battler].hp) - { - if ((gProtectStructs[gBattlerAttacker].notFirstStrike)) - gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless; - else - gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless_PPLoss; - } - else - { - gBattleMoveDamage = gBattleMons[battler].maxHP / 4; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - gBattleMoveDamage *= -1; - } - } + gBattleWeather = (WEATHER_RAIN_PERMANENT | WEATHER_RAIN_TEMPORARY); + BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates); + gBattleScripting.battler = battler; + effect++; } break; - case ABILITYEFFECT_CONTACT: // 4 - switch (gLastUsedAbility) + case ABILITY_SAND_STREAM: + if (!(gBattleWeather & WEATHER_SANDSTORM_PERMANENT)) { - case ABILITY_COLOR_CHANGE: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && move != MOVE_STRUGGLE - && gBattleMoves[move].power != 0 - && TARGET_TURN_DAMAGED - && !IS_BATTLER_OF_TYPE(battler, moveType) - && gBattleMons[battler].hp != 0) - { - SET_BATTLER_TYPE(battler, moveType); - PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_ColorChangeActivates; - effect++; - } - break; - case ABILITY_ROUGH_SKIN: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && gBattleMons[gBattlerAttacker].hp != 0 - && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && TARGET_TURN_DAMAGED - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)) - { - gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_RoughSkinActivates; - effect++; - } - break; - case ABILITY_EFFECT_SPORE: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && gBattleMons[gBattlerAttacker].hp != 0 - && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && TARGET_TURN_DAMAGED - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) - && (Random() % 10) == 0) - { - do - { - gBattleCommunication[MOVE_EFFECT_BYTE] = Random() & 3; - } while (gBattleCommunication[MOVE_EFFECT_BYTE] == 0); - - if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN) - gBattleCommunication[MOVE_EFFECT_BYTE] += 2; // 5 MOVE_EFFECT_PARALYSIS - - gBattleCommunication[MOVE_EFFECT_BYTE] += MOVE_EFFECT_AFFECTS_USER; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; - gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; - effect++; - } - break; - case ABILITY_POISON_POINT: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && gBattleMons[gBattlerAttacker].hp != 0 - && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && TARGET_TURN_DAMAGED - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) - && (Random() % 3) == 0) - { - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_POISON; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; - gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; - effect++; - } - break; - case ABILITY_STATIC: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && gBattleMons[gBattlerAttacker].hp != 0 - && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && TARGET_TURN_DAMAGED - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) - && (Random() % 3) == 0) - { - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; - gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; - effect++; - } - break; - case ABILITY_FLAME_BODY: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && gBattleMons[gBattlerAttacker].hp != 0 - && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) - && TARGET_TURN_DAMAGED - && (Random() % 3) == 0) - { - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; - gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; - effect++; - } - break; - case ABILITY_CUTE_CHARM: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && gBattleMons[gBattlerAttacker].hp != 0 - && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) - && TARGET_TURN_DAMAGED - && gBattleMons[gBattlerTarget].hp != 0 - && (Random() % 3) == 0 - && gBattleMons[gBattlerAttacker].ability != ABILITY_OBLIVIOUS - && GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) - && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) - && GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != MON_GENDERLESS - && GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) != MON_GENDERLESS) - { - gBattleMons[gBattlerAttacker].status2 |= STATUS2_INFATUATED_WITH(gBattlerTarget); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_CuteCharmActivates; - effect++; - } - break; + gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); + BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates); + gBattleScripting.battler = battler; + effect++; } break; - case ABILITYEFFECT_IMMUNITY: // 5 - for (battler = 0; battler < gBattlersCount; battler++) + case ABILITY_DROUGHT: + if (!(gBattleWeather & WEATHER_SUN_PERMANENT)) { - switch (gBattleMons[battler].ability) - { - case ABILITY_IMMUNITY: - if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER)) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); - effect = 1; - } - break; - case ABILITY_OWN_TEMPO: - if (gBattleMons[battler].status2 & STATUS2_CONFUSION) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); - effect = 2; - } - break; - case ABILITY_LIMBER: - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); - effect = 1; - } - break; - case ABILITY_INSOMNIA: - case ABILITY_VITAL_SPIRIT: - if (gBattleMons[battler].status1 & STATUS1_SLEEP) - { - gBattleMons[battler].status2 &= ~(STATUS2_NIGHTMARE); - StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); - effect = 1; - } - break; - case ABILITY_WATER_VEIL: - if (gBattleMons[battler].status1 & STATUS1_BURN) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); - effect = 1; - } - break; - case ABILITY_MAGMA_ARMOR: - if (gBattleMons[battler].status1 & STATUS1_FREEZE) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); - effect = 1; - } - break; - case ABILITY_OBLIVIOUS: - if (gBattleMons[battler].status2 & STATUS2_INFATUATION) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); - effect = 3; - } - break; - } - if (effect) - { - switch (effect) - { - case 1: // status cleared - gBattleMons[battler].status1 = 0; - break; - case 2: // get rid of confusion - gBattleMons[battler].status2 &= ~(STATUS2_CONFUSION); - break; - case 3: // get rid of infatuation - gBattleMons[battler].status2 &= ~(STATUS2_INFATUATION); - break; - } - - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_AbilityCuredStatus; - gBattleScripting.battler = battler; - gActiveBattler = battler; - BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1); - MarkBattlerForControllerExec(gActiveBattler); - return effect; - } + gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); + BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); + gBattleScripting.battler = battler; + effect++; } break; - case ABILITYEFFECT_FORECAST: // 6 - for (battler = 0; battler < gBattlersCount; battler++) + case ABILITY_INTIMIDATE: + if (!(gSpecialStatuses[battler].intimidatedMon)) { - if (gBattleMons[battler].ability == ABILITY_FORECAST) + gStatuses3[battler] |= STATUS3_INTIMIDATE_POKES; + gSpecialStatuses[battler].intimidatedMon = 1; + } + break; + case ABILITY_FORECAST: + effect = CastformDataTypeChange(battler); + if (effect != 0) + { + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); + gBattleScripting.battler = battler; + *(&gBattleStruct->formToChangeInto) = effect - 1; + } + break; + case ABILITY_TRACE: + if (!(gSpecialStatuses[battler].traced)) + { + gStatuses3[battler] |= STATUS3_TRACE; + gSpecialStatuses[battler].traced = 1; + } + break; + case ABILITY_CLOUD_NINE: + case ABILITY_AIR_LOCK: + { + // that's a weird choice for a variable, why not use i or battler? + for (target1 = 0; target1 < gBattlersCount; target1++) { - effect = CastformDataTypeChange(battler); - if (effect) + effect = CastformDataTypeChange(target1); + if (effect != 0) { BattleScriptPushCursorAndCallback(BattleScript_CastformChange); - gBattleScripting.battler = battler; + gBattleScripting.battler = target1; *(&gBattleStruct->formToChangeInto) = effect - 1; - return effect; - } - } - } - break; - case ABILITYEFFECT_SYNCHRONIZE: // 7 - if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT)) - { - gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); - gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); - if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC) - gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON; - - gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect + MOVE_EFFECT_AFFECTS_USER; - gBattleScripting.battler = gBattlerTarget; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_SynchronizeActivates; - gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; - effect++; - } - break; - case ABILITYEFFECT_ATK_SYNCHRONIZE: // 8 - if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT)) - { - gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); - gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); - if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC) - gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON; - - gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect; - gBattleScripting.battler = gBattlerAttacker; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_SynchronizeActivates; - gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; - effect++; - } - break; - case ABILITYEFFECT_INTIMIDATE1: // 9 - for (i = 0; i < gBattlersCount; i++) - { - if (gBattleMons[i].ability == ABILITY_INTIMIDATE && gStatuses3[i] & STATUS3_INTIMIDATE_POKES) - { - gLastUsedAbility = ABILITY_INTIMIDATE; - gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES); - BattleScriptPushCursorAndCallback(BattleScript_82DB4B8); - gBattleStruct->intimidateBattler = i; - effect++; - break; - } - } - break; - case ABILITYEFFECT_TRACE: // 11 - for (i = 0; i < gBattlersCount; i++) - { - if (gBattleMons[i].ability == ABILITY_TRACE && (gStatuses3[i] & STATUS3_TRACE)) - { - u8 target2; - side = (GetBattlerPosition(i) ^ BIT_SIDE) & BIT_SIDE; // side of the opposing pokemon - target1 = GetBattlerAtPosition(side); - target2 = GetBattlerAtPosition(side + BIT_FLANK); - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0 - && gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0) - { - gActiveBattler = GetBattlerAtPosition(((Random() & 1) * 2) | side); - gBattleMons[i].ability = gBattleMons[gActiveBattler].ability; - gLastUsedAbility = gBattleMons[gActiveBattler].ability; - effect++; - } - else if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0) - { - gActiveBattler = target1; - gBattleMons[i].ability = gBattleMons[gActiveBattler].ability; - gLastUsedAbility = gBattleMons[gActiveBattler].ability; - effect++; - } - else if (gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0) - { - gActiveBattler = target2; - gBattleMons[i].ability = gBattleMons[gActiveBattler].ability; - gLastUsedAbility = gBattleMons[gActiveBattler].ability; - effect++; - } - } - else - { - gActiveBattler = target1; - if (gBattleMons[target1].ability && gBattleMons[target1].hp) - { - gBattleMons[i].ability = gBattleMons[target1].ability; - gLastUsedAbility = gBattleMons[target1].ability; - effect++; - } - } - if (effect) - { - BattleScriptPushCursorAndCallback(BattleScript_TraceActivates); - gStatuses3[i] &= ~(STATUS3_TRACE); - gBattleScripting.battler = i; - - PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBattler, gBattlerPartyIndexes[gActiveBattler]) - PREPARE_ABILITY_BUFFER(gBattleTextBuff2, gLastUsedAbility) break; } } } break; - case ABILITYEFFECT_INTIMIDATE2: // 10 - for (i = 0; i < gBattlersCount; i++) - { - if (gBattleMons[i].ability == ABILITY_INTIMIDATE && (gStatuses3[i] & STATUS3_INTIMIDATE_POKES)) - { - gLastUsedAbility = ABILITY_INTIMIDATE; - gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_82DB4C1; - gBattleStruct->intimidateBattler = i; - effect++; - break; - } - } - break; - case ABILITYEFFECT_CHECK_OTHER_SIDE: // 12 - side = GetBattlerSide(battler); - for (i = 0; i < gBattlersCount; i++) - { - if (GetBattlerSide(i) != side && gBattleMons[i].ability == ability) - { - gLastUsedAbility = ability; - effect = i + 1; - } - } - break; - case ABILITYEFFECT_CHECK_BATTLER_SIDE: // 13 - side = GetBattlerSide(battler); - for (i = 0; i < gBattlersCount; i++) - { - if (GetBattlerSide(i) == side && gBattleMons[i].ability == ability) - { - gLastUsedAbility = ability; - effect = i + 1; - } - } - break; - case ABILITYEFFECT_CHECK_ON_FIELD: // 19 - for (i = 0; i < gBattlersCount; i++) - { - if (gBattleMons[i].ability == ability && gBattleMons[i].hp != 0) - { - gLastUsedAbility = ability; - effect = i + 1; - } - } - break; - case ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER: // 15 - for (i = 0; i < gBattlersCount; i++) - { - if (gBattleMons[i].ability == ability && i != battler) - { - gLastUsedAbility = ability; - effect = i + 1; - } - } - break; - case ABILITYEFFECT_COUNT_OTHER_SIDE: // 16 - side = GetBattlerSide(battler); - for (i = 0; i < gBattlersCount; i++) - { - if (GetBattlerSide(i) != side && gBattleMons[i].ability == ability) - { - gLastUsedAbility = ability; - effect++; - } - } - break; - case ABILITYEFFECT_COUNT_BATTLER_SIDE: // 17 - side = GetBattlerSide(battler); - for (i = 0; i < gBattlersCount; i++) - { - if (GetBattlerSide(i) == side && gBattleMons[i].ability == ability) - { - gLastUsedAbility = ability; - effect++; - } - } - break; - case ABILITYEFFECT_COUNT_ON_FIELD: // 18 - for (i = 0; i < gBattlersCount; i++) - { - if (gBattleMons[i].ability == ability && i != battler) - { - gLastUsedAbility = ability; - effect++; - } - } - break; } + break; + case ABILITYEFFECT_ENDTURN: // 1 + if (gBattleMons[battler].hp != 0) + { + gBattlerAttacker = battler; + switch (gLastUsedAbility) + { + case ABILITY_RAIN_DISH: + if (WEATHER_HAS_EFFECT && (gBattleWeather & WEATHER_RAIN_ANY) + && gBattleMons[battler].maxHP > gBattleMons[battler].hp) + { + gLastUsedAbility = ABILITY_RAIN_DISH; // why + BattleScriptPushCursorAndCallback(BattleScript_RainDishActivates); + gBattleMoveDamage = gBattleMons[battler].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + effect++; + } + break; + case ABILITY_SHED_SKIN: + if ((gBattleMons[battler].status1 & STATUS1_ANY) && (Random() % 3) == 0) + { + if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON)) + StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); + if (gBattleMons[battler].status1 & STATUS1_SLEEP) + StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); + if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) + StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); + if (gBattleMons[battler].status1 & STATUS1_BURN) + StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); + if (gBattleMons[battler].status1 & STATUS1_FREEZE) + StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); + gBattleMons[battler].status1 = 0; + gBattleMons[battler].status2 &= ~(STATUS2_NIGHTMARE); // fix nightmare glitch + gBattleScripting.battler = gActiveBattler = battler; + BattleScriptPushCursorAndCallback(BattleScript_ShedSkinActivates); + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); + MarkBattlerForControllerExec(gActiveBattler); + effect++; + } + break; + case ABILITY_SPEED_BOOST: + if (gBattleMons[battler].statStages[STAT_SPEED] < 0xC && gDisableStructs[battler].isFirstTurn != 2) + { + gBattleMons[battler].statStages[STAT_SPEED]++; + gBattleScripting.animArg1 = 0x11; + gBattleScripting.animArg2 = 0; + BattleScriptPushCursorAndCallback(BattleScript_SpeedBoostActivates); + gBattleScripting.battler = battler; + effect++; + } + break; + case ABILITY_TRUANT: + gDisableStructs[gBattlerAttacker].truantCounter ^= 1; + break; + } + } + break; + case ABILITYEFFECT_MOVES_BLOCK: // 2 + if (gLastUsedAbility == ABILITY_SOUNDPROOF) + { + for (i = 0; sSoundMovesTable[i] != 0xFFFF; i++) + { + if (sSoundMovesTable[i] == move) + break; + } + if (sSoundMovesTable[i] != 0xFFFF) + { + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS) + gHitMarker |= HITMARKER_NO_PPDEDUCT; + gBattlescriptCurrInstr = BattleScript_SoundproofProtected; + effect = 1; + } + } + break; + case ABILITYEFFECT_ABSORBING: // 3 + if (move) + { + u8 statId; + switch (gLastUsedAbility) + { + case ABILITY_VOLT_ABSORB: + if (moveType == TYPE_ELECTRIC) + effect = 1; + break; + case ABILITY_WATER_ABSORB: + case ABILITY_DRY_SKIN: + if (moveType == TYPE_WATER) + effect = 1; + break; + case ABILITY_MOTOR_DRIVE: + if (moveType == TYPE_ELECTRIC) + effect = 2, statId = STAT_SPEED; + break; + case ABILITY_LIGHTNING_ROD: + if (moveType == TYPE_ELECTRIC) + effect = 2, statId = STAT_SPATK; + break; + case ABILITY_STORM_DRAIN: + if (moveType == TYPE_WATER) + effect = 2, statId = STAT_SPATK; + break; + case ABILITY_SAP_SIPPER: + if (moveArg == TYPE_GRASS) + effect = 2, statId = STAT_ATK; + break; + case ABILITY_FLASH_FIRE: + if (moveType == TYPE_FIRE && !(gBattleMons[battler].status1 & STATUS1_FREEZE)) + { + if (!(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_FLASH_FIRE)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + if (gProtectStructs[gBattlerAttacker].notFirstStrike) + gBattlescriptCurrInstr = BattleScript_FlashFireBoost; + else + gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss; - if (effect && caseID < ABILITYEFFECT_CHECK_OTHER_SIDE && gLastUsedAbility != 0xFF) - RecordAbilityBattle(battler, gLastUsedAbility); + gBattleResources->flags->flags[battler] |= RESOURCE_FLAG_FLASH_FIRE; + effect = 2; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + if (gProtectStructs[gBattlerAttacker].notFirstStrike) + gBattlescriptCurrInstr = BattleScript_FlashFireBoost; + else + gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss; + + effect = 2; + } + } + break; + } + if (effect == 1) // Drain Hp ability. + { + if (gBattleMons[battler].maxHP == gBattleMons[battler].hp) + { + if ((gProtectStructs[gBattlerAttacker].notFirstStrike)) + gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless; + else + gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless_PPLoss; + } + else + { + if (gProtectStructs[gBattlerAttacker].notFirstStrike) + gBattlescriptCurrInstr = BattleScript_MoveHPDrain; + else + gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss; + + gBattleMoveDamage = gBattleMons[battler].maxHP / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + } + } + else if (effect == 2) // Boost Stat ability; + { + if (gBattleMons[battler].statStages[statId] == 0xC) + { + if ((gProtectStructs[gBattlerAttacker].notFirstStrike)) + gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless; + else + gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless_PPLoss; + } + else + { + if (gProtectStructs[gBattlerAttacker].notFirstStrike) + gBattlescriptCurrInstr = BattleScript_MoveStatDrain; + else + gBattlescriptCurrInstr = BattleScript_MoveStatDrain_PPLoss; + + SET_STATCHANGER(statId, 1, FALSE); + gBattleMons[battler].statStages[statId]++; + PREPARE_STAT_BUFFER(gBattleTextBuff1, statId); + } + } + } + break; + case ABILITYEFFECT_CONTACT: // 4 + switch (gLastUsedAbility) + { + case ABILITY_ANGER_POINT: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gIsCriticalHit + && TARGET_TURN_DAMAGED + && IsBattlerAlive(battler) + && gBattleMons[battler].statStages[STAT_ATK] != 0xC) + { + gBattleMons[battler].statStages[STAT_ATK] = 0xC; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AngryPointActivates; + effect++; + } + break; + case ABILITY_COLOR_CHANGE: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && move != MOVE_STRUGGLE + && gBattleMoves[move].power != 0 + && TARGET_TURN_DAMAGED + && !IS_BATTLER_OF_TYPE(battler, moveType) + && gBattleMons[battler].hp != 0) + { + SET_BATTLER_TYPE(battler, moveType); + PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ColorChangeActivates; + effect++; + } + break; + case ABILITY_ROUGH_SKIN: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)) + { + gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_RoughSkinActivates; + effect++; + } + break; + case ABILITY_EFFECT_SPORE: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && (Random() % 10) == 0) + { + do + { + gBattleCommunication[MOVE_EFFECT_BYTE] = Random() & 3; + } while (gBattleCommunication[MOVE_EFFECT_BYTE] == 0); + + if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN) + gBattleCommunication[MOVE_EFFECT_BYTE] += 2; // 5 MOVE_EFFECT_PARALYSIS + + gBattleCommunication[MOVE_EFFECT_BYTE] += MOVE_EFFECT_AFFECTS_USER; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + effect++; + } + break; + case ABILITY_POISON_POINT: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && (Random() % 3) == 0) + { + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_POISON; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + effect++; + } + break; + case ABILITY_STATIC: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && (Random() % 3) == 0) + { + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + effect++; + } + break; + case ABILITY_FLAME_BODY: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && TARGET_TURN_DAMAGED + && (Random() % 3) == 0) + { + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + effect++; + } + break; + case ABILITY_CUTE_CHARM: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && TARGET_TURN_DAMAGED + && gBattleMons[gBattlerTarget].hp != 0 + && (Random() % 3) == 0 + && gBattleMons[gBattlerAttacker].ability != ABILITY_OBLIVIOUS + && GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) + && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) + && GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != MON_GENDERLESS + && GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) != MON_GENDERLESS) + { + gBattleMons[gBattlerAttacker].status2 |= STATUS2_INFATUATED_WITH(gBattlerTarget); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_CuteCharmActivates; + effect++; + } + break; + } + break; + case ABILITYEFFECT_IMMUNITY: // 5 + for (battler = 0; battler < gBattlersCount; battler++) + { + switch (gBattleMons[battler].ability) + { + case ABILITY_IMMUNITY: + if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER)) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); + effect = 1; + } + break; + case ABILITY_OWN_TEMPO: + if (gBattleMons[battler].status2 & STATUS2_CONFUSION) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); + effect = 2; + } + break; + case ABILITY_LIMBER: + if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); + effect = 1; + } + break; + case ABILITY_INSOMNIA: + case ABILITY_VITAL_SPIRIT: + if (gBattleMons[battler].status1 & STATUS1_SLEEP) + { + gBattleMons[battler].status2 &= ~(STATUS2_NIGHTMARE); + StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); + effect = 1; + } + break; + case ABILITY_WATER_VEIL: + if (gBattleMons[battler].status1 & STATUS1_BURN) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); + effect = 1; + } + break; + case ABILITY_MAGMA_ARMOR: + if (gBattleMons[battler].status1 & STATUS1_FREEZE) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); + effect = 1; + } + break; + case ABILITY_OBLIVIOUS: + if (gBattleMons[battler].status2 & STATUS2_INFATUATION) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); + effect = 3; + } + break; + } + if (effect) + { + switch (effect) + { + case 1: // status cleared + gBattleMons[battler].status1 = 0; + break; + case 2: // get rid of confusion + gBattleMons[battler].status2 &= ~(STATUS2_CONFUSION); + break; + case 3: // get rid of infatuation + gBattleMons[battler].status2 &= ~(STATUS2_INFATUATION); + break; + } + + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AbilityCuredStatus; + gBattleScripting.battler = battler; + gActiveBattler = battler; + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1); + MarkBattlerForControllerExec(gActiveBattler); + return effect; + } + } + break; + case ABILITYEFFECT_FORECAST: // 6 + for (battler = 0; battler < gBattlersCount; battler++) + { + if (gBattleMons[battler].ability == ABILITY_FORECAST) + { + effect = CastformDataTypeChange(battler); + if (effect) + { + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); + gBattleScripting.battler = battler; + *(&gBattleStruct->formToChangeInto) = effect - 1; + return effect; + } + } + } + break; + case ABILITYEFFECT_SYNCHRONIZE: // 7 + if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT)) + { + gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); + gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC) + gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON; + + gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect + MOVE_EFFECT_AFFECTS_USER; + gBattleScripting.battler = gBattlerTarget; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SynchronizeActivates; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + effect++; + } + break; + case ABILITYEFFECT_ATK_SYNCHRONIZE: // 8 + if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT)) + { + gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); + gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC) + gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON; + + gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect; + gBattleScripting.battler = gBattlerAttacker; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SynchronizeActivates; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + effect++; + } + break; + case ABILITYEFFECT_INTIMIDATE1: // 9 + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleMons[i].ability == ABILITY_INTIMIDATE && gStatuses3[i] & STATUS3_INTIMIDATE_POKES) + { + gLastUsedAbility = ABILITY_INTIMIDATE; + gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES); + BattleScriptPushCursorAndCallback(BattleScript_82DB4B8); + gBattleStruct->intimidateBattler = i; + effect++; + break; + } + } + break; + case ABILITYEFFECT_TRACE: // 11 + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleMons[i].ability == ABILITY_TRACE && (gStatuses3[i] & STATUS3_TRACE)) + { + u8 target2; + side = (GetBattlerPosition(i) ^ BIT_SIDE) & BIT_SIDE; // side of the opposing pokemon + target1 = GetBattlerAtPosition(side); + target2 = GetBattlerAtPosition(side + BIT_FLANK); + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0 + && gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0) + { + gActiveBattler = GetBattlerAtPosition(((Random() & 1) * 2) | side); + gBattleMons[i].ability = gBattleMons[gActiveBattler].ability; + gLastUsedAbility = gBattleMons[gActiveBattler].ability; + effect++; + } + else if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0) + { + gActiveBattler = target1; + gBattleMons[i].ability = gBattleMons[gActiveBattler].ability; + gLastUsedAbility = gBattleMons[gActiveBattler].ability; + effect++; + } + else if (gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0) + { + gActiveBattler = target2; + gBattleMons[i].ability = gBattleMons[gActiveBattler].ability; + gLastUsedAbility = gBattleMons[gActiveBattler].ability; + effect++; + } + } + else + { + gActiveBattler = target1; + if (gBattleMons[target1].ability && gBattleMons[target1].hp) + { + gBattleMons[i].ability = gBattleMons[target1].ability; + gLastUsedAbility = gBattleMons[target1].ability; + effect++; + } + } + if (effect) + { + BattleScriptPushCursorAndCallback(BattleScript_TraceActivates); + gStatuses3[i] &= ~(STATUS3_TRACE); + gBattleScripting.battler = i; + + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBattler, gBattlerPartyIndexes[gActiveBattler]) + PREPARE_ABILITY_BUFFER(gBattleTextBuff2, gLastUsedAbility) + break; + } + } + } + break; + case ABILITYEFFECT_INTIMIDATE2: // 10 + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleMons[i].ability == ABILITY_INTIMIDATE && (gStatuses3[i] & STATUS3_INTIMIDATE_POKES)) + { + gLastUsedAbility = ABILITY_INTIMIDATE; + gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_82DB4C1; + gBattleStruct->intimidateBattler = i; + effect++; + break; + } + } + break; + case ABILITYEFFECT_CHECK_OTHER_SIDE: // 12 + side = GetBattlerSide(battler); + for (i = 0; i < gBattlersCount; i++) + { + if (GetBattlerSide(i) != side && gBattleMons[i].ability == ability) + { + gLastUsedAbility = ability; + effect = i + 1; + } + } + break; + case ABILITYEFFECT_CHECK_BATTLER_SIDE: // 13 + side = GetBattlerSide(battler); + for (i = 0; i < gBattlersCount; i++) + { + if (GetBattlerSide(i) == side && gBattleMons[i].ability == ability) + { + gLastUsedAbility = ability; + effect = i + 1; + } + } + break; + case ABILITYEFFECT_CHECK_ON_FIELD: // 19 + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleMons[i].ability == ability && gBattleMons[i].hp != 0) + { + gLastUsedAbility = ability; + effect = i + 1; + } + } + break; + case ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER: // 15 + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleMons[i].ability == ability && i != battler) + { + gLastUsedAbility = ability; + effect = i + 1; + } + } + break; + case ABILITYEFFECT_COUNT_OTHER_SIDE: // 16 + side = GetBattlerSide(battler); + for (i = 0; i < gBattlersCount; i++) + { + if (GetBattlerSide(i) != side && gBattleMons[i].ability == ability) + { + gLastUsedAbility = ability; + effect++; + } + } + break; + case ABILITYEFFECT_COUNT_BATTLER_SIDE: // 17 + side = GetBattlerSide(battler); + for (i = 0; i < gBattlersCount; i++) + { + if (GetBattlerSide(i) == side && gBattleMons[i].ability == ability) + { + gLastUsedAbility = ability; + effect++; + } + } + break; + case ABILITYEFFECT_COUNT_ON_FIELD: // 18 + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleMons[i].ability == ability && i != battler) + { + gLastUsedAbility = ability; + effect++; + } + } + break; } + if (effect && caseID < ABILITYEFFECT_CHECK_OTHER_SIDE && gLastUsedAbility != 0xFF) + RecordAbilityBattle(battler, gLastUsedAbility); + return effect; }