From 6b8665d08f357e995939b15cd911e721f21402c9 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada Date: Wed, 1 Jan 2025 06:24:23 -0300 Subject: [PATCH] Speed up tests in headless mode (#5889) --- include/battle_gfx_sfx_util.h | 1 + include/config/battle.h | 3 +- src/battle_controllers.c | 5 ++- src/battle_gfx_sfx_util.c | 12 +++++++ src/battle_intro.c | 56 +++++++++++++++++++++++++++++ src/battle_main.c | 66 +++++++++++++++++++++-------------- src/battle_script_commands.c | 4 +++ src/pokemon.c | 5 +-- src/pokemon_animation.c | 6 +++- test/test_runner.c | 2 +- 10 files changed, 128 insertions(+), 32 deletions(-) diff --git a/include/battle_gfx_sfx_util.h b/include/battle_gfx_sfx_util.h index 968f8d48dccd..dd85b2658c33 100644 --- a/include/battle_gfx_sfx_util.h +++ b/include/battle_gfx_sfx_util.h @@ -6,6 +6,7 @@ void FreeBattleSpritesData(void); u16 ChooseMoveAndTargetInBattlePalace(u32 battler); void SpriteCB_WaitForBattlerBallReleaseAnim(struct Sprite *sprite); void SpriteCB_TrainerSlideIn(struct Sprite *sprite); +void SpriteCB_TrainerSpawn(struct Sprite *sprite); void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 isStatus2, u32 status); bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId, u16 argument); void InitAndLaunchSpecialAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId); diff --git a/include/config/battle.h b/include/config/battle.h index f1ba1944dc62..cdb0caacfee9 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -226,7 +226,8 @@ // Interface settings #define B_ABILITY_POP_UP TRUE // In Gen5+, the Pokémon abilities are displayed in a pop-up, when they activate in battle. -#define B_FAST_INTRO TRUE // If set to TRUE, battle intro texts print at the same time as animation of a Pokémon, as opposing to waiting for the animation to end. +#define B_FAST_INTRO_PKMN_TEXT TRUE // If set to TRUE, battle intro texts print at the same time as animation of a Pokémon, as opposing to waiting for the animation to end. +#define B_FAST_INTRO_NO_SLIDE FALSE // If set to TRUE, the slide animation that happens at the beginning of the battle is skipped. #define B_FAST_HP_DRAIN TRUE // If set to TRUE, HP bars will move faster. #define B_FAST_EXP_GROW TRUE // If set to TRUE, EXP bars will move faster. #define B_SHOW_TARGETS TRUE // If set to TRUE, all available targets, for moves hitting 2 or 3 Pokémon, will be shown before selecting a move. diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 553eb7a85c61..a5581cf7352a 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -2542,7 +2542,10 @@ void BtlController_HandleDrawTrainerPic(u32 battler, u32 trainerPicId, bool32 is gSprites[gBattlerSpriteIds[battler]].x2 = DISPLAY_WIDTH; gSprites[gBattlerSpriteIds[battler]].sSpeedX = -2; } - gSprites[gBattlerSpriteIds[battler]].callback = SpriteCB_TrainerSlideIn; + if (B_FAST_INTRO_NO_SLIDE || gTestRunnerHeadless) + gSprites[gBattlerSpriteIds[battler]].callback = SpriteCB_TrainerSpawn; + else + gSprites[gBattlerSpriteIds[battler]].callback = SpriteCB_TrainerSlideIn; gBattlerControllerFuncs[battler] = Controller_WaitForTrainerPic; } diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index 1f768274aa9b..620ef57d9421 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -435,6 +435,18 @@ void SpriteCB_TrainerSlideIn(struct Sprite *sprite) } } +void SpriteCB_TrainerSpawn(struct Sprite *sprite) +{ + if (!(gIntroSlideFlags & 1)) + { + sprite->x2 = 0; + if (sprite->y2 != 0) + sprite->callback = SpriteCB_TrainerSlideVertical; + else + sprite->callback = SpriteCallbackDummy; + } +} + // Slide up to 0 if necessary (used by multi battle intro) static void SpriteCB_TrainerSlideVertical(struct Sprite *sprite) { diff --git a/src/battle_intro.c b/src/battle_intro.c index a6b1607285b9..b951c163c839 100644 --- a/src/battle_intro.c +++ b/src/battle_intro.c @@ -8,6 +8,7 @@ #include "main.h" #include "scanline_effect.h" #include "task.h" +#include "test_runner.h" #include "trig.h" #include "constants/battle_partner.h" #include "constants/trainers.h" @@ -17,6 +18,7 @@ static void BattleIntroSlide2(u8); static void BattleIntroSlide3(u8); static void BattleIntroSlideLink(u8); static void BattleIntroSlidePartner(u8); +static void BattleIntroNoSlide(u8); static const u8 sBattleAnimBgCnts[] = {REG_OFFSET_BG0CNT, REG_OFFSET_BG1CNT, REG_OFFSET_BG2CNT, REG_OFFSET_BG3CNT}; @@ -149,9 +151,59 @@ static void BattleIntroSlideEnd(u8 taskId) SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR); } +static void BattleIntroNoSlide(u8 taskId) +{ + switch (gTasks[taskId].tState) + { + case 0: + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gTasks[taskId].data[2] = 16; + gTasks[taskId].tState++; + gIntroSlideFlags &= ~1; + } + else + { + gTasks[taskId].data[2] = 1; + gTasks[taskId].tState++; + gIntroSlideFlags &= ~1; + } + break; + case 1: + gTasks[taskId].data[2]--; + if (gTasks[taskId].data[2] == 0) + { + gTasks[taskId].tState++; + SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR); + gScanlineEffect.state = 3; + } + break; + case 2: + gBattle_WIN0V -= 0xFF * 2; + if ((gBattle_WIN0V & 0xFF00) == 0) + { + gTasks[taskId].tState++; + } + break; + case 3: + gTasks[taskId].tState++; + CpuFill32(0, (void *)BG_SCREEN_ADDR(28), BG_SCREEN_SIZE); + SetBgAttribute(1, BG_ATTR_CHARBASEINDEX, 0); + SetBgAttribute(2, BG_ATTR_CHARBASEINDEX, 0); + SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(28) | BGCNT_TXT256x512); + SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(30) | BGCNT_TXT512x256); + break; + case 4: + BattleIntroSlideEnd(taskId); + break; + } +} + static void BattleIntroSlide1(u8 taskId) { int i; + if (B_FAST_INTRO_NO_SLIDE || gTestRunnerHeadless) + return BattleIntroNoSlide(taskId); gBattle_BG1_X += 6; switch (gTasks[taskId].tState) @@ -237,6 +289,8 @@ static void BattleIntroSlide1(u8 taskId) static void BattleIntroSlide2(u8 taskId) { int i; + if (B_FAST_INTRO_NO_SLIDE || gTestRunnerHeadless) + return BattleIntroNoSlide(taskId); switch (gTasks[taskId].tTerrain) { @@ -349,6 +403,8 @@ static void BattleIntroSlide2(u8 taskId) static void BattleIntroSlide3(u8 taskId) { int i; + if (B_FAST_INTRO_NO_SLIDE || gTestRunnerHeadless) + return BattleIntroNoSlide(taskId); gBattle_BG1_X += 8; switch (gTasks[taskId].tState) diff --git a/src/battle_main.c b/src/battle_main.c index 3dad2c67d628..2391b4f370ff 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -487,21 +487,24 @@ static void CB2_InitBattleInternal(void) else { gBattle_WIN0V = WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1); - ScanlineEffect_Clear(); - - for (i = 0; i < DISPLAY_HEIGHT / 2; i++) + if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless) { - gScanlineEffectRegBuffers[0][i] = 0xF0; - gScanlineEffectRegBuffers[1][i] = 0xF0; - } + ScanlineEffect_Clear(); - for (; i < DISPLAY_HEIGHT; i++) - { - gScanlineEffectRegBuffers[0][i] = 0xFF10; - gScanlineEffectRegBuffers[1][i] = 0xFF10; - } + for (i = 0; i < DISPLAY_HEIGHT / 2; i++) + { + gScanlineEffectRegBuffers[0][i] = 0xF0; + gScanlineEffectRegBuffers[1][i] = 0xF0; + } + + for (; i < DISPLAY_HEIGHT; i++) + { + gScanlineEffectRegBuffers[0][i] = 0xFF10; + gScanlineEffectRegBuffers[1][i] = 0xFF10; + } - ScanlineEffect_SetParams(sIntroScanlineParams16Bit); + ScanlineEffect_SetParams(sIntroScanlineParams16Bit); + } } ResetPaletteFade(); @@ -532,7 +535,8 @@ static void CB2_InitBattleInternal(void) LoadBattleTextboxAndBackground(); ResetSpriteData(); ResetTasks(); - DrawBattleEntryBackground(); + if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless) + DrawBattleEntryBackground(); FreeAllSpritePalettes(); gReservedSpritePaletteCount = MAX_BATTLERS_COUNT; SetVBlankCallback(VBlankCB_Battle); @@ -2650,17 +2654,24 @@ void SpriteCB_WildMon(struct Sprite *sprite) { sprite->callback = SpriteCB_MoveWildMonToRight; StartSpriteAnimIfDifferent(sprite, 0); - if (WILD_DOUBLE_BATTLE) - BeginNormalPaletteFade((0x10000 << sprite->sBattler) | (0x10000 << BATTLE_PARTNER(sprite->sBattler)), 0, 10, 10, RGB(8, 8, 8)); - else - BeginNormalPaletteFade((0x10000 << sprite->sBattler), 0, 10, 10, RGB(8, 8, 8)); + if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless) + { + if (WILD_DOUBLE_BATTLE) + BeginNormalPaletteFade((0x10000 << sprite->sBattler) | (0x10000 << BATTLE_PARTNER(sprite->sBattler)), 0, 10, 10, RGB(8, 8, 8)); + else + BeginNormalPaletteFade((0x10000 << sprite->sBattler), 0, 10, 10, RGB(8, 8, 8)); + } } static void SpriteCB_MoveWildMonToRight(struct Sprite *sprite) { if ((gIntroSlideFlags & 1) == 0) { - sprite->x2 += 2; + if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless) + sprite->x2 += 2; + else + sprite->x2 = 0; + if (sprite->x2 == 0) { sprite->callback = SpriteCB_WildMonShowHealthbox; @@ -2676,10 +2687,13 @@ static void SpriteCB_WildMonShowHealthbox(struct Sprite *sprite) SetHealthboxSpriteVisible(gHealthboxSpriteIds[sprite->sBattler]); sprite->callback = SpriteCB_WildMonAnimate; StartSpriteAnimIfDifferent(sprite, 0); - if (WILD_DOUBLE_BATTLE) - BeginNormalPaletteFade((0x10000 << sprite->sBattler) | (0x10000 << BATTLE_PARTNER(sprite->sBattler)), 0, 10, 0, RGB(8, 8, 8)); - else - BeginNormalPaletteFade((0x10000 << sprite->sBattler), 0, 10, 0, RGB(8, 8, 8)); + if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless) + { + if (WILD_DOUBLE_BATTLE) + BeginNormalPaletteFade((0x10000 << sprite->sBattler) | (0x10000 << BATTLE_PARTNER(sprite->sBattler)), 0, 10, 0, RGB(8, 8, 8)); + else + BeginNormalPaletteFade((0x10000 << sprite->sBattler), 0, 10, 0, RGB(8, 8, 8)); + } } } @@ -3561,7 +3575,7 @@ static void DoBattleIntro(void) } else // Skip party summary since it is a wild battle. { - if (B_FAST_INTRO == TRUE) + if (B_FAST_INTRO_PKMN_TEXT == TRUE) gBattleStruct->introState = BATTLE_INTRO_STATE_INTRO_TEXT; // Don't wait for sprite, print message at the same time. else gBattleStruct->introState++; // Wait for sprite to load. @@ -3633,7 +3647,7 @@ static void DoBattleIntro(void) } else { - if (B_FAST_INTRO == TRUE) + if (B_FAST_INTRO_PKMN_TEXT == TRUE) gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; else gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_TRAINER_2_SEND_OUT_ANIM; @@ -3672,7 +3686,7 @@ static void DoBattleIntro(void) BtlController_EmitIntroTrainerBallThrow(battler, BUFFER_A); MarkBattlerForControllerExec(battler); } - if (B_FAST_INTRO == TRUE + if (B_FAST_INTRO_PKMN_TEXT == TRUE && !(gBattleTypeFlags & (BATTLE_TYPE_RECORDED | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_LINK))) gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; // Print at the same time as trainer sends out second mon. else @@ -3695,7 +3709,7 @@ static void DoBattleIntro(void) battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); // A hack that makes fast intro work in trainer battles too. - if (B_FAST_INTRO == TRUE + if (B_FAST_INTRO_PKMN_TEXT == TRUE && gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & (BATTLE_TYPE_RECORDED | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_LINK)) && gSprites[gHealthboxSpriteIds[battler ^ BIT_SIDE]].callback == SpriteCallbackDummy) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 055f9e9c3b2d..3c719049a661 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2773,6 +2773,8 @@ static void Cmd_waitmessage(void) else { u16 toWait = cmd->time; + if (gTestRunnerHeadless) + gPauseCounterBattle = toWait; if (++gPauseCounterBattle >= toWait) { gPauseCounterBattle = 0; @@ -5273,6 +5275,8 @@ static void Cmd_pause(void) if (gBattleControllerExecFlags == 0) { u16 value = cmd->frames; + if (gTestRunnerHeadless) + gPauseCounterBattle = value; if (++gPauseCounterBattle >= value) { gPauseCounterBattle = 0; diff --git a/src/pokemon.c b/src/pokemon.c index c60e95cc6af4..c5162ecfd0bd 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -39,6 +39,7 @@ #include "string_util.h" #include "strings.h" #include "task.h" +#include "test_runner.h" #include "text.h" #include "trainer_hill.h" #include "util.h" @@ -6277,7 +6278,7 @@ void HandleSetPokedexFlag(u16 nationalNum, u8 caseId, u32 personality) bool8 HasTwoFramesAnimation(u16 species) { - return P_TWO_FRAME_FRONT_SPRITES && species != SPECIES_UNOWN; + return P_TWO_FRAME_FRONT_SPRITES && species != SPECIES_UNOWN && !gTestRunnerHeadless; } static bool8 ShouldSkipFriendshipChange(void) @@ -6896,7 +6897,7 @@ void HealBoxPokemon(struct BoxPokemon *boxMon) u16 GetCryIdBySpecies(u16 species) { species = SanitizeSpeciesId(species); - if (P_CRIES_ENABLED == FALSE || gSpeciesInfo[species].cryId >= CRY_COUNT) + if (P_CRIES_ENABLED == FALSE || gSpeciesInfo[species].cryId >= CRY_COUNT || gTestRunnerHeadless) return CRY_NONE; return gSpeciesInfo[species].cryId; } diff --git a/src/pokemon_animation.c b/src/pokemon_animation.c index d7c0bb343c5e..6bd32ee514b8 100644 --- a/src/pokemon_animation.c +++ b/src/pokemon_animation.c @@ -5,6 +5,7 @@ #include "pokemon_animation.h" #include "sprite.h" #include "task.h" +#include "test_runner.h" #include "trig.h" #include "util.h" #include "data.h" @@ -508,7 +509,10 @@ static void Task_HandleMonAnimation(u8 taskId) for (i = 2; i < ARRAY_COUNT(sprite->data); i++) sprite->data[i] = 0; - sprite->callback = sMonAnimFunctions[gTasks[taskId].tAnimId]; + if (gTestRunnerHeadless) + sprite->callback = WaitAnimEnd; + else + sprite->callback = sMonAnimFunctions[gTasks[taskId].tAnimId]; sIsSummaryAnim = FALSE; gTasks[taskId].tState++; diff --git a/test/test_runner.c b/test/test_runner.c index 4715c1918943..7a81d1dc9f68 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -10,7 +10,7 @@ #include "test_runner.h" #include "test/test.h" -#define TIMEOUT_SECONDS 55 +#define TIMEOUT_SECONDS 60 void CB2_TestRunner(void);