Refactor pokerus and add configs (#7731)

Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
FosterProgramming 2026-01-14 12:04:33 +01:00 committed by GitHub
parent 533d6494e6
commit 550fe9a7de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 1143 additions and 177 deletions

View File

@ -441,6 +441,13 @@ Debug_EventScript_SetFriendship::
releaseall releaseall
end end
Debug_EventScript_GivePokerus::
special ChoosePartyMon
waitstate
callnative DebugNative_Party_SetPokerus
releaseall
end
Debug_EventScript_InflictStatus1_Single_Poison: Debug_EventScript_InflictStatus1_Single_Poison:
setstatus1 STATUS1_POISON, VAR_0x8004 setstatus1 STATUS1_POISON, VAR_0x8004
releaseall releaseall

21
include/config/pokerus.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef GUARD_CONFIG_POKERUS_H
#define GUARD_CONFIG_POKERUS_H
//For Pokérus, we refer to infection as a Pokémon catching Pokérus from an enemy Pokémon (trainer or wild) and we refer to spreading as Pokémon catching Pokérus from another infected Pokémon in the party
#define P_POKERUS_ENABLED TRUE // If FALSE, Pokérus will have no effect, won't be shown and won't be aquired in any way but save data won't be affected
#define P_POKERUS_STRAIN_DISTRIBUTION GEN_LATEST // Pokérus has 16 different strains and their probability distribution change depending on generation, GEN_3 will use the Ruby/Sapphire version and GEN_4 will use the version used in Emerald and Gen 4
#define P_POKERUS_SPREAD_ADJACENCY GEN_LATEST // In Gen 2, Pokérus spread to one adjacent Pokémon but it spreads to both adjacent Pokémon in gen 3+
#define P_POKERUS_SPREAD_DAYS_LEFT GEN_LATEST // In Gen 2, a freshly spreaded Pokémon will get its full infection duration based on strain. In gen 3+, the Pokérus duration will copy the duration from the Pokémon it was spreaded from
#define P_POKERUS_INFECT_AGAIN GEN_LATEST // If Gen 2 only, your party can get infected even when it is already infected with Pokérus (doesn't affect spreading)
#define P_POKERUS_VISIBLE_ON_EGG GEN_LATEST // Controls if eggs can show Pokérus symbol in summary screen (TRUE from gen 3 to 6, FALSE in gen 2,7 and 8)
#define P_POKERUS_INFECT_EGG FALSE // If TRUE, eggs can receive Pokérus from spread and direction infection (gen 2). If FALSE, eggs can receive Pokérus from spread but not direct infection (gen 3). Behavior is unknown in other gens.
#define P_POKERUS_FLAG_INFECTION 0 // If Pokérus can only get infected if this flag is set or undefined (0). This emulates a gen 2 mechanic where Pokémon can only get infected by Pokérus after visiting Goldernrod. This does not affect spreading
// Weird Pokérus behaviors that could be considered bugs. They are TRUE in vanilla Emerald but set to FALSE by default in Expansion (behaviors in other gens is unknown)
#define P_POKERUS_HERD_IMMUNITY FALSE // If TRUE, Pokémon that have been previously infected by the Pokérus in your party reduce the chances of your party getting infected by the Pokérus (because they can be rolled at the target of the infection but are now "immune")
#define P_POKERUS_WEAK_VARIANT FALSE // If TRUE, the variant 0 of Pokérus can be erased by stronger variant when Pokérus is spreading
#define P_POKERUS_INFECTION_ODDS 3 // Actual probability is POKERUS_INFECTION_ODDS/65536
#define P_POKERUS_SPREAD_ODDS 21846 // Actual probability is POKERUS_SPREAD_ODDS/65536 (21846 should correspond to the vanilla Random() % 3)
#endif // GUARD_CONFIG_POKERUS_H

View File

@ -2,7 +2,7 @@
#define GUARD_CONSTANTS_GENERATIONAL_CHANGES_H #define GUARD_CONSTANTS_GENERATIONAL_CHANGES_H
/* Config definitions */ /* Config definitions */
#define CONFIG_DEFINITIONS(F) \ #define BATTLE_CONFIG_DEFINITIONS(F) \
/* Calculation settings */ \ /* Calculation settings */ \
F(CRIT_CHANCE, critChance, (u32, GEN_COUNT - 1)) \ F(CRIT_CHANCE, critChance, (u32, GEN_COUNT - 1)) \
F(CRIT_MULTIPLIER, critMultiplier, (u32, GEN_COUNT - 1)) \ F(CRIT_MULTIPLIER, critMultiplier, (u32, GEN_COUNT - 1)) \
@ -210,6 +210,16 @@
F(COUNTER_TRY_HIT_PARTNER, counterTryHitPartner, (u32, GEN_COUNT - 1)) \ F(COUNTER_TRY_HIT_PARTNER, counterTryHitPartner, (u32, GEN_COUNT - 1)) \
#define POKEMON_CONFIG_DEFINITIONS(F) \
F(POKERUS_ENABLED, pokerusEnabled, (u32, TRUE)) \
F(POKERUS_SPREAD_ADJACENCY, pokerusSpreadAdjacency, (u32, GEN_COUNT - 1)) \
F(POKERUS_SPREAD_DAYS_LEFT, pokerusSpreadDaysLeft, (u32, GEN_COUNT - 1)) \
F(POKERUS_INFECT_AGAIN, pokerusInfectAgain, (u32, GEN_COUNT - 1)) \
F(POKERUS_INFECT_EGG, pokerusInfectEgg, (u32, TRUE)) \
F(POKERUS_HERD_IMMUNITY, pokerusHerdImmunity, (u32, TRUE)) \
F(POKERUS_WEAK_VARIANT, pokerusWeakVariant, (u32, TRUE)) \
#define GET_CONFIG_MAXIMUM(_typeMaxValue, ...) INVOKE_WITH_B(GET_CONFIG_MAXIMUM_, _typeMaxValue) #define GET_CONFIG_MAXIMUM(_typeMaxValue, ...) INVOKE_WITH_B(GET_CONFIG_MAXIMUM_, _typeMaxValue)
#define GET_CONFIG_MAXIMUM_(_type, ...) FIRST(__VA_OPT__(FIRST(__VA_ARGS__),) MAX_BITS((sizeof(_type) * 8))) #define GET_CONFIG_MAXIMUM_(_type, ...) FIRST(__VA_OPT__(FIRST(__VA_ARGS__),) MAX_BITS((sizeof(_type) * 8)))
@ -217,7 +227,8 @@
enum ConfigTag enum ConfigTag
{ {
CONFIG_DEFINITIONS(UNPACK_CONFIG_ENUMS) BATTLE_CONFIG_DEFINITIONS(UNPACK_CONFIG_ENUMS)
POKEMON_CONFIG_DEFINITIONS(UNPACK_CONFIG_ENUMS)
CONFIG_COUNT CONFIG_COUNT
}; };

View File

@ -3,13 +3,15 @@
#include "constants/generational_changes.h" #include "constants/generational_changes.h"
#include "config/battle.h" #include "config/battle.h"
#include "config/pokerus.h"
#define UNPACK_CONFIG_STRUCT(_name, _field, _typeMaxValue, ...) INVOKE_WITH_(UNPACK_CONFIG_STRUCT_, _field, UNPACK_B(_typeMaxValue)); #define UNPACK_CONFIG_STRUCT(_name, _field, _typeMaxValue, ...) INVOKE_WITH_(UNPACK_CONFIG_STRUCT_, _field, UNPACK_B(_typeMaxValue));
#define UNPACK_CONFIG_STRUCT_(_field, _type, ...) _type FIRST(__VA_OPT__(_field:BIT_SIZE(FIRST(__VA_ARGS__)),) _field) #define UNPACK_CONFIG_STRUCT_(_field, _type, ...) _type FIRST(__VA_OPT__(_field:BIT_SIZE(FIRST(__VA_ARGS__)),) _field)
struct GenChanges struct GenChanges
{ {
CONFIG_DEFINITIONS(UNPACK_CONFIG_STRUCT) BATTLE_CONFIG_DEFINITIONS(UNPACK_CONFIG_STRUCT)
POKEMON_CONFIG_DEFINITIONS(UNPACK_CONFIG_STRUCT)
// Expands to: // Expands to:
// u32 critChance:4; // u32 critChance:4;
// u32 critMultiplier:4; // u32 critMultiplier:4;

View File

@ -65,6 +65,8 @@ enum MonData {
MON_DATA_FRIENDSHIP, MON_DATA_FRIENDSHIP,
MON_DATA_SMART, MON_DATA_SMART,
MON_DATA_POKERUS, MON_DATA_POKERUS,
MON_DATA_POKERUS_STRAIN,
MON_DATA_POKERUS_DAYS_LEFT,
MON_DATA_MET_LOCATION, MON_DATA_MET_LOCATION,
MON_DATA_MET_LEVEL, MON_DATA_MET_LEVEL,
MON_DATA_MET_GAME, MON_DATA_MET_GAME,
@ -832,11 +834,6 @@ void AdjustFriendship(struct Pokemon *mon, u8 event);
u8 CalculateFriendshipBonuses(struct Pokemon *mon, u32 modifier, enum HoldEffect itemHoldEffect); u8 CalculateFriendshipBonuses(struct Pokemon *mon, u32 modifier, enum HoldEffect itemHoldEffect);
void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies); void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies);
u16 GetMonEVCount(struct Pokemon *mon); u16 GetMonEVCount(struct Pokemon *mon);
void RandomlyGivePartyPokerus(struct Pokemon *party);
u8 CheckPartyPokerus(struct Pokemon *party, u8 selection);
u8 CheckPartyHasHadPokerus(struct Pokemon *party, u8 selection);
void UpdatePartyPokerusTime(u16 days);
void PartySpreadPokerus(struct Pokemon *party);
bool8 TryIncrementMonLevel(struct Pokemon *mon); bool8 TryIncrementMonLevel(struct Pokemon *mon);
u8 CanLearnTeachableMove(u16 species, enum Move move); u8 CanLearnTeachableMove(u16 species, enum Move move);
u32 GetRelearnerLevelUpMoves(struct Pokemon *mon, u16 *moves); u32 GetRelearnerLevelUpMoves(struct Pokemon *mon, u16 *moves);

14
include/pokerus.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef GUARD_POKERUS_H
#define GUARD_POKERUS_H
u32 GetDaysLeftBasedOnStrain(u32 strain);
void RandomlyGivePartyPokerus(void);
bool32 IsPokerusInParty(void);
bool32 CheckMonPokerus(struct Pokemon *mon);
bool32 CheckMonHasHadPokerus(struct Pokemon *mon);
bool32 ShouldPokemonShowActivePokerus(struct Pokemon *mon);
bool32 ShouldPokemonShowCuredPokerus(struct Pokemon *mon);
void UpdatePartyPokerusTime(u32 days);
void PartySpreadPokerus(void);
#endif // GUARD_POKERUS_H

View File

@ -218,6 +218,11 @@ enum RandomTag
RNG_AI_RANDOM_VALID_SWITCHIN_MID_BATTLE, RNG_AI_RANDOM_VALID_SWITCHIN_MID_BATTLE,
RNG_HEALER, RNG_HEALER,
RNG_DEXNAV_ENCOUNTER_LEVEL, RNG_DEXNAV_ENCOUNTER_LEVEL,
RNG_POKERUS_PARTY_MEMBER,
RNG_POKERUS_INFECTION,
RNG_POKERUS_STRAIN_DISTRIBUTION,
RNG_POKERUS_SPREAD,
RNG_POKERUS_SPREAD_SIDE,
RNG_AI_ASSUME_STATUS_SLEEP, RNG_AI_ASSUME_STATUS_SLEEP,
RNG_AI_ASSUME_STATUS_NONVOLATILE, RNG_AI_ASSUME_STATUS_NONVOLATILE,
RNG_AI_ASSUME_STATUS_HIGH_ODDS, RNG_AI_ASSUME_STATUS_HIGH_ODDS,

View File

@ -43,6 +43,7 @@
#include "pokeball.h" #include "pokeball.h"
#include "pokedex.h" #include "pokedex.h"
#include "pokemon.h" #include "pokemon.h"
#include "pokerus.h"
#include "random.h" #include "random.h"
#include "recorded_battle.h" #include "recorded_battle.h"
#include "roamer.h" #include "roamer.h"
@ -5665,8 +5666,9 @@ static void ReturnFromBattleToOverworld(void)
{ {
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) if (!(gBattleTypeFlags & BATTLE_TYPE_LINK))
{ {
RandomlyGivePartyPokerus(gPlayerParty); CalculatePlayerPartyCount();
PartySpreadPokerus(gPlayerParty); RandomlyGivePartyPokerus();
PartySpreadPokerus();
} }
if (gBattleTypeFlags & BATTLE_TYPE_LINK && gReceivedRemoteLinkPlayers) if (gBattleTypeFlags & BATTLE_TYPE_LINK && gReceivedRemoteLinkPlayers)

View File

@ -5,9 +5,10 @@
#include "event_data.h" #include "event_data.h"
#include "field_specials.h" #include "field_specials.h"
#include "field_weather.h" #include "field_weather.h"
#include "main.h"
#include "lottery_corner.h" #include "lottery_corner.h"
#include "main.h"
#include "overworld.h" #include "overworld.h"
#include "pokerus.h"
#include "rtc.h" #include "rtc.h"
#include "time_events.h" #include "time_events.h"
#include "tv.h" #include "tv.h"

View File

@ -285,6 +285,7 @@ static void DebugAction_PCBag_ClearBag(u8 taskId);
static void DebugAction_PCBag_ClearBoxes(u8 taskId); static void DebugAction_PCBag_ClearBoxes(u8 taskId);
static void DebugAction_Party_HealParty(u8 taskId); static void DebugAction_Party_HealParty(u8 taskId);
static void DebugAction_Party_ClearPokerus(u8 taskId);
static void DebugAction_Party_ClearParty(u8 taskId); static void DebugAction_Party_ClearParty(u8 taskId);
static void DebugAction_Party_SetParty(u8 taskId); static void DebugAction_Party_SetParty(u8 taskId);
static void DebugAction_Party_BattleSingle(u8 taskId); static void DebugAction_Party_BattleSingle(u8 taskId);
@ -366,6 +367,7 @@ extern const u8 Debug_FlagsAndVarNotSetBattleConfigMessage[];
extern const u8 Debug_EventScript_FontTest[]; extern const u8 Debug_EventScript_FontTest[];
extern const u8 Debug_EventScript_CheckEVs[]; extern const u8 Debug_EventScript_CheckEVs[];
extern const u8 Debug_EventScript_CheckIVs[]; extern const u8 Debug_EventScript_CheckIVs[];
extern const u8 Debug_EventScript_GivePokerus[];
extern const u8 Debug_EventScript_InflictStatus1[]; extern const u8 Debug_EventScript_InflictStatus1[];
extern const u8 Debug_EventScript_KoPokemon[]; extern const u8 Debug_EventScript_KoPokemon[];
extern const u8 Debug_EventScript_SetHiddenNature[]; extern const u8 Debug_EventScript_SetHiddenNature[];
@ -612,6 +614,8 @@ static const struct DebugMenuOption sDebugMenu_Actions_Party[] =
{ COMPOUND_STRING("Edit Pokemon"), DebugAction_OpenSubMenu, sDebugMenu_Actions_EditPokemon }, { COMPOUND_STRING("Edit Pokemon"), DebugAction_OpenSubMenu, sDebugMenu_Actions_EditPokemon },
{ COMPOUND_STRING("Check EVs"), DebugAction_ExecuteScript, Debug_EventScript_CheckEVs }, { COMPOUND_STRING("Check EVs"), DebugAction_ExecuteScript, Debug_EventScript_CheckEVs },
{ COMPOUND_STRING("Check IVs"), DebugAction_ExecuteScript, Debug_EventScript_CheckIVs }, { COMPOUND_STRING("Check IVs"), DebugAction_ExecuteScript, Debug_EventScript_CheckIVs },
{ COMPOUND_STRING("Give Pokerus"), DebugAction_ExecuteScript, Debug_EventScript_GivePokerus },
{ COMPOUND_STRING("Clear Pokerus"), DebugAction_Party_ClearPokerus},
{ COMPOUND_STRING("Clear Party"), DebugAction_Party_ClearParty }, { COMPOUND_STRING("Clear Party"), DebugAction_Party_ClearParty },
{ COMPOUND_STRING("Set Party"), DebugAction_Party_SetParty }, { COMPOUND_STRING("Set Party"), DebugAction_Party_SetParty },
{ COMPOUND_STRING("Start Debug Battle"), DebugAction_Party_BattleSingle }, { COMPOUND_STRING("Start Debug Battle"), DebugAction_Party_BattleSingle },
@ -4708,15 +4712,127 @@ void DebugNative_Party_SetFriendship(void)
} }
} }
#undef tPartyId
#undef tFriendship #undef tFriendship
#define tStrain data[6]
static void Debug_Display_PokerusDaysLeftInfo(s32 daysLeft, s32 strain, u32 digit, u8 windowId)
{
ConvertIntToDecimalStringN(gStringVar1, daysLeft, STR_CONV_MODE_LEADING_ZEROS, 2);
if (daysLeft == 0 && strain)
StringCopy(gStringVar2, COMPOUND_STRING("Inactive"));
else if (daysLeft == 0)
StringCopy(gStringVar2, COMPOUND_STRING("No Pokerus"));
else
StringCopy(gStringVar2, COMPOUND_STRING(""));
StringCopy(gStringVar3, gText_DigitIndicator[digit]);
StringExpandPlaceholders(gStringVar4, COMPOUND_STRING("Days Left:\n{STR_VAR_1}\n{STR_VAR_2}{CLEAR_TO 90}\n{STR_VAR_3}"));
AddTextPrinterParameterized(windowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL);
}
static void DebugNativeStep_Party_SetPokerusDaysLeftSelect(u8 taskId)
{
if (JOY_NEW(A_BUTTON))
{
PlaySE(SE_SELECT);
SetMonData(&gPlayerParty[gTasks[taskId].tPartyId], MON_DATA_POKERUS_DAYS_LEFT, &gTasks[taskId].tInput);
DebugNativeStep_CloseDebugWindow(taskId);
return;
}
else if (JOY_NEW(B_BUTTON))
{
PlaySE(SE_SELECT);
DebugNativeStep_CloseDebugWindow(taskId);
return;
}
Debug_HandleInput_Numeric(taskId, 0, 15, 2);
if (JOY_NEW(DPAD_ANY) || JOY_NEW(A_BUTTON))
Debug_Display_PokerusDaysLeftInfo(gTasks[taskId].tInput, gTasks[taskId].tStrain, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId);
}
static void Debug_Display_PokerusStrainInfo(s32 strain, u32 digit, u8 windowId)
{
ConvertIntToDecimalStringN(gStringVar1, strain, STR_CONV_MODE_LEADING_ZEROS, 2);
StringCopy(gStringVar3, gText_DigitIndicator[digit]);
StringExpandPlaceholders(gStringVar4, COMPOUND_STRING("Strain:\n{STR_VAR_1}\n\n{STR_VAR_3}"));
AddTextPrinterParameterized(windowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL);
}
static void DebugNativeStep_Party_SetPokerusStrainSelect(u8 taskId)
{
if (JOY_NEW(A_BUTTON))
{
PlaySE(SE_SELECT);
gTasks[taskId].tStrain = gTasks[taskId].tInput;
SetMonData(&gPlayerParty[gTasks[taskId].tPartyId], MON_DATA_POKERUS_STRAIN, &gTasks[taskId].tInput);
gTasks[taskId].tInput = GetMonData(&gPlayerParty[gTasks[taskId].tPartyId], MON_DATA_POKERUS_DAYS_LEFT);
Debug_Display_PokerusDaysLeftInfo(gTasks[taskId].tInput, gTasks[taskId].tStrain, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId);
gTasks[taskId].func = DebugNativeStep_Party_SetPokerusDaysLeftSelect;
return;
}
else if (JOY_NEW(B_BUTTON))
{
PlaySE(SE_SELECT);
DebugNativeStep_CloseDebugWindow(taskId);
return;
}
Debug_HandleInput_Numeric(taskId, 0, 15, 2);
if (JOY_NEW(DPAD_ANY) || JOY_NEW(A_BUTTON))
Debug_Display_PokerusStrainInfo(gTasks[taskId].tInput, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId);
}
static void DebugNativeStep_Party_SetPokerusMain(u8 taskId)
{
u8 windowId = DebugNativeStep_CreateDebugWindow();
u32 strain = GetMonData(&gPlayerParty[gTasks[taskId].tPartyId], MON_DATA_POKERUS_STRAIN);
// Display initial flag
Debug_Display_PokerusStrainInfo(strain, 0, windowId);
gTasks[taskId].func = DebugNativeStep_Party_SetPokerusStrainSelect;
gTasks[taskId].tSubWindowId = windowId;
gTasks[taskId].tStrain = strain;
gTasks[taskId].tInput = strain;
gTasks[taskId].tDigit = 0;
gTasks[taskId].tPartyId = 0;
}
void DebugNative_Party_SetPokerus(void)
{
if (gSpecialVar_0x8004 < PARTY_SIZE)
{
u32 taskId = CreateTask(DebugNativeStep_Party_SetPokerusMain, 1);
gTasks[taskId].tPartyId = gSpecialVar_0x8004;
}
}
#undef tStrain
#undef tPartyId
#undef tMenuTaskId #undef tMenuTaskId
#undef tWindowId #undef tWindowId
#undef tSubWindowId #undef tSubWindowId
#undef tInput #undef tInput
#undef tDigit #undef tDigit
static void DebugAction_Party_ClearPokerus(u8 taskId)
{
for (u32 i = 0; i < PARTY_SIZE; i++)
{
if (!GetMonData(&gPlayerParty[i], MON_DATA_SPECIES))
continue;
u32 data = 0;
SetMonData(&gPlayerParty[i], MON_DATA_POKERUS, &data);
}
ScriptContext_Enable();
Debug_DestroyMenu_Full(taskId);
}
static void DebugAction_Party_ClearParty(u8 taskId) static void DebugAction_Party_ClearParty(u8 taskId)
{ {
ZeroPlayerPartyMons(); ZeroPlayerPartyMons();

View File

@ -1519,14 +1519,6 @@ bool8 ScriptCheckFreePokemonStorageSpace(void)
return CheckFreePokemonStorageSpace(); return CheckFreePokemonStorageSpace();
} }
bool8 IsPokerusInParty(void)
{
if (!CheckPartyPokerus(gPlayerParty, (1 << PARTY_SIZE) - 1))
return FALSE;
return TRUE;
}
// Task data for Task_ShakeCamera // Task data for Task_ShakeCamera
#define tHorizontalPan data[0] #define tHorizontalPan data[0]
#define tDelayCounter data[1] #define tDelayCounter data[1]

