Align Crafty Shield with wiki and refine IsAllyProtectingFromMove (#8990)

This commit is contained in:
GGbond 2026-01-23 00:36:07 +08:00 committed by GitHub
parent 670bd806e5
commit 5308124191
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 146 additions and 44 deletions

View File

@ -1960,40 +1960,45 @@ bool32 IsAllyProtectingFromMove(u32 battlerAtk, u32 attackerMove, u32 allyMove)
{
return FALSE;
}
else
enum ProtectMethod protectMethod = GetMoveProtectMethod(allyMove);
switch (protectMethod)
{
enum ProtectMethod protectMethod = GetMoveProtectMethod(allyMove);
if (protectMethod == PROTECT_QUICK_GUARD)
case PROTECT_CRAFTY_SHIELD:
if (!IsBattleMoveStatus(attackerMove))
{
u32 priority = GetBattleMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk], attackerMove);
return (priority > 0);
return FALSE;
}
if (IsBattleMoveStatus(attackerMove))
else if (GetMoveEffect(attackerMove) == EFFECT_HOLD_HANDS)
{
switch (protectMethod)
{
case PROTECT_NORMAL:
case PROTECT_CRAFTY_SHIELD:
case PROTECT_MAX_GUARD:
case PROTECT_WIDE_GUARD:
return TRUE;
default:
return FALSE;
}
return TRUE;
}
else
{
switch (protectMethod)
{
case PROTECT_CRAFTY_SHIELD:
return FALSE;
default:
return TRUE;
}
u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, attackerMove);
return (GetBattlerSide(battlerAtk) != GetBattlerSide(BATTLE_PARTNER(battlerAtk))
&& moveTarget != MOVE_TARGET_OPPONENTS_FIELD
&& moveTarget != MOVE_TARGET_ALL_BATTLERS);
}
case PROTECT_WIDE_GUARD:
return IsSpreadMove(GetBattlerMoveTargetType(battlerAtk, attackerMove));
case PROTECT_NORMAL:
case PROTECT_SPIKY_SHIELD:
case PROTECT_MAX_GUARD:
case PROTECT_BANEFUL_BUNKER:
case PROTECT_BURNING_BULWARK:
return TRUE;
case PROTECT_OBSTRUCT:
case PROTECT_SILK_TRAP:
case PROTECT_KINGS_SHIELD:
return !IsBattleMoveStatus(attackerMove);
case PROTECT_QUICK_GUARD:
return (GetChosenMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk]) > 0);
case PROTECT_MAT_BLOCK:
return !IsBattleMoveStatus(attackerMove);
default:
return FALSE;
}
}

View File

