pokeplatinum/src/trainer_data.c
2023-10-30 09:41:06 -07:00

318 lines
9.8 KiB
C

#include <nitro.h>
#include <string.h>
#include "constants/battle.h"
#include "constants/pokemon.h"
#include "constants/trainer.h"
#include "data/trainer_class_genders.h"
#include "struct_decls/struct_02006C24_decl.h"
#include "struct_decls/struct_021C0794_decl.h"
#include "struct_defs/trainer_data.h"
#include "overlay006/battle_params.h"
#include "heap.h"
#include "message.h"
#include "narc.h"
#include "party.h"
#include "pokemon.h"
#include "strbuf.h"
#include "trainer_data.h"
#include "unk_020021B0.h"
#include "unk_0201D15C.h"
#include "unk_020277A4.h"
static void TrainerData_BuildParty(BattleParams *battleParams, int battler, int heapID);
void TrainerData_Encounter(BattleParams *battleParams, const SaveData *save, int heapID)
{
TrainerData trdata;
MessageLoader *msgLoader = MessageLoader_Init(MESSAGE_LOADER_NARC_HANDLE, NARC_INDEX_MSGDATA__PL_MSG, 618, heapID);
const charcode_t *rivalName = MiscSave_RivalName(Save_MiscRO(save));
for (int i = 0; i < MAX_BATTLERS; i++) {
if (!battleParams->trainerIDs[i]) {
continue;
}
TrainerData_Load(battleParams->trainerIDs[i], &trdata);
battleParams->trainerData[i] = trdata;
if (trdata.class == TRAINER_CLASS_RIVAL) {
GF_strcpy(battleParams->trainerData[i].name, rivalName);
} else {
Strbuf *trainerName = MessageLoader_GetNewStrbuf(msgLoader, battleParams->trainerIDs[i]);
Strbuf_ToChars(trainerName, battleParams->trainerData[i].name, TRAINER_NAME_LEN + 1);
Strbuf_Free(trainerName);
}
TrainerData_BuildParty(battleParams, i, heapID);
}
battleParams->battleType |= trdata.battleType;
MessageLoader_Free(msgLoader);
}
u32 TrainerData_LoadParam(int trainerID, enum TrainerDataParam paramID)
{
u32 result;
TrainerData trdata;
TrainerData_Load(trainerID, &trdata);
switch (paramID) {
case TRDATA_TYPE:
result = trdata.type;
break;
case TRDATA_CLASS:
result = trdata.class;
break;
case TRDATA_SPRITE:
result = trdata.sprite;
break;
case TRDATA_PARTY_SIZE:
result = trdata.partySize;
break;
case TRDATA_ITEM_1:
case TRDATA_ITEM_2:
case TRDATA_ITEM_3:
case TRDATA_ITEM_4:
result = trdata.items[paramID - TRDATA_ITEM_1];
break;
case TRDATA_AI_MASK:
result = trdata.aiMask;
break;
case TRDATA_BATTLE_TYPE:
result = trdata.battleType;
break;
}
return result;
}
BOOL TrainerData_HasMessageType(int trainerID, int msgType, int heapID)
{
NARC *narc; // must declare up here to match
u16 offset, data[2];
BOOL result = FALSE;
int size = NARC_GetMemberSizeByIndexPair(NARC_INDEX_POKETOOL__TRMSG__TRTBL, 0);
NARC_ReadFromMemberByIndexPair(&offset, NARC_INDEX_POKETOOL__TRMSG__TRTBLOFS, 0, trainerID * 2, 2);
narc = NARC_ctor(NARC_INDEX_POKETOOL__TRMSG__TRTBL, heapID);
while (offset != size) {
NARC_ReadFromMember(narc, 0, offset, 4, data);
if (data[0] == trainerID && data[1] == msgType) {
result = TRUE;
break;
}
if (data[0] != trainerID) {
break;
}
offset += 4;
}
NARC_dtor(narc);
return result;
}
void TrainerData_LoadMessage(int trainerID, int msgType, Strbuf *strbuf, int heapID)
{
NARC *narc; // must declare up here to match
u16 offset, data[2];
int size = NARC_GetMemberSizeByIndexPair(NARC_INDEX_POKETOOL__TRMSG__TRTBL, 0);
NARC_ReadFromMemberByIndexPair(&offset, NARC_INDEX_POKETOOL__TRMSG__TRTBLOFS, 0, trainerID * 2, 2);
narc = NARC_ctor(NARC_INDEX_POKETOOL__TRMSG__TRTBL, heapID);
while (offset != size) {
NARC_ReadFromMember(narc, 0, offset, 4, data);
if (data[0] == trainerID && data[1] == msgType) {
MessageBank_GetStrbufFromNARC(NARC_INDEX_MSGDATA__PL_MSG, 617, offset / 4, heapID, strbuf);
break;
}
offset += 4;
}
NARC_dtor(narc);
if (offset == size) {
Strbuf_Clear(strbuf);
}
}
void TrainerData_Load(int trainerID, TrainerData *trdata)
{
NARC_ReadWholeMemberByIndexPair(trdata, NARC_INDEX_POKETOOL__TRAINER__TRDATA, trainerID);
}
void TrainerData_LoadParty(int trainerID, void *trparty)
{
NARC_ReadWholeMemberByIndexPair(trparty, NARC_INDEX_POKETOOL__TRAINER__TRPOKE, trainerID);
}
u8 TrainerClass_Gender(int trclass)
{
return sTrainerClassGender[trclass];
}
/**
* @brief Build the party for a trainer as loaded in the BattleParams struct.
*
* @param battleParams The parent BattleParams struct containing trainer data.
* @param battler Which battler's party is to be loaded.
* @param heapID Heap on which to perform any allocations.
*/
static void TrainerData_BuildParty(BattleParams *battleParams, int battler, int heapID)
{
// must make declarations C89-style to match
void *buf;
int i, j;
u32 genderMod, rnd, oldSeed;
u8 ivs;
Pokemon *mon;
oldSeed = LCRNG_GetSeed();
// alloc enough space to support the maximum possible data size
Party_InitWithCapacity(battleParams->parties[battler], MAX_PARTY_SIZE);
buf = Heap_AllocFromHeap(heapID, sizeof(TrainerMonWithMovesAndItem) * MAX_PARTY_SIZE);
mon = Pokemon_New(heapID);
TrainerData_LoadParty(battleParams->trainerIDs[battler], buf);
// determine which magic gender-specific modifier to use for the RNG function
genderMod = TrainerClass_Gender(battleParams->trainerData[battler].class) == GENDER_FEMALE
? 120 : 136;
switch (battleParams->trainerData[battler].type) {
case TRDATATYPE_BASE: {
TrainerMonBase *trmon = (TrainerMonBase *)buf;
for (i = 0; i < battleParams->trainerData[battler].partySize; i++) {
u16 species = trmon[i].species & 0x3FF;
u8 form = (trmon[i].species & 0xFC00) >> 10;
rnd = trmon[i].dv + trmon[i].level + species + battleParams->trainerIDs[battler];
LCRNG_SetSeed(rnd);
for (j = 0; j < battleParams->trainerData[battler].class; j++) {
rnd = LCRNG_Next();
}
rnd = (rnd << 8) + genderMod;
ivs = trmon[i].dv * MAX_IVS_SINGLE_STAT / MAX_DV;
Pokemon_InitWith(mon, species, trmon[i].level, ivs, TRUE, rnd, OTID_NOT_SHINY, 0);
Pokemon_SetBallSeal(trmon[i].cbSeal, mon, heapID);
Pokemon_SetValue(mon, MON_DATA_FORM, &form);
Party_AddPokemon(battleParams->parties[battler], mon);
}
break;
}
case TRDATATYPE_WITH_MOVES: {
TrainerMonWithMoves *trmon = (TrainerMonWithMoves *)buf;
for (i = 0; i < battleParams->trainerData[battler].partySize; i++) {
u16 species = trmon[i].species & 0x3FF;
u8 form = (trmon[i].species & 0xFC00) >> 10;
rnd = trmon[i].dv + trmon[i].level + species + battleParams->trainerIDs[battler];
LCRNG_SetSeed(rnd);
for (j = 0; j < battleParams->trainerData[battler].class; j++) {
rnd = LCRNG_Next();
}
rnd = (rnd << 8) + genderMod;
ivs = trmon[i].dv * MAX_IVS_SINGLE_STAT / MAX_DV;
Pokemon_InitWith(mon, species, trmon[i].level, ivs, TRUE, rnd, OTID_NOT_SHINY, 0);
for (j = 0; j < 4; j++) {
Pokemon_SetMoveSlot(mon, trmon[i].moves[j], j);
}
Pokemon_SetBallSeal(trmon[i].cbSeal, mon, heapID);
Pokemon_SetValue(mon, MON_DATA_FORM, &form);
Party_AddPokemon(battleParams->parties[battler], mon);
}
break;
}
case TRDATATYPE_WITH_ITEM: {
TrainerMonWithItem *trmon = (TrainerMonWithItem *)buf;
for (i = 0; i < battleParams->trainerData[battler].partySize; i++) {
u16 species = trmon[i].species & 0x3FF;
u8 form = (trmon[i].species & 0xFC00) >> 10;
rnd = trmon[i].dv + trmon[i].level + species + battleParams->trainerIDs[battler];
LCRNG_SetSeed(rnd);
for (j = 0; j < battleParams->trainerData[battler].class; j++) {
rnd = LCRNG_Next();
}
rnd = (rnd << 8) + genderMod;
ivs = trmon[i].dv * MAX_IVS_SINGLE_STAT / MAX_DV;
Pokemon_InitWith(mon, species, trmon[i].level, ivs, TRUE, rnd, OTID_NOT_SHINY, 0);
Pokemon_SetValue(mon, MON_DATA_HELD_ITEM, &trmon[i].item);
Pokemon_SetBallSeal(trmon[i].cbSeal, mon, heapID);
Pokemon_SetValue(mon, MON_DATA_FORM, &form);
Party_AddPokemon(battleParams->parties[battler], mon);
}
break;
}
case TRDATATYPE_WITH_MOVES_AND_ITEM: {
TrainerMonWithMovesAndItem *trmon = (TrainerMonWithMovesAndItem *)buf;
for (i = 0; i < battleParams->trainerData[battler].partySize; i++) {
u16 species = trmon[i].species & 0x3FF;
u8 form = (trmon[i].species & 0xFC00) >> 10;
rnd = trmon[i].dv + trmon[i].level + species + battleParams->trainerIDs[battler];
LCRNG_SetSeed(rnd);
for (j = 0; j < battleParams->trainerData[battler].class; j++) {
rnd = LCRNG_Next();
}
rnd = (rnd << 8) + genderMod;
ivs = trmon[i].dv * MAX_IVS_SINGLE_STAT / MAX_DV;
Pokemon_InitWith(mon, species, trmon[i].level, ivs, TRUE, rnd, OTID_NOT_SHINY, 0);
Pokemon_SetValue(mon, MON_DATA_HELD_ITEM, &trmon[i].item);
for (j = 0; j < 4; j++) {
Pokemon_SetMoveSlot(mon, trmon[i].moves[j], j);
}
Pokemon_SetBallSeal(trmon[i].cbSeal, mon, heapID);
Pokemon_SetValue(mon, MON_DATA_FORM, &form);
Party_AddPokemon(battleParams->parties[battler], mon);
}
break;
}
}
Heap_FreeToHeap(buf);
Heap_FreeToHeap(mon);
LCRNG_SetSeed(oldSeed);
}