Merge branch '_RHH/master' into _RHH/upcoming
# Conflicts: # ld_script_modern.ld # src/battle_ai_switch_items.c
This commit is contained in:
commit
09d12fb154
11 changed files with 139 additions and 58 deletions
|
@ -7,11 +7,11 @@ JASC-PAL
|
||||||
201 201 201
|
201 201 201
|
||||||
169 169 169
|
169 169 169
|
||||||
129 129 129
|
129 129 129
|
||||||
249 153 161
|
106 106 106
|
||||||
233 49 49
|
37 37 37
|
||||||
193 33 41
|
106 106 106
|
||||||
145 17 33
|
0 0 0
|
||||||
249 153 161
|
106 106 106
|
||||||
193 33 41
|
193 33 41
|
||||||
141 251 184
|
141 251 184
|
||||||
52 66 162
|
52 66 162
|
||||||
|
|
|
@ -337,7 +337,7 @@ struct AiLogicData
|
||||||
bool8 shouldSwitchMon; // Because all available moves have no/little effect. Each bit per battler.
|
bool8 shouldSwitchMon; // Because all available moves have no/little effect. Each bit per battler.
|
||||||
u8 monToSwitchId[MAX_BATTLERS_COUNT]; // ID of the mon to switch.
|
u8 monToSwitchId[MAX_BATTLERS_COUNT]; // ID of the mon to switch.
|
||||||
bool8 weatherHasEffect; // The same as WEATHER_HAS_EFFECT. Stored here, so it's called only once.
|
bool8 weatherHasEffect; // The same as WEATHER_HAS_EFFECT. Stored here, so it's called only once.
|
||||||
u8 mostSuitableMonId; // Stores result of GetMostSuitableMonToSwitchInto, which decides which generic mon the AI would switch into if they decide to switch. This can be overruled by specific mons found in ShouldSwitch; the final resulting mon is stored in AI_monToSwitchIntoId.
|
u8 mostSuitableMonId[MAX_BATTLERS_COUNT]; // Stores result of GetMostSuitableMonToSwitchInto, which decides which generic mon the AI would switch into if they decide to switch. This can be overruled by specific mons found in ShouldSwitch; the final resulting mon is stored in AI_monToSwitchIntoId.
|
||||||
struct SwitchinCandidate switchinCandidate; // Struct used for deciding which mon to switch to in battle_ai_switch_items.c
|
struct SwitchinCandidate switchinCandidate; // Struct used for deciding which mon to switch to in battle_ai_switch_items.c
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,11 @@ SECTIONS {
|
||||||
ALIGN(4)
|
ALIGN(4)
|
||||||
{
|
{
|
||||||
__ewram_start = .;
|
__ewram_start = .;
|
||||||
|
/*
|
||||||
|
We link malloc.o here to prevent `gHeap` from landing in the middle of EWRAM.
|
||||||
|
Otherwise this causes corruption issues on some ld versions
|
||||||
|
*/
|
||||||
|
gflib/malloc.o(ewram_data);
|
||||||
*(.ewram*)
|
*(.ewram*)
|
||||||
__ewram_end = .;
|
__ewram_end = .;
|
||||||
} > EWRAM
|
} > EWRAM
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "battle_anim.h"
|
#include "battle_anim.h"
|
||||||
#include "battle_ai_util.h"
|
#include "battle_ai_util.h"
|
||||||
#include "battle_ai_main.h"
|
#include "battle_ai_main.h"
|
||||||
|
#include "battle_controllers.h"
|
||||||
#include "battle_factory.h"
|
#include "battle_factory.h"
|
||||||
#include "battle_setup.h"
|
#include "battle_setup.h"
|
||||||
#include "battle_z_move.h"
|
#include "battle_z_move.h"
|
||||||
|
@ -455,11 +456,21 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool32 AI_SwitchMonIfSuitable(u32 battler)
|
static bool32 AI_SwitchMonIfSuitable(u32 battler, bool32 doubleBattle)
|
||||||
{
|
{
|
||||||
u32 monToSwitchId = AI_DATA->mostSuitableMonId;
|
u32 monToSwitchId = AI_DATA->mostSuitableMonId[battler];
|
||||||
if (monToSwitchId != PARTY_SIZE)
|
if (monToSwitchId != PARTY_SIZE && IsValidForBattle(&GetBattlerParty(battler)[monToSwitchId]))
|
||||||
{
|
{
|
||||||
|
gBattleMoveDamage = monToSwitchId;
|
||||||
|
// Edge case: See if partner already chose to switch into the same mon
|
||||||
|
if (doubleBattle)
|
||||||
|
{
|
||||||
|
u32 partner = BATTLE_PARTNER(battler);
|
||||||
|
if (AI_DATA->shouldSwitchMon & gBitTable[partner] && AI_DATA->monToSwitchId[partner] == monToSwitchId)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
AI_DATA->shouldSwitchMon |= gBitTable[battler];
|
AI_DATA->shouldSwitchMon |= gBitTable[battler];
|
||||||
AI_DATA->monToSwitchId[battler] = monToSwitchId;
|
AI_DATA->monToSwitchId[battler] = monToSwitchId;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -496,7 +507,7 @@ static bool32 AI_ShouldSwitchIfBadMoves(u32 battler, bool32 doubleBattle)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == MAX_BATTLERS_COUNT && AI_SwitchMonIfSuitable(battler))
|
if (i == MAX_BATTLERS_COUNT && AI_SwitchMonIfSuitable(battler, doubleBattle))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -507,7 +518,7 @@ static bool32 AI_ShouldSwitchIfBadMoves(u32 battler, bool32 doubleBattle)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == MAX_MON_MOVES && AI_SwitchMonIfSuitable(battler))
|
if (i == MAX_MON_MOVES && AI_SwitchMonIfSuitable(battler, doubleBattle))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,7 +530,7 @@ static bool32 AI_ShouldSwitchIfBadMoves(u32 battler, bool32 doubleBattle)
|
||||||
&& IsTruantMonVulnerable(battler, gBattlerTarget)
|
&& IsTruantMonVulnerable(battler, gBattlerTarget)
|
||||||
&& gDisableStructs[battler].truantCounter
|
&& gDisableStructs[battler].truantCounter
|
||||||
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2
|
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2
|
||||||
&& AI_SwitchMonIfSuitable(battler))
|
&& AI_SwitchMonIfSuitable(battler, doubleBattle))
|
||||||
{
|
{
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have any other viable options, don't switch out
|
// If we don't have any other viable options, don't switch out
|
||||||
if (AI_DATA->mostSuitableMonId == PARTY_SIZE)
|
if (AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
// Start assessing whether or not mon has bad odds
|
// Start assessing whether or not mon has bad odds
|
||||||
|
@ -603,12 +603,12 @@ static bool32 ShouldSwitchIfAbilityBenefit(u32 battler, bool32 emitResult)
|
||||||
moduloChance = 4; //25%
|
moduloChance = 4; //25%
|
||||||
//Attempt to cure bad ailment
|
//Attempt to cure bad ailment
|
||||||
if (gBattleMons[battler].status1 & (STATUS1_SLEEP | STATUS1_FREEZE | STATUS1_TOXIC_POISON)
|
if (gBattleMons[battler].status1 & (STATUS1_SLEEP | STATUS1_FREEZE | STATUS1_TOXIC_POISON)
|
||||||
&& AI_DATA->mostSuitableMonId != PARTY_SIZE)
|
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE)
|
||||||
break;
|
break;
|
||||||
//Attempt to cure lesser ailment
|
//Attempt to cure lesser ailment
|
||||||
if ((gBattleMons[battler].status1 & STATUS1_ANY)
|
if ((gBattleMons[battler].status1 & STATUS1_ANY)
|
||||||
&& (gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2)
|
&& (gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2)
|
||||||
&& AI_DATA->mostSuitableMonId != PARTY_SIZE
|
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
|
||||||
&& Random() % (moduloChance*chanceReducer) == 0)
|
&& Random() % (moduloChance*chanceReducer) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -620,7 +620,7 @@ static bool32 ShouldSwitchIfAbilityBenefit(u32 battler, bool32 emitResult)
|
||||||
if (gBattleMons[battler].status1 & STATUS1_ANY)
|
if (gBattleMons[battler].status1 & STATUS1_ANY)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if ((gBattleMons[battler].hp <= ((gBattleMons[battler].maxHP * 2) / 3))
|
if ((gBattleMons[battler].hp <= ((gBattleMons[battler].maxHP * 2) / 3))
|
||||||
&& AI_DATA->mostSuitableMonId != PARTY_SIZE
|
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE
|
||||||
&& Random() % (moduloChance*chanceReducer) == 0)
|
&& Random() % (moduloChance*chanceReducer) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -856,7 +856,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler, bool32 emitResult)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
// If not Encored or if no good switchin, don't switch
|
// If not Encored or if no good switchin, don't switch
|
||||||
if (gDisableStructs[battler].encoredMove == MOVE_NONE || AI_DATA->mostSuitableMonId == PARTY_SIZE)
|
if (gDisableStructs[battler].encoredMove == MOVE_NONE || AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
// Otherwise 50% chance to switch out
|
// Otherwise 50% chance to switch out
|
||||||
|
@ -890,7 +890,7 @@ static bool32 AreAttackingStatsLowered(u32 battler, bool32 emitResult)
|
||||||
// 50% chance if attack at -2 and have a good candidate mon
|
// 50% chance if attack at -2 and have a good candidate mon
|
||||||
else if (attackingStage == DEFAULT_STAT_STAGE - 2)
|
else if (attackingStage == DEFAULT_STAT_STAGE - 2)
|
||||||
{
|
{
|
||||||
if (AI_DATA->mostSuitableMonId != PARTY_SIZE && (Random() & 1))
|
if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (Random() & 1))
|
||||||
{
|
{
|
||||||
gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE;
|
gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE;
|
||||||
BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0);
|
BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0);
|
||||||
|
@ -915,7 +915,7 @@ static bool32 AreAttackingStatsLowered(u32 battler, bool32 emitResult)
|
||||||
// 50% chance if attack at -2 and have a good candidate mon
|
// 50% chance if attack at -2 and have a good candidate mon
|
||||||
else if (spAttackingStage == DEFAULT_STAT_STAGE - 2)
|
else if (spAttackingStage == DEFAULT_STAT_STAGE - 2)
|
||||||
{
|
{
|
||||||
if (AI_DATA->mostSuitableMonId != PARTY_SIZE && (Random() & 1))
|
if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (Random() & 1))
|
||||||
{
|
{
|
||||||
gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE;
|
gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE;
|
||||||
BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0);
|
BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0);
|
||||||
|
@ -1064,7 +1064,7 @@ void AI_TrySwitchOrUseItem(u32 battler)
|
||||||
{
|
{
|
||||||
if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE)
|
if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE)
|
||||||
{
|
{
|
||||||
s32 monToSwitchId = AI_DATA->mostSuitableMonId;
|
s32 monToSwitchId = AI_DATA->mostSuitableMonId[battler];
|
||||||
if (monToSwitchId == PARTY_SIZE)
|
if (monToSwitchId == PARTY_SIZE)
|
||||||
{
|
{
|
||||||
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
||||||
|
|
|
@ -4075,7 +4075,7 @@ static void HandleTurnActionSelectionState(void)
|
||||||
if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart())
|
if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart())
|
||||||
&& (BattlerHasAi(battler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE)))
|
&& (BattlerHasAi(battler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE)))
|
||||||
{
|
{
|
||||||
AI_DATA->mostSuitableMonId = GetMostSuitableMonToSwitchInto(battler, FALSE);
|
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, FALSE);
|
||||||
gBattleStruct->aiMoveOrAction[battler] = ComputeBattleAiScores(battler);
|
gBattleStruct->aiMoveOrAction[battler] = ComputeBattleAiScores(battler);
|
||||||
}
|
}
|
||||||
// fallthrough
|
// fallthrough
|
||||||
|
|
|
@ -6550,7 +6550,7 @@ static u8 ItemHealHp(u32 battler, u32 itemId, bool32 end2, bool32 percentHeal)
|
||||||
gBattlescriptCurrInstr = BattleScript_ItemHealHP_RemoveItemRet;
|
gBattlescriptCurrInstr = BattleScript_ItemHealHP_RemoveItemRet;
|
||||||
}
|
}
|
||||||
if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_EMERGENCY_EXIT
|
if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_EMERGENCY_EXIT
|
||||||
&& GetNonDynamaxMaxHP(battler) > gBattleMons[battler].maxHP / 2)
|
&& GetNonDynamaxHP(battler) >= GetNonDynamaxMaxHP(battler) / 2)
|
||||||
gBattleResources->flags->flags[battler] &= ~RESOURCE_FLAG_EMERGENCY_EXIT;
|
gBattleResources->flags->flags[battler] &= ~RESOURCE_FLAG_EMERGENCY_EXIT;
|
||||||
|
|
||||||
return ITEM_HP_CHANGE;
|
return ITEM_HP_CHANGE;
|
||||||
|
|
|
@ -8,10 +8,7 @@ SINGLE_BATTLE_TEST("Emergency Exit switches out when taking 50% max-hp damage")
|
||||||
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(262); };
|
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(262); };
|
||||||
OPPONENT(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
} WHEN {
|
} WHEN {
|
||||||
TURN {
|
TURN { MOVE(player, MOVE_SUPER_FANG); SEND_OUT(opponent, 1); }
|
||||||
MOVE(player, MOVE_SUPER_FANG);
|
|
||||||
SEND_OUT(opponent, 1);
|
|
||||||
}
|
|
||||||
} SCENE {
|
} SCENE {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPER_FANG, player);
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPER_FANG, player);
|
||||||
HP_BAR(opponent);
|
HP_BAR(opponent);
|
||||||
|
@ -19,16 +16,14 @@ SINGLE_BATTLE_TEST("Emergency Exit switches out when taking 50% max-hp damage")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SINGLE_BATTLE_TEST("Emergency Exit switches out when taking 50% max-hp damage after a restore hp hold effect was used")
|
SINGLE_BATTLE_TEST("Emergency Exit does not switch out when going below 50% max-HP but healed via held item back above the threshold")
|
||||||
{
|
{
|
||||||
GIVEN {
|
GIVEN {
|
||||||
PLAYER(SPECIES_WOBBUFFET)
|
PLAYER(SPECIES_WOBBUFFET)
|
||||||
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(262); Item(ITEM_SITRUS_BERRY); };
|
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(262); Item(ITEM_SITRUS_BERRY); };
|
||||||
OPPONENT(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
} WHEN {
|
} WHEN {
|
||||||
TURN {
|
TURN { MOVE(player, MOVE_SUPER_FANG); }
|
||||||
MOVE(player, MOVE_SUPER_FANG);
|
|
||||||
}
|
|
||||||
} SCENE {
|
} SCENE {
|
||||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPER_FANG, player);
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPER_FANG, player);
|
||||||
HP_BAR(opponent);
|
HP_BAR(opponent);
|
||||||
|
@ -36,3 +31,19 @@ SINGLE_BATTLE_TEST("Emergency Exit switches out when taking 50% max-hp damage af
|
||||||
NOT ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
|
NOT ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Emergency Exit switches out when going below 50% max-HP but healing via held item is not enough to go back above the threshold")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET)
|
||||||
|
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(133); Item(ITEM_ORAN_BERRY); };
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_SUPER_FANG); SEND_OUT(opponent, 1); }
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPER_FANG, player);
|
||||||
|
HP_BAR(opponent);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
|
||||||
|
ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -702,3 +702,31 @@ AI_SINGLE_BATTLE_TEST("First Impression is not chosen if it's blocked by certain
|
||||||
TURN { EXPECT_MOVE(opponent, MOVE_LUNGE); }
|
TURN { EXPECT_MOVE(opponent, MOVE_LUNGE); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spots in a double battle")
|
||||||
|
{
|
||||||
|
u32 flags;
|
||||||
|
|
||||||
|
PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; }
|
||||||
|
PARAMETRIZE {flags = 0; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags);
|
||||||
|
PLAYER(SPECIES_RATTATA);
|
||||||
|
PLAYER(SPECIES_RATTATA);
|
||||||
|
// No moves to damage player.
|
||||||
|
OPPONENT(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); }
|
||||||
|
OPPONENT(SPECIES_HAUNTER) { Moves(MOVE_SHADOW_BALL); }
|
||||||
|
OPPONENT(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); }
|
||||||
|
OPPONENT(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { EXPECT_SWITCH(opponentLeft, 3); };
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("{PKMN} TRAINER LEAF withdrew Gengar!");
|
||||||
|
MESSAGE("{PKMN} TRAINER LEAF sent out Raticate!");
|
||||||
|
NONE_OF {
|
||||||
|
MESSAGE("{PKMN} TRAINER LEAF withdrew Haunter!");
|
||||||
|
MESSAGE("{PKMN} TRAINER LEAF sent out Raticate!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ void TestRunner_Battle(const struct Test *);
|
||||||
|
|
||||||
static bool32 MgbaOpen_(void);
|
static bool32 MgbaOpen_(void);
|
||||||
static void MgbaExit_(u8 exitCode);
|
static void MgbaExit_(u8 exitCode);
|
||||||
static s32 MgbaPuts_(const char *s);
|
|
||||||
static s32 MgbaVPrintf_(const char *fmt, va_list va);
|
static s32 MgbaVPrintf_(const char *fmt, va_list va);
|
||||||
static void Intr_Timer2(void);
|
static void Intr_Timer2(void);
|
||||||
|
|
||||||
|
@ -293,12 +292,6 @@ top:
|
||||||
color = "";
|
color = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gTestRunnerState.result == TEST_RESULT_PASS
|
|
||||||
&& gTestRunnerState.result != gTestRunnerState.expectedResult)
|
|
||||||
{
|
|
||||||
MgbaPuts_("\e[31mPlease remove KNOWN_FAILING if this test intentionally PASSes\e[0m");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (gTestRunnerState.result)
|
switch (gTestRunnerState.result)
|
||||||
{
|
{
|
||||||
case TEST_RESULT_FAIL:
|
case TEST_RESULT_FAIL:
|
||||||
|
@ -313,7 +306,10 @@ top:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TEST_RESULT_PASS:
|
case TEST_RESULT_PASS:
|
||||||
result = "PASS";
|
if (gTestRunnerState.result != gTestRunnerState.expectedResult)
|
||||||
|
result = "KNOWN_FAILING_PASS";
|
||||||
|
else
|
||||||
|
result = "PASS";
|
||||||
break;
|
break;
|
||||||
case TEST_RESULT_ASSUMPTION_FAIL:
|
case TEST_RESULT_ASSUMPTION_FAIL:
|
||||||
result = "ASSUMPTION_FAIL";
|
result = "ASSUMPTION_FAIL";
|
||||||
|
@ -341,7 +337,12 @@ top:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gTestRunnerState.result == TEST_RESULT_PASS)
|
if (gTestRunnerState.result == TEST_RESULT_PASS)
|
||||||
MgbaPrintf_(":P%s%s\e[0m", color, result);
|
{
|
||||||
|
if (gTestRunnerState.result != gTestRunnerState.expectedResult)
|
||||||
|
MgbaPrintf_(":U%s%s\e[0m", color, result);
|
||||||
|
else
|
||||||
|
MgbaPrintf_(":P%s%s\e[0m", color, result);
|
||||||
|
}
|
||||||
else if (gTestRunnerState.result == TEST_RESULT_ASSUMPTION_FAIL)
|
else if (gTestRunnerState.result == TEST_RESULT_ASSUMPTION_FAIL)
|
||||||
MgbaPrintf_(":A%s%s\e[0m", color, result);
|
MgbaPrintf_(":A%s%s\e[0m", color, result);
|
||||||
else if (gTestRunnerState.result == TEST_RESULT_TODO)
|
else if (gTestRunnerState.result == TEST_RESULT_TODO)
|
||||||
|
@ -513,11 +514,6 @@ static void MgbaExit_(u8 exitCode)
|
||||||
asm("swi 0x3" :: "r" (_exitCode));
|
asm("swi 0x3" :: "r" (_exitCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 MgbaPuts_(const char *s)
|
|
||||||
{
|
|
||||||
return MgbaPrintf_("%s", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 MgbaPrintf_(const char *fmt, ...)
|
s32 MgbaPrintf_(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
#define MAX_PROCESSES 32 // See also test/test.h
|
#define MAX_PROCESSES 32 // See also test/test.h
|
||||||
#define MAX_FAILED_TESTS_TO_LIST 100
|
#define MAX_SUMMARY_TESTS_TO_LIST 50
|
||||||
#define MAX_TEST_LIST_BUFFER_LENGTH 256
|
#define MAX_TEST_LIST_BUFFER_LENGTH 256
|
||||||
|
|
||||||
#define ARRAY_COUNT(arr) (sizeof((arr)) / sizeof((arr)[0]))
|
#define ARRAY_COUNT(arr) (sizeof((arr)) / sizeof((arr)[0]))
|
||||||
|
@ -54,11 +54,13 @@ struct Runner
|
||||||
char *output_buffer;
|
char *output_buffer;
|
||||||
int passes;
|
int passes;
|
||||||
int knownFails;
|
int knownFails;
|
||||||
|
int knownFailsPassing;
|
||||||
int todos;
|
int todos;
|
||||||
int assumptionFails;
|
int assumptionFails;
|
||||||
int fails;
|
int fails;
|
||||||
int results;
|
int results;
|
||||||
char failedTestNames[MAX_FAILED_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
char failedTestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||||
|
char knownFailingPassedTestNames[MAX_SUMMARY_TESTS_TO_LIST][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned nrunners = 0;
|
static unsigned nrunners = 0;
|
||||||
|
@ -107,6 +109,11 @@ static void handle_read(int i, struct Runner *runner)
|
||||||
case 'K':
|
case 'K':
|
||||||
runner->knownFails++;
|
runner->knownFails++;
|
||||||
goto add_to_results;
|
goto add_to_results;
|
||||||
|
case 'U':
|
||||||
|
if (runner->knownFailsPassing < MAX_SUMMARY_TESTS_TO_LIST)
|
||||||
|
strcpy(runner->knownFailingPassedTestNames[runner->knownFailsPassing], runner->test_name);
|
||||||
|
runner->knownFailsPassing++;
|
||||||
|
goto add_to_results;
|
||||||
case 'T':
|
case 'T':
|
||||||
runner->todos++;
|
runner->todos++;
|
||||||
goto add_to_results;
|
goto add_to_results;
|
||||||
|
@ -114,7 +121,7 @@ static void handle_read(int i, struct Runner *runner)
|
||||||
runner->assumptionFails++;
|
runner->assumptionFails++;
|
||||||
goto add_to_results;
|
goto add_to_results;
|
||||||
case 'F':
|
case 'F':
|
||||||
if (runner->fails < MAX_FAILED_TESTS_TO_LIST)
|
if (runner->fails < MAX_SUMMARY_TESTS_TO_LIST)
|
||||||
strcpy(runner->failedTestNames[runner->fails], runner->test_name);
|
strcpy(runner->failedTestNames[runner->fails], runner->test_name);
|
||||||
runner->fails++;
|
runner->fails++;
|
||||||
add_to_results:
|
add_to_results:
|
||||||
|
@ -519,12 +526,14 @@ int main(int argc, char *argv[])
|
||||||
int exit_code = 0;
|
int exit_code = 0;
|
||||||
int passes = 0;
|
int passes = 0;
|
||||||
int knownFails = 0;
|
int knownFails = 0;
|
||||||
|
int knownFailsPassing = 0;
|
||||||
int todos = 0;
|
int todos = 0;
|
||||||
int assumptionFails = 0;
|
int assumptionFails = 0;
|
||||||
int fails = 0;
|
int fails = 0;
|
||||||
int results = 0;
|
int results = 0;
|
||||||
|
|
||||||
char failedTestNames[MAX_FAILED_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
char failedTestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||||
|
char knownFailingPassedTestNames[MAX_SUMMARY_TESTS_TO_LIST * MAX_PROCESSES][MAX_TEST_LIST_BUFFER_LENGTH];
|
||||||
|
|
||||||
for (int i = 0; i < nrunners; i++)
|
for (int i = 0; i < nrunners; i++)
|
||||||
{
|
{
|
||||||
|
@ -540,18 +549,25 @@ int main(int argc, char *argv[])
|
||||||
exit_code = WEXITSTATUS(wstatus);
|
exit_code = WEXITSTATUS(wstatus);
|
||||||
passes += runners[i].passes;
|
passes += runners[i].passes;
|
||||||
knownFails += runners[i].knownFails;
|
knownFails += runners[i].knownFails;
|
||||||
|
for (int j = 0; j < runners[i].knownFailsPassing; j++)
|
||||||
|
{
|
||||||
|
if (j < MAX_SUMMARY_TESTS_TO_LIST)
|
||||||
|
strcpy(knownFailingPassedTestNames[fails], runners[i].knownFailingPassedTestNames[j]);
|
||||||
|
knownFailsPassing++;
|
||||||
|
}
|
||||||
todos += runners[i].todos;
|
todos += runners[i].todos;
|
||||||
assumptionFails += runners[i].assumptionFails;
|
assumptionFails += runners[i].assumptionFails;
|
||||||
for (int j = 0; j < runners[i].fails; j++)
|
for (int j = 0; j < runners[i].fails; j++)
|
||||||
{
|
{
|
||||||
if (j < MAX_FAILED_TESTS_TO_LIST)
|
if (j < MAX_SUMMARY_TESTS_TO_LIST)
|
||||||
strcpy(failedTestNames[fails], runners[i].failedTestNames[j]);
|
strcpy(failedTestNames[fails], runners[i].failedTestNames[j]);
|
||||||
fails++;
|
fails++;
|
||||||
}
|
}
|
||||||
results += runners[i].results;
|
results += runners[i].results;
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(failedTestNames, min(fails, MAX_FAILED_TESTS_TO_LIST), sizeof(char) * MAX_TEST_LIST_BUFFER_LENGTH, compare_strings);
|
qsort(failedTestNames, min(fails, MAX_SUMMARY_TESTS_TO_LIST), sizeof(char) * MAX_TEST_LIST_BUFFER_LENGTH, compare_strings);
|
||||||
|
qsort(knownFailingPassedTestNames, min(fails, MAX_SUMMARY_TESTS_TO_LIST), sizeof(char) * MAX_TEST_LIST_BUFFER_LENGTH, compare_strings);
|
||||||
|
|
||||||
if (results == 0)
|
if (results == 0)
|
||||||
{
|
{
|
||||||
|
@ -559,28 +575,42 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
fprintf(stdout, "\n");
|
||||||
if (fails > 0)
|
if (fails > 0)
|
||||||
{
|
{
|
||||||
fprintf(stdout, "\n- Tests \e[31mFAILED\e[0m : %d Add TESTS='X' to run tests with the defined prefix.\n", fails);
|
fprintf(stdout, "- Tests \e[31mFAILED\e[0m : %d Add TESTS='X' to run tests with the defined prefix.\n", fails);
|
||||||
for (int i = 0; i < fails; i++)
|
for (int i = 0; i < fails; i++)
|
||||||
{
|
{
|
||||||
if (i >= MAX_FAILED_TESTS_TO_LIST)
|
if (i >= MAX_SUMMARY_TESTS_TO_LIST)
|
||||||
{
|
{
|
||||||
fprintf(stdout, " - \e[31mand %d more...\e[0m\n", fails - MAX_FAILED_TESTS_TO_LIST);
|
fprintf(stdout, " - \e[31mand %d more...\e[0m\n", fails - MAX_SUMMARY_TESTS_TO_LIST);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fprintf(stdout, " - \e[31m%s\e[0m.\n", failedTestNames[i]);
|
fprintf(stdout, " - \e[31m%s\e[0m.\n", failedTestNames[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(stdout, "- Tests \e[32mPASSED\e[0m: %d\n", passes);
|
if (knownFailsPassing > 0)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "- \e[31mKNOWN_FAILING_PASSED\e[0m: %d \e[31mPlease remove KNOWN_FAILING if these tests intentionally PASS\e[0m\n", knownFailsPassing);
|
||||||
|
for (int i = 0; i < knownFailsPassing; i++)
|
||||||
|
{
|
||||||
|
if (i >= MAX_SUMMARY_TESTS_TO_LIST)
|
||||||
|
{
|
||||||
|
fprintf(stdout, " - \e[31mand %d more...\e[0m\n", knownFailsPassing - MAX_SUMMARY_TESTS_TO_LIST);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fprintf(stdout, " - \e[31m%s\e[0m.\n", knownFailingPassedTestNames[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stdout, "- Tests \e[32mPASSED\e[0m: %d\n", passes);
|
||||||
if (knownFails > 0)
|
if (knownFails > 0)
|
||||||
fprintf(stdout, "- Tests \e[33mKNOWN_FAILING\e[0m: %d\n", knownFails);
|
fprintf(stdout, "- Tests \e[33mKNOWN_FAILING\e[0m: %d\n", knownFails);
|
||||||
if (todos > 0)
|
if (todos > 0)
|
||||||
fprintf(stdout, "- Tests \e[33mTO_DO\e[0m: %d\n", todos);
|
fprintf(stdout, "- Tests \e[33mTO_DO\e[0m: %d\n", todos);
|
||||||
if (assumptionFails > 0)
|
if (assumptionFails > 0)
|
||||||
fprintf(stdout, "- \e[33mASSUMPTIONS_FAILED\e[0m: %d\n", assumptionFails);
|
fprintf(stdout, "- \e[33mASSUMPTIONS_FAILED\e[0m: %d\n", assumptionFails);
|
||||||
|
|
||||||
fprintf(stdout, "- Tests \e[34mTOTAL\e[0m: %d\n", results);
|
fprintf(stdout, "- Tests \e[34mTOTAL\e[0m: %d\n", results);
|
||||||
}
|
}
|
||||||
fprintf(stdout, "\n");
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue