pmd-red/src/dungeon.c
2025-03-27 16:12:45 +01:00

452 lines
12 KiB
C

#include "global.h"
#include "constants/dungeon.h"
#include "constants/monster.h"
#include "constants/type.h"
#include "code_800D090.h"
#include "code_8092334.h"
#include "dungeon.h"
#include "items.h"
#include "moves.h"
#include "pokemon.h"
#include "pokemon_mid.h"
#include "random.h"
#include "string_format.h"
#include "strings.h"
#include "dungeon_data.h"
extern const char gUnknown_8108F10[];
extern const char gUnknown_8108F18[];
extern const char gUnknown_8108F2C[];
extern u8 gDungeonFloorCount[];
extern const u8 *const gUnknown_8108084[];
extern DungeonLocation gUnknown_8107828[];
extern u8 gDungeonFloorCount[];
extern u8 gUnknown_81077E8[];
extern u8 gUnknown_8108F40[];
extern u16 gUnknown_8108F42[];
extern u8 gUnknown_8108F4A[4];
extern u8 gUnknown_8108F50[];
static void sub_8090888(u8 *param_1, u8 *param_2);
static bool8 sub_8090820(u16 moveID);
const u8 *GetDungeonName1(u8 dungeon)
{
return gDungeonNames[dungeon].name1;
}
const u8 *GetDungeonName2(u8 dungeon)
{
return gDungeonNames[dungeon].name2;
}
bool8 IsStairDirectionUp(u8 dungeon)
{
return gDungeons[dungeon].stairDirectionUp;
}
s16 GetTurnLimit(u8 dungeon)
{
return gDungeons[dungeon].turnLimit;
}
bool8 IsEnterWithoutGameSave(u8 dungeon)
{
return gDungeons[dungeon].enterWithoutGameSave;
}
u8 HasCheckpoint(u8 dungeon)
{
return gDungeons[dungeon].hasCheckpoint;
}
bool8 IsLevelResetTo1(u8 dungeon)
{
return gDungeons[dungeon].levelResetTo1;
}
u32 GetMaxItemsAllowed(u8 dungeon)
{
return gDungeons[dungeon].maxItemsAllowed;
}
bool8 IsKeepMoney(u8 dungeon)
{
return gDungeons[dungeon].keepMoney;
}
s8 GetRescuesAllowed(u8 dungeon)
{
return gDungeons[dungeon].rescuesAllowed;
}
bool8 IsRecruitingEnabled(u8 dungeon)
{
return gDungeons[dungeon].recruitingEnabled;
}
bool8 CanLeaderSwitch(u8 dungeon)
{
return gDungeons[dungeon].leaderCanSwitch;
}
s16 GetRandomMovementChance(u8 dungeon)
{
return gDungeons[dungeon].randomMovementChance;
}
bool8 sub_809017C(DungeonLocation* a1)
{
DungeonLocation location;
int i;
sub_80901D8(&location, a1);
for (i = 0; i < 999 && gUnknown_8107828[i].id != 63; ++i) {
if (location.id == gUnknown_8107828[i].id &&
location.floor == gUnknown_8107828[i].floor) {
return TRUE;
}
}
return FALSE;
}
void sub_80901D8(DungeonLocation *param_1,DungeonLocation *param_2)
{
if (DUNGEON_IS_MAZE(param_2->id)) {
param_1->id = DUNGEON_NORMAL_MAZE;
param_1->floor = (param_2->id - DUNGEON_NORMAL_MAZE_2) * 3 + param_2->floor;
}
else {
*param_1 = *param_2;
}
}
void PrintYellowDungeonNametoBuffer(u8 *buffer, DungeonLocation *dungeonLocation)
{
sprintfStatic(buffer, gUnknown_8108F10, gDungeonNames[dungeonLocation->id].name1); // {color YELLOW_D}%s{reset} (normal floor print (no B)
}
void PrintDungeonLocationtoBuffer(u8 *buffer, DungeonLocation *dungeonLocation)
{
if(gDungeons[dungeonLocation->id].stairDirectionUp){
sprintfStatic(buffer, gUnknown_8108F18, gDungeonNames[dungeonLocation->id].name1, dungeonLocation->floor); //_F
}
else
{
sprintfStatic(buffer, gUnknown_8108F2C, gDungeonNames[dungeonLocation->id].name1, dungeonLocation->floor); // B _F
}
}
void CopyDungeonName1toBuffer(u8 *buffer, DungeonLocation *dungeonLocation)
{
strncpy(buffer, gDungeonNames[dungeonLocation->id].name1, 0x50);
}
s32 GetDungeonFloorCount(u8 dungeon)
{
if (DUNGEON_IS_MAZE(dungeon))
return 4;
else if(dungeon > DUNGEON_PURITY_FOREST)
return 1;
else
return gDungeonFloorCount[dungeon];
}
u8 sub_80902C8(u8 dungeon)
{
if (DUNGEON_IS_MAZE(dungeon))
return 0;
else if(dungeon > DUNGEON_PURITY_FOREST)
return 0;
else
return gUnknown_81077E8[dungeon];
}
// arm9.bin::0205ECA0
void WriteDungeonLocationBits(DataSerializer* r0, DungeonLocation* src)
{
WriteBits(r0, &src->id, 7);
WriteBits(r0, &src->floor, 7);
}
// arm9.bin::0205EC64
void ReadDungeonLocationBits(DataSerializer* r0, DungeonLocation* dst)
{
dst->id = 0;
dst->floor = 0;
ReadBits(r0, &dst->id, 7);
ReadBits(r0, &dst->floor, 7);
}
bool8 DoEnemiesEvolveWhenKOed(u8 dungeon)
{
return gDungeons[dungeon].enemiesEvolveWhenKOed;
}
// Needed to match.
static inline void AddNewLine(const u8 *str, u8 *buffer, u8 *newLine)
{
FormatString(str, buffer, newLine, 0);
}
// I think this checks if the dungeon HM requirement is met
u32 sub_809034C(u8 dungeonIndex, s32 speciesId_, u8 *buffer, bool32 param_4_, bool32 param_5_)
{
s32 maxPartyMembers, i;
s32 speciesId = (s16) speciesId_;
bool32 param_4 = (bool8) (param_4_);
bool32 param_5 = (bool8) (param_5_);
s32 numInvSlots = GetNumberOfFilledInventorySlots();
s32 counter = 0;
s32 sp_0xf0;
bool8 sp_0xf4 = FALSE;
bool8 r8 = FALSE;
u8 text[200];
u8 newLine[2];
newLine[0] = '\n';
newLine[1] = 0;
strcpy(buffer,gUnknown_8108F40);
sp_0xf0 = 0;
for (i = 0; i < NUM_MONSTERS; i++) {
struct PokemonStruct1 *mon = &gRecruitedPokemonRef->pokemon[i];
if (PokemonFlag1(mon) && PokemonFlag2(mon)) {
if (mon->heldItem.id != 0) {
sp_0xf0++;
}
if (++counter == 4) break;
}
}
maxPartyMembers = gDungeons[dungeonIndex].maxPartyMembers;
if (!param_4 && maxPartyMembers > 3) {
maxPartyMembers = 3;
}
if (counter > maxPartyMembers) {
if (maxPartyMembers == 1) {
AddNewLine(gText_OnlyOneMonMayEnterDungeon,text,newLine);
}
else {
gFormatArgs[0] = counter - maxPartyMembers;
AddNewLine(gText_TooManyMembersToEnterDungeon,text,newLine);
}
sub_8090888(buffer,text);
r8 = TRUE;
}
if (gDungeons[dungeonIndex].maxItemsAllowed != 0 && gDungeons[dungeonIndex].maxItemsAllowed < numInvSlots) {
gFormatArgs[0] = gDungeons[dungeonIndex].maxItemsAllowed;
gFormatArgs[1] = numInvSlots - gDungeons[dungeonIndex].maxItemsAllowed;
AddNewLine((!r8) ? gText_OnlyXItemsMayBeBroughtIntoDungeon : gText_AlsoOnlyXItemsMayBeBroughtIntoDungeon, text, newLine);
sub_8090888(buffer,text);
r8 = TRUE;
}
if (speciesId != MONSTER_NONE) {
s32 i, bodySize;
CopyCyanMonsterNametoBuffer(gFormatBuffer_Monsters[0],speciesId);
if (counter > 3) {
AddNewLine((!r8) ? gText_ClientCouldNotJoinTooManyMembers : gText_AlsoClientCouldNotJoinTooManyMembers, text,newLine);
sub_8090888(buffer,text);
r8 = TRUE;
}
bodySize = GetBodySize(speciesId);
for (i = 0; i < NUM_MONSTERS; i++) {
struct PokemonStruct1 *mon = &gRecruitedPokemonRef->pokemon[i];
if (PokemonFlag1(mon) && PokemonFlag2(mon)){
bodySize += GetBodySize(mon->speciesNum);
}
}
if (bodySize > 6) {
AddNewLine((!r8) ? gText_ClientCouldNotJoinNoSpace : gText_AlsoClientCouldNotJoinNoSpace, text,newLine);
sub_8090888(buffer,text);
r8 = TRUE;
}
}
if (param_4) {
s32 i;
//u16 local_4c[4] = {0x99, 0x9C, 0x9b, 0xdb};
//u8 local_44[4] = {0xe1, 0xe7, 0xe6, 0xe2};
u16 local_4c[4];
u8 local_44[4];
memcpy(local_4c,gUnknown_8108F42,8);
memcpy(local_44,gUnknown_8108F4A,4);
for (i = 0; i < 4; i++) {
if ((((gDungeons[dungeonIndex].HMMask >> (i) & 1) != 0) && !sub_8090820(local_4c[i])) && GetItemPossessionCount(local_44[i]) == 0) {
break;
}
}
if (i < 4) {
struct Move move;
InitPokemonMove(&move,local_4c[i]);
BufferMoveName(gFormatBuffer_Items[0],&move,0);
AddNewLine((!r8) ? gText_MustHaveMonWithMove : gText_AlsoMustHaveMonWithMove, text,newLine);
sub_8090888(buffer,text);
r8 = TRUE;
}
}
if (gDungeons[dungeonIndex].HMMask & 0x10) {
s32 otherSpeciesId = NUM_MONSTERS;
if (speciesId != MONSTER_NONE && (GetPokemonType(speciesId,0) == TYPE_WATER || (GetPokemonType(speciesId,1) == TYPE_WATER))) {
otherSpeciesId = 0;
}
if (otherSpeciesId == NUM_MONSTERS) {
for (otherSpeciesId = 0; otherSpeciesId < NUM_MONSTERS; otherSpeciesId++) {
struct PokemonStruct1 *mon = &gRecruitedPokemonRef->pokemon[otherSpeciesId];
if (PokemonFlag1(mon) && PokemonFlag2(mon)
&& (GetPokemonType(mon->speciesNum,0) == TYPE_WATER || GetPokemonType(mon->speciesNum,1) == TYPE_WATER))
{
break;
}
}
if (otherSpeciesId == NUM_MONSTERS) {
AddNewLine((!r8) ? gText_MustHaveWaterTypeMon : gText_AlsoMustHaveWaterTypeMon, text,newLine);
sub_8090888(buffer,text);
r8 = TRUE;
}
}
}
if (r8) {
return 1;
}
if ((!gDungeons[dungeonIndex].enterWithoutGameSave) || (param_5)) {
if (!sp_0xf4) {
strcpy(buffer,gText_IsOkToEnterWithFollowingRules);
strcat(buffer,newLine);
sp_0xf4 = TRUE;
}
strcat(buffer,gText_GameWilllBeSavedBeforeEntering);
strcat(buffer,newLine);
}
if (gDungeons[dungeonIndex].levelResetTo1) {
if (!sp_0xf4) {
strcpy(buffer,gText_IsOkToEnterWithFollowingRules);
strcat(buffer,newLine);
sp_0xf4 = TRUE;
}
strcat(buffer,gText_TeamWillEnterAtLv1);
strcat(buffer,newLine);
}
if ((gDungeons[dungeonIndex].maxItemsAllowed == 0) && (numInvSlots + sp_0xf0 != 0)) {
if (!sp_0xf4) {
strcpy(buffer,gText_IsOkToEnterWithFollowingRules);
strcat(buffer,newLine);
sp_0xf4 = TRUE;
}
strcat(buffer,gText_AllItemsLostOnEntering);
strcat(buffer,newLine);
}
if ((!gDungeons[dungeonIndex].keepMoney) && (gTeamInventoryRef->teamMoney != 0)) {
if (!sp_0xf4) {
strcpy(buffer,gText_IsOkToEnterWithFollowingRules);
strcat(buffer,newLine);
sp_0xf4 = TRUE;
}
strcat(buffer, gText_AllMoneyLostOnEntering);
strcat(buffer,newLine);
}
if (sp_0xf4) {
return 2;
}
else {
sprintfStatic(buffer,gUnknown_8108F50);
return 0;
}
}
static bool8 sub_8090820(u16 moveID)
{
s32 speciesId, moveIndex;
for (speciesId = 0; speciesId < NUM_MONSTERS; speciesId++) {
PokemonStruct1 *pokeStruct = &gRecruitedPokemonRef->pokemon[speciesId];
if (PokemonFlag1(pokeStruct) && PokemonFlag2(pokeStruct)) {
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) {
Move *move = &pokeStruct->moves[moveIndex];
if (MoveFlagExists(move) && move->id == moveID) {
return TRUE;
}
}
}
}
return FALSE;
}
static void sub_8090888(u8 *param_1, u8 *param_2)
{
s32 iVar3 = 0;
while (*param_1 != '\0') {
switch (*param_1) {
case '\n':
iVar3++;
break;
}
param_1++;
}
while (iVar3 % 3) {
*param_1++ = '\n';
iVar3++;
}
while (*param_2 != '\0') {
*param_1++ = *param_2;
param_2++;
}
*param_1 = '\0';
}
u32 sub_80908D8(DungeonLocation *dungeon)
{
if (dungeon->id < DUNGEON_OUT_ON_RESCUE && dungeon->floor < gDungeonFloorCount[dungeon->id]) {
return gUnknown_8108084[dungeon->id][dungeon->floor];
}
else {
return 1;
}
}
u8 sub_8090910(DungeonLocation *dungeon, u32 param_2)
{
s32 rand1 = RandInt(9999);
s32 rand2 = RandInt(9999);
if (dungeon->id < DUNGEON_OUT_ON_RESCUE && dungeon->floor < gDungeonFloorCount[dungeon->id]) {
return sub_8091E94(param_2, rand1, rand2);
}
else {
return 0x46;
}
}
bool8 IsNotValidDungeon(u8 dungeon)
{
if (dungeon >= DUNGEON_OUT_ON_RESCUE) {
return TRUE;
}
else {
s32 i;
for (i = 0; gInvalidDungeonIDs[i] != DUNGEON_OUT_ON_RESCUE; i++) {
if (gInvalidDungeonIDs[i] == dungeon)
return TRUE;
}
return FALSE;
}
}