Wild battle tests + tests for exp points (#3342)
* Add WIld Battles to test runner + exp tests
This commit is contained in:
parent
baca050724
commit
2fcb9bbc9b
@ -153,6 +153,7 @@ BattleScript_PrintCaughtMonInfo::
|
|||||||
getexp BS_TARGET
|
getexp BS_TARGET
|
||||||
sethword gBattle_BG2_X, 0
|
sethword gBattle_BG2_X, 0
|
||||||
BattleScript_TryPrintCaughtMonInfo:
|
BattleScript_TryPrintCaughtMonInfo:
|
||||||
|
jumpifbattletype BATTLE_TYPE_RECORDED, BattleScript_GiveCaughtMonEnd
|
||||||
trysetcaughtmondexflags BattleScript_TryNicknameCaughtMon
|
trysetcaughtmondexflags BattleScript_TryNicknameCaughtMon
|
||||||
printstring STRINGID_PKMNDATAADDEDTODEX
|
printstring STRINGID_PKMNDATAADDEDTODEX
|
||||||
waitstate
|
waitstate
|
||||||
|
|||||||
@ -304,6 +304,7 @@ void BtlController_HandleBattleAnimation(u32 battler, bool32 ignoreSE, bool32 up
|
|||||||
// player controller
|
// player controller
|
||||||
void SetControllerToPlayer(u32 battler);
|
void SetControllerToPlayer(u32 battler);
|
||||||
void SetBattleEndCallbacks(u32 battler);
|
void SetBattleEndCallbacks(u32 battler);
|
||||||
|
void PlayerHandleBallThrowAnim(u32 battler);
|
||||||
void PlayerHandleExpUpdate(u32 battler);
|
void PlayerHandleExpUpdate(u32 battler);
|
||||||
u32 LinkPlayerGetTrainerPicId(u32 multiplayerId);
|
u32 LinkPlayerGetTrainerPicId(u32 multiplayerId);
|
||||||
void CB2_SetUpReshowBattleScreenAfterMenu(void);
|
void CB2_SetUpReshowBattleScreenAfterMenu(void);
|
||||||
|
|||||||
@ -86,6 +86,7 @@
|
|||||||
| BATTLE_TYPE_GROUDON | BATTLE_TYPE_KYOGRE | BATTLE_TYPE_RAYQUAZA))
|
| 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 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_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)
|
#define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER | BATTLE_TYPE_INGAME_PARTNER)
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,7 @@ u8 RecordedBattle_BufferNewBattlerData(u8 *dst);
|
|||||||
void RecordedBattle_RecordAllBattlerData(u8 *data);
|
void RecordedBattle_RecordAllBattlerData(u8 *data);
|
||||||
bool32 CanCopyRecordedBattleSaveData(void);
|
bool32 CanCopyRecordedBattleSaveData(void);
|
||||||
bool32 MoveRecordedBattleToSaveData(void);
|
bool32 MoveRecordedBattleToSaveData(void);
|
||||||
|
void SetPartiesFromRecordedSave(struct RecordedBattleSave *src);
|
||||||
void SetVariablesForRecordedBattle(struct RecordedBattleSave *);
|
void SetVariablesForRecordedBattle(struct RecordedBattleSave *);
|
||||||
void PlayRecordedBattle(void (*CB2_After)(void));
|
void PlayRecordedBattle(void (*CB2_After)(void));
|
||||||
u8 GetRecordedBattleFrontierFacility(void);
|
u8 GetRecordedBattleFrontierFacility(void);
|
||||||
|
|||||||
@ -359,6 +359,20 @@
|
|||||||
* ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
* ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||||
* target can only be specified for ANIM_TYPE_MOVE.
|
* 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:])
|
* HP_BAR(battler, [damage: | hp: | captureDamage: | captureHP:])
|
||||||
* If hp: or damage: are used, causes the test to fail if that amount of
|
* If hp: or damage: are used, causes the test to fail if that amount of
|
||||||
* damage is not dealt, e.g.:
|
* damage is not dealt, e.g.:
|
||||||
@ -470,7 +484,7 @@
|
|||||||
#define MAX_TURNS 16
|
#define MAX_TURNS 16
|
||||||
#define MAX_QUEUED_EVENTS 25
|
#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 (*SingleBattleTestFunction)(void *, u32, struct BattlePokemon *, struct BattlePokemon *);
|
||||||
typedef void (*DoubleBattleTestFunction)(void *, u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *);
|
typedef void (*DoubleBattleTestFunction)(void *, u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *);
|
||||||
@ -492,6 +506,7 @@ enum
|
|||||||
QUEUED_ABILITY_POPUP_EVENT,
|
QUEUED_ABILITY_POPUP_EVENT,
|
||||||
QUEUED_ANIMATION_EVENT,
|
QUEUED_ANIMATION_EVENT,
|
||||||
QUEUED_HP_EVENT,
|
QUEUED_HP_EVENT,
|
||||||
|
QUEUED_EXP_EVENT,
|
||||||
QUEUED_MESSAGE_EVENT,
|
QUEUED_MESSAGE_EVENT,
|
||||||
QUEUED_STATUS_EVENT,
|
QUEUED_STATUS_EVENT,
|
||||||
};
|
};
|
||||||
@ -511,6 +526,7 @@ struct QueuedAnimationEvent
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum { HP_EVENT_NEW_HP, HP_EVENT_DELTA_HP };
|
enum { HP_EVENT_NEW_HP, HP_EVENT_DELTA_HP };
|
||||||
|
enum { EXP_EVENT_NEW_EXP, EXP_EVENT_DELTA_EXP };
|
||||||
|
|
||||||
struct QueuedHPEvent
|
struct QueuedHPEvent
|
||||||
{
|
{
|
||||||
@ -519,6 +535,13 @@ struct QueuedHPEvent
|
|||||||
u32 address:28;
|
u32 address:28;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct QueuedExpEvent
|
||||||
|
{
|
||||||
|
u32 battlerId:3;
|
||||||
|
u32 type:1;
|
||||||
|
u32 address:28;
|
||||||
|
};
|
||||||
|
|
||||||
struct QueuedMessageEvent
|
struct QueuedMessageEvent
|
||||||
{
|
{
|
||||||
const u8 *pattern;
|
const u8 *pattern;
|
||||||
@ -541,6 +564,7 @@ struct QueuedEvent
|
|||||||
struct QueuedAbilityEvent ability;
|
struct QueuedAbilityEvent ability;
|
||||||
struct QueuedAnimationEvent animation;
|
struct QueuedAnimationEvent animation;
|
||||||
struct QueuedHPEvent hp;
|
struct QueuedHPEvent hp;
|
||||||
|
struct QueuedExpEvent exp;
|
||||||
struct QueuedMessageEvent message;
|
struct QueuedMessageEvent message;
|
||||||
struct QueuedStatusEvent status;
|
struct QueuedStatusEvent status;
|
||||||
} as;
|
} as;
|
||||||
@ -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)
|
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, ...) \
|
#define DOUBLE_BATTLE_TEST(_name, ...) \
|
||||||
struct CAT(Result, __LINE__) { MEMBERS(__VA_ARGS__) }; \
|
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 *); \
|
static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *, u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); \
|
||||||
@ -741,6 +783,7 @@ struct moveWithPP {
|
|||||||
#define MovesWithPP(movewithpp1, ...) MovesWithPP_(__LINE__, (struct moveWithPP[MAX_MON_MOVES]) {movewithpp1, __VA_ARGS__})
|
#define MovesWithPP(movewithpp1, ...) MovesWithPP_(__LINE__, (struct moveWithPP[MAX_MON_MOVES]) {movewithpp1, __VA_ARGS__})
|
||||||
#define Friendship(friendship) Friendship_(__LINE__, friendship)
|
#define Friendship(friendship) Friendship_(__LINE__, friendship)
|
||||||
#define Status1(status1) Status1_(__LINE__, status1)
|
#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 OpenPokemon(u32 sourceLine, u32 side, u32 species);
|
||||||
void ClosePokemon(u32 sourceLine);
|
void ClosePokemon(u32 sourceLine);
|
||||||
@ -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 MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]);
|
||||||
void Friendship_(u32 sourceLine, u32 friendship);
|
void Friendship_(u32 sourceLine, u32 friendship);
|
||||||
void Status1_(u32 sourceLine, u32 status1);
|
void Status1_(u32 sourceLine, u32 status1);
|
||||||
|
void OTName_(u32 sourceLine, const u8 *otName);
|
||||||
|
|
||||||
#define PLAYER_PARTY (gBattleTestRunnerState->data.recordedBattle.playerParty)
|
#define PLAYER_PARTY (gBattleTestRunnerState->data.recordedBattle.playerParty)
|
||||||
#define OPPONENT_PARTY (gBattleTestRunnerState->data.recordedBattle.opponentParty)
|
#define OPPONENT_PARTY (gBattleTestRunnerState->data.recordedBattle.opponentParty)
|
||||||
@ -837,6 +881,7 @@ void SendOut(u32 sourceLine, struct BattlePokemon *, u32 partyIndex);
|
|||||||
#define ABILITY_POPUP(battler, ...) QueueAbility(__LINE__, battler, (struct AbilityEventContext) { __VA_ARGS__ })
|
#define ABILITY_POPUP(battler, ...) QueueAbility(__LINE__, battler, (struct AbilityEventContext) { __VA_ARGS__ })
|
||||||
#define ANIMATION(type, id, ...) QueueAnimation(__LINE__, type, id, (struct AnimationEventContext) { __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 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).
|
// 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 MESSAGE(pattern) do {static const u8 msg[] = _(pattern); QueueMessage(__LINE__, msg);} while (0)
|
||||||
#define STATUS_ICON(battler, status) QueueStatus(__LINE__, battler, (struct StatusEventContext) { status })
|
#define STATUS_ICON(battler, status) QueueStatus(__LINE__, battler, (struct StatusEventContext) { status })
|
||||||
@ -872,6 +917,15 @@ struct HPEventContext
|
|||||||
bool8 explicitCaptureDamage;
|
bool8 explicitCaptureDamage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ExpEventContext
|
||||||
|
{
|
||||||
|
u8 _;
|
||||||
|
u32 exp;
|
||||||
|
bool8 explicitExp;
|
||||||
|
s32 *captureGainedExp;
|
||||||
|
bool8 explicitCaptureGainedExp;
|
||||||
|
};
|
||||||
|
|
||||||
struct StatusEventContext
|
struct StatusEventContext
|
||||||
{
|
{
|
||||||
u16 status1;
|
u16 status1;
|
||||||
@ -891,6 +945,7 @@ void CloseQueueGroup(u32 sourceLine);
|
|||||||
void QueueAbility(u32 sourceLine, struct BattlePokemon *battler, struct AbilityEventContext);
|
void QueueAbility(u32 sourceLine, struct BattlePokemon *battler, struct AbilityEventContext);
|
||||||
void QueueAnimation(u32 sourceLine, u32 type, u32 id, struct AnimationEventContext);
|
void QueueAnimation(u32 sourceLine, u32 type, u32 id, struct AnimationEventContext);
|
||||||
void QueueHP(u32 sourceLine, struct BattlePokemon *battler, struct HPEventContext);
|
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 QueueMessage(u32 sourceLine, const u8 *pattern);
|
||||||
void QueueStatus(u32 sourceLine, struct BattlePokemon *battler, struct StatusEventContext);
|
void QueueStatus(u32 sourceLine, struct BattlePokemon *battler, struct StatusEventContext);
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ extern const bool8 gTestRunnerSkipIsFail;
|
|||||||
void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, u32 ability);
|
void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, u32 ability);
|
||||||
void TestRunner_Battle_RecordAnimation(u32 animType, u32 animId);
|
void TestRunner_Battle_RecordAnimation(u32 animType, u32 animId);
|
||||||
void TestRunner_Battle_RecordHP(u32 battlerId, u32 oldHP, u32 newHP);
|
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_RecordMessage(const u8 *message);
|
||||||
void TestRunner_Battle_RecordStatus1(u32 battlerId, u32 status1);
|
void TestRunner_Battle_RecordStatus1(u32 battlerId, u32 status1);
|
||||||
void TestRunner_Battle_AfterLastTurn(void);
|
void TestRunner_Battle_AfterLastTurn(void);
|
||||||
@ -23,6 +24,7 @@ u32 TestRunner_Battle_GetForcedAbility(u32 side, u32 partyIndex);
|
|||||||
#define TestRunner_Battle_RecordAbilityPopUp(...) (void)0
|
#define TestRunner_Battle_RecordAbilityPopUp(...) (void)0
|
||||||
#define TestRunner_Battle_RecordAnimation(...) (void)0
|
#define TestRunner_Battle_RecordAnimation(...) (void)0
|
||||||
#define TestRunner_Battle_RecordHP(...) (void)0
|
#define TestRunner_Battle_RecordHP(...) (void)0
|
||||||
|
#define TestRunner_Battle_RecordExp(...) (void)0
|
||||||
#define TestRunner_Battle_RecordMessage(...) (void)0
|
#define TestRunner_Battle_RecordMessage(...) (void)0
|
||||||
#define TestRunner_Battle_RecordStatus1(...) (void)0
|
#define TestRunner_Battle_RecordStatus1(...) (void)0
|
||||||
#define TestRunner_Battle_AfterLastTurn(...) (void)0
|
#define TestRunner_Battle_AfterLastTurn(...) (void)0
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "string_util.h"
|
#include "string_util.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
#include "test_runner.h"
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
@ -45,7 +46,6 @@ static void PlayerHandleTrainerSlide(u32 battler);
|
|||||||
static void PlayerHandleTrainerSlideBack(u32 battler);
|
static void PlayerHandleTrainerSlideBack(u32 battler);
|
||||||
static void PlayerHandlePaletteFade(u32 battler);
|
static void PlayerHandlePaletteFade(u32 battler);
|
||||||
static void PlayerHandleSuccessBallThrowAnim(u32 battler);
|
static void PlayerHandleSuccessBallThrowAnim(u32 battler);
|
||||||
static void PlayerHandleBallThrowAnim(u32 battler);
|
|
||||||
static void PlayerHandlePause(u32 battler);
|
static void PlayerHandlePause(u32 battler);
|
||||||
static void PlayerHandleMoveAnimation(u32 battler);
|
static void PlayerHandleMoveAnimation(u32 battler);
|
||||||
static void PlayerHandlePrintString(u32 battler);
|
static void PlayerHandlePrintString(u32 battler);
|
||||||
@ -1452,6 +1452,7 @@ static void Task_PrepareToGiveExpWithExpBar(u8 taskId)
|
|||||||
exp -= currLvlExp;
|
exp -= currLvlExp;
|
||||||
expToNextLvl = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1] - currLvlExp;
|
expToNextLvl = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1] - currLvlExp;
|
||||||
SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], expToNextLvl, exp, -gainedExp);
|
SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], expToNextLvl, exp, -gainedExp);
|
||||||
|
TestRunner_Battle_RecordExp(battler, exp, -gainedExp);
|
||||||
PlaySE(SE_EXP);
|
PlaySE(SE_EXP);
|
||||||
gTasks[taskId].func = Task_GiveExpWithExpBar;
|
gTasks[taskId].func = Task_GiveExpWithExpBar;
|
||||||
}
|
}
|
||||||
@ -1850,7 +1851,7 @@ static void PlayerHandleSuccessBallThrowAnim(u32 battler)
|
|||||||
BtlController_HandleSuccessBallThrowAnim(battler, gBattlerTarget, B_ANIM_BALL_THROW, TRUE);
|
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);
|
BtlController_HandleBallThrowAnim(battler, gBattlerTarget, B_ANIM_BALL_THROW, TRUE);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -501,27 +501,7 @@ static void RecordedOpponentHandleChoosePokemon(u32 battler)
|
|||||||
|
|
||||||
static void RecordedOpponentHandleHealthBarUpdate(u32 battler)
|
static void RecordedOpponentHandleHealthBarUpdate(u32 battler)
|
||||||
{
|
{
|
||||||
s16 hpVal;
|
BtlController_HandleHealthBarUpdate(battler, FALSE);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RecordedOpponentHandleStatusIconUpdate(u32 battler)
|
static void RecordedOpponentHandleStatusIconUpdate(u32 battler)
|
||||||
|
|||||||
@ -66,7 +66,7 @@ static void (*const sRecordedPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 ba
|
|||||||
[CONTROLLER_FAINTANIMATION] = BtlController_HandleFaintAnimation,
|
[CONTROLLER_FAINTANIMATION] = BtlController_HandleFaintAnimation,
|
||||||
[CONTROLLER_PALETTEFADE] = BtlController_Empty,
|
[CONTROLLER_PALETTEFADE] = BtlController_Empty,
|
||||||
[CONTROLLER_SUCCESSBALLTHROWANIM] = BtlController_Empty,
|
[CONTROLLER_SUCCESSBALLTHROWANIM] = BtlController_Empty,
|
||||||
[CONTROLLER_BALLTHROWANIM] = BtlController_Empty,
|
[CONTROLLER_BALLTHROWANIM] = PlayerHandleBallThrowAnim,
|
||||||
[CONTROLLER_PAUSE] = BtlController_Empty,
|
[CONTROLLER_PAUSE] = BtlController_Empty,
|
||||||
[CONTROLLER_MOVEANIMATION] = RecordedPlayerHandleMoveAnimation,
|
[CONTROLLER_MOVEANIMATION] = RecordedPlayerHandleMoveAnimation,
|
||||||
[CONTROLLER_PRINTSTRING] = RecordedPlayerHandlePrintString,
|
[CONTROLLER_PRINTSTRING] = RecordedPlayerHandlePrintString,
|
||||||
@ -78,7 +78,7 @@ static void (*const sRecordedPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 ba
|
|||||||
[CONTROLLER_CHOOSEPOKEMON] = RecordedPlayerHandleChoosePokemon,
|
[CONTROLLER_CHOOSEPOKEMON] = RecordedPlayerHandleChoosePokemon,
|
||||||
[CONTROLLER_23] = BtlController_Empty,
|
[CONTROLLER_23] = BtlController_Empty,
|
||||||
[CONTROLLER_HEALTHBARUPDATE] = RecordedPlayerHandleHealthBarUpdate,
|
[CONTROLLER_HEALTHBARUPDATE] = RecordedPlayerHandleHealthBarUpdate,
|
||||||
[CONTROLLER_EXPUPDATE] = BtlController_Empty,
|
[CONTROLLER_EXPUPDATE] = PlayerHandleExpUpdate,
|
||||||
[CONTROLLER_STATUSICONUPDATE] = RecordedPlayerHandleStatusIconUpdate,
|
[CONTROLLER_STATUSICONUPDATE] = RecordedPlayerHandleStatusIconUpdate,
|
||||||
[CONTROLLER_STATUSANIMATION] = RecordedPlayerHandleStatusAnimation,
|
[CONTROLLER_STATUSANIMATION] = RecordedPlayerHandleStatusAnimation,
|
||||||
[CONTROLLER_STATUSXOR] = BtlController_Empty,
|
[CONTROLLER_STATUSXOR] = BtlController_Empty,
|
||||||
@ -507,28 +507,7 @@ static void RecordedPlayerHandleChoosePokemon(u32 battler)
|
|||||||
|
|
||||||
static void RecordedPlayerHandleHealthBarUpdate(u32 battler)
|
static void RecordedPlayerHandleHealthBarUpdate(u32 battler)
|
||||||
{
|
{
|
||||||
s16 hpVal;
|
BtlController_HandleHealthBarUpdate(battler, TRUE);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RecordedPlayerHandleStatusIconUpdate(u32 battler)
|
static void RecordedPlayerHandleStatusIconUpdate(u32 battler)
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
#include "string_util.h"
|
#include "string_util.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
#include "test_runner.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
#include "constants/abilities.h"
|
#include "constants/abilities.h"
|
||||||
@ -2687,26 +2688,26 @@ void BtlController_HandlePrintString(u32 battler, bool32 updateTvData, bool32 ar
|
|||||||
|
|
||||||
void BtlController_HandleHealthBarUpdate(u32 battler, bool32 updateHpText)
|
void BtlController_HandleHealthBarUpdate(u32 battler, bool32 updateHpText)
|
||||||
{
|
{
|
||||||
|
s32 maxHP, curHP;
|
||||||
s16 hpVal;
|
s16 hpVal;
|
||||||
struct Pokemon *party = GetBattlerParty(battler);
|
struct Pokemon *party = GetBattlerParty(battler);
|
||||||
|
|
||||||
LoadBattleBarGfx(0);
|
LoadBattleBarGfx(0);
|
||||||
hpVal = gBattleResources->bufferA[battler][2] | (gBattleResources->bufferA[battler][3] << 8);
|
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)
|
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);
|
SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, curHP, hpVal);
|
||||||
|
TestRunner_Battle_RecordHP(battler, curHP, min(maxHP, max(0, curHP - hpVal)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 maxHP = GetMonData(&party[gBattlerPartyIndexes[battler]], MON_DATA_MAX_HP);
|
|
||||||
|
|
||||||
SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, 0, hpVal);
|
SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, 0, hpVal);
|
||||||
if (updateHpText)
|
if (updateHpText)
|
||||||
UpdateHpTextInHealthbox(gHealthboxSpriteIds[battler], HP_CURRENT, 0, maxHP);
|
UpdateHpTextInHealthbox(gHealthboxSpriteIds[battler], HP_CURRENT, 0, maxHP);
|
||||||
|
TestRunner_Battle_RecordHP(battler, curHP, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
gBattlerControllerFuncs[battler] = Controller_WaitForHealthBar;
|
gBattlerControllerFuncs[battler] = Controller_WaitForHealthBar;
|
||||||
|
|||||||
@ -3865,7 +3865,7 @@ void BattlePutTextOnWindow(const u8 *text, u8 windowId)
|
|||||||
else
|
else
|
||||||
gTextFlags.useAlternateDownArrow = TRUE;
|
gTextFlags.useAlternateDownArrow = TRUE;
|
||||||
|
|
||||||
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED))
|
if ((gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED)) || gTestRunnerEnabled)
|
||||||
gTextFlags.autoScroll = TRUE;
|
gTextFlags.autoScroll = TRUE;
|
||||||
else
|
else
|
||||||
gTextFlags.autoScroll = FALSE;
|
gTextFlags.autoScroll = FALSE;
|
||||||
|
|||||||
@ -4030,6 +4030,23 @@ static void Cmd_jumpbasedontype(void)
|
|||||||
|
|
||||||
FEATURE_FLAG_ASSERT(I_EXP_SHARE_FLAG, YouNeedToSetTheExpShareFlagToAnUnusedFlag);
|
FEATURE_FLAG_ASSERT(I_EXP_SHARE_FLAG, YouNeedToSetTheExpShareFlagToAnUnusedFlag);
|
||||||
|
|
||||||
|
static bool32 BattleTypeAllowsExp(void)
|
||||||
|
{
|
||||||
|
if (RECORDED_WILD_BATTLE)
|
||||||
|
return TRUE;
|
||||||
|
else if (gBattleTypeFlags &
|
||||||
|
( BATTLE_TYPE_LINK
|
||||||
|
| BATTLE_TYPE_RECORDED_LINK
|
||||||
|
| BATTLE_TYPE_TRAINER_HILL
|
||||||
|
| BATTLE_TYPE_FRONTIER
|
||||||
|
| BATTLE_TYPE_SAFARI
|
||||||
|
| BATTLE_TYPE_BATTLE_TOWER
|
||||||
|
| BATTLE_TYPE_EREADER_TRAINER))
|
||||||
|
return FALSE;
|
||||||
|
else
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static u32 GetMonHoldEffect(struct Pokemon *mon)
|
static u32 GetMonHoldEffect(struct Pokemon *mon)
|
||||||
{
|
{
|
||||||
u32 holdEffect;
|
u32 holdEffect;
|
||||||
@ -4058,14 +4075,7 @@ static void Cmd_getexp(void)
|
|||||||
case 0: // check if should receive exp at all
|
case 0: // check if should receive exp at all
|
||||||
if (GetBattlerSide(gBattlerFainted) != B_SIDE_OPPONENT
|
if (GetBattlerSide(gBattlerFainted) != B_SIDE_OPPONENT
|
||||||
|| IsAiVsAiBattle()
|
|| IsAiVsAiBattle()
|
||||||
|| (gBattleTypeFlags &
|
|| !BattleTypeAllowsExp())
|
||||||
(BATTLE_TYPE_LINK
|
|
||||||
| BATTLE_TYPE_RECORDED_LINK
|
|
||||||
| BATTLE_TYPE_TRAINER_HILL
|
|
||||||
| BATTLE_TYPE_FRONTIER
|
|
||||||
| BATTLE_TYPE_SAFARI
|
|
||||||
| BATTLE_TYPE_BATTLE_TOWER
|
|
||||||
| BATTLE_TYPE_EREADER_TRAINER)))
|
|
||||||
{
|
{
|
||||||
gBattleScripting.getexpState = 6; // goto last case
|
gBattleScripting.getexpState = 6; // goto last case
|
||||||
}
|
}
|
||||||
@ -7086,7 +7096,7 @@ static void Cmd_handlelearnnewmove(void)
|
|||||||
while (learnMove == MON_ALREADY_KNOWS_MOVE)
|
while (learnMove == MON_ALREADY_KNOWS_MOVE)
|
||||||
learnMove = MonTryLearningNewMove(&gPlayerParty[monId], FALSE);
|
learnMove = MonTryLearningNewMove(&gPlayerParty[monId], FALSE);
|
||||||
|
|
||||||
if (learnMove == MOVE_NONE)
|
if (learnMove == MOVE_NONE || RECORDED_WILD_BATTLE)
|
||||||
{
|
{
|
||||||
gBattlescriptCurrInstr = cmd->nothingToLearnPtr;
|
gBattlescriptCurrInstr = cmd->nothingToLearnPtr;
|
||||||
}
|
}
|
||||||
@ -7777,7 +7787,7 @@ static void Cmd_drawlvlupbox(void)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
if (gMain.newKeys != 0)
|
if (gMain.newKeys != 0 || RECORDED_WILD_BATTLE)
|
||||||
{
|
{
|
||||||
// Draw page 2 of level up box
|
// Draw page 2 of level up box
|
||||||
PlaySE(SE_SELECT);
|
PlaySE(SE_SELECT);
|
||||||
@ -7787,7 +7797,7 @@ static void Cmd_drawlvlupbox(void)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
if (gMain.newKeys != 0)
|
if (gMain.newKeys != 0 || RECORDED_WILD_BATTLE)
|
||||||
{
|
{
|
||||||
// Close level up box
|
// Close level up box
|
||||||
PlaySE(SE_SELECT);
|
PlaySE(SE_SELECT);
|
||||||
@ -15264,7 +15274,7 @@ static void Cmd_trysetcaughtmondexflags(void)
|
|||||||
{
|
{
|
||||||
CMD_ARGS(const u8 *failInstr);
|
CMD_ARGS(const u8 *failInstr);
|
||||||
|
|
||||||
u16 species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_SPECIES, NULL);
|
u32 species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_SPECIES, NULL);
|
||||||
u32 personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_PERSONALITY, NULL);
|
u32 personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_PERSONALITY, NULL);
|
||||||
|
|
||||||
if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT))
|
if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT))
|
||||||
|
|||||||
@ -493,20 +493,25 @@ static void Task_StartAfterCountdown(u8 taskId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetVariablesForRecordedBattle(struct RecordedBattleSave *src)
|
void SetPartiesFromRecordedSave(struct RecordedBattleSave *src)
|
||||||
{
|
{
|
||||||
bool8 var;
|
s32 i;
|
||||||
s32 i, j;
|
|
||||||
|
|
||||||
ZeroPlayerPartyMons();
|
ZeroPlayerPartyMons();
|
||||||
ZeroEnemyPartyMons();
|
ZeroEnemyPartyMons();
|
||||||
|
|
||||||
for (i = 0; i < PARTY_SIZE; i++)
|
for (i = 0; i < PARTY_SIZE; i++)
|
||||||
{
|
{
|
||||||
gPlayerParty[i] = src->playerParty[i];
|
gPlayerParty[i] = src->playerParty[i];
|
||||||
gEnemyParty[i] = src->opponentParty[i];
|
gEnemyParty[i] = src->opponentParty[i];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetVariablesForRecordedBattle(struct RecordedBattleSave *src)
|
||||||
|
{
|
||||||
|
bool8 var;
|
||||||
|
s32 i, j;
|
||||||
|
|
||||||
|
SetPartiesFromRecordedSave(src);
|
||||||
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
||||||
{
|
{
|
||||||
for (var = FALSE, j = 0; j < PLAYER_NAME_LENGTH + 1; j++)
|
for (var = FALSE, j = 0; j < PLAYER_NAME_LENGTH + 1; j++)
|
||||||
|
|||||||
150
test/battle/exp.c
Normal file
150
test/battle/exp.c
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
#include "global.h"
|
||||||
|
#include "test/battle.h"
|
||||||
|
|
||||||
|
#if B_EXP_CATCH >= GEN_6
|
||||||
|
|
||||||
|
WILD_BATTLE_TEST("Pokemon gain exp after catching a Pokemon")
|
||||||
|
{
|
||||||
|
u8 level = 0;
|
||||||
|
|
||||||
|
PARAMETRIZE { level = 50; }
|
||||||
|
PARAMETRIZE { level = MAX_LEVEL; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) { Level(level); }
|
||||||
|
OPPONENT(SPECIES_CATERPIE) { HP(1); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { USE_ITEM(player, ITEM_ULTRA_BALL); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("You used Ultra Ball!");
|
||||||
|
ANIMATION(ANIM_TYPE_SPECIAL, B_ANIM_BALL_THROW, player);
|
||||||
|
if (level != MAX_LEVEL) {
|
||||||
|
EXPERIENCE_BAR(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // B_EXP_CATCH
|
||||||
|
|
||||||
|
WILD_BATTLE_TEST("Higher leveled Pokemon give more exp", u32 exp)
|
||||||
|
{
|
||||||
|
u8 level = 0;
|
||||||
|
|
||||||
|
PARAMETRIZE { level = 5; }
|
||||||
|
PARAMETRIZE { level = 10; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) { Level(20); }
|
||||||
|
OPPONENT(SPECIES_CATERPIE) { Level(level); HP(1); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_TACKLE); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Tackle!");
|
||||||
|
MESSAGE("Wild Caterpie fainted!");
|
||||||
|
EXPERIENCE_BAR(player, captureGainedExp: &results[i].exp);
|
||||||
|
} FINALLY {
|
||||||
|
EXPECT_GT(results[1].exp, results[0].exp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WILD_BATTLE_TEST("Lucky Egg boosts gained exp points by 50%", u32 exp)
|
||||||
|
{
|
||||||
|
u32 item = 0;
|
||||||
|
|
||||||
|
PARAMETRIZE { item = ITEM_LUCKY_EGG; }
|
||||||
|
PARAMETRIZE { item = ITEM_NONE; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) { Level(20); Item(item); }
|
||||||
|
OPPONENT(SPECIES_CATERPIE) { Level(10); HP(1); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_TACKLE); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Tackle!");
|
||||||
|
MESSAGE("Wild Caterpie fainted!");
|
||||||
|
EXPERIENCE_BAR(player, captureGainedExp: &results[i].exp);
|
||||||
|
} FINALLY {
|
||||||
|
EXPECT_MUL_EQ(results[1].exp, Q_4_12(1.5), results[0].exp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (B_SCALED_EXP == GEN_5 || B_SCALED_EXP >= GEN_7)
|
||||||
|
|
||||||
|
WILD_BATTLE_TEST("Exp is scaled to player and opponent's levels", u32 exp)
|
||||||
|
{
|
||||||
|
u8 level = 0;
|
||||||
|
|
||||||
|
PARAMETRIZE { level = 5; }
|
||||||
|
PARAMETRIZE { level = 10; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) { Level(level); }
|
||||||
|
OPPONENT(SPECIES_CATERPIE) { Level(5); HP(1); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_TACKLE); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Tackle!");
|
||||||
|
MESSAGE("Wild Caterpie fainted!");
|
||||||
|
EXPERIENCE_BAR(player, captureGainedExp: &results[i].exp);
|
||||||
|
} FINALLY {
|
||||||
|
EXPECT_GT(results[0].exp, results[1].exp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WILD_BATTLE_TEST("Large exp gains are supported", u32 exp) // #1455
|
||||||
|
{
|
||||||
|
u8 level = 0;
|
||||||
|
|
||||||
|
PARAMETRIZE { level = 10; }
|
||||||
|
PARAMETRIZE { level = 50; }
|
||||||
|
PARAMETRIZE { level = MAX_LEVEL; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) { Level(1); Item(ITEM_LUCKY_EGG); OTName("Test"); } // OT Name is different so it gets more exp as a traded mon
|
||||||
|
OPPONENT(SPECIES_BLISSEY) { Level(level); HP(1); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_TACKLE); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Tackle!");
|
||||||
|
MESSAGE("Wild Blissey fainted!");
|
||||||
|
EXPERIENCE_BAR(player, captureGainedExp: &results[i].exp);
|
||||||
|
} THEN {
|
||||||
|
EXPECT(GetMonData(&gPlayerParty[0], MON_DATA_LEVEL) > 1);
|
||||||
|
EXPECT(GetMonData(&gPlayerParty[0], MON_DATA_EXP) > 1);
|
||||||
|
} FINALLY {
|
||||||
|
EXPECT_GT(results[1].exp, results[0].exp);
|
||||||
|
EXPECT_GT(results[2].exp, results[1].exp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if I_EXP_SHARE_ITEM < GEN_6
|
||||||
|
|
||||||
|
WILD_BATTLE_TEST("Exp Share(held) gives Experience to mons which did not participate in battle")
|
||||||
|
{
|
||||||
|
u32 item = 0;
|
||||||
|
|
||||||
|
PARAMETRIZE { item = ITEM_NONE; }
|
||||||
|
PARAMETRIZE { item = ITEM_EXP_SHARE; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
PLAYER(SPECIES_WYNAUT) { Level(40); Item(item); }
|
||||||
|
OPPONENT(SPECIES_CATERPIE) { Level(10); HP(1); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_TACKLE); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Tackle!");
|
||||||
|
MESSAGE("Wild Caterpie fainted!");
|
||||||
|
// This message should appear only for gen6> exp share.
|
||||||
|
NOT MESSAGE("The rest of your team gained EXP. Points thanks to the Exp. Share!");
|
||||||
|
} THEN {
|
||||||
|
if (item == ITEM_EXP_SHARE)
|
||||||
|
EXPECT_GT(GetMonData(&gPlayerParty[1], MON_DATA_EXP), gExperienceTables[gSpeciesInfo[SPECIES_WYNAUT].growthRate][40]);
|
||||||
|
else
|
||||||
|
EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_EXP), gExperienceTables[gSpeciesInfo[SPECIES_WYNAUT].growthRate][40]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // I_EXP_SHARE_ITEM
|
||||||
@ -95,6 +95,7 @@ static void InvokeTestFunction(const struct BattleTest *test)
|
|||||||
switch (test->type)
|
switch (test->type)
|
||||||
{
|
{
|
||||||
case BATTLE_TEST_SINGLES:
|
case BATTLE_TEST_SINGLES:
|
||||||
|
case BATTLE_TEST_WILD:
|
||||||
InvokeSingleTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], test->function.singles, &DATA.stack[BATTLE_TEST_STACK_SIZE]);
|
InvokeSingleTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], test->function.singles, &DATA.stack[BATTLE_TEST_STACK_SIZE]);
|
||||||
break;
|
break;
|
||||||
case BATTLE_TEST_DOUBLES:
|
case BATTLE_TEST_DOUBLES:
|
||||||
@ -236,7 +237,10 @@ static void BattleTest_Run(void *data)
|
|||||||
DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT;
|
DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT;
|
||||||
|
|
||||||
DATA.recordedBattle.textSpeed = OPTIONS_TEXT_SPEED_FAST;
|
DATA.recordedBattle.textSpeed = OPTIONS_TEXT_SPEED_FAST;
|
||||||
DATA.recordedBattle.battleFlags = BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_IS_MASTER;
|
if (test->type == BATTLE_TEST_WILD)
|
||||||
|
DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER;
|
||||||
|
else
|
||||||
|
DATA.recordedBattle.battleFlags = BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_IS_MASTER;
|
||||||
if (test->type == BATTLE_TEST_DOUBLES)
|
if (test->type == BATTLE_TEST_DOUBLES)
|
||||||
{
|
{
|
||||||
DATA.recordedBattle.battleFlags |= BATTLE_TYPE_DOUBLE;
|
DATA.recordedBattle.battleFlags |= BATTLE_TYPE_DOUBLE;
|
||||||
@ -293,7 +297,6 @@ static void BattleTest_Run(void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetVariablesForRecordedBattle(&DATA.recordedBattle);
|
SetVariablesForRecordedBattle(&DATA.recordedBattle);
|
||||||
|
|
||||||
if (STATE->trials)
|
if (STATE->trials)
|
||||||
gMain.savedCallback = CB2_BattleTest_NextTrial;
|
gMain.savedCallback = CB2_BattleTest_NextTrial;
|
||||||
else if (STATE->parameters)
|
else if (STATE->parameters)
|
||||||
@ -708,6 +711,96 @@ void TestRunner_Battle_RecordHP(u32 battlerId, u32 oldHP, u32 newHP)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static s32 TryExp(s32 i, s32 n, u32 battlerId, u32 oldExp, u32 newExp)
|
||||||
|
{
|
||||||
|
struct QueuedExpEvent *event;
|
||||||
|
s32 iMax = i + n;
|
||||||
|
for (; i < iMax; i++)
|
||||||
|
{
|
||||||
|
if (DATA.queuedEvents[i].type != QUEUED_EXP_EVENT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
event = &DATA.queuedEvents[i].as.exp;
|
||||||
|
|
||||||
|
if (event->battlerId == battlerId)
|
||||||
|
{
|
||||||
|
if (event->address <= 0xFFFF)
|
||||||
|
{
|
||||||
|
switch (event->type)
|
||||||
|
{
|
||||||
|
case EXP_EVENT_NEW_EXP:
|
||||||
|
if (event->address == newExp)
|
||||||
|
return i;
|
||||||
|
break;
|
||||||
|
case EXP_EVENT_DELTA_EXP:
|
||||||
|
if (event->address == 0)
|
||||||
|
return i;
|
||||||
|
else if ((s16)event->address == oldExp - newExp)
|
||||||
|
return i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (event->type)
|
||||||
|
{
|
||||||
|
case EXP_EVENT_NEW_EXP:
|
||||||
|
*(u32 *)event->address = newExp;
|
||||||
|
break;
|
||||||
|
case EXP_EVENT_DELTA_EXP:
|
||||||
|
*(s32 *)event->address = oldExp - newExp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestRunner_Battle_RecordExp(u32 battlerId, u32 oldExp, u32 newExp)
|
||||||
|
{
|
||||||
|
s32 queuedEvent;
|
||||||
|
s32 match;
|
||||||
|
struct QueuedEvent *event;
|
||||||
|
|
||||||
|
if (DATA.queuedEvent == DATA.queuedEventsCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
event = &DATA.queuedEvents[DATA.queuedEvent];
|
||||||
|
switch (event->groupType)
|
||||||
|
{
|
||||||
|
case QUEUE_GROUP_NONE:
|
||||||
|
case QUEUE_GROUP_ONE_OF:
|
||||||
|
if (TryExp(DATA.queuedEvent, event->groupSize, battlerId, oldExp, newExp) != -1)
|
||||||
|
DATA.queuedEvent += event->groupSize;
|
||||||
|
break;
|
||||||
|
case QUEUE_GROUP_NONE_OF:
|
||||||
|
queuedEvent = DATA.queuedEvent;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if ((match = TryExp(queuedEvent, event->groupSize, battlerId, oldExp, newExp)) != -1)
|
||||||
|
{
|
||||||
|
const char *filename = gTestRunnerState.test->filename;
|
||||||
|
u32 line = SourceLine(DATA.queuedEvents[match].sourceLineOffset);
|
||||||
|
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: Matched EXPERIENCE_BAR", filename, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
queuedEvent += event->groupSize;
|
||||||
|
if (queuedEvent == DATA.queuedEventsCount)
|
||||||
|
break;
|
||||||
|
|
||||||
|
event = &DATA.queuedEvents[queuedEvent];
|
||||||
|
if (event->groupType == QUEUE_GROUP_NONE_OF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryExp(queuedEvent, event->groupSize, battlerId, oldExp, newExp) != -1)
|
||||||
|
DATA.queuedEvent = queuedEvent + event->groupSize;
|
||||||
|
} while (FALSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static s32 TryMessage(s32 i, s32 n, const u8 *string)
|
static s32 TryMessage(s32 i, s32 n, const u8 *string)
|
||||||
{
|
{
|
||||||
s32 j, k;
|
s32 j, k;
|
||||||
@ -866,6 +959,7 @@ static const char *const sEventTypeMacros[] =
|
|||||||
[QUEUED_ABILITY_POPUP_EVENT] = "ABILITY_POPUP",
|
[QUEUED_ABILITY_POPUP_EVENT] = "ABILITY_POPUP",
|
||||||
[QUEUED_ANIMATION_EVENT] = "ANIMATION",
|
[QUEUED_ANIMATION_EVENT] = "ANIMATION",
|
||||||
[QUEUED_HP_EVENT] = "HP_BAR",
|
[QUEUED_HP_EVENT] = "HP_BAR",
|
||||||
|
[QUEUED_EXP_EVENT] = "EXPERIENCE_BAR",
|
||||||
[QUEUED_MESSAGE_EVENT] = "MESSAGE",
|
[QUEUED_MESSAGE_EVENT] = "MESSAGE",
|
||||||
[QUEUED_STATUS_EVENT] = "STATUS_ICON",
|
[QUEUED_STATUS_EVENT] = "STATUS_ICON",
|
||||||
};
|
};
|
||||||
@ -1276,6 +1370,12 @@ void Status1_(u32 sourceLine, u32 status1)
|
|||||||
SetMonData(DATA.currentMon, MON_DATA_STATUS, &status1);
|
SetMonData(DATA.currentMon, MON_DATA_STATUS, &status1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OTName_(u32 sourceLine, const u8 *otName)
|
||||||
|
{
|
||||||
|
INVALID_IF(!DATA.currentMon, "Traded outside of PLAYER/OPPONENT");
|
||||||
|
SetMonData(DATA.currentMon, MON_DATA_OT_NAME, &otName);
|
||||||
|
}
|
||||||
|
|
||||||
static const char *const sBattlerIdentifiersSingles[] =
|
static const char *const sBattlerIdentifiersSingles[] =
|
||||||
{
|
{
|
||||||
"player",
|
"player",
|
||||||
@ -1784,6 +1884,48 @@ void QueueHP(u32 sourceLine, struct BattlePokemon *battler, struct HPEventContex
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QueueExp(u32 sourceLine, struct BattlePokemon *battler, struct ExpEventContext ctx)
|
||||||
|
{
|
||||||
|
s32 battlerId = battler - gBattleMons;
|
||||||
|
u32 type;
|
||||||
|
uintptr_t address;
|
||||||
|
|
||||||
|
INVALID_IF(!STATE->runScene, "EXPERIENCE_BAR outside of SCENE");
|
||||||
|
if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS)
|
||||||
|
Test_ExitWithResult(TEST_RESULT_ERROR, "%s:%d: EXPERIENCE_BAR exceeds MAX_QUEUED_EVENTS", gTestRunnerState.test->filename, sourceLine);
|
||||||
|
|
||||||
|
if (ctx.explicitExp)
|
||||||
|
{
|
||||||
|
type = EXP_EVENT_NEW_EXP;
|
||||||
|
address = (u32)ctx.exp;
|
||||||
|
}
|
||||||
|
else if (ctx.explicitCaptureGainedExp)
|
||||||
|
{
|
||||||
|
INVALID_IF(ctx.captureGainedExp == NULL, "captureGainedExp is NULL");
|
||||||
|
type = EXP_EVENT_DELTA_EXP;
|
||||||
|
*ctx.captureGainedExp = 0;
|
||||||
|
address = (uintptr_t)ctx.captureGainedExp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = EXP_EVENT_DELTA_EXP;
|
||||||
|
address = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DATA.queuedEvents[DATA.queuedEventsCount++] = (struct QueuedEvent) {
|
||||||
|
.type = QUEUED_EXP_EVENT,
|
||||||
|
.sourceLineOffset = SourceLineOffset(sourceLine),
|
||||||
|
.groupType = QUEUE_GROUP_NONE,
|
||||||
|
.groupSize = 1,
|
||||||
|
.as = { .exp = {
|
||||||
|
.battlerId = battlerId,
|
||||||
|
.type = type,
|
||||||
|
.address = address,
|
||||||
|
}},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void QueueMessage(u32 sourceLine, const u8 *pattern)
|
void QueueMessage(u32 sourceLine, const u8 *pattern)
|
||||||
{
|
{
|
||||||
INVALID_IF(!STATE->runScene, "MESSAGE outside of SCENE");
|
INVALID_IF(!STATE->runScene, "MESSAGE outside of SCENE");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user