diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index a8b847e8d..e38ea4c8e 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -171,12 +171,21 @@ .4byte \ptr .endm - .macro jumpiftype battler:req, type:req, ptr:req + .macro jumpbasedontype battler:req, type:req, case:req, ptr:req .byte 0x22 .byte \battler .byte \type + .byte \case .4byte \ptr .endm + + .macro jumpiftype battler:req, type:req, ptr:req + jumpbasedontype \battler, \type, 1, \ptr + .endm + + .macro jumpifnottype battler:req, type:req, ptr:req + jumpbasedontype \battler, \type, 0, \ptr + .endm .macro getexp battler:req .byte 0x23 @@ -1728,3 +1737,10 @@ .macro dmgtocurrattackerhp manipulatedamage ATK80_CURR_ATTACKER_HP .endm + + .macro jumpifflowerveil jumpptr:req + jumpifnottype BS_TARGET, TYPE_GRASS, 1f + jumpifability BS_TARGET_SIDE, ABILITY_FLOWER_VEIL, \jumpptr + 1: + .endm + diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 663ae83d9..53f7d922a 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1818,6 +1818,7 @@ BattleScript_EffectSleep:: jumpifsubstituteblocks BattleScript_ButItFailed jumpifstatus BS_TARGET, STATUS1_SLEEP, BattleScript_AlreadyAsleep jumpifcantmakeasleep BattleScript_CantMakeAsleep + jumpifflowerveil BattleScript_FlowerVeilProtects jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifsideaffecting BS_TARGET, SIDE_STATUS_SAFEGUARD, BattleScript_SafeguardProtected @@ -1826,6 +1827,18 @@ BattleScript_EffectSleep:: setmoveeffect MOVE_EFFECT_SLEEP seteffectprimary goto BattleScript_MoveEnd + +BattleScript_FlowerVeilProtectsRet:: + pause 0x20 + call BattleScript_AbilityPopUp + printstring STRINGID_FLOWERVEILPROTECTED + waitmessage 0x40 + return + +BattleScript_FlowerVeilProtects: + call BattleScript_FlowerVeilProtectsRet + orhalfword gMoveResultFlags, MOVE_RESULT_FAILED + goto BattleScript_MoveEnd BattleScript_AlreadyAsleep:: setalreadystatusedmoveattempt BS_ATTACKER @@ -2265,6 +2278,7 @@ BattleScript_EffectToxic:: attackstring ppreduce jumpifability BS_TARGET, ABILITY_IMMUNITY, BattleScript_ImmunityProtected + jumpifflowerveil BattleScript_FlowerVeilProtects jumpifsubstituteblocks BattleScript_ButItFailed jumpifstatus BS_TARGET, STATUS1_POISON, BattleScript_AlreadyPoisoned jumpifstatus BS_TARGET, STATUS1_TOXIC_POISON, BattleScript_AlreadyPoisoned @@ -2587,6 +2601,7 @@ BattleScript_EffectPoison:: attackstring ppreduce jumpifability BS_TARGET, ABILITY_IMMUNITY, BattleScript_ImmunityProtected + jumpifflowerveil BattleScript_FlowerVeilProtects jumpifsubstituteblocks BattleScript_ButItFailed jumpifstatus BS_TARGET, STATUS1_POISON, BattleScript_AlreadyPoisoned jumpifstatus BS_TARGET, STATUS1_TOXIC_POISON, BattleScript_AlreadyPoisoned @@ -2608,6 +2623,7 @@ BattleScript_EffectParalyze: attackstring ppreduce jumpifability BS_TARGET, ABILITY_LIMBER, BattleScript_LimberProtected + jumpifflowerveil BattleScript_FlowerVeilProtects jumpifsubstituteblocks BattleScript_ButItFailed typecalc jumpifmovehadnoeffect BattleScript_ButItFailed @@ -3789,6 +3805,7 @@ BattleScript_EffectWillOWisp:: jumpifstatus BS_TARGET, STATUS1_BURN, BattleScript_AlreadyBurned jumpiftype BS_TARGET, TYPE_FIRE, BattleScript_NotAffected jumpifability BS_TARGET, ABILITY_WATER_VEIL, BattleScript_WaterVeilPrevents + jumpifflowerveil BattleScript_FlowerVeilProtects jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifsideaffecting BS_TARGET, SIDE_STATUS_SAFEGUARD, BattleScript_SafeguardProtected @@ -4050,6 +4067,7 @@ BattleScript_EffectYawn:: ppreduce jumpifability BS_TARGET, ABILITY_VITAL_SPIRIT, BattleScript_PrintBankAbilityMadeIneffective jumpifability BS_TARGET, ABILITY_INSOMNIA, BattleScript_PrintBankAbilityMadeIneffective + jumpifflowerveil BattleScript_FlowerVeilProtects jumpifsubstituteblocks BattleScript_ButItFailed jumpifsideaffecting BS_TARGET, SIDE_STATUS_SAFEGUARD, BattleScript_SafeguardProtected accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON @@ -4061,7 +4079,7 @@ BattleScript_EffectYawn:: waitmessage 0x40 goto BattleScript_MoveEnd BattleScript_PrintBankAbilityMadeIneffective:: - copybyte sBATTLER, sBATTLER_WITH_ABILITY + copybyte sBATTLER, gBattlerAbility BattleScript_PrintAbilityMadeIneffective:: pause 0x20 printstring STRINGID_PKMNSXMADEITINEFFECTIVE diff --git a/include/battle.h b/include/battle.h index 4f4597294..c186be6ae 100644 --- a/include/battle.h +++ b/include/battle.h @@ -620,7 +620,7 @@ struct BattleScripting u8 animArg2; u16 tripleKickPower; u8 atk49_state; - u8 battlerWithAbility; + u8 unused_15; u8 unused_16; u8 battler; u8 animTurn; diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 9ceb67ff4..e84500b78 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -14,6 +14,7 @@ void HandleBattleWindow(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags); bool8 UproarWakeUpCheck(u8 battlerId); bool32 DoesSubstituteBlockMove(u8 battlerAtk, u8 battlerDef, u32 move); bool32 CanUseLastResort(u8 battlerId); +u32 IsFlowerVeilProtected(u32 battler); extern void (* const gBattleScriptingCommandsTable[])(void); extern const u8 gUnknown_0831C494[][4]; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 6a352af56..efededa9d 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -300,5 +300,6 @@ extern const u8 BattleScript_PowderMoveNoEffect[]; extern const u8 BattleScript_GrassyTerrainLoop[]; extern const u8 BattleScript_VCreateStatLoss[]; extern const u8 BattleScript_SpikyShieldEffect[]; +extern const u8 BattleScript_FlowerVeilProtectsRet[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_util.h b/include/battle_util.h index d056fb018..0f940b51b 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -6,7 +6,7 @@ #define MOVE_LIMITATION_DISABLED (1 << 2) #define MOVE_LIMITATION_TORMENTED (1 << 3) #define MOVE_LIMITATION_TAUNT (1 << 4) -#define MOVE_LIMITATION_IMPRISON (1 << 5) +#define MOVE_LIMITATION_IMPRISON (1 << 5) #define ABILITYEFFECT_ON_SWITCHIN 0x0 #define ABILITYEFFECT_ENDTURN 0x1 @@ -20,23 +20,13 @@ #define ABILITYEFFECT_INTIMIDATE1 0x9 #define ABILITYEFFECT_INTIMIDATE2 0xA #define ABILITYEFFECT_TRACE 0xB -#define ABILITYEFFECT_CHECK_OTHER_SIDE 0xC -#define ABILITYEFFECT_CHECK_BATTLER_SIDE 0xD -#define ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER 0xF -#define ABILITYEFFECT_COUNT_OTHER_SIDE 0x10 -#define ABILITYEFFECT_COUNT_BATTLER_SIDE 0x11 -#define ABILITYEFFECT_COUNT_ON_FIELD 0x12 -#define ABILITYEFFECT_CHECK_ON_FIELD 0x13 #define ABILITYEFFECT_SWITCH_IN_WEATHER 0xFF -#define ABILITY_ON_OPPOSING_FIELD(battlerId, abilityId)(AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, battlerId, abilityId, 0, 0)) -#define ABILITY_ON_FIELD(abilityId)(AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, abilityId, 0, 0)) - #define ITEMEFFECT_ON_SWITCH_IN 0x0 #define ITEMEFFECT_MOVE_END 0x3 #define ITEMEFFECT_KINGSROCK_SHELLBELL 0x4 -#define WEATHER_HAS_EFFECT ((!ABILITY_ON_FIELD(ABILITY_CLOUD_NINE) && !ABILITY_ON_FIELD(ABILITY_AIR_LOCK))) +#define WEATHER_HAS_EFFECT ((!IsAbilityOnField(ABILITY_CLOUD_NINE) && !IsAbilityOnField(ABILITY_AIR_LOCK))) #define IS_WHOLE_SIDE_ALIVE(battler)((IsBattlerAlive(battler) && IsBattlerAlive(BATTLE_PARTNER(battler)))) @@ -72,6 +62,11 @@ bool8 HasNoMonsToSwitch(u8 battlerId, u8 r1, u8 r2); u8 CastformDataTypeChange(u8 battlerId); bool32 TryChangeBattleWeather(u8 battler, u32 weatherEnumId, bool32 viaAbility); u8 AbilityBattleEffects(u8 caseID, u8 battlerId, u8 ability, u8 special, u16 moveArg); +u32 GetBattlerAbility(u8 battlerId); +u32 IsAbilityOnSide(u32 battlerId, u32 ability); +u32 IsAbilityOnOpposingSide(u32 battlerId, u32 ability); +u32 IsAbilityOnField(u32 ability); +u32 IsAbilityOnFieldExcept(u32 battlerId, u32 ability); void BattleScriptExecute(const u8* BS_ptr); void BattleScriptPushCursorAndCallback(const u8* BS_ptr); u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn); @@ -79,7 +74,6 @@ void ClearFuryCutterDestinyBondGrudge(u8 battlerId); void HandleAction_RunBattleScript(void); u8 GetMoveTarget(u16 move, u8 setTarget); u8 IsMonDisobedient(void); -u32 GetBattlerAbility(u8 battlerId); u32 GetBattlerHoldEffect(u8 battlerId, bool32 checkNegating); u32 GetBattlerHoldEffectParam(u8 battlerId); bool32 IsMoveMakingContact(u16 move, u8 battlerAtk); diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 4118a8589..5b2df78f8 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -11,7 +11,7 @@ #define sB_ANIM_ARG2 gBattleScripting + 0x11 #define sTRIPLE_KICK_POWER gBattleScripting + 0x12 #define sMOVEEND_STATE gBattleScripting + 0x14 -#define sBATTLER_WITH_ABILITY gBattleScripting + 0x15 +#define sUNUSED_15 gBattleScripting + 0x15 #define sUNUSED_16 gBattleScripting + 0x16 #define sBATTLER gBattleScripting + 0x17 #define sB_ANIM_TURN gBattleScripting + 0x18 @@ -45,7 +45,7 @@ #define BS_BATTLER_0 7 #define BS_ATTACKER_WITH_PARTNER 4 // for atk98_status_icon_update #define BS_ATTACKER_SIDE 8 // for atk1E_jumpifability -#define BS_NOT_ATTACKER_SIDE 9 // for atk1E_jumpifability +#define BS_TARGET_SIDE 9 // for atk1E_jumpifability #define BS_SCRIPTING 10 #define BS_PLAYER1 11 #define BS_OPPONENT1 12 @@ -139,6 +139,7 @@ #define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 76 #define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 77 #define VARIOUS_JUMP_IF_ROAR_FAILS 78 +#define VARIOUS_JUMP_IF_FLOWER_VEIL 79 // 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 9f9425d0d..007ea7987 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -524,6 +524,7 @@ #define STRINGID_ELECTRICTERRAINPREVENTS 520 #define STRINGID_PSYCHICTERRAINPREVENTS 521 #define STRINGID_SAFETYGOOGLESPROTECTED 522 +#define STRINGID_FLOWERVEILPROTECTED 523 #define BATTLESTRINGS_COUNT 529 diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index ec0d20ad0..4011925d9 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -414,11 +414,11 @@ static bool8 ShouldSwitch(void) return FALSE; if (gStatuses3[gActiveBattler] & STATUS3_ROOTED) return FALSE; - if (ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_SHADOW_TAG)) + if (IsAbilityOnOpposingSide(gActiveBattler, ABILITY_SHADOW_TAG)) return FALSE; - if (ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_ARENA_TRAP)) // Misses the flying type and Levitate check. + if (IsAbilityOnOpposingSide(gActiveBattler, ABILITY_ARENA_TRAP)) // Misses the flying type and Levitate check. return FALSE; - if (ABILITY_ON_FIELD(ABILITY_MAGNET_PULL)) + if (IsAbilityOnField(ABILITY_MAGNET_PULL)) { if (gBattleMons[gActiveBattler].type1 == TYPE_STEEL) return FALSE; diff --git a/src/battle_main.c b/src/battle_main.c index 28d8dc0ee..f1e57a408 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3711,7 +3711,7 @@ u8 IsRunningFromBattleImpossible(void) return 2; } } - i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER, gActiveBattler, ABILITY_MAGNET_PULL, 0, 0); + i = IsAbilityOnFieldExcept(gActiveBattler, ABILITY_MAGNET_PULL); if (i != 0 && IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL)) { gBattleScripting.battler = i - 1; @@ -3902,11 +3902,11 @@ static void HandleTurnActionSelectionState(void) { BtlController_EmitChoosePokemon(0, PARTY_CANT_SWITCH, 6, ABILITY_NONE, gBattleStruct->field_60[gActiveBattler]); } - else if ((i = ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_SHADOW_TAG)) - || ((i = ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_ARENA_TRAP)) + else if ((i = IsAbilityOnOpposingSide(gActiveBattler, ABILITY_SHADOW_TAG)) + || ((i = IsAbilityOnOpposingSide(gActiveBattler, ABILITY_ARENA_TRAP)) && !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_FLYING) && gBattleMons[gActiveBattler].ability != ABILITY_LEVITATE) - || ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER, gActiveBattler, ABILITY_MAGNET_PULL, 0, 0)) + || ((i = IsAbilityOnFieldExcept(gActiveBattler, ABILITY_MAGNET_PULL)) && IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL))) { BtlController_EmitChoosePokemon(0, ((i - 1) << 4) | PARTY_ABILITY_PREVENTS, 6, gLastUsedAbility, gBattleStruct->field_60[gActiveBattler]); diff --git a/src/battle_message.c b/src/battle_message.c index 8b043adea..e141b9edf 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -649,9 +649,11 @@ static const u8 sText_GrassyTerrainHeals[] = _("{B_ATK_NAME_WITH_PREFIX} is heal static const u8 sText_ElectricTerrainPreventsSleep[] = _("{B_DEF_NAME_WITH_PREFIX} surrounds itself\nwith electrified terrain!"); static const u8 sText_PsychicTerrainPreventsPriority[] = _("{B_DEF_NAME_WITH_PREFIX} surrounds itself\nwith psychic terrain!"); static const u8 sText_SafetyGooglesProtected[] = _("{B_DEF_NAME_WITH_PREFIX} is not affected\nthanks to its {B_LAST_ITEM}!"); +static const u8 sText_FlowerVeilProtected[] = _("{B_DEF_NAME_WITH_PREFIX} surrounded itself\nwith a veil of petals!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_FLOWERVEILPROTECTED - 12] = sText_FlowerVeilProtected, [STRINGID_SAFETYGOOGLESPROTECTED - 12] = sText_SafetyGooglesProtected, [STRINGID_SPECTRALTHIEFSTEAL - 12] = sText_SpectralThiefSteal, [STRINGID_BELCHCANTSELECT - 12] = sText_BelchCantUse, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index adad0eda0..29968b92e 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -109,7 +109,7 @@ static void atk1E_jumpifability(void); static void atk1F_jumpifsideaffecting(void); static void atk20_jumpifstat(void); static void atk21_jumpifstatus3condition(void); -static void atk22_jumpiftype(void); +static void atk22_jumpbasedontype(void); static void atk23_getexp(void); static void atk24(void); static void atk25_movevaluescleanup(void); @@ -368,7 +368,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk1F_jumpifsideaffecting, atk20_jumpifstat, atk21_jumpifstatus3condition, - atk22_jumpiftype, + atk22_jumpbasedontype, atk23_getexp, atk24, atk25_movevaluescleanup, @@ -1285,7 +1285,7 @@ static void atk02_attackstring(void) static void atk03_ppreduce(void) { - s32 ppToDeduct = 1; + s32 i, ppToDeduct = 1; if (gBattleControllerExecFlags) return; @@ -1295,14 +1295,22 @@ static void atk03_ppreduce(void) switch (gBattleMoves[gCurrentMove].target) { case MOVE_TARGET_FOES_AND_ALLY: - ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_ON_FIELD, gBattlerAttacker, ABILITY_PRESSURE, 0, 0); + for (i = 0; i < gBattlersCount; i++) + { + if (i != gBattlerAttacker && IsBattlerAlive(i)) + ppToDeduct += (GetBattlerAbility(i) == ABILITY_PRESSURE); + } break; case MOVE_TARGET_BOTH: case MOVE_TARGET_OPPONENTS_FIELD: - ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBattlerAttacker, ABILITY_PRESSURE, 0, 0); + for (i = 0; i < gBattlersCount; i++) + { + if (GetBattlerSide(i) != GetBattlerSide(gBattlerAttacker) && IsBattlerAlive(i)) + ppToDeduct += (GetBattlerAbility(i) == ABILITY_PRESSURE); + } break; default: - if (gBattlerAttacker != gBattlerTarget && gBattleMons[gBattlerTarget].ability == ABILITY_PRESSURE) + if (gBattlerAttacker != gBattlerTarget && GetBattlerAbility(gBattlerTarget) == ABILITY_PRESSURE) ppToDeduct++; break; } @@ -2004,7 +2012,7 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattleScripting.battler = gBattlerAttacker; } - if (gBattleMons[gEffectBattler].ability == ABILITY_SHIELD_DUST && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + if (GetBattlerAbility(gEffectBattler) == ABILITY_SHIELD_DUST && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) && !primary && gBattleScripting.moveEffect <= 9) INCREMENT_RESET_RETURN @@ -2026,7 +2034,7 @@ void SetMoveEffect(bool32 primary, u32 certain) { case STATUS1_SLEEP: // check active uproar - if (gBattleMons[gEffectBattler].ability != ABILITY_SOUNDPROOF) + if (GetBattlerAbility(gEffectBattler) != ABILITY_SOUNDPROOF) { for (gActiveBattler = 0; gActiveBattler < gBattlersCount && !(gBattleMons[gActiveBattler].status2 & STATUS2_UPROAR); @@ -2040,16 +2048,16 @@ void SetMoveEffect(bool32 primary, u32 certain) break; if (gActiveBattler != gBattlersCount) break; - if (gBattleMons[gEffectBattler].ability == ABILITY_VITAL_SPIRIT) - break; - if (gBattleMons[gEffectBattler].ability == ABILITY_INSOMNIA) + if (GetBattlerAbility(gEffectBattler) == ABILITY_VITAL_SPIRIT + || GetBattlerAbility(gEffectBattler) == ABILITY_INSOMNIA + || IsFlowerVeilProtected(gEffectBattler)) break; CancelMultiTurnMoves(gEffectBattler); statusChanged = TRUE; break; case STATUS1_POISON: - if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY + if (GetBattlerAbility(gEffectBattler) == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { gLastUsedAbility = ABILITY_IMMUNITY; @@ -2085,13 +2093,13 @@ void SetMoveEffect(bool32 primary, u32 certain) break; if (gBattleMons[gEffectBattler].status1) break; - if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY) + if (GetBattlerAbility(gEffectBattler) == ABILITY_IMMUNITY || IsFlowerVeilProtected(gEffectBattler)) break; statusChanged = TRUE; break; case STATUS1_BURN: - if (gBattleMons[gEffectBattler].ability == ABILITY_WATER_VEIL + if (GetBattlerAbility(gEffectBattler) == ABILITY_WATER_VEIL && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { gLastUsedAbility = ABILITY_WATER_VEIL; @@ -2122,7 +2130,7 @@ void SetMoveEffect(bool32 primary, u32 certain) } if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_FIRE)) break; - if (gBattleMons[gEffectBattler].ability == ABILITY_WATER_VEIL) + if (GetBattlerAbility(gEffectBattler) == ABILITY_WATER_VEIL || IsFlowerVeilProtected(gEffectBattler)) break; if (gBattleMons[gEffectBattler].status1) break; @@ -2138,14 +2146,14 @@ void SetMoveEffect(bool32 primary, u32 certain) break; if (noSunCanFreeze == 0) break; - if (gBattleMons[gEffectBattler].ability == ABILITY_MAGMA_ARMOR) + if (GetBattlerAbility(gEffectBattler) == ABILITY_MAGMA_ARMOR || IsFlowerVeilProtected(gEffectBattler)) break; CancelMultiTurnMoves(gEffectBattler); statusChanged = TRUE; break; case STATUS1_PARALYSIS: - if (gBattleMons[gEffectBattler].ability == ABILITY_LIMBER) + if (GetBattlerAbility(gEffectBattler) == ABILITY_LIMBER) { if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) { @@ -2181,7 +2189,7 @@ void SetMoveEffect(bool32 primary, u32 certain) } if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_ELECTRIC)) break; - if (gBattleMons[gEffectBattler].ability == ABILITY_LIMBER) + if (GetBattlerAbility(gEffectBattler) == ABILITY_LIMBER || IsFlowerVeilProtected(gEffectBattler)) break; if (gBattleMons[gEffectBattler].status1) break; @@ -2189,7 +2197,7 @@ void SetMoveEffect(bool32 primary, u32 certain) statusChanged = TRUE; break; case STATUS1_TOXIC_POISON: - if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + if (GetBattlerAbility(gEffectBattler) == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { gLastUsedAbility = ABILITY_IMMUNITY; RecordAbilityBattle(gEffectBattler, ABILITY_IMMUNITY); @@ -2222,7 +2230,7 @@ void SetMoveEffect(bool32 primary, u32 certain) break; if (!IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_POISON) && !IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_STEEL)) { - if (gBattleMons[gEffectBattler].ability == ABILITY_IMMUNITY) + if (GetBattlerAbility(gEffectBattler) == ABILITY_IMMUNITY || IsFlowerVeilProtected(gEffectBattler)) break; // It's redundant, because at this point we know the status1 value is 0. @@ -2269,8 +2277,7 @@ void SetMoveEffect(bool32 primary, u32 certain) || gBattleScripting.moveEffect == MOVE_EFFECT_PARALYSIS || gBattleScripting.moveEffect == MOVE_EFFECT_BURN) { - u8* synchronizeEffect = &gBattleStruct->synchronizeMoveEffect; - *synchronizeEffect = gBattleScripting.moveEffect; + gBattleStruct->synchronizeMoveEffect = gBattleScripting.moveEffect; gHitMarker |= HITMARKER_SYNCHRONISE_EFFECT; } return; @@ -2295,7 +2302,7 @@ void SetMoveEffect(bool32 primary, u32 certain) switch (gBattleScripting.moveEffect) { case MOVE_EFFECT_CONFUSION: - if (gBattleMons[gEffectBattler].ability == ABILITY_OWN_TEMPO + if (GetBattlerAbility(gEffectBattler) == ABILITY_OWN_TEMPO || gBattleMons[gEffectBattler].status2 & STATUS2_CONFUSION) { gBattlescriptCurrInstr++; @@ -2648,7 +2655,7 @@ void SetMoveEffect(bool32 primary, u32 certain) } break; case MOVE_EFFECT_KNOCK_OFF: - if (gBattleMons[gEffectBattler].ability == ABILITY_STICKY_HOLD) + if (GetBattlerAbility(gEffectBattler) == ABILITY_STICKY_HOLD) { if (gBattleMons[gEffectBattler].item == 0) { @@ -2991,48 +2998,45 @@ static void atk1D_jumpifstatus2(void) static void atk1E_jumpifability(void) { - u8 battlerId; - u8 ability = gBattlescriptCurrInstr[2]; - const u8* jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 3); + u32 battlerId; + bool32 hasAbility = FALSE; + u32 ability = gBattlescriptCurrInstr[2]; - if (gBattlescriptCurrInstr[1] == BS_ATTACKER_SIDE) + switch (gBattlescriptCurrInstr[1]) { - battlerId = AbilityBattleEffects(ABILITYEFFECT_CHECK_BATTLER_SIDE, gBattlerAttacker, ability, 0, 0); + default: + battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); + if (GetBattlerAbility(battlerId) == ability) + hasAbility = TRUE; + break; + case BS_ATTACKER_SIDE: + battlerId = IsAbilityOnSide(gBattlerAttacker, ability); if (battlerId) { - gLastUsedAbility = ability; - gBattlescriptCurrInstr = jumpPtr; - RecordAbilityBattle(battlerId - 1, gLastUsedAbility); - gBattleScripting.battlerWithAbility = battlerId - 1; + battlerId--; + hasAbility = TRUE; } - else - gBattlescriptCurrInstr += 7; + break; + case BS_TARGET_SIDE: + battlerId = IsAbilityOnOpposingSide(gBattlerAttacker, ability); + if (battlerId) + { + battlerId--; + hasAbility = TRUE; + } + break; } - else if (gBattlescriptCurrInstr[1] == BS_NOT_ATTACKER_SIDE) + + if (hasAbility) { - 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; + gLastUsedAbility = ability; + gBattlescriptCurrInstr = T2_READ_PTR(gBattlescriptCurrInstr + 3); + RecordAbilityBattle(battlerId, gLastUsedAbility); + gBattlerAbility = battlerId; } else { - battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); - if (gBattleMons[battlerId].ability == ability) - { - gLastUsedAbility = ability; - gBattlescriptCurrInstr = jumpPtr; - RecordAbilityBattle(battlerId, gLastUsedAbility); - gBattleScripting.battlerWithAbility = battlerId; - } - else - gBattlescriptCurrInstr += 7; + gBattlescriptCurrInstr += 7; } } @@ -3138,16 +3142,28 @@ static void atk21_jumpifstatus3condition(void) } } -static void atk22_jumpiftype(void) +static void atk22_jumpbasedontype(void) { u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); u8 type = gBattlescriptCurrInstr[2]; - const u8* jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 3); + const u8* jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 4); - if (IS_BATTLER_OF_TYPE(battlerId, type)) - gBattlescriptCurrInstr = jumpPtr; + // jumpiftype + if (gBattlescriptCurrInstr[3]) + { + if (IS_BATTLER_OF_TYPE(battlerId, type)) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 8; + } + // jumpifnottype else - gBattlescriptCurrInstr += 7; + { + if (!IS_BATTLER_OF_TYPE(battlerId, type)) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 8; + } } static void atk23_getexp(void) @@ -3918,7 +3934,7 @@ static void atk42_setroost(void) static void atk43_jumpifabilitypresent(void) { - if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, gBattlescriptCurrInstr[1], 0, 0)) + if (IsAbilityOnField(gBattlescriptCurrInstr[1])) gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2); else gBattlescriptCurrInstr += 6; @@ -6360,6 +6376,14 @@ static bool32 ClearDefogHazards(u8 battlerAtk, bool32 clear) return FALSE; } +u32 IsFlowerVeilProtected(u32 battler) +{ + if (IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) + return IsAbilityOnSide(battler, ABILITY_FLOWER_VEIL); + else + return 0; +} + static void atk76_various(void) { struct Pokemon *mon; @@ -7689,15 +7713,15 @@ bool8 UproarWakeUpCheck(u8 battlerId) static void atk84_jumpifcantmakeasleep(void) { const u8 *jumpPtr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + u32 ability = GetBattlerAbility(gBattlerTarget); if (UproarWakeUpCheck(gBattlerTarget)) { gBattlescriptCurrInstr = jumpPtr; } - else if (gBattleMons[gBattlerTarget].ability == ABILITY_INSOMNIA - || gBattleMons[gBattlerTarget].ability == ABILITY_VITAL_SPIRIT) + else if (ability == ABILITY_INSOMNIA || ability == ABILITY_VITAL_SPIRIT) { - gLastUsedAbility = gBattleMons[gBattlerTarget].ability; + gLastUsedAbility = ability; gBattleCommunication[MULTISTRING_CHOOSER] = 2; gBattlescriptCurrInstr = jumpPtr; RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); @@ -7851,8 +7875,8 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr gBattlescriptCurrInstr = BattleScript_ButItFailed; return STAT_CHANGE_DIDNT_WORK; } - else if ((gBattleMons[gActiveBattler].ability == ABILITY_CLEAR_BODY - || gBattleMons[gActiveBattler].ability == ABILITY_WHITE_SMOKE) + else if ((GetBattlerAbility(gActiveBattler) == ABILITY_CLEAR_BODY + || GetBattlerAbility(gActiveBattler) == ABILITY_WHITE_SMOKE) && !certain && gCurrentMove != MOVE_CURSE) { if (flags == STAT_CHANGE_BS_PTR) @@ -7867,14 +7891,34 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr gBattleScripting.battler = gActiveBattler; gBattlerAbility = gActiveBattler; gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss; - gLastUsedAbility = gBattleMons[gActiveBattler].ability; + gLastUsedAbility = GetBattlerAbility(gActiveBattler); RecordAbilityBattle(gActiveBattler, gLastUsedAbility); gSpecialStatuses[gActiveBattler].statLowered = 1; } } return STAT_CHANGE_DIDNT_WORK; } - else if (gBattleMons[gActiveBattler].ability == ABILITY_KEEN_EYE + else if ((index = IsFlowerVeilProtected(gActiveBattler)) && !certain) + { + if (flags == STAT_CHANGE_BS_PTR) + { + if (gSpecialStatuses[gActiveBattler].statLowered) + { + gBattlescriptCurrInstr = BS_ptr; + } + else + { + BattleScriptPush(BS_ptr); + gBattleScripting.battler = gActiveBattler; + gBattlerAbility = index - 1; + gBattlescriptCurrInstr = BattleScript_FlowerVeilProtectsRet; + gLastUsedAbility = ABILITY_FLOWER_VEIL; + gSpecialStatuses[gActiveBattler].statLowered = 1; + } + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (GetBattlerAbility(gActiveBattler) == ABILITY_KEEN_EYE && !certain && statId == STAT_ACC) { if (flags == STAT_CHANGE_BS_PTR) @@ -7883,12 +7927,12 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr gBattleScripting.battler = gActiveBattler; gBattlerAbility = gActiveBattler; gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; - gLastUsedAbility = gBattleMons[gActiveBattler].ability; + gLastUsedAbility = GetBattlerAbility(gActiveBattler); RecordAbilityBattle(gActiveBattler, gLastUsedAbility); } return STAT_CHANGE_DIDNT_WORK; } - else if (gBattleMons[gActiveBattler].ability == ABILITY_HYPER_CUTTER + else if (GetBattlerAbility(gActiveBattler) == ABILITY_HYPER_CUTTER && !certain && statId == STAT_ATK) { if (flags == STAT_CHANGE_BS_PTR) @@ -7897,12 +7941,12 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr gBattleScripting.battler = gActiveBattler; gBattlerAbility = gActiveBattler; gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; - gLastUsedAbility = gBattleMons[gActiveBattler].ability; + gLastUsedAbility = GetBattlerAbility(gActiveBattler); RecordAbilityBattle(gActiveBattler, gLastUsedAbility); } return STAT_CHANGE_DIDNT_WORK; } - else if (gBattleMons[gActiveBattler].ability == ABILITY_SHIELD_DUST && flags == 0) + else if (GetBattlerAbility(gActiveBattler) == ABILITY_SHIELD_DUST && flags == 0) { return STAT_CHANGE_DIDNT_WORK; } diff --git a/src/battle_util.c b/src/battle_util.c index af5bc99c2..67f73fc21 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3560,83 +3560,9 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA } } 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) + if (effect && gLastUsedAbility != 0xFF) RecordAbilityBattle(battler, gLastUsedAbility); if (effect && caseID <= ABILITYEFFECT_MOVE_END) gBattlerAbility = battler; @@ -3644,6 +3570,64 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA return effect; } +u32 GetBattlerAbility(u8 battlerId) +{ + if (gStatuses3[battlerId] & STATUS3_GASTRO_ACID) + return ABILITY_NONE; + else if ((gBattleMons[gBattlerAttacker].ability == ABILITY_MOLD_BREAKER + || gBattleMons[gBattlerAttacker].ability == ABILITY_TERAVOLT + || gBattleMons[gBattlerAttacker].ability == ABILITY_TURBOBLAZE) + && sAbilitiesAffectedByMoldBreaker[gBattleMons[battlerId].ability] + && gBattlerByTurnOrder[gCurrentTurnActionNumber] == gBattlerAttacker + && gActionsByTurnOrder[gBattlerByTurnOrder[gBattlerAttacker]] == B_ACTION_USE_MOVE + && gCurrentTurnActionNumber < gBattlersCount + && !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID)) + return ABILITY_NONE; + else + return gBattleMons[battlerId].ability; +} + +u32 IsAbilityOnSide(u32 battlerId, u32 ability) +{ + if (IsBattlerAlive(battlerId) && GetBattlerAbility(battlerId) == ability) + return battlerId + 1; + else if (IsBattlerAlive(BATTLE_PARTNER(battlerId)) && GetBattlerAbility(BATTLE_PARTNER(battlerId)) == ability) + return BATTLE_PARTNER(battlerId) + 1; + else + return 0; +} + +u32 IsAbilityOnOpposingSide(u32 battlerId, u32 ability) +{ + return IsAbilityOnSide(BATTLE_OPPOSITE(battlerId), ability); +} + +u32 IsAbilityOnField(u32 ability) +{ + u32 i; + + for (i = 0; i < gBattlersCount; i++) + { + if (IsBattlerAlive(i) && GetBattlerAbility(i) == ability) + return i + 1; + } + + return 0; +} + +u32 IsAbilityOnFieldExcept(u32 battlerId, u32 ability) +{ + u32 i; + + for (i = 0; i < gBattlersCount; i++) + { + if (i != battlerId && IsBattlerAlive(i) && GetBattlerAbility(i) == ability) + return i + 1; + } + + return 0; +} + void BattleScriptExecute(const u8 *BS_ptr) { gBattlescriptCurrInstr = BS_ptr; @@ -4372,7 +4356,7 @@ u8 GetMoveTarget(u16 move, u8 setTarget) targetBattler = Random() % gBattlersCount; } while (targetBattler == gBattlerAttacker || side == GetBattlerSide(targetBattler) || gAbsentBattlerFlags & gBitTable[targetBattler]); if (gBattleMoves[move].type == TYPE_ELECTRIC - && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBattlerAttacker, ABILITY_LIGHTNING_ROD, 0, 0) + && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_LIGHTNING_ROD) && gBattleMons[targetBattler].ability != ABILITY_LIGHTNING_ROD) { targetBattler ^= BIT_FLANK; @@ -4380,7 +4364,7 @@ u8 GetMoveTarget(u16 move, u8 setTarget) gSpecialStatuses[targetBattler].lightningRodRedirected = 1; } else if (gBattleMoves[move].type == TYPE_WATER - && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBattlerAttacker, ABILITY_STORM_DRAIN, 0, 0) + && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_STORM_DRAIN) && gBattleMons[targetBattler].ability != ABILITY_STORM_DRAIN) { targetBattler ^= BIT_FLANK; @@ -4564,23 +4548,6 @@ u8 IsMonDisobedient(void) } } -u32 GetBattlerAbility(u8 battlerId) -{ - if (gStatuses3[battlerId] & STATUS3_GASTRO_ACID) - return ABILITY_NONE; - else if ((gBattleMons[gBattlerAttacker].ability == ABILITY_MOLD_BREAKER - || gBattleMons[gBattlerAttacker].ability == ABILITY_TERAVOLT - || gBattleMons[gBattlerAttacker].ability == ABILITY_TURBOBLAZE) - && sAbilitiesAffectedByMoldBreaker[gBattleMons[battlerId].ability] - && gBattlerByTurnOrder[gCurrentTurnActionNumber] == gBattlerAttacker - && gActionsByTurnOrder[gBattlerByTurnOrder[gBattlerAttacker]] == B_ACTION_USE_MOVE - && gCurrentTurnActionNumber < gBattlersCount - && !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID)) - return ABILITY_NONE; - else - return gBattleMons[battlerId].ability; -} - u32 GetBattlerHoldEffect(u8 battlerId, bool32 checkNegating) { if (checkNegating) @@ -5052,10 +5019,10 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe } // field abilities - if ((ABILITY_ON_FIELD(ABILITY_DARK_AURA) && moveType == TYPE_DARK) - || (ABILITY_ON_FIELD(ABILITY_FAIRY_AURA) && moveType == TYPE_FAIRY)) + if ((IsAbilityOnField(ABILITY_DARK_AURA) && moveType == TYPE_DARK) + || (IsAbilityOnField(ABILITY_FAIRY_AURA) && moveType == TYPE_FAIRY)) { - if (ABILITY_ON_FIELD(ABILITY_AURA_BREAK)) + if (IsAbilityOnField(ABILITY_AURA_BREAK)) MulModifier(&modifier, UQ_4_12(0.75)); else MulModifier(&modifier, UQ_4_12(1.25));