@ -6635,6 +6635,26 @@ static inline bool32 IsSideProtected(u32 battler, enum ProtectMethod method)
|| gProtectStructs[BATTLE_PARTNER(battler)].protected == method;
}
static bool32 IsCraftyShieldProtected(u32 battlerAtk, u32 battlerDef, u32 move)
{
if (!IsBattleMoveStatus(move))
return FALSE;
if (!IsSideProtected(battlerDef, PROTECT_CRAFTY_SHIELD))
return FALSE;
if (GetMoveEffect(move) == EFFECT_HOLD_HANDS)
return TRUE;
u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move);
if (!IsBattlerAlly(battlerAtk, battlerDef)
&& moveTarget != MOVE_TARGET_OPPONENTS_FIELD
&& moveTarget != MOVE_TARGET_ALL_BATTLERS)
return TRUE;
return FALSE;
}
bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move)
{
if (gProtectStructs[battlerDef].protected == PROTECT_NONE
@ -6652,9 +6672,7 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move)
bool32 isProtected = FALSE;
if (IsSideProtected(battlerDef, PROTECT_CRAFTY_SHIELD)
&& IsBattleMoveStatus(move)
&& GetMoveEffect(move) != EFFECT_COACHING)
if (IsCraftyShieldProtected(battlerAtk, battlerDef, move))
isProtected = TRUE;
else if (MoveIgnoresProtect(move))
isProtected = FALSE;

View File

@ -528,7 +528,7 @@ DOUBLE_BATTLE_TEST("Protect: Quick Guard can not fail on consecutive turns (Gen6
}
}
DOUBLE_BATTLE_TEST("Protect: Crafty Shield protects self and ally from status moves")
DOUBLE_BATTLE_TEST("Crafty Shield protects self and ally from opposing status moves")
{
u16 move = MOVE_NONE;
struct BattlePokemon *targetOpponent = NULL;
@ -569,6 +569,72 @@ DOUBLE_BATTLE_TEST("Protect: Crafty Shield protects self and ally from status mo
}
}
DOUBLE_BATTLE_TEST("Crafty Shield does not protect against status moves used on the user's side")
{
u32 move;
PARAMETRIZE { move = MOVE_AROMATHERAPY; }
PARAMETRIZE { move = MOVE_ACUPRESSURE; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_AROMATHERAPY) == EFFECT_HEAL_BELL);
ASSUME(GetMoveEffect(MOVE_ACUPRESSURE) == EFFECT_ACUPRESSURE);
PLAYER(SPECIES_WOBBUFFET) { Speed(5); }
PLAYER(SPECIES_WOBBUFFET) { Speed(5); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(10); }
OPPONENT(SPECIES_WYNAUT) { Speed(5); Status1(STATUS1_BURN); }
} WHEN {
TURN {
MOVE(opponentLeft, MOVE_CRAFTY_SHIELD);
if (move == MOVE_ACUPRESSURE)
MOVE(opponentRight, move, target: opponentLeft);
else
MOVE(opponentRight, move);
}
TURN {}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CRAFTY_SHIELD, opponentLeft);
if (move == MOVE_ACUPRESSURE) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
} else {
ANIMATION(ANIM_TYPE_MOVE, MOVE_AROMATHERAPY, opponentRight);
STATUS_ICON(opponentRight, none: TRUE);
}
}
}
DOUBLE_BATTLE_TEST("Crafty Shield does not protect against entry hazard moves")
{
u32 move;
PARAMETRIZE { move = MOVE_SPIKES; }
PARAMETRIZE { move = MOVE_STEALTH_ROCK; }
PARAMETRIZE { move = MOVE_TOXIC_SPIKES; }
PARAMETRIZE { move = MOVE_STICKY_WEB; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_CRAFTY_SHIELD); MOVE(playerLeft, move, target: opponentLeft); }
TURN {}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CRAFTY_SHIELD, opponentLeft);
if (move == MOVE_SPIKES) {
MESSAGE("Spikes were scattered on the ground all around the opposing team!");
} else if (move == MOVE_TOXIC_SPIKES) {
MESSAGE("Poison spikes were scattered on the ground all around the opposing team!");
} else if (move == MOVE_STEALTH_ROCK) {
MESSAGE("Pointed stones float in the air around the opposing team!");
} else {
MESSAGE("A sticky web has been laid out on the ground around the opposing team!");
}
}
}
SINGLE_BATTLE_TEST("Protect: Protect does not block Confide or Decorate")
{
u32 move;
@ -618,6 +684,11 @@ DOUBLE_BATTLE_TEST("Crafty Shield protects self and ally from Confide and Decora
DOUBLE_BATTLE_TEST("Crafty Shield does not protect against moves that target all battlers")
{
u32 move;
PARAMETRIZE { move = MOVE_FLOWER_SHIELD; }
PARAMETRIZE { move = MOVE_PERISH_SONG; }
GIVEN {
ASSUME(GetSpeciesType(SPECIES_TANGELA, 0) == TYPE_GRASS);
ASSUME(GetSpeciesType(SPECIES_TANGROWTH, 0) == TYPE_GRASS);
@ -628,21 +699,29 @@ DOUBLE_BATTLE_TEST("Crafty Shield does not protect against moves that target all
OPPONENT(SPECIES_SUNKERN);
OPPONENT(SPECIES_SUNFLORA);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_CRAFTY_SHIELD); MOVE(opponentRight, MOVE_CELEBRATE); MOVE(playerLeft, MOVE_FLOWER_SHIELD); MOVE(playerRight, MOVE_CELEBRATE); }
TURN { MOVE(opponentLeft, MOVE_CRAFTY_SHIELD); MOVE(opponentRight, MOVE_CELEBRATE); MOVE(playerLeft, move); MOVE(playerRight, MOVE_CELEBRATE); }
} SCENE {
MESSAGE("Tangela used Flower Shield!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
MESSAGE("Tangela's Defense rose!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
MESSAGE("The opposing Sunkern's Defense rose!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
MESSAGE("Tangrowth's Defense rose!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
MESSAGE("The opposing Sunflora's Defense rose!");
if (move == MOVE_FLOWER_SHIELD) {
MESSAGE("Tangela used Flower Shield!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
MESSAGE("Tangela's Defense rose!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
MESSAGE("The opposing Sunkern's Defense rose!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
MESSAGE("Tangrowth's Defense rose!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLOWER_SHIELD, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
MESSAGE("The opposing Sunflora's Defense rose!");
} else {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PERISH_SONG, playerLeft);
NONE_OF {
MESSAGE("The opposing Sunkern protected itself!");
MESSAGE("The opposing Sunflora protected itself!");
}
}
}
}