Skip to content

Commit

Permalink
Wild battle tests + tests for exp points (rh-hideout#3342)
Browse files Browse the repository at this point in the history
* Add WIld Battles to test runner + exp tests
  • Loading branch information
DizzyEggg authored Sep 27, 2023
1 parent baca050 commit 2fcb9bb
Show file tree
Hide file tree
Showing 15 changed files with 401 additions and 72 deletions.
1 change: 1 addition & 0 deletions data/battle_scripts_2.s
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ BattleScript_PrintCaughtMonInfo::
getexp BS_TARGET
sethword gBattle_BG2_X, 0
BattleScript_TryPrintCaughtMonInfo:
jumpifbattletype BATTLE_TYPE_RECORDED, BattleScript_GiveCaughtMonEnd
trysetcaughtmondexflags BattleScript_TryNicknameCaughtMon
printstring STRINGID_PKMNDATAADDEDTODEX
waitstate
Expand Down
1 change: 1 addition & 0 deletions include/battle_controllers.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ void BtlController_HandleBattleAnimation(u32 battler, bool32 ignoreSE, bool32 up
// player controller
void SetControllerToPlayer(u32 battler);
void SetBattleEndCallbacks(u32 battler);
void PlayerHandleBallThrowAnim(u32 battler);
void PlayerHandleExpUpdate(u32 battler);
u32 LinkPlayerGetTrainerPicId(u32 multiplayerId);
void CB2_SetUpReshowBattleScreenAfterMenu(void);
Expand Down
1 change: 1 addition & 0 deletions include/constants/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
| BATTLE_TYPE_GROUDON | BATTLE_TYPE_KYOGRE | BATTLE_TYPE_RAYQUAZA))

#define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER))))
#define RECORDED_WILD_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_RECORDED) && !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER)))
#define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gTrainerBattleOpponent_B == 0xFFFF))
#define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER | BATTLE_TYPE_INGAME_PARTNER)

Expand Down
1 change: 1 addition & 0 deletions include/recorded_battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ u8 RecordedBattle_BufferNewBattlerData(u8 *dst);
void RecordedBattle_RecordAllBattlerData(u8 *data);
bool32 CanCopyRecordedBattleSaveData(void);
bool32 MoveRecordedBattleToSaveData(void);
void SetPartiesFromRecordedSave(struct RecordedBattleSave *src);
void SetVariablesForRecordedBattle(struct RecordedBattleSave *);
void PlayRecordedBattle(void (*CB2_After)(void));
u8 GetRecordedBattleFrontierFacility(void);
Expand Down
57 changes: 56 additions & 1 deletion include/test/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,20 @@
* ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
* target can only be specified for ANIM_TYPE_MOVE.
*
* EXPERIENCE_BAR(battler, [exp: | captureGainedExp:])
* If exp: is used, causes the test to fail if that amount of
* experience is not gained, e.g.:
* EXPERIENCE_BAR(player, exp: 0);
* If captureGainedExp: is used, causes the test to fail if
* the Experience bar does not change, and then writes that change to the
* pointer, e.g.:
* u32 exp;
* EXPERIENCE_BAR(player, captureGainedExp: &exp);
* If none of the above are used, causes the test to fail if the Exp
* does not change at all.
* Please note that due to nature of tests, this command
* is only usable in WILD_BATTLE_TEST and will fail elsewhere.
*
* HP_BAR(battler, [damage: | hp: | captureDamage: | captureHP:])
* If hp: or damage: are used, causes the test to fail if that amount of
* damage is not dealt, e.g.:
Expand Down Expand Up @@ -470,7 +484,7 @@
#define MAX_TURNS 16
#define MAX_QUEUED_EVENTS 25

enum { BATTLE_TEST_SINGLES, BATTLE_TEST_DOUBLES };
enum { BATTLE_TEST_SINGLES, BATTLE_TEST_DOUBLES, BATTLE_TEST_WILD };

typedef void (*SingleBattleTestFunction)(void *, u32, struct BattlePokemon *, struct BattlePokemon *);
typedef void (*DoubleBattleTestFunction)(void *, u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *);
Expand All @@ -492,6 +506,7 @@ enum
QUEUED_ABILITY_POPUP_EVENT,
QUEUED_ANIMATION_EVENT,
QUEUED_HP_EVENT,
QUEUED_EXP_EVENT,
QUEUED_MESSAGE_EVENT,
QUEUED_STATUS_EVENT,
};
Expand All @@ -511,6 +526,7 @@ struct QueuedAnimationEvent
};

enum { HP_EVENT_NEW_HP, HP_EVENT_DELTA_HP };
enum { EXP_EVENT_NEW_EXP, EXP_EVENT_DELTA_EXP };

