Merge branch '_RHH/master' into _RHH/upcoming
# Conflicts: # src/battle_ai_util.c # src/battle_util.c
This commit is contained in:
commit
c79188e3b3
@ -8315,7 +8315,7 @@ BattleScript_DazzlingProtected::
|
||||
attackstring
|
||||
ppreduce
|
||||
pause B_WAIT_TIME_SHORT
|
||||
call BattleScript_AbilityPopUp
|
||||
call BattleScript_AbilityPopUpScripting
|
||||
printstring STRINGID_POKEMONCANNOTUSEMOVE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
@ -517,6 +517,7 @@ struct MoveInfo
|
||||
u32 parentalBondBanned:1;
|
||||
u32 skyBattleBanned:1;
|
||||
u32 sketchBanned:1;
|
||||
u32 padding:5; // end of word
|
||||
|
||||
u32 argument;
|
||||
|
||||
|
||||
@ -975,48 +975,21 @@ static u32 AI_GetEffectiveness(uq4_12_t multiplier)
|
||||
*/
|
||||
s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered)
|
||||
{
|
||||
u32 fasterAI = 0, fasterPlayer = 0, i;
|
||||
s8 prioAI = 0;
|
||||
s8 prioBattler2 = 0;
|
||||
u16 *battler2Moves = GetMovesArray(battler2);
|
||||
|
||||
// Check move priorities first.
|
||||
prioAI = GetMovePriority(battlerAI, moveConsidered);
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
prioBattler2 = GetMovePriority(battler2, battler2Moves[i]);
|
||||
if (battler2Moves[i] == MOVE_NONE || battler2Moves[i] == MOVE_UNAVAILABLE
|
||||
|| (prioBattler2 > prioAI && !CanIndexMoveFaintTarget(battler2, battlerAI, i , 2)))
|
||||
continue;
|
||||
|
||||
if (prioAI > prioBattler2)
|
||||
fasterAI++;
|
||||
else if (prioBattler2 > prioAI)
|
||||
fasterPlayer++;
|
||||
}
|
||||
|
||||
if (fasterAI > fasterPlayer)
|
||||
{
|
||||
if (prioAI > prioBattler2)
|
||||
return AI_IS_FASTER;
|
||||
|
||||
if (GetWhichBattlerFasterArgs(battlerAI, battler2, TRUE,
|
||||
AI_DATA->abilities[battlerAI], AI_DATA->abilities[battler2],
|
||||
AI_DATA->holdEffects[battlerAI], AI_DATA->holdEffects[battler2],
|
||||
AI_DATA->speedStats[battlerAI], AI_DATA->speedStats[battler2],
|
||||
prioAI, prioBattler2) == 1)
|
||||
return AI_IS_FASTER;
|
||||
}
|
||||
else if (fasterAI < fasterPlayer)
|
||||
{
|
||||
return AI_IS_SLOWER;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prioAI > prioBattler2)
|
||||
return AI_IS_FASTER; // if we didn't know any of battler 2's moves to compare priorities, assume they don't have a prio+ move
|
||||
// Priorities are the same(at least comparing to moves the AI is aware of), decide by speed.
|
||||
if (GetWhichBattlerFasterArgs(battlerAI, battler2, TRUE,
|
||||
AI_DATA->abilities[battlerAI], AI_DATA->abilities[battler2],
|
||||
AI_DATA->holdEffects[battlerAI], AI_DATA->holdEffects[battler2],
|
||||
AI_DATA->speedStats[battlerAI], AI_DATA->speedStats[battler2],
|
||||
prioAI, prioBattler2) == 1)
|
||||
return AI_IS_FASTER;
|
||||
else
|
||||
return AI_IS_SLOWER;
|
||||
}
|
||||
return AI_IS_SLOWER;
|
||||
}
|
||||
|
||||
// Check if target has means to faint ai mon.
|
||||
@ -1731,19 +1704,14 @@ bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
|
||||
bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
if (defAbility == ABILITY_CONTRARY
|
||||
|| defAbility == ABILITY_CLEAR_BODY
|
||||
|| defAbility == ABILITY_FULL_METAL_BODY
|
||||
|| defAbility == ABILITY_WHITE_SMOKE
|
||||
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET)
|
||||
return FALSE;
|
||||
|
||||
if (AI_IsSlower(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& defAbility != ABILITY_CONTRARY
|
||||
&& defAbility != ABILITY_CLEAR_BODY
|
||||
&& defAbility != ABILITY_FULL_METAL_BODY
|
||||
&& defAbility != ABILITY_WHITE_SMOKE
|
||||
&& AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
return (AI_IsSlower(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered));
|
||||
}
|
||||
|
||||
bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
|
||||
@ -5097,7 +5097,7 @@ s8 GetMovePriority(u32 battler, u16 move)
|
||||
gProtectStructs[battler].pranksterElevated = 1;
|
||||
priority++;
|
||||
}
|
||||
else if (gMovesInfo[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battler))
|
||||
else if (gMovesInfo[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battler) && !IsDynamaxed(battler) && !(gBattleStruct->dynamax.toDynamax & gBitTable[battler]))
|
||||
{
|
||||
priority++;
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ static const u8 sText_CantEscape2[] = _("Can't escape!\p");
|
||||
static const u8 sText_AttackerCantEscape[] = _("{B_ATK_NAME_WITH_PREFIX} can't escape!");
|
||||
static const u8 sText_HitXTimes[] = _("Hit {B_BUFF1} time(s)!");
|
||||
static const u8 sText_PkmnFellAsleep[] = _("{B_EFF_NAME_WITH_PREFIX}\nfell asleep!");
|
||||
static const u8 sText_PkmnMadeSleep[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nmade {B_EFF_NAME_WITH_PREFIX} sleep!");
|
||||
static const u8 sText_PkmnMadeSleep[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\nmade {B_EFF_NAME_WITH_PREFIX} sleep!");
|
||||
static const u8 sText_PkmnAlreadyAsleep[] = _("{B_DEF_NAME_WITH_PREFIX} is\nalready asleep!");
|
||||
static const u8 sText_PkmnAlreadyAsleep2[] = _("{B_ATK_NAME_WITH_PREFIX} is\nalready asleep!");
|
||||
static const u8 sText_PkmnWasntAffected[] = _("{B_DEF_NAME_WITH_PREFIX}\nwasn't affected!");
|
||||
@ -103,12 +103,12 @@ static const u8 sText_PkmnBadlyPoisoned[] = _("{B_EFF_NAME_WITH_PREFIX} is badly
|
||||
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_PkmnBurnedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\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!");
|
||||
static const u8 sText_PkmnFrozenBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\nfroze {B_EFF_NAME_WITH_PREFIX} solid!");
|
||||
static const u8 sText_PkmnIsFrozen[] = _("{B_ATK_NAME_WITH_PREFIX} is\nfrozen solid!");
|
||||
static const u8 sText_PkmnWasDefrosted[] = _("{B_DEF_NAME_WITH_PREFIX} was\ndefrosted!");
|
||||
static const u8 sText_PkmnWasDefrosted2[] = _("{B_ATK_NAME_WITH_PREFIX} was\ndefrosted!");
|
||||
@ -117,7 +117,7 @@ static const u8 sText_PkmnFrostbiteHealed[] = _("{B_DEF_NAME_WITH_PREFIX}'s\nfro
|
||||
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_PkmnWasParalyzedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\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!");
|
||||
static const u8 sText_PkmnIsAlreadyParalyzed[] = _("{B_DEF_NAME_WITH_PREFIX} is\nalready paralyzed!");
|
||||
static const u8 sText_PkmnHealedParalysis[] = _("{B_DEF_NAME_WITH_PREFIX} was\nhealed of paralysis!");
|
||||
|
||||
@ -6231,8 +6231,19 @@ static void Cmd_moveend(void)
|
||||
case MOVEEND_DANCER: // Special case because it's so annoying
|
||||
if (gMovesInfo[gCurrentMove].danceMove)
|
||||
{
|
||||
u8 battler, nextDancer = 0;
|
||||
u32 battler, nextDancer = 0;
|
||||
bool32 turnOnHitmarker = FALSE;
|
||||
|
||||
for (battler = 0; battler < MAX_BATTLERS_COUNT; battler++)
|
||||
{
|
||||
if (gSpecialStatuses[battler].dancerUsedMove)
|
||||
{
|
||||
// in case a battler fails to act on a Dancer-called move
|
||||
turnOnHitmarker = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(gBattleStruct->lastMoveFailed & gBitTable[gBattlerAttacker]
|
||||
|| (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove
|
||||
&& gBattleStruct->bouncedMoveIsUsed)))
|
||||
@ -6248,6 +6259,8 @@ static void Cmd_moveend(void)
|
||||
{
|
||||
if (GetBattlerAbility(battler) == ABILITY_DANCER && !gSpecialStatuses[battler].dancerUsedMove)
|
||||
{
|
||||
if (turnOnHitmarker)
|
||||
gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED;
|
||||
if (!nextDancer || (gBattleMons[battler].speed < gBattleMons[nextDancer & 0x3].speed))
|
||||
nextDancer = battler | 0x4;
|
||||
}
|
||||
|
||||
@ -4970,10 +4970,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
BattleScriptPushCursorAndCallback(BattleScript_BadDreamsActivates);
|
||||
effect++;
|
||||
break;
|
||||
SOLAR_POWER_HP_DROP:
|
||||
case ABILITY_SOLAR_POWER:
|
||||
if (IsBattlerWeatherAffected(battler, B_WEATHER_SUN))
|
||||
{
|
||||
SOLAR_POWER_HP_DROP:
|
||||
BattleScriptPushCursorAndCallback(BattleScript_SolarPowerActivates);
|
||||
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8;
|
||||
if (gBattleMoveDamage == 0)
|
||||
@ -5045,31 +5045,70 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
case ABILITYEFFECT_WOULD_BLOCK:
|
||||
{
|
||||
u16 moveTarget = GetBattlerMoveTargetType(battler, move);
|
||||
u16 battlerAbility = GetBattlerAbility(battler);
|
||||
u16 targetAbility = GetBattlerAbility(gBattlerTarget);
|
||||
const u8 * battleScriptBlocksMove = NULL;
|
||||
|
||||
if ((gLastUsedAbility == ABILITY_SOUNDPROOF && gMovesInfo[move].soundMove && !(moveTarget & MOVE_TARGET_USER))
|
||||
|| (gLastUsedAbility == ABILITY_BULLETPROOF && gMovesInfo[move].ballisticMove))
|
||||
switch (gLastUsedAbility)
|
||||
{
|
||||
case ABILITY_SOUNDPROOF:
|
||||
if (gMovesInfo[move].soundMove && !(moveTarget & MOVE_TARGET_USER))
|
||||
effect = 1;
|
||||
break;
|
||||
case ABILITY_BULLETPROOF:
|
||||
if (gMovesInfo[move].ballisticMove)
|
||||
effect = 1;
|
||||
break;
|
||||
case ABILITY_DAZZLING:
|
||||
case ABILITY_QUEENLY_MAJESTY:
|
||||
case ABILITY_ARMOR_TAIL:
|
||||
if (GetChosenMovePriority(gBattlerAttacker) > 0 && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
|
||||
effect = 2;
|
||||
break;
|
||||
case ABILITY_GOOD_AS_GOLD:
|
||||
if (IS_MOVE_STATUS(gCurrentMove)
|
||||
&& !(moveTarget & MOVE_TARGET_USER)
|
||||
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
|
||||
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
|
||||
effect = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!effect)
|
||||
{
|
||||
switch (GetBattlerAbility(BATTLE_PARTNER(battler)))
|
||||
{
|
||||
case ABILITY_DAZZLING:
|
||||
case ABILITY_QUEENLY_MAJESTY:
|
||||
case ABILITY_ARMOR_TAIL:
|
||||
if (GetChosenMovePriority(gBattlerAttacker) > 0 && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
|
||||
effect = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (effect == 1)
|
||||
{
|
||||
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
battleScriptBlocksMove = BattleScript_SoundproofProtected;
|
||||
effect = 1;
|
||||
}
|
||||
else if ((gLastUsedAbility == ABILITY_DAZZLING || gLastUsedAbility == ABILITY_QUEENLY_MAJESTY || gLastUsedAbility == ABILITY_ARMOR_TAIL || IsBattlerAlive(battler ^= BIT_FLANK))
|
||||
&& (battlerAbility == ABILITY_DAZZLING || battlerAbility == ABILITY_QUEENLY_MAJESTY || battlerAbility == ABILITY_ARMOR_TAIL)
|
||||
&& GetChosenMovePriority(gBattlerAttacker) > 0
|
||||
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
|
||||
else if (effect == 2 || effect == 4)
|
||||
{
|
||||
if (effect == 4)
|
||||
gBattleScripting.battler = BATTLE_PARTNER(battler);
|
||||
else
|
||||
gBattleScripting.battler = battler;
|
||||
|
||||
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
battleScriptBlocksMove = BattleScript_DazzlingProtected;
|
||||
effect = 1;
|
||||
}
|
||||
else if (effect == 3)
|
||||
{
|
||||
battleScriptBlocksMove = BattleScript_GoodAsGoldActivates;
|
||||
}
|
||||
else if (GetChosenMovePriority(gBattlerAttacker) > 0
|
||||
&& BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
|
||||
&& !(IS_MOVE_STATUS(move) && (targetAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove)))
|
||||
&& BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
|
||||
&& !(IS_MOVE_STATUS(move) && (gLastUsedAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove)))
|
||||
{
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || !(moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)))
|
||||
CancelMultiTurnMoves(gBattlerAttacker); // Don't cancel moves that can hit two targets bc one target might not be protected
|
||||
@ -5077,15 +5116,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
battleScriptBlocksMove = BattleScript_DarkTypePreventsPrankster;
|
||||
effect = 1;
|
||||
}
|
||||
else if (GetBattlerAbility(gBattlerTarget) == ABILITY_GOOD_AS_GOLD
|
||||
&& IS_MOVE_STATUS(gCurrentMove)
|
||||
&& !(moveTarget & MOVE_TARGET_USER)
|
||||
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
|
||||
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
|
||||
{
|
||||
battleScriptBlocksMove = BattleScript_GoodAsGoldActivates;
|
||||
effect = 1;
|
||||
}
|
||||
if (caseID == ABILITYEFFECT_WOULD_BLOCK)
|
||||
{
|
||||
if (effect && gLastUsedAbility != 0xFFFF)
|
||||
@ -5562,6 +5592,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& RandomWeighted(RNG_STATIC, 2, 1))
|
||||
{
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS;
|
||||
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect;
|
||||
gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT;
|
||||
@ -5579,6 +5610,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& RandomWeighted(RNG_FLAME_BODY, 2, 1))
|
||||
{
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN;
|
||||
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect;
|
||||
gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT;
|
||||
@ -5851,6 +5883,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
if (IsBattlerAlive(battler)
|
||||
&& (gMovesInfo[gCurrentMove].danceMove)
|
||||
&& !gSpecialStatuses[battler].dancerUsedMove
|
||||
&& (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED)
|
||||
&& gBattlerAttacker != battler)
|
||||
{
|
||||
// Set bit and save Dancer mon's original target
|
||||
|
||||
@ -1602,6 +1602,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
|
||||
.name = _("Disguise"),
|
||||
.description = COMPOUND_STRING("Decoy protects it once."),
|
||||
.aiRating = 8,
|
||||
.breakable = TRUE,
|
||||
.cantBeCopied = TRUE,
|
||||
.cantBeSwapped = TRUE,
|
||||
.cantBeTraced = TRUE,
|
||||
|
||||
@ -6331,6 +6331,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
|
||||
.category = DAMAGE_CATEGORY_STATUS,
|
||||
.zMove = { .effect = Z_EFFECT_DEF_UP_1 },
|
||||
.magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5,
|
||||
.ignoresSubstitute = TRUE,
|
||||
.contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS,
|
||||
.contestCategory = CONTEST_CATEGORY_TOUGH,
|
||||
.contestComboStarterId = 0,
|
||||
@ -10411,7 +10412,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
|
||||
.priority = 0,
|
||||
.category = DAMAGE_CATEGORY_STATUS,
|
||||
.zMove = { .effect = Z_EFFECT_ACC_UP_1 },
|
||||
//.ignoresSubstitute = TRUE,
|
||||
.ignoresSubstitute = B_UPDATED_MOVE_FLAGS == GEN_4,
|
||||
.magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5,
|
||||
.contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS,
|
||||
.contestCategory = CONTEST_CATEGORY_BEAUTY,
|
||||
@ -14339,6 +14340,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
|
||||
.zMove = { .effect = Z_EFFECT_SPDEF_UP_2 },
|
||||
.powderMove = TRUE,
|
||||
.magicCoatAffected = TRUE,
|
||||
.ignoresSubstitute = TRUE,
|
||||
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
|
||||
.contestCategory = CONTEST_CATEGORY_SMART,
|
||||
.contestComboStarterId = 0,
|
||||
|
||||
4
test/battle/ability/armor_tail.c
Normal file
4
test/battle/ability/armor_tail.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// Tests for Armor Tail are handled in test/battle/ability/dazzling.c
|
||||
@ -53,3 +53,76 @@ DOUBLE_BATTLE_TEST("Dancer can copy Teeter Dance and confuse both opposing targe
|
||||
MESSAGE("Wynaut became confused!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dancer triggers from slowest to fastest")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(10); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(50); }
|
||||
OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(3); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_DRAGON_DANCE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Dancer doesn't trigger if the original user flinches")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100));
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET)
|
||||
OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_FAKE_OUT); MOVE(player, MOVE_DRAGON_DANCE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, opponent);
|
||||
MESSAGE("Wobbuffet flinched!");
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dancer still triggers if another dancer flinches")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100));
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(10); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(5); }
|
||||
OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(3); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_FAKE_OUT, target: playerLeft); MOVE(playerRight, MOVE_DRAGON_DANCE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_DANCER);
|
||||
MESSAGE("Wobbuffet flinched!");
|
||||
NONE_OF {
|
||||
MESSAGE("Wobbuffet used Dragon Dance!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
}
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DANCER);
|
||||
MESSAGE("Foe Oricorio used Dragon Dance!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
52
test/battle/ability/dazzling.c
Normal file
52
test/battle/ability/dazzling.c
Normal file
@ -0,0 +1,52 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority > 0);
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect the user from priority moves")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; }
|
||||
PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; }
|
||||
PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_QUICK_ATTACK, target: opponentLeft); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponentRight);
|
||||
ABILITY_POPUP(opponentLeft, ability);
|
||||
MESSAGE("Wobbuffet cannot use Quick Attack!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect users partner from priority moves")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; }
|
||||
PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; }
|
||||
PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_QUICK_ATTACK, target: opponentRight); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponentRight);
|
||||
ABILITY_POPUP(opponentLeft, ability);
|
||||
MESSAGE("Wobbuffet cannot use Quick Attack!");
|
||||
}
|
||||
}
|
||||
70
test/battle/ability/good_as_gold.c
Normal file
70
test/battle/ability/good_as_gold.c
Normal file
@ -0,0 +1,70 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
|
||||
SINGLE_BATTLE_TEST("Good as Gold protects from status moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].category == DAMAGE_CATEGORY_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TOXIC); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
|
||||
ABILITY_POPUP(opponent, ABILITY_GOOD_AS_GOLD);
|
||||
MESSAGE("It doesn't affect Foe Gholdengo…");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Good as Gold doesn't protect the user from it's own moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_NASTY_PLOT].category == DAMAGE_CATEGORY_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_NASTY_PLOT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_NASTY_PLOT, opponent);
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_GOOD_AS_GOLD);
|
||||
MESSAGE("It doesn't affect Foe Gholdengo…");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Good as Gold doesn't protect from moves that target the field")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].category == DAMAGE_CATEGORY_STATUS);
|
||||
ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].target == MOVE_TARGET_OPPONENTS_FIELD);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, player);
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_GOOD_AS_GOLD);
|
||||
MESSAGE("It doesn't affect Foe Gholdengo…");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Good as Gold protects from partner's status moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_HELPING_HAND].category == DAMAGE_CATEGORY_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_HELPING_HAND); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HELPING_HAND, opponentRight);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_GOOD_AS_GOLD);
|
||||
MESSAGE("It doesn't affect Foe Gholdengo…");
|
||||
}
|
||||
}
|
||||
4
test/battle/ability/queenly_majesty.c
Normal file
4
test/battle/ability/queenly_majesty.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// Tests for Queenly Majesty are handled in test/battle/ability/dazzling.c
|
||||
Loading…
x
Reference in New Issue
Block a user