mirror of
https://github.com/pret/pmd-red.git
synced 2024-11-23 05:00:12 +00:00
GenerateSecondaryTerrainFormations failed attempt
This commit is contained in:
parent
cb5242ba6c
commit
799ea6a5c6
1065
asm/code_804FD30.s
1065
asm/code_804FD30.s
File diff suppressed because it is too large
Load Diff
@ -125,7 +125,7 @@ typedef struct UnkDungeonGlobal_unk1C574
|
||||
u8 unk3;
|
||||
u8 unk4;
|
||||
u8 floorConnectivity;
|
||||
u8 unk6;
|
||||
u8 enemyDensity;
|
||||
u8 kecleonShopChance; // Percentage chance 0-100%
|
||||
u8 monsterHouseChance; // Percentage chance 0-100%
|
||||
u8 mazeRoomChance; // Percentage chance 0-100%
|
||||
@ -347,7 +347,7 @@ typedef struct Dungeon
|
||||
u8 fill3802[0x3904 - 0x3802];
|
||||
/* 0x3904 */ s16 numItems;
|
||||
u8 fill3906[0x3A08 - 0x3906];
|
||||
/* 0x3A08 */ u8 unk3A08;
|
||||
/* 0x3A08 */ bool8 forceMonsterHouse; // Forces the current floor to have monster house
|
||||
/* 0x3A09 */ u8 unk3A09;
|
||||
/* 0x3A0A */ u8 unk3A0A;
|
||||
/* 0x3A0B */ u8 unk3A0B;
|
||||
|
@ -751,7 +751,7 @@ void xxx_dungeon_8042F6C(struct UnkStruct_xxx_dungeon_8042F6C *r8)
|
||||
}
|
||||
else {
|
||||
sub_80427AC();
|
||||
sub_8075900(GetLeader(), gDungeon->unk3A08);
|
||||
sub_8075900(GetLeader(), gDungeon->forceMonsterHouse);
|
||||
sub_807EAA0(1, 0);
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ void HandleGiveItemAction(Entity *param_1)
|
||||
if (!info2->isTeamLeader) {
|
||||
info2->flags = info2->flags | MOVEMENT_FLAG_UNK_14;
|
||||
}
|
||||
sub_807AB38(param_1,gDungeon->unk3A08);
|
||||
sub_807AB38(param_1,gDungeon->forceMonsterHouse);
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@ void HandleTakeItemAction(Entity *param_1)
|
||||
if (!info->isTeamLeader) {
|
||||
info->flags |= MOVEMENT_FLAG_UNK_14;
|
||||
}
|
||||
sub_807AB38(param_1,gDungeon->unk3A08);
|
||||
sub_807AB38(param_1,gDungeon->forceMonsterHouse);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -267,7 +267,7 @@ void sub_8066BD4(Entity *param_1)
|
||||
if (!info->isTeamLeader) {
|
||||
info->flags = info->flags | MOVEMENT_FLAG_UNK_14;
|
||||
}
|
||||
sub_807AB38(param_1,gDungeon->unk3A08);
|
||||
sub_807AB38(param_1,gDungeon->forceMonsterHouse);
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,7 +325,7 @@ void HandlePlaceItemAction(Entity *param_1)
|
||||
PlaySoundEffect(0x14d);
|
||||
SetMessageArgument(gFormatBuffer_Monsters[0],entity,0);
|
||||
TryDisplayDungeonLoggableMessage(entity,*gUnknown_80F8E28);
|
||||
sub_807AB38(entity,gDungeon->unk3A08);
|
||||
sub_807AB38(entity,gDungeon->forceMonsterHouse);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1019,7 +1019,7 @@ bool8 UseAttack(Entity *a0)
|
||||
|
||||
sub_8071DA4(mon);
|
||||
sub_8046D20();
|
||||
sub_8075900(mon, gDungeon->unk3A08);
|
||||
sub_8075900(mon, gDungeon->forceMonsterHouse);
|
||||
}
|
||||
if (!EntityExists(mon))
|
||||
continue;
|
||||
|
@ -157,7 +157,7 @@ void sub_807CD9C(Entity *pokemon, Entity *target, u32 direction)
|
||||
sub_807EC28(FALSE);
|
||||
}
|
||||
sub_806A5B8(target);
|
||||
sub_8075900(target,gDungeon->unk3A08);
|
||||
sub_8075900(target,gDungeon->forceMonsterHouse);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -321,7 +321,7 @@ void sub_807D148(Entity *pokemon, Entity *target, u32 param_3, Position *pos)
|
||||
sub_807EC28(0);
|
||||
}
|
||||
sub_806A5B8(target);
|
||||
sub_8075900(target,gDungeon->unk3A08);
|
||||
sub_8075900(target,gDungeon->forceMonsterHouse);
|
||||
}
|
||||
|
||||
void sub_807D3CC(Entity *param_1)
|
||||
|
@ -101,7 +101,7 @@ void sub_807E254(Entity *pokemon,Entity *target)
|
||||
sub_807EC28(FALSE);
|
||||
}
|
||||
sub_806A5B8(pokemon);
|
||||
sub_8075900(pokemon,gDungeon->unk3A08);
|
||||
sub_8075900(pokemon,gDungeon->forceMonsterHouse);
|
||||
}
|
||||
|
||||
if (EntityExists(target)) {
|
||||
@ -110,7 +110,7 @@ void sub_807E254(Entity *pokemon,Entity *target)
|
||||
sub_807EC28(FALSE);
|
||||
}
|
||||
sub_806A5B8(target);
|
||||
sub_8075900(target,gDungeon->unk3A08);
|
||||
sub_8075900(target,gDungeon->forceMonsterHouse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1065,7 +1065,7 @@ void HandleUseOrbAction(Entity *pokemon)
|
||||
}
|
||||
|
||||
sub_806A5B8(pokemon);
|
||||
sub_8075900(pokemon, gDungeon->unk3A08);
|
||||
sub_8075900(pokemon, gDungeon->forceMonsterHouse);
|
||||
}
|
||||
else if (r4)
|
||||
sub_8044D40(&act, 0);
|
||||
|
@ -107,9 +107,9 @@ void GenerateCrossFloor(UnkDungeonGlobal_unk1C574 *a0);
|
||||
void GenerateBeetleFloor(UnkDungeonGlobal_unk1C574 *a0);
|
||||
void GenerateOuterRoomsFloor(s32 gridSizeX_, s32 gridSizeY_, UnkDungeonGlobal_unk1C574 *unkPtr);
|
||||
void sub_8051654(UnkDungeonGlobal_unk1C574 *a0);
|
||||
void sub_80506F0(s32 a0, UnkDungeonGlobal_unk1C574 *a1);
|
||||
void GenerateSecondaryTerrainFormations(u32 flag, UnkDungeonGlobal_unk1C574 *unkPtr);
|
||||
void SpawnNonEnemies(UnkDungeonGlobal_unk1C574 *unkPtr, bool8 isEmptyMonsterHouse);
|
||||
void sub_8050438(UnkDungeonGlobal_unk1C574 *unkPtr, bool8 isEmptyMonsterHouse);
|
||||
void SpawnEnemies(UnkDungeonGlobal_unk1C574 *unkPtr, bool8 isEmptyMonsterHouse);
|
||||
|
||||
EWRAM_DATA u8 gUnknown_202F1A8 = 0;
|
||||
EWRAM_DATA u8 gUnknown_202F1A9 = 0;
|
||||
@ -210,7 +210,7 @@ void sub_804AFAC(void)
|
||||
ResetFloor();
|
||||
gDungeon->playerSpawn.x = -1;
|
||||
gDungeon->playerSpawn.y = -1;
|
||||
gDungeon->unk3A08 = 0;
|
||||
gDungeon->forceMonsterHouse = 0;
|
||||
if (gDungeon->bossBattleIndex != 0) {
|
||||
if (sub_804C70C(gDungeon->bossBattleIndex, unkPtr)) {
|
||||
break;
|
||||
@ -247,7 +247,7 @@ void sub_804AFAC(void)
|
||||
y = 1;
|
||||
}
|
||||
|
||||
gDungeon->unk3A08 = 0;
|
||||
gDungeon->forceMonsterHouse = 0;
|
||||
gDungeon->monsterHouseRoom = 0xFF;
|
||||
gUnknown_202F1D0 = r7;
|
||||
switch (r7 & 0xF) {
|
||||
@ -270,7 +270,7 @@ void sub_804AFAC(void)
|
||||
break;
|
||||
case 2:
|
||||
GenerateOneRoomMonsterHouseFloor();
|
||||
gDungeon->unk3A08 = 1;
|
||||
gDungeon->forceMonsterHouse = 1;
|
||||
break;
|
||||
case 3:
|
||||
GenerateOuterRingFloor(unkPtr);
|
||||
@ -282,7 +282,7 @@ void sub_804AFAC(void)
|
||||
break;
|
||||
case 5:
|
||||
GenerateTwoRoomsWithMonsterHouseFloor();
|
||||
gDungeon->unk3A08 = 1;
|
||||
gDungeon->forceMonsterHouse = 1;
|
||||
break;
|
||||
case 6:
|
||||
GenerateLineFloor(unkPtr);
|
||||
@ -342,15 +342,15 @@ void sub_804AFAC(void)
|
||||
gUnknown_202F1D8.x = -1;
|
||||
gUnknown_202F1D8.y = -1;
|
||||
GenerateOneRoomMonsterHouseFloor();
|
||||
gDungeon->unk3A08 = 1;
|
||||
gDungeon->forceMonsterHouse = 1;
|
||||
}
|
||||
sub_804E9DC();
|
||||
if (r10) {
|
||||
sub_80506F0(1, unkPtr);
|
||||
GenerateSecondaryTerrainFormations(1, unkPtr);
|
||||
}
|
||||
r4 = (DungeonRandInt(100) < unkPtr->connectedToTop);
|
||||
SpawnNonEnemies(unkPtr, r4);
|
||||
sub_8050438(unkPtr, r4);
|
||||
SpawnEnemies(unkPtr, r4);
|
||||
ResolveInvalidSpawns();
|
||||
if (gDungeon->playerSpawn.x != -1 && gDungeon->playerSpawn.y != -1)
|
||||
{
|
||||
@ -366,10 +366,10 @@ void sub_804AFAC(void)
|
||||
gUnknown_202F1D8.y = -1;
|
||||
ResetFloor();
|
||||
GenerateOneRoomMonsterHouseFloor();
|
||||
gDungeon->unk3A08 = 1;
|
||||
gDungeon->forceMonsterHouse = TRUE;
|
||||
sub_804E9DC();
|
||||
SpawnNonEnemies(unkPtr, FALSE);
|
||||
sub_8050438(unkPtr, FALSE);
|
||||
SpawnEnemies(unkPtr, FALSE);
|
||||
ResolveInvalidSpawns();
|
||||
}
|
||||
|
||||
@ -863,7 +863,7 @@ void NAKED sub_804AFAC(void)
|
||||
" beq _0804B3AA\n"
|
||||
" movs r0, 0x1\n"
|
||||
" mov r1, r8\n"
|
||||
" bl sub_80506F0\n"
|
||||
" bl GenerateSecondaryTerrainFormations\n"
|
||||
"_0804B3AA:\n"
|
||||
" movs r0, 0x64\n"
|
||||
" bl DungeonRandInt\n"
|
||||
@ -879,7 +879,7 @@ void NAKED sub_804AFAC(void)
|
||||
" bl SpawnNonEnemies\n"
|
||||
" mov r0, r8\n"
|
||||
" adds r1, r4, 0\n"
|
||||
" bl sub_8050438\n"
|
||||
" bl SpawnEnemies\n"
|
||||
" bl ResolveInvalidSpawns\n"
|
||||
" ldr r5, _0804B4C0\n"
|
||||
" ldr r1, [r5]\n"
|
||||
@ -955,7 +955,7 @@ void NAKED sub_804AFAC(void)
|
||||
" bl SpawnNonEnemies\n"
|
||||
" mov r0, r8\n"
|
||||
" movs r1, 0\n"
|
||||
" bl sub_8050438\n"
|
||||
" bl SpawnEnemies\n"
|
||||
" bl ResolveInvalidSpawns\n"
|
||||
"_0804B474:\n"
|
||||
" ldr r1, _0804B4B8\n"
|
||||
@ -4607,9 +4607,10 @@ void ShuffleSpawnPositions(struct PositionU8 *spawns, s32 count)
|
||||
* See below for specific conditions on each type of spawn.
|
||||
*/
|
||||
extern const s16 gUnknown_80F4DA0;
|
||||
extern const s16 gUnknown_80F4DA4;
|
||||
void SpawnNonEnemies(UnkDungeonGlobal_unk1C574 *unkPtr, bool8 isEmptyMonsterHouse)
|
||||
{
|
||||
struct PositionU8 validSpawns[1792];
|
||||
struct PositionU8 validSpawns[DUNGEON_MAX_SIZE_X * DUNGEON_MAX_SIZE_Y];
|
||||
s32 count;
|
||||
s32 randIndex;
|
||||
s32 i;
|
||||
@ -4940,4 +4941,460 @@ void SpawnNonEnemies(UnkDungeonGlobal_unk1C574 *unkPtr, bool8 isEmptyMonsterHous
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SpawnEnemies - Spawns all enemies, including those in forced monster houses
|
||||
*/
|
||||
void SpawnEnemies(UnkDungeonGlobal_unk1C574 *unkPtr, bool8 isEmptyMonsterHouse)
|
||||
{
|
||||
struct PositionU8 validSpawns[DUNGEON_MAX_SIZE_X * DUNGEON_MAX_SIZE_Y];
|
||||
s32 count;
|
||||
s32 randIndex;
|
||||
s32 i;
|
||||
s32 x, y;
|
||||
Dungeon *dungeon = gDungeon;
|
||||
s32 numEnemies, numMonsterHouseEnemies;
|
||||
s32 enemyDensity = unkPtr->enemyDensity;
|
||||
|
||||
if (enemyDensity > 0) {
|
||||
// Positive means value with variance
|
||||
numEnemies = DungeonRandRange(enemyDensity / 2, enemyDensity);
|
||||
|
||||
if (numEnemies < 1) {
|
||||
numEnemies = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Negative means exact value.
|
||||
// Bug - abs is missing, also it should be s8, not u8
|
||||
numEnemies = enemyDensity;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for (x = 0; x < DUNGEON_MAX_SIZE_X; x++) {
|
||||
for (y = 0; y < DUNGEON_MAX_SIZE_Y; y++) {
|
||||
// Enemies can spawn on tiles that are:
|
||||
// - Open Terrain
|
||||
// - In a room
|
||||
// - Not in a Kecleon Shop
|
||||
// - Don't have stairs, an item
|
||||
// - Not a special tile that can't be broken by Absolute Mover
|
||||
// - Not where the player spawns
|
||||
Tile *tile = GetTile(x, y);
|
||||
if (GetTerrainType(tile) != TERRAIN_TYPE_NORMAL)
|
||||
continue;
|
||||
if (tile->room == CORRIDOR_ROOM)
|
||||
continue;
|
||||
if (tile->terrainType & TERRAIN_TYPE_SHOP)
|
||||
continue;
|
||||
if (tile->spawnOrVisibilityFlags & SPAWN_FLAG_ITEM)
|
||||
continue;
|
||||
if (tile->spawnOrVisibilityFlags & SPAWN_FLAG_STAIRS)
|
||||
continue;
|
||||
if (tile->terrainType & TERRAIN_TYPE_NATURAL_JUNCTION)
|
||||
continue;
|
||||
if (tile->terrainType & TERRAIN_TYPE_UNBREAKABLE)
|
||||
continue;
|
||||
if (x == dungeon->playerSpawn.x && y == dungeon->playerSpawn.y)
|
||||
continue;
|
||||
|
||||
validSpawns[count].x = x;
|
||||
validSpawns[count].y = y;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count != 0) {
|
||||
// ?
|
||||
if (gDungeon->unk688) {
|
||||
numEnemies++;
|
||||
}
|
||||
if (numEnemies != 0) {
|
||||
// Randomly select among the valid enemy spawn spots
|
||||
ShuffleSpawnPositions(validSpawns, count);
|
||||
randIndex = DungeonRandInt(count);
|
||||
|
||||
for (i = 0; i < numEnemies; i++) {
|
||||
Tile *tile = GetTileSafe(validSpawns[randIndex].x, validSpawns[randIndex].y);
|
||||
// Spawn an enemy here
|
||||
tile->spawnOrVisibilityFlags |= SPAWN_FLAG_MONSTER;
|
||||
|
||||
randIndex++;
|
||||
if (randIndex == count) {
|
||||
// Wrap around to the start
|
||||
randIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!dungeon->forceMonsterHouse) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This floor was marked to force a monster house
|
||||
// Place extra enemy spawns in the Monster House room
|
||||
|
||||
numMonsterHouseEnemies = gUnknown_80F4DA4;
|
||||
count = 0;
|
||||
if (isEmptyMonsterHouse) {
|
||||
// An "empty" monster house only spawns 3 enemies
|
||||
numMonsterHouseEnemies = 3;
|
||||
}
|
||||
|
||||
numMonsterHouseEnemies = (numMonsterHouseEnemies * 3) / 2;
|
||||
|
||||
for (x = 0; x < DUNGEON_MAX_SIZE_X; x++) {
|
||||
s32 y;
|
||||
for (y = 0; y < DUNGEON_MAX_SIZE_Y; y++) {
|
||||
// Monster House enemies can spawn on tiles that are:
|
||||
// - Open Terrain
|
||||
// - In a room
|
||||
// - Not in a Kecleon Shop
|
||||
// - Not a special tile that can't be broken by Absolute Mover
|
||||
// - Not where the player spawns
|
||||
// - In the monster house room
|
||||
|
||||
Tile *tile = GetTile(x, y);
|
||||
if (GetTerrainType(tile) != TERRAIN_TYPE_NORMAL)
|
||||
continue;
|
||||
if (tile->room == CORRIDOR_ROOM)
|
||||
continue;
|
||||
if (tile->terrainType & TERRAIN_TYPE_SHOP)
|
||||
continue;
|
||||
if (tile->terrainType & TERRAIN_TYPE_UNBREAKABLE)
|
||||
continue;
|
||||
if (!(tile->terrainType & TERRAIN_TYPE_IN_MONSTER_HOUSE))
|
||||
continue;
|
||||
if (x == dungeon->playerSpawn.x && y == dungeon->playerSpawn.y)
|
||||
continue;
|
||||
|
||||
validSpawns[count].x = x;
|
||||
validSpawns[count].y = y;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count != 0) {
|
||||
numEnemies = DungeonRandRange((7 * count) / 10, (8 * count) / 10);
|
||||
|
||||
if (numEnemies == 0) {
|
||||
numEnemies = 1;
|
||||
}
|
||||
|
||||
if (numEnemies >= numMonsterHouseEnemies) {
|
||||
// Don't spawn more enemies than the designated limit
|
||||
numEnemies = numMonsterHouseEnemies;
|
||||
}
|
||||
|
||||
// Randomly select among the valid enemy spawn spots
|
||||
ShuffleSpawnPositions(validSpawns, count);
|
||||
randIndex = DungeonRandInt(count);
|
||||
|
||||
for (i = 0; i < numEnemies; i++) {
|
||||
Tile *tile = GetTileSafe(validSpawns[randIndex].x, validSpawns[randIndex].y);
|
||||
// Spawn an enemy here
|
||||
tile->spawnOrVisibilityFlags |= SPAWN_FLAG_MONSTER;
|
||||
|
||||
randIndex++;
|
||||
if (randIndex == count) {
|
||||
// Wrap around to the start
|
||||
randIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SetSecondaryTerrainOnWall - Set a specific tile to have secondary terrain if the tile
|
||||
* is a passable wall.
|
||||
*/
|
||||
void SetSecondaryTerrainOnWall(Tile *tile)
|
||||
{
|
||||
bool8 isWall = TRUE;
|
||||
if (GetTerrainType(tile) != TERRAIN_TYPE_WALL)
|
||||
isWall = FALSE;
|
||||
if (tile->terrainType & TERRAIN_TYPE_IMPASSABLE_WALL)
|
||||
isWall = FALSE;
|
||||
|
||||
if (isWall) {
|
||||
SetTerrainSecondary(tile);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GenerateSecondaryTerrainFormations - Generates secondary terrain (water/lava) formations
|
||||
*
|
||||
* This generation includes rivers, lakes along the river path, and standalone lakes.
|
||||
*
|
||||
* The river flows from top-to-bottom or bottom-to-top, using a random walk ending when the walk
|
||||
* goes out of bounds or finds existing secondary terrain. Because of this, rivers can end prematurely
|
||||
* when a lake is generated.
|
||||
*
|
||||
* Lakes are a large collection of secondary terrain generated around a central point.
|
||||
* Standalone lakes are generated based on secondary_terrain_density
|
||||
*
|
||||
* The formations will never cut into room tiles, but can pass through to the other side.
|
||||
*/
|
||||
extern const s32 gUnknown_80F6DF8[8];
|
||||
void GenerateSecondaryTerrainFormations(u32 flag, UnkDungeonGlobal_unk1C574 *unkPtr)
|
||||
{
|
||||
s32 num_tiles_fill;
|
||||
s32 dir_x, dir_y;
|
||||
bool8 dir_y_upwards;
|
||||
s32 steps_until_lake;
|
||||
s32 j;
|
||||
s32 offsetX;
|
||||
s32 offsetY;
|
||||
s32 numToGen;
|
||||
s32 densityN;
|
||||
s32 x, y;
|
||||
|
||||
if (!(unkPtr->roomFlags & flag))
|
||||
return;
|
||||
|
||||
|
||||
// Generate 1-3 "river+lake" formations
|
||||
numToGen = gUnknown_80F6DF8[DungeonRandInt(ARRAY_COUNT(gUnknown_80F6DF8))];
|
||||
//for (i = 0; i < numToGen; i++) {
|
||||
for (;numToGen != 0; numToGen--) {
|
||||
// Randomly pick between starting from the bottom going up, or from the top going down
|
||||
|
||||
|
||||
if (DungeonRandInt(100) < 50) {
|
||||
dir_y_upwards = TRUE;
|
||||
y = DUNGEON_MAX_SIZE_Y - 1;
|
||||
dir_y = -1;
|
||||
}
|
||||
else {
|
||||
dir_y_upwards = FALSE;
|
||||
y = 0;
|
||||
dir_y = 1;
|
||||
}
|
||||
|
||||
steps_until_lake = DungeonRandInt(50) + 10;
|
||||
|
||||
// Pick a random column in the interior to start the river on
|
||||
x = DungeonRandRange(2, DUNGEON_MAX_SIZE_X - 2);
|
||||
dir_x = 0;
|
||||
|
||||
while (1) {
|
||||
// Fill in tiles in chunks of size 2-7 before changing the flow direction
|
||||
num_tiles_fill = DungeonRandInt(6) + 2;
|
||||
//for (v = 0; v < num_tiles_fill; v++) {
|
||||
while (num_tiles_fill != 0) {
|
||||
if (x >= 0 && x < DUNGEON_MAX_SIZE_X) {
|
||||
if (GetTerrainType(GetTile(x, y)) != TERRAIN_TYPE_SECONDARY) {
|
||||
if (!PosIsOutOfBounds(x, y)) {
|
||||
// Fill in secondary terrain as we go
|
||||
SetSecondaryTerrainOnWall(GetTileSafe(x, y));
|
||||
}
|
||||
}
|
||||
else {
|
||||
goto LABEL;
|
||||
}
|
||||
}
|
||||
num_tiles_fill--;
|
||||
|
||||
// Move to the next tile
|
||||
x += dir_x;
|
||||
y += dir_y;
|
||||
|
||||
// Vertically out of bounds, stop
|
||||
if (y < 0 || y >= DUNGEON_MAX_SIZE_Y) {
|
||||
break;
|
||||
}
|
||||
|
||||
steps_until_lake--;
|
||||
if (steps_until_lake != 0)
|
||||
continue;
|
||||
|
||||
// After we go a certain number of steps, make a "lake"
|
||||
|
||||
// This loop will attempt to generate new lake tiles up to 64 times
|
||||
// We select a random tile, check for space and nearby secondary terrain tiles,
|
||||
// then if verified add a new lake tile.
|
||||
for (j = 0; j < 64; j++) {
|
||||
// Each tile is in a random location +-3 tiles from the current cursor in either direction
|
||||
s32 offsetX = DungeonRandInt(7) - 3;
|
||||
s32 offsetY = DungeonRandInt(7) - 3;
|
||||
|
||||
// Check that there's enough space for a lake within a 2 tile margin of the map bounds
|
||||
if (offsetX + x < 2 || offsetX + x >= DUNGEON_MAX_SIZE_X - 2 || offsetY + y < 2 || offsetY + y >= DUNGEON_MAX_SIZE_Y - 2)
|
||||
continue;
|
||||
|
||||
// Make secondary terrain here if it's within 2 tiles
|
||||
// of a tile that's currently secondary terrain
|
||||
// This results in a "cluster" akin to a lake
|
||||
if (GetTerrainType(GetTile(offsetX + x + 1, offsetY + y + 1)) == TERRAIN_TYPE_SECONDARY ||
|
||||
GetTerrainType(GetTile(offsetX + x + 1, offsetY + y + 0)) == TERRAIN_TYPE_SECONDARY ||
|
||||
GetTerrainType(GetTile(offsetX + x + 1, offsetY + y - 1)) == TERRAIN_TYPE_SECONDARY ||
|
||||
GetTerrainType(GetTile(offsetX + x + 0, offsetY + y + 1)) == TERRAIN_TYPE_SECONDARY ||
|
||||
GetTerrainType(GetTile(offsetX + x + 0, offsetY + y - 1)) == TERRAIN_TYPE_SECONDARY ||
|
||||
GetTerrainType(GetTile(offsetX + x - 1, offsetY + y + 1)) == TERRAIN_TYPE_SECONDARY ||
|
||||
GetTerrainType(GetTile(offsetX + x - 1, offsetY + y + 0)) == TERRAIN_TYPE_SECONDARY ||
|
||||
GetTerrainType(GetTile(offsetX + x - 1, offsetY + y - 1)) == TERRAIN_TYPE_SECONDARY)
|
||||
{
|
||||
if (!PosIsOutOfBounds(x + offsetX, y + offsetY)) {
|
||||
SetSecondaryTerrainOnWall(GetTileSafe(offsetX + x, offsetY + y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finalization/gap-filling step because the random approach
|
||||
// might leave weird gaps. Go through every tile and do an
|
||||
// on line nearest-neighbor interpolation of secondary terrain
|
||||
// tiles to smoothen out the "lake"
|
||||
for (offsetX = -3; offsetX <= 3; offsetX++) {
|
||||
for (offsetY = -3; offsetY <= 3; offsetY++) {
|
||||
s32 numAdjacent = 0;
|
||||
s32 xPlus1, yPlus1;
|
||||
|
||||
if (offsetX + x < 2 || offsetX + x >= DUNGEON_MAX_SIZE_X - 2 || offsetY + y < 2 || offsetY + y >= DUNGEON_MAX_SIZE_Y - 2)
|
||||
continue;
|
||||
|
||||
// Count the number of secondary terrain tiles adjacent (all 8 directions)
|
||||
xPlus1 = offsetX + x + 1;
|
||||
yPlus1 = offsetY + y + 1;
|
||||
|
||||
if (GetTerrainType(GetTile(xPlus1, yPlus1)) == TERRAIN_TYPE_SECONDARY) numAdjacent++;
|
||||
if (GetTerrainType(GetTile(offsetX + x + 1, offsetY + y + 0)) == TERRAIN_TYPE_SECONDARY) numAdjacent++;
|
||||
if (GetTerrainType(GetTile(offsetX + x + 1, offsetY + y - 1)) == TERRAIN_TYPE_SECONDARY) numAdjacent++;
|
||||
if (GetTerrainType(GetTile(offsetX + x + 0, offsetY + y + 1)) == TERRAIN_TYPE_SECONDARY) numAdjacent++;
|
||||
if (GetTerrainType(GetTile(offsetX + x + 0, offsetY + y - 1)) == TERRAIN_TYPE_SECONDARY) numAdjacent++;
|
||||
if (GetTerrainType(GetTile(offsetX + x - 1, offsetY + y + 1)) == TERRAIN_TYPE_SECONDARY) numAdjacent++;
|
||||
if (GetTerrainType(GetTile(offsetX + x - 1, offsetY + y + 0)) == TERRAIN_TYPE_SECONDARY) numAdjacent++;
|
||||
if (GetTerrainType(GetTile(offsetX + x - 1, offsetY + y - 1)) == TERRAIN_TYPE_SECONDARY) numAdjacent++;
|
||||
|
||||
// If at least half are secondary terrain, make this tile secondary terrain as well
|
||||
if (numAdjacent >= 4 && !PosIsOutOfBounds(x + offsetX , y + offsetY)) {
|
||||
SetSecondaryTerrainOnWall(GetTileSafe(offsetX + x , offsetY + y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Creating a lake doesn't mean we are done yet
|
||||
// but it's likely that the next iteration will hit the tile
|
||||
// stopping condition for secondary terrain, if not the river continues
|
||||
|
||||
// Alternate between horizontal and vertical movement each iteration
|
||||
if (dir_x != 0) {
|
||||
// The y direction never reverses, ensuring the river doesn't
|
||||
// double back on itself and cuts across the map only once
|
||||
if (dir_y_upwards) {
|
||||
dir_y = -1;
|
||||
}
|
||||
else {
|
||||
dir_y = 1;
|
||||
}
|
||||
|
||||
dir_x = 0;
|
||||
}
|
||||
else {
|
||||
//Randomly pick between left and right
|
||||
if (DungeonRandInt(100) < 50) {
|
||||
dir_x = -1;
|
||||
}
|
||||
else {
|
||||
dir_x = 1;
|
||||
}
|
||||
|
||||
dir_y = 0;
|
||||
}
|
||||
|
||||
if (y < 0 || y >= DUNGEON_MAX_SIZE_Y) {
|
||||
LABEL:
|
||||
// Vertically out of bounds, stop
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate standalone lakes secondary_terrain_density # of times
|
||||
for (densityN = 0; densityN < unkPtr->unk15; densityN++) {
|
||||
s32 x, y;
|
||||
bool8 table[10][10];
|
||||
// Try to pick a random tile in the interior to seed the "lake"
|
||||
// Incredibly unlikely to fail
|
||||
s32 rnd_y = 0;
|
||||
s32 rnd_x = 0;
|
||||
s32 n = 0;
|
||||
|
||||
// Up to 200 attempts
|
||||
while (n < 200) {
|
||||
rnd_x = DungeonRandRange(0, DUNGEON_MAX_SIZE_X);
|
||||
rnd_y = DungeonRandRange(0, DUNGEON_MAX_SIZE_Y);
|
||||
|
||||
if (rnd_x >= 1 && rnd_x < DUNGEON_MAX_SIZE_X - 1 && rnd_y >= 1 && rnd_y < DUNGEON_MAX_SIZE_Y - 1)
|
||||
break;
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n == 200)
|
||||
continue;
|
||||
|
||||
// Make a 10x10 grid with TRUE on the boundary and FALSE on the interior
|
||||
for (x = 0; x < 10; x++) {
|
||||
for (y = 0; y < 10; y++) {
|
||||
if (x == 0 || x == 9 || y == 0 || y == 9) {
|
||||
table[x][y] = TRUE;
|
||||
}
|
||||
else {
|
||||
table[x][y] = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate an "inverse lake" by spreading the TRUE values inwards
|
||||
for (n = 0; n < 80; n++) {
|
||||
// Pick a random interior point on the 10x10 grid
|
||||
x = DungeonRandInt(8) + 1;
|
||||
y = DungeonRandInt(8) + 1;
|
||||
|
||||
if (table[x - 1][y] || table[x + 1][y] || table[x][y - 1] || table[x][y + 1]) {
|
||||
table[x][y] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through the grid, any spaces which are still FALSE form the inverse-inverse lake
|
||||
// or as some may prefer to call it, just a regular lake!
|
||||
for (x = 0; x < 10; x++) {
|
||||
for (y = 0; y < 10; y++) {
|
||||
if (!table[x][y]) {
|
||||
// Shift the 0-10 random offset position into +- 5 to center around the lake seed tile
|
||||
SetSecondaryTerrainOnWall(GetTileSafe(x + rnd_x - 5, y + rnd_y - 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up secondary terrain that got in places it shouldn't
|
||||
for (x = 0; x < DUNGEON_MAX_SIZE_X; x++) {
|
||||
for (y = 0; y < DUNGEON_MAX_SIZE_Y; y++) {
|
||||
Tile *tile = GetTileSafe(x, y);
|
||||
if (GetTerrainType(tile) != TERRAIN_TYPE_SECONDARY)
|
||||
continue;
|
||||
|
||||
// Revert tiles back to open terrain if:
|
||||
// - in a kecleon shop
|
||||
// - in a monster house
|
||||
// - is an unbreakable tile
|
||||
// - on a stairs spawn point
|
||||
// This really shouldn't happen since we only place terrain on wall tiles to begin with,
|
||||
// but it provides additional safety
|
||||
|
||||
if (tile->terrainType & (TERRAIN_TYPE_SHOP | TERRAIN_TYPE_IN_MONSTER_HOUSE | TERRAIN_TYPE_UNBREAKABLE) || (tile->spawnOrVisibilityFlags & SPAWN_FLAG_STAIRS)) {
|
||||
SetTerrainNormal(tile);
|
||||
}
|
||||
else {
|
||||
// Revert to wall tiles if they're on the soft/hard borders
|
||||
if (x <= 1 || x >= DUNGEON_MAX_SIZE_X - 1 || y <= 1 || y >= DUNGEON_MAX_SIZE_Y - 1) {
|
||||
SetTerrainWall(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -2749,7 +2749,7 @@ _0805AA5E:
|
||||
sub_807EC28(FALSE);
|
||||
}
|
||||
sub_806A5B8(target);
|
||||
sub_8075900(target,gDungeon->unk3A08);
|
||||
sub_8075900(target,gDungeon->forceMonsterHouse);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
@ -483,7 +483,7 @@ void sub_8081454(unkStruct_8094924 *param_1)
|
||||
int iVar4;
|
||||
|
||||
sub_808300C(param_1,gMisakiSan);
|
||||
sub_80830B4(param_1, gDungeon->unk3A08);
|
||||
sub_80830B4(param_1, gDungeon->forceMonsterHouse);
|
||||
sub_80830B4(param_1, gDungeon->unk3A09);
|
||||
sub_80830B4(param_1, gDungeon->unk3A0A);
|
||||
sub_80830B4(param_1, gDungeon->unk3A0B);
|
||||
@ -820,7 +820,7 @@ void sub_8081C7C(unkStruct_8094924 *r0)
|
||||
s32 iVar7;
|
||||
|
||||
sub_8083018(r0,gMisakiSan);
|
||||
gDungeon->unk3A08 = sub_80831DC(r0);
|
||||
gDungeon->forceMonsterHouse = sub_80831DC(r0);
|
||||
gDungeon->unk3A09 = sub_80831DC(r0);
|
||||
gDungeon->unk3A0A = sub_80831DC(r0);
|
||||
gDungeon->unk3A0B = sub_80831DC(r0);
|
||||
|
Loading…
Reference in New Issue
Block a user