Support gimmicks in AI tests
This commit is contained in:
parent
0422340356
commit
97376a5b5a
@ -638,7 +638,8 @@ struct BattlerTurn
|
||||
|
||||
struct ExpectedAIAction
|
||||
{
|
||||
u16 sourceLine;
|
||||
u16 sourceLine:13; // TODO: Avoid stealing these bits.
|
||||
enum Gimmick gimmick:3;
|
||||
u8 type:4; // which action
|
||||
u8 moveSlots:4; // Expected move(s) to be chosen or not, marked as bits.
|
||||
u8 target:4; // move target or id of mon which gets sent out
|
||||
|
||||
@ -7,6 +7,8 @@ extern const bool8 gTestRunnerSkipIsFail;
|
||||
|
||||
#if TESTING
|
||||
|
||||
enum Gimmick;
|
||||
|
||||
void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, u32 ability);
|
||||
void TestRunner_Battle_RecordAnimation(u32 animType, u32 animId);
|
||||
void TestRunner_Battle_RecordHP(u32 battlerId, u32 oldHP, u32 newHP);
|
||||
@ -14,7 +16,7 @@ void TestRunner_Battle_RecordExp(u32 battlerId, u32 oldExp, u32 newExp);
|
||||
void TestRunner_Battle_RecordMessage(const u8 *message);
|
||||
void TestRunner_Battle_RecordStatus1(u32 battlerId, u32 status1);
|
||||
void TestRunner_Battle_AfterLastTurn(void);
|
||||
void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target);
|
||||
void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target, enum Gimmick gimmick);
|
||||
void TestRunner_Battle_CheckSwitch(u32 battlerId, u32 partyIndex);
|
||||
void TestRunner_Battle_CheckAiMoveScores(u32 battlerId);
|
||||
void TestRunner_Battle_AISetScore(const char *file, u32 line, u32 battlerId, u32 moveIndex, s32 score);
|
||||
|
||||
@ -4502,7 +4502,10 @@ static void HandleTurnActionSelectionState(void)
|
||||
|
||||
if (gTestRunnerEnabled)
|
||||
{
|
||||
TestRunner_Battle_CheckChosenMove(battler, gChosenMoveByBattler[battler], gBattleStruct->moveTarget[battler]);
|
||||
UNUSED enum Gimmick gimmick = GIMMICK_NONE;
|
||||
if (gBattleResources->bufferB[battler][2] & RET_GIMMICK)
|
||||
gimmick = gBattleStruct->gimmick.usableGimmick[battler];
|
||||
TestRunner_Battle_CheckChosenMove(battler, gChosenMoveByBattler[battler], gBattleStruct->moveTarget[battler], gimmick);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI will tera if it enables a ko")
|
||||
{
|
||||
KNOWN_FAILING; // Tests don't currently give the AI the capability to tera, even with a tera type set.
|
||||
GIVEN {
|
||||
ASSUME(GetMovePower(MOVE_SEED_BOMB) == 80);
|
||||
ASSUME(GetMovePower(MOVE_AQUA_TAIL) == 90);
|
||||
@ -14,9 +13,9 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI will tera if it enables a ko")
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(1); Moves(MOVE_AQUA_TAIL, MOVE_SEED_BOMB); TeraType(TYPE_GRASS); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); TeraType(TYPE_FIRE); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_SEED_BOMB); }
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_SEED_BOMB, gimmick: GIMMICK_TERA); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
MESSAGE("The opposing Wobbuffet terastilized into the Grass type!");
|
||||
MESSAGE("The opposing Wobbuffet terastallized into the Grass type!");
|
||||
MESSAGE("Wobbuffet fainted!");
|
||||
}
|
||||
}
|
||||
@ -34,7 +33,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI will not tera if it gets outsped a
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
NOT MESSAGE("The opposing Wobbuffet terastilized into the Grass type!");
|
||||
NOT MESSAGE("The opposing Wobbuffet terastallized into the Grass type!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +49,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI will not tera if it gets ko'd by p
|
||||
} WHEN {
|
||||
TURN { }
|
||||
} SCENE {
|
||||
NOT MESSAGE("The opposing Wobbuffet terastilized into the Grass type!");
|
||||
NOT MESSAGE("The opposing Wobbuffet terastallized into the Grass type!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,6 +67,6 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI will not tera if it gets ko'd by p
|
||||
// } WHEN {
|
||||
// TURN { MOVE(player, MOVE_SEED_BOMB); }
|
||||
// } SCENE {
|
||||
// MESSAGE("The opposing Wobbuffet terastilized into the Fire type!");
|
||||
// MESSAGE("The opposing Wobbuffet terastallized into the Fire type!");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -765,6 +765,16 @@ static const char *const sBattleActionNames[] =
|
||||
[B_ACTION_SWITCH] = "SWITCH",
|
||||
};
|
||||
|
||||
static const char *const sGimmickIdentifiers[GIMMICKS_COUNT] =
|
||||
{
|
||||
[GIMMICK_NONE] = "N/A",
|
||||
[GIMMICK_MEGA] = "Mega Evolution",
|
||||
[GIMMICK_ULTRA_BURST] = "Ultra Burst",
|
||||
[GIMMICK_Z_MOVE] = "Z-Move",
|
||||
[GIMMICK_DYNAMAX] = "Dynamax",
|
||||
[GIMMICK_TERA] = "Terastallize",
|
||||
};
|
||||
|
||||
static u32 CountAiExpectMoves(struct ExpectedAIAction *expectedAction, u32 battlerId, bool32 printLog)
|
||||
{
|
||||
u32 i, countExpected = 0;
|
||||
@ -780,7 +790,7 @@ static u32 CountAiExpectMoves(struct ExpectedAIAction *expectedAction, u32 battl
|
||||
return countExpected;
|
||||
}
|
||||
|
||||
void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target)
|
||||
void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target, enum Gimmick gimmick)
|
||||
{
|
||||
const char *filename = gTestRunnerState.test->filename;
|
||||
u32 id = DATA.trial.aiActionsPlayed[battlerId];
|
||||
@ -802,6 +812,9 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target)
|
||||
if (expectedAction->explicitTarget && expectedAction->target != target)
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected target %s, got %s", filename, expectedAction->sourceLine, BattlerIdentifier(expectedAction->target), BattlerIdentifier(target));
|
||||
|
||||
if (expectedAction->gimmick != GIMMICKS_COUNT && expectedAction->gimmick != gimmick)
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected gimmick %s, got %s", filename, expectedAction->sourceLine, sGimmickIdentifiers[expectedAction->gimmick], sGimmickIdentifiers[gimmick]);
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if ((1u << i) & expectedAction->moveSlots)
|
||||
@ -1616,6 +1629,17 @@ void ClosePokemon(u32 sourceLine)
|
||||
DATA.currentMon = NULL;
|
||||
}
|
||||
|
||||
static void SetGimmick(u32 sourceLine, u32 side, u32 partyIndex, enum Gimmick gimmick)
|
||||
{
|
||||
enum Gimmick currentGimmick = DATA.chosenGimmick[side][partyIndex];
|
||||
if (!((currentGimmick == GIMMICK_ULTRA_BURST && gimmick == GIMMICK_Z_MOVE)
|
||||
|| (currentGimmick == GIMMICK_Z_MOVE && gimmick == GIMMICK_ULTRA_BURST)))
|
||||
{
|
||||
INVALID_IF(currentGimmick != GIMMICK_NONE && currentGimmick != gimmick, "Cannot set %s because %s already set", sGimmickIdentifiers[gimmick], sGimmickIdentifiers[currentGimmick]);
|
||||
}
|
||||
DATA.chosenGimmick[side][partyIndex] = gimmick;
|
||||
}
|
||||
|
||||
void Gender_(u32 sourceLine, u32 gender)
|
||||
{
|
||||
const struct SpeciesInfo *info;
|
||||
@ -1778,6 +1802,15 @@ void Item_(u32 sourceLine, u32 item)
|
||||
INVALID_IF(!DATA.currentMon, "Item outside of PLAYER/OPPONENT");
|
||||
INVALID_IF(item >= ITEMS_COUNT, "Illegal item: %d", item);
|
||||
SetMonData(DATA.currentMon, MON_DATA_HELD_ITEM, &item);
|
||||
switch (GetItemHoldEffect(item))
|
||||
{
|
||||
case HOLD_EFFECT_MEGA_STONE:
|
||||
SetGimmick(sourceLine, DATA.currentSide, DATA.currentPartyIndex, GIMMICK_MEGA);
|
||||
break;
|
||||
case HOLD_EFFECT_Z_CRYSTAL:
|
||||
SetGimmick(sourceLine, DATA.currentSide, DATA.currentPartyIndex, GIMMICK_Z_MOVE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Moves_(u32 sourceLine, u16 moves[MAX_MON_MOVES])
|
||||
@ -1834,18 +1867,21 @@ void DynamaxLevel_(u32 sourceLine, u32 dynamaxLevel)
|
||||
{
|
||||
INVALID_IF(!DATA.currentMon, "DynamaxLevel outside of PLAYER/OPPONENT");
|
||||
SetMonData(DATA.currentMon, MON_DATA_DYNAMAX_LEVEL, &dynamaxLevel);
|
||||
SetGimmick(sourceLine, DATA.currentSide, DATA.currentPartyIndex, GIMMICK_DYNAMAX);
|
||||
}
|
||||
|
||||
void GigantamaxFactor_(u32 sourceLine, bool32 gigantamaxFactor)
|
||||
{
|
||||
INVALID_IF(!DATA.currentMon, "GigantamaxFactor outside of PLAYER/OPPONENT");
|
||||
SetMonData(DATA.currentMon, MON_DATA_GIGANTAMAX_FACTOR, &gigantamaxFactor);
|
||||
SetGimmick(sourceLine, DATA.currentSide, DATA.currentPartyIndex, GIMMICK_DYNAMAX);
|
||||
}
|
||||
|
||||
void TeraType_(u32 sourceLine, u32 teraType)
|
||||
{
|
||||
INVALID_IF(!DATA.currentMon, "TeraType outside of PLAYER/OPPONENT");
|
||||
SetMonData(DATA.currentMon, MON_DATA_TERA_TYPE, &teraType);
|
||||
SetGimmick(sourceLine, DATA.currentSide, DATA.currentPartyIndex, GIMMICK_TERA);
|
||||
}
|
||||
|
||||
void Shadow_(u32 sourceLine, bool32 isShadow)
|
||||
@ -2146,11 +2182,7 @@ void MoveGetIdAndSlot(s32 battlerId, struct MoveContext *ctx, u32 *moveId, u32 *
|
||||
INVALID_IF(ctx->gimmick != GIMMICK_Z_MOVE && ctx->gimmick != GIMMICK_ULTRA_BURST && holdEffect == HOLD_EFFECT_Z_CRYSTAL, "Cannot use another gimmick while holding a Z-Crystal");
|
||||
|
||||
// Check multiple gimmick use.
|
||||
INVALID_IF(DATA.chosenGimmick[side][DATA.currentMonIndexes[battlerId]] != GIMMICK_NONE
|
||||
&& !(DATA.chosenGimmick[side][DATA.currentMonIndexes[battlerId]] == GIMMICK_ULTRA_BURST
|
||||
&& ctx->gimmick == GIMMICK_Z_MOVE), "Cannot use multiple gimmicks on the same battler");
|
||||
|
||||
DATA.chosenGimmick[side][DATA.currentMonIndexes[battlerId]] = ctx->gimmick;
|
||||
SetGimmick(sourceLine, side, DATA.currentMonIndexes[battlerId], ctx->gimmick);
|
||||
*moveSlot |= RET_GIMMICK;
|
||||
}
|
||||
}
|
||||
@ -2280,11 +2312,12 @@ static void TryMarkExpectMove(u32 sourceLine, struct BattlePokemon *battler, str
|
||||
|
||||
id = DATA.expectedAiActionIndex[battlerId];
|
||||
DATA.expectedAiActions[battlerId][id].type = B_ACTION_USE_MOVE;
|
||||
DATA.expectedAiActions[battlerId][id].moveSlots |= 1 << moveSlot;
|
||||
DATA.expectedAiActions[battlerId][id].moveSlots |= 1 << (moveSlot & ~RET_GIMMICK);
|
||||
DATA.expectedAiActions[battlerId][id].target = target;
|
||||
DATA.expectedAiActions[battlerId][id].explicitTarget = ctx->explicitTarget;
|
||||
DATA.expectedAiActions[battlerId][id].sourceLine = sourceLine;
|
||||
DATA.expectedAiActions[battlerId][id].actionSet = TRUE;
|
||||
DATA.expectedAiActions[battlerId][id].gimmick = ctx->explicitGimmick ? ctx->gimmick : GIMMICKS_COUNT;
|
||||
if (ctx->explicitNotExpected)
|
||||
DATA.expectedAiActions[battlerId][id].notMove = ctx->notExpected;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user