mirror of
https://github.com/rh-hideout/pokeemerald-expansion.git
synced 2026-04-26 02:14:22 -05:00
Adds hazard queue (#7295)
This commit is contained in:
parent
7ae97ab6e9
commit
31a561201b
|
|
@ -6113,53 +6113,13 @@ BattleScript_LeechSeedFree::
|
|||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_SpikesFree::
|
||||
printstring STRINGID_PKMNBLEWAWAYSPIKES
|
||||
BattleScript_SpinHazardsAway::
|
||||
printfromtable gSpinHazardsStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_ToxicSpikesFree::
|
||||
printstring STRINGID_PKMNBLEWAWAYTOXICSPIKES
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_StickyWebFree::
|
||||
printstring STRINGID_PKMNBLEWAWAYSTICKYWEB
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_StealthRockFree::
|
||||
printstring STRINGID_PKMNBLEWAWAYSTEALTHROCK
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_SteelsurgeFree::
|
||||
printstring STRINGID_PKMNBLEWAWAYSHARPSTEEL
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_SpikesDefog::
|
||||
printstring STRINGID_SPIKESDISAPPEAREDFROMTEAM
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_ToxicSpikesDefog::
|
||||
printstring STRINGID_TOXICSPIKESDISAPPEAREDFROMTEAM
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_StickyWebDefog::
|
||||
printstring STRINGID_STICKYWEBDISAPPEAREDFROMTEAM
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_StealthRockDefog::
|
||||
printstring STRINGID_STEALTHROCKDISAPPEAREDFROMTEAM
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_SteelsurgeDefog::
|
||||
printstring STRINGID_SHARPSTEELDISAPPEAREDFROMTEAM
|
||||
BattleScript_DefogClearHazards::
|
||||
printfromtable gDefogHazardsStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -117,24 +117,20 @@ struct DisableStruct
|
|||
u8 tarShot:1;
|
||||
u8 octolock:1;
|
||||
u8 cudChew:1;
|
||||
u8 spikesDone:1;
|
||||
u8 toxicSpikesDone:1;
|
||||
u8 stickyWebDone:1;
|
||||
u8 stealthRockDone:1;
|
||||
u8 weatherAbilityDone:1;
|
||||
u8 terrainAbilityDone:1;
|
||||
u8 syrupBombIsShiny:1;
|
||||
u8 steelSurgeDone:1;
|
||||
u8 usedProteanLibero:1;
|
||||
u8 flashFireBoosted:1;
|
||||
u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching)
|
||||
u8 boosterEnergyActivated:1;
|
||||
u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching)
|
||||
u8 roostActive:1;
|
||||
u8 unburdenActive:1;
|
||||
u8 neutralizingGas:1;
|
||||
u8 iceFaceActivationPrevention:1; // fixes hit escape move edge case
|
||||
u8 unnerveActivated:1; // Unnerve and As One (Unnerve part) activate only once per switch in
|
||||
u8 padding:3;
|
||||
u8 hazardsDone:1;
|
||||
u8 padding:1;
|
||||
};
|
||||
|
||||
// Fully Cleared each turn after end turn effects are done. A few things are cleared before end turn effects
|
||||
|
|
@ -222,21 +218,18 @@ struct SideTimer
|
|||
u16 lightscreenTimer;
|
||||
u16 mistTimer;
|
||||
u16 safeguardTimer;
|
||||
u16 spikesAmount; // debug menu complains. might be better to solve there instead if possible
|
||||
u16 toxicSpikesAmount;
|
||||
u16 stealthRockAmount;
|
||||
u16 stickyWebAmount;
|
||||
u8 spikesAmount:4;
|
||||
u8 toxicSpikesAmount:4;
|
||||
u8 stickyWebBattlerId;
|
||||
u8 stickyWebBattlerSide; // Used for Court Change
|
||||
u16 auroraVeilTimer;
|
||||
u16 tailwindTimer;
|
||||
u16 luckyChantTimer;
|
||||
u16 steelsurgeAmount;
|
||||
// Timers below this point are not swapped by Court Change
|
||||
u16 followmeTimer;
|
||||
u8 followmeTimer:4;
|
||||
u8 followmeTarget:3;
|
||||
u8 followmePowder:1; // Rage powder, does not affect grass type pokemon.
|
||||
u16 retaliateTimer;
|
||||
u8 retaliateTimer;
|
||||
u16 damageNonTypesTimer;
|
||||
u8 damageNonTypesType;
|
||||
u16 rainbowTimer;
|
||||
|
|
@ -780,6 +773,10 @@ struct BattleStruct
|
|||
s16 savedcheekPouchDamage; // Cheek Pouch can happen in the middle of an attack execution so we need to store the current dmg
|
||||
struct MessageStatus slideMessageStatus;
|
||||
u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT];
|
||||
u8 hazardsQueue[NUM_BATTLE_SIDES][HAZARDS_MAX_COUNT];
|
||||
u8 numHazards[NUM_BATTLE_SIDES];
|
||||
u8 hazardsCounter:4; // Counter for applying hazard on switch in
|
||||
u8 padding2:4;
|
||||
};
|
||||
|
||||
struct AiBattleData
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ extern const u8 BattleScript_AllStatsUp[];
|
|||
extern const u8 BattleScript_RapidSpinAway[];
|
||||
extern const u8 BattleScript_WrapFree[];
|
||||
extern const u8 BattleScript_LeechSeedFree[];
|
||||
extern const u8 BattleScript_SpikesFree[];
|
||||
extern const u8 BattleScript_SpinHazardsAway[];
|
||||
extern const u8 BattleScript_MonTookFutureAttack[];
|
||||
extern const u8 BattleScript_NoMovesLeft[];
|
||||
extern const u8 BattleScript_SelectingMoveWithNoPP[];
|
||||
|
|
@ -312,13 +312,7 @@ extern const u8 BattleScript_SelectingNotAllowedMoveGravityInPalace[];
|
|||
extern const u8 BattleScript_SelectingNotAllowedMoveHealBlock[];
|
||||
extern const u8 BattleScript_MoveUsedHealBlockPrevents[];
|
||||
extern const u8 BattleScript_SelectingNotAllowedMoveHealBlockInPalace[];
|
||||
extern const u8 BattleScript_ToxicSpikesFree[];
|
||||
extern const u8 BattleScript_StickyWebFree[];
|
||||
extern const u8 BattleScript_StealthRockFree[];
|
||||
extern const u8 BattleScript_SpikesDefog[];
|
||||
extern const u8 BattleScript_ToxicSpikesDefog[];
|
||||
extern const u8 BattleScript_StickyWebDefog[];
|
||||
extern const u8 BattleScript_StealthRockDefog[];
|
||||
extern const u8 BattleScript_DefogClearHazards[];
|
||||
extern const u8 BattleScript_MegaEvolution[];
|
||||
extern const u8 BattleScript_WishMegaEvolution[];
|
||||
extern const u8 BattleScript_MoveEffectClearSmog[];
|
||||
|
|
@ -555,8 +549,6 @@ extern const u8 BattleScript_EffectSetWeather[];
|
|||
extern const u8 BattleScript_EffectSetTerrain[];
|
||||
extern const u8 BattleScript_EffectStonesurge[];
|
||||
extern const u8 BattleScript_EffectSteelsurge[];
|
||||
extern const u8 BattleScript_SteelsurgeFree[];
|
||||
extern const u8 BattleScript_SteelsurgeDefog[];
|
||||
extern const u8 BattleScript_DamageNonTypesStarts[];
|
||||
extern const u8 BattleScript_DamageNonTypesContinues[];
|
||||
extern const u8 BattleScript_DefogTryHazards[];
|
||||
|
|
|
|||
|
|
@ -400,5 +400,11 @@ bool32 TrySwitchInEjectPack(enum ItemCaseId caseID);
|
|||
u32 GetMonVolatile(u32 battler, enum Volatile volatile);
|
||||
void SetMonVolatile(u32 battler, enum Volatile volatile, u32 newValue);
|
||||
u32 TryBoosterEnergy(u32 battler, u32 ability, enum ItemCaseId caseID);
|
||||
void PushHazardTypeToQueue(u32 side, enum Hazards hazardType);
|
||||
bool32 IsHazardOnSide(u32 side, enum Hazards hazardType);
|
||||
bool32 AreAnyHazardsOnSide(u32 side);
|
||||
void RemoveAllHazardsFromField(u32 side);
|
||||
bool32 IsHazardOnSideAndClear(u32 side, enum Hazards hazardType);
|
||||
void RemoveHazardFromField(u32 side, enum Hazards hazardType);
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
|
|
|||
|
|
@ -289,28 +289,31 @@ enum Volatile
|
|||
// Per-side statuses that affect an entire party
|
||||
#define SIDE_STATUS_REFLECT (1 << 0)
|
||||
#define SIDE_STATUS_LIGHTSCREEN (1 << 1)
|
||||
#define SIDE_STATUS_STICKY_WEB (1 << 2)
|
||||
#define SIDE_STATUS_SPIKES (1 << 4)
|
||||
#define SIDE_STATUS_SAFEGUARD (1 << 5)
|
||||
#define SIDE_STATUS_FUTUREATTACK (1 << 6)
|
||||
#define SIDE_STATUS_MIST (1 << 8)
|
||||
// (1 << 9) previously was SIDE_STATUS_SPIKES_DAMAGED
|
||||
#define SIDE_STATUS_TAILWIND (1 << 10)
|
||||
#define SIDE_STATUS_AURORA_VEIL (1 << 11)
|
||||
#define SIDE_STATUS_LUCKY_CHANT (1 << 12)
|
||||
#define SIDE_STATUS_TOXIC_SPIKES (1 << 13)
|
||||
#define SIDE_STATUS_STEALTH_ROCK (1 << 14)
|
||||
// Missing flags previously were SIDE_STATUS_TOXIC_SPIKES_DAMAGED, SIDE_STATUS_STEALTH_ROCK_DAMAGED, SIDE_STATUS_STICKY_WEB_DAMAGED
|
||||
#define SIDE_STATUS_STEELSURGE (1 << 18)
|
||||
#define SIDE_STATUS_DAMAGE_NON_TYPES (1 << 19)
|
||||
#define SIDE_STATUS_RAINBOW (1 << 20)
|
||||
#define SIDE_STATUS_SEA_OF_FIRE (1 << 21)
|
||||
#define SIDE_STATUS_SWAMP (1 << 22)
|
||||
#define SIDE_STATUS_SAFEGUARD (1 << 2)
|
||||
#define SIDE_STATUS_FUTUREATTACK (1 << 3)
|
||||
#define SIDE_STATUS_MIST (1 << 4)
|
||||
#define SIDE_STATUS_TAILWIND (1 << 5)
|
||||
#define SIDE_STATUS_AURORA_VEIL (1 << 6)
|
||||
#define SIDE_STATUS_LUCKY_CHANT (1 << 7)
|
||||
#define SIDE_STATUS_DAMAGE_NON_TYPES (1 << 8)
|
||||
#define SIDE_STATUS_RAINBOW (1 << 9)
|
||||
#define SIDE_STATUS_SEA_OF_FIRE (1 << 10)
|
||||
#define SIDE_STATUS_SWAMP (1 << 11)
|
||||
|
||||
#define SIDE_STATUS_HAZARDS_ANY (SIDE_STATUS_SPIKES | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STEELSURGE)
|
||||
#define SIDE_STATUS_SCREEN_ANY (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL)
|
||||
#define SIDE_STATUS_PLEDGE_ANY (SIDE_STATUS_RAINBOW | SIDE_STATUS_SEA_OF_FIRE | SIDE_STATUS_SWAMP)
|
||||
|
||||
enum Hazards
|
||||
{
|
||||
HAZARDS_NONE,
|
||||
HAZARDS_SPIKES,
|
||||
HAZARDS_STICKY_WEB,
|
||||
HAZARDS_TOXIC_SPIKES,
|
||||
HAZARDS_STEALTH_ROCK,
|
||||
HAZARDS_STEELSURGE,
|
||||
HAZARDS_MAX_COUNT,
|
||||
};
|
||||
|
||||
// Used for damaging entry hazards based on type
|
||||
enum TypeSideHazard
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1817,7 +1817,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
ADJUST_SCORE(-10); // only one mon needs to set up the last layer of Spikes
|
||||
break;
|
||||
case EFFECT_STEALTH_ROCK:
|
||||
if (gSideTimers[GetBattlerSide(battlerDef)].stealthRockAmount > 0
|
||||
if (IsHazardOnSide(GetBattlerSide(battlerDef), HAZARDS_STEALTH_ROCK)
|
||||
|| PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) //Only one mon needs to set up Stealth Rocks
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
|
|
@ -1828,9 +1828,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
ADJUST_SCORE(-10); // only one mon needs to set up the last layer of Toxic Spikes
|
||||
break;
|
||||
case EFFECT_STICKY_WEB:
|
||||
if (gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount)
|
||||
if (IsHazardOnSide(GetBattlerSide(battlerDef), HAZARDS_STICKY_WEB))
|
||||
ADJUST_SCORE(-10);
|
||||
else if (PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount)
|
||||
else if (PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove) && IsHazardOnSide(GetBattlerSide(battlerDef), HAZARDS_STICKY_WEB))
|
||||
ADJUST_SCORE(-10); // only one mon needs to set up Sticky Web
|
||||
break;
|
||||
case EFFECT_FORESIGHT:
|
||||
|
|
@ -2283,9 +2283,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
ADJUST_SCORE(-9);
|
||||
break;
|
||||
case EFFECT_DEFOG:
|
||||
if (gSideStatuses[GetBattlerSide(battlerDef)]
|
||||
& (SIDE_STATUS_SCREEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST)
|
||||
|| gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY)
|
||||
if (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SCREEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST)
|
||||
|| AreAnyHazardsOnSide(GetBattlerSide(battlerAtk)))
|
||||
{
|
||||
if (PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
{
|
||||
|
|
@ -2294,7 +2293,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
}
|
||||
}
|
||||
|
||||
if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_HAZARDS_ANY)
|
||||
if (AreAnyHazardsOnSide(GetBattlerSide(battlerDef)))
|
||||
{
|
||||
ADJUST_SCORE(-10); //Don't blow away opposing hazards
|
||||
break;
|
||||
|
|
@ -4390,12 +4389,12 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||
//ADJUST_SCORE(8);
|
||||
break;
|
||||
case EFFECT_DEFOG:
|
||||
if ((gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0)
|
||||
if ((AreAnyHazardsOnSide(GetBattlerSide(battlerAtk)) && CountUsablePartyMons(battlerAtk) != 0)
|
||||
|| (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SCREEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST)))
|
||||
{
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
}
|
||||
else if (!(gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SPIKES)) //Don't blow away hazards if you set them up
|
||||
else if (!IsHazardOnSide(GetBattlerSide(battlerDef), HAZARDS_SPIKES)) //Don't blow away hazards if you set them up
|
||||
{
|
||||
if (isDoubleBattle)
|
||||
{
|
||||
|
|
@ -4939,7 +4938,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_RAPID_SPIN:
|
||||
if ((gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0)
|
||||
if ((AreAnyHazardsOnSide(GetBattlerSide(battlerAtk)) && CountUsablePartyMons(battlerAtk) != 0)
|
||||
|| (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
case EFFECT_SPECTRAL_THIEF:
|
||||
|
|
@ -5789,13 +5788,31 @@ static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
|||
return score;
|
||||
}
|
||||
|
||||
bool32 DoesSideHaveDamagingHazards(u32 side)
|
||||
{
|
||||
for (u32 counter = 0; counter < HAZARDS_MAX_COUNT; counter++)
|
||||
{
|
||||
switch (gBattleStruct->hazardsQueue[side][counter])
|
||||
{
|
||||
case HAZARDS_SPIKES:
|
||||
case HAZARDS_TOXIC_SPIKES:
|
||||
case HAZARDS_STEALTH_ROCK:
|
||||
case HAZARDS_STEELSURGE:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
u32 i;
|
||||
u32 unmodifiedScore = score;
|
||||
u32 ability = gBattleMons[battlerAtk].ability;
|
||||
u32 opposingHazardFlags = gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_TOXIC_SPIKES);
|
||||
u32 aiHazardFlags = gSideStatuses[GetBattlerSide(battlerAtk)] & (SIDE_STATUS_HAZARDS_ANY);
|
||||
bool32 opposingHazardFlags = DoesSideHaveDamagingHazards(GetBattlerSide(battlerDef));
|
||||
bool32 aiHazardFlags = AreAnyHazardsOnSide(GetBattlerSide(battlerAtk));
|
||||
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
|
||||
struct AiLogicData *aiData = gAiLogicData;
|
||||
uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex];
|
||||
|
|
@ -5856,21 +5873,21 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_HIT_SWITCH_TARGET:
|
||||
if (opposingHazardFlags != 0)
|
||||
if (opposingHazardFlags)
|
||||
ADJUST_SCORE(BEST_EFFECT);
|
||||
else
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_ROAR:
|
||||
if (opposingHazardFlags != 0)
|
||||
if (opposingHazardFlags)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_RAPID_SPIN:
|
||||
if (aiHazardFlags != 0)
|
||||
if (aiHazardFlags)
|
||||
ADJUST_SCORE(BEST_EFFECT);
|
||||
break;
|
||||
case EFFECT_DEFOG:
|
||||
if (aiHazardFlags != 0)
|
||||
if (aiHazardFlags)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_WISH:
|
||||
|
|
|
|||
|
|
@ -1529,20 +1529,20 @@ static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon
|
|||
u16 heldItemEffect = GetItemHoldEffect(battleMon->item);
|
||||
u32 maxHP = battleMon->maxHP, ability = battleMon->ability, status = battleMon->status1;
|
||||
u32 spikesDamage = 0, tSpikesDamage = 0, hazardDamage = 0;
|
||||
u32 hazardFlags = gSideStatuses[GetBattlerSide(battler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES | SIDE_STATUS_SAFEGUARD);
|
||||
u32 side = GetBattlerSide(battler);
|
||||
|
||||
// Check ways mon might avoid all hazards
|
||||
if (ability != ABILITY_MAGIC_GUARD || (heldItemEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS &&
|
||||
!((gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) || ability == ABILITY_KLUTZ)))
|
||||
{
|
||||
// Stealth Rock
|
||||
if ((hazardFlags & SIDE_STATUS_STEALTH_ROCK) && heldItemEffect != HOLD_EFFECT_HEAVY_DUTY_BOOTS)
|
||||
if (IsHazardOnSide(side, HAZARDS_STEALTH_ROCK) && heldItemEffect != HOLD_EFFECT_HEAVY_DUTY_BOOTS)
|
||||
hazardDamage += GetStealthHazardDamageByTypesAndHP(TYPE_SIDE_HAZARD_POINTED_STONES, defType1, defType2, battleMon->maxHP);
|
||||
// G-Max Steelsurge
|
||||
if ((hazardFlags & SIDE_STATUS_STEELSURGE) && heldItemEffect != HOLD_EFFECT_HEAVY_DUTY_BOOTS)
|
||||
if (IsHazardOnSide(side, HAZARDS_STEELSURGE) && heldItemEffect != HOLD_EFFECT_HEAVY_DUTY_BOOTS)
|
||||
hazardDamage += GetStealthHazardDamageByTypesAndHP(TYPE_SIDE_HAZARD_SHARP_STEEL, defType1, defType2, battleMon->maxHP);
|
||||
// Spikes
|
||||
if ((hazardFlags & SIDE_STATUS_SPIKES) && IsMonGrounded(heldItemEffect, ability, defType1, defType2))
|
||||
if (IsHazardOnSide(side, HAZARDS_TOXIC_SPIKES) && IsMonGrounded(heldItemEffect, ability, defType1, defType2))
|
||||
{
|
||||
spikesDamage = maxHP / ((5 - gSideTimers[GetBattlerSide(battler)].spikesAmount) * 2);
|
||||
if (spikesDamage == 0)
|
||||
|
|
@ -1550,11 +1550,11 @@ static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon
|
|||
hazardDamage += spikesDamage;
|
||||
}
|
||||
|
||||
if ((hazardFlags & SIDE_STATUS_TOXIC_SPIKES) && (defType1 != TYPE_POISON && defType2 != TYPE_POISON
|
||||
if (IsHazardOnSide(side, HAZARDS_SPIKES) && (defType1 != TYPE_POISON && defType2 != TYPE_POISON
|
||||
&& defType1 != TYPE_STEEL && defType2 != TYPE_STEEL
|
||||
&& ability != ABILITY_IMMUNITY && ability != ABILITY_POISON_HEAL && ability != ABILITY_COMATOSE
|
||||
&& status == 0
|
||||
&& !(hazardFlags & SIDE_STATUS_SAFEGUARD)
|
||||
&& !(gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD)
|
||||
&& !IsAbilityOnSide(battler, ABILITY_PASTEL_VEIL)
|
||||
&& !IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN)
|
||||
&& !IsAbilityStatusProtected(battler, ability)
|
||||
|
|
|
|||
|
|
@ -1982,7 +1982,7 @@ u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat)
|
|||
// Don't decrese stat if opposing battler has Encore
|
||||
if (HasBattlerSideMoveWithEffect(battlerDef, EFFECT_ENCORE))
|
||||
return NO_INCREASE;
|
||||
|
||||
|
||||
if (DoesAbilityRaiseStatsWhenLowered(gAiLogicData->abilities[battlerDef]))
|
||||
return NO_INCREASE;
|
||||
|
||||
|
|
@ -2979,13 +2979,13 @@ static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler)
|
|||
u32 ability = GetMonAbility(mon); // we know our own party data
|
||||
enum ItemHoldEffect holdEffect;
|
||||
u32 species = GetMonData(mon, MON_DATA_SPECIES);
|
||||
u32 flags = gSideStatuses[GetBattlerSide(currBattler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STEELSURGE | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES);
|
||||
s32 hazardDamage = 0;
|
||||
u32 type1 = GetSpeciesType(species, 0);
|
||||
u32 type2 = GetSpeciesType(species, 1);
|
||||
u32 maxHp = GetMonData(mon, MON_DATA_MAX_HP);
|
||||
u32 side = GetBattlerSide(currBattler);
|
||||
|
||||
if (flags == 0)
|
||||
if (!AreAnyHazardsOnSide(side))
|
||||
return FALSE;
|
||||
|
||||
if (ability == ABILITY_MAGIC_GUARD)
|
||||
|
|
@ -2997,12 +2997,12 @@ static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler)
|
|||
if (holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS)
|
||||
return FALSE;
|
||||
|
||||
if (flags & SIDE_STATUS_STEALTH_ROCK)
|
||||
if (IsHazardOnSide(side, HAZARDS_STEALTH_ROCK))
|
||||
hazardDamage += GetStealthHazardDamageByTypesAndHP(TYPE_SIDE_HAZARD_POINTED_STONES, type1, type2, maxHp);
|
||||
if ((flags & SIDE_STATUS_STEELSURGE))
|
||||
if (IsHazardOnSide(side, HAZARDS_STEELSURGE))
|
||||
hazardDamage += GetStealthHazardDamageByTypesAndHP(TYPE_SIDE_HAZARD_SHARP_STEEL, type1, type2, maxHp);
|
||||
|
||||
if (flags & SIDE_STATUS_SPIKES && ((type1 != TYPE_FLYING && type2 != TYPE_FLYING
|
||||
if (IsHazardOnSide(side, HAZARDS_SPIKES) && ((type1 != TYPE_FLYING && type2 != TYPE_FLYING
|
||||
&& ability != ABILITY_LEVITATE && holdEffect != HOLD_EFFECT_AIR_BALLOON)
|
||||
|| holdEffect == HOLD_EFFECT_IRON_BALL || gFieldStatuses & STATUS_FIELD_GRAVITY))
|
||||
{
|
||||
|
|
@ -3070,7 +3070,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov
|
|||
return SHOULD_PIVOT;
|
||||
|
||||
/* TODO - check if switchable mon unafffected by/will remove hazards
|
||||
if (gSideStatuses[battlerAtk] & SIDE_STATUS_SPIKES && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS)
|
||||
if (IsHazardOnSide(GetBattlerSide(battlerAtk, HAZARDS_SPIKES) && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS)
|
||||
return SHOULD_PIVOT;*/
|
||||
|
||||
/*if (BattlerWillFaintFromSecondaryDamage(battlerAtk, gAiLogicData->abilities[battlerAtk]) && switchScore >= SWITCHING_INCREASE_WALLS_FOE)
|
||||
|
|
@ -3152,7 +3152,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov
|
|||
if (!hasStatBoost)
|
||||
{
|
||||
// TODO - check if switching prevents/removes hazards
|
||||
//if (gSideStatuses[battlerAtk] & SIDE_STATUS_SPIKES && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS)
|
||||
//if (IsHazardOnSide(GetBattlerSide(battlerAtk, HAZARDS_SPIKES) && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS)
|
||||
//return SHOULD_PIVOT;
|
||||
|
||||
// TODO - not always a good idea
|
||||
|
|
@ -4787,9 +4787,9 @@ bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData
|
|||
|
||||
void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
{
|
||||
if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0)
|
||||
if (AreAnyHazardsOnSide(GetBattlerSide(battlerAtk)) && CountUsablePartyMons(battlerAtk) != 0)
|
||||
ADJUST_SCORE_PTR(GOOD_EFFECT);
|
||||
if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerDef) != 0)
|
||||
if (AreAnyHazardsOnSide(GetBattlerSide(battlerDef)) && CountUsablePartyMons(battlerDef) != 0)
|
||||
ADJUST_SCORE_PTR(-2);
|
||||
|
||||
if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE && AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
|
|
@ -5029,7 +5029,7 @@ bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, u32 ability)
|
|||
// At the moment, the parts about Mummy and Wandering Spirit are not actually used.
|
||||
bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct AiLogicData *aiData)
|
||||
{
|
||||
// Dynamaxed Pokemon are immune to some ability-changing effects.
|
||||
// Dynamaxed Pokemon are immune to some ability-changing effects.
|
||||
if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX)
|
||||
{
|
||||
switch (effect)
|
||||
|
|
@ -5044,7 +5044,7 @@ bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct
|
|||
|
||||
if (gStatuses3[battlerDef] & STATUS3_GASTRO_ACID)
|
||||
return FALSE;
|
||||
|
||||
|
||||
u32 atkAbility = aiData->abilities[battlerAtk];
|
||||
u32 defAbility = aiData->abilities[battlerDef];
|
||||
bool32 hasSameAbility = (atkAbility == defAbility);
|
||||
|
|
@ -5078,7 +5078,7 @@ bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct
|
|||
{
|
||||
u32 partnerAbility = aiData->abilities[BATTLE_PARTNER(battlerAtk)];
|
||||
if (gAbilitiesInfo[partnerAbility].cantBeSuppressed)
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
if (partnerAbility == defAbility)
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -5113,7 +5113,7 @@ bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct
|
|||
if (defAbility == ABILITY_INSOMNIA || gAbilitiesInfo[defAbility].cantBeOverwritten)
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -5217,14 +5217,14 @@ void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 effect, s32 *score,
|
|||
{
|
||||
ADJUST_SCORE_PTR(-20);
|
||||
}
|
||||
|
||||
|
||||
// Trigger Plus or Minus in modern gens. This is not in the overarching function because Skill Swap is rarely beneficial here.
|
||||
if (B_PLUS_MINUS_INTERACTION >= GEN_5)
|
||||
{
|
||||
if (((effect == EFFECT_ENTRAINMENT) && (abilityAtk == ABILITY_PLUS || abilityAtk == ABILITY_MINUS)) || ((effect == EFFECT_ROLE_PLAY) && (abilityDef == ABILITY_PLUS || abilityDef == ABILITY_MINUS)))
|
||||
ADJUST_SCORE_PTR(DECENT_EFFECT);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// Targeting an opponent.
|
||||
else
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ enum
|
|||
LIST_ITEM_VOLATILE,
|
||||
LIST_ITEM_STATUS3,
|
||||
LIST_ITEM_STATUS4,
|
||||
LIST_ITEM_HAZARDS,
|
||||
LIST_ITEM_SIDE_STATUS,
|
||||
LIST_ITEM_AI,
|
||||
LIST_ITEM_AI_MOVES_PTS,
|
||||
|
|
@ -176,18 +177,22 @@ enum
|
|||
|
||||
enum
|
||||
{
|
||||
LIST_SIDE_REFLECT,
|
||||
LIST_SIDE_LIGHTSCREEN,
|
||||
LIST_SIDE_STICKY_WEB,
|
||||
LIST_SIDE_SPIKES,
|
||||
LIST_SIDE_TOXIC_SPIKES,
|
||||
LIST_SIDE_STEALTH_ROCK,
|
||||
LIST_SIDE_STEELSURGE,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
LIST_SIDE_REFLECT,
|
||||
LIST_SIDE_LIGHTSCREEN,
|
||||
LIST_SIDE_SAFEGUARD,
|
||||
LIST_SIDE_MIST,
|
||||
LIST_SIDE_TAILWIND,
|
||||
LIST_SIDE_AURORA_VEIL,
|
||||
LIST_SIDE_LUCKY_CHANT,
|
||||
LIST_SIDE_TOXIC_SPIKES,
|
||||
LIST_SIDE_STEALTH_ROCK,
|
||||
LIST_SIDE_STEELSURGE,
|
||||
LIST_SIDE_DAMAGE_NON_TYPES,
|
||||
LIST_SIDE_RAINBOW,
|
||||
LIST_SIDE_SEA_OF_FIRE,
|
||||
|
|
@ -250,6 +255,7 @@ enum
|
|||
VAL_BITFIELD_16,
|
||||
VAL_BITFIELD_32,
|
||||
VAL_VOLATILE,
|
||||
VAL_HAZARDS,
|
||||
VAR_SIDE_STATUS,
|
||||
VAR_SHOW_HP,
|
||||
VAR_SUBSTITUTE,
|
||||
|
|
@ -352,23 +358,24 @@ static const struct BitfieldInfo sAIBitfield[] =
|
|||
|
||||
static const struct ListMenuItem sMainListItems[] =
|
||||
{
|
||||
{COMPOUND_STRING("Moves"), LIST_ITEM_MOVES},
|
||||
{sText_Ability, LIST_ITEM_ABILITY},
|
||||
{sText_HeldItem, LIST_ITEM_HELD_ITEM},
|
||||
{COMPOUND_STRING("PP"), LIST_ITEM_PP},
|
||||
{COMPOUND_STRING("Types"), LIST_ITEM_TYPES},
|
||||
{COMPOUND_STRING("Stats"), LIST_ITEM_STATS},
|
||||
{COMPOUND_STRING("Stat Stages"), LIST_ITEM_STAT_STAGES},
|
||||
{COMPOUND_STRING("Status1"), LIST_ITEM_STATUS1},
|
||||
{COMPOUND_STRING("Volatiles"), LIST_ITEM_VOLATILE},
|
||||
{COMPOUND_STRING("Status3"), LIST_ITEM_STATUS3},
|
||||
{COMPOUND_STRING("Status4"), LIST_ITEM_STATUS4},
|
||||
{COMPOUND_STRING("Side Status"), LIST_ITEM_SIDE_STATUS},
|
||||
{COMPOUND_STRING("AI"), LIST_ITEM_AI},
|
||||
{COMPOUND_STRING("AI Pts/Dmg"), LIST_ITEM_AI_MOVES_PTS},
|
||||
{COMPOUND_STRING("AI Info"), LIST_ITEM_AI_INFO},
|
||||
{COMPOUND_STRING("AI Party"), LIST_ITEM_AI_PARTY},
|
||||
{COMPOUND_STRING("Various"), LIST_ITEM_VARIOUS},
|
||||
{COMPOUND_STRING("Moves"), LIST_ITEM_MOVES},
|
||||
{sText_Ability, LIST_ITEM_ABILITY},
|
||||
{sText_HeldItem, LIST_ITEM_HELD_ITEM},
|
||||
{COMPOUND_STRING("PP"), LIST_ITEM_PP},
|
||||
{COMPOUND_STRING("Types"), LIST_ITEM_TYPES},
|
||||
{COMPOUND_STRING("Stats"), LIST_ITEM_STATS},
|
||||
{COMPOUND_STRING("Stat Stages"), LIST_ITEM_STAT_STAGES},
|
||||
{COMPOUND_STRING("Status1"), LIST_ITEM_STATUS1},
|
||||
{COMPOUND_STRING("Volatiles"), LIST_ITEM_VOLATILE},
|
||||
{COMPOUND_STRING("Status3"), LIST_ITEM_STATUS3},
|
||||
{COMPOUND_STRING("Status4"), LIST_ITEM_STATUS4},
|
||||
{COMPOUND_STRING("Hazards"), LIST_ITEM_HAZARDS},
|
||||
{COMPOUND_STRING("Side Status"), LIST_ITEM_SIDE_STATUS},
|
||||
{COMPOUND_STRING("AI"), LIST_ITEM_AI},
|
||||
{COMPOUND_STRING("AI Pts/Dmg"), LIST_ITEM_AI_MOVES_PTS},
|
||||
{COMPOUND_STRING("AI Info"), LIST_ITEM_AI_INFO},
|
||||
{COMPOUND_STRING("AI Party"), LIST_ITEM_AI_PARTY},
|
||||
{COMPOUND_STRING("Various"), LIST_ITEM_VARIOUS},
|
||||
};
|
||||
|
||||
static const struct ListMenuItem sStatsListItems[] =
|
||||
|
|
@ -448,20 +455,24 @@ static const struct ListMenuItem sStatus4ListItems[] =
|
|||
{COMPOUND_STRING("Glaive Rush"), LIST_STATUS4_GLAIVE_RUSH},
|
||||
};
|
||||
|
||||
static const struct ListMenuItem sHazardsListItems[] =
|
||||
{
|
||||
{COMPOUND_STRING("Spikes"), LIST_SIDE_SPIKES},
|
||||
{COMPOUND_STRING("Sticky Web"), LIST_SIDE_STICKY_WEB},
|
||||
{COMPOUND_STRING("Toxic Spikes"), LIST_SIDE_TOXIC_SPIKES},
|
||||
{COMPOUND_STRING("Stealth Rock"), LIST_SIDE_STEALTH_ROCK},
|
||||
{COMPOUND_STRING("Steelsurge"), LIST_SIDE_STEELSURGE},
|
||||
};
|
||||
|
||||
static const struct ListMenuItem sSideStatusListItems[] =
|
||||
{
|
||||
{COMPOUND_STRING("Reflect"), LIST_SIDE_REFLECT},
|
||||
{COMPOUND_STRING("Light Screen"), LIST_SIDE_LIGHTSCREEN},
|
||||
{COMPOUND_STRING("Sticky Web"), LIST_SIDE_STICKY_WEB},
|
||||
{COMPOUND_STRING("Spikes"), LIST_SIDE_SPIKES},
|
||||
{COMPOUND_STRING("Safeguard"), LIST_SIDE_SAFEGUARD},
|
||||
{COMPOUND_STRING("Mist"), LIST_SIDE_MIST},
|
||||
{COMPOUND_STRING("Tailwind"), LIST_SIDE_TAILWIND},
|
||||
{COMPOUND_STRING("Aurora Veil"), LIST_SIDE_AURORA_VEIL},
|
||||
{COMPOUND_STRING("Lucky Chant"), LIST_SIDE_LUCKY_CHANT},
|
||||
{COMPOUND_STRING("Toxic Spikes"), LIST_SIDE_TOXIC_SPIKES},
|
||||
{COMPOUND_STRING("Stealth Rock"), LIST_SIDE_STEALTH_ROCK},
|
||||
{COMPOUND_STRING("Steelsurge"), LIST_SIDE_STEELSURGE},
|
||||
{COMPOUND_STRING("Damage Non-Types"), LIST_SIDE_DAMAGE_NON_TYPES},
|
||||
{COMPOUND_STRING("Rainbow"), LIST_SIDE_RAINBOW},
|
||||
{COMPOUND_STRING("Sea of Fire"), LIST_SIDE_SEA_OF_FIRE},
|
||||
|
|
@ -659,6 +670,8 @@ static void PrintDigitChars(struct BattleDebugMenu *data);
|
|||
static void SetUpModifyArrows(struct BattleDebugMenu *data);
|
||||
static void UpdateBattlerValue(struct BattleDebugMenu *data);
|
||||
static void UpdateMonData(struct BattleDebugMenu *data);
|
||||
static void ChangeHazardsValue(struct BattleDebugMenu *data);
|
||||
static u32 GetHazardsValue(struct BattleDebugMenu *data);
|
||||
static u16 *GetSideStatusValue(struct BattleDebugMenu *data, bool32 changeStatus, bool32 statusTrue);
|
||||
static bool32 TryMoveDigit(struct BattleDebugModifyArrows *modArrows, bool32 moveUp);
|
||||
static void SwitchToDebugView(u8 taskId);
|
||||
|
|
@ -1424,6 +1437,10 @@ static void CreateSecondaryListMenu(struct BattleDebugMenu *data)
|
|||
listTemplate.items = sVariousListItems;
|
||||
itemsCount = ARRAY_COUNT(sVariousListItems);
|
||||
break;
|
||||
case LIST_ITEM_HAZARDS:
|
||||
listTemplate.items = sHazardsListItems;
|
||||
itemsCount = ARRAY_COUNT(sHazardsListItems);
|
||||
break;
|
||||
case LIST_ITEM_SIDE_STATUS:
|
||||
listTemplate.items = sSideStatusListItems;
|
||||
itemsCount = ARRAY_COUNT(sSideStatusListItems);
|
||||
|
|
@ -1625,6 +1642,9 @@ static void UpdateBattlerValue(struct BattleDebugMenu *data)
|
|||
case VAL_VOLATILE:
|
||||
SetMonVolatile(data->battlerId, data->currentSecondaryListItemId, data->modifyArrows.currValue);
|
||||
break;
|
||||
case VAL_HAZARDS:
|
||||
ChangeHazardsValue(data);
|
||||
break;
|
||||
case VAR_SIDE_STATUS:
|
||||
*GetSideStatusValue(data, TRUE, data->modifyArrows.currValue != 0) = data->modifyArrows.currValue;
|
||||
break;
|
||||
|
|
@ -1702,6 +1722,83 @@ static void ValueToCharDigits(u8 *charDigits, u32 newValue, u8 maxDigits)
|
|||
charDigits[i] = valueDigits[i] + CHAR_0;
|
||||
}
|
||||
|
||||
static void ChangeHazardsValue(struct BattleDebugMenu *data)
|
||||
{
|
||||
u32 side = GetBattlerSide(data->battlerId);
|
||||
|
||||
switch (data->currentSecondaryListItemId)
|
||||
{
|
||||
case LIST_SIDE_SPIKES:
|
||||
if (data->modifyArrows.currValue > 0)
|
||||
{
|
||||
if (gSideTimers[side].spikesAmount == 0)
|
||||
PushHazardTypeToQueue(side, HAZARDS_SPIKES);
|
||||
gSideTimers[side].spikesAmount = data->modifyArrows.currValue;
|
||||
}
|
||||
else if (data->modifyArrows.currValue == 0)
|
||||
{
|
||||
gSideTimers[side].spikesAmount = 0;
|
||||
RemoveHazardFromField(side, HAZARDS_SPIKES);
|
||||
}
|
||||
break;
|
||||
case LIST_SIDE_TOXIC_SPIKES:
|
||||
if (data->modifyArrows.currValue > 0)
|
||||
{
|
||||
if (gSideTimers[side].toxicSpikesAmount == 0)
|
||||
PushHazardTypeToQueue(side, HAZARDS_TOXIC_SPIKES);
|
||||
gSideTimers[side].toxicSpikesAmount = data->modifyArrows.currValue;
|
||||
}
|
||||
else if (data->modifyArrows.currValue == 0)
|
||||
{
|
||||
gSideTimers[side].toxicSpikesAmount = 0;
|
||||
RemoveHazardFromField(side, HAZARDS_TOXIC_SPIKES);
|
||||
}
|
||||
break;
|
||||
case LIST_SIDE_STICKY_WEB:
|
||||
if (data->modifyArrows.currValue > 0)
|
||||
PushHazardTypeToQueue(side, HAZARDS_STICKY_WEB);
|
||||
else if (data->modifyArrows.currValue == 0)
|
||||
RemoveHazardFromField(side, HAZARDS_STICKY_WEB);
|
||||
break;
|
||||
case LIST_SIDE_STEALTH_ROCK:
|
||||
if (data->modifyArrows.currValue > 0)
|
||||
PushHazardTypeToQueue(side, HAZARDS_STEALTH_ROCK);
|
||||
else if (data->modifyArrows.currValue == 0)
|
||||
RemoveHazardFromField(side, HAZARDS_STEALTH_ROCK);
|
||||
break;
|
||||
case LIST_SIDE_STEELSURGE:
|
||||
if (data->modifyArrows.currValue > 0)
|
||||
PushHazardTypeToQueue(side, HAZARDS_STEELSURGE);
|
||||
else if (data->modifyArrows.currValue == 0)
|
||||
RemoveHazardFromField(side, HAZARDS_STEELSURGE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 GetHazardsValue(struct BattleDebugMenu *data)
|
||||
{
|
||||
u32 hazardsLayers = 0;
|
||||
switch (data->currentSecondaryListItemId)
|
||||
{
|
||||
case LIST_SIDE_SPIKES:
|
||||
hazardsLayers = gSideTimers[GetBattlerSide(data->battlerId)].spikesAmount;
|
||||
break;
|
||||
case LIST_SIDE_TOXIC_SPIKES:
|
||||
hazardsLayers = gSideTimers[GetBattlerSide(data->battlerId)].toxicSpikesAmount;
|
||||
break;
|
||||
case LIST_SIDE_STICKY_WEB:
|
||||
hazardsLayers = IsHazardOnSide(GetBattlerSide(data->battlerId), HAZARDS_STICKY_WEB);
|
||||
break;
|
||||
case LIST_SIDE_STEALTH_ROCK:
|
||||
hazardsLayers = IsHazardOnSide(GetBattlerSide(data->battlerId), HAZARDS_STEALTH_ROCK);
|
||||
break;
|
||||
case LIST_SIDE_STEELSURGE:
|
||||
hazardsLayers = IsHazardOnSide(GetBattlerSide(data->battlerId), HAZARDS_STEELSURGE);
|
||||
break;
|
||||
}
|
||||
return hazardsLayers;
|
||||
}
|
||||
|
||||
static u16 *GetSideStatusValue(struct BattleDebugMenu *data, bool32 changeStatus, bool32 statusTrue)
|
||||
{
|
||||
struct SideTimer *sideTimer = &gSideTimers[GetBattlerSide(data->battlerId)];
|
||||
|
|
@ -1726,26 +1823,6 @@ static u16 *GetSideStatusValue(struct BattleDebugMenu *data, bool32 changeStatus
|
|||
*(u32 *)(data->modifyArrows.modifiedValPtr) &= ~SIDE_STATUS_LIGHTSCREEN;
|
||||
}
|
||||
return &sideTimer->lightscreenTimer;
|
||||
case LIST_SIDE_STICKY_WEB:
|
||||
if (changeStatus)
|
||||
{
|
||||
if (statusTrue)
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) |= SIDE_STATUS_STICKY_WEB;
|
||||
else
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) &= ~SIDE_STATUS_STICKY_WEB;
|
||||
sideTimer->stickyWebBattlerId = data->battlerId;
|
||||
sideTimer->stickyWebBattlerSide = GetBattlerSide(data->battlerId);
|
||||
}
|
||||
return &sideTimer->stickyWebAmount;
|
||||
case LIST_SIDE_SPIKES:
|
||||
if (changeStatus)
|
||||
{
|
||||
if (statusTrue)
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) |= SIDE_STATUS_SPIKES;
|
||||
else
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) &= ~SIDE_STATUS_SPIKES;
|
||||
}
|
||||
return &sideTimer->spikesAmount;
|
||||
case LIST_SIDE_SAFEGUARD:
|
||||
if (changeStatus)
|
||||
{
|
||||
|
|
@ -1791,33 +1868,6 @@ static u16 *GetSideStatusValue(struct BattleDebugMenu *data, bool32 changeStatus
|
|||
*(u32 *)(data->modifyArrows.modifiedValPtr) &= ~SIDE_STATUS_LUCKY_CHANT;
|
||||
}
|
||||
return &sideTimer->luckyChantTimer;
|
||||
case LIST_SIDE_TOXIC_SPIKES:
|
||||
if (changeStatus)
|
||||
{
|
||||
if (statusTrue)
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) |= SIDE_STATUS_TOXIC_SPIKES;
|
||||
else
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) &= ~SIDE_STATUS_TOXIC_SPIKES;
|
||||
}
|
||||
return &sideTimer->toxicSpikesAmount;
|
||||
case LIST_SIDE_STEALTH_ROCK:
|
||||
if (changeStatus)
|
||||
{
|
||||
if (statusTrue)
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) |= SIDE_STATUS_STEALTH_ROCK;
|
||||
else
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) &= ~SIDE_STATUS_STEALTH_ROCK;
|
||||
}
|
||||
return &sideTimer->stealthRockAmount;
|
||||
case LIST_SIDE_STEELSURGE:
|
||||
if (changeStatus)
|
||||
{
|
||||
if (statusTrue)
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) |= SIDE_STATUS_STEELSURGE;
|
||||
else
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) &= ~SIDE_STATUS_STEELSURGE;
|
||||
}
|
||||
return &sideTimer->steelsurgeAmount;
|
||||
case LIST_SIDE_DAMAGE_NON_TYPES:
|
||||
if (changeStatus)
|
||||
{
|
||||
|
|
@ -2034,16 +2084,29 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data)
|
|||
data->modifyArrows.maxValue = (1 << data->bitfield[data->currentSecondaryListItemId].bitsCount) - 1;
|
||||
data->modifyArrows.maxDigits = MAX_DIGITS(data->modifyArrows.maxValue);
|
||||
break;
|
||||
case LIST_ITEM_HAZARDS:
|
||||
data->modifyArrows.minValue = 0;
|
||||
switch (data->currentSecondaryListItemId)
|
||||
{
|
||||
case LIST_SIDE_SPIKES:
|
||||
data->modifyArrows.maxValue = 3;
|
||||
break;
|
||||
case LIST_SIDE_TOXIC_SPIKES:
|
||||
data->modifyArrows.maxValue = 2;
|
||||
break;
|
||||
case LIST_SIDE_STICKY_WEB:
|
||||
case LIST_SIDE_STEALTH_ROCK:
|
||||
case LIST_SIDE_STEELSURGE:
|
||||
data->modifyArrows.maxValue = 1;
|
||||
break;
|
||||
}
|
||||
data->modifyArrows.maxDigits = 2;
|
||||
data->modifyArrows.typeOfVal = VAL_HAZARDS;
|
||||
data->modifyArrows.currValue = GetHazardsValue(data);
|
||||
break;
|
||||
case LIST_ITEM_SIDE_STATUS:
|
||||
data->modifyArrows.minValue = 0;
|
||||
|
||||
if (data->currentSecondaryListItemId == LIST_SIDE_SPIKES)
|
||||
data->modifyArrows.maxValue = 3;
|
||||
else if (data->currentSecondaryListItemId == LIST_SIDE_STEALTH_ROCK || data->currentSecondaryListItemId == LIST_SIDE_STICKY_WEB)
|
||||
data->modifyArrows.maxValue = 1;
|
||||
else
|
||||
data->modifyArrows.maxValue = 9;
|
||||
|
||||
data->modifyArrows.maxValue = 9;
|
||||
data->modifyArrows.maxDigits = 2;
|
||||
data->modifyArrows.modifiedValPtr = &gSideStatuses[GetBattlerSide(data->battlerId)];
|
||||
data->modifyArrows.typeOfVal = VAR_SIDE_STATUS;
|
||||
|
|
|
|||
|
|
@ -1400,6 +1400,24 @@ const u16 gDamageNonTypesDmgStringIds[] =
|
|||
[B_MSG_HURT_BY_ROCKS_THROWN] = STRINGID_PKMNHURTBYROCKSTHROWN,
|
||||
};
|
||||
|
||||
const u16 gDefogHazardsStringIds[] =
|
||||
{
|
||||
[HAZARDS_SPIKES] = STRINGID_SPIKESDISAPPEAREDFROMTEAM,
|
||||
[HAZARDS_STICKY_WEB] = STRINGID_STICKYWEBDISAPPEAREDFROMTEAM,
|
||||
[HAZARDS_TOXIC_SPIKES] = STRINGID_TOXICSPIKESDISAPPEAREDFROMTEAM,
|
||||
[HAZARDS_STEALTH_ROCK] = STRINGID_STEALTHROCKDISAPPEAREDFROMTEAM,
|
||||
[HAZARDS_STEELSURGE] = STRINGID_SHARPSTEELDISAPPEAREDFROMTEAM,
|
||||
};
|
||||
|
||||
const u16 gSpinHazardsStringIds[] =
|
||||
{
|
||||
[HAZARDS_SPIKES] = STRINGID_PKMNBLEWAWAYSPIKES,
|
||||
[HAZARDS_STICKY_WEB] = STRINGID_PKMNBLEWAWAYSTICKYWEB,
|
||||
[HAZARDS_TOXIC_SPIKES] = STRINGID_PKMNBLEWAWAYTOXICSPIKES,
|
||||
[HAZARDS_STEALTH_ROCK] = STRINGID_PKMNBLEWAWAYSTEALTHROCK,
|
||||
[HAZARDS_STEELSURGE] = STRINGID_PKMNBLEWAWAYSHARPSTEEL,
|
||||
};
|
||||
|
||||
const u8 gText_PkmnIsEvolving[] = _("What?\n{STR_VAR_1} is evolving!");
|
||||
const u8 gText_CongratsPkmnEvolved[] = _("Congratulations! Your {STR_VAR_1}\nevolved into {STR_VAR_2}!{WAIT_SE}\p");
|
||||
const u8 gText_PkmnStoppedEvolving[] = _("Huh? {STR_VAR_1}\nstopped evolving!\p");
|
||||
|
|
|
|||
|
|
@ -3848,7 +3848,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
|
|||
}
|
||||
break;
|
||||
case MOVE_EFFECT_STEALTH_ROCK:
|
||||
if (!(gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_STEALTH_ROCK))
|
||||
if (!IsHazardOnSide(GetBattlerSide(gEffectBattler), HAZARDS_STEALTH_ROCK))
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_POINTEDSTONESFLOAT;
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
|
|
@ -4284,7 +4284,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
|
|||
break;
|
||||
}
|
||||
case MOVE_EFFECT_STEELSURGE:
|
||||
if (!(gSideStatuses[GetBattlerSide(gBattlerTarget)] & SIDE_STATUS_STEELSURGE))
|
||||
if (!IsHazardOnSide(GetBattlerSide(gBattlerTarget), HAZARDS_STEELSURGE))
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SHARPSTEELFLOATS;
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
|
|
@ -4293,8 +4293,8 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
|
|||
break;
|
||||
case MOVE_EFFECT_DEFOG:
|
||||
if (gSideStatuses[GetBattlerSide(gBattlerTarget)] & SIDE_STATUS_SCREEN_ANY
|
||||
|| gSideStatuses[GetBattlerSide(gBattlerTarget)] & SIDE_STATUS_HAZARDS_ANY
|
||||
|| gSideStatuses[GetBattlerSide(gBattlerAttacker)] & SIDE_STATUS_HAZARDS_ANY
|
||||
|| AreAnyHazardsOnSide(GetBattlerSide(gBattlerTarget))
|
||||
|| AreAnyHazardsOnSide(GetBattlerSide(gBattlerAttacker))
|
||||
|| gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)
|
||||
{
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
|
|
@ -8026,23 +8026,6 @@ static void Cmd_switchhandleorder(void)
|
|||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void SetDmgHazardsBattlescript(u8 battler, u8 multistringId)
|
||||
{
|
||||
gBattleMons[battler].status2 &= ~STATUS2_DESTINY_BOND;
|
||||
gHitMarker &= ~HITMARKER_DESTINYBOND;
|
||||
gBattleScripting.battler = battler;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = multistringId;
|
||||
|
||||
if (gBattlescriptCurrInstr[1] == BS_TARGET)
|
||||
BattleScriptCall(BattleScript_DmgHazardsOnTarget);
|
||||
else if (gBattlescriptCurrInstr[1] == BS_ATTACKER)
|
||||
BattleScriptCall(BattleScript_DmgHazardsOnAttacker);
|
||||
else if (gBattlescriptCurrInstr[1] == BS_SCRIPTING)
|
||||
BattleScriptCall(BattleScript_DmgHazardsOnBattlerScripting);
|
||||
else
|
||||
BattleScriptCall(BattleScript_DmgHazardsOnFaintedBattler);
|
||||
}
|
||||
|
||||
bool32 DoSwitchInAbilities(u32 battler)
|
||||
{
|
||||
return (TryPrimalReversion(battler)
|
||||
|
|
@ -8062,9 +8045,106 @@ static void UpdateSentMonFlags(u32 battler)
|
|||
gBattleStruct->appearedInBattle |= 1u << gBattlerPartyIndexes[battler];
|
||||
}
|
||||
|
||||
static void SetDmgHazardsBattlescript(u8 battler, u8 multistringId)
|
||||
{
|
||||
gBattleMons[battler].status2 &= ~STATUS2_DESTINY_BOND;
|
||||
gHitMarker &= ~HITMARKER_DESTINYBOND;
|
||||
gBattleScripting.battler = battler;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = multistringId;
|
||||
|
||||
if (gBattlescriptCurrInstr[1] == BS_TARGET)
|
||||
BattleScriptCall(BattleScript_DmgHazardsOnTarget);
|
||||
else if (gBattlescriptCurrInstr[1] == BS_ATTACKER)
|
||||
BattleScriptCall(BattleScript_DmgHazardsOnAttacker);
|
||||
else if (gBattlescriptCurrInstr[1] == BS_SCRIPTING)
|
||||
BattleScriptCall(BattleScript_DmgHazardsOnBattlerScripting);
|
||||
else
|
||||
BattleScriptCall(BattleScript_DmgHazardsOnFaintedBattler);
|
||||
}
|
||||
|
||||
void TryHazardsOnSwitchIn(u32 battler, u32 side, enum Hazards hazardType)
|
||||
{
|
||||
switch (hazardType)
|
||||
{
|
||||
case HAZARDS_NONE:
|
||||
break;
|
||||
case HAZARDS_SPIKES:
|
||||
if (GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD
|
||||
&& IsBattlerAffectedByHazards(battler, FALSE)
|
||||
&& IsBattlerGrounded(battler))
|
||||
{
|
||||
u8 spikesDmg = (5 - gSideTimers[side].spikesAmount) * 2;
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (spikesDmg);
|
||||
if (gBattleStruct->moveDamage[battler] == 0)
|
||||
gBattleStruct->moveDamage[battler] = 1;
|
||||
SetDmgHazardsBattlescript(battler, B_MSG_PKMNHURTBYSPIKES);
|
||||
}
|
||||
break;
|
||||
case HAZARDS_STICKY_WEB:
|
||||
if (IsBattlerAffectedByHazards(battler, FALSE) && IsBattlerGrounded(battler))
|
||||
{
|
||||
gBattleScripting.battler = battler;
|
||||
SET_STATCHANGER(STAT_SPEED, 1, TRUE);
|
||||
BattleScriptCall(BattleScript_StickyWebOnSwitchIn);
|
||||
}
|
||||
break;
|
||||
case HAZARDS_TOXIC_SPIKES:
|
||||
if (!IsBattlerGrounded(battler))
|
||||
break;
|
||||
|
||||
if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON)) // Absorb the toxic spikes.
|
||||
{
|
||||
gBattleStruct->hazardsCounter--; // reduce counter so the next hazard can be applied
|
||||
gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount = 0;
|
||||
RemoveHazardFromField(side, HAZARDS_TOXIC_SPIKES);
|
||||
gBattleScripting.battler = battler;
|
||||
BattleScriptCall(BattleScript_ToxicSpikesAbsorbed);
|
||||
}
|
||||
else if (IsBattlerAffectedByHazards(battler, TRUE)
|
||||
&& CanBePoisoned(battler, battler, GetBattlerAbility(battler), GetBattlerAbility(battler)))
|
||||
{
|
||||
gBattleScripting.battler = battler;
|
||||
BattleScriptPushCursor();
|
||||
if (gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount >= 2)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_ToxicSpikesBadlyPoisoned;
|
||||
gBattleMons[battler].status1 |= STATUS1_TOXIC_POISON;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_ToxicSpikesPoisoned;
|
||||
gBattleMons[battler].status1 |= STATUS1_POISON;
|
||||
}
|
||||
|
||||
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[battler].status1), &gBattleMons[battler].status1);
|
||||
MarkBattlerForControllerExec(battler);
|
||||
}
|
||||
break;
|
||||
case HAZARDS_STEALTH_ROCK:
|
||||
if (IsBattlerAffectedByHazards(battler, FALSE) && GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD)
|
||||
{
|
||||
gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_POINTED_STONES, battler);
|
||||
if (gBattleStruct->moveDamage[battler] != 0)
|
||||
SetDmgHazardsBattlescript(battler, B_MSG_STEALTHROCKDMG);
|
||||
}
|
||||
break;
|
||||
case HAZARDS_STEELSURGE:
|
||||
if (IsBattlerAffectedByHazards(battler, FALSE) && GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD)
|
||||
{
|
||||
gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_SHARP_STEEL, battler);
|
||||
if (gBattleStruct->moveDamage[battler] != 0)
|
||||
SetDmgHazardsBattlescript(battler, B_MSG_SHARPSTEELDMG);
|
||||
}
|
||||
break;
|
||||
case HAZARDS_MAX_COUNT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool32 DoSwitchInEffectsForBattler(u32 battler)
|
||||
{
|
||||
u32 i = 0;
|
||||
u32 side = GetBattlerSide(battler);
|
||||
// Neutralizing Gas announces itself before hazards
|
||||
if (gBattleMons[battler].ability == ABILITY_NEUTRALIZING_GAS && gSpecialStatuses[battler].announceNeutralizingGas == 0)
|
||||
{
|
||||
|
|
@ -8091,85 +8171,17 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler)
|
|||
gBattleStruct->battlerState[battler].storedLunarDance = FALSE;
|
||||
}
|
||||
}
|
||||
else if (!(gDisableStructs[battler].spikesDone)
|
||||
&& (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SPIKES)
|
||||
&& GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD
|
||||
&& IsBattlerAffectedByHazards(battler, FALSE)
|
||||
&& IsBattlerGrounded(battler))
|
||||
else if (!gDisableStructs[battler].hazardsDone)
|
||||
{
|
||||
u8 spikesDmg = (5 - gSideTimers[GetBattlerSide(battler)].spikesAmount) * 2;
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (spikesDmg);
|
||||
if (gBattleStruct->moveDamage[battler] == 0)
|
||||
gBattleStruct->moveDamage[battler] = 1;
|
||||
|
||||
gDisableStructs[battler].spikesDone = TRUE;
|
||||
SetDmgHazardsBattlescript(battler, B_MSG_PKMNHURTBYSPIKES);
|
||||
}
|
||||
else if (!(gDisableStructs[battler].stealthRockDone)
|
||||
&& (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_STEALTH_ROCK)
|
||||
&& IsBattlerAffectedByHazards(battler, FALSE)
|
||||
&& GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD)
|
||||
{
|
||||
gDisableStructs[battler].stealthRockDone = TRUE;
|
||||
gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_POINTED_STONES, battler);
|
||||
|
||||
if (gBattleStruct->moveDamage[battler] != 0)
|
||||
SetDmgHazardsBattlescript(battler, B_MSG_STEALTHROCKDMG);
|
||||
}
|
||||
else if (!(gDisableStructs[battler].toxicSpikesDone)
|
||||
&& (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TOXIC_SPIKES)
|
||||
&& IsBattlerGrounded(battler))
|
||||
{
|
||||
gDisableStructs[battler].toxicSpikesDone = TRUE;
|
||||
if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON)) // Absorb the toxic spikes.
|
||||
TryHazardsOnSwitchIn(battler, side, gBattleStruct->hazardsQueue[side][gBattleStruct->hazardsCounter]);
|
||||
gBattleStruct->hazardsCounter++;
|
||||
// Done once we reach the first element without any hazard type or the array is full
|
||||
if (gBattleStruct->hazardsQueue[side][gBattleStruct->hazardsCounter] == HAZARDS_NONE
|
||||
|| gBattleStruct->hazardsCounter == HAZARDS_MAX_COUNT)
|
||||
{
|
||||
gSideStatuses[GetBattlerSide(battler)] &= ~SIDE_STATUS_TOXIC_SPIKES;
|
||||
gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount = 0;
|
||||
gBattleScripting.battler = battler;
|
||||
BattleScriptCall(BattleScript_ToxicSpikesAbsorbed);
|
||||
gDisableStructs[battler].hazardsDone = TRUE;
|
||||
gBattleStruct->hazardsCounter = 0;
|
||||
}
|
||||
else if (IsBattlerAffectedByHazards(battler, TRUE))
|
||||
{
|
||||
if (CanBePoisoned(gBattlerAttacker, battler, GetBattlerAbility(gBattlerAttacker), GetBattlerAbility(battler)))
|
||||
{
|
||||
gBattleScripting.battler = battler;
|
||||
BattleScriptPushCursor();
|
||||
if (gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount >= 2)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_ToxicSpikesBadlyPoisoned;
|
||||
gBattleMons[battler].status1 |= STATUS1_TOXIC_POISON;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_ToxicSpikesPoisoned;
|
||||
gBattleMons[battler].status1 |= STATUS1_POISON;
|
||||
}
|
||||
|
||||
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[battler].status1), &gBattleMons[battler].status1);
|
||||
MarkBattlerForControllerExec(battler);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(gDisableStructs[battler].stickyWebDone)
|
||||
&& (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_STICKY_WEB)
|
||||
&& IsBattlerAffectedByHazards(battler, FALSE)
|
||||
&& IsBattlerGrounded(battler))
|
||||
{
|
||||
gDisableStructs[battler].stickyWebDone = TRUE;
|
||||
gBattleScripting.battler = battler;
|
||||
SET_STATCHANGER(STAT_SPEED, 1, TRUE);
|
||||
BattleScriptCall(BattleScript_StickyWebOnSwitchIn);
|
||||
}
|
||||
else if (!(gDisableStructs[battler].steelSurgeDone)
|
||||
&& (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_STEELSURGE)
|
||||
&& IsBattlerAffectedByHazards(battler, FALSE)
|
||||
&& GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD)
|
||||
{
|
||||
gDisableStructs[battler].steelSurgeDone = TRUE;
|
||||
gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_SHARP_STEEL, battler);
|
||||
|
||||
if (gBattleStruct->moveDamage[battler] != 0)
|
||||
SetDmgHazardsBattlescript(battler, B_MSG_SHARPSTEELDMG);
|
||||
}
|
||||
else if (gBattleMons[battler].hp != gBattleMons[battler].maxHP && gBattleStruct->zmove.healReplacement)
|
||||
{
|
||||
|
|
@ -8220,12 +8232,6 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
gDisableStructs[battler].stickyWebDone = FALSE;
|
||||
gDisableStructs[battler].spikesDone = FALSE;
|
||||
gDisableStructs[battler].toxicSpikesDone = FALSE;
|
||||
gDisableStructs[battler].stealthRockDone = FALSE;
|
||||
gDisableStructs[battler].steelSurgeDone = FALSE;
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (gBattlerByTurnOrder[i] == battler)
|
||||
|
|
@ -8234,6 +8240,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler)
|
|||
gBattleStruct->hpOnSwitchout[GetBattlerSide(i)] = gBattleMons[i].hp;
|
||||
}
|
||||
|
||||
gDisableStructs[battler].hazardsDone = FALSE;
|
||||
gBattleStruct->battlerState[battler].forcedSwitch = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -9567,6 +9574,32 @@ static void RemoveAllTerrains(void)
|
|||
} \
|
||||
}
|
||||
|
||||
static bool32 DefogClearHazards(u32 saveBattler, u32 side, bool32 clear)
|
||||
{
|
||||
if (!AreAnyHazardsOnSide(side))
|
||||
return FALSE;
|
||||
|
||||
for (u32 hazardType = HAZARDS_NONE + 1; hazardType < HAZARDS_MAX_COUNT; hazardType++)
|
||||
{
|
||||
bool32 checkOrClear = clear ? IsHazardOnSideAndClear(side, hazardType) : IsHazardOnSide(side, hazardType);
|
||||
if (checkOrClear)
|
||||
{
|
||||
if (clear)
|
||||
{
|
||||
gBattleStruct->numHazards[side]--;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = hazardType;
|
||||
BattleScriptCall(BattleScript_DefogClearHazards);
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlerAttacker = saveBattler;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool32 TryDefogClear(u32 battlerAtk, bool32 clear)
|
||||
{
|
||||
s32 i;
|
||||
|
|
@ -9589,11 +9622,8 @@ static bool32 TryDefogClear(u32 battlerAtk, bool32 clear)
|
|||
if (B_DEFOG_EFFECT_CLEARING >= GEN_6)
|
||||
{
|
||||
gBattlerAttacker = i; // For correct battle string. Ally's / Foe's
|
||||
DEFOG_CLEAR(SIDE_STATUS_SPIKES, spikesAmount, BattleScript_SpikesDefog, 0);
|
||||
DEFOG_CLEAR(SIDE_STATUS_STEALTH_ROCK, stealthRockAmount, BattleScript_StealthRockDefog, 0);
|
||||
DEFOG_CLEAR(SIDE_STATUS_TOXIC_SPIKES, toxicSpikesAmount, BattleScript_ToxicSpikesDefog, 0);
|
||||
DEFOG_CLEAR(SIDE_STATUS_STICKY_WEB, stickyWebAmount, BattleScript_StickyWebDefog, 0);
|
||||
DEFOG_CLEAR(SIDE_STATUS_STEELSURGE, steelsurgeAmount, BattleScript_SteelsurgeDefog, 0);
|
||||
if (DefogClearHazards(saveBattler, i, clear))
|
||||
return TRUE;
|
||||
}
|
||||
if (gBattleWeather & B_WEATHER_FOG)
|
||||
{
|
||||
|
|
@ -9621,14 +9651,9 @@ static bool32 TryTidyUpClear(u32 battlerAtk, bool32 clear)
|
|||
|
||||
for (i = 0; i < NUM_BATTLE_SIDES; i++)
|
||||
{
|
||||
struct SideTimer *sideTimer = &gSideTimers[i];
|
||||
u32 *sideStatuses = &gSideStatuses[i];
|
||||
|
||||
gBattlerAttacker = i; // For correct battle string. Ally's / Foe's
|
||||
DEFOG_CLEAR(SIDE_STATUS_SPIKES, spikesAmount, BattleScript_SpikesDefog, 0);
|
||||
DEFOG_CLEAR(SIDE_STATUS_STEALTH_ROCK, stealthRockAmount, BattleScript_StealthRockDefog, 0);
|
||||
DEFOG_CLEAR(SIDE_STATUS_TOXIC_SPIKES, toxicSpikesAmount, BattleScript_ToxicSpikesDefog, 0);
|
||||
DEFOG_CLEAR(SIDE_STATUS_STICKY_WEB, stickyWebAmount, BattleScript_StickyWebDefog, 0);
|
||||
if (DefogClearHazards(saveBattler, i, clear))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
||||
|
|
@ -9780,17 +9805,23 @@ void BS_CourtChangeSwapSideStatuses(void)
|
|||
COURTCHANGE_SWAP(SIDE_STATUS_TAILWIND, tailwindTimer, temp);
|
||||
// Lucky Chant doesn't exist in gen 8, but seems like it should be affected by Court Change
|
||||
COURTCHANGE_SWAP(SIDE_STATUS_LUCKY_CHANT, luckyChantTimer, temp);
|
||||
COURTCHANGE_SWAP(SIDE_STATUS_SPIKES, spikesAmount, temp);
|
||||
COURTCHANGE_SWAP(SIDE_STATUS_STEALTH_ROCK, stealthRockAmount, temp);
|
||||
COURTCHANGE_SWAP(SIDE_STATUS_TOXIC_SPIKES, toxicSpikesAmount, temp);
|
||||
COURTCHANGE_SWAP(SIDE_STATUS_STICKY_WEB, stickyWebAmount, temp);
|
||||
COURTCHANGE_SWAP(SIDE_STATUS_STEELSURGE, steelsurgeAmount, temp);
|
||||
COURTCHANGE_SWAP(SIDE_STATUS_DAMAGE_NON_TYPES, damageNonTypesTimer, temp);
|
||||
// Track Pledge effect side
|
||||
COURTCHANGE_SWAP(SIDE_STATUS_RAINBOW, rainbowTimer, temp);
|
||||
COURTCHANGE_SWAP(SIDE_STATUS_SEA_OF_FIRE, seaOfFireTimer, temp);
|
||||
COURTCHANGE_SWAP(SIDE_STATUS_SWAMP, swampTimer, temp);
|
||||
|
||||
// Hazards
|
||||
u32 tempQueue[HAZARDS_MAX_COUNT] = {HAZARDS_NONE};
|
||||
for (u32 i = 0; i < HAZARDS_MAX_COUNT; i++)
|
||||
tempQueue[i] = gBattleStruct->hazardsQueue[B_SIDE_PLAYER][i];
|
||||
for (u32 i = 0; i < HAZARDS_MAX_COUNT; i++)
|
||||
gBattleStruct->hazardsQueue[B_SIDE_PLAYER][i] = gBattleStruct->hazardsQueue[B_SIDE_OPPONENT][i];
|
||||
for (u32 i = 0; i < HAZARDS_MAX_COUNT; i++)
|
||||
gBattleStruct->hazardsQueue[B_SIDE_OPPONENT][i] = tempQueue[i];
|
||||
SWAP(sideTimerPlayer->spikesAmount, sideTimerOpp->spikesAmount, temp);
|
||||
SWAP(sideTimerPlayer->toxicSpikesAmount, sideTimerOpp->toxicSpikesAmount, temp);
|
||||
|
||||
// Change battler IDs of swapped effects. Needed for the correct string when they expire
|
||||
UPDATE_COURTCHANGED_BATTLER(stickyWebBattlerId);
|
||||
|
||||
|
|
@ -13950,7 +13981,8 @@ static void Cmd_trysetspikes(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
gSideStatuses[targetSide] |= SIDE_STATUS_SPIKES;
|
||||
if (gSideTimers[targetSide].spikesAmount == 0) // Add only once to the queue
|
||||
PushHazardTypeToQueue(targetSide, HAZARDS_SPIKES);
|
||||
gSideTimers[targetSide].spikesAmount++;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
|
@ -14313,35 +14345,18 @@ static void Cmd_rapidspinfree(void)
|
|||
gStatuses3[gBattlerAttacker] &= ~STATUS3_LEECHSEED_BATTLER;
|
||||
BattleScriptCall(BattleScript_LeechSeedFree);
|
||||
}
|
||||
else if (gSideStatuses[atkSide] & SIDE_STATUS_SPIKES)
|
||||
else if (AreAnyHazardsOnSide(atkSide))
|
||||
{
|
||||
gSideStatuses[atkSide] &= ~SIDE_STATUS_SPIKES;
|
||||
gSideTimers[atkSide].spikesAmount = 0;
|
||||
BattleScriptCall(BattleScript_SpikesFree);
|
||||
}
|
||||
else if (gSideStatuses[atkSide] & SIDE_STATUS_TOXIC_SPIKES)
|
||||
{
|
||||
gSideStatuses[atkSide] &= ~SIDE_STATUS_TOXIC_SPIKES;
|
||||
gSideTimers[atkSide].toxicSpikesAmount = 0;
|
||||
BattleScriptCall(BattleScript_ToxicSpikesFree);
|
||||
}
|
||||
else if (gSideStatuses[atkSide] & SIDE_STATUS_STICKY_WEB)
|
||||
{
|
||||
gSideStatuses[atkSide] &= ~SIDE_STATUS_STICKY_WEB;
|
||||
gSideTimers[atkSide].stickyWebAmount = 0;
|
||||
BattleScriptCall(BattleScript_StickyWebFree);
|
||||
}
|
||||
else if (gSideStatuses[atkSide] & SIDE_STATUS_STEALTH_ROCK)
|
||||
{
|
||||
gSideStatuses[atkSide] &= ~SIDE_STATUS_STEALTH_ROCK;
|
||||
gSideTimers[atkSide].stealthRockAmount = 0;
|
||||
BattleScriptCall(BattleScript_StealthRockFree);
|
||||
}
|
||||
else if (gSideStatuses[atkSide] & SIDE_STATUS_STEELSURGE)
|
||||
{
|
||||
gSideStatuses[atkSide] &= ~SIDE_STATUS_STEELSURGE;
|
||||
gSideTimers[atkSide].steelsurgeAmount = 0;
|
||||
BattleScriptCall(BattleScript_SteelsurgeFree);
|
||||
for (u32 hazardType = HAZARDS_NONE + 1; hazardType < HAZARDS_MAX_COUNT; hazardType++)
|
||||
{
|
||||
if (IsHazardOnSideAndClear(atkSide, hazardType))
|
||||
{
|
||||
gBattleStruct->numHazards[atkSide]--;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = hazardType;
|
||||
BattleScriptCall(BattleScript_SpinHazardsAway);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -14432,16 +14447,15 @@ static void Cmd_setstickyweb(void)
|
|||
|
||||
u8 targetSide = GetBattlerSide(gBattlerTarget);
|
||||
|
||||
if (gSideStatuses[targetSide] & SIDE_STATUS_STICKY_WEB)
|
||||
if (IsHazardOnSide(targetSide, HAZARDS_STICKY_WEB))
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gSideStatuses[targetSide] |= SIDE_STATUS_STICKY_WEB;
|
||||
PushHazardTypeToQueue(targetSide, HAZARDS_STICKY_WEB);
|
||||
gSideTimers[targetSide].stickyWebBattlerId = gBattlerAttacker; // For Mirror Armor
|
||||
gSideTimers[targetSide].stickyWebBattlerSide = GetBattlerSide(gBattlerAttacker); // For Court Change/Defiant - set this to the user's side
|
||||
gSideTimers[targetSide].stickyWebAmount = 1;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
|
@ -14967,8 +14981,9 @@ static void Cmd_settoxicspikes(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (gSideTimers[targetSide].toxicSpikesAmount == 0)
|
||||
PushHazardTypeToQueue(targetSide, HAZARDS_TOXIC_SPIKES);
|
||||
gSideTimers[targetSide].toxicSpikesAmount++;
|
||||
gSideStatuses[targetSide] |= SIDE_STATUS_TOXIC_SPIKES;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
|
@ -15158,14 +15173,13 @@ static void Cmd_setstealthrock(void)
|
|||
CMD_ARGS(const u8 *failInstr);
|
||||
|
||||
u8 targetSide = GetBattlerSide(gBattlerTarget);
|
||||
if (gSideStatuses[targetSide] & SIDE_STATUS_STEALTH_ROCK)
|
||||
if (IsHazardOnSide(targetSide, HAZARDS_STEALTH_ROCK))
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gSideStatuses[targetSide] |= SIDE_STATUS_STEALTH_ROCK;
|
||||
gSideTimers[targetSide].stealthRockAmount = 1;
|
||||
PushHazardTypeToQueue(targetSide, HAZARDS_STEALTH_ROCK);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
|
@ -18544,14 +18558,13 @@ void BS_SetSteelsurge(void)
|
|||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
u8 targetSide = GetBattlerSide(gBattlerTarget);
|
||||
if (gSideStatuses[targetSide] & SIDE_STATUS_STEELSURGE)
|
||||
if (IsHazardOnSide(targetSide, HAZARDS_STEELSURGE))
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gSideStatuses[targetSide] |= SIDE_STATUS_STEELSURGE;
|
||||
gSideTimers[targetSide].steelsurgeAmount = 1;
|
||||
PushHazardTypeToQueue(targetSide, HAZARDS_STEELSURGE);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11445,3 +11445,79 @@ void SetMonVolatile(u32 battler, enum Volatile _volatile, u32 newValue)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Hazards are added to a queue and applied based in order (FIFO)
|
||||
void PushHazardTypeToQueue(u32 side, enum Hazards hazardType)
|
||||
{
|
||||
if (!IsHazardOnSide(side, hazardType)) // Failsafe
|
||||
gBattleStruct->hazardsQueue[side][gBattleStruct->numHazards[side]++] = hazardType;
|
||||
}
|
||||
|
||||
bool32 IsHazardOnSide(u32 side, enum Hazards hazardType)
|
||||
{
|
||||
for (u32 i = 0; i < HAZARDS_MAX_COUNT; i++)
|
||||
{
|
||||
if (gBattleStruct->hazardsQueue[side][i] == hazardType)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 AreAnyHazardsOnSide(u32 side)
|
||||
{
|
||||
return gBattleStruct->numHazards[side] > 0;
|
||||
}
|
||||
|
||||
bool32 IsHazardOnSideAndClear(u32 side, enum Hazards hazardType)
|
||||
{
|
||||
for (u32 i = 0; i < HAZARDS_MAX_COUNT; i++)
|
||||
{
|
||||
if (gBattleStruct->hazardsQueue[side][i] == hazardType)
|
||||
{
|
||||
gBattleStruct->hazardsQueue[side][i] = HAZARDS_NONE;
|
||||
if (hazardType == HAZARDS_SPIKES)
|
||||
gSideTimers[side].spikesAmount = 0;
|
||||
else if (hazardType == HAZARDS_TOXIC_SPIKES)
|
||||
gSideTimers[side].toxicSpikesAmount = 0;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void RemoveAllHazardsFromField(u32 side)
|
||||
{
|
||||
gSideTimers[side].spikesAmount = 0;
|
||||
gSideTimers[side].toxicSpikesAmount = 0;
|
||||
gBattleStruct->numHazards[side] = 0;
|
||||
for (u32 i = 0; i < HAZARDS_MAX_COUNT; i++)
|
||||
gBattleStruct->hazardsQueue[side][i] = HAZARDS_NONE;
|
||||
}
|
||||
|
||||
void RemoveHazardFromField(u32 side, enum Hazards hazardType)
|
||||
{
|
||||
u32 i;
|
||||
for (i = 0; i < HAZARDS_MAX_COUNT; i++)
|
||||
{
|
||||
if (gBattleStruct->hazardsQueue[side][i] == hazardType)
|
||||
{
|
||||
gBattleStruct->hazardsQueue[side][i] = HAZARDS_NONE;
|
||||
gBattleStruct->numHazards[side]--;
|
||||
if (hazardType == HAZARDS_SPIKES)
|
||||
gSideTimers[side].spikesAmount = 0;
|
||||
else if (hazardType == HAZARDS_TOXIC_SPIKES)
|
||||
gSideTimers[side].toxicSpikesAmount = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (i < HAZARDS_MAX_COUNT)
|
||||
{
|
||||
if (i+1 == HAZARDS_MAX_COUNT)
|
||||
{
|
||||
gBattleStruct->hazardsQueue[side][i] = HAZARDS_NONE;
|
||||
break;
|
||||
}
|
||||
gBattleStruct->hazardsQueue[side][i] = gBattleStruct->hazardsQueue[side][i+1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
40
test/battle/hazards.c
Normal file
40
test/battle/hazards.c
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Hazards are applied based on order of set up")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_GRIMER);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); }
|
||||
TURN { MOVE(opponent, MOVE_STEALTH_ROCK); }
|
||||
TURN { MOVE(opponent, MOVE_STICKY_WEB); }
|
||||
TURN { MOVE(opponent, MOVE_SPIKES); }
|
||||
TURN { MOVE(opponent, MOVE_STEALTH_ROCK); SWITCH(player, 1); }
|
||||
TURN { MOVE(opponent, MOVE_STEALTH_ROCK); SWITCH(player, 2); }
|
||||
TURN { MOVE(opponent, MOVE_STEALTH_ROCK); SWITCH(player, 0); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent);
|
||||
MESSAGE("Wobbuffet was poisoned!");
|
||||
MESSAGE("Pointed stones dug into Wobbuffet!");
|
||||
MESSAGE("Wobbuffet was caught in a sticky web!");
|
||||
MESSAGE("Wobbuffet was hurt by the spikes!");
|
||||
MESSAGE("The poison spikes disappeared from the ground around your team!");
|
||||
MESSAGE("Pointed stones dug into Wynaut!");
|
||||
MESSAGE("Wynaut was caught in a sticky web!");
|
||||
MESSAGE("Wynaut was hurt by the spikes!");
|
||||
} THEN {
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][0], HAZARDS_STEALTH_ROCK);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][1], HAZARDS_STICKY_WEB);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][2], HAZARDS_SPIKES);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][3], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][4], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][5], HAZARDS_NONE);
|
||||
}
|
||||
}
|
||||
|
|
@ -29,16 +29,16 @@ DOUBLE_BATTLE_TEST("Court Change swaps entry hazards used by the opponent")
|
|||
MESSAGE("Wynaut swapped the battle effects affecting each side of the field!");
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
NONE_OF {
|
||||
MESSAGE("Wynaut was hurt by the spikes!");
|
||||
MESSAGE("Pointed stones dug into Wynaut!");
|
||||
MESSAGE("Wynaut was poisoned!");
|
||||
MESSAGE("Wynaut was caught in a sticky web!");
|
||||
MESSAGE("Pointed stones dug into Wynaut!");
|
||||
MESSAGE("Wynaut was hurt by the spikes!");
|
||||
MESSAGE("Wynaut was poisoned!");
|
||||
}
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
MESSAGE("The opposing Wobbuffet was hurt by the spikes!");
|
||||
MESSAGE("Pointed stones dug into the opposing Wobbuffet!");
|
||||
MESSAGE("The opposing Wobbuffet was poisoned!");
|
||||
MESSAGE("The opposing Wobbuffet was caught in a sticky web!");
|
||||
MESSAGE("Pointed stones dug into the opposing Wobbuffet!");
|
||||
MESSAGE("The opposing Wobbuffet was hurt by the spikes!");
|
||||
MESSAGE("The opposing Wobbuffet was poisoned!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,16 +64,16 @@ DOUBLE_BATTLE_TEST("Court Change swaps entry hazards used by the player")
|
|||
MESSAGE("The opposing Wynaut used Court Change!");
|
||||
MESSAGE("The opposing Wynaut swapped the battle effects affecting each side of the field!");
|
||||
SEND_IN_MESSAGE("Wobbuffet");
|
||||
MESSAGE("Wobbuffet was hurt by the spikes!");
|
||||
MESSAGE("Pointed stones dug into Wobbuffet!");
|
||||
MESSAGE("Wobbuffet was poisoned!");
|
||||
MESSAGE("Wobbuffet was caught in a sticky web!");
|
||||
MESSAGE("Pointed stones dug into Wobbuffet!");
|
||||
MESSAGE("Wobbuffet was hurt by the spikes!");
|
||||
MESSAGE("Wobbuffet was poisoned!");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
NONE_OF {
|
||||
MESSAGE("The opposing Wynaut was hurt by the spikes!");
|
||||
MESSAGE("Pointed stones dug into the opposing Wynaut!");
|
||||
MESSAGE("The opposing Wynaut was poisoned!");
|
||||
MESSAGE("The opposing Wynaut was caught in a sticky web!");
|
||||
MESSAGE("Pointed stones dug into the opposing Wynaut!");
|
||||
MESSAGE("The opposing Wynaut was hurt by the spikes!");
|
||||
MESSAGE("The opposing Wynaut was poisoned!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,8 +154,8 @@ DOUBLE_BATTLE_TEST("Defog removes Stealth Rock and Sticky Web from user's side (
|
|||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, playerLeft);
|
||||
if (move == MOVE_DEFOG && B_DEFOG_EFFECT_CLEARING >= GEN_6) {
|
||||
MESSAGE("The pointed stones disappeared from around your team!");
|
||||
MESSAGE("The sticky web has disappeared from the ground around your team!");
|
||||
MESSAGE("The pointed stones disappeared from around your team!");
|
||||
}
|
||||
// Switch happens
|
||||
SWITCH_OUT_MESSAGE("Wobbuffet");
|
||||
|
|
@ -365,16 +365,30 @@ DOUBLE_BATTLE_TEST("Defog removes everything it can")
|
|||
|
||||
if (B_DEFOG_EFFECT_CLEARING >= GEN_6) {
|
||||
MESSAGE("The spikes disappeared from the ground around your team!");
|
||||
MESSAGE("The pointed stones disappeared from around your team!");
|
||||
MESSAGE("The poison spikes disappeared from the ground around your team!");
|
||||
MESSAGE("The sticky web has disappeared from the ground around your team!");
|
||||
MESSAGE("The poison spikes disappeared from the ground around your team!");
|
||||
MESSAGE("The pointed stones disappeared from around your team!");
|
||||
|
||||
// Opponent side
|
||||
MESSAGE("The spikes disappeared from the ground around the opposing team!");
|
||||
MESSAGE("The pointed stones disappeared from around the opposing team!");
|
||||
MESSAGE("The poison spikes disappeared from the ground around the opposing team!");
|
||||
MESSAGE("The sticky web has disappeared from the ground around the opposing team!");
|
||||
MESSAGE("The poison spikes disappeared from the ground around the opposing team!");
|
||||
MESSAGE("The pointed stones disappeared from around the opposing team!");
|
||||
}
|
||||
} THEN {
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][0], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][1], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][2], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][3], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][4], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][5], HAZARDS_NONE);
|
||||
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[1][0], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[1][1], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[1][2], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[1][3], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[1][4], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[1][5], HAZARDS_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -159,8 +159,8 @@ SINGLE_BATTLE_TEST("Dragon Tail switches target out and incoming mon has Levitat
|
|||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, player);
|
||||
HP_BAR(opponent);
|
||||
MESSAGE("The opposing Weezing was dragged out!");
|
||||
HP_BAR(opponent);
|
||||
NOT STATUS_ICON(opponent, poison: TRUE);
|
||||
MESSAGE("The poison spikes disappeared from the ground around the opposing team!");
|
||||
NOT STATUS_ICON(opponent, poison: TRUE);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,3 +63,32 @@ SINGLE_BATTLE_TEST("Rapid Spin: Mortal Spin blows away Wrap, hazards and poisons
|
|||
MESSAGE("Wobbuffet blew away Stealth Rock!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Rapid Spin blows away all hazards")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_RAPID_SPIN) == EFFECT_RAPID_SPIN);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_STEALTH_ROCK); }
|
||||
TURN { MOVE(opponent, MOVE_STICKY_WEB); }
|
||||
TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); }
|
||||
TURN { MOVE(opponent, MOVE_SPIKES); MOVE(player, MOVE_RAPID_SPIN); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAPID_SPIN, player);
|
||||
|
||||
MESSAGE("Wobbuffet blew away Spikes!");
|
||||
MESSAGE("Wobbuffet blew away Sticky Web!");
|
||||
MESSAGE("Wobbuffet blew away Toxic Spikes!");
|
||||
MESSAGE("Wobbuffet blew away Stealth Rock!");
|
||||
} THEN {
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][0], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][1], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][2], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][3], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][4], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][5], HAZARDS_NONE);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,3 +133,30 @@ SINGLE_BATTLE_TEST("Spikes do not damage airborne Pokemon")
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Toxic Spikes: Only three layers can be set up")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SPIKES); }
|
||||
TURN { MOVE(opponent, MOVE_SPIKES); }
|
||||
TURN { MOVE(opponent, MOVE_SPIKES); }
|
||||
TURN { MOVE(opponent, MOVE_SPIKES); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent);
|
||||
} THEN {
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][0], HAZARDS_SPIKES);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][1], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][2], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][3], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][4], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][5], HAZARDS_NONE);
|
||||
u32 spikesAmount = gSideTimers[0].spikesAmount;
|
||||
EXPECT_EQ(spikesAmount, 3);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ SINGLE_BATTLE_TEST("Tidy Up removes hazards and raises Stats")
|
|||
MESSAGE("Wobbuffet used Tidy Up!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TIDY_UP, player);
|
||||
MESSAGE("The spikes disappeared from the ground around your team!");
|
||||
MESSAGE("The pointed stones disappeared from around your team!");
|
||||
MESSAGE("The poison spikes disappeared from the ground around your team!");
|
||||
MESSAGE("The sticky web has disappeared from the ground around your team!");
|
||||
MESSAGE("The poison spikes disappeared from the ground around your team!");
|
||||
MESSAGE("The pointed stones disappeared from around your team!");
|
||||
MESSAGE("Tidying up complete!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Wobbuffet's Attack rose!");
|
||||
|
|
|
|||
|
|
@ -266,3 +266,28 @@ SINGLE_BATTLE_TEST("Toxic Spikes print bad poison for 2 layers")
|
|||
MESSAGE("The opposing Wynaut was badly poisoned!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Toxic Spikes: Only two layers can be set up")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); }
|
||||
TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); }
|
||||
TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent);
|
||||
} THEN {
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][0], HAZARDS_TOXIC_SPIKES);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][1], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][2], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][3], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][4], HAZARDS_NONE);
|
||||
EXPECT_EQ(gBattleStruct->hazardsQueue[0][5], HAZARDS_NONE);
|
||||
u32 toxicSpikesAmount = gSideTimers[0].toxicSpikesAmount;
|
||||
EXPECT_EQ(toxicSpikesAmount, 2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user