pokeemerald-expansion/src/script_pokemon_util.c
Nephrite 47cac73a61
Some checks are pending
CI / build-emerald (push) Waiting to run
CI / build-firered (push) Waiting to run
CI / build-leafgreen (push) Waiting to run
CI / release (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
CI / docs_validate (push) Waiting to run
CI / allcontributors (push) Waiting to run
gBerries refactor + untangling berry indices from item IDs (#7305)
2026-03-21 21:30:09 +01:00

692 lines
21 KiB
C

#include "global.h"
#include "battle.h"
#include "battle_gfx_sfx_util.h"
#include "berry.h"
#include "caps.h"
#include "data.h"
#include "daycare.h"
#include "decompress.h"
#include "event_data.h"
#include "international_string_util.h"
#include "item.h"
#include "link.h"
#include "link_rfu.h"
#include "main.h"
#include "menu.h"
#include "overworld.h"
#include "ow_synchronize.h"
#include "palette.h"
#include "party_menu.h"
#include "pokedex.h"
#include "pokemon.h"
#include "pokemon_storage_system.h"
#include "random.h"
#include "script.h"
#include "sprite.h"
#include "string_util.h"
#include "tv.h"
#include "wild_encounter.h"
#include "constants/abilities.h"
#include "constants/items.h"
#include "constants/battle_frontier.h"
static void CB2_ReturnFromChooseHalfParty(void);
static void CB2_ReturnFromChooseBattleFrontierParty(void);
static void HealPlayerBoxes(void);
void HealPlayerParty(void)
{
u32 i;
for (i = 0; i < gPlayerPartyCount; i++)
HealPokemon(&gPlayerParty[i]);
if (OW_PC_HEAL >= GEN_8)
HealPlayerBoxes();
// Recharge Tera Orb, if possible.
if (B_FLAG_TERA_ORB_CHARGED != 0 && CheckBagHasItem(ITEM_TERA_ORB, 1))
FlagSet(B_FLAG_TERA_ORB_CHARGED);
}
static void HealPlayerBoxes(void)
{
int boxId, boxPosition;
struct BoxPokemon *boxMon;
for (boxId = 0; boxId < TOTAL_BOXES_COUNT; boxId++)
{
for (boxPosition = 0; boxPosition < IN_BOX_COUNT; boxPosition++)
{
boxMon = &gPokemonStoragePtr->boxes[boxId][boxPosition];
if (GetBoxMonData(boxMon, MON_DATA_SANITY_HAS_SPECIES))
HealBoxPokemon(boxMon);
}
}
}
u8 ScriptGiveEgg(enum Species species)
{
struct Pokemon mon;
u8 isEgg;
CreateEgg(&mon, species, TRUE);
isEgg = TRUE;
SetMonData(&mon, MON_DATA_IS_EGG, &isEgg);
return GiveCapturedMonToPlayer(&mon);
}
void HasEnoughMonsForDoubleBattle(void)
{
switch (GetMonsStateToDoubles())
{
case PLAYER_HAS_TWO_USABLE_MONS:
gSpecialVar_Result = PLAYER_HAS_TWO_USABLE_MONS;
break;
case PLAYER_HAS_ONE_MON:
gSpecialVar_Result = PLAYER_HAS_ONE_MON;
break;
case PLAYER_HAS_ONE_USABLE_MON:
gSpecialVar_Result = PLAYER_HAS_ONE_USABLE_MON;
break;
}
}
static bool32 CheckPartyMonHasHeldItem(enum Item item)
{
int i;
for (i = 0; i < PARTY_SIZE; i++)
{
enum Species species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG);
if (species != SPECIES_NONE && species != SPECIES_EGG && GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM) == item)
return TRUE;
}
return FALSE;
}
bool8 DoesPartyHaveEnigmaBerry(void)
{
bool8 hasItem = CheckPartyMonHasHeldItem(ITEM_ENIGMA_BERRY_E_READER);
if (hasItem == TRUE)
GetBerryNameByBerryType(BERRY_ID_ENGIMA_E_READER, gStringVar1);
return hasItem;
}
void CreateScriptedWildMon(enum Species species, u8 level, enum Item item)
{
u8 heldItem[2];
ZeroEnemyPartyMons();
u32 personality = GetMonPersonality(species,
GetSynchronizedGender(STATIC_WILDMON_ORIGIN, species),
GetSynchronizedNature(STATIC_WILDMON_ORIGIN, species),
RANDOM_UNOWN_LETTER);
CreateMonWithIVs(&gEnemyParty[0], species, level, personality, OTID_STRUCT_PLAYER_ID, USE_RANDOM_IVS);
GiveMonInitialMoveset(&gEnemyParty[0]);
if (item)
{
heldItem[0] = item;
heldItem[1] = item >> 8;
SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, heldItem);
}
}
void CreateScriptedDoubleWildMon(enum Species species1, u8 level1, enum Item item1, enum Species species2, u8 level2, enum Item item2)
{
u8 heldItem1[2];
u8 heldItem2[2];
ZeroEnemyPartyMons();
u32 personality = GetMonPersonality(species1,
GetSynchronizedGender(STATIC_WILDMON_ORIGIN, species1),
GetSynchronizedNature(STATIC_WILDMON_ORIGIN, species1),
RANDOM_UNOWN_LETTER);
CreateMonWithIVs(&gEnemyParty[0], species1, level1, personality, OTID_STRUCT_PLAYER_ID, USE_RANDOM_IVS);
GiveMonInitialMoveset(&gEnemyParty[0]);
if (item1)
{
heldItem1[0] = item1;
heldItem1[1] = item1 >> 8;
SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, heldItem1);
}
personality = GetMonPersonality(species2,
GetSynchronizedGender(STATIC_WILDMON_ORIGIN, species2),
GetSynchronizedNature(STATIC_WILDMON_ORIGIN, species2),
RANDOM_UNOWN_LETTER);
CreateMonWithIVs(&gEnemyParty[1], species2, level2, personality, OTID_STRUCT_PLAYER_ID, USE_RANDOM_IVS);
GiveMonInitialMoveset(&gEnemyParty[1]);
if (item2)
{
heldItem2[0] = item2;
heldItem2[1] = item2 >> 8;
SetMonData(&gEnemyParty[1], MON_DATA_HELD_ITEM, heldItem2);
}
}
void ScriptSetMonMoveSlot(u8 monIndex, enum Move move, u8 slot)
{
// Allows monIndex to go out of bounds of gPlayerParty. Doesn't occur in vanilla
#ifdef BUGFIX
if (monIndex >= PARTY_SIZE)
#else
if (monIndex > PARTY_SIZE)
#endif
monIndex = gPlayerPartyCount - 1;
SetMonMoveSlot(&gPlayerParty[monIndex], move, slot);
}
// Note: When control returns to the event script, gSpecialVar_Result will be
// TRUE if the party selection was successful.
void ChooseHalfPartyForBattle(void)
{
gMain.savedCallback = CB2_ReturnFromChooseHalfParty;
VarSet(VAR_FRONTIER_FACILITY, FACILITY_MULTI_OR_EREADER);
InitChooseHalfPartyForBattle(0);
}
static void CB2_ReturnFromChooseHalfParty(void)
{
switch (gSelectedOrderFromParty[0])
{
case 0:
gSpecialVar_Result = FALSE;
break;
default:
gSpecialVar_Result = TRUE;
break;
}
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
}
void ChoosePartyForBattleFrontier(void)
{
gMain.savedCallback = CB2_ReturnFromChooseBattleFrontierParty;
InitChooseHalfPartyForBattle(gSpecialVar_0x8004 + 1);
}
static void CB2_ReturnFromChooseBattleFrontierParty(void)
{
switch (gSelectedOrderFromParty[0])
{
case 0:
gSpecialVar_Result = FALSE;
break;
default:
gSpecialVar_Result = TRUE;
break;
}
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
}
void ReducePlayerPartyToSelectedMons(void)
{
struct Pokemon party[MAX_FRONTIER_PARTY_SIZE];
int i;
CpuFill32(0, party, sizeof party);
// copy the selected Pokémon according to the order.
for (i = 0; i < MAX_FRONTIER_PARTY_SIZE; i++)
if (gSelectedOrderFromParty[i]) // as long as the order keeps going (did the player select 1 mon? 2? 3?), do not stop
party[i] = gPlayerParty[gSelectedOrderFromParty[i] - 1]; // index is 0 based, not literal
CpuFill32(0, gPlayerParty, sizeof gPlayerParty);
// overwrite the first 4 with the order copied to.
for (i = 0; i < MAX_FRONTIER_PARTY_SIZE; i++)
gPlayerParty[i] = party[i];
CalculatePlayerPartyCount();
}
void CanHyperTrain(struct ScriptContext *ctx)
{
u32 stat = ScriptReadByte(ctx);
u32 partyIndex = VarGet(ScriptReadHalfword(ctx));
Script_RequestEffects(SCREFF_V1);
assertf(stat < NUM_STATS, "invalid stat: %d", stat)
{
gSpecialVar_Result = FALSE;
return;
}
CalculatePlayerPartyCount();
assertf(partyIndex < gPlayerPartyCount, "invalid party index: %d", partyIndex)
{
gSpecialVar_Result = FALSE;
return;
}
if (!GetMonData(&gPlayerParty[partyIndex], MON_DATA_HYPER_TRAINED_HP + stat)
&& GetMonData(&gPlayerParty[partyIndex], MON_DATA_HP_IV + stat) < MAX_PER_STAT_IVS)
{
gSpecialVar_Result = TRUE;
}
else
{
gSpecialVar_Result = FALSE;
}
}
void HyperTrain(struct ScriptContext *ctx)
{
u32 stat = ScriptReadByte(ctx);
u32 partyIndex = VarGet(ScriptReadHalfword(ctx));
Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE);
assertf(stat < NUM_STATS, "invalid stat: %d", stat)
{
return;
}
CalculatePlayerPartyCount();
assertf(partyIndex < gPlayerPartyCount, "invalid party index: %d", partyIndex)
{
return;
}
bool32 data = TRUE;
SetMonData(&gPlayerParty[partyIndex], MON_DATA_HYPER_TRAINED_HP + stat, &data);
CalculateMonStats(&gPlayerParty[partyIndex]);
}
void HasGigantamaxFactor(struct ScriptContext *ctx)
{
u32 partyIndex = VarGet(ScriptReadHalfword(ctx));
Script_RequestEffects(SCREFF_V1);
if (partyIndex < PARTY_SIZE)
gSpecialVar_Result = GetMonData(&gPlayerParty[partyIndex], MON_DATA_GIGANTAMAX_FACTOR);
else
gSpecialVar_Result = FALSE;
}
void ToggleGigantamaxFactor(struct ScriptContext *ctx)
{
u32 partyIndex = VarGet(ScriptReadHalfword(ctx));
Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE);
gSpecialVar_Result = FALSE;
if (partyIndex < PARTY_SIZE)
{
bool32 gigantamaxFactor;
if (gSpeciesInfo[SanitizeSpeciesId(GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPECIES))].isMythical)
return;
gigantamaxFactor = GetMonData(&gPlayerParty[partyIndex], MON_DATA_GIGANTAMAX_FACTOR);
gigantamaxFactor = !gigantamaxFactor;
SetMonData(&gPlayerParty[partyIndex], MON_DATA_GIGANTAMAX_FACTOR, &gigantamaxFactor);
gSpecialVar_Result = TRUE;
}
}
void CheckTeraType(struct ScriptContext *ctx)
{
u32 partyIndex = VarGet(ScriptReadHalfword(ctx));
Script_RequestEffects(SCREFF_V1);
gSpecialVar_Result = TYPE_NONE;
if (partyIndex < PARTY_SIZE)
gSpecialVar_Result = GetMonData(&gPlayerParty[partyIndex], MON_DATA_TERA_TYPE);
}
void SetTeraType(struct ScriptContext *ctx)
{
enum Type type = ScriptReadByte(ctx);
u32 partyIndex = VarGet(ScriptReadHalfword(ctx));
Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE);
if (type < NUMBER_OF_MON_TYPES && partyIndex < PARTY_SIZE)
SetMonData(&gPlayerParty[partyIndex], MON_DATA_TERA_TYPE, &type);
}
/* Creates a Pokemon via script
* if side/slot are assigned, it will create the mon at the assigned party location
* if slot == PARTY_SIZE, it will give the mon to first available party or storage slot
*/
static u32 ScriptGiveMonParameterized(u8 side, u8 slot, enum Species species, u8 level, enum Item item, enum PokeBall ball, u8 nature, u8 abilityNum, u8 gender, u16 *evs, u16 *ivs, enum Move *moves, enum ShinyMode shinyMode, bool8 gmaxFactor, enum Type teraType, u8 dmaxLevel)
{
struct Pokemon mon;
u32 i;
bool32 isShiny;
u32 personality = GetMonPersonality(species, gender, nature, RANDOM_UNOWN_LETTER);
CreateMon(&mon, species, level, personality, OTID_STRUCT_PLAYER_ID);
// shininess
if (shinyMode == SHINY_MODE_ALWAYS || (P_FLAG_FORCE_SHINY != 0 && FlagGet(P_FLAG_FORCE_SHINY)))
isShiny = TRUE;
else if (shinyMode == SHINY_MODE_NEVER || (P_FLAG_FORCE_NO_SHINY != 0 && FlagGet(P_FLAG_FORCE_NO_SHINY)))
isShiny = FALSE;
else
isShiny = GetMonData(&mon, MON_DATA_IS_SHINY);
SetMonData(&mon, MON_DATA_IS_SHINY, &isShiny);
// gigantamax factor
SetMonData(&mon, MON_DATA_GIGANTAMAX_FACTOR, &gmaxFactor);
// Dynamax Level
SetMonData(&mon, MON_DATA_DYNAMAX_LEVEL, &dmaxLevel);
// tera type
if (teraType == TYPE_NONE || teraType == TYPE_MYSTERY || teraType >= NUMBER_OF_MON_TYPES)
teraType = GetTeraTypeFromPersonality(&mon);
SetMonData(&mon, MON_DATA_TERA_TYPE, &teraType);
// EV and IV
for (i = 0; i < NUM_STATS; i++)
{
// EV
if (evs[i] <= MAX_PER_STAT_EVS)
SetMonData(&mon, MON_DATA_HP_EV + i, &evs[i]);
// IV
if (ivs[i] <= MAX_PER_STAT_IVS)
SetMonData(&mon, MON_DATA_HP_IV + i, &ivs[i]);
}
CalculateMonStats(&mon);
// moves
bool32 all_default_flag = TRUE;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] != MOVE_DEFAULT)
{
all_default_flag = FALSE;
break;
}
}
if (all_default_flag)
{
GiveMonInitialMoveset(&mon);
}
else
{
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] == MOVE_NONE)
break;
if (moves[i] < MOVES_COUNT)
{
SetMonMoveSlot(&mon, moves[i], i);
}
else if (moves[i] == MOVE_DEFAULT)
{
GiveMonDefaultMove(&mon, i);
continue;
}
else
{
assertf(FALSE, "invalid move: %d", moves[i]) {}
}
}
}
// ability
if (abilityNum != NUM_ABILITY_PERSONALITY)
{
assertf(abilityNum < NUM_ABILITY_SLOTS && GetAbilityBySpecies(species, abilityNum) != ABILITY_NONE,
"invalid ability num %d for species %d", abilityNum, species)
{
// If the ability num is invalid, we loop to find a valid one
do {
abilityNum = Random() % NUM_ABILITY_SLOTS; // includes hidden abilities
} while (GetAbilityBySpecies(species, abilityNum) == ABILITY_NONE);
}
SetMonData(&mon, MON_DATA_ABILITY_NUM, &abilityNum);
}
// ball
if (ball > POKEBALL_COUNT)
ball = BALL_POKE;
SetMonData(&mon, MON_DATA_POKEBALL, &ball);
// held item
SetMonData(&mon, MON_DATA_HELD_ITEM, &item);
// In case a mon with a form changing item is given. Eg: SPECIES_ARCEUS_NORMAL with ITEM_SPLASH_PLATE will transform into SPECIES_ARCEUS_WATER upon gifted.
TryFormChange(&mon, FORM_CHANGE_ITEM_HOLD);
if (side == B_SIDE_PLAYER)
return GiveScriptedMonToPlayer(&mon, slot);
assertf(slot < PARTY_SIZE, "invalid slot: %d", slot)
{
return MON_CANT_GIVE;
}
CopyMon(&gEnemyParty[slot], &mon, sizeof(struct Pokemon));
return MON_GIVEN_TO_PARTY;
}
u32 ScriptGiveMon(enum Species species, u8 level, enum Item item)
{
struct Pokemon mon;
u8 heldItem[2];
CreateRandomMon(&mon, species, level);
if (item)
{
heldItem[0] = item;
heldItem[1] = item >> 8;
SetMonData(&mon, MON_DATA_HELD_ITEM, heldItem);
}
return GiveScriptedMonToPlayer(&mon, PARTY_SIZE);
}
#define PARSE_FLAG(n, default_) (flags & (1 << (n))) ? VarGet(ScriptReadHalfword(ctx)) : (default_)
#define ADD_MOVE_IF_NOT_DEFAULT(i, move) \
if (move && move != MOVE_DEFAULT) \
{ \
moves[i] = move; \
i++; \
}
#define ADD_MOVE_IF_DEFAULT(i, move) \
if (moves[i] == MOVE_NONE && move == MOVE_DEFAULT) \
{ \
moves[i] = MOVE_DEFAULT; \
i++; \
}
/* Give or create a mon to either player or opponent
*/
void ScrCmd_createmon(struct ScriptContext *ctx)
{
u8 side = ScriptReadByte(ctx);
u8 slot = ScriptReadByte(ctx);
enum Species species = VarGet(ScriptReadHalfword(ctx));
u8 level = VarGet(ScriptReadHalfword(ctx));
u32 flags = ScriptReadWord(ctx);
enum Item item = PARSE_FLAG(0, ITEM_NONE);
enum PokeBall ball = PARSE_FLAG(1, BALL_POKE);
u8 nature = PARSE_FLAG(2, NATURE_RANDOM);
u8 abilityNum = PARSE_FLAG(3, NUM_ABILITY_PERSONALITY);
u8 gender = PARSE_FLAG(4, MON_GENDER_RANDOM);
u32 i;
u16 evs[NUM_STATS];
for (i = 0; i < NUM_STATS; i++)
{
evs[i] = PARSE_FLAG(5 + i, 0);
assertf(evs[i] <= MAX_PER_STAT_EVS, "invalid ev value of %d above maximum of %d", evs[i], MAX_PER_STAT_EVS)
{
evs[i] = MAX_PER_STAT_EVS;
}
}
u16 ivs[NUM_STATS];
u32 nonFixedIvCount = 0;
enum Stat availableIVs[NUM_STATS];
enum Stat selectedIvs[NUM_STATS];
for (i = 0; i < NUM_STATS; i++)
{
ivs[i] = PARSE_FLAG(11 + i, USE_RANDOM_IVS);
assertf(ivs[i] <= USE_RANDOM_IVS, "invalid iv value of %d above maximum of %d", ivs[i], MAX_PER_STAT_IVS)
{
ivs[i] = MAX_PER_STAT_IVS;
}
if (ivs[i] == USE_RANDOM_IVS)
{
availableIVs[nonFixedIvCount] = i;
ivs[i] = Random() % (MAX_PER_STAT_IVS + 1);
nonFixedIvCount++;
}
}
// Perfect IV calculation
if (gSpeciesInfo[species].perfectIVCount != 0)
{
// Select the IVs that will be perfected.
for (i = 0; i < nonFixedIvCount && i < gSpeciesInfo[species].perfectIVCount; i++)
{
u8 index = Random() % (nonFixedIvCount - i);
selectedIvs[i] = availableIVs[index];
RemoveIVIndexFromList(availableIVs, index);
}
for (i = 0; i < nonFixedIvCount && i < gSpeciesInfo[species].perfectIVCount; i++)
{
ivs[selectedIvs[i]] = MAX_PER_STAT_IVS;
}
}
enum Move move1 = PARSE_FLAG(17, MOVE_DEFAULT);
enum Move move2 = PARSE_FLAG(18, MOVE_DEFAULT);
enum Move move3 = PARSE_FLAG(19, MOVE_DEFAULT);
enum Move move4 = PARSE_FLAG(20, MOVE_DEFAULT);
enum ShinyMode shinyMode = PARSE_FLAG(21, SHINY_MODE_RANDOM);
bool8 gmaxFactor = PARSE_FLAG(22, FALSE);
enum Type teraType = PARSE_FLAG(23, NUMBER_OF_MON_TYPES);
u8 dmaxLevel = PARSE_FLAG(24, 0);
enum Move moves[MAX_MON_MOVES];
for (i = 0; i < MAX_MON_MOVES; i++)
moves[i] = MOVE_NONE;
i = 0;
//Reorder moves to put non-default moves first, default moves second and empty moves last
ADD_MOVE_IF_NOT_DEFAULT(i, move1)
ADD_MOVE_IF_NOT_DEFAULT(i, move2)
ADD_MOVE_IF_NOT_DEFAULT(i, move3)
ADD_MOVE_IF_NOT_DEFAULT(i, move4)
ADD_MOVE_IF_DEFAULT(i, move1)
ADD_MOVE_IF_DEFAULT(i, move2)
ADD_MOVE_IF_DEFAULT(i, move3)
ADD_MOVE_IF_DEFAULT(i, move4)
enum GeneratedMonOrigin origin;
if (side == 0)
{
Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE);
origin = GIFTMON_ORIGIN;
}
else
{
Script_RequestEffects(SCREFF_V1);
origin = STATIC_WILDMON_ORIGIN;
}
if (gender == MON_GENDER_MAY_CUTE_CHARM)
gender = GetSynchronizedGender(origin, species);
if (nature == NATURE_MAY_SYNCHRONIZE)
nature = GetSynchronizedNature(origin, species);
gSpecialVar_Result = ScriptGiveMonParameterized(side, slot, species, level, item, ball, nature, abilityNum, gender, evs, ivs, moves, shinyMode, gmaxFactor, teraType, dmaxLevel);
}
#undef PARSE_FLAG
void Script_GetChosenMonOffensiveEVs(void)
{
ConvertIntToDecimalStringN(gStringVar1, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_ATK_EV), STR_CONV_MODE_LEFT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar2, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPATK_EV), STR_CONV_MODE_LEFT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar3, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPEED_EV), STR_CONV_MODE_LEFT_ALIGN, 3);
}
void Script_GetChosenMonDefensiveEVs(void)
{
ConvertIntToDecimalStringN(gStringVar1, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_HP_EV), STR_CONV_MODE_LEFT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar2, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_DEF_EV), STR_CONV_MODE_LEFT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar3, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPDEF_EV), STR_CONV_MODE_LEFT_ALIGN, 3);
}
void Script_GetChosenMonOffensiveIVs(void)
{
ConvertIntToDecimalStringN(gStringVar1, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_ATK_IV), STR_CONV_MODE_LEFT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar2, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPATK_IV), STR_CONV_MODE_LEFT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar3, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPEED_IV), STR_CONV_MODE_LEFT_ALIGN, 3);
}
void Script_GetChosenMonDefensiveIVs(void)
{
ConvertIntToDecimalStringN(gStringVar1, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_HP_IV), STR_CONV_MODE_LEFT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar2, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_DEF_IV), STR_CONV_MODE_LEFT_ALIGN, 3);
ConvertIntToDecimalStringN(gStringVar3, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPDEF_IV), STR_CONV_MODE_LEFT_ALIGN, 3);
}
void Script_SetStatus1(struct ScriptContext *ctx)
{
u32 status1 = VarGet(ScriptReadHalfword(ctx));
u32 slot = VarGet(ScriptReadHalfword(ctx));
Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE);
if (slot >= PARTY_SIZE)
{
enum Species species;
for (slot = 0; slot < PARTY_SIZE; slot++)
{
species = GetMonData(&gPlayerParty[slot], MON_DATA_SPECIES);
if (species != SPECIES_NONE
&& species != SPECIES_EGG
&& GetMonData(&gPlayerParty[slot], MON_DATA_HP) != 0)
SetMonData(&gPlayerParty[slot], MON_DATA_STATUS, &status1);
}
}
else
{
SetMonData(&gPlayerParty[slot], MON_DATA_STATUS, &status1);
}
}
void Script_SetKO(struct ScriptContext *ctx)
{
u32 slot = VarGet(ScriptReadHalfword(ctx));
Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE);
if (slot < PARTY_SIZE)
{
u32 hp = 0;
SetMonData(&gPlayerParty[slot], MON_DATA_HP, &hp);
}
}
void Script_GiveRandomBerry(struct ScriptContext *ctx)
{
enum BerryId loBerry = ScriptReadByte(ctx);
enum BerryId hiBerry = ScriptReadByte(ctx);
gSpecialVar_Result = BerryTypeToItemId(RandomUniform(RNG_RANDOM_BERRY, loBerry, hiBerry));
}