pokeplatinum/src/pokeradar.c

517 lines
14 KiB
C

#include "pokeradar.h"
#include <nitro.h>
#include <string.h>
#include "constants/battle.h"
#include "consts/sdat.h"
#include "struct_defs/struct_0201CFEC.h"
#include "struct_defs/struct_020698E4.h"
#include "field/field_system.h"
#include "overlay005/ov5_021F2D20.h"
#include "overlay006/ov6_022430C4.h"
#include "overlay101/struct_ov101_021D5D90_decl.h"
#include "bag.h"
#include "field_task.h"
#include "heap.h"
#include "inlines.h"
#include "map_object.h"
#include "map_tile_behavior.h"
#include "player_avatar.h"
#include "scrcmd.h"
#include "script_manager.h"
#include "unk_02005474.h"
#include "unk_0201CED8.h"
#include "unk_0202D7A8.h"
#include "unk_02039C80.h"
#include "unk_02054D00.h"
#include "unk_020553DC.h"
#include "unk_020711EC.h"
typedef struct {
int unk_00;
int unk_04;
int shakeType;
BOOL active;
BOOL continueChain;
BOOL shiny;
UnkStruct_ov101_021D5D90 *unk_18;
VecFx32 position;
} GrassPatch;
typedef struct RadarChain {
int shakeType;
int count;
int species;
int level;
BOOL active;
BOOL unk_14;
BOOL unk_18;
GrassPatch patch[NUM_GRASS_PATCHES];
UnkStruct_0201CFEC unk_BC;
u8 unk_D0;
} RadarChain;
static BOOL CheckTileIsGrass(FieldSystem *fieldSystem, const fx32 param1, const int param2, const int param3, const u8 param4, const u8 param5, GrassPatch *patch);
static BOOL sub_020698AC(const RadarChain *chain, const int param1, const int param2, u8 *param3);
static void sub_020698E4(FieldSystem *fieldSystem, RadarChain *chain);
static u8 sub_0206994C(FieldSystem *fieldSystem);
static BOOL CheckPatchContinueChain(const u8 patchRing, const int battleResult);
static BOOL CheckPatchShiny(const int param0);
static void IncWithCap(int *param0);
RadarChain *RadarChain_Init(const int heapID)
{
RadarChain *chain = Heap_AllocFromHeap(heapID, sizeof(RadarChain));
sub_0201CFEC(FX32_ONE * 16, FX32_ONE * 8, FX32_ONE * 16, &chain->unk_BC);
return chain;
}
void RadarChain_Free(RadarChain *chain)
{
Heap_FreeToHeap(chain);
}
void RadarChain_Clear(RadarChain *chain)
{
chain->count = 0;
chain->shakeType = PATCH_SHAKE_SOFT;
chain->species = 0;
chain->level = 0;
chain->active = FALSE;
chain->unk_D0 = 0;
chain->unk_14 = 1;
chain->unk_18 = 0;
MI_CpuClear8(chain->patch, sizeof(GrassPatch) * NUM_GRASS_PATCHES);
for (u8 patchRing = 0; patchRing < NUM_GRASS_PATCHES; patchRing++) {
chain->patch[patchRing].active = FALSE;
}
}
BOOL RadarSpawnPatches(FieldSystem *fieldSystem, const int param1, const int param2, RadarChain *chain)
{
u8 v1, v2;
u8 v3;
u8 v4;
int v5, v6;
u8 v7;
u8 ringTileCount[NUM_GRASS_PATCHES] = { // Number of tiles in each ring of the radar. Lowest being the most outer ring
32,
24,
16,
8
};
const VecFx32 *v8 = PlayerAvatar_PosVector(fieldSystem->playerAvatar);
v7 = 0;
for (u8 patchRing = 0; patchRing < NUM_GRASS_PATCHES; patchRing++) {
v3 = inline_020564D0(ringTileCount[patchRing]);
v1 = 9 - (patchRing * 2);
v2 = 9 - (patchRing * 2);
v4 = v3 / v1;
if (v4 == 0) {
v5 = patchRing + v3 % v1;
v6 = patchRing;
} else if (v4 == 1) {
v5 = patchRing + v3 % v1;
v6 = patchRing + v2 - 1;
} else {
GF_ASSERT(v3 >= (v1 * 2));
v4 = v3 - (v1 * 2);
v6 = patchRing + (v4 / 2) + 1;
if (v4 % 2 == 0) {
v5 = patchRing;
} else {
v5 = patchRing + v1 - 1;
}
}
BOOL v10 = CheckTileIsGrass(fieldSystem, v8->y, param1, param2, v5, v6, &chain->patch[patchRing]);
if (v10) {
v7++;
}
}
if (v7 == 0) {
RadarChain_Clear(chain);
sub_02055554(fieldSystem, sub_02055428(fieldSystem, fieldSystem->location->mapId), 1);
} else {
chain->active = TRUE;
}
return chain->active;
}
void SetupGrassPatches(FieldSystem *fieldSystem, const int param1, RadarChain *chain)
{
for (u8 patchRing = 0; patchRing < NUM_GRASS_PATCHES; patchRing++) {
if (chain->patch[patchRing].active) {
chain->patch[patchRing].continueChain = CheckPatchContinueChain(patchRing, param1);
if (!chain->patch[patchRing].continueChain) {
if (inline_020564D0(100) < 50) { // If the patch will break the chain, it has a 50/50 chance of shaking the other type
chain->patch[patchRing].shakeType = PATCH_SHAKE_SOFT;
} else {
chain->patch[patchRing].shakeType = PATCH_SHAKE_HARD;
}
chain->patch[patchRing].shiny = FALSE;
} else {
chain->patch[patchRing].shakeType = chain->shakeType; // A patch that continues the chain, shakes the type the chain is set to
chain->patch[patchRing].shiny = CheckPatchShiny(fieldSystem->chain->count);
}
}
}
}
void sub_02069638(FieldSystem *fieldSystem, RadarChain *chain)
{
for (u8 patchRing = 0; patchRing < NUM_GRASS_PATCHES; patchRing++) {
if (chain->patch[patchRing].active) {
int v1 = chain->patch[patchRing].unk_00;
int v2 = chain->patch[patchRing].unk_04;
if (chain->patch[patchRing].shiny) {
chain->patch[patchRing].unk_18 = ov5_021F3154(fieldSystem, v1, v2, 2);
} else {
if (chain->patch[patchRing].shakeType == PATCH_SHAKE_SOFT) {
chain->patch[patchRing].unk_18 = ov5_021F3154(fieldSystem, v1, v2, 0);
} else {
chain->patch[patchRing].unk_18 = ov5_021F3154(fieldSystem, v1, v2, 1);
}
}
} else {
chain->patch[patchRing].unk_18 = NULL;
}
}
}
BOOL sub_02069690(RadarChain *chain)
{
u8 v0 = 0;
for (u8 patchRing = 0; patchRing < NUM_GRASS_PATCHES; patchRing++) {
if (chain->patch[patchRing].unk_18 != NULL) {
if (ov5_021F31A8(chain->patch[patchRing].unk_18)) {
sub_0207136C(chain->patch[patchRing].unk_18);
chain->patch[patchRing].unk_18 = NULL;
v0++;
}
} else {
v0++;
}
}
if (v0 >= 4) {
return TRUE;
}
return FALSE;
}
BOOL sub_020696DC(const int param0, const int param1, FieldSystem *fieldSystem, RadarChain *chain, int *param4, BOOL *param5, BOOL *param6)
{
u8 patchRing;
*param5 = 0;
*param6 = 0;
if (!sub_020698AC(chain, param0, param1, &patchRing)) {
return FALSE;
}
chain->unk_18 = 1;
BOOL continueChain = chain->patch[patchRing].continueChain;
int shakeType = chain->patch[patchRing].shakeType;
if (chain->unk_14 == 0) {
if (continueChain) {
IncWithCap(&(chain->count));
*param4 = shakeType;
*param5 = 1;
sub_020698E4(fieldSystem, chain);
*param6 = chain->patch[patchRing].shiny;
return TRUE;
} else {
*param4 = shakeType;
}
} else {
*param4 = shakeType;
chain->unk_14 = 0;
chain->unk_D0 = sub_0206994C(fieldSystem);
}
chain->shakeType = *param4;
return TRUE;
}
void SetRadarMon(RadarChain *chain, const int species, const int level)
{
GF_ASSERT(species != 0);
chain->species = species;
chain->level = level;
}
void GetRadarMon(RadarChain *chain, int *species, int *level)
{
*species = chain->species;
*level = chain->level;
}
const BOOL sub_02069798(const RadarChain *chain)
{
return chain->unk_18;
}
void sub_0206979C(FieldSystem *fieldSystem)
{
BOOL v0;
GrassPatch *patch;
int patchRing;
if (!fieldSystem->chain->active || fieldSystem->task != NULL) {
return;
}
for (patchRing = 0; patchRing < NUM_GRASS_PATCHES; patchRing++) {
patch = &(fieldSystem->chain->patch[patchRing]);
v0 = sub_0201CF7C(&(patch->position), &(fieldSystem->chain->unk_BC));
if (patch->active && !v0) {
patch->active = FALSE;
}
}
int v3 = 0;
for (patchRing = 0; patchRing < NUM_GRASS_PATCHES; patchRing++) {
patch = &(fieldSystem->chain->patch[patchRing]);
if (patch->active == 0) {
v3++;
}
}
if (v3 == 4) {
RadarChain_Clear(fieldSystem->chain);
sub_02055554(fieldSystem, sub_02055428(fieldSystem, fieldSystem->location->mapId), 1);
}
}
BOOL GetRadarChainActive(const RadarChain *chain)
{
return chain->active;
}
static BOOL CheckTileIsGrass(FieldSystem *fieldSystem, const fx32 param1, const int param2, const int param3, const u8 param4, const u8 param5, GrassPatch *patch)
{
int v0 = (param2 - (9 / 2)) + param4;
int v1 = (param3 - (9 / 2)) + param5;
patch->unk_00 = v0;
patch->unk_04 = v1;
u8 v2 = FieldSystem_GetTileAttributes(fieldSystem, v0, v1);
if (sub_0205DAC8(v2)) {
u8 v3;
patch->position.x = FX32_ONE * 16 * v0;
patch->position.z = FX32_ONE * 16 * v1;
patch->position.y = sub_02054FBC(fieldSystem, 0, patch->position.x, patch->position.z, &v3);
if (param1 != patch->position.y) {
patch->active = FALSE;
return FALSE;
}
int v5 = v0 / 32;
int v6 = v1 / 32;
int v4 = sub_02039E30(fieldSystem->unk_2C, v5, v6);
if (fieldSystem->location->mapId != v4) {
patch->active = FALSE;
return FALSE;
}
patch->active = TRUE;
return TRUE;
} else {
patch->active = FALSE;
return FALSE;
}
}
static BOOL sub_020698AC(const RadarChain *chain, const int param1, const int param2, u8 *param3)
{
for (u8 patchRing = 0; patchRing < NUM_GRASS_PATCHES; patchRing++) {
if (chain->patch[patchRing].active) {
if ((chain->patch[patchRing].unk_00 == param1) && (chain->patch[patchRing].unk_04 == param2)) {
*param3 = patchRing;
return TRUE;
}
}
}
return FALSE;
}
static void sub_020698E4(FieldSystem *fieldSystem, RadarChain *chain)
{
UnkStruct_020698E4 *v0 = sub_0202D830(sub_0202D834(fieldSystem->saveData));
int v1 = v0->unk_00[chain->unk_D0].unk_02;
if (v1 < chain->count) {
v0->unk_00[chain->unk_D0].unk_02 = chain->count;
v0->unk_00[chain->unk_D0].unk_00 = chain->species;
ov6_02243160(v0);
if (v0->unk_00[chain->unk_D0].unk_02 <= chain->count) {
for (int v2 = 0; v2 < 3; v2++) {
if (v0->unk_00[(2 - v2)].unk_02 == chain->count) {
chain->unk_D0 = (2 - v2);
return;
}
}
GF_ASSERT(FALSE);
}
}
}
static u8 sub_0206994C(FieldSystem *fieldSystem)
{
u8 v1;
BOOL v2;
UnkStruct_020698E4 *v0 = sub_0202D830(sub_0202D834(fieldSystem->saveData));
for (v1 = 0; v1 < 3; v1++) {
if (v0->unk_00[v1].unk_00 == 0) {
return v1;
}
}
(v0->unk_00[0].unk_02 < v0->unk_00[1].unk_02) ? (v2 = 1) : (v2 = 0);
if (v2) {
v1 = 0;
} else {
v1 = 1;
}
(v0->unk_00[v1].unk_02 < v0->unk_00[2].unk_02) ? (v2 = 1) : (v2 = 0);
if (!v2) {
v1 = 2;
}
return v1;
}
static BOOL CheckPatchContinueChain(const u8 patchRing, const int battleResult)
{
u8 *rates;
u8 ratesNormal[4] = { 88, 68, 48, 28 };
u8 ratesBoosted[4] = { 98, 78, 58, 38 };
if (battleResult == BATTLE_RESULT_WIN) { // If the battle resulted in fainting the mon, use the regular rates
rates = ratesNormal;
} else if (battleResult == BATTLE_RESULT_CAPTURED_MON) { // If the battle resulted in a capture, use the boosted rates
rates = ratesBoosted;
}
if (inline_020564D0(100) < rates[patchRing]) { // Check if random number falls within the rates
return TRUE; // Patch will continue the chain
} else {
return FALSE; // Patch will break the chain
}
}
BOOL RefreshRadarChain(FieldTask *taskMan)
{
FieldSystem *fieldSystem = FieldTask_GetFieldSystem(taskMan);
int *v1 = FieldTask_GetEnv(taskMan);
switch (*v1) {
case 0:
MapObjectMan_PauseAllMovement(fieldSystem->mapObjMan);
u8 *v2 = sub_0202D9C4(sub_0202D834(fieldSystem->saveData));
if (*v2 < RADAR_BATTERY_STEPS) {
ScriptManager_Start(taskMan, 8970, NULL, NULL);
*(u16 *)FieldSystem_GetScriptMemberPtr(fieldSystem, SCRIPT_DATA_PARAMETER_0) = RADAR_BATTERY_STEPS - (*v2);
*v1 = 4;
} else {
*v2 = 0;
int v3 = Player_GetXPos(fieldSystem->playerAvatar);
int v4 = Player_GetZPos(fieldSystem->playerAvatar);
RadarSpawnPatches(fieldSystem, v3, v4, fieldSystem->chain);
if (fieldSystem->chain->active) {
SetupGrassPatches(fieldSystem, 0x1, fieldSystem->chain);
sub_02069638(fieldSystem, fieldSystem->chain);
*v1 = 1;
} else {
*v1 = 3;
}
}
break;
case 1:
Sound_PlayBGM(SEQ_POKERADAR);
*v1 = 2;
break;
case 2:
if (sub_02069690(fieldSystem->chain)) {
*v1 = 4;
}
break;
case 4:
Heap_FreeToHeap(v1);
MapObjectMan_UnpauseAllMovement(fieldSystem->mapObjMan);
return TRUE;
break;
case 3:
ScriptManager_Start(taskMan, 8971, NULL, NULL);
*v1 = 4;
break;
}
return FALSE;
}
static BOOL CheckPatchShiny(const int chainCount)
{
if (!chainCount) {
return FALSE;
}
int rate = 8200 - (chainCount * 200);
if (rate < 200) {
rate = 200;
}
if (!inline_020564D0(rate)) {
return TRUE;
} else {
return FALSE;
}
}
void sub_02069B74(FieldSystem *fieldSystem)
{
IncWithCap(&(fieldSystem->chain->count));
sub_020698E4(fieldSystem, fieldSystem->chain);
}
int GetChainCount(FieldSystem *fieldSystem)
{
return fieldSystem->chain->count;
}
void RadarChargeStep(FieldSystem *fieldSystem)
{
u8 *v0;
if (Bag_CanRemoveItem(SaveData_GetBag(fieldSystem->saveData), 431, 1, 4) == 1) {
v0 = sub_0202D9C4(sub_0202D834(fieldSystem->saveData));
if ((*v0) < RADAR_BATTERY_STEPS) {
(*v0)++;
}
}
}
static void IncWithCap(int *param0)
{
(*param0)++;
if ((*param0) > 999) {
(*param0) = 999;
}
}