diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 42219c7ee2..4f41d154ef 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -286,7 +286,11 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectHealPulse @ EFFECT_HEAL_PULSE .4byte BattleScript_EffectQuash @ EFFECT_QUASH .4byte BattleScript_EffectIonDeluge @ EFFECT_ION_DELUGE +#if B_USE_FROSTBITE == TRUE + .4byte BattleScript_EffectFrostbiteHit @ EFFECT_FREEZE_DRY +#else .4byte BattleScript_EffectFreezeHit @ EFFECT_FREEZE_DRY +#endif .4byte BattleScript_EffectTopsyTurvy @ EFFECT_TOPSY_TURVY .4byte BattleScript_EffectMistyTerrain @ EFFECT_MISTY_TERRAIN .4byte BattleScript_EffectGrassyTerrain @ EFFECT_GRASSY_TERRAIN @@ -424,6 +428,7 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectDireClaw @ EFFECT_DIRE_CLAW .4byte BattleScript_EffectBarbBarrage @ EFFECT_BARB_BARRAGE .4byte BattleScript_EffectRevivalBlessing @ EFFECT_REVIVAL_BLESSING + .4byte BattleScript_EffectFrostbiteHit @ EFFECT_FROSTBITE_HIT BattleScript_EffectRevivalBlessing:: attackcanceler @@ -576,6 +581,7 @@ BattleScript_AffectionBasedStatusHeal:: jumpifstatus BS_ATTACKER, STATUS1_PARALYSIS, BattleScript_AffectionBasedStatus_HealParalysisString jumpifstatus BS_ATTACKER, STATUS1_BURN, BattleScript_AffectionBasedStatus_HealBurnString jumpifstatus BS_ATTACKER, STATUS1_FREEZE, BattleScript_AffectionBasedStatus_HealFreezeString + jumpifstatus BS_ATTACKER, STATUS1_FROSTBITE, BattleScript_AffectionBasedStatus_HealFrostbiteString end2 BattleScript_AffectionBasedStatus_HealPoisonString: printstring STRINGID_ATTACKEREXPELLEDTHEPOISON @@ -591,6 +597,9 @@ BattleScript_AffectionBasedStatus_HealBurnString: goto BattleScript_AffectionBasedStatusHeal_Continue BattleScript_AffectionBasedStatus_HealFreezeString: printstring STRINGID_ATTACKERMELTEDTHEICE + goto BattleScript_AffectionBasedStatusHeal_Continue +BattleScript_AffectionBasedStatus_HealFrostbiteString: + printstring STRINGID_ATTACKERHEALEDITSFROSTBITE BattleScript_AffectionBasedStatusHeal_Continue: waitmessage B_WAIT_TIME_LONG clearstatus BS_ATTACKER @@ -3466,6 +3475,10 @@ BattleScript_EffectBurnHit:: setmoveeffect MOVE_EFFECT_BURN goto BattleScript_EffectHit +BattleScript_EffectFrostbiteHit:: + setmoveeffect MOVE_EFFECT_FROSTBITE + goto BattleScript_EffectHit + BattleScript_EffectSleepHit:: setmoveeffect MOVE_EFFECT_SLEEP goto BattleScript_EffectHit @@ -8127,6 +8140,11 @@ BattleScript_BurnTurnDmg:: waitmessage B_WAIT_TIME_LONG goto BattleScript_DoStatusTurnDmg +BattleScript_FrostbiteTurnDmg:: + printstring STRINGID_PKMNHURTBYFROSTBITE + waitmessage B_WAIT_TIME_LONG + goto BattleScript_DoStatusTurnDmg + BattleScript_MoveUsedIsFrozen:: printstring STRINGID_PKMNISFROZEN waitmessage B_WAIT_TIME_LONG @@ -8139,12 +8157,24 @@ BattleScript_MoveUsedUnfroze:: updatestatusicon BS_ATTACKER return +BattleScript_MoveUsedUnfrostbite:: + printfromtable gFrostbiteHealedStringIds + waitmessage B_WAIT_TIME_LONG + updatestatusicon BS_ATTACKER + return + BattleScript_DefrostedViaFireMove:: printstring STRINGID_PKMNWASDEFROSTED waitmessage B_WAIT_TIME_LONG updatestatusicon BS_TARGET return +BattleScript_FrostbiteHealedViaFireMove:: + printstring STRINGID_PKMNFROSTBITEHEALED + waitmessage B_WAIT_TIME_LONG + updatestatusicon BS_TARGET + return + BattleScript_MoveUsedIsParalyzed:: printstring STRINGID_PKMNISPARALYZED waitmessage B_WAIT_TIME_LONG @@ -8366,6 +8396,12 @@ BattleScript_MoveEffectBurn:: waitmessage B_WAIT_TIME_LONG goto BattleScript_UpdateEffectStatusIconRet +BattleScript_MoveEffectFrostbite:: + statusanimation BS_EFFECT_BATTLER + printfromtable gGotFrostbiteStringIds + waitmessage B_WAIT_TIME_LONG + goto BattleScript_UpdateEffectStatusIconRet + BattleScript_MoveEffectFreeze:: statusanimation BS_EFFECT_BATTLER printfromtable gGotFrozenStringIds @@ -9544,6 +9580,18 @@ BattleScript_BerryCureFrzRet:: removeitem BS_SCRIPTING return +BattleScript_BerryCureFsbEnd2:: + call BattleScript_BerryCureFrzRet + end2 + +BattleScript_BerryCureFsbRet:: + playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT + printstring STRINGID_PKMNSITEMHEALEDFROSTBITE + waitmessage B_WAIT_TIME_LONG + updatestatusicon BS_SCRIPTING + removeitem BS_SCRIPTING + return + BattleScript_BerryCureSlpEnd2:: call BattleScript_BerryCureSlpRet end2 diff --git a/graphics/battle_interface/status.png b/graphics/battle_interface/status.png index 9fae45b71f..0b212907e5 100644 Binary files a/graphics/battle_interface/status.png and b/graphics/battle_interface/status.png differ diff --git a/graphics/battle_interface/status2.png b/graphics/battle_interface/status2.png index af7ce05d3b..5d7f6459be 100644 Binary files a/graphics/battle_interface/status2.png and b/graphics/battle_interface/status2.png differ diff --git a/graphics/battle_interface/status3.png b/graphics/battle_interface/status3.png index d0febfb17c..7cc8cd56dc 100644 Binary files a/graphics/battle_interface/status3.png and b/graphics/battle_interface/status3.png differ diff --git a/graphics/battle_interface/status4.png b/graphics/battle_interface/status4.png index 9704a36119..c5ab2c5e11 100644 Binary files a/graphics/battle_interface/status4.png and b/graphics/battle_interface/status4.png differ diff --git a/graphics/interface/status_icons.png b/graphics/interface/status_icons.png index fe802d7f66..f93406cfd1 100644 Binary files a/graphics/interface/status_icons.png and b/graphics/interface/status_icons.png differ diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index d1319f0ca7..1a0fbc2645 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -130,6 +130,7 @@ bool32 IsSemiInvulnerable(u8 battlerDef, u16 move); // status checks bool32 AI_CanBeBurned(u8 battler, u16 ability); +bool32 AI_CanGetFrostbite(u8 battler, u16 ability); bool32 AI_CanBeConfused(u8 battler, u16 ability); bool32 AI_CanSleep(u8 battler, u16 ability); bool32 IsBattlerIncapacitated(u8 battler, u16 ability); @@ -140,6 +141,7 @@ bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u1 bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); bool32 ShouldBurnSelf(u8 battler, u16 ability); bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); +bool32 AI_CanGiveFrostbite(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGender, u8 defGender); bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof); u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move); @@ -170,10 +172,11 @@ bool32 SideHasMoveSplit(u8 battlerId, u8 split); // score increases void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score); -void IncreasePoisonScore(u8 battlerAtk, u8 battlerdef, u16 move, s16 *score); -void IncreaseBurnScore(u8 battlerAtk, u8 battlerdef, u16 move, s16 *score); +void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); +void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); +void IncreaseFrostbiteScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); -#endif //GUARD_BATTLE_AI_UTIL_H \ No newline at end of file +#endif //GUARD_BATTLE_AI_UTIL_H diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 51773df8d5..8cd8606a54 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -108,9 +108,12 @@ extern const u8 BattleScript_MoveUsedWokeUp[]; extern const u8 BattleScript_MonWokeUpInUproar[]; extern const u8 BattleScript_PoisonTurnDmg[]; extern const u8 BattleScript_BurnTurnDmg[]; +extern const u8 BattleScript_FrostbiteTurnDmg[]; extern const u8 BattleScript_MoveUsedIsFrozen[]; extern const u8 BattleScript_MoveUsedUnfroze[]; +extern const u8 BattleScript_MoveUsedUnfrostbite[]; extern const u8 BattleScript_DefrostedViaFireMove[]; +extern const u8 BattleScript_FrostbiteHealedViaFireMove[]; extern const u8 BattleScript_MoveUsedIsParalyzed[]; extern const u8 BattleScript_MoveUsedFlinched[]; extern const u8 BattleScript_PrintUproarOverTurns[]; @@ -131,6 +134,7 @@ extern const u8 BattleScript_MoveEffectSleep[]; extern const u8 BattleScript_YawnMakesAsleep[]; extern const u8 BattleScript_MoveEffectPoison[]; extern const u8 BattleScript_MoveEffectBurn[]; +extern const u8 BattleScript_MoveEffectFrostbite[]; extern const u8 BattleScript_MoveEffectFreeze[]; extern const u8 BattleScript_MoveEffectParalysis[]; extern const u8 BattleScript_MoveEffectUproar[]; @@ -192,6 +196,8 @@ extern const u8 BattleScript_BerryCureBrnEnd2[]; extern const u8 BattleScript_BerryCureBrnRet[]; extern const u8 BattleScript_BerryCureFrzEnd2[]; extern const u8 BattleScript_BerryCureFrzRet[]; +extern const u8 BattleScript_BerryCureFsbEnd2[]; +extern const u8 BattleScript_BerryCureFsbRet[]; extern const u8 BattleScript_BerryCureSlpEnd2[]; extern const u8 BattleScript_BerryCureSlpRet[]; extern const u8 BattleScript_BerryCureConfusionEnd2[]; diff --git a/include/battle_util.h b/include/battle_util.h index 0ad287c537..e28e41aad7 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -228,6 +228,7 @@ bool32 CanBePoisoned(u8 battlerAttacker, u8 battlerTarget); bool32 CanBeBurned(u8 battlerId); bool32 CanBeParalyzed(u8 battlerId); bool32 CanBeFrozen(u8 battlerId); +bool32 CanGetFrostbite(u8 battlerId); bool32 CanBeConfused(u8 battlerId); bool32 IsBattlerTerrainAffected(u8 battlerId, u32 terrainFlag); u32 GetBattlerFriendshipScore(u8 battlerId); diff --git a/include/config/battle.h b/include/config/battle.h index 4861d046ca..da58c8bbf8 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -188,14 +188,15 @@ #define B_LAST_USED_BALL_BUTTON R_BUTTON // If last used ball is implemented, this button (or button combo) will trigger throwing the last used ball. // Other settings -#define B_DOUBLE_WILD_CHANCE 0 // % chance of encountering two Pokémon in a Wild Encounter. -#define B_DOUBLE_WILD_REQUIRE_2_MONS FALSE // If set to TRUE, Wild Double Battles will default to Single Battles when the player only has 1 usuable Pokémon, ignoring B_DOUBLE_WILD_CHANCE and B_FLAG_FORCE_DOUBLE_WILD. -#define B_MULTI_BATTLE_WHITEOUT GEN_LATEST // In Gen4+, multi battles end when the Player and also their Partner don't have any more Pokémon to fight. -#define B_EVOLUTION_AFTER_WHITEOUT GEN_LATEST // In Gen6+, Pokemon that qualify for evolution after battle will evolve even if the player loses. -#define B_WILD_NATURAL_ENEMIES TRUE // If set to TRUE, certain wild mon species will attack other species when partnered in double wild battles (eg. Zangoose vs Seviper) -#define B_AFFECTION_MECHANICS FALSE // In Gen6+, there's a stat called affection that can trigger different effects in battle. From LGPE onwards, those effects use friendship instead. -#define B_TRAINER_CLASS_POKE_BALLS GEN_LATEST // In Gen7+, trainers will use certain types of Poké Balls depending on their trainer class. -#define B_OBEDIENCE_MECHANICS GEN_LATEST // In PLA+ (here Gen8+), obedience restrictions also apply to non-outsider Pokémon, albeit based on their level met rather than actual level +#define B_DOUBLE_WILD_CHANCE 0 // % chance of encountering two Pokémon in a Wild Encounter. +#define B_DOUBLE_WILD_REQUIRE_2_MONS FALSE // If set to TRUE, Wild Double Battles will default to Single Battles when the player only has 1 usuable Pokémon, ignoring B_DOUBLE_WILD_CHANCE and B_FLAG_FORCE_DOUBLE_WILD. +#define B_MULTI_BATTLE_WHITEOUT GEN_LATEST // In Gen4+, multi battles end when the Player and also their Partner don't have any more Pokémon to fight. +#define B_EVOLUTION_AFTER_WHITEOUT GEN_LATEST // In Gen6+, Pokemon that qualify for evolution after battle will evolve even if the player loses. +#define B_WILD_NATURAL_ENEMIES TRUE // If set to TRUE, certain wild mon species will attack other species when partnered in double wild battles (eg. Zangoose vs Seviper) +#define B_AFFECTION_MECHANICS FALSE // In Gen6+, there's a stat called affection that can trigger different effects in battle. From LGPE onwards, those effects use friendship instead. +#define B_TRAINER_CLASS_POKE_BALLS GEN_LATEST // In Gen7+, trainers will use certain types of Poké Balls depending on their trainer class. +#define B_OBEDIENCE_MECHANICS GEN_LATEST // In PLA+ (here Gen8+), obedience restrictions also apply to non-outsider Pokémon, albeit based on their level met rather than actual level +#define B_USE_FROSTBITE FALSE // In PLA, Frostbite replaces Freeze. Enabling this flag does the same here. Moves can still be cherry-picked to either Freeze or Frostbite. Freeze-Dry, Secret Power & Tri Attack depend on this config. // Animation Settings #define B_NEW_SWORD_PARTICLE TRUE // If set to TRUE, it updates Swords Dance's particle. diff --git a/include/constants/battle.h b/include/constants/battle.h index a37f0c6d59..950d98484f 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -115,8 +115,9 @@ #define STATUS1_TOXIC_POISON (1 << 7) #define STATUS1_TOXIC_COUNTER (1 << 8 | 1 << 9 | 1 << 10 | 1 << 11) #define STATUS1_TOXIC_TURN(num) ((num) << 8) +#define STATUS1_FROSTBITE (1 << 12) #define STATUS1_PSN_ANY (STATUS1_POISON | STATUS1_TOXIC_POISON) -#define STATUS1_ANY (STATUS1_SLEEP | STATUS1_POISON | STATUS1_BURN | STATUS1_FREEZE | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON) +#define STATUS1_ANY (STATUS1_SLEEP | STATUS1_POISON | STATUS1_BURN | STATUS1_FREEZE | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON | STATUS1_FROSTBITE) // Volatile status ailments // These are removed after exiting the battle or switching out @@ -307,79 +308,80 @@ #define MOVE_EFFECT_FREEZE 4 #define MOVE_EFFECT_PARALYSIS 5 #define MOVE_EFFECT_TOXIC 6 -#define PRIMARY_STATUS_MOVE_EFFECT MOVE_EFFECT_TOXIC // All above move effects apply primary status -#define MOVE_EFFECT_CONFUSION 7 -#define MOVE_EFFECT_FLINCH 8 -#define MOVE_EFFECT_TRI_ATTACK 9 -#define MOVE_EFFECT_UPROAR 10 -#define MOVE_EFFECT_PAYDAY 11 -#define MOVE_EFFECT_CHARGING 12 -#define MOVE_EFFECT_WRAP 13 -#define MOVE_EFFECT_BURN_UP 14 // MOVE_EFFECT_BURN_UP replaces unused MOVE_EFFECT_RECOIL_25 so that stat change animations don't break -#define MOVE_EFFECT_ATK_PLUS_1 15 -#define MOVE_EFFECT_DEF_PLUS_1 16 -#define MOVE_EFFECT_SPD_PLUS_1 17 -#define MOVE_EFFECT_SP_ATK_PLUS_1 18 -#define MOVE_EFFECT_SP_DEF_PLUS_1 19 -#define MOVE_EFFECT_ACC_PLUS_1 20 -#define MOVE_EFFECT_EVS_PLUS_1 21 -#define MOVE_EFFECT_ATK_MINUS_1 22 -#define MOVE_EFFECT_DEF_MINUS_1 23 -#define MOVE_EFFECT_SPD_MINUS_1 24 -#define MOVE_EFFECT_SP_ATK_MINUS_1 25 -#define MOVE_EFFECT_SP_DEF_MINUS_1 26 -#define MOVE_EFFECT_ACC_MINUS_1 27 -#define MOVE_EFFECT_EVS_MINUS_1 28 -#define MOVE_EFFECT_RECHARGE 29 -#define MOVE_EFFECT_RAGE 30 -#define MOVE_EFFECT_STEAL_ITEM 31 -#define MOVE_EFFECT_PREVENT_ESCAPE 32 -#define MOVE_EFFECT_NIGHTMARE 33 -#define MOVE_EFFECT_ALL_STATS_UP 34 -#define MOVE_EFFECT_RAPIDSPIN 35 -#define MOVE_EFFECT_REMOVE_STATUS 36 -#define MOVE_EFFECT_ATK_DEF_DOWN 37 -#define MOVE_EFFECT_SCALE_SHOT 38 // MOVE_EFFECT_SCALE_SHOT replaces unused MOVE_EFFECT_RECOIL_33 so that stat change animations don't break -#define MOVE_EFFECT_ATK_PLUS_2 39 -#define MOVE_EFFECT_DEF_PLUS_2 40 -#define MOVE_EFFECT_SPD_PLUS_2 41 -#define MOVE_EFFECT_SP_ATK_PLUS_2 42 -#define MOVE_EFFECT_SP_DEF_PLUS_2 43 -#define MOVE_EFFECT_ACC_PLUS_2 44 -#define MOVE_EFFECT_EVS_PLUS_2 45 -#define MOVE_EFFECT_ATK_MINUS_2 46 -#define MOVE_EFFECT_DEF_MINUS_2 47 -#define MOVE_EFFECT_SPD_MINUS_2 48 -#define MOVE_EFFECT_SP_ATK_MINUS_2 49 -#define MOVE_EFFECT_SP_DEF_MINUS_2 50 -#define MOVE_EFFECT_ACC_MINUS_2 51 -#define MOVE_EFFECT_EVS_MINUS_2 52 -#define MOVE_EFFECT_THRASH 53 -#define MOVE_EFFECT_KNOCK_OFF 54 -#define MOVE_EFFECT_DEF_SPDEF_DOWN 55 -#define MOVE_EFFECT_CLEAR_SMOG 56 -#define MOVE_EFFECT_SP_ATK_TWO_DOWN 57 -#define MOVE_EFFECT_SMACK_DOWN 58 -#define MOVE_EFFECT_FLAME_BURST 59 -#define MOVE_EFFECT_FEINT 60 -#define MOVE_EFFECT_SPECTRAL_THIEF 61 -#define MOVE_EFFECT_V_CREATE 62 -#define MOVE_EFFECT_HAPPY_HOUR 63 -#define MOVE_EFFECT_CORE_ENFORCER 64 -#define MOVE_EFFECT_THROAT_CHOP 65 -#define MOVE_EFFECT_INCINERATE 66 -#define MOVE_EFFECT_BUG_BITE 67 -#define MOVE_EFFECT_RECOIL_HP_25 68 -#define MOVE_EFFECT_RELIC_SONG 69 -#define MOVE_EFFECT_TRAP_BOTH 70 -#define MOVE_EFFECT_DOUBLE_SHOCK 71 -#define MOVE_EFFECT_ROUND 72 -#define MOVE_EFFECT_STOCKPILE_WORE_OFF 73 -#define MOVE_EFFECT_DIRE_CLAW 74 -#define MOVE_EFFECT_STEALTH_ROCK 75 -#define MOVE_EFFECT_SPIKES 76 +#define MOVE_EFFECT_FROSTBITE 7 +#define PRIMARY_STATUS_MOVE_EFFECT MOVE_EFFECT_FROSTBITE // All above move effects apply primary status +#define MOVE_EFFECT_CONFUSION 8 +#define MOVE_EFFECT_FLINCH 9 +#define MOVE_EFFECT_TRI_ATTACK 10 +#define MOVE_EFFECT_UPROAR 11 +#define MOVE_EFFECT_PAYDAY 12 +#define MOVE_EFFECT_CHARGING 13 +#define MOVE_EFFECT_WRAP 14 +#define MOVE_EFFECT_BURN_UP 15 // MOVE_EFFECT_BURN_UP replaces unused MOVE_EFFECT_RECOIL_25 so that stat change animations don't break +#define MOVE_EFFECT_ATK_PLUS_1 16 +#define MOVE_EFFECT_DEF_PLUS_1 17 +#define MOVE_EFFECT_SPD_PLUS_1 18 +#define MOVE_EFFECT_SP_ATK_PLUS_1 19 +#define MOVE_EFFECT_SP_DEF_PLUS_1 20 +#define MOVE_EFFECT_ACC_PLUS_1 21 +#define MOVE_EFFECT_EVS_PLUS_1 22 +#define MOVE_EFFECT_ATK_MINUS_1 23 +#define MOVE_EFFECT_DEF_MINUS_1 24 +#define MOVE_EFFECT_SPD_MINUS_1 25 +#define MOVE_EFFECT_SP_ATK_MINUS_1 26 +#define MOVE_EFFECT_SP_DEF_MINUS_1 27 +#define MOVE_EFFECT_ACC_MINUS_1 28 +#define MOVE_EFFECT_EVS_MINUS_1 29 +#define MOVE_EFFECT_RECHARGE 30 +#define MOVE_EFFECT_RAGE 31 +#define MOVE_EFFECT_STEAL_ITEM 32 +#define MOVE_EFFECT_PREVENT_ESCAPE 33 +#define MOVE_EFFECT_NIGHTMARE 34 +#define MOVE_EFFECT_ALL_STATS_UP 35 +#define MOVE_EFFECT_RAPIDSPIN 36 +#define MOVE_EFFECT_REMOVE_STATUS 37 +#define MOVE_EFFECT_ATK_DEF_DOWN 38 +#define MOVE_EFFECT_SCALE_SHOT 39 // MOVE_EFFECT_SCALE_SHOT replaces unused MOVE_EFFECT_RECOIL_33 so that stat change animations don't break +#define MOVE_EFFECT_ATK_PLUS_2 40 +#define MOVE_EFFECT_DEF_PLUS_2 41 +#define MOVE_EFFECT_SPD_PLUS_2 42 +#define MOVE_EFFECT_SP_ATK_PLUS_2 43 +#define MOVE_EFFECT_SP_DEF_PLUS_2 44 +#define MOVE_EFFECT_ACC_PLUS_2 45 +#define MOVE_EFFECT_EVS_PLUS_2 46 +#define MOVE_EFFECT_ATK_MINUS_2 47 +#define MOVE_EFFECT_DEF_MINUS_2 48 +#define MOVE_EFFECT_SPD_MINUS_2 49 +#define MOVE_EFFECT_SP_ATK_MINUS_2 50 +#define MOVE_EFFECT_SP_DEF_MINUS_2 51 +#define MOVE_EFFECT_ACC_MINUS_2 52 +#define MOVE_EFFECT_EVS_MINUS_2 53 +#define MOVE_EFFECT_THRASH 54 +#define MOVE_EFFECT_KNOCK_OFF 55 +#define MOVE_EFFECT_DEF_SPDEF_DOWN 56 +#define MOVE_EFFECT_CLEAR_SMOG 57 +#define MOVE_EFFECT_SP_ATK_TWO_DOWN 58 +#define MOVE_EFFECT_SMACK_DOWN 59 +#define MOVE_EFFECT_FLAME_BURST 60 +#define MOVE_EFFECT_FEINT 61 +#define MOVE_EFFECT_SPECTRAL_THIEF 62 +#define MOVE_EFFECT_V_CREATE 63 +#define MOVE_EFFECT_HAPPY_HOUR 64 +#define MOVE_EFFECT_CORE_ENFORCER 65 +#define MOVE_EFFECT_THROAT_CHOP 66 +#define MOVE_EFFECT_INCINERATE 67 +#define MOVE_EFFECT_BUG_BITE 68 +#define MOVE_EFFECT_RECOIL_HP_25 69 +#define MOVE_EFFECT_RELIC_SONG 70 +#define MOVE_EFFECT_TRAP_BOTH 71 +#define MOVE_EFFECT_DOUBLE_SHOCK 72 +#define MOVE_EFFECT_ROUND 73 +#define MOVE_EFFECT_STOCKPILE_WORE_OFF 74 +#define MOVE_EFFECT_DIRE_CLAW 75 +#define MOVE_EFFECT_STEALTH_ROCK 76 +#define MOVE_EFFECT_SPIKES 77 -#define NUM_MOVE_EFFECTS 77 +#define NUM_MOVE_EFFECTS 78 #define MOVE_EFFECT_AFFECTS_USER 0x4000 #define MOVE_EFFECT_CERTAIN 0x8000 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index d1562dec93..5df12b4496 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -405,7 +405,8 @@ #define EFFECT_DIRE_CLAW 399 #define EFFECT_BARB_BARRAGE 400 #define EFFECT_REVIVAL_BLESSING 401 +#define EFFECT_FROSTBITE_HIT 402 -#define NUM_BATTLE_MOVE_EFFECTS 402 +#define NUM_BATTLE_MOVE_EFFECTS 403 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index f4fd589db1..48abc03b9e 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -652,8 +652,15 @@ #define STRINGID_ITEMCUREDSPECIESSTATUS 650 #define STRINGID_ITEMRESTOREDSPECIESPP 651 #define STRINGID_THUNDERCAGETRAPPED 652 +#define STRINGID_PKMNHURTBYFROSTBITE 653 +#define STRINGID_PKMNGOTFROSTBITE 654 +#define STRINGID_PKMNSITEMHEALEDFROSTBITE 655 +#define STRINGID_ATTACKERHEALEDITSFROSTBITE 656 +#define STRINGID_PKMNFROSTBITEHEALED 657 +#define STRINGID_PKMNFROSTBITEHEALED2 658 +#define STRINGID_PKMNFROSTBITEHEALEDBY 659 -#define BATTLESTRINGS_COUNT 653 +#define BATTLESTRINGS_COUNT 660 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, @@ -861,6 +868,10 @@ #define B_MSG_DEFROSTED 0 #define B_MSG_DEFROSTED_BY_MOVE 1 +// gFrostbiteHealedStringIds +#define B_MSG_FROSTBITE_HEALED 0 +#define B_MSG_FROSTBITE_HEALED_BY_MOVE 1 + // gBattlePalaceFlavorTextTable #define B_MSG_GLINT_IN_EYE 0 #define B_MSG_GETTING_IN_POS 1 diff --git a/include/constants/item_effects.h b/include/constants/item_effects.h index 7cd4a58f48..fca7924514 100644 --- a/include/constants/item_effects.h +++ b/include/constants/item_effects.h @@ -74,7 +74,7 @@ #define ITEM_EFFECT_CURE_POISON 3 #define ITEM_EFFECT_CURE_SLEEP 4 #define ITEM_EFFECT_CURE_BURN 5 -#define ITEM_EFFECT_CURE_FREEZE 6 +#define ITEM_EFFECT_CURE_FREEZE_FROSTBITE 6 #define ITEM_EFFECT_CURE_PARALYSIS 7 #define ITEM_EFFECT_CURE_CONFUSION 8 #define ITEM_EFFECT_CURE_INFATUATION 9 diff --git a/include/constants/party_menu.h b/include/constants/party_menu.h index f28b75122f..fd94afe544 100644 --- a/include/constants/party_menu.h +++ b/include/constants/party_menu.h @@ -11,6 +11,7 @@ #define AILMENT_BRN 5 #define AILMENT_PKRS 6 #define AILMENT_FNT 7 +#define AILMENT_FSB 8 #define PARTY_LAYOUT_SINGLE 0 #define PARTY_LAYOUT_DOUBLE 1 diff --git a/include/pokemon.h b/include/pokemon.h index b3ba009bec..6b476c5fc6 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -346,7 +346,7 @@ struct BattleMove s8 priority; u32 flags; u8 split; - u8 argument; + u16 argument; u8 zMoveEffect; }; diff --git a/include/strings.h b/include/strings.h index 72109ed945..4019dee0b1 100644 --- a/include/strings.h +++ b/include/strings.h @@ -475,6 +475,7 @@ extern const u8 gText_EscapeFromHere[]; extern const u8 gText_PkmnCuredOfPoison[]; extern const u8 gText_PkmnWokeUp2[]; extern const u8 gText_PkmnBurnHealed[]; +extern const u8 gText_PkmnFrostbiteHealed[]; extern const u8 gText_PkmnThawedOut[]; extern const u8 gText_PkmnCuredOfParalysis[]; extern const u8 gText_PkmnGotOverInfatuation[]; diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index cadcb55f16..7dc33dd3b2 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1725,7 +1725,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_REFRESH: - if (!(gBattleMons[battlerDef].status1 & (STATUS1_PSN_ANY | STATUS1_BURN | STATUS1_PARALYSIS))) + if (!(gBattleMons[battlerDef].status1 & (STATUS1_PSN_ANY | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_FROSTBITE))) score -= 10; break; case EFFECT_PSYCHO_SHIFT: @@ -1734,6 +1734,9 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) else if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && !AI_CanBurn(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; + else if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && !AI_CanGiveFrostbite(battlerAtk, battlerDef, + AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) + score -= 10; else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS && !AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) @@ -3139,7 +3142,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; // check thawing moves - if ((gBattleMons[battlerAtk].status1 & STATUS1_FREEZE) && TestMoveFlags(move, FLAG_THAW_USER)) + if ((gBattleMons[battlerAtk].status1 & (STATUS1_FREEZE | STATUS1_FROSTBITE)) && TestMoveFlags(move, FLAG_THAW_USER)) score += (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) ? 20 : 10; // check burn @@ -3161,6 +3164,25 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } } + // check frostbite + if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE) + { + switch (AI_DATA->abilities[battlerAtk]) + { + case ABILITY_GUTS: + break; + case ABILITY_NATURAL_CURE: + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING + && HasOnlyMovesWithSplit(battlerAtk, SPLIT_SPECIAL, TRUE)) + score = 90; // Force switch if all your attacking moves are special and you have Natural Cure. + break; + default: + if (IS_MOVE_SPECIAL(move) && gBattleMoves[move].effect != EFFECT_FACADE) + score -= 2; + break; + } + } + // attacker ability checks switch (AI_DATA->abilities[battlerAtk]) { @@ -3598,7 +3620,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SUBSTITUTE: if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) score += 3; - if (gBattleMons[battlerDef].status1 & (STATUS1_BURN | STATUS1_PSN_ANY)) + if (gBattleMons[battlerDef].status1 & (STATUS1_BURN | STATUS1_PSN_ANY | STATUS1_FROSTBITE)) score++; if (HasMoveEffect(battlerDef, EFFECT_SLEEP) || HasMoveEffect(battlerDef, EFFECT_TOXIC) @@ -4385,6 +4407,8 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) IncreaseParalyzeScore(battlerAtk, battlerDef, move, &score); else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) IncreaseSleepScore(battlerAtk, battlerDef, move, &score); + else if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE) + IncreaseFrostbiteScore(battlerAtk, battlerDef, move, &score); break; case EFFECT_GRUDGE: break; @@ -4773,7 +4797,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; break; case EFFECT_FACADE: - if (gBattleMons[battlerAtk].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON)) + if (gBattleMons[battlerAtk].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON | STATUS1_FROSTBITE)) score++; break; case EFFECT_FOCUS_PUNCH: diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 29911d798f..d7fd062ba2 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -1079,7 +1079,7 @@ static bool8 ShouldUseItem(void) shouldUse = TRUE; if (itemEffects[3] & ITEM3_BURN && gBattleMons[gActiveBattler].status1 & STATUS1_BURN) shouldUse = TRUE; - if (itemEffects[3] & ITEM3_FREEZE && gBattleMons[gActiveBattler].status1 & STATUS1_FREEZE) + if (itemEffects[3] & ITEM3_FREEZE && (gBattleMons[gActiveBattler].status1 & STATUS1_FREEZE || gBattleMons[gActiveBattler].status1 & STATUS1_FROSTBITE)) shouldUse = TRUE; if (itemEffects[3] & ITEM3_PARALYSIS && gBattleMons[gActiveBattler].status1 & STATUS1_PARALYSIS) shouldUse = TRUE; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index f23127a0c3..3adbd77ae2 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1678,7 +1678,7 @@ void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s1 (*score) -= min(uses, 3); } - if (gBattleMons[battlerAtk].status1 & (STATUS1_PSN_ANY | STATUS1_BURN) + if (gBattleMons[battlerAtk].status1 & (STATUS1_PSN_ANY | STATUS1_BURN | STATUS1_FROSTBITE) || gBattleMons[battlerAtk].status2 & (STATUS2_CURSED | STATUS2_INFATUATION) || gStatuses3[battlerAtk] & (STATUS3_PERISH_SONG | STATUS3_LEECHSEED | STATUS3_YAWN)) { @@ -2766,6 +2766,7 @@ bool32 AI_CanSleep(u8 battler, u16 ability) { if (ability == ABILITY_INSOMNIA || ability == ABILITY_VITAL_SPIRIT + || ability == ABILITY_COMATOSE || gBattleMons[battler].status1 & STATUS1_ANY || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD || (gFieldStatuses & (STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN)) @@ -2839,6 +2840,7 @@ bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 static bool32 AI_CanBeParalyzed(u8 battler, u16 ability) { if (ability == ABILITY_LIMBER + || ability == ABILITY_COMATOSE || IS_BATTLER_OF_TYPE(battler, TYPE_ELECTRIC) || gBattleMons[battler].status1 & STATUS1_ANY || IsAbilityStatusProtected(battler)) @@ -2884,6 +2886,7 @@ bool32 AI_CanBeBurned(u8 battler, u16 ability) { if (ability == ABILITY_WATER_VEIL || ability == ABILITY_WATER_BUBBLE + || ability == ABILITY_COMATOSE || IS_BATTLER_OF_TYPE(battler, TYPE_FIRE) || gBattleMons[battler].status1 & STATUS1_ANY || IsAbilityStatusProtected(battler) @@ -2892,6 +2895,18 @@ bool32 AI_CanBeBurned(u8 battler, u16 ability) return TRUE; } +bool32 AI_CanGetFrostbite(u8 battler, u16 ability) +{ + if (ability == ABILITY_MAGMA_ARMOR + || ability == ABILITY_COMATOSE + || IS_BATTLER_OF_TYPE(battler, TYPE_ICE) + || gBattleMons[battler].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battler) + || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) + return FALSE; + return TRUE; +} + bool32 ShouldBurnSelf(u8 battler, u16 ability) { if (AI_CanBeBurned(battler, ability) && ( @@ -2918,6 +2933,18 @@ bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPar return TRUE; } +bool32 AI_CanGiveFrostbite(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) +{ + if (!AI_CanGetFrostbite(battlerDef, defAbility) + || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 + || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) + || PartnerMoveEffectIsStatusSameTarget(battlerAtkPartner, battlerDef, partnerMove)) + { + return FALSE; + } + return TRUE; +} + bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGender, u8 defGender) { if ((gBattleMons[battlerDef].status2 & STATUS2_INFATUATION) @@ -3717,6 +3744,25 @@ void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) } } +void IncreaseFrostbiteScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +{ + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + + if (AI_CanGiveFrostbite(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) + { + (*score)++; // frostbite is good + if (HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) + { + if (CanTargetFaintAi(battlerDef, battlerAtk)) + *score += 2; // frostbiting the target to stay alive is cool + } + + if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_HEX)) + (*score)++; + } +} + bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move) { if (TestMoveFlags(move, FLAG_MAKES_CONTACT) diff --git a/src/battle_debug.c b/src/battle_debug.c index 1d690caaa0..0549cf91ed 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -181,6 +181,7 @@ static const u8 sText_SideStatus[] = _("Side Status"); static const u8 sText_MaxHp[] = _("HP Max"); static const u8 sText_CurrHp[] = _("HP Current"); static const u8 sText_Freeze[] = _("Freeze"); +static const u8 sText_Frostbite[] = _("Frostbite"); static const u8 sText_ToxicPoison[] = _("Toxic Poison"); static const u8 sText_ToxicCounter[] = _("Toxic Counter"); static const u8 sText_Flinch[] = _("Flinch"); @@ -258,6 +259,7 @@ static const struct BitfieldInfo sStatus1Bitfield[] = {/*Paralysis*/1, 6}, {/*Toxic Poison*/ 1, 7}, {/*Toxic Counter*/ 4, 8}, + {/*Frostbite*/ 1, 12}, }; static const struct BitfieldInfo sStatus2Bitfield[] = @@ -397,6 +399,7 @@ static const struct ListMenuItem sStatus1ListItems[] = {gText_Paralysis, 4}, {sText_ToxicPoison, 5}, {sText_ToxicCounter, 6}, + {sText_Frostbite, 7}, }; static const struct ListMenuItem sStatus2ListItems[] = diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index d926494a8d..c06a7795a5 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -398,7 +398,7 @@ void InitAndLaunchChosenStatusAnimation(bool8 isStatus2, u32 status) gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].statusAnimActive = 1; if (!isStatus2) { - if (status == STATUS1_FREEZE) + if (status == STATUS1_FREEZE || status == STATUS1_FROSTBITE) LaunchStatusAnimation(gActiveBattler, B_ANIM_STATUS_FRZ); else if (status == STATUS1_POISON || status & STATUS1_TOXIC_POISON) LaunchStatusAnimation(gActiveBattler, B_ANIM_STATUS_PSN); diff --git a/src/battle_interface.c b/src/battle_interface.c index 9c380d4a4a..58b1d1117a 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -73,6 +73,9 @@ enum HEALTHBOX_GFX_STATUS_BRN_BATTLER0, //status brn HEALTHBOX_GFX_34, HEALTHBOX_GFX_35, + HEALTHBOX_GFX_STATUS_FSB_BATTLER0, //status fsb + HEALTHBOX_GFX_116, + HEALTHBOX_GFX_117, HEALTHBOX_GFX_36, //misc [Black section] HEALTHBOX_GFX_37, //misc [Black section] HEALTHBOX_GFX_38, //misc [Black section] @@ -123,6 +126,9 @@ enum HEALTHBOX_GFX_STATUS_BRN_BATTLER1, //status2 "BRN" HEALTHBOX_GFX_84, HEALTHBOX_GFX_85, + HEALTHBOX_GFX_STATUS_FSB_BATTLER1, //status2 "FSB" + HEALTHBOX_GFX_118, + HEALTHBOX_GFX_119, HEALTHBOX_GFX_STATUS_PSN_BATTLER2, //status3 "PSN" HEALTHBOX_GFX_87, HEALTHBOX_GFX_88, @@ -138,6 +144,9 @@ enum HEALTHBOX_GFX_STATUS_BRN_BATTLER2, //status3 "BRN" HEALTHBOX_GFX_99, HEALTHBOX_GFX_100, + HEALTHBOX_GFX_STATUS_FSB_BATTLER2, //status3 "FSB" + HEALTHBOX_GFX_120, + HEALTHBOX_GFX_121, HEALTHBOX_GFX_STATUS_PSN_BATTLER3, //status4 "PSN" HEALTHBOX_GFX_102, HEALTHBOX_GFX_103, @@ -153,6 +162,9 @@ enum HEALTHBOX_GFX_STATUS_BRN_BATTLER3, //status4 "BRN" HEALTHBOX_GFX_114, HEALTHBOX_GFX_115, + HEALTHBOX_GFX_STATUS_FSB_BATTLER3, //status4 "FSB" + HEALTHBOX_GFX_122, + HEALTHBOX_GFX_123, HEALTHBOX_GFX_FRAME_END, HEALTHBOX_GFX_FRAME_END_BAR, }; @@ -2201,6 +2213,11 @@ static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId) statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBattlerId(HEALTHBOX_GFX_STATUS_FRZ_BATTLER0, battlerId)); statusPalId = PAL_STATUS_FRZ; } + else if (status & STATUS1_FROSTBITE) + { + statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBattlerId(HEALTHBOX_GFX_STATUS_FSB_BATTLER0, battlerId)); + statusPalId = PAL_STATUS_FRZ; + } else if (status & STATUS1_PARALYSIS) { statusGfxPtr = GetHealthboxElementGfxPtr(GetStatusIconForBattlerId(HEALTHBOX_GFX_STATUS_PRZ_BATTLER0, battlerId)); @@ -2283,6 +2300,16 @@ static u8 GetStatusIconForBattlerId(u8 statusElementId, u8 battlerId) else ret = HEALTHBOX_GFX_STATUS_FRZ_BATTLER3; break; + case HEALTHBOX_GFX_STATUS_FSB_BATTLER0: + if (battlerId == 0) + ret = HEALTHBOX_GFX_STATUS_FSB_BATTLER0; + else if (battlerId == 1) + ret = HEALTHBOX_GFX_STATUS_FSB_BATTLER1; + else if (battlerId == 2) + ret = HEALTHBOX_GFX_STATUS_FSB_BATTLER2; + else + ret = HEALTHBOX_GFX_STATUS_FSB_BATTLER3; + break; case HEALTHBOX_GFX_STATUS_BRN_BATTLER0: if (battlerId == 0) ret = HEALTHBOX_GFX_STATUS_BRN_BATTLER0; diff --git a/src/battle_message.c b/src/battle_message.c index 21f7098f81..29fdbd28c2 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -101,8 +101,10 @@ static const u8 sText_PkmnAlreadyPoisoned[] = _("{B_DEF_NAME_WITH_PREFIX} is alr static const u8 sText_PkmnBadlyPoisoned[] = _("{B_EFF_NAME_WITH_PREFIX} is badly\npoisoned!"); static const u8 sText_PkmnEnergyDrained[] = _("{B_DEF_NAME_WITH_PREFIX} had its\nenergy drained!"); static const u8 sText_PkmnWasBurned[] = _("{B_EFF_NAME_WITH_PREFIX} was burned!"); +static const u8 sText_PkmnGotFrostbite[] = _("{B_EFF_NAME_WITH_PREFIX} got frostbite!"); static const u8 sText_PkmnBurnedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nburned {B_EFF_NAME_WITH_PREFIX}!"); static const u8 sText_PkmnHurtByBurn[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt\nby its burn!"); +static const u8 sText_PkmnHurtByFrostbite[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt\nby its frostbite!"); static const u8 sText_PkmnAlreadyHasBurn[] = _("{B_DEF_NAME_WITH_PREFIX} already\nhas a burn."); static const u8 sText_PkmnWasFrozen[] = _("{B_EFF_NAME_WITH_PREFIX} was\nfrozen solid!"); static const u8 sText_PkmnFrozenBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nfroze {B_EFF_NAME_WITH_PREFIX} solid!"); @@ -110,6 +112,9 @@ static const u8 sText_PkmnIsFrozen[] = _("{B_ATK_NAME_WITH_PREFIX} is\nfrozen so static const u8 sText_PkmnWasDefrosted[] = _("{B_DEF_NAME_WITH_PREFIX} was\ndefrosted!"); static const u8 sText_PkmnWasDefrosted2[] = _("{B_ATK_NAME_WITH_PREFIX} was\ndefrosted!"); static const u8 sText_PkmnWasDefrostedBy[] = _("{B_ATK_NAME_WITH_PREFIX} was\ndefrosted by {B_CURRENT_MOVE}!"); +static const u8 sText_PkmnFrostbiteHealed[] = _("{B_DEF_NAME_WITH_PREFIX}'s\nfrostbite was healed!"); +static const u8 sText_PkmnFrostbiteHealed2[] = _("{B_ATK_NAME_WITH_PREFIX}'s\nfrostbite was healed!"); +static const u8 sText_PkmnFrostbiteHealedBy[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_CURRENT_MOVE}\nhealed its frostbite!"); static const u8 sText_PkmnWasParalyzed[] = _("{B_EFF_NAME_WITH_PREFIX} is paralyzed!\nIt may be unable to move!"); static const u8 sText_PkmnWasParalyzedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nparalyzed {B_EFF_NAME_WITH_PREFIX}!\lIt may be unable to move!"); static const u8 sText_PkmnIsParalyzed[] = _("{B_ATK_NAME_WITH_PREFIX} is paralyzed!\nIt can't move!"); @@ -491,6 +496,7 @@ static const u8 sText_BerrySuffix[] = _(" BERRY"); static const u8 sText_PkmnsItemCuredParalysis[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_LAST_ITEM}\ncured paralysis!"); static const u8 sText_PkmnsItemCuredPoison[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_LAST_ITEM}\ncured poison!"); static const u8 sText_PkmnsItemHealedBurn[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_LAST_ITEM}\nhealed its burn!"); +static const u8 sText_PkmnsItemHealedFrostbite[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_LAST_ITEM}\nhealed its frostbite!"); static const u8 sText_PkmnsItemDefrostedIt[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_LAST_ITEM}\ndefrosted it!"); static const u8 sText_PkmnsItemWokeIt[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_LAST_ITEM}\nwoke it from its sleep!"); static const u8 sText_PkmnsItemSnappedOut[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_LAST_ITEM}\nsnapped it out of confusion!"); @@ -768,6 +774,7 @@ static const u8 sText_AttackerExpelledThePoison[] = _("{B_ATK_NAME_WITH_PREFIX} static const u8 sText_AttackerShookItselfAwake[] = _("{B_ATK_NAME_WITH_PREFIX} shook itself awake!"); static const u8 sText_AttackerBrokeThroughParalysis[] = _("{B_ATK_NAME_WITH_PREFIX} gathered all its energy\nto overcome its paralysis!"); static const u8 sText_AttackerHealedItsBurn[] = _("{B_ATK_NAME_WITH_PREFIX} healed its burn with\nits sheer determination!"); +static const u8 sText_AttackerHealedItsFrostbite[] = _("{B_ATK_NAME_WITH_PREFIX} healed its frostbite with\nits sheer determination!"); static const u8 sText_AttackerMeltedTheIce[] = _("{B_ATK_NAME_WITH_PREFIX} melted the ice with\nits fiery determination!"); static const u8 sText_TargetToughedItOut[] = _("{B_DEF_NAME_WITH_PREFIX} toughed it out\nto show you its best side!"); static const u8 sText_AttackerLostElectricType[] = _("{B_ATK_NAME_WITH_PREFIX} used up all\nof its electricity!"); @@ -1430,6 +1437,13 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_TARGETTOOHEAVY - BATTLESTRINGS_TABLE_START] = sText_TargetTooHeavy, [STRINGID_ATTACKERLOSTELECTRICTYPE - BATTLESTRINGS_TABLE_START] = sText_AttackerLostElectricType, [STRINGID_PKMNSABILITYPREVENTSABILITY - BATTLESTRINGS_TABLE_START] = sText_PkmnsAbilityPreventsAbility, + [STRINGID_PKMNHURTBYFROSTBITE - BATTLESTRINGS_TABLE_START] = sText_PkmnHurtByFrostbite, + [STRINGID_PKMNGOTFROSTBITE - BATTLESTRINGS_TABLE_START] = sText_PkmnGotFrostbite, + [STRINGID_PKMNSITEMHEALEDFROSTBITE - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemHealedFrostbite, + [STRINGID_ATTACKERHEALEDITSFROSTBITE - BATTLESTRINGS_TABLE_START] = sText_AttackerHealedItsFrostbite, + [STRINGID_PKMNFROSTBITEHEALED - BATTLESTRINGS_TABLE_START] = sText_PkmnFrostbiteHealed, + [STRINGID_PKMNFROSTBITEHEALED2 - BATTLESTRINGS_TABLE_START] = sText_PkmnFrostbiteHealed2, + [STRINGID_PKMNFROSTBITEHEALEDBY - BATTLESTRINGS_TABLE_START] = sText_PkmnFrostbiteHealedBy, }; const u16 gTrainerUsedItemStringIds[] = @@ -1732,6 +1746,17 @@ const u16 gGotBurnedStringIds[] = [B_MSG_STATUSED_BY_ABILITY] = STRINGID_PKMNBURNEDBY }; +const u16 gGotFrostbiteStringIds[] = +{ + [B_MSG_STATUSED] = STRINGID_PKMNGOTFROSTBITE +}; + +const u16 gFrostbiteHealedStringIds[] = +{ + [B_MSG_FROSTBITE_HEALED] = STRINGID_PKMNFROSTBITEHEALED2, + [B_MSG_FROSTBITE_HEALED_BY_MOVE] = STRINGID_PKMNFROSTBITEHEALEDBY +}; + const u16 gGotFrozenStringIds[] = { [B_MSG_STATUSED] = STRINGID_PKMNWASFROZEN, @@ -1892,7 +1917,7 @@ const u16 gRoomsStringIds[] = const u16 gStatusConditionsStringIds[] = { - STRINGID_PKMNWASPOISONED, STRINGID_PKMNBADLYPOISONED, STRINGID_PKMNWASBURNED, STRINGID_PKMNWASPARALYZED, STRINGID_PKMNFELLASLEEP + STRINGID_PKMNWASPOISONED, STRINGID_PKMNBADLYPOISONED, STRINGID_PKMNWASBURNED, STRINGID_PKMNWASPARALYZED, STRINGID_PKMNFELLASLEEP, STRINGID_PKMNGOTFROSTBITE }; const u8 gText_PkmnIsEvolving[] = _("What?\n{STR_VAR_1} is evolving!"); diff --git a/src/battle_pike.c b/src/battle_pike.c index 9751d565de..37dfd9997d 100644 --- a/src/battle_pike.c +++ b/src/battle_pike.c @@ -729,6 +729,7 @@ static void GetRoomInflictedStatus(void) switch (sStatusFlags) { case STATUS1_FREEZE: + case STATUS1_FROSTBITE: gSpecialVar_Result = PIKE_STATUS_FREEZE; break; case STATUS1_BURN: @@ -818,6 +819,7 @@ static bool8 DoesAbilityPreventStatus(struct Pokemon *mon, u32 status) switch (status) { case STATUS1_FREEZE: + case STATUS1_FROSTBITE: if (ability == ABILITY_MAGMA_ARMOR) ret = TRUE; break; @@ -853,6 +855,7 @@ static bool8 DoesTypePreventStatus(u16 species, u32 status) ret = TRUE; break; case STATUS1_FREEZE: + case STATUS1_FROSTBITE: if (gSpeciesInfo[species].types[0] == TYPE_ICE || gSpeciesInfo[species].types[1] == TYPE_ICE) ret = TRUE; break; @@ -913,7 +916,11 @@ static bool8 TryInflictRandomStatus(void) if (rand < 35) sStatusFlags = STATUS1_TOXIC_POISON; else if (rand < 60) + #if B_USE_FROSTBITE == TRUE + sStatusFlags = STATUS1_FROSTBITE; + #else sStatusFlags = STATUS1_FREEZE; + #endif else if (rand < 80) sStatusFlags = STATUS1_PARALYSIS; else if (rand < 90) @@ -950,6 +957,7 @@ static bool8 TryInflictRandomStatus(void) switch (sStatusFlags) { case STATUS1_FREEZE: + case STATUS1_FROSTBITE: sStatusMon = PIKE_STATUSMON_DUSCLOPS; break; case STATUS1_BURN: diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index cdc8cfa904..1784f9682b 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -61,6 +61,7 @@ #include "constants/trainers.h" #include "battle_util.h" #include "constants/pokemon.h" +#include "config/battle.h" // Helper for accessing command arguments and advancing gBattlescriptCurrInstr. // @@ -896,6 +897,7 @@ static const u32 sStatusFlagsForMoveEffects[NUM_MOVE_EFFECTS] = [MOVE_EFFECT_FREEZE] = STATUS1_FREEZE, [MOVE_EFFECT_PARALYSIS] = STATUS1_PARALYSIS, [MOVE_EFFECT_TOXIC] = STATUS1_TOXIC_POISON, + [MOVE_EFFECT_FROSTBITE] = STATUS1_FROSTBITE, [MOVE_EFFECT_CONFUSION] = STATUS2_CONFUSION, [MOVE_EFFECT_FLINCH] = STATUS2_FLINCHED, [MOVE_EFFECT_UPROAR] = STATUS2_UPROAR, @@ -919,6 +921,7 @@ static const u8 *const sMoveEffectBS_Ptrs[] = [MOVE_EFFECT_UPROAR] = BattleScript_MoveEffectUproar, [MOVE_EFFECT_PAYDAY] = BattleScript_MoveEffectPayDay, [MOVE_EFFECT_WRAP] = BattleScript_MoveEffectWrap, + [MOVE_EFFECT_FROSTBITE] = BattleScript_MoveEffectFrostbite, }; static const struct WindowTemplate sUnusedWinTemplate = @@ -3208,6 +3211,12 @@ void SetMoveEffect(bool32 primary, u32 certain) gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE; } break; + case STATUS1_FROSTBITE: + if (!CanGetFrostbite(gEffectBattler)) + break; + + statusChanged = TRUE; + break; } if (statusChanged == TRUE) { @@ -3366,7 +3375,11 @@ void SetMoveEffect(bool32 primary, u32 certain) } else { + #if B_USE_FROSTBITE == TRUE + static const u8 sTriAttackEffects[] = { MOVE_EFFECT_BURN, MOVE_EFFECT_FROSTBITE, MOVE_EFFECT_PARALYSIS }; + #else static const u8 sTriAttackEffects[] = { MOVE_EFFECT_BURN, MOVE_EFFECT_FREEZE, MOVE_EFFECT_PARALYSIS }; + #endif gBattleScripting.moveEffect = RandomElement(RNG_TRI_ATTACK, sTriAttackEffects); SetMoveEffect(FALSE, 0); } @@ -5575,7 +5588,6 @@ static void Cmd_moveend(void) if (gBattleMons[gBattlerTarget].status1 & STATUS1_FREEZE && gBattleMons[gBattlerTarget].hp != 0 && gBattlerAttacker != gBattlerTarget - && gSpecialStatuses[gBattlerTarget].specialDmg && (moveType == TYPE_FIRE #if B_BURN_HIT_THAW >= GEN_6 || gBattleMoves[gCurrentMove].effect == EFFECT_BURN_HIT @@ -5591,6 +5603,20 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_DefrostedViaFireMove; effect = TRUE; } + if (gBattleMons[gBattlerTarget].status1 & STATUS1_FROSTBITE + && gBattleMons[gBattlerTarget].hp != 0 + && gBattlerAttacker != gBattlerTarget + && gBattleMoves[originallyUsedMove].flags & FLAG_THAW_USER + && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) + { + gBattleMons[gBattlerTarget].status1 &= ~STATUS1_FROSTBITE; + gActiveBattler = gBattlerTarget; + BtlController_EmitSetMonData(BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1); + MarkBattlerForControllerExec(gActiveBattler); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_FrostbiteHealedViaFireMove; + effect = TRUE; + } gBattleScripting.moveendState++; break; case MOVEEND_RECOIL: @@ -9917,6 +9943,9 @@ static void Cmd_various(void) case STATUS1_TOXIC_POISON: gBattleScripting.moveEffect = MOVE_EFFECT_TOXIC; break; + case STATUS1_FROSTBITE: + gBattleScripting.moveEffect = MOVE_EFFECT_FROSTBITE; + break; default: gBattleScripting.moveEffect = 0; break; @@ -10085,6 +10114,8 @@ static void Cmd_various(void) gBattleCommunication[MULTISTRING_CHOOSER] = 3; else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) && CanSleep(gBattlerTarget)) gBattleCommunication[MULTISTRING_CHOOSER] = 4; + else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE) && CanBeFrozen(gBattlerTarget)) + gBattleCommunication[MULTISTRING_CHOOSER] = 5; else { gBattlescriptCurrInstr = cmd->failInstr; @@ -14315,7 +14346,7 @@ static void Cmd_cureifburnedparalysedorpoisoned(void) { CMD_ARGS(const u8 *failInstr); - if (gBattleMons[gBattlerAttacker].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON)) + if (gBattleMons[gBattlerAttacker].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON | STATUS1_FROSTBITE)) { gBattleMons[gBattlerAttacker].status1 = 0; gBattlescriptCurrInstr = cmd->nextInstr; @@ -15037,7 +15068,11 @@ u16 GetSecretPowerMoveEffect(void) break; case BATTLE_TERRAIN_SNOW: case BATTLE_TERRAIN_ICE: + #if B_USE_FROSTBITE == TRUE + moveEffect = MOVE_EFFECT_FROSTBITE; + #else moveEffect = MOVE_EFFECT_FREEZE; + #endif break; case BATTLE_TERRAIN_VOLCANO: moveEffect = MOVE_EFFECT_BURN; @@ -15626,7 +15661,7 @@ static void Cmd_handleballthrow(void) if (gBattleMons[gBattlerTarget].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) odds *= 2; - if (gBattleMons[gBattlerTarget].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON)) + if (gBattleMons[gBattlerTarget].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON | STATUS1_FROSTBITE)) odds = (odds * 15) / 10; if (gBattleResults.catchAttempts[gLastUsedItem - FIRST_BALL] < 255) diff --git a/src/battle_tv.c b/src/battle_tv.c index 10c2144ccd..f5c9f43c4e 100644 --- a/src/battle_tv.c +++ b/src/battle_tv.c @@ -481,6 +481,7 @@ static const u16 sPoints_MoveEffect[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_DOUBLE_SHOCK] = 0, // TODO: Assign points [EFFECT_SPECIAL_ATTACK_UP_HIT] = 1, [EFFECT_VICTORY_DANCE] = 0, // TODO: Assign points + [EFFECT_FROSTBITE_HIT] = 1, }; static const u16 sPoints_Effectiveness[] = diff --git a/src/battle_util.c b/src/battle_util.c index 99fa85ab27..1c5a5d5d94 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2533,6 +2533,7 @@ enum ENDTURN_POISON, ENDTURN_BAD_POISON, ENDTURN_BURN, + ENDTURN_FROSTBITE, ENDTURN_NIGHTMARES, ENDTURN_CURSE, ENDTURN_WRAP, @@ -2746,6 +2747,23 @@ u8 DoBattlerEndTurnEffects(void) } gBattleStruct->turnEffectsTracker++; break; + case ENDTURN_FROSTBITE: // burn + if ((gBattleMons[gActiveBattler].status1 & STATUS1_FROSTBITE) + && gBattleMons[gActiveBattler].hp != 0) + { + MAGIC_GUARD_CHECK; + #if B_BURN_DAMAGE >= GEN_7 + gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16; + #else + gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8; + #endif + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + BattleScriptExecute(BattleScript_FrostbiteTurnDmg); + effect++; + } + gBattleStruct->turnEffectsTracker++; + break; case ENDTURN_NIGHTMARES: // spooky nightmares if ((gBattleMons[gActiveBattler].status2 & STATUS2_NIGHTMARE) && gBattleMons[gActiveBattler].hp != 0) @@ -3637,6 +3655,17 @@ u8 AtkCanceller_UnableToUseMove(void) } effect = 2; } + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE && (gBattleMoves[gCurrentMove].flags & FLAG_THAW_USER)) + { + if (!(gBattleMoves[gCurrentMove].effect == EFFECT_BURN_UP && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE))) + { + gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FROSTBITE; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveUsedUnfrostbite; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FROSTBITE_HEALED_BY_MOVE; + } + effect = 2; + } gBattleStruct->atkCancellerTracker++; break; case CANCELLER_POWDER_MOVE: @@ -4852,7 +4881,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); if (gBattleMons[battler].status1 & STATUS1_BURN) StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); - if (gBattleMons[battler].status1 & STATUS1_FREEZE) + if (gBattleMons[battler].status1 & (STATUS1_FREEZE | STATUS1_FROSTBITE)) StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); gBattleMons[battler].status1 = 0; @@ -5878,7 +5907,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move } break; case ABILITY_MAGMA_ARMOR: - if (gBattleMons[battler].status1 & STATUS1_FREEZE) + if (gBattleMons[battler].status1 & (STATUS1_FREEZE | STATUS1_FROSTBITE)) { StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); effect = 1; @@ -6411,6 +6440,20 @@ bool32 CanBeFrozen(u8 battlerId) return TRUE; } +bool32 CanGetFrostbite(u8 battlerId) +{ + u16 ability = GetBattlerAbility(battlerId); + if (IS_BATTLER_OF_TYPE(battlerId, TYPE_ICE) + || gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_SAFEGUARD + || ability == ABILITY_MAGMA_ARMOR + || ability == ABILITY_COMATOSE + || gBattleMons[battlerId].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battlerId) + || IsBattlerTerrainAffected(battlerId, STATUS_FIELD_MISTY_TERRAIN)) + return FALSE; + return TRUE; +} + bool32 CanBeConfused(u8 battlerId) { if (GetBattlerAbility(battlerId) == ABILITY_OWN_TEMPO @@ -6825,6 +6868,13 @@ static u8 ItemEffectMoveEnd(u32 battlerId, u16 holdEffect) gBattlescriptCurrInstr = BattleScript_BerryCureFrzRet; effect = ITEM_STATUS_CHANGE; } + if (gBattleMons[battlerId].status1 & STATUS1_FROSTBITE && !UnnerveOn(battlerId, gLastUsedItem)) + { + gBattleMons[battlerId].status1 &= ~STATUS1_FROSTBITE; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BerryCureFsbRet; + effect = ITEM_STATUS_CHANGE; + } break; case HOLD_EFFECT_CURE_SLP: if (gBattleMons[battlerId].status1 & STATUS1_SLEEP && !UnnerveOn(battlerId, gLastUsedItem)) @@ -6873,7 +6923,7 @@ static u8 ItemEffectMoveEnd(u32 battlerId, u16 holdEffect) if (gBattleMons[battlerId].status1 & STATUS1_BURN) StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); - if (gBattleMons[battlerId].status1 & STATUS1_FREEZE) + if (gBattleMons[battlerId].status1 & STATUS1_FREEZE || gBattleMons[battlerId].status1 & STATUS1_FROSTBITE) StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION) @@ -7061,6 +7111,12 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) BattleScriptExecute(BattleScript_BerryCureFrzEnd2); effect = ITEM_STATUS_CHANGE; } + if (gBattleMons[battlerId].status1 & STATUS1_FROSTBITE && !UnnerveOn(battlerId, gLastUsedItem)) + { + gBattleMons[battlerId].status1 &= ~STATUS1_FROSTBITE; + BattleScriptExecute(BattleScript_BerryCureFsbEnd2); + effect = ITEM_STATUS_CHANGE; + } break; case HOLD_EFFECT_CURE_SLP: if (gBattleMons[battlerId].status1 & STATUS1_SLEEP && !UnnerveOn(battlerId, gLastUsedItem)) @@ -7096,7 +7152,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); i++; } - if (gBattleMons[battlerId].status1 & STATUS1_FREEZE) + if (gBattleMons[battlerId].status1 & STATUS1_FREEZE || gBattleMons[battlerId].status1 & STATUS1_FROSTBITE) { StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); i++; @@ -7394,6 +7450,12 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) BattleScriptExecute(BattleScript_BerryCureFrzEnd2); effect = ITEM_STATUS_CHANGE; } + if (gBattleMons[battlerId].status1 & STATUS1_FROSTBITE && !UnnerveOn(battlerId, gLastUsedItem)) + { + gBattleMons[battlerId].status1 &= ~STATUS1_FROSTBITE; + BattleScriptExecute(BattleScript_BerryCureFsbEnd2); + effect = ITEM_STATUS_CHANGE; + } break; case HOLD_EFFECT_CURE_SLP: if (gBattleMons[battlerId].status1 & STATUS1_SLEEP && !UnnerveOn(battlerId, gLastUsedItem)) @@ -7437,7 +7499,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); i++; } - if (gBattleMons[battlerId].status1 & STATUS1_FREEZE) + if (gBattleMons[battlerId].status1 & STATUS1_FREEZE || gBattleMons[battlerId].status1 & STATUS1_FROSTBITE) { StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); i++; @@ -9020,7 +9082,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe switch (gBattleMoves[move].effect) { case EFFECT_FACADE: - if (gBattleMons[battlerAtk].status1 & (STATUS1_BURN | STATUS1_PSN_ANY | STATUS1_PARALYSIS)) + if (gBattleMons[battlerAtk].status1 & (STATUS1_BURN | STATUS1_PSN_ANY | STATUS1_PARALYSIS | STATUS1_FROSTBITE)) MulModifier(&modifier, UQ_4_12(2.0)); break; case EFFECT_BRINE: @@ -9489,6 +9551,14 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move && abilityAtk != ABILITY_GUTS) dmg = ApplyModifier(UQ_4_12(0.5), dmg); + // check frostbite + if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && !IS_MOVE_PHYSICAL(move) + #if B_BURN_FACADE_DMG >= GEN_6 + && gBattleMoves[move].effect != EFFECT_FACADE + #endif + && abilityAtk != ABILITY_GUTS) + dmg = ApplyModifier(UQ_4_12(0.5), dmg); + // check sunny/rain weather if (IsBattlerWeatherAffected(battlerAtk, B_WEATHER_RAIN)) { diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 4a89222a96..9473bae71c 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -121,7 +121,11 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_ICE_PUNCH] = { - .effect = EFFECT_FREEZE_HIT, + #if B_USE_FROSTBITE == TRUE + .effect = EFFECT_FROSTBITE_HIT, + #else + .effect = EFFECT_FREEZE_HIT, + #endif .power = 75, .type = TYPE_ICE, .accuracy = 100, @@ -982,7 +986,13 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = #else .power = 95, #endif - .effect = EFFECT_FREEZE_HIT, + // The following effect is also relevant in battle_pike.c + // If you cherry-pick this to use something other than the config, make sure to update it there too + #if B_USE_FROSTBITE == TRUE + .effect = EFFECT_FROSTBITE_HIT, + #else + .effect = EFFECT_FREEZE_HIT, + #endif .type = TYPE_ICE, .accuracy = 100, .pp = 10, @@ -1001,7 +1011,11 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = #else .power = 120, #endif - .effect = EFFECT_FREEZE_HIT, + #if B_USE_FROSTBITE == TRUE + .effect = EFFECT_FROSTBITE_HIT, + #else + .effect = EFFECT_FREEZE_HIT, + #endif .type = TYPE_ICE, .accuracy = 70, .pp = 5, @@ -3062,7 +3076,11 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_POWDER_SNOW] = { - .effect = EFFECT_FREEZE_HIT, + #if B_USE_FROSTBITE == TRUE + .effect = EFFECT_FROSTBITE_HIT, + #else + .effect = EFFECT_FREEZE_HIT, + #endif .power = 40, .type = TYPE_ICE, .accuracy = 100, @@ -7177,6 +7195,11 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = #else .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_SHEER_FORCE_BOOST | FLAG_STRONG_JAW_BOOST, #endif + #if B_USE_FROSTBITE == TRUE + .argument = STATUS1_FROSTBITE, + #else + .argument = STATUS1_FREEZE, + #endif .effect = EFFECT_FLINCH_STATUS, .power = 65, .type = TYPE_ICE, @@ -7186,7 +7209,6 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = .target = MOVE_TARGET_SELECTED, .priority = 0, .split = SPLIT_PHYSICAL, - .argument = STATUS1_FREEZE, .zMoveEffect = Z_EFFECT_NONE, }, @@ -12354,7 +12376,11 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_FREEZING_GLARE] = { .power = 90, - .effect = EFFECT_FREEZE_HIT, + #if B_USE_FROSTBITE == TRUE + .effect = EFFECT_FROSTBITE_HIT, + #else + .effect = EFFECT_FREEZE_HIT, + #endif .type = TYPE_PSYCHIC, .accuracy = 100, .pp = 10, diff --git a/src/data/party_menu.h b/src/data/party_menu.h index 4a06fa135e..e7ebf98939 100644 --- a/src/data/party_menu.h +++ b/src/data/party_menu.h @@ -1054,7 +1054,7 @@ static const union AnimCmd sSpriteAnim_StatusFaint[] = ANIMCMD_END }; -static const union AnimCmd sSpriteAnim_Blank[] = +static const union AnimCmd sSpriteAnim_StatusFrostbite[] = { ANIMCMD_FRAME(28, 0), ANIMCMD_END @@ -1069,7 +1069,7 @@ static const union AnimCmd *const sSpriteTemplate_StatusCondition[] = sSpriteAnim_StatusBurn, sSpriteAnim_StatusPokerus, sSpriteAnim_StatusFaint, - sSpriteAnim_Blank + sSpriteAnim_StatusFrostbite }; static const struct CompressedSpriteSheet sSpriteSheet_StatusIcons = diff --git a/src/data/text/move_descriptions.h b/src/data/text/move_descriptions.h index c2b7e0b234..f950c2a1aa 100644 --- a/src/data/text/move_descriptions.h +++ b/src/data/text/move_descriptions.h @@ -38,7 +38,11 @@ static const u8 sFirePunchDescription[] = _( static const u8 sIcePunchDescription[] = _( "An icy punch that may\n" +#if B_USE_FROSTBITE == TRUE + "leave the foe with frostbite."); +#else "freeze the foe."); +#endif static const u8 sThunderPunchDescription[] = _( "An electrified punch that\n" @@ -238,11 +242,19 @@ static const u8 sSurfDescription[] = _( static const u8 sIceBeamDescription[] = _( "Blasts the foe with an icy\n" +#if B_USE_FROSTBITE == TRUE + "beam. May cause frostbite."); +#else "beam that may freeze it."); +#endif static const u8 sBlizzardDescription[] = _( "Hits the foe with an icy\n" +#if B_USE_FROSTBITE == TRUE + "storm. May cause frostbite."); +#else "storm that may freeze it."); +#endif static const u8 sPsybeamDescription[] = _( "Fires a peculiar ray that\n" @@ -2931,7 +2943,11 @@ static const u8 sDragonEnergyDescription[] = _( static const u8 sFreezingGlareDescription[] = _( "Shoots psychic power from\n" +#if B_USE_FROSTBITE == TRUE + "the eyes. May frostbite."); +#else "the eyes. May freeze the foe."); +#endif static const u8 sFieryWrathDescription[] = _( "An attack fueled by your\n" diff --git a/src/item.c b/src/item.c index b2b19480a3..2c69372446 100644 --- a/src/item.c +++ b/src/item.c @@ -941,7 +941,7 @@ u8 ItemId_GetBattleUsage(u16 itemId) case ITEM_EFFECT_CURE_POISON: case ITEM_EFFECT_CURE_SLEEP: case ITEM_EFFECT_CURE_BURN: - case ITEM_EFFECT_CURE_FREEZE: + case ITEM_EFFECT_CURE_FREEZE_FROSTBITE: case ITEM_EFFECT_CURE_PARALYSIS: case ITEM_EFFECT_CURE_ALL_STATUS: case ITEM_EFFECT_CURE_CONFUSION: @@ -976,7 +976,7 @@ u32 GetItemStatus1Mask(u16 itemId) case ITEM3_PARALYSIS: return STATUS1_PARALYSIS; case ITEM3_FREEZE: - return STATUS1_FREEZE; + return STATUS1_FREEZE | STATUS1_FROSTBITE; case ITEM3_BURN: return STATUS1_BURN; case ITEM3_POISON: diff --git a/src/item_use.c b/src/item_use.c index 437cf80376..2f703a3a9a 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -1245,7 +1245,7 @@ void ItemUseOutOfBattle_EnigmaBerry(u8 taskId) case ITEM_EFFECT_CURE_POISON: case ITEM_EFFECT_CURE_SLEEP: case ITEM_EFFECT_CURE_BURN: - case ITEM_EFFECT_CURE_FREEZE: + case ITEM_EFFECT_CURE_FREEZE_FROSTBITE: case ITEM_EFFECT_CURE_PARALYSIS: case ITEM_EFFECT_CURE_ALL_STATUS: case ITEM_EFFECT_ATK_EV: diff --git a/src/party_menu.c b/src/party_menu.c index ca0794ad28..773495a4d5 100755 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -1942,6 +1942,8 @@ u8 GetAilmentFromStatus(u32 status) return AILMENT_FRZ; if (status & STATUS1_BURN) return AILMENT_BRN; + if (status & STATUS1_FROSTBITE) + return AILMENT_FSB; return AILMENT_NONE; } @@ -4316,7 +4318,7 @@ static bool8 IsHPRecoveryItem(u16 item) return FALSE; } -static void GetMedicineItemEffectMessage(u16 item) +static void GetMedicineItemEffectMessage(u16 item, u32 statusCured) { switch (GetItemEffectType(item)) { @@ -4329,8 +4331,11 @@ static void GetMedicineItemEffectMessage(u16 item) case ITEM_EFFECT_CURE_BURN: StringExpandPlaceholders(gStringVar4, gText_PkmnBurnHealed); break; - case ITEM_EFFECT_CURE_FREEZE: - StringExpandPlaceholders(gStringVar4, gText_PkmnThawedOut); + case ITEM_EFFECT_CURE_FREEZE_FROSTBITE: + if (statusCured & STATUS1_FREEZE) + StringExpandPlaceholders(gStringVar4, gText_PkmnThawedOut); + if (statusCured & STATUS1_FROSTBITE) + StringExpandPlaceholders(gStringVar4, gText_PkmnFrostbiteHealed); break; case ITEM_EFFECT_CURE_PARALYSIS: StringExpandPlaceholders(gStringVar4, gText_PkmnCuredOfParalysis); @@ -4491,6 +4496,7 @@ void ItemUseCB_Medicine(u8 taskId, TaskFunc task) struct Pokemon *mon = &gPlayerParty[gPartyMenu.slotId]; u16 item = gSpecialVar_ItemId; bool8 canHeal, cannotUse; + u32 oldStatus = GetMonData(mon, MON_DATA_STATUS); if (NotUsingHPEVItemOnShedinja(mon, item) == FALSE) { @@ -4543,7 +4549,7 @@ void ItemUseCB_Medicine(u8 taskId, TaskFunc task) else { GetMonNickname(mon, gStringVar1); - GetMedicineItemEffectMessage(item); + GetMedicineItemEffectMessage(item, oldStatus); DisplayPartyMenuMessage(gStringVar4, TRUE); ScheduleBgCopyTilemapToVram(2); gTasks[taskId].func = task; @@ -4967,7 +4973,7 @@ static void TryUseItemOnMove(u8 taskId) RemoveBagItem(item, 1); move = GetMonData(mon, MON_DATA_MOVE1 + *moveSlot); StringCopy(gStringVar1, gMoveNames[move]); - GetMedicineItemEffectMessage(item); + GetMedicineItemEffectMessage(item, 0); DisplayPartyMenuMessage(gStringVar4, TRUE); ScheduleBgCopyTilemapToVram(2); gTasks[taskId].func = Task_ClosePartyMenuAfterText; @@ -5817,7 +5823,7 @@ u8 GetItemEffectType(u16 item) else if (statusCure == ITEM3_BURN) return ITEM_EFFECT_CURE_BURN; else if (statusCure == ITEM3_FREEZE) - return ITEM_EFFECT_CURE_FREEZE; + return ITEM_EFFECT_CURE_FREEZE_FROSTBITE; else if (statusCure == ITEM3_PARALYSIS) return ITEM_EFFECT_CURE_PARALYSIS; else if (statusCure == ITEM3_CONFUSION) diff --git a/src/pokemon.c b/src/pokemon.c index 2cdaf453f0..ec63332fef 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -5815,7 +5815,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov retVal = FALSE; if ((itemEffect[i] & ITEM3_BURN) && HealStatusConditions(mon, partyIndex, STATUS1_BURN, battlerId) == 0) retVal = FALSE; - if ((itemEffect[i] & ITEM3_FREEZE) && HealStatusConditions(mon, partyIndex, STATUS1_FREEZE, battlerId) == 0) + if ((itemEffect[i] & ITEM3_FREEZE) && HealStatusConditions(mon, partyIndex, STATUS1_FREEZE | STATUS1_FROSTBITE, battlerId) == 0) retVal = FALSE; if ((itemEffect[i] & ITEM3_PARALYSIS) && HealStatusConditions(mon, partyIndex, STATUS1_PARALYSIS, battlerId) == 0) retVal = FALSE; diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c index 3313076262..f7106b8752 100644 --- a/src/pokemon_summary_screen.c +++ b/src/pokemon_summary_screen.c @@ -1112,6 +1112,10 @@ static const union AnimCmd sSpriteAnim_StatusFaint[] = { ANIMCMD_FRAME(24, 0, FALSE, FALSE), ANIMCMD_END }; +static const union AnimCmd sSpriteAnim_StatusFrostbite[] = { + ANIMCMD_FRAME(28, 0, FALSE, FALSE), + ANIMCMD_END +}; static const union AnimCmd *const sSpriteAnimTable_StatusCondition[] = { sSpriteAnim_StatusPoison, sSpriteAnim_StatusParalyzed, @@ -1120,11 +1124,12 @@ static const union AnimCmd *const sSpriteAnimTable_StatusCondition[] = { sSpriteAnim_StatusBurn, sSpriteAnim_StatusPokerus, sSpriteAnim_StatusFaint, + sSpriteAnim_StatusFrostbite, }; static const struct CompressedSpriteSheet sStatusIconsSpriteSheet = { .data = gStatusGfx_Icons, - .size = 0x380, + .size = 0x400, .tag = TAG_MON_STATUS }; static const struct CompressedSpritePalette sStatusIconsSpritePalette = diff --git a/src/strings.c b/src/strings.c index 75ff2ef994..eb7bb8ba1f 100644 --- a/src/strings.c +++ b/src/strings.c @@ -414,6 +414,7 @@ const u8 gText_PkmnCuredOfPoison[] = _("{STR_VAR_1} was cured of its\npoisoning. const u8 gText_PkmnCuredOfParalysis[] = _("{STR_VAR_1} was cured of\nparalysis.{PAUSE_UNTIL_PRESS}"); const u8 gText_PkmnWokeUp2[] = _("{STR_VAR_1} woke up.{PAUSE_UNTIL_PRESS}"); const u8 gText_PkmnBurnHealed[] = _("{STR_VAR_1}'s burn was healed.{PAUSE_UNTIL_PRESS}"); +const u8 gText_PkmnFrostbiteHealed[] = _("{STR_VAR_1}'s frostbite was healed.{PAUSE_UNTIL_PRESS}"); const u8 gText_PkmnThawedOut[] = _("{STR_VAR_1} was thawed out.{PAUSE_UNTIL_PRESS}"); const u8 gText_PPWasRestored[] = _("PP was restored.{PAUSE_UNTIL_PRESS}"); const u8 gText_PkmnRegainhedHealth[] = _("{STR_VAR_1} regained health.{PAUSE_UNTIL_PRESS}"); // Unused diff --git a/test/status_frostbite.c b/test/status_frostbite.c new file mode 100644 index 0000000000..f034478217 --- /dev/null +++ b/test/status_frostbite.c @@ -0,0 +1,96 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Frostbite reduces the special attack by 50 percent") +{ + s16 reducedDamage; + s16 normaleDamage; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_FROSTBITE); } + } WHEN { + TURN { MOVE(opponent, MOVE_SWIFT); MOVE(player, MOVE_FLAME_WHEEL); } + TURN { MOVE(opponent, MOVE_SWIFT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWIFT, opponent); + HP_BAR(player, captureDamage: &reducedDamage); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLAME_WHEEL, player); + HP_BAR(opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWIFT, opponent); + HP_BAR(player, captureDamage: &normaleDamage); + } THEN { EXPECT_EQ(reducedDamage * 2, normaleDamage); } +} + +SINGLE_BATTLE_TEST("Frostbite deals 1/16 damage to effected pokemon") +{ + s16 frostbiteDamage; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_FROSTBITE); } + } WHEN { + TURN { } + } SCENE { + MESSAGE("Foe Wobbuffet is hurt by its frostbite!"); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent); + HP_BAR(opponent, captureDamage: &frostbiteDamage); + } THEN { EXPECT_EQ(frostbiteDamage, opponent->maxHP / 16); } +} + +SINGLE_BATTLE_TEST("Frostbite is healed if hit with a thawing move") +{ + u32 move; + + PARAMETRIZE { move = MOVE_FLAME_WHEEL; } + PARAMETRIZE { move = MOVE_SACRED_FIRE; } + PARAMETRIZE { move = MOVE_FLARE_BLITZ; } + PARAMETRIZE { move = MOVE_FUSION_FLARE; } + PARAMETRIZE { move = MOVE_EMBER; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_FROSTBITE); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + if (move == MOVE_EMBER) { + NONE_OF { + MESSAGE("Foe Wobbuffet's frostbite was healed!"); + } + } else { + MESSAGE("Foe Wobbuffet's frostbite was healed!"); + } + } +} + +SINGLE_BATTLE_TEST("Frostbite is healed when the user uses a thawing move") +{ + u32 move; + + PARAMETRIZE { move = MOVE_FLAME_WHEEL; } + PARAMETRIZE { move = MOVE_SACRED_FIRE; } + PARAMETRIZE { move = MOVE_FLARE_BLITZ; } + PARAMETRIZE { move = MOVE_FUSION_FLARE; } + PARAMETRIZE { move = MOVE_EMBER; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FROSTBITE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + if (move == MOVE_EMBER) { + MESSAGE("Wobbuffet is hurt by its frostbite!"); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, player); + } else { + NONE_OF { + MESSAGE("Wobbuffet is hurt by its frostbite!"); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, player); + } + } + } +} diff --git a/test/test_battle.h b/test/test_battle.h index 967bb661dd..432e33fa80 100644 --- a/test/test_battle.h +++ b/test/test_battle.h @@ -333,7 +333,7 @@ * Used when the battler chooses to switch to another Pokémon but not * via Switch, e.g. after fainting or due to a U-turn. * SEND_OUT(player, 1); - * + * * USE_ITEM(battler, itemId, [partyIndex:], [move:]) * Used when the battler chooses to use an item from the Bag. The item * ID must be specified, and party index and move slot if applicable, e.g: @@ -526,8 +526,7 @@ struct QueuedMessageEvent struct QueuedStatusEvent { u32 battlerId:3; - u32 mask:8; - u32 unused_01:21; + u32 mask:29; }; struct QueuedEvent @@ -872,6 +871,7 @@ struct StatusEventContext bool8 freeze:1; bool8 paralysis:1; bool8 badPoison:1; + bool8 frostbite:1; }; void OpenQueueGroup(u32 sourceLine, enum QueueGroupType); diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 9f3b9a5f80..95c4513084 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -1720,6 +1720,8 @@ void QueueStatus(u32 sourceLine, struct BattlePokemon *battler, struct StatusEve mask = STATUS1_PARALYSIS; else if (ctx.badPoison) mask = STATUS1_TOXIC_POISON; + else if (ctx.frostbite) + mask = STATUS1_FROSTBITE; else mask = ctx.status1;