Fix AI handling of Trick/Bestow and add comprehensive tests (#8516)
This commit is contained in:
parent
5700fb08a2
commit
ded6a0fe18
@ -2057,6 +2057,15 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-20);
|
||||
break;
|
||||
case EFFECT_TRICK:
|
||||
if ((gBattleMons[battlerAtk].item == ITEM_NONE && aiData->items[battlerDef] == ITEM_NONE)
|
||||
|| !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item)
|
||||
|| !CanBattlerGetOrLoseItem(battlerAtk, aiData->items[battlerDef])
|
||||
|| !CanBattlerGetOrLoseItem(battlerDef, aiData->items[battlerDef])
|
||||
|| !CanBattlerGetOrLoseItem(battlerDef, gBattleMons[battlerAtk].item)
|
||||
|| aiData->abilities[battlerAtk] == ABILITY_STICKY_HOLD
|
||||
|| aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(-10);
|
||||
case EFFECT_KNOCK_OFF:
|
||||
case EFFECT_CORROSIVE_GAS:
|
||||
if (aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD)
|
||||
@ -2450,8 +2459,12 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_BESTOW:
|
||||
if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_NONE
|
||||
|| !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item)) // AI knows its own item
|
||||
if (gBattleMons[battlerAtk].item == ITEM_NONE
|
||||
|| aiData->items[battlerDef] != ITEM_NONE
|
||||
|| !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item) // AI knows its own item
|
||||
|| !CanBattlerGetOrLoseItem(battlerDef, gBattleMons[battlerAtk].item)
|
||||
|| aiData->abilities[battlerAtk] == ABILITY_STICKY_HOLD
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_WISH:
|
||||
|
||||
@ -12698,7 +12698,7 @@ static void Cmd_trysethelpinghand(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Trick // TODO: Sticky Hold
|
||||
// Trick
|
||||
static void Cmd_tryswapitems(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *failInstr);
|
||||
@ -12743,6 +12743,10 @@ static void Cmd_tryswapitems(void)
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
// check if ability prevents swapping
|
||||
else if (GetBattlerAbility(gBattlerAttacker) == ABILITY_STICKY_HOLD)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else if (GetBattlerAbility(gBattlerTarget) == ABILITY_STICKY_HOLD)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_StickyHoldActivates;
|
||||
@ -17475,6 +17479,7 @@ void BS_TryBestow(void)
|
||||
|| gBattleMons[gBattlerTarget].item != ITEM_NONE
|
||||
|| !CanBattlerGetOrLoseItem(gBattlerAttacker, gBattleMons[gBattlerAttacker].item)
|
||||
|| !CanBattlerGetOrLoseItem(gBattlerTarget, gBattleMons[gBattlerAttacker].item)
|
||||
|| GetBattlerAbility(gBattlerAttacker) == ABILITY_STICKY_HOLD
|
||||
|| gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerTarget)] & (1u << gBattlerPartyIndexes[gBattlerTarget]))
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
|
||||
@ -56,6 +56,88 @@ AI_DOUBLE_BATTLE_TEST("AI will not use Helping Hand if partner does not have any
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI skips Trick/Bestow when items are missing or target already holds one")
|
||||
{
|
||||
u16 move = MOVE_NONE, atkItem = ITEM_NONE, targetItem = ITEM_NONE;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TRICK; atkItem = ITEM_NONE; targetItem = ITEM_NONE; }
|
||||
PARAMETRIZE { move = MOVE_BESTOW; atkItem = ITEM_NONE; targetItem = ITEM_NONE; }
|
||||
PARAMETRIZE { move = MOVE_BESTOW; atkItem = ITEM_ORAN_BERRY; targetItem = ITEM_LEFTOVERS; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(targetItem); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(move, MOVE_SCRATCH); Item(atkItem); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { NOT_EXPECT_MOVE(opponentLeft, move); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI skips Trick/Bestow with unexchangeable items")
|
||||
{
|
||||
u16 move = MOVE_NONE, atkItem = ITEM_NONE, targetItem = ITEM_NONE;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TRICK; atkItem = ITEM_ORANGE_MAIL; targetItem = ITEM_NONE; }
|
||||
PARAMETRIZE { move = MOVE_TRICK; atkItem = ITEM_ORAN_BERRY; targetItem = ITEM_ORANGE_MAIL; }
|
||||
PARAMETRIZE { move = MOVE_BESTOW; atkItem = ITEM_ORANGE_MAIL; targetItem = ITEM_NONE; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(targetItem); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(move, MOVE_SCRATCH); Item(atkItem); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { NOT_EXPECT_MOVE(opponentLeft, move); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI skips Trick/Bestow around Sticky Hold")
|
||||
{
|
||||
u16 move = MOVE_NONE, atkItem = ITEM_ORAN_BERRY, targetItem = ITEM_NONE;
|
||||
enum Ability atkAbility = ABILITY_PRESSURE, targetAbility = ABILITY_PRESSURE;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TRICK; atkAbility = ABILITY_STICKY_HOLD; targetAbility = ABILITY_PRESSURE; targetItem = ITEM_LEFTOVERS; }
|
||||
PARAMETRIZE { move = MOVE_TRICK; atkAbility = ABILITY_PRESSURE; targetAbility = ABILITY_STICKY_HOLD; targetItem = ITEM_LEFTOVERS; }
|
||||
PARAMETRIZE { move = MOVE_BESTOW; atkAbility = ABILITY_STICKY_HOLD; targetAbility = ABILITY_PRESSURE; targetItem = ITEM_NONE; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Ability(targetAbility); Item(targetItem); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Ability(atkAbility); Item(atkItem); Moves(move, MOVE_SCRATCH); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { NOT_EXPECT_MOVE(opponentLeft, move); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI skips Trick/Bestow if the target has a Substitute")
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE);
|
||||
|
||||
u16 move = MOVE_NONE, atkItem = ITEM_NONE, targetItem = ITEM_NONE;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TRICK; atkItem = ITEM_ORAN_BERRY; targetItem = ITEM_LEFTOVERS; }
|
||||
PARAMETRIZE { move = MOVE_BESTOW; atkItem = ITEM_ORAN_BERRY; targetItem = ITEM_NONE; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_SUBSTITUTE, MOVE_CELEBRATE); Item(targetItem); Speed(20); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); Speed(20); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(move, MOVE_SCRATCH); Item(atkItem); Speed(1); Attack(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); Speed(1); }
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(playerLeft, MOVE_SUBSTITUTE);
|
||||
MOVE(playerRight, MOVE_CELEBRATE);
|
||||
}
|
||||
TURN { NOT_EXPECT_MOVE(opponentLeft, move); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI will not use a status move if partner already chose Helping Hand")
|
||||
{
|
||||
s32 j;
|
||||
|
||||
@ -92,6 +92,21 @@ SINGLE_BATTLE_TEST("Bestow fails if the user's held item is a Z-Crystal")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Bestow fails if the user has Sticky Hold")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_STICKY_HOLD); Item(ITEM_SITRUS_BERRY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_BESTOW); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
} THEN {
|
||||
EXPECT(player->item == ITEM_SITRUS_BERRY);
|
||||
EXPECT(opponent->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Bestow fails if the target is behind a Substitute (Gen 6+)")
|
||||
{
|
||||
GIVEN {
|
||||
@ -130,4 +145,3 @@ SINGLE_BATTLE_TEST("Bestow fails if the user's held item changes its form")
|
||||
EXPECT(opponent->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,185 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
#include "mail.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Trick (Move Effect) test titles")
|
||||
SINGLE_BATTLE_TEST("Trick swaps held items")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LUM_BERRY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRICK); }
|
||||
} THEN {
|
||||
EXPECT(player->item == ITEM_LUM_BERRY);
|
||||
EXPECT(opponent->item == ITEM_SITRUS_BERRY);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trick succeeds if only the user has an item")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRICK); }
|
||||
} THEN {
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
EXPECT(opponent->item == ITEM_SITRUS_BERRY);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trick succeeds if only the target has an item")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LUM_BERRY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRICK); }
|
||||
} THEN {
|
||||
EXPECT(player->item == ITEM_LUM_BERRY);
|
||||
EXPECT(opponent->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trick fails if both battlers have no held item")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRICK); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
} THEN {
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
EXPECT(opponent->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trick fails if either item is Mail")
|
||||
{
|
||||
u16 atkItem = ITEM_NONE, defItem = ITEM_NONE;
|
||||
|
||||
ASSUME(ItemIsMail(ITEM_ORANGE_MAIL));
|
||||
PARAMETRIZE { atkItem = ITEM_ORANGE_MAIL; defItem = ITEM_NONE; }
|
||||
PARAMETRIZE { atkItem = ITEM_ORAN_BERRY; defItem = ITEM_ORANGE_MAIL; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(atkItem); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(defItem); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRICK); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
} THEN {
|
||||
EXPECT(player->item == atkItem);
|
||||
EXPECT(opponent->item == defItem);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trick fails if either item is a Z-Crystal")
|
||||
{
|
||||
u16 atkItem = ITEM_NONE, defItem = ITEM_NONE;
|
||||
|
||||
ASSUME(GetItemHoldEffect(ITEM_FIGHTINIUM_Z) == HOLD_EFFECT_Z_CRYSTAL);
|
||||
PARAMETRIZE { atkItem = ITEM_FIGHTINIUM_Z; defItem = ITEM_NONE; }
|
||||
PARAMETRIZE { atkItem = ITEM_SITRUS_BERRY; defItem = ITEM_FIGHTINIUM_Z; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(atkItem); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(defItem); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRICK); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
} THEN {
|
||||
EXPECT(player->item == atkItem);
|
||||
EXPECT(opponent->item == defItem);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trick fails if either battler holds a Mega Stone")
|
||||
{
|
||||
u16 atkItem = ITEM_NONE, defItem = ITEM_NONE;
|
||||
u16 atkSpecies = SPECIES_WOBBUFFET, defSpecies = SPECIES_WOBBUFFET;
|
||||
|
||||
PARAMETRIZE { atkSpecies = SPECIES_BLAZIKEN; atkItem = ITEM_BLAZIKENITE; defSpecies = SPECIES_WOBBUFFET; defItem = ITEM_SITRUS_BERRY; }
|
||||
PARAMETRIZE { atkSpecies = SPECIES_WOBBUFFET; atkItem = ITEM_SITRUS_BERRY; defSpecies = SPECIES_BLAZIKEN; defItem = ITEM_BLAZIKENITE; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(atkSpecies) { Item(atkItem); }
|
||||
OPPONENT(defSpecies) { Item(defItem); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRICK); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
} THEN {
|
||||
EXPECT(player->item == atkItem);
|
||||
EXPECT(opponent->item == defItem);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trick fails if an item changes the holder's form")
|
||||
{
|
||||
u16 atkItem = ITEM_NONE, defItem = ITEM_NONE;
|
||||
|
||||
PARAMETRIZE { atkItem = ITEM_GRISEOUS_CORE; defItem = ITEM_SITRUS_BERRY; }
|
||||
PARAMETRIZE { atkItem = ITEM_SITRUS_BERRY; defItem = ITEM_GRISEOUS_CORE; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GIRATINA_ORIGIN) { Item(atkItem); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(defItem); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRICK); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
} THEN {
|
||||
EXPECT(player->item == atkItem);
|
||||
EXPECT(opponent->item == defItem);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trick fails if the user has Sticky Hold")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_STICKY_HOLD); Item(ITEM_SITRUS_BERRY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LUM_BERRY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRICK); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
} THEN {
|
||||
EXPECT(player->item == ITEM_SITRUS_BERRY);
|
||||
EXPECT(opponent->item == ITEM_LUM_BERRY);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trick fails against Sticky Hold")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_STICKY_HOLD); Item(ITEM_LUM_BERRY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TRICK); }
|
||||
} SCENE {
|
||||
MESSAGE("The opposing Wobbuffet's Sticky Hold made Trick ineffective!");
|
||||
} THEN {
|
||||
EXPECT(player->item == ITEM_SITRUS_BERRY);
|
||||
EXPECT(opponent->item == ITEM_LUM_BERRY);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Trick fails if the target is behind a Substitute")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); Speed(50); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LUM_BERRY); Speed(100); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_TRICK); }
|
||||
} SCENE {
|
||||
MESSAGE("But it failed!");
|
||||
} THEN {
|
||||
EXPECT(player->item == ITEM_SITRUS_BERRY);
|
||||
EXPECT(opponent->item == ITEM_LUM_BERRY);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user