struct QueuedHPEvent
{
Expand All @@ -519,6 +535,13 @@ struct QueuedHPEvent
u32 address:28;
};

struct QueuedExpEvent
{
u32 battlerId:3;
u32 type:1;
u32 address:28;
};

struct QueuedMessageEvent
{
const u8 *pattern;
Expand All @@ -541,6 +564,7 @@ struct QueuedEvent
struct QueuedAbilityEvent ability;
struct QueuedAnimationEvent animation;
struct QueuedHPEvent hp;
struct QueuedExpEvent exp;
struct QueuedMessageEvent message;
struct QueuedStatusEvent status;
} as;
Expand Down Expand Up @@ -676,6 +700,24 @@ extern struct BattleTestRunnerState *gBattleTestRunnerState;
}; \
static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *results, u32 i, struct BattlePokemon *player, struct BattlePokemon *opponent)

#define WILD_BATTLE_TEST(_name, ...) \
struct CAT(Result, __LINE__) { MEMBERS(__VA_ARGS__) }; \
static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *, u32, struct BattlePokemon *, struct BattlePokemon *); \
__attribute__((section(".tests"))) static const struct Test CAT(sTest, __LINE__) = \
{ \
.name = _name, \
.filename = __FILE__, \
.runner = &gBattleTestRunner, \
.data = (void *)&(const struct BattleTest) \
{ \
.type = BATTLE_TEST_WILD, \
.sourceLine = __LINE__, \
.function = { .singles = (SingleBattleTestFunction)CAT(Test, __LINE__) }, \
.resultsSize = sizeof(struct CAT(Result, __LINE__)), \
}, \
}; \
static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *results, u32 i, struct BattlePokemon *player, struct BattlePokemon *opponent)

#define DOUBLE_BATTLE_TEST(_name, ...) \
struct CAT(Result, __LINE__) { MEMBERS(__VA_ARGS__) }; \
static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *, u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); \
Expand Down Expand Up @@ -741,6 +783,7 @@ struct moveWithPP {
#define MovesWithPP(movewithpp1, ...) MovesWithPP_(__LINE__, (struct moveWithPP[MAX_MON_MOVES]) {movewithpp1, __VA_ARGS__})
#define Friendship(friendship) Friendship_(__LINE__, friendship)
#define Status1(status1) Status1_(__LINE__, status1)
#define OTName(otName) do {static const u8 otName_[] = _(otName); OTName_(__LINE__, otName_);} while (0)

void OpenPokemon(u32 sourceLine, u32 side, u32 species);
void ClosePokemon(u32 sourceLine);
Expand All @@ -762,6 +805,7 @@ void Moves_(u32 sourceLine, const u16 moves[MAX_MON_MOVES]);
void MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]);
void Friendship_(u32 sourceLine, u32 friendship);
void Status1_(u32 sourceLine, u32 status1);
void OTName_(u32 sourceLine, const u8 *otName);

#define PLAYER_PARTY (gBattleTestRunnerState->data.recordedBattle.playerParty)
#define OPPONENT_PARTY (gBattleTestRunnerState->data.recordedBattle.opponentParty)
Expand Down Expand Up @@ -837,6 +881,7 @@ void SendOut(u32 sourceLine, struct BattlePokemon *, u32 partyIndex);
#define ABILITY_POPUP(battler, ...) QueueAbility(__LINE__, battler, (struct AbilityEventContext) { __VA_ARGS__ })
#define ANIMATION(type, id, ...) QueueAnimation(__LINE__, type, id, (struct AnimationEventContext) { __VA_ARGS__ })
#define HP_BAR(battler, ...) QueueHP(__LINE__, battler, (struct HPEventContext) { APPEND_TRUE(__VA_ARGS__) })
#define EXPERIENCE_BAR(battler, ...) QueueExp(__LINE__, battler, (struct ExpEventContext) { APPEND_TRUE(__VA_ARGS__) })
// Static const is needed to make the modern compiler put the pattern variable in the .rodata section, instead of putting it on stack(which can break the game).
#define MESSAGE(pattern) do {static const u8 msg[] = _(pattern); QueueMessage(__LINE__, msg);} while (0)
#define STATUS_ICON(battler, status) QueueStatus(__LINE__, battler, (struct StatusEventContext) { status })
Expand Down Expand Up @@ -872,6 +917,15 @@ struct HPEventContext
bool8 explicitCaptureDamage;
};

struct ExpEventContext
{
u8 _;
u32 exp;
bool8 explicitExp;
s32 *captureGainedExp;
bool8 explicitCaptureGainedExp;
};