View File

@ -2,12 +2,15 @@
#include "generational_changes.h" #include "generational_changes.h"
#include "malloc.h" #include "malloc.h"
#include "constants/generational_changes.h" #include "constants/generational_changes.h"
#include "config/pokerus.h"
#define UNPACK_CONFIG_GEN_CHANGES2(_name, _field, ...) ._field = B_##_name, #define UNPACK_BATTLE_CONFIG_GEN_CHANGES(_name, _field, ...) ._field = B_##_name,
#define UNPACK_POKEMON_CONFIG_GEN_CHANGES(_name, _field, ...) ._field = P_##_name,
const struct GenChanges sConfigChanges = const struct GenChanges sConfigChanges =
{ {
CONFIG_DEFINITIONS(UNPACK_CONFIG_GEN_CHANGES2) BATTLE_CONFIG_DEFINITIONS(UNPACK_BATTLE_CONFIG_GEN_CHANGES)
POKEMON_CONFIG_DEFINITIONS(UNPACK_POKEMON_CONFIG_GEN_CHANGES)
/* Expands to: /* Expands to:
.critChance = B_CRIT_CHANCE, .critChance = B_CRIT_CHANCE,
.critMultiplier = B_CRIT_MULTIPLIER, .critMultiplier = B_CRIT_MULTIPLIER,
@ -29,8 +32,6 @@ EWRAM_DATA struct GenChanges *gConfigChangesTestOverride = NULL;
#define UNPACK_CONFIG_SETTERS(_name, _field, ...) case CONFIG_##_name: return; #define UNPACK_CONFIG_SETTERS(_name, _field, ...) case CONFIG_##_name: return;
#endif #endif
// Gets the value of a volatile status flag for a certain battler
// Primarily used for the debug menu and scripts. Outside of it explicit references are preferred
u32 GetConfig(enum ConfigTag _genConfig) u32 GetConfig(enum ConfigTag _genConfig)
{ {
#if TESTING #if TESTING
@ -38,7 +39,8 @@ u32 GetConfig(enum ConfigTag _genConfig)
{ {
switch (_genConfig) switch (_genConfig)
{ {
CONFIG_DEFINITIONS(UNPACK_CONFIG_GETTERS) BATTLE_CONFIG_DEFINITIONS(UNPACK_CONFIG_GETTERS)
POKEMON_CONFIG_DEFINITIONS(UNPACK_CONFIG_GETTERS)
/* Expands to: /* Expands to:
case CONFIG_CRIT_CHANCE: case CONFIG_CRIT_CHANCE:
return gConfigChangesTestOverride->critChance; return gConfigChangesTestOverride->critChance;
@ -52,7 +54,8 @@ u32 GetConfig(enum ConfigTag _genConfig)
{ {
switch (_genConfig) switch (_genConfig)
{ {
CONFIG_DEFINITIONS(UNPACK_CONFIG_OVERRIDE_GETTERS) BATTLE_CONFIG_DEFINITIONS(UNPACK_CONFIG_OVERRIDE_GETTERS)
POKEMON_CONFIG_DEFINITIONS(UNPACK_CONFIG_OVERRIDE_GETTERS)
/* Expands to: /* Expands to:
case CONFIG_CRIT_CHANCE: case CONFIG_CRIT_CHANCE:
return sConfigChanges.critChance; return sConfigChanges.critChance;
@ -69,7 +72,8 @@ u32 GetClampedValue(enum ConfigTag _genConfig, u32 newValue)
u32 clampedValue = 0; u32 clampedValue = 0;
switch(_genConfig) switch(_genConfig)
{ {
CONFIG_DEFINITIONS(UNPACK_CONFIG_CLAMPER) BATTLE_CONFIG_DEFINITIONS(UNPACK_CONFIG_CLAMPER)
POKEMON_CONFIG_DEFINITIONS(UNPACK_CONFIG_CLAMPER)
default: default:
return 0; return 0;
} }
@ -84,7 +88,8 @@ void SetConfig(enum ConfigTag _genConfig, u32 _value)
u32 clampedValue = GetClampedValue(_genConfig, _value); u32 clampedValue = GetClampedValue(_genConfig, _value);
switch (_genConfig) switch (_genConfig)
{ {
CONFIG_DEFINITIONS(UNPACK_CONFIG_SETTERS) BATTLE_CONFIG_DEFINITIONS(UNPACK_CONFIG_SETTERS)
POKEMON_CONFIG_DEFINITIONS(UNPACK_CONFIG_SETTERS)
/* Expands to: /* Expands to:
#if TESTING #if TESTING
case CONFIG_CRIT_CHANCE: case CONFIG_CRIT_CHANCE:

View File

@ -53,6 +53,7 @@
#include "pokemon_jump.h" #include "pokemon_jump.h"
#include "pokemon_storage_system.h" #include "pokemon_storage_system.h"
#include "pokemon_summary_screen.h" #include "pokemon_summary_screen.h"
#include "pokerus.h"
#include "region_map.h" #include "region_map.h"
#include "reshow_battle_screen.h" #include "reshow_battle_screen.h"
#include "scanline_effect.h" #include "scanline_effect.h"
@ -2172,7 +2173,7 @@ u8 GetMonAilment(struct Pokemon *mon)
ailment = GetAilmentFromStatus(GetMonData(mon, MON_DATA_STATUS)); ailment = GetAilmentFromStatus(GetMonData(mon, MON_DATA_STATUS));
if (ailment != AILMENT_NONE) if (ailment != AILMENT_NONE)
return ailment; return ailment;
if (CheckPartyPokerus(mon, 0)) if (ShouldPokemonShowActivePokerus(mon))
return AILMENT_PKRS; return AILMENT_PKRS;
return AILMENT_NONE; return AILMENT_NONE;
} }

View File

@ -39,6 +39,7 @@
#include "pokemon_icon.h" #include "pokemon_icon.h"
#include "pokemon_summary_screen.h" #include "pokemon_summary_screen.h"
#include "pokemon_storage_system.h" #include "pokemon_storage_system.h"
#include "pokerus.h"
#include "random.h" #include "random.h"
#include "recorded_battle.h" #include "recorded_battle.h"
#include "regions.h" #include "regions.h"
@ -2387,6 +2388,12 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
case MON_DATA_POKERUS: case MON_DATA_POKERUS:
retVal = GetSubstruct3(boxMon)->pokerus; retVal = GetSubstruct3(boxMon)->pokerus;
break; break;
case MON_DATA_POKERUS_STRAIN:
retVal = ((GetSubstruct3(boxMon)->pokerus & 0xF0) >> 4);
break;
case MON_DATA_POKERUS_DAYS_LEFT:
retVal = (GetSubstruct3(boxMon)->pokerus & 0x0F);
break;
case MON_DATA_MET_LOCATION: case MON_DATA_MET_LOCATION:
retVal = GetSubstruct3(boxMon)->metLocation; retVal = GetSubstruct3(boxMon)->metLocation;
break; break;
@ -2896,6 +2903,12 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg)
case MON_DATA_POKERUS: case MON_DATA_POKERUS:
SET8(GetSubstruct3(boxMon)->pokerus); SET8(GetSubstruct3(boxMon)->pokerus);
break; break;
case MON_DATA_POKERUS_STRAIN:
GetSubstruct3(boxMon)->pokerus = (*data << 4) | (GetSubstruct3(boxMon)->pokerus & 0x0F);
break;
case MON_DATA_POKERUS_DAYS_LEFT:
GetSubstruct3(boxMon)->pokerus = (GetSubstruct3(boxMon)->pokerus & 0xF0) | *data;
break;
case MON_DATA_MET_LOCATION: case MON_DATA_MET_LOCATION:
SET8(GetSubstruct3(boxMon)->metLocation); SET8(GetSubstruct3(boxMon)->metLocation);
break; break;
@ -5236,7 +5249,7 @@ void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies)
if (totalEVs >= currentEVCap) if (totalEVs >= currentEVCap)
break; break;
if (CheckPartyHasHadPokerus(mon, 0)) if (CheckMonHasHadPokerus(mon))
multiplier = 2; multiplier = 2;
else else
multiplier = 1; multiplier = 1;
@ -5313,152 +5326,6 @@ u16 GetMonEVCount(struct Pokemon *mon)
return count; return count;
} }
void RandomlyGivePartyPokerus(struct Pokemon *party)
{
u16 rnd = Random();
if (rnd == 0x4000 || rnd == 0x8000 || rnd == 0xC000)
{
struct Pokemon *mon;
do
{
rnd = Random() % PARTY_SIZE;
mon = &party[rnd];
}
while (!GetMonData(mon, MON_DATA_SPECIES, 0) || GetMonData(mon, MON_DATA_IS_EGG, 0));
if (!(CheckPartyHasHadPokerus(party, 1u << rnd)))
{
u8 rnd2;
do
{
rnd2 = Random();
}
while ((rnd2 & 0x7) == 0);
if (rnd2 & 0xF0)
rnd2 &= 0x7;
rnd2 |= (rnd2 << 4);
rnd2 &= 0xF3;
rnd2++;
SetMonData(&party[rnd], MON_DATA_POKERUS, &rnd2);
}
}
}
u8 CheckPartyPokerus(struct Pokemon *party, u8 selection)
{
u8 retVal;
int partyIndex = 0;
unsigned curBit = 1;
retVal = 0;
if (selection)
{
do
{
if ((selection & 1) && (GetMonData(&party[partyIndex], MON_DATA_POKERUS, 0) & 0xF))
retVal |= curBit;
partyIndex++;
curBit <<= 1;
selection >>= 1;
}
while (selection);
}
else if (GetMonData(&party[0], MON_DATA_POKERUS, 0) & 0xF)
{
retVal = 1;
}
return retVal;
}
u8 CheckPartyHasHadPokerus(struct Pokemon *party, u8 selection)
{
u8 retVal;
int partyIndex = 0;
unsigned curBit = 1;
retVal = 0;
if (selection)
{
do
{
if ((selection & 1) && GetMonData(&party[partyIndex], MON_DATA_POKERUS, 0))
retVal |= curBit;
partyIndex++;
curBit <<= 1;
selection >>= 1;
}
while (selection);
}
else if (GetMonData(&party[0], MON_DATA_POKERUS, 0))
{
retVal = 1;
}
return retVal;
}
void UpdatePartyPokerusTime(u16 days)
{
int i;
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, 0))
{
u8 pokerus = GetMonData(&gPlayerParty[i], MON_DATA_POKERUS, 0);
if (pokerus & 0xF)
{
if ((pokerus & 0xF) < days || days > 4)
pokerus &= 0xF0;
else
pokerus -= days;
if (pokerus == 0)
pokerus = 0x10;
SetMonData(&gPlayerParty[i], MON_DATA_POKERUS, &pokerus);
}
}
}
}
void PartySpreadPokerus(struct Pokemon *party)
{
if ((Random() % 3) == 0)
{
int i;
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&party[i], MON_DATA_SPECIES, 0))
{
u8 pokerus = GetMonData(&party[i], MON_DATA_POKERUS, 0);
u8 curPokerus = pokerus;
if (pokerus)
{
if (pokerus & 0xF)
{
// Spread to adjacent party members.
if (i != 0 && !(GetMonData(&party[i - 1], MON_DATA_POKERUS, 0) & 0xF0))
SetMonData(&party[i - 1], MON_DATA_POKERUS, &curPokerus);
if (i != (PARTY_SIZE - 1) && !(GetMonData(&party[i + 1], MON_DATA_POKERUS, 0) & 0xF0))
{
SetMonData(&party[i + 1], MON_DATA_POKERUS, &curPokerus);
i++;
}
}
}
}
}
}
}
bool8 TryIncrementMonLevel(struct Pokemon *mon) bool8 TryIncrementMonLevel(struct Pokemon *mon)
{ {
u16 species = GetMonData(mon, MON_DATA_SPECIES, 0); u16 species = GetMonData(mon, MON_DATA_SPECIES, 0);

View File

@ -33,6 +33,7 @@
#include "pokemon_sprite_visualizer.h" #include "pokemon_sprite_visualizer.h"
#include "pokemon_storage_system.h" #include "pokemon_storage_system.h"
#include "pokemon_summary_screen.h" #include "pokemon_summary_screen.h"
#include "pokerus.h"
#include "region_map.h" #include "region_map.h"
#include "scanline_effect.h" #include "scanline_effect.h"
#include "sound.h" #include "sound.h"
@ -3129,7 +3130,7 @@ static void TilemapFiveMovesDisplay(u16 *dst, u16 palette, bool8 remove)
static void DrawPokerusCuredSymbol(struct Pokemon *mon) // This checks if the mon has been cured of pokerus static void DrawPokerusCuredSymbol(struct Pokemon *mon) // This checks if the mon has been cured of pokerus
{ {
if (!CheckPartyPokerus(mon, 0) && CheckPartyHasHadPokerus(mon, 0)) // If yes it draws the cured symbol if (ShouldPokemonShowCuredPokerus(mon))
{ {
sMonSummaryScreen->bgTilemapBuffers[PSS_PAGE_INFO][0][0x223] = 0x2C; sMonSummaryScreen->bgTilemapBuffers[PSS_PAGE_INFO][0][0x223] = 0x2C;
sMonSummaryScreen->bgTilemapBuffers[PSS_PAGE_INFO][1][0x223] = 0x2C; sMonSummaryScreen->bgTilemapBuffers[PSS_PAGE_INFO][1][0x223] = 0x2C;

218
src/pokerus.c Normal file
View File

@ -0,0 +1,218 @@
#include "global.h"
#include "event_data.h"
#include "generational_changes.h"
#include "pokemon.h"
#include "pokerus.h"
#include "random.h"
#include "config/pokerus.h"
u32 GetDaysLeftBasedOnStrain(u32 strain)
{
u32 daysLeft = (strain % 4) + 1;
return daysLeft;
}
static u32 GetRandomPokerusStrain(void)
{
if (P_POKERUS_STRAIN_DISTRIBUTION < GEN_3) // Gen 1 - 2 (Gen 1 had no Pokérus but we default it with gen 2)
return RandomWeighted(RNG_POKERUS_STRAIN_DISTRIBUTION, 15, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1);
else if (P_POKERUS_STRAIN_DISTRIBUTION < GEN_4) //Gen 3 (Ruby/Sapphire only)
return RandomWeighted(RNG_POKERUS_STRAIN_DISTRIBUTION, 30, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1);
else // Gen 4+ (Pokérus was disabled in gen 9 but we default it here)
return RandomWeighted(RNG_POKERUS_STRAIN_DISTRIBUTION, 0, 31, 31, 31, 31, 31, 31, 31, 0, 1, 1, 1, 1, 1, 1, 1);
}
void RandomlyGivePartyPokerus(void)
{
if (!GetConfig(CONFIG_POKERUS_ENABLED))
return;
if ((GetConfig(CONFIG_POKERUS_INFECT_AGAIN) > GEN_2) && IsPokerusInParty())
return;
if (P_POKERUS_FLAG_INFECTION && !FlagGet(P_POKERUS_FLAG_INFECTION))
return;
if (RandomUniform(RNG_POKERUS_INFECTION, 0, MAX_u16) < P_POKERUS_INFECTION_ODDS)
{
struct Pokemon *mon;
u32 randomIndex;
u32 validTargetsCount = 0;
s32 validTargets[PARTY_SIZE];
for (u32 i = 0; i < PARTY_SIZE; i++)
{
mon = &gPlayerParty[i];
if (!GetMonData(mon, MON_DATA_SPECIES))
continue;
else if (!GetConfig(CONFIG_POKERUS_INFECT_EGG) && GetMonData(mon, MON_DATA_IS_EGG))
continue;
else if (!GetConfig(CONFIG_POKERUS_HERD_IMMUNITY) && CheckMonHasHadPokerus(mon))
continue;
validTargets[validTargetsCount] = i;
validTargetsCount++;
}
if (validTargetsCount == 0)
return;
randomIndex = RandomUniform(RNG_POKERUS_PARTY_MEMBER, 0, validTargetsCount - 1);
mon = &gPlayerParty[validTargets[randomIndex]];
if (!CheckMonHasHadPokerus(mon))
{
u32 strain = GetRandomPokerusStrain();
u32 daysLeft = GetDaysLeftBasedOnStrain(strain);
SetMonData(mon, MON_DATA_POKERUS_STRAIN, &strain);
SetMonData(mon, MON_DATA_POKERUS_DAYS_LEFT, &daysLeft);
}
}
}
bool32 IsPokerusInParty(void)
{
if (!GetConfig(CONFIG_POKERUS_ENABLED))
return FALSE;
for (u32 i = 0; i < PARTY_SIZE; i++)
{
if (!GetMonData(&gPlayerParty[i], MON_DATA_SPECIES))
continue;
if (GetMonData(&gPlayerParty[i], MON_DATA_POKERUS_DAYS_LEFT))
return TRUE;
}
return FALSE;
}
bool32 CheckMonPokerus(struct Pokemon *mon)
{
if (!GetConfig(CONFIG_POKERUS_ENABLED))
return FALSE;
if (GetMonData(mon, MON_DATA_POKERUS_DAYS_LEFT))
return TRUE;
return FALSE;
}
bool32 CheckMonHasHadPokerus(struct Pokemon *mon)
{
if (!GetConfig(CONFIG_POKERUS_ENABLED))
return FALSE;
if (GetMonData(mon, MON_DATA_POKERUS))
return TRUE;
return FALSE;
}
bool32 IsPokerusVisible(struct Pokemon *mon)
{
if ((P_POKERUS_VISIBLE_ON_EGG >= GEN_3 && P_POKERUS_VISIBLE_ON_EGG <= GEN_6) || !GetMonData(mon, MON_DATA_IS_EGG))
return TRUE;
return FALSE;
}
bool32 ShouldPokemonShowActivePokerus(struct Pokemon *mon)
{
if (!IsPokerusVisible(mon))
return FALSE;
return CheckMonPokerus(mon);
}
bool32 ShouldPokemonShowCuredPokerus(struct Pokemon *mon)
{
if (!IsPokerusVisible(mon))
return FALSE;
if (CheckMonPokerus(mon))
return FALSE;
return CheckMonHasHadPokerus(mon);
}
void UpdatePartyPokerusTime(u32 days)
{
if (!GetConfig(CONFIG_POKERUS_ENABLED))
return;
for (u32 i = 0; i < PARTY_SIZE; i++)
{
if (!GetMonData(&gPlayerParty[i], MON_DATA_SPECIES))
continue;
u32 strain = GetMonData(&gPlayerParty[i], MON_DATA_POKERUS_STRAIN);
u32 daysLeft = GetMonData(&gPlayerParty[i], MON_DATA_POKERUS_DAYS_LEFT);
if (daysLeft)
{
if (daysLeft < days)
daysLeft = 0;
else
daysLeft -= days;
//If the strain was 0, we changed it to 1 when the Pokérus disappear to remember the Pokémon was infected by Pokérus
// (otherwise its data would look the same as unaffected Pokémon)
if (daysLeft == 0 && strain == 0)
{
strain = 1;
SetMonData(&gPlayerParty[i], MON_DATA_POKERUS_STRAIN, &strain);
}
SetMonData(&gPlayerParty[i], MON_DATA_POKERUS_DAYS_LEFT, &daysLeft);
}
}
}
static void SpreadPokerusToSpecificMon(struct Pokemon *mon, u32 strain, u32 daysLeft)
{
SetMonData(mon, MON_DATA_POKERUS_STRAIN, &strain);
if (GetConfig(CONFIG_POKERUS_SPREAD_DAYS_LEFT) < GEN_3)
daysLeft = GetDaysLeftBasedOnStrain(strain);
SetMonData(mon, MON_DATA_POKERUS_DAYS_LEFT, &daysLeft);
}
static bool32 CanReceivePokerusFromSpread(struct Pokemon *mon)
{
if (GetConfig(CONFIG_POKERUS_WEAK_VARIANT))
return !GetMonData(mon, MON_DATA_POKERUS_STRAIN);
return !GetMonData(mon, MON_DATA_POKERUS);
}
void PartySpreadPokerus(void)
{
if (!GetConfig(CONFIG_POKERUS_ENABLED))
return;
if (RandomUniform(RNG_POKERUS_SPREAD, 0, MAX_u16) >= P_POKERUS_SPREAD_ODDS)
return;
for (u32 i = 0; i < PARTY_SIZE; i++)
{
if (!GetMonData(&gPlayerParty[i], MON_DATA_SPECIES))
continue;
u32 strain = GetMonData(&gPlayerParty[i], MON_DATA_POKERUS_STRAIN);
u32 daysLeft = GetMonData(&gPlayerParty[i], MON_DATA_POKERUS_DAYS_LEFT);
if (daysLeft)
{
bool32 spreadUp = TRUE, spreadDown = TRUE;
if (GetConfig(CONFIG_POKERUS_SPREAD_ADJACENCY) < GEN_3)
{
if (i == (gPlayerPartyCount - 1))
spreadUp = FALSE;
else if (RandomUniform(RNG_POKERUS_SPREAD_SIDE, 0, 1))
spreadDown = FALSE;
else
spreadUp = FALSE;
}
if (spreadDown && i != 0 && CanReceivePokerusFromSpread(&gPlayerParty[i - 1]))
SpreadPokerusToSpecificMon(&gPlayerParty[i - 1], strain, daysLeft);
if (spreadUp && i != (PARTY_SIZE - 1) && CanReceivePokerusFromSpread(&gPlayerParty[i + 1]))
{
SpreadPokerusToSpecificMon(&gPlayerParty[i + 1], strain, daysLeft);
i++;
}
}
}
}

704
test/pokerus.c Normal file
View File

@ -0,0 +1,704 @@
#include "global.h"
#include "malloc.h"
#include "event_data.h"
#include "pokemon.h"
#include "pokerus.h"
#include "generational_changes.h"
#include "random.h"
#include "test/overworld_script.h"
#include "test/test.h"
#include "config/pokerus.h"
TEST("(Pokerus) No infection when POKERUS_ENABLED is false")
{
bool32 enabled;
PARAMETRIZE { enabled = TRUE; }
PARAMETRIZE { enabled = FALSE; }
SetConfig(CONFIG_POKERUS_ENABLED, enabled);
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
SET_RNG(RNG_POKERUS_INFECTION, 0);
CalculatePlayerPartyCount();
RandomlyGivePartyPokerus();
EXPECT_EQ((GetMonData(&gPlayerParty[0], MON_DATA_POKERUS) > 0), enabled);
}
TEST("(Pokerus) RandomlyGivePartyPokerus doesn't freeze if the party is empty")
{
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
ZeroPlayerPartyMons();
SET_RNG(RNG_POKERUS_INFECTION, 0);
CalculatePlayerPartyCount();
RandomlyGivePartyPokerus();
EXPECT_EQ(gPlayerPartyCount, 0);
}
TEST("(Pokerus) Eggs can only be infected if POKERUS_INFECT_EGG is TRUE")
{
bool32 infectEgg;
PARAMETRIZE { infectEgg = TRUE; }
PARAMETRIZE { infectEgg = FALSE; }
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
SetConfig(CONFIG_POKERUS_INFECT_EGG, infectEgg);
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
bool32 isEgg = TRUE;
SetMonData(&gPlayerParty[0], MON_DATA_IS_EGG, &isEgg);
SET_RNG(RNG_POKERUS_INFECTION, 0);
CalculatePlayerPartyCount();
RandomlyGivePartyPokerus();
EXPECT_EQ((GetMonData(&gPlayerParty[0], MON_DATA_POKERUS) > 0), infectEgg);
}
TEST("(Pokerus) No infection when POKERUS_INFECT_AGAIN is false and you already have active pokerus in party")
{
u32 infectAgain;
PARAMETRIZE { infectAgain = GEN_2; }
PARAMETRIZE { infectAgain = GEN_3; }
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
SetConfig(CONFIG_POKERUS_INFECT_AGAIN, infectAgain);
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100;
givemon SPECIES_PIKACHU, 100;
);
u8 pokerus = 1;
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS, &pokerus);
SET_RNG(RNG_POKERUS_INFECTION, 0);
CalculatePlayerPartyCount();
RandomlyGivePartyPokerus();
EXPECT_EQ((GetMonData(&gPlayerParty[1], MON_DATA_POKERUS) > 0), infectAgain == GEN_2);
}
TEST("(Pokerus) Test POKERUS_HERD_IMMUNITY config in RandomlyGivePartyPokerus")
{
u32 herdImmunity;
PARAMETRIZE { herdImmunity = TRUE; }
PARAMETRIZE { herdImmunity = FALSE; }
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
SetConfig(CONFIG_POKERUS_HERD_IMMUNITY, herdImmunity);
SetConfig(CONFIG_POKERUS_INFECT_AGAIN, GEN_2);
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100;
givemon SPECIES_PIKACHU, 100;
);
u8 pokerus = 1;
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS, &pokerus);
SET_RNG(RNG_POKERUS_INFECTION, 0);
SET_RNG(RNG_POKERUS_PARTY_MEMBER, 0);
CalculatePlayerPartyCount();
RandomlyGivePartyPokerus();
EXPECT_EQ((GetMonData(&gPlayerParty[1], MON_DATA_POKERUS) == 0), herdImmunity);
}
#if P_POKERUS_FLAG_INFECTION
TEST("(Pokerus) No infection when P_POKERUS_FLAG_INFECTION is clear")
{
u32 flag;
PARAMETRIZE { flag = TRUE; }
PARAMETRIZE { flag = FALSE; }
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100;
givemon SPECIES_PIKACHU, 100;
);
u8 pokerus = 1;
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS, &pokerus);
if (flag)
FlagSet(P_POKERUS_FLAG_INFECTION);
else
FlagClear(P_POKERUS_FLAG_INFECTION);
SET_RNG(RNG_POKERUS_INFECTION, 0);
CalculatePlayerPartyCount();
RandomlyGivePartyPokerus();
EXPECT_EQ((GetMonData(&gPlayerParty[1], MON_DATA_POKERUS) > 0), flag);
}
#endif
TEST("(Pokerus) Test GetMonData for MON_DATA_POKERUS_DAYS_LEFT and MON_DATA_POKERUS_STRAIN")
{
u32 strain = 0;
u32 daysLeft = 0;
for (u32 i = 0; i < 16; i++)
{
for (u32 j = 0; j < 16; j++)
{
PARAMETRIZE { strain = i; daysLeft = j;}
}
}
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100;
);
u8 pokerus = (strain << 4) | daysLeft;
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS, &pokerus);
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS_STRAIN), strain);
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS_DAYS_LEFT), daysLeft);
}
TEST("(Pokerus) Test SetMonData for MON_DATA_POKERUS_DAYS_LEFT and MON_DATA_POKERUS_STRAIN")
{
u32 strain = 0;
u32 daysLeft = 0;
for (u32 i = 0; i < 16; i++)
{
for (u32 j = 0; j < 16; j++)
{
PARAMETRIZE { strain = i; daysLeft = j; }
}
}
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100;
);
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS_STRAIN, &strain);
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS_DAYS_LEFT, &daysLeft);
u8 pokerus = (strain << 4) | daysLeft;
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS), pokerus);
}
TEST("(Pokerus) Test IsPokerusInParty general behavior")
{
u32 enabled = 0;
u32 partyMember = 0;
u32 pokerus = 0;
for (u32 i = 0; i < PARTY_SIZE; i++)
{
for (u32 j = 0; j <= MAX_u8; j++)
{
if ((j & 0x0F) == 0)
continue;
PARAMETRIZE { enabled = TRUE; partyMember = i; pokerus = j; }
PARAMETRIZE { enabled = FALSE; partyMember = i, pokerus = j; }
}
}
SetConfig(CONFIG_POKERUS_ENABLED, enabled);
ZeroPlayerPartyMons();
for (u32 i = 0; i < PARTY_SIZE; i++)
{
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
}
EXPECT_EQ(IsPokerusInParty(), FALSE);
u32 tmp = pokerus;
SetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS, &tmp);
EXPECT_EQ(IsPokerusInParty(), enabled);
}
TEST("(Pokerus) Test CheckMonPokerus general behavior")
{
u32 enabled = 0;
u32 pokerus = 0;
for (u32 i = 0; i < PARTY_SIZE; i++)
{
for (u32 j = 0; j <= MAX_u8; j++)
{
if ((j & 0x0F) == 0)
continue;
PARAMETRIZE { enabled = TRUE; pokerus = j; }
PARAMETRIZE { enabled = FALSE; pokerus = j; }
}
}
SetConfig(CONFIG_POKERUS_ENABLED, enabled);
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
EXPECT_EQ(CheckMonPokerus(&gPlayerParty[0]), FALSE);
u32 tmp = pokerus;
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS, &tmp);
EXPECT_EQ(CheckMonPokerus(&gPlayerParty[0]), enabled);
}
TEST("(Pokerus) Test CheckMonHasHadPokerus general behavior")
{
u32 enabled = 0;
u32 pokerus = 0;
for (u32 i = 0; i < PARTY_SIZE; i++)
{
for (u32 j = 1; j <= MAX_u8; j++)
{
PARAMETRIZE { enabled = TRUE; pokerus = j; }
PARAMETRIZE { enabled = FALSE; pokerus = j; }
}
}
SetConfig(CONFIG_POKERUS_ENABLED, enabled);
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
EXPECT_EQ(CheckMonHasHadPokerus(&gPlayerParty[0]), FALSE);
u32 tmp = pokerus;
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS, &tmp);
EXPECT_EQ(CheckMonHasHadPokerus(&gPlayerParty[0]), enabled);
}
TEST("(Pokerus) Test UpdatePartyPokerusTime general behavior")
{
u32 enabled = 0;
u32 strain = 0;
s32 daysLeft = 0;
s32 daysPassed = 0;
for (u32 i = 0; i < 16; i++)
{
for (u32 j = 0; j < 16; j++)
{
for (u32 k = 1; k < 4; k++)
{
PARAMETRIZE { enabled = TRUE; strain = i; daysLeft = j; daysPassed = k; }
PARAMETRIZE { enabled = FALSE; strain = i; daysLeft = j; daysPassed = k; }
}
}
}
SetConfig(CONFIG_POKERUS_ENABLED, enabled);
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS_STRAIN, &strain);
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS_DAYS_LEFT, &daysLeft);
UpdatePartyPokerusTime(daysPassed);
if (enabled)
{
if ( (strain == 0) //Verify strain 0 is modified to strain 1 when timer is up
&& (daysLeft > 0)
&& ((daysLeft - daysPassed) <= 0)
)
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS_STRAIN), 1);
else
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS_STRAIN), strain);
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS_DAYS_LEFT), max(0, daysLeft - daysPassed));
}
else
{
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS_STRAIN), strain);
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS_DAYS_LEFT), daysLeft);
}
}
TEST("(Pokerus) Test PartySpreadPokerus general behavior")
{
u32 partyMember = 0;
u32 pokerus = 0;
for (u32 i = 0; i <= MAX_u8; i++)
{
if ((i & 0x0F) == 0)
continue;
for (u32 k = 0; k < PARTY_SIZE; k++)
{
PARAMETRIZE {pokerus = i; partyMember = k;}
}
}
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
SetConfig(CONFIG_POKERUS_SPREAD_DAYS_LEFT, GEN_3);
SetConfig(CONFIG_POKERUS_SPREAD_ADJACENCY, GEN_3);
ZeroPlayerPartyMons();
for (u32 i = 0; i < PARTY_SIZE; i++)
{
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
}
SetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS, &pokerus);
SET_RNG(RNG_POKERUS_SPREAD, 0);
PartySpreadPokerus();
EXPECT_EQ(GetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS), pokerus);
if (partyMember == 0)
{
EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_POKERUS), pokerus);
for (u32 i = 2; i < PARTY_SIZE; i++)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
else if (partyMember == PARTY_SIZE - 1)
{
EXPECT_EQ(GetMonData(&gPlayerParty[PARTY_SIZE - 2], MON_DATA_POKERUS), pokerus);
for (u32 i = 0; i < (PARTY_SIZE - 2); i++)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
else
{
for (u32 i = 0; i < PARTY_SIZE; i++)
{
if ((i < (partyMember - 1)) || (i > (partyMember + 1)))
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
else
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), pokerus);
}
}
}
TEST("(Pokerus) Test PartySpreadPokerus: Pokerus can spread to and from eggs")
{
u32 partyMember = 0;
u32 pokerus = 0;
for (u32 i = 0; i <= MAX_u8; i++)
{
if ((i & 0x0F) == 0)
continue;
for (u32 k = 0; k < PARTY_SIZE; k++)
{
PARAMETRIZE {pokerus = i; partyMember = k;}
}
}
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
SetConfig(CONFIG_POKERUS_SPREAD_DAYS_LEFT, GEN_3);
SetConfig(CONFIG_POKERUS_SPREAD_ADJACENCY, GEN_3);
ZeroPlayerPartyMons();
for (u32 i = 0; i < PARTY_SIZE; i++)
{
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
bool32 isEgg = TRUE;
SetMonData(&gPlayerParty[i], MON_DATA_IS_EGG, &isEgg);
}
SetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS, &pokerus);
SET_RNG(RNG_POKERUS_SPREAD, 0);
PartySpreadPokerus();
EXPECT_EQ(GetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS), pokerus);
if (partyMember == 0)
{
EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_POKERUS), pokerus);
for (u32 i = 2; i < PARTY_SIZE; i++)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
else if (partyMember == PARTY_SIZE - 1)
{
EXPECT_EQ(GetMonData(&gPlayerParty[PARTY_SIZE - 2], MON_DATA_POKERUS), pokerus);
for (u32 i = 0; i < (PARTY_SIZE - 2); i++)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
else
{
for (u32 i = 0; i < PARTY_SIZE; i++)
{
if ((i < (partyMember - 1)) || (i > (partyMember + 1)))
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
else
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), pokerus);
}
}
}
TEST("(Pokerus) Test PartySpreadPokerus: do not spread inactive pokerus")
{
u32 partyMember = 0;
u32 pokerus = 0;
for (u32 i = 0; i <= MAX_u8; i++)
{
if (i & 0x0F)
continue;
for (u32 k = 0; k < PARTY_SIZE; k++)
{
PARAMETRIZE { pokerus = i; partyMember = k; }
}
}
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
ZeroPlayerPartyMons();
for (u32 i = 0; i < PARTY_SIZE; i++)
{
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
}
SetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS, &pokerus);
SET_RNG(RNG_POKERUS_SPREAD, 0);
EXPECT_EQ(GetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS), pokerus);
for (u32 i = 0; i < PARTY_SIZE; i++)
{
if (i != partyMember)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
}
TEST("(Pokerus) Test PartySpreadPokerus: do not spread if POKERUS_ENABLED is false")
{
u32 partyMember = 0;
u32 pokerus = 0;
for (u32 i = 0; i <= MAX_u8; i++)
{
for (u32 k = 0; k < PARTY_SIZE; k++)
{
PARAMETRIZE { pokerus = i; partyMember = k; }
}
}
SetConfig(CONFIG_POKERUS_ENABLED, FALSE);
ZeroPlayerPartyMons();
for (u32 i = 0; i < PARTY_SIZE; i++)
{
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
}
SetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS, &pokerus);
SET_RNG(RNG_POKERUS_SPREAD, 0);
PartySpreadPokerus();
EXPECT_EQ(GetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS), pokerus);
for (u32 i = 0; i < PARTY_SIZE; i++)
{
if (i != partyMember)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
}
TEST("(Pokerus) Test PartySpreadPokerus: do not spread to pokemon who got pokerus before")
{
u32 pokerus1 = 0;
u32 pokerus2 = 0;
for (u32 i = 1; i < 16; i++)
{
for (u32 j = 1; j < 16; j++)
{
PARAMETRIZE { pokerus1 = ((i << 4) | 1); pokerus2 = ((j << 4) | 0); }
PARAMETRIZE { pokerus1 = ((i << 4) | 2); pokerus2 = ((j << 4) | 1); }
}
}
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100;
givemon SPECIES_PIKACHU, 100;
);
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS, &pokerus1);
SetMonData(&gPlayerParty[1], MON_DATA_POKERUS, &pokerus2);
SET_RNG(RNG_POKERUS_SPREAD, 0);
PartySpreadPokerus();
EXPECT_NE(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS), GetMonData(&gPlayerParty[1], MON_DATA_POKERUS));
}
TEST("(Pokerus) Test PartySpreadPokerus: strain 0 can be spread to if POKERUS_WEAK_VARIANT is true")
{
u32 weakVariant = 0;
u32 pokerus2 = 0;
for (u32 i = 2; i <= MAX_u8; i++)
{
if ((i & 0x0F) == 0)
continue;
PARAMETRIZE { weakVariant = TRUE; pokerus2 = i; }
PARAMETRIZE { weakVariant = FALSE; pokerus2 = i; }
}
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
SetConfig(CONFIG_POKERUS_WEAK_VARIANT, weakVariant);
ZeroPlayerPartyMons();
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100;
givemon SPECIES_PIKACHU, 100;
);
u32 pokerus1 = 1;
SetMonData(&gPlayerParty[0], MON_DATA_POKERUS, &pokerus1);
SetMonData(&gPlayerParty[1], MON_DATA_POKERUS, &pokerus2);
SET_RNG(RNG_POKERUS_SPREAD, 0);
PartySpreadPokerus();
if (weakVariant)
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS), GetMonData(&gPlayerParty[1], MON_DATA_POKERUS));
else
EXPECT_NE(GetMonData(&gPlayerParty[0], MON_DATA_POKERUS), GetMonData(&gPlayerParty[1], MON_DATA_POKERUS));
}
TEST("(Pokerus) Test PartySpreadPokerus when POKERUS_SPREAD_DAYS_LEFT is set to GEN2")
{
u32 partyMember = 0;
u32 strain = 0;
u32 daysLeft = 0;
for (u32 i = 0; i < 16; i++)
{
for (u32 j = 1; j < 16; j++)
{
for (u32 k = 0; k < PARTY_SIZE; k++)
{
PARAMETRIZE {strain = i; daysLeft = j; partyMember = k;}
}
}
}
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
SetConfig(CONFIG_POKERUS_SPREAD_DAYS_LEFT, GEN_2);
SetConfig(CONFIG_POKERUS_SPREAD_ADJACENCY, GEN_3);
ZeroPlayerPartyMons();
for (u32 i = 0; i < PARTY_SIZE; i++)
{
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
}
SetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS_STRAIN, &strain);
SetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS_DAYS_LEFT, &daysLeft);
SET_RNG(RNG_POKERUS_SPREAD, 0);
PartySpreadPokerus();
EXPECT_EQ(GetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS_STRAIN), strain);
EXPECT_EQ(GetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS_DAYS_LEFT), daysLeft);
if (partyMember == 0)
{
EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_POKERUS_STRAIN), strain);
EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_POKERUS_DAYS_LEFT), GetDaysLeftBasedOnStrain(strain));
for (u32 i = 2; i < PARTY_SIZE; i++)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
else if (partyMember == PARTY_SIZE - 1)
{
EXPECT_EQ(GetMonData(&gPlayerParty[PARTY_SIZE - 2], MON_DATA_POKERUS_STRAIN), strain);
EXPECT_EQ(GetMonData(&gPlayerParty[PARTY_SIZE - 2], MON_DATA_POKERUS_DAYS_LEFT), GetDaysLeftBasedOnStrain(strain));
for (u32 i = 0; i < (PARTY_SIZE - 2); i++)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
else
{
for (u32 i = 0; i < PARTY_SIZE; i++)
{
if ((i < (partyMember - 1)) || (i > (partyMember + 1)))
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
else if (i != partyMember)
{
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS_STRAIN), strain);
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS_DAYS_LEFT), GetDaysLeftBasedOnStrain(strain));
}
}
}
}
TEST("(Pokerus) Test PartySpreadPokerus using gen2 adjacency")
{
u32 partyMember = 0;
u32 pokerus = 0;
u32 spreadUp = 0; //spread in ascending order of party index
for (u32 i = 0; i <= MAX_u8; i++)
{
if ((i & 0x0F) == 0)
continue;
for (u32 k = 0; k < PARTY_SIZE; k++)
{
PARAMETRIZE { pokerus = i; partyMember = k; spreadUp = TRUE; }
PARAMETRIZE { pokerus = i; partyMember = k; spreadUp = FALSE; }
}
}
SetConfig(CONFIG_POKERUS_ENABLED, TRUE);
SetConfig(CONFIG_POKERUS_SPREAD_DAYS_LEFT, GEN_3);
SetConfig(CONFIG_POKERUS_SPREAD_ADJACENCY, GEN_2);
ZeroPlayerPartyMons();
for (u32 i = 0; i < PARTY_SIZE; i++)
{
RUN_OVERWORLD_SCRIPT(
givemon SPECIES_PIKACHU, 100
);
}
SetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS, &pokerus);
SET_RNG(RNG_POKERUS_SPREAD, 0);
SET_RNG(RNG_POKERUS_SPREAD_SIDE, spreadUp);
PartySpreadPokerus();
EXPECT_EQ(GetMonData(&gPlayerParty[partyMember], MON_DATA_POKERUS), pokerus);
if (partyMember == 0)
{
if (spreadUp)
EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_POKERUS), pokerus);
else
EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_POKERUS), 0);
for (u32 i = 2; i < PARTY_SIZE; i++)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
else if (partyMember == PARTY_SIZE - 1)
{
EXPECT_EQ(GetMonData(&gPlayerParty[PARTY_SIZE - 2], MON_DATA_POKERUS), pokerus);
for (u32 i = 0; i < (PARTY_SIZE - 2); i++)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
else
{
for (u32 i = 0; i < PARTY_SIZE; i++)
{
if (!spreadUp && (i == (partyMember - 1)))
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), pokerus);
else if (spreadUp && (i == (partyMember + 1)))
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), pokerus);
else if (i != partyMember)
EXPECT_EQ(GetMonData(&gPlayerParty[i], MON_DATA_POKERUS), 0);
}
}
}

View File

@ -561,6 +561,7 @@ void Test_ExpectFail(u32 failLine)
static void FunctionTest_SetUp(void *data) static void FunctionTest_SetUp(void *data)
{ {
(void)data; (void)data;
TestInitConfigData();
ClearRiggedRng(); ClearRiggedRng();
gFunctionTestRunnerState = AllocZeroed(sizeof(*gFunctionTestRunnerState)); gFunctionTestRunnerState = AllocZeroed(sizeof(*gFunctionTestRunnerState));
SeedRng(0); SeedRng(0);
@ -581,6 +582,7 @@ static void FunctionTest_Run(void *data)
static void FunctionTest_TearDown(void *data) static void FunctionTest_TearDown(void *data)
{ {
(void)data; (void)data;
TestFreeConfigData();
FREE_AND_SET_NULL(gFunctionTestRunnerState); FREE_AND_SET_NULL(gFunctionTestRunnerState);
} }