pokeplatinum/src/overlay023/secret_bases.c
2026-01-02 10:20:27 -08:00

2776 lines
91 KiB
C

#include "overlay023/secret_bases.h"
#include <nitro.h>
#include <string.h>
#include "constants/field/map_prop.h"
#include "constants/field_base_tiles.h"
#include "constants/goods.h"
#include "constants/heap.h"
#include "constants/map_object.h"
#include "constants/traps.h"
#include "generated/movement_actions.h"
#include "generated/trainer_score_events.h"
#include "struct_defs/underground.h"
#include "struct_defs/underground_record.h"
#include "field/field_system.h"
#include "overlay005/map_prop.h"
#include "overlay005/ov5_021F55CC.h"
#include "overlay005/ov5_021F5894.h"
#include "overlay023/ov23_02241F74.h"
#include "overlay023/ov23_02248F1C.h"
#include "overlay023/ov23_022499E4.h"
#include "overlay023/ov23_02253598.h"
#include "overlay023/underground_menu.h"
#include "overlay023/underground_player.h"
#include "overlay023/underground_player_talk.h"
#include "overlay023/underground_spheres.h"
#include "overlay023/underground_text_printer.h"
#include "overlay023/underground_traps.h"
#include "bg_window.h"
#include "comm_player_manager.h"
#include "communication_information.h"
#include "communication_system.h"
#include "field_map_change.h"
#include "field_system.h"
#include "field_task.h"
#include "font.h"
#include "game_records.h"
#include "goods.h"
#include "graphics.h"
#include "heap.h"
#include "journal.h"
#include "location.h"
#include "map_object_move.h"
#include "menu.h"
#include "message.h"
#include "player_avatar.h"
#include "render_window.h"
#include "savedata.h"
#include "screen_fade.h"
#include "sound_playback.h"
#include "string_gf.h"
#include "string_list.h"
#include "sys_task.h"
#include "sys_task_manager.h"
#include "system.h"
#include "system_flags.h"
#include "terrain_collision_manager.h"
#include "trainer_info.h"
#include "unk_0202854C.h"
#include "unk_02030EE0.h"
#include "unk_02033200.h"
#include "unk_020366A0.h"
#include "unk_0205F180.h"
#include "unk_020655F4.h"
#include "vars_flags.h"
#include "res/graphics/trap_effects/trap_effects.naix.h"
#include "res/text/bank/underground_capture_flag.h"
#include "res/text/bank/underground_common.h"
#define ENTRANCE_LOCATION_NONE 0xFFF
#define NETID_CURRENT_PLAYER_BASE 16
#define SECRET_BASE_COUNT 17
#define DEFAULT_BASE_RETURN_X 72
#define DEFAULT_BASE_RETURN_Z 437
enum BaseCreateRequest {
BASE_CREATE_REQ_USE_DIGGER_DRILL = 0,
BASE_CREATE_REQ_CLOSE_BASE,
BASE_CREATE_REQ_NEW_BASE,
BASE_CREATE_REQ_MOVE_BASE,
};
enum BaseCreateEvent {
BASE_CREATE_EVENT_CANT_DRILL = 0,
BASE_CREATE_EVENT_USE_DRILL,
BASE_CREATE_EVENT_CLOSE_BASE,
BASE_CREATE_EVENT_MOVE_BASE,
BASE_CREATE_EVENT_NEW_BASE,
BASE_CREATE_EVENT_CANT_ENTER,
BASE_CREATE_EVENT_CANT_DRILL_IN_BASE,
};
enum EnterPromptState {
ENTER_PROMPT_STATE_INIT = 0,
ENTER_PROMPT_STATE_OPEN_CONFIRM_MENU_OTHER_BASE,
ENTER_PROMPT_STATE_CONFIRM_OTHER_BASE,
ENTER_PROMPT_STATE_ENTER_AFTER_TEXT,
ENTER_PROMPT_STATE_OPEN_CONFIRM_MENU_OWN_BASE,
ENTER_PROMPT_STATE_CONFIRM_OWN_BASE,
ENTER_PROMPT_STATE_OPEN_CLOSE_DOOR_MENU,
ENTER_PROMPT_STATE_CLOSE_DOOR_MENU,
ENTER_PROMPT_STATE_CLOSE_DOOR_COMMS,
ENTER_PROMPT_STATE_ENTER_CLOSE_DOOR_AND_END,
ENTER_PROMPT_STATE_ENTER_AND_END,
};
enum ExitPromptState {
EXIT_PROMPT_STATE_INIT = 0,
EXIT_PROMPT_STATE_OPEN_CONFIRM_MENU,
EXIT_PROMPT_STATE_CONFIRM,
EXIT_PROMPT_STATE_OPEN_CONFIRM_MENU_DOOR_CLOSED,
EXIT_PROMPT_STATE_CONFIRM_DOOR_CLOSED,
EXIT_PROMPT_STATE_OPEN_COMMS_CONFIRM_MENU,
EXIT_PROMPT_STATE_CONFIRM_COMMS,
EXIT_PROMPT_STATE_EXIT_AND_END,
};
enum DrillState {
DRILL_STATE_INIT = 0,
DRILL_STATE_WAIT,
DRILL_STATE_CREATE_ENTRANCE,
DRILL_STATE_PRINT_PROMPT,
DRILL_STATE_CANCEL_AFTER_BUTTON_PRESS,
DRILL_STATE_OPEN_CONFIRM_MENU,
DRILL_STATE_CONFIRM,
DRILL_STATE_REMOVE_DRILL = 9,
DRILL_STATE_CREATE_BASE_AND_END,
};
enum FlagRankUpState {
FLAG_RANK_UP_STATE_PRINT_FLAG_REGISTERED = 0,
FLAG_RANK_UP_STATE_PRINT_RANK_UP,
FLAG_RANK_UP_STATE_UPDATE_PC_PROP,
FLAG_RANK_UP_STATE_3_UNUSED,
FLAG_RANK_UP_STATE_END,
};
enum MoveToFromBaseState {
BASE_MOVE_STATE_INIT = 0,
BASE_MOVE_STATE_FADE_OUT,
BASE_MOVE_STATE_WAIT_FOR_FADE_OUT,
BASE_MOVE_STATE_STOP_FIELD_MAP,
BASE_MOVE_STATE_UPDATE_LOCATION,
BASE_MOVE_STATE_RESUME_FIELD_MAP,
BASE_MOVE_STATE_FADE_IN,
BASE_MOVE_STATE_WAIT_FOR_FADE_IN,
BASE_MOVE_STATE_END_AFTER_TEXT_OR_NEW_LINK,
BASE_MOVE_STATE_FRAME_DELAY,
BASE_MOVE_STATE_WAIT,
BASE_MOVE_STATE_BLOCK_ENTRANCE,
BASE_MOVE_STATE_FACE_NORTH_AND_END_AFTER_TEXT,
BASE_MOVE_STATE_END,
};
enum MoveStatus {
MOVE_STATUS_NONE = 0,
MOVE_STATUS_ENTERING,
MOVE_STATUS_ERROR_WHILE_ENTERING,
MOVE_STATUS_ERROR_WHILE_ENTERING_2 = 4,
MOVE_STATUS_ENTERING_2,
MOVE_STATUS_EXITING,
};
typedef struct SecretBaseInfo {
u8 ownerNetID;
u8 visitorNetID;
u8 secretBase[sizeof(SecretBase)];
} SecretBaseInfo;
typedef struct BaseEntrance {
u16 x;
u16 z;
u8 dir;
} BaseEntrance;
typedef struct BaseExitEvent {
u16 x;
u16 z;
u8 netID;
u8 dir;
u8 forceExit;
} BaseExitEvent;
typedef struct SecretBasesEnv {
FieldSystem *fieldSystem;
SysTask *sysTask;
SecretBaseInfo baseInfo[SECRET_BASE_COUNT];
SecretBaseInfo *currentOccupiedBaseInfo;
u32 baseCollisions[SECRET_BASE_COUNT][SECRET_BASE_DEPTH];
BaseEntrance baseEntrances[MAX_CONNECTED_PLAYERS];
BaseEntrance baseEntrancesServer[MAX_CONNECTED_PLAYERS];
u8 moveStatus;
u8 baseEntrancePropIDs[SECRET_BASE_COUNT];
u16 baseEntrancePropXCoords[SECRET_BASE_COUNT];
u16 baseEntrancePropZCoords[SECRET_BASE_COUNT];
u8 baseEntrancePropDirs[SECRET_BASE_COUNT];
u8 obtainedFlagOwnerNetIDs[MAX_CONNECTED_PLAYERS];
u8 flagStealVictimNetIDs[MAX_CONNECTED_PLAYERS];
u8 tookBackFlagMessageQueued[MAX_CONNECTED_PLAYERS];
u8 occupiedBaseOwnerIDs[MAX_CONNECTED_PLAYERS];
u8 baseTransitioningOwnerNetIDs[MAX_CONNECTED_PLAYERS]; // netID of the base the player is currently entering/exiting
u8 baseEnteringOwnerNetIDs[MAX_CONNECTED_PLAYERS]; // netID of the base the player is currently entering
u8 visitedBaseOwnerNetIDs[MAX_CONNECTED_PLAYERS];
u8 playerAffectedByTool[MAX_CONNECTED_PLAYERS];
u8 baseEntrancesBuffer[MAX_CONNECTED_PLAYERS * 4];
u16 baseReturnXCoords[MAX_CONNECTED_PLAYERS];
u16 baseReturnZCoords[MAX_CONNECTED_PLAYERS];
u16 baseReturnDirs[MAX_CONNECTED_PLAYERS];
u16 currentBaseReturnXCoord;
u16 currentBaseReturnZCoord;
u8 currentBaseReturnDir;
u8 unused;
u8 dummy;
u8 baseEntranceLocationsReceived;
u8 baseEntranceGraphicsDisabled;
u8 baseEntranceGraphicsEnabled;
u8 currentPlayerInBase;
} SecretBasesEnv;
typedef struct BaseTransitionContext {
FieldSystem *fieldSystem;
Menu *menu;
SysTask *sysTask;
int state;
int subState;
int mapID;
int warpID;
int x;
int z;
int dir;
u8 initialConnectedCount;
u8 timer;
u8 unused;
u8 netID;
u8 baseOwnerNetID;
u8 forceExit;
u8 showBlockedEntranceMessage;
} BaseTransitionContext;
typedef struct DiggerDrillContext {
FieldSystem *fieldSystem;
SysTask *sysTask;
Menu *menu;
int state;
u8 unused;
u8 timer;
u8 hasExistingBase;
} DiggerDrillContext;
typedef struct BaseTransitionPromptEvent {
u16 x;
u16 z;
u8 netID;
u8 baseOwnerNetID;
u8 dir;
u8 entering; // false if exiting
} BaseTransitionPromptEvent;
typedef struct BaseTransitionEvent {
u8 baseOwnerNetID;
u8 success;
u8 entering; // false if exiting
} BaseTransitionEvent;
typedef struct SecretBaseCreateEvent {
u8 netID;
u8 type;
} SecretBaseCreateEvent;
typedef struct FlagRankUpEvent {
u8 netID;
u8 prevFlagRank;
} FlagRankUpEvent;
typedef struct FlagRankUpContext {
int state;
u8 unused;
u8 prevFlagRank;
} FlagRankUpContext;
typedef struct GoodInteractionEvent {
u8 netID;
u8 bankEntry;
} GoodInteractionEvent;
static void SecretBases_CalculateBaseCollision(SecretBase *secretBase, u32 *baseCollision);
static void SecretBases_SendBaseEntrancesBuffer(void);
static void SecretBases_ClearAllBaseEntranceProps(void);
static void SecretBases_SetBaseEntrancePropLocation(int x, int z, int dir, int netID);
static void SecretBases_StartMoveToFromSecretBaseTask(FieldSystem *fieldSystem, int x, int z, int dir, int netID, BOOL forceExit);
static void SecretBases_StartExitBasePromptTask(FieldSystem *fieldSystem, int x, int z, int dir, int baseOwnerNetID, int netID);
static void SecretBases_StartEnterBasePromptTask(FieldSystem *fieldSystem, int x, int z, int dir, int baseOwnerNetID, int netID);
static BOOL SecretBases_TryEnterBase(int baseOwnerNetID, int netID);
static void SecretBases_ExitBase(int baseOwnerNetID, int netID, BOOL forceExit);
static void SecretBases_CreateBase(void);
static void SecretBases_ClearBaseEntranceProp(int netID);
static void SecretBases_DrawBaseEntrancesTask(SysTask *unused, void *unused1);
static void ov23_0224DC08(void);
static void ov23_0224DC24(void);
static SecretBasesEnv *secretBasesEnv = NULL;
static const WindowTemplate Unk_ov23_02256864 = {
.bgLayer = BG_LAYER_MAIN_3,
.tilemapLeft = 25,
.tilemapTop = 13,
.width = 6,
.height = 4,
.palette = 13,
.baseTile = 543,
};
static const WindowTemplate Unk_ov23_0225686C = {
.bgLayer = BG_LAYER_MAIN_3,
.tilemapLeft = 16,
.tilemapTop = 13,
.width = 15,
.height = 4,
.palette = 13,
.baseTile = 505,
};
// clang-format off
// these refer to a 8x2 grid of secret bases, not the grid of walkable tiles
static u8 sSecretBaseXCoordinates[] = {
1, 2, 3, 4, 5, 6, 7, 8,
1, 2, 3, 4, 5, 6, 7, 8,
[NETID_CURRENT_PLAYER_BASE] = 0
};
// these refer to a 8x2 grid of secret bases, not the grid of walkable tiles
static u8 sSecretBaseZCoordinates[] = {
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
[NETID_CURRENT_PLAYER_BASE] = 0
};
// clang-format on
static int SecretBases_GetOwnerNetIDFromCoordinates(int x, int z)
{
int secretBaseXCoord = x / SECRET_BASE_WIDTH;
int secretBaseZCoord = z / SECRET_BASE_DEPTH;
for (int netID = 0; netID < SECRET_BASE_COUNT; netID++) {
if (secretBaseXCoord == sSecretBaseXCoordinates[netID] && secretBaseZCoord == sSecretBaseZCoordinates[netID]) {
return netID;
}
}
return NETID_CURRENT_PLAYER_BASE;
}
static BOOL SecretBases_AreCoordinatesOnBaseExit(int x, int z)
{
const BaseEntrance entrance = {
.x = 15,
.z = 24,
.dir = DIR_NORTH,
};
const int baseWidth = SECRET_BASE_WIDTH;
for (int netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
if (x == entrance.x + netID * baseWidth + baseWidth && z == entrance.z) {
return TRUE;
}
}
return FALSE;
}
static void SecretBases_GetBaseExitCoordinates(int netID, BaseEntrance *out)
{
const BaseEntrance entrance = {
.x = 15,
.z = 24,
.dir = DIR_NORTH,
};
const int baseWidth = SECRET_BASE_WIDTH;
if (CommServerClient_IsInClosedSecretBase()) {
out->x = entrance.x;
out->z = entrance.z;
return;
}
if (netID == NETID_CURRENT_PLAYER_BASE) {
netID = 0;
}
out->x = entrance.x + netID * baseWidth + baseWidth;
out->z = entrance.z;
}
static void SecretBases_GetBaseExitCoordinatesOverrideNetID(int netID, BaseEntrance *out)
{
SecretBases_GetBaseExitCoordinates(CommSys_IsAlone() ? NETID_CURRENT_PLAYER_BASE : netID, out);
}
void SecretBasesEnv_Init(void *dest, FieldSystem *fieldSystem)
{
int netID;
if (secretBasesEnv) {
return;
}
GF_ASSERT(SecretBase_Size() == sizeof(SecretBase));
secretBasesEnv = dest;
MI_CpuFill8(secretBasesEnv, 0, sizeof(SecretBasesEnv));
secretBasesEnv->fieldSystem = fieldSystem;
for (netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
secretBasesEnv->baseEntrances[netID].x = ENTRANCE_LOCATION_NONE;
secretBasesEnv->baseEntrances[netID].z = ENTRANCE_LOCATION_NONE;
secretBasesEnv->baseEntrancesServer[netID].x = ENTRANCE_LOCATION_NONE;
secretBasesEnv->baseEntrancesServer[netID].z = ENTRANCE_LOCATION_NONE;
secretBasesEnv->baseTransitioningOwnerNetIDs[netID] = NETID_NONE;
secretBasesEnv->baseEnteringOwnerNetIDs[netID] = NETID_NONE;
secretBasesEnv->occupiedBaseOwnerIDs[netID] = NETID_NONE;
secretBasesEnv->visitedBaseOwnerNetIDs[netID] = NETID_NONE;
secretBasesEnv->obtainedFlagOwnerNetIDs[netID] = NETID_NONE;
secretBasesEnv->flagStealVictimNetIDs[netID] = NETID_NONE;
secretBasesEnv->tookBackFlagMessageQueued[netID] = 0xff;
secretBasesEnv->baseReturnXCoords[netID] = DEFAULT_BASE_RETURN_X;
secretBasesEnv->baseReturnZCoords[netID] = DEFAULT_BASE_RETURN_Z;
secretBasesEnv->baseReturnDirs[netID] = DIR_SOUTH;
}
for (netID = 0; netID < SECRET_BASE_COUNT; netID++) {
SecretBase *secretBase = (SecretBase *)secretBasesEnv->baseInfo[netID].secretBase;
SecretBase_Init(secretBase);
secretBasesEnv->baseEntrancePropIDs[netID] = PROP_NONE;
secretBasesEnv->baseEntrancePropDirs[netID] = DIR_NONE;
}
MI_CpuFill8(secretBasesEnv->baseCollisions, 0xFF, SECRET_BASE_COUNT * SECRET_BASE_DEPTH * sizeof(u32));
SecretBases_LoadCurrentPlayerBase(fieldSystem);
secretBasesEnv->currentBaseReturnXCoord = DEFAULT_BASE_RETURN_X;
secretBasesEnv->currentBaseReturnZCoord = DEFAULT_BASE_RETURN_Z;
secretBasesEnv->currentBaseReturnDir = DIR_SOUTH;
secretBasesEnv->sysTask = SysTask_Start(SecretBases_DrawBaseEntrancesTask, NULL, 100);
}
void SecretBases_LoadCurrentPlayerBase(FieldSystem *fieldSystem)
{
SecretBase *secretBase = SaveData_GetSecretBase(FieldSystem_GetSaveData(fieldSystem));
UndergroundRecord *undergroundRecord = SecretBase_GetUndergroundRecord(secretBase);
UndergroundRecord_SetTrainerScore(undergroundRecord, GameRecords_GetTrainerScore(SaveData_GetGameRecords(fieldSystem->saveData)));
MI_CpuCopy8(secretBase, secretBasesEnv->baseInfo[NETID_CURRENT_PLAYER_BASE].secretBase, sizeof(SecretBase));
SecretBases_CalculateBaseCollision(secretBase, secretBasesEnv->baseCollisions[NETID_CURRENT_PLAYER_BASE]);
MI_CpuCopy8(secretBase, secretBasesEnv->baseInfo[0].secretBase, sizeof(SecretBase));
SecretBases_CalculateBaseCollision(secretBase, secretBasesEnv->baseCollisions[0]);
}
static void SecretBases_AddGoodCollisionToBaseCollision(int x, int z, const u8 *goodCollision, u32 *baseCollision)
{
for (int i = 0; i < 3; i++) {
if (z + i < SECRET_BASE_DEPTH) {
for (int j = 0; j < 3; j++) {
if (goodCollision[i * 3 + j]) {
if (x + j < SECRET_BASE_WIDTH) {
baseCollision[i + z] &= ~(0x1 << (x + j));
}
}
}
}
}
}
static void SecretBases_CalculateBaseCollision(SecretBase *secretBase, u32 *baseCollision)
{
const u8 *goodCollision;
// clang-format off
u8 pcCollision[] = {
1, 1, 0,
0, 0, 0,
0, 0, 0,
};
u8 boulderCollision[] = {
1, 1, 0,
1, 1, 0,
0, 0, 0,
};
// clang-format on
MI_CpuFill8(baseCollision, 0xFF, 32 * sizeof(u32));
for (int i = 0; i < MAX_PLACED_GOODS + MAX_BASE_BOULDERS + 1; i++) {
int goodID = SecretBase_GetGoodIDAtIndex(secretBase, i);
if (goodID == UG_GOOD_NONE) {
continue;
}
int x = SecretBase_GetGoodXCoordAtIndex(secretBase, i);
int z = SecretBase_GetGoodZCoordAtIndex(secretBase, i);
if (i == 0) {
goodCollision = pcCollision;
} else if (i < MAX_PLACED_GOODS + 1) {
goodCollision = Good_GetCollision(goodID);
} else {
goodCollision = boulderCollision;
}
SecretBases_AddGoodCollisionToBaseCollision(x, z, goodCollision, baseCollision);
}
}
void SecretBases_DisableBaseEntranceGraphics(void)
{
SecretBases_ClearAllBaseEntranceProps();
if (secretBasesEnv->sysTask) {
SysTask_Done(secretBasesEnv->sysTask);
secretBasesEnv->sysTask = NULL;
}
secretBasesEnv->baseEntranceGraphicsDisabled = TRUE;
}
void SecretBases_EnableBaseEntranceGraphics(void)
{
secretBasesEnv->baseEntranceGraphicsDisabled = FALSE;
if (!secretBasesEnv->currentPlayerInBase) {
int netID;
for (netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
SecretBases_ClearBaseEntranceProp(netID);
}
for (netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
BaseEntrance *entrance = &secretBasesEnv->baseEntrances[netID];
if (entrance->x != ENTRANCE_LOCATION_NONE && entrance->z != ENTRANCE_LOCATION_NONE) {
SecretBases_SetBaseEntrancePropLocation(entrance->x, entrance->z, entrance->dir, netID);
}
}
}
if (secretBasesEnv->sysTask == NULL) {
secretBasesEnv->sysTask = SysTask_Start(SecretBases_DrawBaseEntrancesTask, NULL, 100);
}
}
void SecretBasesEnv_Free(void)
{
if (secretBasesEnv->sysTask) {
SysTask_Done(secretBasesEnv->sysTask);
secretBasesEnv->sysTask = NULL;
}
SecretBases_ClearAllBaseEntranceProps();
if (secretBasesEnv) {
Heap_Free(secretBasesEnv);
}
secretBasesEnv = NULL;
}
void SecretBases_ResetAllBaseInfo(void)
{
for (int netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
SecretBase *secretBase = (SecretBase *)secretBasesEnv->baseInfo[netID].secretBase;
SecretBase_SetInactive(secretBase);
secretBasesEnv->baseEntrances[netID].x = ENTRANCE_LOCATION_NONE;
secretBasesEnv->baseEntrances[netID].z = ENTRANCE_LOCATION_NONE;
secretBasesEnv->baseEntrancesServer[netID].x = ENTRANCE_LOCATION_NONE;
secretBasesEnv->baseEntrancesServer[netID].z = ENTRANCE_LOCATION_NONE;
}
MI_CpuFill8(secretBasesEnv->baseCollisions, 0xFF, SECRET_BASE_COUNT * SECRET_BASE_DEPTH * sizeof(u32));
SecretBases_LoadCurrentPlayerBase(secretBasesEnv->fieldSystem);
}
void SecretBases_ClearAllBaseInfo(void)
{
for (int netID = 0; netID < SECRET_BASE_COUNT; netID++) {
SecretBase *secretBase = (SecretBase *)secretBasesEnv->baseInfo[netID].secretBase;
SecretBase_Init(secretBase);
}
SecretBases_LoadCurrentPlayerBase(secretBasesEnv->fieldSystem);
}
int SecretBasesEnv_Size(void)
{
return sizeof(SecretBasesEnv);
}
void SecretBases_ResetBaseEntranceData(int netID)
{
if (secretBasesEnv) {
secretBasesEnv->occupiedBaseOwnerIDs[netID] = NETID_NONE;
secretBasesEnv->baseTransitioningOwnerNetIDs[netID] = NETID_NONE;
secretBasesEnv->baseEnteringOwnerNetIDs[netID] = NETID_NONE;
secretBasesEnv->baseEntrancesServer[netID].x = ENTRANCE_LOCATION_NONE;
secretBasesEnv->baseEntrancesServer[netID].z = ENTRANCE_LOCATION_NONE;
}
}
void SecretBases_RemoveBaseEntrance(int netID)
{
if (secretBasesEnv) {
SecretBases_ClearBaseEntranceProp(netID);
secretBasesEnv->baseEntrances[netID].x = ENTRANCE_LOCATION_NONE;
secretBasesEnv->baseEntrances[netID].z = ENTRANCE_LOCATION_NONE;
}
}
static void SecretBases_ResumeFieldSystem(int unused)
{
CommPlayerMan_ResumeFieldSystem();
}
static int SecretBases_GetEntranceOwnerNetIDFromCoords(int x, int z)
{
for (int netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
SecretBase *secretBase = (SecretBase *)secretBasesEnv->baseInfo[netID].secretBase;
if (!SecretBase_IsActive(secretBase)) {
continue;
}
if (!CommPlayer_IsActive(netID)) {
continue;
}
if (x == SecretBase_GetEntranceXCoord(secretBase) && z == SecretBase_GetEntranceZCoord(secretBase)) {
return netID;
}
}
return NETID_NONE;
}
void SecretBases_ProcessBaseTransitionPromptEvent(int unused0, int unused1, void *data, void *unused3)
{
BaseTransitionPromptEvent *event = data;
if (event->netID != CommSys_CurNetId()) {
return;
}
if (secretBasesEnv->baseEntranceGraphicsDisabled) {
return;
}
if (event->entering) {
SecretBases_StartEnterBasePromptTask(secretBasesEnv->fieldSystem, event->x, event->z, DIR_NORTH, event->netID, event->baseOwnerNetID);
} else {
SecretBases_StartExitBasePromptTask(secretBasesEnv->fieldSystem, event->x, event->z, event->dir, event->netID, event->baseOwnerNetID);
}
}
void SecretBases_ProcessFailedBaseEnter(int unused0, int unused1, void *data, void *unused3)
{
u8 *netID = data;
if (CommSys_CurNetId() == *netID) {
CommPlayerMan_PauseFieldSystem();
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_WallCrumbledCantEnter, TRUE, SecretBases_ResumeFieldSystem);
ov23_0224DC24();
}
}
int CommPacketSizeOf_BaseTransitionPromptEvent(void)
{
return sizeof(BaseTransitionPromptEvent);
}
void SecretBases_ProcessBaseTransitionEvent(int netID, int unused1, void *data, void *unused3)
{
BaseTransitionEvent *event = data;
u8 buffer = netID;
if (CommSys_CurNetId() != 0) {
GF_ASSERT(FALSE);
return;
}
if (event->success) {
if (event->entering) {
if (!SecretBases_TryEnterBase(event->baseOwnerNetID, netID)) {
secretBasesEnv->baseTransitioningOwnerNetIDs[netID] = NETID_NONE;
CommSys_SendDataFixedSizeServer(61, &buffer);
}
} else {
SecretBases_ExitBase(event->baseOwnerNetID, netID, FALSE);
}
} else {
secretBasesEnv->baseTransitioningOwnerNetIDs[netID] = NETID_NONE;
}
}
int CommPacketSizeOf_BaseTransitionEvent(void)
{
return sizeof(BaseTransitionEvent);
}
static BOOL SecretBases_TryEnterBase(int baseOwnerNetID, int netID)
{
SecretBaseInfo *baseInfo = &secretBasesEnv->baseInfo[baseOwnerNetID];
SecretBase *secretBase = (SecretBase *)baseInfo->secretBase;
if (!SecretBase_IsActive(secretBase)) {
return FALSE;
}
if (CommSys_IsCmdQueuedServer(54)) {
return FALSE;
}
for (int i = 0; i < MAX_CONNECTED_PLAYERS; i++) {
if (CommSys_IsPlayerConnected(i)) {
if (secretBasesEnv->baseEnteringOwnerNetIDs[i] == baseOwnerNetID) {
return FALSE;
}
}
}
BaseEntrance entrance;
SecretBases_GetBaseExitCoordinatesOverrideNetID(baseOwnerNetID, &entrance);
baseInfo->visitorNetID = netID;
SecretBases_SendEnteredBase(baseOwnerNetID);
secretBasesEnv->baseTransitioningOwnerNetIDs[netID] = baseOwnerNetID;
secretBasesEnv->baseEnteringOwnerNetIDs[netID] = baseOwnerNetID;
UndergroundPlayer_MoveToFromSecretBaseServer(netID, entrance.x, entrance.z, DIR_NORTH);
return TRUE;
}
static void SecretBases_ExitBase(int baseOwnerNetID, int netID, BOOL forceExit)
{
BaseExitEvent event;
SecretBase *unused = (SecretBase *)&secretBasesEnv->baseInfo[baseOwnerNetID].secretBase;
BaseEntrance unused2;
SecretBases_GetBaseExitCoordinates(baseOwnerNetID, &unused2);
secretBasesEnv->baseTransitioningOwnerNetIDs[netID] = baseOwnerNetID;
int x, z, dir;
if (CommSys_IsAlone()) {
x = secretBasesEnv->currentBaseReturnXCoord;
z = secretBasesEnv->currentBaseReturnZCoord;
dir = secretBasesEnv->currentBaseReturnDir;
} else {
x = secretBasesEnv->baseReturnXCoords[netID];
z = secretBasesEnv->baseReturnZCoords[netID];
dir = secretBasesEnv->baseReturnDirs[netID];
}
UndergroundPlayer_MoveToFromSecretBaseServer(netID, x, z, dir);
x += MapObject_GetDxFromDir(dir);
z += MapObject_GetDzFromDir(dir);
event.x = x;
event.z = z;
event.netID = netID;
event.dir = dir;
event.forceExit = forceExit;
CommSys_SendDataFixedSizeServer(57, &event);
CommPlayerMan_SetMovementEnabled(netID, FALSE);
}
BOOL SecretBases_CheckForEnterExit(int netID, int x, int z)
{
BaseExitEvent exitEvent;
BaseEntrance entrance;
BaseTransitionPromptEvent promptEvent;
if (!secretBasesEnv) {
return FALSE;
}
if (netID != 0 && !CommSys_IsPlayerConnected(netID)) {
return FALSE;
}
if (UndergroundPlayer_IsAffectedByTrap(netID)) {
return FALSE;
}
if (secretBasesEnv->baseTransitioningOwnerNetIDs[netID] != NETID_NONE) {
return TRUE;
}
int baseOwnerNetID = SecretBases_GetEntranceOwnerNetIDFromCoords(x, z);
if (baseOwnerNetID != NETID_NONE) {
secretBasesEnv->baseTransitioningOwnerNetIDs[netID] = baseOwnerNetID;
promptEvent.entering = TRUE;
promptEvent.x = x;
promptEvent.z = z;
promptEvent.dir = DIR_NORTH;
promptEvent.netID = netID;
promptEvent.baseOwnerNetID = baseOwnerNetID;
CommSys_SendDataFixedSizeServer(58, &promptEvent);
CommPlayerMan_SetMovementEnabled(netID, FALSE);
return TRUE;
}
for (baseOwnerNetID = 0; baseOwnerNetID <= MAX_CONNECTED_PLAYERS; baseOwnerNetID++) {
SecretBase *secretBase = (SecretBase *)secretBasesEnv->baseInfo[baseOwnerNetID].secretBase;
if (!SecretBase_IsActive(secretBase)) {
continue;
}
SecretBases_GetBaseExitCoordinates(baseOwnerNetID, &entrance);
if (x == entrance.x && z == entrance.z) {
secretBasesEnv->baseTransitioningOwnerNetIDs[netID] = baseOwnerNetID;
promptEvent.entering = FALSE;
promptEvent.x = x;
promptEvent.z = z;
promptEvent.dir = DIR_NORTH;
promptEvent.netID = netID;
promptEvent.baseOwnerNetID = baseOwnerNetID;
CommSys_SendDataFixedSizeServer(58, &promptEvent);
CommPlayerMan_SetMovementEnabled(netID, FALSE);
return TRUE;
}
}
if (SecretBases_AreCoordinatesOnBaseExit(x, z)) {
exitEvent.x = secretBasesEnv->baseReturnXCoords[netID];
exitEvent.z = secretBasesEnv->baseReturnZCoords[netID];
exitEvent.netID = netID;
exitEvent.dir = secretBasesEnv->baseReturnDirs[netID];
exitEvent.forceExit = FALSE;
secretBasesEnv->baseTransitioningOwnerNetIDs[netID] = 0;
UndergroundPlayer_MoveToFromSecretBaseServer(netID, exitEvent.x, exitEvent.z, exitEvent.dir);
CommSys_SendDataFixedSizeServer(57, &exitEvent);
return TRUE;
}
return FALSE;
}
static void SecretBases_EndBaseTransitionPromptTaskSuccess(SysTask *sysTask, void *data)
{
BaseTransitionContext *ctx = data;
if (ctx->menu) {
Menu_DestroyForExit(ctx->menu, HEAP_ID_FIELD1);
}
SysTask_Done(sysTask);
Heap_Free(ctx);
CommManUnderground_ClearCurrentSysTaskInfo();
}
static void SecretBases_EndBaseTransitionPromptTaskFail(SysTask *sysTask, void *data)
{
BaseTransitionContext *ctx = data;
if (ctx->menu) {
Menu_DestroyForExit(ctx->menu, HEAP_ID_FIELD1);
}
BaseTransitionEvent event;
event.success = FALSE;
event.baseOwnerNetID = ctx->baseOwnerNetID;
event.entering = FALSE;
CommSys_SendDataFixedSize(59, &event);
SysTask_Done(sysTask);
Heap_Free(ctx);
CommManUnderground_ClearCurrentSysTaskInfo();
ov23_0224DC24();
}
static void SecretBases_ExitBasePromptTask(SysTask *sysTask, void *data)
{
BaseTransitionContext *ctx = data;
FieldSystem *fieldSystem = ctx->fieldSystem;
int input;
BOOL canceled = FALSE;
switch (ctx->state) {
case EXIT_PROMPT_STATE_INIT:
int bankEntry;
if (CommServerClient_IsInClosedSecretBase()) {
bankEntry = UndergroundCommon_Text_OpenDoorAndExitBasePrompt;
ctx->state = EXIT_PROMPT_STATE_OPEN_CONFIRM_MENU_DOOR_CLOSED;
} else {
bankEntry = UndergroundCommon_Text_ExitBasePrompt;
ctx->state = EXIT_PROMPT_STATE_OPEN_CONFIRM_MENU;
}
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), bankEntry, FALSE, NULL);
break;
case EXIT_PROMPT_STATE_OPEN_CONFIRM_MENU:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
ctx->menu = Menu_MakeYesNoChoice(fieldSystem->bgConfig, &Unk_ov23_02256864, BASE_TILE_STANDARD_WINDOW_FRAME, 11, HEAP_ID_FIELD1);
ctx->state = EXIT_PROMPT_STATE_CONFIRM;
}
break;
case EXIT_PROMPT_STATE_CONFIRM:
input = Menu_ProcessInputAndHandleExit(ctx->menu, HEAP_ID_FIELD1);
if (input == 0) {
ctx->menu = NULL;
ctx->state = EXIT_PROMPT_STATE_EXIT_AND_END;
} else if (input != MENU_NOTHING_CHOSEN) {
ctx->menu = NULL;
canceled = TRUE;
}
break;
case EXIT_PROMPT_STATE_OPEN_CONFIRM_MENU_DOOR_CLOSED:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
ctx->menu = Menu_MakeYesNoChoice(fieldSystem->bgConfig, &Unk_ov23_02256864, BASE_TILE_STANDARD_WINDOW_FRAME, 11, HEAP_ID_FIELD1);
ctx->state = EXIT_PROMPT_STATE_CONFIRM_DOOR_CLOSED;
}
break;
case EXIT_PROMPT_STATE_CONFIRM_DOOR_CLOSED:
input = Menu_ProcessInputAndHandleExit(ctx->menu, HEAP_ID_FIELD1);
if (input == 0) {
ctx->menu = NULL;
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_CommsWillBeLaunched, FALSE, NULL);
ctx->state = EXIT_PROMPT_STATE_OPEN_COMMS_CONFIRM_MENU;
} else if (input != MENU_NOTHING_CHOSEN) {
ctx->menu = NULL;
canceled = TRUE;
}
break;
case EXIT_PROMPT_STATE_OPEN_COMMS_CONFIRM_MENU:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
ctx->menu = Menu_MakeYesNoChoice(fieldSystem->bgConfig, &Unk_ov23_02256864, BASE_TILE_STANDARD_WINDOW_FRAME, 11, HEAP_ID_FIELD1);
ctx->state = EXIT_PROMPT_STATE_CONFIRM_COMMS;
}
break;
case EXIT_PROMPT_STATE_CONFIRM_COMMS:
input = Menu_ProcessInputAndHandleExit(ctx->menu, HEAP_ID_FIELD1);
if (input == 0) {
ctx->menu = NULL;
ctx->state = EXIT_PROMPT_STATE_EXIT_AND_END;
} else if (input != MENU_NOTHING_CHOSEN) {
ctx->menu = NULL;
canceled = TRUE;
}
break;
case EXIT_PROMPT_STATE_EXIT_AND_END:
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetCommonTextPrinter());
BaseTransitionEvent event;
event.success = TRUE;
event.baseOwnerNetID = ctx->baseOwnerNetID;
event.entering = FALSE;
CommSys_SendDataFixedSize(59, &event);
SecretBases_EndBaseTransitionPromptTaskSuccess(sysTask, ctx);
return;
}
if (!CommServerClient_IsInClosedSecretBase()) {
if (ctx->baseOwnerNetID < MAX_CONNECTED_PLAYERS && !CommSys_IsPlayerConnected(ctx->baseOwnerNetID) && CommSys_CurNetId() != 0) {
canceled = TRUE;
}
}
if (canceled) {
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetCommonTextPrinter());
SecretBases_EndBaseTransitionPromptTaskFail(sysTask, ctx);
CommPlayerMan_ResumeFieldSystem();
}
}
static void SecretBases_StartExitBasePromptTask(FieldSystem *fieldSystem, int x, int z, int dir, int netID, int baseOwnerNetID)
{
BaseTransitionContext *ctx = NULL;
ov23_0224DC08();
ctx = Heap_AllocAtEnd(HEAP_ID_FIELD1, sizeof(BaseTransitionContext));
MI_CpuClear8(ctx, sizeof(BaseTransitionContext));
ctx->warpID = WARP_ID_NONE;
ctx->x = x;
ctx->z = z;
ctx->netID = netID;
ctx->baseOwnerNetID = baseOwnerNetID;
ctx->mapID = MAP_HEADER_UNDERGROUND;
ctx->dir = dir;
ctx->fieldSystem = fieldSystem;
ctx->sysTask = SysTask_Start(SecretBases_ExitBasePromptTask, ctx, 100);
CommManUnderground_SetCurrentSysTask(ctx, ctx->sysTask, SecretBases_EndBaseTransitionPromptTaskFail);
CommPlayerMan_PauseFieldSystem();
}
static BaseTransitionContext *BaseTransitionContext_New(FieldSystem *fieldSystem, int x, int z, int dir, int netID, int baseOwnerNetID)
{
BaseTransitionContext *ctx = NULL;
if (fieldSystem->task == NULL) {
ctx = Heap_AllocAtEnd(HEAP_ID_FIELD2, sizeof(BaseTransitionContext));
MI_CpuClear8(ctx, sizeof(BaseTransitionContext));
ctx->warpID = WARP_ID_NONE;
ctx->x = x;
ctx->z = z;
ctx->netID = netID;
ctx->baseOwnerNetID = baseOwnerNetID;
GF_ASSERT(fieldSystem->location->mapId == MAP_HEADER_UNDERGROUND);
ctx->mapID = MAP_HEADER_UNDERGROUND;
ctx->dir = dir;
}
return ctx;
}
static int SecretBases_CountPlayersInBase(int ownerNetID, BOOL useServerLocation)
{
int count = 0;
for (int netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
if (!CommSys_IsPlayerConnected(netID)) {
continue;
}
int x, z;
if (useServerLocation) {
x = CommPlayer_GetXServerIfActive(netID);
z = CommPlayer_GetZServerIfActive(netID);
} else {
x = CommPlayer_XPos(netID);
z = CommPlayer_ZPos(netID);
}
if (!(x == 0xffff && z == 0xffff) && Underground_AreCoordinatesInSecretBase(x, z)) {
int baseNetID = SecretBases_GetOwnerNetIDFromCoordinates(x, z);
if (baseNetID == ownerNetID) {
count++;
}
}
}
return count;
}
static Menu *SecretBases_MakeLeaveOpenOrCloseMenu(BgConfig *bgConfig, const WindowTemplate *windowTemplate, u16 tile, u8 palette, u32 heapID)
{
MessageLoader *loader = UndergroundTextPrinter_GetMessageLoader(CommManUnderground_GetCommonTextPrinter());
StringList *choices = StringList_New(2, heapID);
StringList_AddFromMessageBank(choices, loader, UndergroundCommon_Text_LeaveDoorOpen, 0);
StringList_AddFromMessageBank(choices, loader, UndergroundCommon_Text_CloseAndDecorate, 1);
MenuTemplate menuTemplate;
menuTemplate.choices = choices;
menuTemplate.window = Window_New(heapID, 1);
menuTemplate.fontID = FONT_SYSTEM;
menuTemplate.xSize = 1;
menuTemplate.ySize = 2;
menuTemplate.lineSpacing = 0;
menuTemplate.suppressCursor = FALSE;
menuTemplate.lineSpacing = 0;
Window_AddFromTemplate(bgConfig, menuTemplate.window, windowTemplate);
Window_DrawStandardFrame(menuTemplate.window, TRUE, tile, palette);
return Menu_NewAndCopyToVRAM(&menuTemplate, 8, 0, 0, heapID, PAD_BUTTON_B);
}
static void SecretBases_EnterBasePromptTask(SysTask *sysTask, void *data)
{
BaseTransitionContext *ctx = data;
FieldSystem *fieldSystem = ctx->fieldSystem;
int input;
BOOL canceled = FALSE;
switch (ctx->state) {
case ENTER_PROMPT_STATE_INIT:
int bankEntry;
if (ctx->baseOwnerNetID != ctx->netID) {
bankEntry = UndergroundCommon_Text_DiscoveredCavernEnterPrompt;
ctx->state = ENTER_PROMPT_STATE_OPEN_CONFIRM_MENU_OTHER_BASE;
} else {
bankEntry = UndergroundCommon_Text_EnterOwnBasePrompt;
ctx->state = ENTER_PROMPT_STATE_OPEN_CONFIRM_MENU_OWN_BASE;
}
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), bankEntry, FALSE, NULL);
break;
case ENTER_PROMPT_STATE_OPEN_CONFIRM_MENU_OTHER_BASE:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
ctx->menu = Menu_MakeYesNoChoice(fieldSystem->bgConfig, &Unk_ov23_02256864, BASE_TILE_STANDARD_WINDOW_FRAME, 11, HEAP_ID_FIELD1);
ctx->state = ENTER_PROMPT_STATE_CONFIRM_OTHER_BASE;
}
break;
case ENTER_PROMPT_STATE_CONFIRM_OTHER_BASE:
input = Menu_ProcessInputAndHandleExit(ctx->menu, HEAP_ID_FIELD1);
if (input == 0) {
ctx->menu = NULL;
ctx->state = ENTER_PROMPT_STATE_ENTER_AFTER_TEXT;
} else if (input != MENU_NOTHING_CHOSEN) {
ctx->menu = NULL;
canceled = TRUE;
}
break;
case ENTER_PROMPT_STATE_ENTER_AFTER_TEXT:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
ctx->state = ENTER_PROMPT_STATE_ENTER_AND_END;
}
break;
case ENTER_PROMPT_STATE_OPEN_CONFIRM_MENU_OWN_BASE:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
ctx->menu = Menu_MakeYesNoChoice(fieldSystem->bgConfig, &Unk_ov23_02256864, BASE_TILE_STANDARD_WINDOW_FRAME, 11, HEAP_ID_FIELD1);
ctx->state = ENTER_PROMPT_STATE_CONFIRM_OWN_BASE;
}
break;
case ENTER_PROMPT_STATE_CONFIRM_OWN_BASE:
input = Menu_ProcessInputAndHandleExit(ctx->menu, HEAP_ID_FIELD1);
if (input == 0) {
ctx->menu = NULL;
if (UndergroundPlayer_IsHoldingFlag(ctx->baseOwnerNetID) || (SecretBases_CountPlayersInBase(ctx->baseOwnerNetID, 0) > 0)) {
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_EnteredOwnBase, FALSE, NULL);
ctx->state = ENTER_PROMPT_STATE_ENTER_AFTER_TEXT;
} else {
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_LeaveEntranceOpenOrClose, FALSE, NULL);
ctx->state = ENTER_PROMPT_STATE_OPEN_CLOSE_DOOR_MENU;
}
} else if (input != MENU_NOTHING_CHOSEN) {
ctx->menu = NULL;
canceled = TRUE;
}
break;
case ENTER_PROMPT_STATE_OPEN_CLOSE_DOOR_MENU:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
ctx->menu = SecretBases_MakeLeaveOpenOrCloseMenu(fieldSystem->bgConfig, &Unk_ov23_0225686C, BASE_TILE_STANDARD_WINDOW_FRAME, 11, HEAP_ID_FIELD1);
ctx->state = ENTER_PROMPT_STATE_CLOSE_DOOR_MENU;
}
break;
case ENTER_PROMPT_STATE_CLOSE_DOOR_MENU:
input = Menu_ProcessInputAndHandleExit(ctx->menu, HEAP_ID_FIELD1);
if (input == 0) {
ctx->menu = NULL;
ctx->state = ENTER_PROMPT_STATE_ENTER_AFTER_TEXT;
} else if (input == 1) {
ctx->menu = NULL;
ctx->state = ENTER_PROMPT_STATE_CLOSE_DOOR_COMMS;
} else if (input != MENU_NOTHING_CHOSEN) {
ctx->menu = NULL;
canceled = TRUE;
}
break;
case ENTER_PROMPT_STATE_CLOSE_DOOR_COMMS:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetCommonTextPrinter());
ov23_02249A74();
ctx->state = ENTER_PROMPT_STATE_ENTER_CLOSE_DOOR_AND_END;
}
break;
case ENTER_PROMPT_STATE_ENTER_CLOSE_DOOR_AND_END:
if (CommServerClient_IsInClosedSecretBase() && CommSys_CurNetId() == 0) {
u8 type = BASE_CREATE_REQ_CLOSE_BASE;
CommSys_SendDataFixedSize(86, &type);
SecretBases_EndBaseTransitionPromptTaskSuccess(sysTask, ctx);
return;
}
break;
case ENTER_PROMPT_STATE_ENTER_AND_END:
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetCommonTextPrinter());
BaseTransitionEvent event;
event.success = TRUE;
event.baseOwnerNetID = ctx->baseOwnerNetID;
event.entering = TRUE;
CommSys_SendDataFixedSize(59, &event);
SecretBases_EndBaseTransitionPromptTaskSuccess(sysTask, ctx);
secretBasesEnv->moveStatus = MOVE_STATUS_ENTERING;
return;
}
if (ctx->baseOwnerNetID != NETID_CURRENT_PLAYER_BASE && !CommPlayer_IsActive(ctx->baseOwnerNetID)) {
if (ctx->state != ENTER_PROMPT_STATE_CLOSE_DOOR_COMMS && ctx->state != ENTER_PROMPT_STATE_ENTER_CLOSE_DOOR_AND_END) {
canceled = TRUE;
}
}
if (canceled) {
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetCommonTextPrinter());
SecretBases_EndBaseTransitionPromptTaskFail(sysTask, ctx);
CommPlayerMan_ResumeFieldSystem();
}
}
static void SecretBases_StartEnterBasePromptTask(FieldSystem *fieldSystem, int x, int z, int dir, int netID, int baseOwnerNetID)
{
BaseTransitionContext *ctx = Heap_AllocAtEnd(HEAP_ID_FIELD1, sizeof(BaseTransitionContext));
MI_CpuClear8(ctx, sizeof(BaseTransitionContext));
ctx->warpID = WARP_ID_NONE;
ctx->x = x;
ctx->z = z;
ctx->netID = netID;
ctx->baseOwnerNetID = baseOwnerNetID;
ctx->mapID = MAP_HEADER_UNDERGROUND;
ctx->dir = dir;
ctx->fieldSystem = fieldSystem;
ctx->timer = 0;
ov23_0224DC08();
ctx->sysTask = SysTask_Start(SecretBases_EnterBasePromptTask, ctx, 100);
CommManUnderground_SetCurrentSysTask(ctx, ctx->sysTask, SecretBases_EndBaseTransitionPromptTaskFail);
CommPlayerMan_PauseFieldSystem();
}
int CommPacketSizeOf_BaseExitEvent(void)
{
return sizeof(BaseExitEvent);
}
void SecretBases_ProcessBaseExitEvent(int unused0, int unused1, void *data, void *unused3)
{
BaseExitEvent *event = data;
secretBasesEnv->occupiedBaseOwnerIDs[event->netID] = NETID_NONE;
if (CommSys_CurNetId() == event->netID) {
ov23_022535EC();
UndergroundTalk_ExitConversation();
ov23_0224321C();
UndergroundTraps_ForceEndCurrentTrapEffectClient(CommSys_CurNetId(), FALSE);
CommSys_SendMessage(43);
secretBasesEnv->currentPlayerInBase = FALSE;
sub_02059638(TRUE);
SecretBases_StartMoveToFromSecretBaseTask(secretBasesEnv->fieldSystem, event->x, event->z, event->dir, event->netID, event->forceExit);
secretBasesEnv->currentOccupiedBaseInfo = NULL;
} else {
UndergroundTraps_StopLinkSpin(event->netID);
UndergroundPlayer_MoveToFromSecretBaseClient(event->netID, event->x, event->z, event->dir);
}
}
void SecretBases_RequestClearTransitioningStatus(void)
{
CommSys_SendMessage(56);
}
void SecretBases_ClearTransitioningStatus(int netID, int unused1, void *unused2, void *unused3)
{
secretBasesEnv->baseTransitioningOwnerNetIDs[netID] = NETID_NONE;
secretBasesEnv->baseEnteringOwnerNetIDs[netID] = NETID_NONE;
}
BOOL SecretBases_IsPlayerMidBaseTransition(int netID)
{
if (secretBasesEnv) {
if (secretBasesEnv->baseTransitioningOwnerNetIDs[netID] != NETID_NONE) {
return TRUE;
}
}
return FALSE;
}
static void SecretBases_SetEntranceForPlayer(int x, int z, int dir, int netID)
{
SecretBaseInfo *baseInfo = &secretBasesEnv->baseInfo[netID];
if (baseInfo) {
SecretBase *secretBase = (SecretBase *)baseInfo->secretBase;
SecretBase_SetEntrance(secretBase, x, z, CommPlayer_GetOppositeDir(dir));
baseInfo->ownerNetID = netID;
}
}
void SecretBases_SendBaseInfo(void)
{
SecretBase *unused = (SecretBase *)secretBasesEnv->baseInfo[NETID_CURRENT_PLAYER_BASE].secretBase;
int unused2 = CommSys_CurNetId();
CommSys_WriteToQueue(53, &secretBasesEnv->baseInfo[NETID_CURRENT_PLAYER_BASE], sizeof(SecretBaseInfo));
}
void SecretBases_SendEnteredBase(int baseOwnerNetID)
{
CommSys_WriteToQueueServer(54, &secretBasesEnv->baseInfo[baseOwnerNetID], sizeof(SecretBaseInfo));
}
void SecretBases_ProcessBaseEnter(int unused0, int unused1, void *data, void *unused3)
{
SecretBaseInfo *baseInfo = data;
if (!secretBasesEnv) {
return;
}
if (CommSys_CurNetId() == baseInfo->visitorNetID && secretBasesEnv->moveStatus == MOVE_STATUS_ERROR_WHILE_ENTERING) {
secretBasesEnv->moveStatus = MOVE_STATUS_NONE;
CommPlayerMan_ResumeFieldSystem();
CommSys_SendMessage(56);
CommPlayer_SendPos(FALSE);
ov23_0224DC24();
return;
}
secretBasesEnv->moveStatus = MOVE_STATUS_ENTERING_2;
int baseOwnerNetID = baseInfo->ownerNetID;
GF_ASSERT(baseOwnerNetID < SECRET_BASE_COUNT);
baseInfo = &secretBasesEnv->baseInfo[baseOwnerNetID];
MI_CpuCopy8(data, baseInfo, sizeof(SecretBaseInfo));
secretBasesEnv->occupiedBaseOwnerIDs[baseInfo->visitorNetID] = baseInfo->ownerNetID;
if (baseInfo->ownerNetID != NETID_CURRENT_PLAYER_BASE) {
secretBasesEnv->visitedBaseOwnerNetIDs[baseInfo->visitorNetID] = baseInfo->ownerNetID;
}
BaseEntrance exit;
SecretBases_GetBaseExitCoordinatesOverrideNetID(baseInfo->ownerNetID, &exit);
if (CommSys_CurNetId() == baseInfo->visitorNetID) {
secretBasesEnv->currentPlayerInBase = TRUE;
SecretBases_StartMoveToFromSecretBaseTask(secretBasesEnv->fieldSystem, exit.x, exit.z - 1, DIR_NORTH, baseInfo->visitorNetID, FALSE);
secretBasesEnv->currentOccupiedBaseInfo = baseInfo;
SecretBase *secretBase = (SecretBase *)baseInfo->secretBase;
secretBasesEnv->currentBaseReturnXCoord = SecretBase_GetEntranceXCoord(secretBase);
secretBasesEnv->currentBaseReturnZCoord = SecretBase_GetEntranceZCoord(secretBase);
secretBasesEnv->currentBaseReturnDir = SecretBase_GetEntranceDir(secretBase);
ov23_02243360();
} else {
UndergroundPlayer_MoveToFromSecretBaseClient(baseInfo->visitorNetID, exit.x, exit.z, DIR_NORTH);
}
}
void SecretBases_ProcessBaseInfo(int netID, int unused1, void *data, void *unused3)
{
u8 *info = data;
if (!secretBasesEnv) {
return;
}
SecretBaseInfo *baseInfo = &secretBasesEnv->baseInfo[netID];
MI_CpuCopy8(info, baseInfo, sizeof(SecretBaseInfo));
baseInfo->ownerNetID = netID;
secretBasesEnv->dummy = 1;
SecretBase *secretBase = (SecretBase *)baseInfo->secretBase;
secretBasesEnv->baseEntrancesServer[netID].x = SecretBase_GetEntranceXCoord(secretBase);
secretBasesEnv->baseEntrancesServer[netID].z = SecretBase_GetEntranceZCoord(secretBase);
secretBasesEnv->baseEntrancesServer[netID].dir = SecretBase_GetEntranceDir(secretBase);
SecretBases_SendBaseEntrancesBuffer();
SecretBases_CalculateBaseCollision(secretBase, secretBasesEnv->baseCollisions[netID]);
SecretBases_RemoveNewLinkFromBase(netID);
}
int CommPacketSizeOf_SecretBaseInfo(void)
{
return sizeof(SecretBaseInfo);
}
BOOL SecretBases_AreBaseEntranceLocationsReceived(void)
{
return secretBasesEnv->baseEntranceLocationsReceived;
}
void SecretBases_ClearBaseEntranceLocationsReceived(void)
{
secretBasesEnv->baseEntranceLocationsReceived = FALSE;
}
static void SecretBases_SendBaseEntrancesBuffer(void)
{
int index = 0;
for (int netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
BaseEntrance *entrance = &secretBasesEnv->baseEntrancesServer[netID];
secretBasesEnv->baseEntrancesBuffer[index] = entrance->x & 0xFF;
index++;
secretBasesEnv->baseEntrancesBuffer[index] = ((entrance->x >> 8) & 0xF) + ((entrance->z >> 4) & 0xF0);
index++;
secretBasesEnv->baseEntrancesBuffer[index] = entrance->z & 0xFF;
index++;
secretBasesEnv->baseEntrancesBuffer[index] = entrance->dir;
index++;
}
CommSys_WriteToQueueServer(55, &secretBasesEnv->baseEntrancesBuffer, sizeof(secretBasesEnv->baseEntrancesBuffer));
}
void SecretBases_ProcessBaseEntrancesBuffer(int unused0, int unused1, void *data, void *unused3)
{
u8 *baseEntrancesBuffer = (u8 *)data;
BaseEntrance temp;
BaseEntrance *tempPtr;
if (!secretBasesEnv) {
return;
}
for (int netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
SecretBases_ClearBaseEntranceProp(netID);
}
int index = 0;
for (int netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
BaseEntrance *baseEntrance = &secretBasesEnv->baseEntrances[netID];
tempPtr = &temp;
tempPtr->x = baseEntrancesBuffer[index];
index++;
tempPtr->x += (int)baseEntrancesBuffer[index] << 8 & 0xF00;
tempPtr->z = (int)baseEntrancesBuffer[index] << 4 & 0xF00;
index++;
tempPtr->z += baseEntrancesBuffer[index];
index++;
tempPtr->dir = baseEntrancesBuffer[index];
index++;
if (tempPtr->x != ENTRANCE_LOCATION_NONE && tempPtr->z != ENTRANCE_LOCATION_NONE) {
MI_CpuCopy8(tempPtr, baseEntrance, sizeof(BaseEntrance));
SecretBases_SetBaseEntrancePropLocation(tempPtr->x, tempPtr->z, tempPtr->dir, netID);
}
}
secretBasesEnv->baseEntranceLocationsReceived = TRUE;
}
int CommPacketSizeOf_BaseEntrancesBuffer(void)
{
return sizeof(secretBasesEnv->baseEntrancesBuffer);
}
static void SecretBases_SetBaseEntrancePropLocation(int x, int z, int dir, int netID)
{
secretBasesEnv->baseEntrancePropDirs[netID] = dir;
secretBasesEnv->baseEntrancePropXCoords[netID] = x;
secretBasesEnv->baseEntrancePropZCoords[netID] = z;
}
static void SecretBases_DrawBaseEntrancesTask(SysTask *unused, void *unused1)
{
int entranceX, entranceZ; // need to be declared here to match
if (secretBasesEnv->baseEntranceGraphicsDisabled) {
return;
}
if (!secretBasesEnv->baseEntranceGraphicsEnabled) {
return;
}
if (secretBasesEnv->fieldSystem->playerAvatar == NULL) {
return;
}
int playerX = Player_GetXPos(secretBasesEnv->fieldSystem->playerAvatar);
int playerZ = Player_GetZPos(secretBasesEnv->fieldSystem->playerAvatar);
if (Underground_AreCoordinatesInSecretBase(playerX, playerZ)) {
return;
}
for (int netID = 0; netID < SECRET_BASE_COUNT; netID++) {
if (netID < MAX_CONNECTED_PLAYERS) {
if (CommInfo_TrainerInfo(netID) == NULL) {
SecretBases_RemoveBaseEntrance(netID);
SecretBases_ClearToolEffectFlag(netID);
}
}
if (secretBasesEnv->baseEntrancePropDirs[netID] != (u8)DIR_NONE) {
int dir = secretBasesEnv->baseEntrancePropDirs[netID];
entranceX = secretBasesEnv->baseEntrancePropXCoords[netID];
entranceZ = secretBasesEnv->baseEntrancePropZCoords[netID];
if (secretBasesEnv->baseEntrancePropIDs[netID] != PROP_NONE) {
MapPropManager_InitOne(secretBasesEnv->baseEntrancePropIDs[netID], secretBasesEnv->fieldSystem->mapPropManager);
}
VecFx32 position;
position.x = entranceX * (FX32_ONE * 16) + (FX32_ONE * 8);
position.y = 0;
position.z = entranceZ * (FX32_ONE * 16) + (FX32_ONE * 8);
secretBasesEnv->baseEntrancePropIDs[netID] = MapPropManager_LoadOne(secretBasesEnv->fieldSystem->mapPropManager, secretBasesEnv->fieldSystem->areaDataManager, MAP_PROP_MODEL_SECRET_BASE_ENTRANCE_NORTH + dir, &position, NULL, secretBasesEnv->fieldSystem->mapPropAnimMan);
}
}
}
static void SecretBases_ClearBaseEntranceProp(int netID)
{
if (secretBasesEnv->baseEntrancePropIDs[netID] != PROP_NONE) {
MapPropManager_InitOne(secretBasesEnv->baseEntrancePropIDs[netID], secretBasesEnv->fieldSystem->mapPropManager);
secretBasesEnv->baseEntrancePropIDs[netID] = PROP_NONE;
secretBasesEnv->baseEntrancePropDirs[netID] = DIR_NONE;
}
}
static void SecretBases_ClearAllBaseEntranceProps(void)
{
if (secretBasesEnv == NULL) {
return;
}
for (int netID = 0; netID < SECRET_BASE_COUNT; netID++) {
SecretBases_ClearBaseEntranceProp(netID);
}
}
static BOOL SecretBases_StopFieldMap(FieldTask *task)
{
FieldSystem *fieldSystem = FieldTask_GetFieldSystem(task);
BaseTransitionContext *ctx = FieldTask_GetEnv(task);
switch (ctx->subState) {
case 0:
FieldSystem_FlagNotRunningFieldMap(fieldSystem);
ctx->subState++;
break;
case 1:
if (!FieldSystem_HasParentProcess(fieldSystem)) {
ctx->subState = 0;
return TRUE;
}
break;
}
return FALSE;
}
static BOOL SecretBases_ResumeFieldMap(FieldTask *task)
{
FieldSystem *fieldSystem = FieldTask_GetFieldSystem(task);
BaseTransitionContext *ctx = FieldTask_GetEnv(task);
switch (ctx->subState) {
case 0:
FieldSystem_StartFieldMapInner(fieldSystem);
ctx->subState++;
break;
case 1:
if (FieldSystem_IsRunningFieldMap(fieldSystem)) {
ctx->subState = 0;
return TRUE;
}
break;
}
return FALSE;
}
static BOOL SecretBases_MoveToFromSecretBaseTask(FieldTask *task)
{
FieldSystem *fieldSystem = FieldTask_GetFieldSystem(task);
BaseTransitionContext *ctx = FieldTask_GetEnv(task);
switch (ctx->state) {
case BASE_MOVE_STATE_INIT:
SecretBases_SetEntranceGraphicsEnabled(FALSE);
ov23_0224DC08();
ctx->initialConnectedCount = CommSys_ConnectedCount();
CommSys_DisableSendMovementData();
UndergroundSpheres_DisableBuriedSphereSparkles();
if (ov23_02249AB8()) {
ctx->state = BASE_MOVE_STATE_FADE_OUT;
}
break;
case BASE_MOVE_STATE_FADE_OUT:
FinishScreenFade();
StartScreenFade(FADE_SUB_THEN_MAIN, FADE_TYPE_CIRCLE_OUT, FADE_TYPE_TOP_HALF_CIRCLE_OUT, COLOR_BLACK, 6, 1, HEAP_ID_FIELD1);
ov23_0224942C(fieldSystem->unk_6C);
Sound_PlayEffect(SEQ_SE_DP_KAIDAN2);
ctx->state++;
break;
case BASE_MOVE_STATE_WAIT_FOR_FADE_OUT:
if (IsScreenFadeDone()) {
if (fieldSystem->unk_6C == NULL) {
ctx->state++;
}
}
break;
case BASE_MOVE_STATE_STOP_FIELD_MAP:
if (SecretBases_StopFieldMap(task)) {
ctx->state++;
}
break;
case BASE_MOVE_STATE_UPDATE_LOCATION:
Location nextLocation;
nextLocation.mapId = ctx->mapID;
nextLocation.warpId = ctx->warpID;
nextLocation.x = ctx->x;
nextLocation.z = ctx->z;
nextLocation.faceDirection = ctx->dir;
sub_020544F0(task, &nextLocation);
ctx->state++;
break;
case BASE_MOVE_STATE_RESUME_FIELD_MAP:
if (SecretBases_ResumeFieldMap(task)) {
ctx->state++;
}
break;
case BASE_MOVE_STATE_FADE_IN:
fieldSystem->unk_6C = ov23_02249404(fieldSystem);
FinishScreenFade();
StartScreenFade(FADE_MAIN_THEN_SUB, FADE_TYPE_CIRCLE_IN, FADE_TYPE_TOP_HALF_CIRCLE_IN, COLOR_BLACK, 6, 1, HEAP_ID_FIELD1);
ctx->state++;
break;
case BASE_MOVE_STATE_WAIT_FOR_FADE_IN:
if (!IsScreenFadeDone()) {
break;
}
if (CommServerClient_IsInClosedSecretBase() && !Underground_AreCoordinatesInSecretBase(ctx->x, ctx->z)) {
ctx->showBlockedEntranceMessage = FALSE;
} else {
ctx->showBlockedEntranceMessage = TRUE;
}
CommSys_EnableSendMovementData();
CommPlayerMan_PauseFieldSystem();
Graphics_LoadPalette(NARC_INDEX_DATA__UG_TRAP, text_window_NCLR, PAL_LOAD_MAIN_BG, PLTT_OFFSET(10), PALETTE_SIZE_BYTES * 4, HEAP_ID_FIELD1);
LoadStandardWindowGraphics(fieldSystem->bgConfig, BG_LAYER_MAIN_3, BASE_TILE_STANDARD_WINDOW_FRAME, 11, 2, HEAP_ID_FIELD1);
if (ctx->forceExit) {
CommPlayerMan_ClearPauseContextBits();
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_EscapedToAvoidDanger, FALSE, NULL);
ctx->state = BASE_MOVE_STATE_END_AFTER_TEXT_OR_NEW_LINK;
} else if (!secretBasesEnv->currentPlayerInBase) {
ctx->state = BASE_MOVE_STATE_END;
} else {
ctx->timer = 0;
ctx->state = BASE_MOVE_STATE_FRAME_DELAY;
}
break;
case BASE_MOVE_STATE_FRAME_DELAY:
ctx->timer++;
ctx->timer = 0;
ctx->state = BASE_MOVE_STATE_WAIT;
break;
case BASE_MOVE_STATE_WAIT:
ctx->timer++;
if (ctx->timer > 10) {
if (!CommServerClient_IsInClosedSecretBase() || !ctx->showBlockedEntranceMessage) {
ctx->state = BASE_MOVE_STATE_END;
} else {
ctx->state = BASE_MOVE_STATE_BLOCK_ENTRANCE;
}
}
break;
case BASE_MOVE_STATE_BLOCK_ENTRANCE:
CommPlayerMan_ForceDir();
PlayerAvatar_SetAnimationCode(fieldSystem->playerAvatar, MovementAction_TurnActionTowardsDir(DIR_SOUTH, MOVEMENT_ACTION_WALK_ON_SPOT_FAST_NORTH), 1);
CommPlayer_SetDir(DIR_SOUTH);
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_BlockedEntranceToDecorate, FALSE, NULL);
Sound_PlayEffect(SEQ_SE_DP_DOOR);
ctx->state = BASE_MOVE_STATE_FACE_NORTH_AND_END_AFTER_TEXT;
break;
case BASE_MOVE_STATE_FACE_NORTH_AND_END_AFTER_TEXT:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
if (JOY_NEW(PAD_BUTTON_A | PAD_BUTTON_B)) {
ctx->state = BASE_MOVE_STATE_END;
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetCommonTextPrinter());
CommPlayer_SetDir(DIR_NORTH);
}
}
break;
case BASE_MOVE_STATE_END:
if (CommServerClient_IsInClosedSecretBase() && !Underground_AreCoordinatesInSecretBase(ctx->x, ctx->z)) {
ov23_02249AA4();
} else {
ov23_02249B60();
}
sub_02059638(FALSE);
CommPlayerMan_ResumeFieldSystem();
Heap_Free(ctx);
if (CommServerClient_IsInClosedSecretBase() && Underground_AreCoordinatesInSecretBase(ctx->x, ctx->z)) {
ov23_02242FA8();
} else {
ov23_02242FBC();
}
if (secretBasesEnv->moveStatus == MOVE_STATUS_ERROR_WHILE_ENTERING_2 && secretBasesEnv->currentPlayerInBase) {
secretBasesEnv->moveStatus = MOVE_STATUS_EXITING;
} else {
secretBasesEnv->moveStatus = MOVE_STATUS_NONE;
}
ov23_0224DC24();
SecretBases_SetEntranceGraphicsEnabled(TRUE);
return TRUE;
case BASE_MOVE_STATE_END_AFTER_TEXT_OR_NEW_LINK:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
if (JOY_NEW(PAD_BUTTON_A | PAD_BUTTON_B)) {
ctx->state = BASE_MOVE_STATE_END;
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetCommonTextPrinter());
return FALSE;
}
}
if (CommSys_ConnectedCount() > 1 && ctx->initialConnectedCount == 0) {
ctx->state = BASE_MOVE_STATE_END;
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetCommonTextPrinter());
}
break;
}
return FALSE;
}
static void SecretBases_StartMoveToFromSecretBaseTask(FieldSystem *fieldSystem, int x, int z, int dir, int netID, BOOL forceExit)
{
BaseTransitionContext *ctx = BaseTransitionContext_New(fieldSystem, x, z, dir, netID, netID);
if (ctx) {
ctx->forceExit = forceExit;
FieldSystem_CreateTask(fieldSystem, SecretBases_MoveToFromSecretBaseTask, ctx);
}
}
static void SecretBases_DiggerDrillTask(SysTask *sysTask, void *data)
{
DiggerDrillContext *ctx = data;
FieldSystem *fieldSystem = ctx->fieldSystem;
BOOL canceled = FALSE;
switch (ctx->state) {
case DRILL_STATE_INIT:
SecretBase *secretBase = SaveData_GetSecretBase(fieldSystem->saveData);
ctx->hasExistingBase = SecretBase_IsActive(secretBase);
CommPlayerMan_PauseFieldSystem();
UndergroundTextPrinter_SetUndergroundTrapName(CommManUnderground_GetCommonTextPrinter(), TRAP_DIGGER_DRILL);
Sound_PlayEffect(SEQ_SE_DP_DORIRU);
ov5_021F58FC(Player_MapObject(fieldSystem->playerAvatar), 0, 0, 0);
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_ItemWasUsed, FALSE, NULL);
ctx->state = DRILL_STATE_WAIT;
ctx->timer = 0;
break;
case DRILL_STATE_WAIT:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
ctx->timer++;
if (ctx->timer > 30) {
ctx->state = DRILL_STATE_CREATE_ENTRANCE;
}
}
break;
case DRILL_STATE_CREATE_ENTRANCE: {
int x = CommPlayer_GetXInFrontOfPlayer(CommSys_CurNetId());
int z = CommPlayer_GetZInFrontOfPlayer(CommSys_CurNetId());
int dir = CommPlayer_GetOppositeDir(PlayerAvatar_GetDir(fieldSystem->playerAvatar));
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_DiscoveredCavern, FALSE, NULL);
SecretBases_SetBaseEntrancePropLocation(x, z, dir, NETID_CURRENT_PLAYER_BASE);
ov5_021F5634(fieldSystem, x, 0, z);
ctx->state = DRILL_STATE_PRINT_PROMPT;
} break;
case DRILL_STATE_PRINT_PROMPT:
if (UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter()) == FALSE) {
int bankEntry;
if (SecretBases_CountPlayersInBase(CommSys_CurNetId(), FALSE) != 0) {
bankEntry = UndergroundCommon_Text_CantMoveBaseSomeoneInside;
ctx->state = DRILL_STATE_CANCEL_AFTER_BUTTON_PRESS;
} else if (ctx->hasExistingBase) {
bankEntry = UndergroundCommon_Text_MoveBasePrompt;
ctx->state = DRILL_STATE_OPEN_CONFIRM_MENU;
} else {
bankEntry = UndergroundCommon_Text_MakeBasePrompt;
ctx->state = DRILL_STATE_OPEN_CONFIRM_MENU;
}
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), bankEntry, FALSE, NULL);
}
break;
case DRILL_STATE_CANCEL_AFTER_BUTTON_PRESS:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
if (JOY_NEW(PAD_BUTTON_A)) {
canceled = TRUE;
}
}
break;
case DRILL_STATE_OPEN_CONFIRM_MENU:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCommonTextPrinter())) {
ctx->menu = Menu_MakeYesNoChoice(fieldSystem->bgConfig, &Unk_ov23_02256864, BASE_TILE_STANDARD_WINDOW_FRAME, 11, HEAP_ID_FIELD1);
ctx->state = 6;
}
break;
case DRILL_STATE_CONFIRM:
u32 input = Menu_ProcessInputAndHandleExit(ctx->menu, HEAP_ID_FIELD1);
if (input == 0) {
ctx->state = DRILL_STATE_REMOVE_DRILL;
ctx->menu = NULL;
} else if (input != MENU_NOTHING_CHOSEN) {
canceled = TRUE;
ctx->menu = NULL;
}
break;
case DRILL_STATE_REMOVE_DRILL:
UndergroundMenu_RemoveSelectedTrap(TRAP_DIGGER_DRILL);
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetCommonTextPrinter());
ov23_02249A74();
ctx->state = DRILL_STATE_CREATE_BASE_AND_END;
break;
case DRILL_STATE_CREATE_BASE_AND_END:
if (CommServerClient_IsInClosedSecretBase() && CommSys_CurNetId() == 0) {
u8 type = BASE_CREATE_REQ_NEW_BASE;
if (ctx->hasExistingBase) {
type = BASE_CREATE_REQ_MOVE_BASE;
}
SecretBases_CreateBase();
CommSys_SendDataFixedSize(86, &type);
SysTask_Done(sysTask);
Heap_Free(ctx);
CommManUnderground_ClearCurrentSysTaskInfo();
return;
}
break;
}
if (canceled) {
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_ClosedHole, TRUE, SecretBases_ResumeFieldSystem);
SecretBases_ClearBaseEntranceProp(NETID_CURRENT_PLAYER_BASE);
int x = CommPlayer_GetXInFrontOfPlayer(CommSys_CurNetId());
int z = CommPlayer_GetZInFrontOfPlayer(CommSys_CurNetId());
ov5_021F5634(fieldSystem, x, 0, z);
SysTask_Done(sysTask);
Heap_Free(ctx);
CommManUnderground_ClearCurrentSysTaskInfo();
ov23_0224DC24();
}
}
void SecretBases_UseDiggerDrill(void)
{
u8 type = BASE_CREATE_REQ_USE_DIGGER_DRILL;
CommSys_SendDataFixedSize(86, &type);
}
int CommPacketSizeOf_SecretBaseCreateEvent(void)
{
return sizeof(SecretBaseCreateEvent);
}
void SecretBases_ProcessBaseCreateRequest(int netID, int unused1, void *data, void *unused3)
{
u8 *type = data;
int x = CommPlayer_GetXInFrontOfPlayerServer(netID);
int z = CommPlayer_GetZInFrontOfPlayerServer(netID);
int cornerCheckX1, cornerCheckZ1, cornerCheckX2, cornerCheckZ2;
int dir = CommPlayer_DirServer(netID);
// variables reused here for an overly complicated dir check despite the actual dir value having just been retrieved
cornerCheckX2 = x - CommPlayer_GetXServerIfActive(netID);
cornerCheckZ2 = z - CommPlayer_GetZServerIfActive(netID);
if (cornerCheckZ2 != 0) { // facing up or down
cornerCheckX1 = x + 1;
cornerCheckX2 = x - 1;
cornerCheckZ2 = cornerCheckZ1 = z;
} else { // facing left or right
cornerCheckZ1 = z + 1;
cornerCheckZ2 = z - 1;
cornerCheckX2 = cornerCheckX1 = x;
}
SecretBaseCreateEvent event;
event.netID = netID;
if (*type == BASE_CREATE_REQ_USE_DIGGER_DRILL) {
event.type = BASE_CREATE_EVENT_CANT_DRILL;
} else {
event.type = BASE_CREATE_EVENT_CANT_ENTER;
}
int entranceOwnerNetID = SecretBases_GetEntranceOwnerNetIDFromCoords(x, z);
if (*type != BASE_CREATE_REQ_USE_DIGGER_DRILL || entranceOwnerNetID == NETID_NONE) {
if (Underground_AreCoordinatesInSecretBase(x, z)) {
event.type = BASE_CREATE_EVENT_CANT_DRILL_IN_BASE;
} else if (TerrainCollisionManager_CheckCollision(secretBasesEnv->fieldSystem, x, z) && TerrainCollisionManager_CheckCollision(secretBasesEnv->fieldSystem, cornerCheckX1, cornerCheckZ1) && TerrainCollisionManager_CheckCollision(secretBasesEnv->fieldSystem, cornerCheckX2, cornerCheckZ2)) {
if (*type == BASE_CREATE_REQ_USE_DIGGER_DRILL) {
event.type = BASE_CREATE_EVENT_USE_DRILL;
} else {
SecretBases_SetEntranceForPlayer(x, z, dir, NETID_CURRENT_PLAYER_BASE);
if (SecretBases_TryEnterBase(NETID_CURRENT_PLAYER_BASE, netID)) {
switch (*type) {
case BASE_CREATE_REQ_CLOSE_BASE:
event.type = BASE_CREATE_EVENT_CLOSE_BASE;
break;
case BASE_CREATE_REQ_MOVE_BASE:
event.type = BASE_CREATE_EVENT_MOVE_BASE;
break;
case BASE_CREATE_REQ_NEW_BASE:
event.type = BASE_CREATE_EVENT_NEW_BASE;
break;
}
}
}
}
}
CommSys_SendDataFixedSizeServer(87, &event);
}
static void SecretBases_EndDiggerDrillTask(SysTask *sysTask, void *data)
{
DiggerDrillContext *ctx = data;
SecretBases_ClearBaseEntranceProp(NETID_CURRENT_PLAYER_BASE);
if (ctx->menu) {
Menu_DestroyForExit(ctx->menu, HEAP_ID_FIELD1);
}
SysTask_Done(sysTask);
Heap_Free(ctx);
CommManUnderground_ClearCurrentSysTaskInfo();
CommPlayerMan_ResumeFieldSystem();
ov23_0224DC24();
}
static void SecretBases_StartDiggerDrillTask(void)
{
ov23_0224DC08();
DiggerDrillContext *ctx = Heap_AllocAtEnd(HEAP_ID_FIELD1, sizeof(DiggerDrillContext));
MI_CpuClear8(ctx, sizeof(DiggerDrillContext));
ctx->state = DRILL_STATE_INIT;
ctx->unused = CommSys_CurNetId();
ctx->fieldSystem = secretBasesEnv->fieldSystem;
ctx->sysTask = SysTask_Start(SecretBases_DiggerDrillTask, ctx, 100);
CommManUnderground_SetCurrentSysTask(ctx, ctx->sysTask, SecretBases_EndDiggerDrillTask);
}
void SecretBases_ProcessBaseCreateEvent(int unused0, int unused1, void *data, void *unused3)
{
SecretBaseCreateEvent *event = data;
UndergroundRecord *undergroundRecord = SaveData_GetUndergroundRecord(FieldSystem_GetSaveData(secretBasesEnv->fieldSystem));
if (event->netID != CommSys_CurNetId()) {
return;
}
if (event->type == BASE_CREATE_EVENT_CANT_DRILL) {
CommPlayerMan_PauseFieldSystem();
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_CantBeUsedHere, TRUE, SecretBases_ResumeFieldSystem);
ov23_0224DC24();
} else if (event->type == BASE_CREATE_EVENT_USE_DRILL) {
SecretBases_StartDiggerDrillTask();
} else if (event->type == BASE_CREATE_EVENT_CANT_DRILL_IN_BASE) {
CommPlayerMan_PauseFieldSystem();
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_CantDrillInBase, TRUE, SecretBases_ResumeFieldSystem);
ov23_0224DC24();
} else if (event->type == BASE_CREATE_EVENT_CANT_ENTER) {
CommPlayerMan_PauseFieldSystem();
UndergroundTextPrinter_PrintText(CommManUnderground_GetCommonTextPrinter(), UndergroundCommon_Text_WallCrumbledCantEnter, TRUE, SecretBases_ResumeFieldSystem);
ov23_02249AA4();
ov23_0224DC24();
} else if (event->type == BASE_CREATE_EVENT_CLOSE_BASE || event->type == BASE_CREATE_EVENT_MOVE_BASE || event->type == BASE_CREATE_EVENT_NEW_BASE) {
int x = CommPlayer_GetXInFrontOfPlayer(event->netID);
int z = CommPlayer_GetZInFrontOfPlayer(event->netID);
int dir = CommPlayer_Dir(event->netID);
SecretBases_SetEntranceForPlayer(x, z, dir, event->netID);
SecretBases_SetEntranceForPlayer(x, z, dir, NETID_CURRENT_PLAYER_BASE);
if (event->type == BASE_CREATE_EVENT_MOVE_BASE) {
UndergroundRecord_IncrementTimesBaseMoved(undergroundRecord);
}
if (event->type == BASE_CREATE_EVENT_MOVE_BASE || event->type == BASE_CREATE_EVENT_NEW_BASE) {
void *journalEntryLocationEvent = JournalEntry_CreateEventBuiltSecretBase(HEAP_ID_FIELD2);
JournalEntry_SaveData(secretBasesEnv->fieldSystem->journalEntry, journalEntryLocationEvent, JOURNAL_LOCATION);
GameRecords_IncrementTrainerScore(SaveData_GetGameRecords(secretBasesEnv->fieldSystem->saveData), TRAINER_SCORE_EVENT_UNDERGROUND_NEW_SECRET_BASE);
}
}
}
BOOL SecretBases_GetQueuedMessage(String *dest)
{
if (!secretBasesEnv) {
return FALSE;
}
for (int netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
if (secretBasesEnv->visitedBaseOwnerNetIDs[netID] != NETID_NONE) {
int baseOwnerNetID = secretBasesEnv->visitedBaseOwnerNetIDs[netID];
secretBasesEnv->visitedBaseOwnerNetIDs[netID] = NETID_NONE;
if (netID != baseOwnerNetID) {
TrainerInfo *trainerInfo = CommInfo_TrainerInfo(netID);
TrainerInfo *baseOwnerInfo = CommInfo_TrainerInfo(baseOwnerNetID);
if (CommManUnderground_FormatCommonStringWith2TrainerNames(trainerInfo, baseOwnerInfo, UndergroundCommon_Text_PlayerEnteredPlayersSecretBase, dest)) {
return TRUE;
}
}
}
if (secretBasesEnv->obtainedFlagOwnerNetIDs[netID] != NETID_NONE) {
TrainerInfo *trainerInfo = CommInfo_TrainerInfo(netID);
TrainerInfo *flagOwnerInfo = CommInfo_TrainerInfo(secretBasesEnv->obtainedFlagOwnerNetIDs[netID]);
secretBasesEnv->obtainedFlagOwnerNetIDs[netID] = NETID_NONE;
if (CommManUnderground_FormatCommonStringWith2TrainerNames(trainerInfo, flagOwnerInfo, UndergroundCommon_Text_PlayerObtainedPlayersFlag, dest)) {
return TRUE;
}
}
if (secretBasesEnv->tookBackFlagMessageQueued[netID] != 0xff) {
TrainerInfo *trainerInfo = CommInfo_TrainerInfo(netID);
secretBasesEnv->tookBackFlagMessageQueued[netID] = 0xff;
if (CommManUnderground_FormatCommonStringWithTrainerName(trainerInfo, 0, UndergroundCommon_Text_PlayerTookBackFlag, dest)) {
return TRUE;
}
break;
}
if (secretBasesEnv->flagStealVictimNetIDs[netID] != NETID_NONE) {
TrainerInfo *trainerInfo = CommInfo_TrainerInfo(netID);
TrainerInfo *victimInfo = CommInfo_TrainerInfo(secretBasesEnv->flagStealVictimNetIDs[netID]);
secretBasesEnv->flagStealVictimNetIDs[netID] = NETID_NONE;
if (CommManUnderground_FormatCommonStringWith2TrainerNames(trainerInfo, victimInfo, UndergroundCommon_Text_PlayerTookPlayersFlag, dest)) {
return TRUE;
}
}
}
return FALSE;
}
SecretBase *SecretBases_GetCurrentOccupiedBase(SaveData *saveData)
{
if (secretBasesEnv) {
if (secretBasesEnv->currentOccupiedBaseInfo) {
return (SecretBase *)secretBasesEnv->currentOccupiedBaseInfo->secretBase;
}
}
return NULL;
}
// refers to a 8x2 grid of secret bases, not the grid of walkable tiles
int SecretBases_GetBaseXCoordinate(void)
{
if (secretBasesEnv) {
if (secretBasesEnv->currentOccupiedBaseInfo) {
return sSecretBaseXCoordinates[secretBasesEnv->currentOccupiedBaseInfo->ownerNetID];
}
}
return 0;
}
// refers to a 8x2 grid of secret bases, not the grid of walkable tiles
int SecretBases_GetBaseZCoordinate(void)
{
if (secretBasesEnv) {
if (secretBasesEnv->currentOccupiedBaseInfo) {
return sSecretBaseZCoordinates[secretBasesEnv->currentOccupiedBaseInfo->ownerNetID];
}
}
return 0;
}
BOOL SecretBases_AreCoordinatesWalkable(int x, int z)
{
if (!secretBasesEnv) {
return TRUE;
}
if (z >= SECRET_BASE_DEPTH * 2) {
return TRUE;
}
int baseX = x / SECRET_BASE_WIDTH;
int baseZ = z / SECRET_BASE_DEPTH;
for (int netID = 0; netID < SECRET_BASE_COUNT; netID++) {
if (baseX == sSecretBaseXCoordinates[netID] && baseZ == sSecretBaseZCoordinates[netID]) {
int xWithinBase = x % SECRET_BASE_WIDTH;
int zWithinBase = z % SECRET_BASE_DEPTH;
if (secretBasesEnv->baseCollisions[netID][zWithinBase] & (0x1 << xWithinBase)) {
return TRUE;
} else {
return FALSE;
}
}
}
return TRUE;
}
static void SecretBases_CreateBase(void)
{
SecretBase *secretBase = SaveData_GetSecretBase(FieldSystem_GetSaveData(secretBasesEnv->fieldSystem));
Underground *underground = SaveData_GetUnderground(FieldSystem_GetSaveData(secretBasesEnv->fieldSystem));
int x = CommPlayer_GetXInFrontOfPlayerServer(0);
int z = CommPlayer_GetZInFrontOfPlayerServer(0);
int dir = CommPlayer_DirServer(0);
const int minX = 10, xAdjustRightOfPC = 18, minZ = 12, xRange = 5, zRange = 6;
int occupiedCoords[MAX_BASE_BOULDERS + 1][2];
occupiedCoords[0][0] = PC_COORDINATE_X + 1;
occupiedCoords[0][1] = PC_COORDINATE_Z;
SystemFlag_SetCreatedSecretBase(SaveData_GetVarsFlags(secretBasesEnv->fieldSystem->saveData));
SecretBase_Clear(secretBase);
Underground_InitPlacedGoodSlots(underground);
MATHRandContext32 rand;
CommSys_Seed(&rand);
for (int i = 0; i < MAX_BASE_BOULDERS; i++) {
int boulderX = MATH_Rand32(&rand, xRange);
// ensure no rocks spawn in a line from the entrance to the pc
if (boulderX < 2) {
boulderX = boulderX * 2 + minX;
} else {
boulderX = (boulderX - 3) * 2 + xAdjustRightOfPC;
}
int boulderZ = MATH_Rand32(&rand, zRange) * 2 + minZ;
BOOL canPlace = TRUE;
for (int j = 0; j <= i; j++) {
if (occupiedCoords[j][0] == boulderX && occupiedCoords[j][1] == boulderZ) {
canPlace = FALSE;
break;
}
}
if (!canPlace) {
i--;
continue;
}
SecretBase_SetGoodCoordsAtIndex(secretBase, MAX_PLACED_GOODS + 1 + i, boulderX, boulderZ);
occupiedCoords[i + 1][0] = boulderX;
occupiedCoords[i + 1][1] = boulderZ;
}
MI_CpuFill8(secretBasesEnv->baseCollisions, 0xFF, SECRET_BASE_COUNT * SECRET_BASE_DEPTH * sizeof(u32));
SecretBase_SetEntrance(secretBase, x, z, CommPlayer_GetOppositeDir(dir));
MI_CpuCopy8(secretBase, secretBasesEnv->baseInfo[NETID_CURRENT_PLAYER_BASE].secretBase, sizeof(SecretBase));
SecretBases_CalculateBaseCollision(secretBase, secretBasesEnv->baseCollisions[NETID_CURRENT_PLAYER_BASE]);
}
int SecretBases_PrintDecorateBaseMessage(int bankEntry)
{
return UndergroundTextPrinter_PrintText(CommManUnderground_GetDecorateBaseTextPrinter(), bankEntry, FALSE, NULL);
}
void SecretBases_EraseDecorateBaseMessageBox(void)
{
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetDecorateBaseTextPrinter());
}
void SecretBases_SetGoodNameForPrinter(int goodID)
{
UndergroundTextPrinter_SetGoodNameWithIndex(CommManUnderground_GetDecorateBaseTextPrinter(), 0, goodID);
}
void SecretBases_SetTwoDigitNumberWithIndexForPrinter(int num, int index)
{
UndergroundTextPrinter_SetTwoDigitNumberWithIndex(CommManUnderground_GetDecorateBaseTextPrinter(), index, num);
}
static int SecretBases_GetGoodWithCollisionAtCoordinates(SecretBase *secretBase, int xWithinBase, int zWithinBase)
{
const u8 *collision;
for (int i = 0; i < MAX_PLACED_GOODS + MAX_BASE_BOULDERS + 1; i++) {
int goodID = SecretBase_GetGoodIDAtIndex(secretBase, i);
if (goodID == UG_GOOD_NONE) {
continue;
}
if (i == 0) {
continue;
} else if (i < MAX_PLACED_GOODS + 1) {
collision = Good_GetCollision(goodID);
} else {
continue;
}
int xOffset = SecretBase_GetGoodXCoordAtIndex(secretBase, i);
int zOffset = SecretBase_GetGoodZCoordAtIndex(secretBase, i);
xOffset = xWithinBase - xOffset;
zOffset = zWithinBase - zOffset;
if (xOffset < 0 || xOffset > 2) {
continue;
}
if (zOffset < 0 || zOffset > 2) {
continue;
}
if (collision[zOffset * 3 + xOffset]) {
return goodID;
}
}
return UG_GOOD_NONE;
}
BOOL SecretBases_CheckForInteractableGood(int netID, Coordinates *coordinates)
{
int x = coordinates->x;
int z = coordinates->z;
if (!SecretBases_AreCoordinatesWalkable(x, z)) {
GoodInteractionEvent event;
event.netID = netID;
int baseOwnerNetID = SecretBases_GetOwnerNetIDFromCoordinates(x, z);
SecretBase *secretBase = (SecretBase *)secretBasesEnv->baseInfo[baseOwnerNetID].secretBase;
int goodID = SecretBases_GetGoodWithCollisionAtCoordinates(secretBase, x % SECRET_BASE_WIDTH, z % SECRET_BASE_DEPTH);
event.bankEntry = Good_GetInteractMessageID(goodID);
if (event.bankEntry != 0) {
CommPlayerMan_SetMovementEnabled(netID, FALSE);
CommSys_SendDataFixedSizeServer(60, &event);
return TRUE;
}
}
return FALSE;
}
void SecretBases_ProcessGoodInteractionEvent(int unused0, int unused1, void *data, void *unused3)
{
GoodInteractionEvent *event = data;
SecretBase *secretBase = (SecretBase *)secretBasesEnv->currentOccupiedBaseInfo->secretBase;
UndergroundRecord *undergroundRecord = SecretBase_GetUndergroundRecord(secretBase);
if (event->netID == CommSys_CurNetId()) {
ov23_02253A00(undergroundRecord, event->bankEntry);
}
}
int CommPacketSizeOf_GoodInteractionEvent(void)
{
return sizeof(GoodInteractionEvent);
}
void SecretBases_QueueObtainedFlagMessage(int netID, int flagOwnerNetID)
{
if (secretBasesEnv) {
secretBasesEnv->obtainedFlagOwnerNetIDs[netID] = flagOwnerNetID;
}
}
void SecretBases_QueueTookFlagMessage(int netID, int victimNetID)
{
if (secretBasesEnv) {
secretBasesEnv->flagStealVictimNetIDs[netID] = victimNetID;
}
}
void SecretBases_QueueTookBackFlagMessage(int netID)
{
if (secretBasesEnv) {
secretBasesEnv->tookBackFlagMessageQueued[netID] = TRUE;
}
}
static void SecretBases_UpdatePCMapProp(FlagRankUpContext *ctx)
{
VecFx32 position; // needs to be declared here to match
MapProp *mapProp = MapPropManager_GetLoadedProp(secretBasesEnv->fieldSystem->mapPropManager, 0);
position = MapProp_GetPosition(mapProp);
MapPropManager_InitOne(0, secretBasesEnv->fieldSystem->mapPropManager);
MapPropManager_LoadOne(secretBasesEnv->fieldSystem->mapPropManager, secretBasesEnv->fieldSystem->areaDataManager, MAP_PROP_MODEL_SECRET_BASE_PC_BRONZE_FLAG + ctx->prevFlagRank, &position, NULL, secretBasesEnv->fieldSystem->mapPropAnimMan);
}
static void SecretBases_EndFlagRankUpTask(SysTask *sysTask, void *ctx)
{
Heap_Free(ctx);
SysTask_Done(sysTask);
}
static void SecretBases_FlagRankUpTask(SysTask *sysTask, void *data)
{
FlagRankUpContext *ctx = data;
switch (ctx->state) {
case FLAG_RANK_UP_STATE_PRINT_FLAG_REGISTERED:
CommPlayerMan_PauseFieldSystem();
UndergroundTextPrinter_PrintText(CommManUnderground_GetCaptureFlagTextPrinter(), UndergroundCaptureFlag_Text_ObtainedFlagWasRegistered, FALSE, NULL);
Sound_PlayEffect(SEQ_SE_DP_PIRORIRO2);
ctx->state = FLAG_RANK_UP_STATE_PRINT_RANK_UP;
break;
case FLAG_RANK_UP_STATE_PRINT_RANK_UP:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCaptureFlagTextPrinter())) {
if (JOY_NEW(PAD_BUTTON_A | PAD_BUTTON_B)) {
UndergroundTextPrinter_PrintText(CommManUnderground_GetCaptureFlagTextPrinter(), UndergroundCaptureFlag_Text_FlagBecameBronze + ctx->prevFlagRank, FALSE, NULL);
ctx->state = FLAG_RANK_UP_STATE_UPDATE_PC_PROP;
}
}
break;
case FLAG_RANK_UP_STATE_UPDATE_PC_PROP:
if (!UndergroundTextPrinter_IsPrinterActive(CommManUnderground_GetCaptureFlagTextPrinter())) {
if (JOY_NEW(PAD_BUTTON_A | PAD_BUTTON_B)) {
SecretBases_UpdatePCMapProp(ctx);
ctx->state = FLAG_RANK_UP_STATE_END;
UndergroundTextPrinter_EraseMessageBoxWindow(CommManUnderground_GetCaptureFlagTextPrinter());
CommPlayerMan_ResumeFieldSystem();
}
}
break;
case FLAG_RANK_UP_STATE_3_UNUSED:
StartScreenFade(FADE_SUB_THEN_MAIN, FADE_TYPE_BRIGHTNESS_OUT, FADE_TYPE_BRIGHTNESS_OUT, COLOR_BLACK, 6, 1, HEAP_ID_FIELD1);
break;
case FLAG_RANK_UP_STATE_END:
Heap_Free(ctx);
SysTask_Done(sysTask);
CommManUnderground_ClearCurrentSysTaskInfo();
break;
}
}
void SecretBases_ProcessFlagRankUp(int netID, int unused1, void *data, void *unused3)
{
u8 *prevFlagRank = data;
FlagRankUpEvent event = {
.netID = netID,
.prevFlagRank = *prevFlagRank,
};
CommSys_SendDataFixedSizeServer(97, &event);
}
void SecretBases_ProcessFlagRankUpEvent(int unused0, int unused1, void *data, void *unused3)
{
FlagRankUpEvent *event = data;
if (event->netID == CommSys_CurNetId()) {
FlagRankUpContext *ctx = Heap_Alloc(HEAP_ID_FIELD2, sizeof(FlagRankUpContext));
MI_CpuClear8(ctx, sizeof(ctx));
ctx->state = FLAG_RANK_UP_STATE_PRINT_FLAG_REGISTERED;
ctx->prevFlagRank = event->prevFlagRank;
SysTask *sysTask = SysTask_Start(SecretBases_FlagRankUpTask, ctx, 100);
CommManUnderground_SetCurrentSysTask(ctx, sysTask, SecretBases_EndFlagRankUpTask);
}
}
int CommPacketSizeOf_FlagRankUpEvent(void)
{
return sizeof(FlagRankUpEvent);
}
static int SecretBases_GetPlacedGoodAtCoordinates(SecretBase *secretBase, int xWithinBase, int zWithinBase)
{
for (int i = 0; i < MAX_PLACED_GOODS + MAX_BASE_BOULDERS + 1; i++) {
int goodID = SecretBase_GetGoodIDAtIndex(secretBase, i);
if (goodID == UG_GOOD_NONE) {
continue;
}
if (i == 0) {
continue;
} else if (i < MAX_PLACED_GOODS + 1) {
Good_GetCollision(goodID);
} else {
continue;
}
int goodX = SecretBase_GetGoodXCoordAtIndex(secretBase, i);
int goodZ = SecretBase_GetGoodZCoordAtIndex(secretBase, i);
goodX = xWithinBase - goodX;
goodZ = zWithinBase - goodZ;
if (goodX == 0 && goodZ == 0) {
return goodID;
}
}
return UG_GOOD_NONE;
}
static int SecretBases_GetTrapIDFromGoodID(int goodID)
{
switch (goodID) {
case UG_GOOD_HOLE_TOOL:
return TRAP_HOLE;
case UG_GOOD_PIT_TOOL:
return TRAP_PIT;
case UG_GOOD_SMOKE_TOOL:
return TRAP_SMOKE;
case UG_GOOD_BIG_SMOKE_TOOL:
return TRAP_BIG_SMOKE;
case UG_GOOD_ROCK_TOOL:
return TRAP_ROCK;
case UG_GOOD_ROCKFALL_TOOL:
return TRAP_ROCKFALL;
case UG_GOOD_FOAM_TOOL:
return TRAP_FOAM;
case UG_GOOD_BUBBLE_TOOL:
return TRAP_BUBBLE;
case UG_GOOD_ALERT_TOOL_1:
return TRAP_ALERT_1;
case UG_GOOD_ALERT_TOOL_2:
return TRAP_ALERT_2;
case UG_GOOD_ALERT_TOOL_3:
return TRAP_ALERT_3;
case UG_GOOD_ALERT_TOOL_4:
return TRAP_ALERT_4;
case UG_GOOD_LEAF_TOOL:
return TRAP_LEAF;
case UG_GOOD_FLOWER_TOOL:
return TRAP_FLOWER;
case UG_GOOD_EMBER_TOOL:
return TRAP_EMBER;
case UG_GOOD_FIRE_TOOL:
return TRAP_FIRE;
}
return TRAP_NONE;
}
BOOL SecretBases_CheckPlayerTriggeredTool(int netID)
{
int x = CommPlayer_GetXServerIfActive(netID);
int z = CommPlayer_GetZServerIfActive(netID);
int dir = CommPlayer_DirServer(netID);
if (!Underground_AreCoordinatesInSecretBase(x, z)) {
return FALSE;
}
if (SecretBases_AreCoordinatesWalkable(x, z) == TRUE && !secretBasesEnv->playerAffectedByTool[netID]) {
int baseOwnerNetID = SecretBases_GetOwnerNetIDFromCoordinates(x, z);
SecretBase *secretBase = (SecretBase *)secretBasesEnv->baseInfo[baseOwnerNetID].secretBase;
u8 goodID = SecretBases_GetPlacedGoodAtCoordinates(secretBase, x % SECRET_BASE_WIDTH, z % SECRET_BASE_DEPTH);
int trapID = SecretBases_GetTrapIDFromGoodID(goodID);
if (trapID != TRAP_NONE) {
secretBasesEnv->playerAffectedByTool[netID] = TRUE;
UndergroundTraps_HandleTriggeredTool(netID, NETID_NONE, trapID, x, z, dir);
return TRUE;
}
}
return FALSE;
}
BOOL SecretBases_ClearToolEffectFlag(int netID)
{
if (secretBasesEnv) {
secretBasesEnv->playerAffectedByTool[netID] = FALSE;
}
return FALSE;
}
void SecretBases_HandleDisconnectedPlayers(int unused)
{
int netID;
int x, z;
u8 playerRemovedFromBase[MAX_CONNECTED_PLAYERS];
MI_CpuClear8(playerRemovedFromBase, MAX_CONNECTED_PLAYERS);
for (netID = 0; netID < MAX_CONNECTED_PLAYERS; netID++) {
if (CommSys_IsPlayerConnected(netID)) {
x = CommPlayer_GetXServerIfActive(netID);
z = CommPlayer_GetZServerIfActive(netID);
if (x == 0xffff && z == 0xffff) {
continue;
}
int baseOwnerNetID = SecretBases_GetOwnerNetIDFromCoordinates(x, z);
if (netID == baseOwnerNetID || baseOwnerNetID == NETID_CURRENT_PLAYER_BASE) {
continue;
}
if (CommSys_IsPlayerConnected(baseOwnerNetID)) {
continue;
}
if (secretBasesEnv->baseTransitioningOwnerNetIDs[netID] == NETID_NONE && secretBasesEnv->baseEnteringOwnerNetIDs[netID] == NETID_NONE) {
if (Underground_AreCoordinatesInSecretBase(x, z)) {
if (!playerRemovedFromBase[netID]) {
SecretBases_ExitBase(baseOwnerNetID, netID, TRUE);
playerRemovedFromBase[netID] = TRUE;
}
}
}
}
}
netID = CommSys_CurNetId();
if (secretBasesEnv->moveStatus == MOVE_STATUS_EXITING) {
x = CommPlayer_GetXServerIfActive(netID);
z = CommPlayer_GetZServerIfActive(netID);
if (!(x == 0xffff && z == 0xffff) && Underground_AreCoordinatesInSecretBase(x, z)) {
int baseOwnerNetID = SecretBases_GetOwnerNetIDFromCoordinates(x, z);
if (!playerRemovedFromBase[netID]) {
SecretBases_ExitBase(baseOwnerNetID, netID, TRUE);
playerRemovedFromBase[netID] = TRUE;
}
}
if (playerRemovedFromBase[netID]) {
secretBasesEnv->moveStatus = MOVE_STATUS_NONE;
}
}
}
BOOL SecretBases_RemovePlayerFromBase(int netID, BOOL forceExit)
{
if (secretBasesEnv->occupiedBaseOwnerIDs[netID] == NETID_NONE) {
return FALSE;
}
int x = CommPlayer_XPos(CommSys_CurNetId());
int z = CommPlayer_ZPos(CommSys_CurNetId());
if (!Underground_AreCoordinatesInSecretBase(x, z)) {
secretBasesEnv->occupiedBaseOwnerIDs[netID] = NETID_NONE;
return FALSE;
}
ov23_022535EC();
UndergroundTalk_ExitConversation();
ov23_0224321C();
UndergroundTraps_ForceEndCurrentTrapEffectClient(CommSys_CurNetId(), FALSE);
x = secretBasesEnv->currentBaseReturnXCoord;
z = secretBasesEnv->currentBaseReturnZCoord;
int dir = secretBasesEnv->currentBaseReturnDir;
GF_ASSERT(x != 0 && z != 0);
x += MapObject_GetDxFromDir(dir);
z += MapObject_GetDzFromDir(dir);
secretBasesEnv->currentPlayerInBase = FALSE;
SecretBases_StartMoveToFromSecretBaseTask(secretBasesEnv->fieldSystem, x, z, dir, netID, forceExit);
ov23_02249AB8();
secretBasesEnv->currentOccupiedBaseInfo = NULL;
secretBasesEnv->occupiedBaseOwnerIDs[netID] = NETID_NONE;
return TRUE;
}
void SecretBases_AbortBaseEnterEarly(void)
{
if (secretBasesEnv->moveStatus == MOVE_STATUS_ENTERING) {
secretBasesEnv->moveStatus = MOVE_STATUS_ERROR_WHILE_ENTERING;
CommPlayer_InitPersonal();
SecretBases_ResetBaseEntranceData(0);
}
}
void SecretBases_AbortBaseEnterLate(void)
{
if (secretBasesEnv->moveStatus == MOVE_STATUS_ENTERING_2) {
secretBasesEnv->moveStatus = MOVE_STATUS_ERROR_WHILE_ENTERING_2;
}
}
// if a new link joins while already in their secret base, kick them out
void SecretBases_RemoveNewLinkFromBase(int netID)
{
int x = CommPlayer_GetXServer(netID);
int z = CommPlayer_GetZServer(netID);
if (!TerrainCollisionManager_CheckCollision(secretBasesEnv->fieldSystem, x, z)) {
if (netID == 0) {
return;
}
if (CommServerClient_IsInClosedSecretBase()) {
return;
}
}
if (x == 0xffff && z == 0xffff) {
SecretBases_ExitBase(netID, netID, TRUE);
} else if (Underground_AreCoordinatesInSecretBase(x, z) || TerrainCollisionManager_CheckCollision(secretBasesEnv->fieldSystem, x, z)) {
SecretBases_ExitBase(netID, netID, TRUE);
}
}
int SecretBases_GetCurrentBaseReturnXCoord(void)
{
if (secretBasesEnv) {
return secretBasesEnv->currentBaseReturnXCoord;
}
return DEFAULT_BASE_RETURN_X;
}
int SecretBases_GetCurrentBaseReturnZCoord(void)
{
if (secretBasesEnv) {
return secretBasesEnv->currentBaseReturnZCoord;
}
return DEFAULT_BASE_RETURN_Z;
}
int SecretBases_GetCurrentBaseReturnDir(void)
{
if (secretBasesEnv) {
return secretBasesEnv->currentBaseReturnDir;
}
return DIR_SOUTH;
}
void SecretBases_SetBaseReturnXCoord(int netID, int x)
{
if (secretBasesEnv) {
secretBasesEnv->baseReturnXCoords[netID] = x;
}
}
void SecretBases_SetBaseReturnZCoord(int netID, int z)
{
if (secretBasesEnv) {
secretBasesEnv->baseReturnZCoords[netID] = z;
}
}
void SecretBases_SetBaseReturnDir(int netID, int dir)
{
if (secretBasesEnv) {
secretBasesEnv->baseReturnDirs[netID] = dir;
}
}
void SecretBases_SetEntranceGraphicsEnabled(BOOL enabled)
{
secretBasesEnv->baseEntranceGraphicsEnabled = enabled;
}
static void ov23_0224DC08(void)
{
sub_02032174(TRUE);
sub_02032138(TRUE);
sub_02036814(TRUE);
sub_020340FC();
}
static void ov23_0224DC24(void)
{
sub_02032174(FALSE);
sub_02032138(FALSE);
sub_02036814(FALSE);
sub_020340FC();
}