struct StatusEventContext
{
u16 status1;
Expand All @@ -891,6 +945,7 @@ void CloseQueueGroup(u32 sourceLine);
void QueueAbility(u32 sourceLine, struct BattlePokemon *battler, struct AbilityEventContext);
void QueueAnimation(u32 sourceLine, u32 type, u32 id, struct AnimationEventContext);
void QueueHP(u32 sourceLine, struct BattlePokemon *battler, struct HPEventContext);
void QueueExp(u32 sourceLine, struct BattlePokemon *battler, struct ExpEventContext);
void QueueMessage(u32 sourceLine, const u8 *pattern);
void QueueStatus(u32 sourceLine, struct BattlePokemon *battler, struct StatusEventContext);

Expand Down
2 changes: 2 additions & 0 deletions include/test_runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern const bool8 gTestRunnerSkipIsFail;
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);
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);
Expand All @@ -23,6 +24,7 @@ u32 TestRunner_Battle_GetForcedAbility(u32 side, u32 partyIndex);
#define TestRunner_Battle_RecordAbilityPopUp(...) (void)0
#define TestRunner_Battle_RecordAnimation(...) (void)0
#define TestRunner_Battle_RecordHP(...) (void)0
#define TestRunner_Battle_RecordExp(...) (void)0
#define TestRunner_Battle_RecordMessage(...) (void)0
#define TestRunner_Battle_RecordStatus1(...) (void)0
#define TestRunner_Battle_AfterLastTurn(...) (void)0
Expand Down
5 changes: 3 additions & 2 deletions src/battle_controller_player.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "sound.h"
#include "string_util.h"
#include "task.h"
#include "test_runner.h"
#include "text.h"
#include "util.h"
#include "window.h"
Expand All @@ -45,7 +46,6 @@ static void PlayerHandleTrainerSlide(u32 battler);
static void PlayerHandleTrainerSlideBack(u32 battler);
static void PlayerHandlePaletteFade(u32 battler);
static void PlayerHandleSuccessBallThrowAnim(u32 battler);
static void PlayerHandleBallThrowAnim(u32 battler);
static void PlayerHandlePause(u32 battler);
static void PlayerHandleMoveAnimation(u32 battler);
static void PlayerHandlePrintString(u32 battler);
Expand Down Expand Up @@ -1452,6 +1452,7 @@ static void Task_PrepareToGiveExpWithExpBar(u8 taskId)
exp -= currLvlExp;
expToNextLvl = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1] - currLvlExp;
SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], expToNextLvl, exp, -gainedExp);
TestRunner_Battle_RecordExp(battler, exp, -gainedExp);
PlaySE(SE_EXP);
gTasks[taskId].func = Task_GiveExpWithExpBar;
}
Expand Down Expand Up @@ -1850,7 +1851,7 @@ static void PlayerHandleSuccessBallThrowAnim(u32 battler)
BtlController_HandleSuccessBallThrowAnim(battler, gBattlerTarget, B_ANIM_BALL_THROW, TRUE);
}

static void PlayerHandleBallThrowAnim(u32 battler)
void PlayerHandleBallThrowAnim(u32 battler)
{
BtlController_HandleBallThrowAnim(battler, gBattlerTarget, B_ANIM_BALL_THROW, TRUE);
}
Expand Down
22 changes: 1 addition & 21 deletions src/battle_controller_recorded_opponent.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,27 +501,7 @@ static void RecordedOpponentHandleChoosePokemon(u32 battler)

static void RecordedOpponentHandleHealthBarUpdate(u32 battler)
{
s16 hpVal;
s32 maxHP, curHP;

LoadBattleBarGfx(0);
hpVal = gBattleResources->bufferA[battler][2] | (gBattleResources->bufferA[battler][3] << 8);

maxHP = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_MAX_HP);
curHP = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_HP);

if (hpVal != INSTANT_HP_BAR_DROP)
{
SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, curHP, hpVal);
TestRunner_Battle_RecordHP(battler, curHP, min(maxHP, max(0, curHP - hpVal)));
}
else
{
SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, 0, hpVal);
TestRunner_Battle_RecordHP(battler, curHP, 0);
}

gBattlerControllerFuncs[battler] = Controller_WaitForHealthBar;
BtlController_HandleHealthBarUpdate(battler, FALSE);
}

