diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index f533853142..5c6a33f073 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1726,6 +1726,11 @@ .4byte \failInstr .endm + .macro tryhitswitchtarget failInstr:req + callnative BS_TryHitSwitchTarget + .4byte \failInstr + .endm + .macro jumpifcommanderactive jumpInstr:req callnative BS_JumpIfCommanderActive .4byte \jumpInstr @@ -1965,11 +1970,6 @@ various BS_ATTACKER, VARIOUS_SET_ARG_TO_BATTLE_DAMAGE .endm - .macro tryhitswitchtarget failInstr:req - various BS_ATTACKER, VARIOUS_TRY_HIT_SWITCH_TARGET - .4byte \failInstr - .endm - .macro tryautotomize battler:req, failInstr:req various \battler, VARIOUS_TRY_AUTOTOMIZE .4byte \failInstr diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 3476dc5ef2..29878dcdd2 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -138,94 +138,93 @@ #define VARIOUS_HANDLE_MEGA_EVO 46 #define VARIOUS_TRY_LAST_RESORT 47 #define VARIOUS_SET_ARG_TO_BATTLE_DAMAGE 48 -#define VARIOUS_TRY_HIT_SWITCH_TARGET 49 -#define VARIOUS_TRY_AUTOTOMIZE 50 -#define VARIOUS_ABILITY_POPUP 51 -#define VARIOUS_JUMP_IF_TARGET_ALLY 52 -#define VARIOUS_TRY_SYNCHRONOISE 53 -#define VARIOUS_PSYCHO_SHIFT 54 -#define VARIOUS_CURE_STATUS 55 -#define VARIOUS_POWER_TRICK 56 -#define VARIOUS_AFTER_YOU 57 -#define VARIOUS_BESTOW 58 -#define VARIOUS_JUMP_IF_NOT_GROUNDED 59 -#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 60 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 61 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 62 -#define VARIOUS_SET_AURORA_VEIL 63 -#define VARIOUS_TRY_THIRD_TYPE 64 -#define VARIOUS_ACUPRESSURE 65 -#define VARIOUS_SET_POWDER 66 -#define VARIOUS_SPECTRAL_THIEF 67 -#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 68 -#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 69 -#define VARIOUS_JUMP_IF_ROAR_FAILS 70 -#define VARIOUS_TRY_INSTRUCT 71 -#define VARIOUS_JUMP_IF_NOT_BERRY 72 -#define VARIOUS_TRACE_ABILITY 73 -#define VARIOUS_UPDATE_NICK 74 -#define VARIOUS_TRY_ILLUSION_OFF 75 -#define VARIOUS_SET_SPRITEIGNORE0HP 76 -#define VARIOUS_HANDLE_FORM_CHANGE 77 -#define VARIOUS_GET_STAT_VALUE 78 -#define VARIOUS_JUMP_IF_FULL_HP 79 -#define VARIOUS_LOSE_TYPE 80 -#define VARIOUS_TRY_ACTIVATE_SOULHEART 81 -#define VARIOUS_TRY_ACTIVATE_RECEIVER 82 -#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 83 -#define VARIOUS_TRY_FRISK 84 -#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 85 -#define VARIOUS_TRY_FAIRY_LOCK 86 -#define VARIOUS_JUMP_IF_NO_ALLY 87 -#define VARIOUS_POISON_TYPE_IMMUNITY 88 -#define VARIOUS_JUMP_IF_HOLD_EFFECT 89 -#define VARIOUS_INFATUATE_WITH_BATTLER 90 -#define VARIOUS_SET_LAST_USED_ITEM 91 -#define VARIOUS_PARALYZE_TYPE_IMMUNITY 92 -#define VARIOUS_JUMP_IF_ABSENT 93 -#define VARIOUS_DESTROY_ABILITY_POPUP 94 -#define VARIOUS_TOTEM_BOOST 95 -#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 96 -#define VARIOUS_MOVEEND_ITEM_EFFECTS 97 -#define VARIOUS_TERRAIN_SEED 98 -#define VARIOUS_MAKE_INVISIBLE 99 -#define VARIOUS_ROOM_SERVICE 100 -#define VARIOUS_EERIE_SPELL_PP_REDUCE 101 -#define VARIOUS_JUMP_IF_TEAM_HEALTHY 102 -#define VARIOUS_TRY_HEAL_QUARTER_HP 103 -#define VARIOUS_REMOVE_TERRAIN 104 -#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 105 -#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 106 -#define VARIOUS_GET_ROTOTILLER_TARGETS 107 -#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 108 -#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 109 -#define VARIOUS_CONSUME_BERRY 110 -#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 111 -#define VARIOUS_JUMP_IF_SPECIES 112 -#define VARIOUS_UPDATE_ABILITY_POPUP 113 -#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 114 -#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 115 -#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 116 -#define VARIOUS_TRY_NO_RETREAT 117 -#define VARIOUS_TRY_TAR_SHOT 118 -#define VARIOUS_CAN_TAR_SHOT_WORK 119 -#define VARIOUS_CHECK_POLTERGEIST 120 -#define VARIOUS_CUT_1_3_HP_RAISE_STATS 121 -#define VARIOUS_TRY_END_NEUTRALIZING_GAS 122 -#define VARIOUS_JUMP_IF_UNDER_200 123 -#define VARIOUS_SET_SKY_DROP 124 -#define VARIOUS_CLEAR_SKY_DROP 125 -#define VARIOUS_SKY_DROP_YAWN 126 -#define VARIOUS_CURE_CERTAIN_STATUSES 127 -#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 128 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 129 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 130 -#define VARIOUS_SAVE_BATTLER_ITEM 131 -#define VARIOUS_RESTORE_BATTLER_ITEM 132 -#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 133 -#define VARIOUS_SET_BEAK_BLAST 134 -#define VARIOUS_SWAP_SIDE_STATUSES 135 -#define VARIOUS_SWAP_STATS 136 +#define VARIOUS_TRY_AUTOTOMIZE 49 +#define VARIOUS_ABILITY_POPUP 50 +#define VARIOUS_JUMP_IF_TARGET_ALLY 51 +#define VARIOUS_TRY_SYNCHRONOISE 52 +#define VARIOUS_PSYCHO_SHIFT 53 +#define VARIOUS_CURE_STATUS 54 +#define VARIOUS_POWER_TRICK 55 +#define VARIOUS_AFTER_YOU 56 +#define VARIOUS_BESTOW 57 +#define VARIOUS_JUMP_IF_NOT_GROUNDED 58 +#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 59 +#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 60 +#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 61 +#define VARIOUS_SET_AURORA_VEIL 62 +#define VARIOUS_TRY_THIRD_TYPE 63 +#define VARIOUS_ACUPRESSURE 64 +#define VARIOUS_SET_POWDER 65 +#define VARIOUS_SPECTRAL_THIEF 66 +#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 67 +#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 68 +#define VARIOUS_JUMP_IF_ROAR_FAILS 69 +#define VARIOUS_TRY_INSTRUCT 70 +#define VARIOUS_JUMP_IF_NOT_BERRY 71 +#define VARIOUS_TRACE_ABILITY 72 +#define VARIOUS_UPDATE_NICK 73 +#define VARIOUS_TRY_ILLUSION_OFF 74 +#define VARIOUS_SET_SPRITEIGNORE0HP 75 +#define VARIOUS_HANDLE_FORM_CHANGE 76 +#define VARIOUS_GET_STAT_VALUE 77 +#define VARIOUS_JUMP_IF_FULL_HP 78 +#define VARIOUS_LOSE_TYPE 79 +#define VARIOUS_TRY_ACTIVATE_SOULHEART 80 +#define VARIOUS_TRY_ACTIVATE_RECEIVER 81 +#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 82 +#define VARIOUS_TRY_FRISK 83 +#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 84 +#define VARIOUS_TRY_FAIRY_LOCK 85 +#define VARIOUS_JUMP_IF_NO_ALLY 86 +#define VARIOUS_POISON_TYPE_IMMUNITY 87 +#define VARIOUS_JUMP_IF_HOLD_EFFECT 88 +#define VARIOUS_INFATUATE_WITH_BATTLER 89 +#define VARIOUS_SET_LAST_USED_ITEM 90 +#define VARIOUS_PARALYZE_TYPE_IMMUNITY 91 +#define VARIOUS_JUMP_IF_ABSENT 92 +#define VARIOUS_DESTROY_ABILITY_POPUP 93 +#define VARIOUS_TOTEM_BOOST 94 +#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 95 +#define VARIOUS_MOVEEND_ITEM_EFFECTS 96 +#define VARIOUS_TERRAIN_SEED 97 +#define VARIOUS_MAKE_INVISIBLE 98 +#define VARIOUS_ROOM_SERVICE 99 +#define VARIOUS_EERIE_SPELL_PP_REDUCE 100 +#define VARIOUS_JUMP_IF_TEAM_HEALTHY 101 +#define VARIOUS_TRY_HEAL_QUARTER_HP 102 +#define VARIOUS_REMOVE_TERRAIN 103 +#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 104 +#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 105 +#define VARIOUS_GET_ROTOTILLER_TARGETS 106 +#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 107 +#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 108 +#define VARIOUS_CONSUME_BERRY 109 +#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 110 +#define VARIOUS_JUMP_IF_SPECIES 111 +#define VARIOUS_UPDATE_ABILITY_POPUP 112 +#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 113 +#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 114 +#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 115 +#define VARIOUS_TRY_NO_RETREAT 116 +#define VARIOUS_TRY_TAR_SHOT 117 +#define VARIOUS_CAN_TAR_SHOT_WORK 118 +#define VARIOUS_CHECK_POLTERGEIST 119 +#define VARIOUS_CUT_1_3_HP_RAISE_STATS 120 +#define VARIOUS_TRY_END_NEUTRALIZING_GAS 121 +#define VARIOUS_JUMP_IF_UNDER_200 122 +#define VARIOUS_SET_SKY_DROP 123 +#define VARIOUS_CLEAR_SKY_DROP 124 +#define VARIOUS_SKY_DROP_YAWN 125 +#define VARIOUS_CURE_CERTAIN_STATUSES 126 +#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 127 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 128 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 129 +#define VARIOUS_SAVE_BATTLER_ITEM 130 +#define VARIOUS_RESTORE_BATTLER_ITEM 131 +#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 132 +#define VARIOUS_SET_BEAK_BLAST 133 +#define VARIOUS_SWAP_SIDE_STATUSES 134 +#define VARIOUS_SWAP_STATS 135 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/test/battle.h b/include/test/battle.h index c2ad0cd0c7..1a7cb070de 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -682,6 +682,7 @@ struct BattleTestData struct RecordedBattleSave recordedBattle; u8 battleRecordTypes[MAX_BATTLERS_COUNT][BATTLER_RECORD_SIZE]; + u8 battleRecordTurnNumbers[MAX_BATTLERS_COUNT][BATTLER_RECORD_SIZE]; u8 battleRecordSourceLineOffsets[MAX_BATTLERS_COUNT][BATTLER_RECORD_SIZE]; u16 recordIndexes[MAX_BATTLERS_COUNT]; struct BattlerTurn battleRecordTurns[MAX_TURNS][MAX_BATTLERS_COUNT]; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 6284f675b1..ed854af37e 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -10067,24 +10067,6 @@ static void Cmd_various(void) gBattleMoveDamage = gMovesInfo[gCurrentMove].argument; break; } - case VARIOUS_TRY_HIT_SWITCH_TARGET: - { - VARIOUS_ARGS(const u8 *failInstr); - if (IsBattlerAlive(gBattlerAttacker) - && IsBattlerAlive(gBattlerTarget) - && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && TARGET_TURN_DAMAGED - && GetBattlerAbility(gBattlerTarget) != ABILITY_GUARD_DOG) - { - gBattleScripting.switchCase = B_SWITCH_HIT; - gBattlescriptCurrInstr = cmd->nextInstr; - } - else - { - gBattlescriptCurrInstr = cmd->failInstr; - } - return; - } case VARIOUS_TRY_AUTOTOMIZE: { VARIOUS_ARGS(const u8 *failInstr); @@ -17346,6 +17328,26 @@ void BS_JumpIfBlockedBySoundproof(void) } } +void BS_TryHitSwitchTarget(void) +{ + NATIVE_ARGS(const u8 *failInstr); + + if (IsBattlerAlive(gBattlerAttacker) + && IsBattlerAlive(gBattlerTarget) + && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && TARGET_TURN_DAMAGED + && gSpecialStatuses[gBattlerAttacker].parentalBondState != PARENTAL_BOND_1ST_HIT + && GetBattlerAbility(gBattlerTarget) != ABILITY_GUARD_DOG) + { + gBattleScripting.switchCase = B_SWITCH_HIT; + gBattlescriptCurrInstr = cmd->nextInstr; + } + else + { + gBattlescriptCurrInstr = cmd->failInstr; + } +} + void BS_TeatimeInvul(void) { NATIVE_ARGS(u8 battler, const u8 *jumpInstr); diff --git a/test/battle/ability/parental_bond.c b/test/battle/ability/parental_bond.c index e4b6323286..a1614a8ffc 100644 --- a/test/battle/ability/parental_bond.c +++ b/test/battle/ability/parental_bond.c @@ -286,6 +286,26 @@ SINGLE_BATTLE_TEST("Parental Bond Snore strikes twice while asleep") } } +SINGLE_BATTLE_TEST("Parental Bond only triggers Dragon Tail's target switch out on the second hit") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET); + PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_DRAGON_TAIL, gimmick: GIMMICK_MEGA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, player); + HP_BAR(opponent); + HP_BAR(opponent); + MESSAGE("The opposing Wynaut was dragged out!"); + } + THEN { + EXPECT_EQ(player->species, SPECIES_KANGASKHAN_MEGA); + } +} + TO_DO_BATTLE_TEST("Parental Bond tests"); // Temporary TODO: Convert Bulbapedia description into tests. diff --git a/test/battle/ability/sap_sipper.c b/test/battle/ability/sap_sipper.c index a33c1a2b29..d691d4e91a 100644 --- a/test/battle/ability/sap_sipper.c +++ b/test/battle/ability/sap_sipper.c @@ -46,7 +46,7 @@ SINGLE_BATTLE_TEST("Sap Sipper does not increase Attack if already maxed") { GIVEN { PLAYER(SPECIES_MARILL) { Ability(ABILITY_SAP_SIPPER); } - OPPONENT(SPECIES_WOBBUFFET) { Speed(1); } + OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_BELLY_DRUM); MOVE(opponent, MOVE_VINE_WHIP); } } SCENE { diff --git a/test/battle/weather/hail.c b/test/battle/weather/hail.c index 2fa7b11d9b..6c7f7bcdec 100644 --- a/test/battle/weather/hail.c +++ b/test/battle/weather/hail.c @@ -57,7 +57,7 @@ SINGLE_BATTLE_TEST("Hail fails if Desolate Land or Primordial Sea are active") DOUBLE_BATTLE_TEST("Hail deals damage based on turn order") { GIVEN { - PLAYER(SPECIES_GLALIE); + PLAYER(SPECIES_GLALIE) { Speed(4); } PLAYER(SPECIES_WYNAUT) { Speed(1); } OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } OPPONENT(SPECIES_WYNAUT) { Speed(3); } diff --git a/test/battle/weather/sandstorm.c b/test/battle/weather/sandstorm.c index f211653995..38502cbbc7 100644 --- a/test/battle/weather/sandstorm.c +++ b/test/battle/weather/sandstorm.c @@ -69,7 +69,7 @@ SINGLE_BATTLE_TEST("Sandstorm damage does not hurt Ground, Rock, and Steel-type DOUBLE_BATTLE_TEST("Sandstorm deals damage based on turn order") { GIVEN { - PLAYER(SPECIES_PHANPY); + PLAYER(SPECIES_PHANPY) { Speed(4); } PLAYER(SPECIES_WYNAUT) { Speed(1); } OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } OPPONENT(SPECIES_WYNAUT) { Speed(3); } diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index fcb35ecd9d..04db97e85d 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -322,8 +322,10 @@ static void BattleTest_Run(void *data) if (DATA.hasExplicitSpeeds) { + // TODO: If a battler is taking the default action maybe it + // should not require an explicit speed? if (DATA.explicitSpeeds[B_SIDE_PLAYER] != (1 << DATA.playerPartySize) - 1 - && DATA.explicitSpeeds[B_SIDE_OPPONENT] != (1 << DATA.opponentPartySize) - 1) + || DATA.explicitSpeeds[B_SIDE_OPPONENT] != (1 << DATA.opponentPartySize) - 1) { Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LSpeed required for all PLAYERs and OPPONENTs"); } @@ -371,7 +373,7 @@ u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi) } else if (STATE->trials != n) { - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniform called with inconsistent trials %d and %d", STATE->trials, n); + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniform called from %p with tag %d and inconsistent trials %d and %d", __builtin_extract_return_addr(__builtin_return_address(0)), tag, STATE->trials, n); } STATE->trialRatio = Q_4_12(1) / STATE->trials; return STATE->runTrial + lo; @@ -413,7 +415,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32 while (reject(STATE->runTrial + lo + STATE->rngTrialOffset)) { if (STATE->runTrial + lo + STATE->rngTrialOffset > hi) - Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LRandomUniformExcept called with inconsistent reject"); + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniformExcept called from %p with tag %d and inconsistent reject", __builtin_extract_return_addr(__builtin_return_address(0)), tag); STATE->rngTrialOffset++; } @@ -424,7 +426,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32 while (reject(default_)) { if (default_ == lo) - Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LRandomUniformExcept rejected all values"); + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniformExcept called from %p with tag %d rejected all values", __builtin_extract_return_addr(__builtin_return_address(0)), tag); default_--; } return default_; @@ -454,7 +456,7 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) } else if (STATE->trials != n) { - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeighted called with inconsistent trials %d and %d", STATE->trials, n); + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeighted called from %p with tag %d and inconsistent trials %d and %d", __builtin_extract_return_addr(__builtin_return_address(0)), tag, STATE->trials, n); } // TODO: Detect inconsistent sum. STATE->trialRatio = Q_4_12(weights[STATE->runTrial]) / sum; @@ -488,7 +490,7 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) while (weights[n-1] == 0) { if (n == 1) - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called with all zero weights"); + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called from %p with tag %d and all zero weights", __builtin_extract_return_addr(__builtin_return_address(0)), tag); n--; } return n-1; @@ -527,7 +529,7 @@ const void *RandomElementArray(enum RandomTag tag, const void *array, size_t siz } else if (STATE->trials != count) { - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomElement called with inconsistent trials %d and %d", STATE->trials, count); + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomElement called from %p with tag %d and inconsistent trials %d and %d", __builtin_extract_return_addr(__builtin_return_address(0)), tag, STATE->trials, count); } STATE->trialRatio = Q_4_12(1) / count; return (const u8 *)array + size * STATE->runTrial; @@ -1855,6 +1857,7 @@ static void PushBattlerAction(u32 sourceLine, s32 battlerId, u32 actionType, u32 if (recordIndex >= BATTLER_RECORD_SIZE) Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LToo many actions"); DATA.battleRecordTypes[battlerId][recordIndex] = actionType; + DATA.battleRecordTurnNumbers[battlerId][recordIndex] = DATA.turns; DATA.battleRecordSourceLineOffsets[battlerId][recordIndex] = SourceLineOffset(sourceLine); DATA.recordedBattle.battleRecord[battlerId][recordIndex] = byte; } @@ -1903,6 +1906,17 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde if (actualMacro) { + if (gBattleResults.battleTurnCounter != DATA.battleRecordTurnNumbers[battlerId][recordIndex]) + { + switch (DATA.battleRecordTypes[battlerId][recordIndex]) + { + case RECORDED_PARTY_INDEX: + Test_ExitWithResult(TEST_RESULT_INVALID, line, ":L%s:%d: %s not required (is the send out random?)", filename, line, actualMacro); + default: + Test_ExitWithResult(TEST_RESULT_INVALID, line, ":L%s:%d: %s not required", filename, line, actualMacro); + } + } + switch (actionType) { case RECORDED_ACTION_TYPE: @@ -2415,7 +2429,7 @@ void SendOut(u32 sourceLine, struct BattlePokemon *battler, u32 partyIndex) s32 i; s32 battlerId = battler - gBattleMons; INVALID_IF(DATA.turnState == TURN_CLOSED, "SEND_OUT outside TURN"); - INVALID_IF(partyIndex >= ((battlerId & BIT_SIDE) == B_SIDE_PLAYER ? DATA.playerPartySize : DATA.opponentPartySize), "SWITCH to invalid party index"); + INVALID_IF(partyIndex >= ((battlerId & BIT_SIDE) == B_SIDE_PLAYER ? DATA.playerPartySize : DATA.opponentPartySize), "SEND_OUT of invalid party index"); INVALID_IF(IsAITest() && (battlerId & BIT_SIDE) == B_SIDE_OPPONENT, "SEND_OUT is not allowed for opponent in AI tests. Use EXPECT_SEND_OUT instead"); for (i = 0; i < STATE->battlersCount; i++) { diff --git a/tools/mgba-rom-test-hydra/main.c b/tools/mgba-rom-test-hydra/main.c index d4c0f4e080..55ba664e75 100644 --- a/tools/mgba-rom-test-hydra/main.c +++ b/tools/mgba-rom-test-hydra/main.c @@ -812,7 +812,9 @@ int main(int argc, char *argv[]) fprintf(stdout, " - \e[31mand %d more...\e[0m\n", fails - MAX_SUMMARY_TESTS_TO_LIST); break; } - fprintf(stdout, " - \e[31m%s\e[0m - %s.\n", failed_TestFilenameLine[i], failed_TestNames[i]); + fprintf(stdout, " - \e[31m"); + fprint_buffer(stdout, failed_TestFilenameLine[i], strlen(failed_TestFilenameLine[i])); + fprintf(stdout, "\e[0m - %s.\n", failed_TestNames[i]); } } @@ -826,7 +828,9 @@ int main(int argc, char *argv[]) fprintf(stdout, " - \e[33mand %d more...\e[0m\n", assumptionFails - MAX_SUMMARY_TESTS_TO_LIST); break; } - fprintf(stdout, " - \e[33m%s\e[0m - %s.\n", assumeFailed_FilenameLine[i], assumeFailed_TestNames[i]); + fprintf(stdout, " - \e[33m"); + fprint_buffer(stdout, assumeFailed_FilenameLine[i], strlen(assumeFailed_FilenameLine[i])); + fprintf(stdout, "\e[0m - %s.\n", assumeFailed_TestNames[i]); } } @@ -840,7 +844,9 @@ int main(int argc, char *argv[]) fprintf(stdout, " - \e[32mand %d more...\e[0m\n", knownFailsPassing - MAX_SUMMARY_TESTS_TO_LIST); break; } - fprintf(stdout, " - \e[32m%s\e[0m - %s.\n", knownFailingPassed_FilenameLine[i], knownFailingPassed_TestNames[i]); + fprintf(stdout, " - \e[32m"); + fprint_buffer(stdout, knownFailingPassed_FilenameLine[i], strlen(knownFailingPassed_FilenameLine[i])); + fprintf(stdout, "\e[0m - %s.\n", knownFailingPassed_TestNames[i]); } }