static void RecordedOpponentHandleStatusIconUpdate(u32 battler)
Expand Down
27 changes: 3 additions & 24 deletions src/battle_controller_recorded_player.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ static void (*const sRecordedPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 ba
[CONTROLLER_FAINTANIMATION] = BtlController_HandleFaintAnimation,
[CONTROLLER_PALETTEFADE] = BtlController_Empty,
[CONTROLLER_SUCCESSBALLTHROWANIM] = BtlController_Empty,
[CONTROLLER_BALLTHROWANIM] = BtlController_Empty,
[CONTROLLER_BALLTHROWANIM] = PlayerHandleBallThrowAnim,
[CONTROLLER_PAUSE] = BtlController_Empty,
[CONTROLLER_MOVEANIMATION] = RecordedPlayerHandleMoveAnimation,
[CONTROLLER_PRINTSTRING] = RecordedPlayerHandlePrintString,
Expand All @@ -78,7 +78,7 @@ static void (*const sRecordedPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 ba
[CONTROLLER_CHOOSEPOKEMON] = RecordedPlayerHandleChoosePokemon,
[CONTROLLER_23] = BtlController_Empty,
[CONTROLLER_HEALTHBARUPDATE] = RecordedPlayerHandleHealthBarUpdate,
[CONTROLLER_EXPUPDATE] = BtlController_Empty,
[CONTROLLER_EXPUPDATE] = PlayerHandleExpUpdate,
[CONTROLLER_STATUSICONUPDATE] = RecordedPlayerHandleStatusIconUpdate,
[CONTROLLER_STATUSANIMATION] = RecordedPlayerHandleStatusAnimation,
[CONTROLLER_STATUSXOR] = BtlController_Empty,
Expand Down Expand Up @@ -507,28 +507,7 @@ static void RecordedPlayerHandleChoosePokemon(u32 battler)

static void RecordedPlayerHandleHealthBarUpdate(u32 battler)
{
s16 hpVal;
s32 maxHP, curHP;

LoadBattleBarGfx(0);
hpVal = gBattleResources->bufferA[battler][2] | (gBattleResources->bufferA[battler][3] << 8);

maxHP = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_MAX_HP);
curHP = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_HP);

if (hpVal != INSTANT_HP_BAR_DROP)
{
SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, curHP, hpVal);
TestRunner_Battle_RecordHP(battler, curHP, min(maxHP, max(0, curHP - hpVal)));
}
else
{
SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, 0, hpVal);
UpdateHpTextInHealthbox(gHealthboxSpriteIds[battler], HP_CURRENT, 0, maxHP);
TestRunner_Battle_RecordHP(battler, curHP, 0);
}

gBattlerControllerFuncs[battler] = Controller_WaitForHealthBar;
BtlController_HandleHealthBarUpdate(battler, TRUE);
}

static void RecordedPlayerHandleStatusIconUpdate(u32 battler)
Expand Down
11 changes: 6 additions & 5 deletions src/battle_controllers.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "string_util.h"
#include "sound.h"
#include "task.h"
#include "test_runner.h"
#include "util.h"
#include "text.h"
#include "constants/abilities.h"
Expand Down Expand Up @@ -2687,26 +2688,26 @@ void BtlController_HandlePrintString(u32 battler, bool32 updateTvData, bool32 ar

void BtlController_HandleHealthBarUpdate(u32 battler, bool32 updateHpText)
{
s32 maxHP, curHP;
s16 hpVal;
struct Pokemon *party = GetBattlerParty(battler);

LoadBattleBarGfx(0);
hpVal = gBattleResources->bufferA[battler][2] | (gBattleResources->bufferA[battler][3] << 8);
maxHP = GetMonData(&party[gBattlerPartyIndexes[battler]], MON_DATA_MAX_HP);
curHP = GetMonData(&party[gBattlerPartyIndexes[battler]], MON_DATA_HP);

if (hpVal != INSTANT_HP_BAR_DROP)
{
u32 maxHP = GetMonData(&party[gBattlerPartyIndexes[battler]], MON_DATA_MAX_HP);
u32 curHP = GetMonData(&party[gBattlerPartyIndexes[battler]], MON_DATA_HP);

SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, curHP, hpVal);
TestRunner_Battle_RecordHP(battler, curHP, min(maxHP, max(0, curHP - hpVal)));
}
else
{
u32 maxHP = GetMonData(&party[gBattlerPartyIndexes[battler]], MON_DATA_MAX_HP);

SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, 0, hpVal);
if (updateHpText)
UpdateHpTextInHealthbox(gHealthboxSpriteIds[battler], HP_CURRENT, 0, maxHP);
TestRunner_Battle_RecordHP(battler, curHP, 0);
}

gBattlerControllerFuncs[battler] = Controller_WaitForHealthBar;
Expand Down
2 changes: 1 addition & 1 deletion src/battle_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -3865,7 +3865,7 @@ void BattlePutTextOnWindow(const u8 *text, u8 windowId)
else
gTextFlags.useAlternateDownArrow = TRUE;

if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED))
if ((gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED)) || gTestRunnerEnabled)
gTextFlags.autoScroll = TRUE;
else
gTextFlags.autoScroll = FALSE;
Expand Down
Loading

0 comments on commit 2fcb9bb

Please sign in to comment.