mirror of
https://github.com/pret/pmd-sky.git
synced 2026-08-22 10:34:44 -05:00
Decomped GenerateSecondaryTerrainFormations
Decomped by @DizzyEggg
This commit is contained in:
@@ -1,82 +1,16 @@
|
||||
#pragma once
|
||||
.public DUNGEON_PTR
|
||||
.public DetermineAllTilesWalkableNeighbors
|
||||
.public DungeonRand16Bit
|
||||
.public DungeonRandInt
|
||||
.public DungeonRandRange
|
||||
.public DungeonRngSetPrimary
|
||||
.public DungeonRngSetSecondary
|
||||
.public FIRST_DUNGEON_WITH_MONSTER_HOUSE_TRAPS
|
||||
.public FIXED_ROOM_DATA_PTR
|
||||
.public FIXED_ROOM_ENTITY_SPAWN_TABLE
|
||||
.public FIXED_ROOM_MONSTER_SPAWN_STATS_TABLE
|
||||
.public FLOOR_GENERATION_STATUS
|
||||
.public GenerateAndSpawnItem
|
||||
.public GetExplorerMazeMonster
|
||||
.public GetFloorType
|
||||
.public GetMatchingMonsterId
|
||||
.public GetMonsterIdFromSpawnEntry
|
||||
.public GetMonsterLevelToSpawn
|
||||
.public GetOutlawLeaderLevel
|
||||
.public GetOutlawLevel
|
||||
.public GetOutlawMinionLevel
|
||||
.public GetPerformanceFlagWithChecks
|
||||
.public GetSpecialTargetItem
|
||||
.public GetTile
|
||||
.public GetTileSafe
|
||||
.public HIDDEN_STAIRS_SPAWN_BLOCKED
|
||||
.public HIDDEN_STAIRS_SPAWN_CHANCE_MULTIPLIER
|
||||
.public HandleSir0Translation
|
||||
.public InitOtherMonsterData
|
||||
.public InitializeTile
|
||||
.public IsCurrentMissionType
|
||||
.public IsDestinationFloor
|
||||
.public IsFullFloorFixedRoom
|
||||
.public IsGoldenChamber
|
||||
.public IsSecretRoom
|
||||
.public IsTreasureBox
|
||||
.public KECLEON_SHOP_BOOST_CHANCE_MULTIPLIER
|
||||
.public LoadFileFromRom
|
||||
.public LogMessageByIdWithPopupCheckUser
|
||||
.public MONSTER_HOUSE_MAX_MONSTER_SPAWNS
|
||||
.public MONSTER_HOUSE_MAX_NON_MONSTER_SPAWNS
|
||||
.public MemAlloc
|
||||
.public MemFree
|
||||
.public MemZero
|
||||
.public MultiplyByFixedPoint
|
||||
.public PointsToZero
|
||||
.public PosIsOutOfBounds
|
||||
.public SHOP_ITEM_CHANCES
|
||||
.public SetMonsterLevelAndId
|
||||
.public SetShouldBoostHiddenStairsSpawnChance
|
||||
.public SetShouldBoostKecleonShopSpawnChance
|
||||
.public ShouldBoostHiddenStairsSpawnChance
|
||||
.public ShouldBoostKecleonShopSpawnChance
|
||||
.public SpawnEnemyTrapAtPos
|
||||
.public SpawnMonster
|
||||
.public TREASURE_BOX_1_ITEM_IDS
|
||||
.public UnloadFile
|
||||
.public UpdateMinimap
|
||||
.public UpdateTrapsVisibility
|
||||
.public ZInit8
|
||||
.public SpawnStairs
|
||||
.public _s32_div_f
|
||||
.public abs
|
||||
.public ov10_022C4B34
|
||||
.public ov10_022C6C75
|
||||
.public ov10_022C6C77
|
||||
.public ov10_022C6C78
|
||||
.public ov10_022C6C79
|
||||
.public ov29_022E6694
|
||||
.public ov29_022E7BD0
|
||||
.public ov29_022EA370
|
||||
.public ov29_023365E8
|
||||
.public ov29_02336694
|
||||
.public ov29_023442B8
|
||||
.public ov29_02348BE8
|
||||
.public ov29_023502F0
|
||||
.public ov29_023502F4
|
||||
.public ov29_02353030
|
||||
.public ov29_02353050
|
||||
.public ov29_02353110
|
||||
.public ov29_023534F0
|
||||
.public ov29_0237CFC0
|
||||
|
||||
75
asm/include/overlay_29_02341E6C.inc
Normal file
75
asm/include/overlay_29_02341E6C.inc
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
.public DUNGEON_PTR
|
||||
.public DetermineAllTilesWalkableNeighbors
|
||||
.public DungeonRand16Bit
|
||||
.public DungeonRandInt
|
||||
.public DungeonRandRange
|
||||
.public DungeonRngSetPrimary
|
||||
.public DungeonRngSetSecondary
|
||||
.public FIXED_ROOM_DATA_PTR
|
||||
.public FIXED_ROOM_ENTITY_SPAWN_TABLE
|
||||
.public FIXED_ROOM_MONSTER_SPAWN_STATS_TABLE
|
||||
.public FLOOR_GENERATION_STATUS
|
||||
.public GenerateAndSpawnItem
|
||||
.public GetExplorerMazeMonster
|
||||
.public GetFloorType
|
||||
.public GetMatchingMonsterId
|
||||
.public GetMonsterIdFromSpawnEntry
|
||||
.public GetMonsterLevelToSpawn
|
||||
.public GetOutlawLeaderLevel
|
||||
.public GetOutlawLevel
|
||||
.public GetOutlawMinionLevel
|
||||
.public GetPerformanceFlagWithChecks
|
||||
.public GetSpecialTargetItem
|
||||
.public GetTileSafe
|
||||
.public HIDDEN_STAIRS_SPAWN_BLOCKED
|
||||
.public HIDDEN_STAIRS_SPAWN_CHANCE_MULTIPLIER
|
||||
.public HandleSir0Translation
|
||||
.public InitOtherMonsterData
|
||||
.public InitializeTile
|
||||
.public IsCurrentMissionType
|
||||
.public IsDestinationFloor
|
||||
.public IsFullFloorFixedRoom
|
||||
.public IsGoldenChamber
|
||||
.public IsSecretRoom
|
||||
.public IsTreasureBox
|
||||
.public KECLEON_SHOP_BOOST_CHANCE_MULTIPLIER
|
||||
.public LoadFileFromRom
|
||||
.public LogMessageByIdWithPopupCheckUser
|
||||
.public MemAlloc
|
||||
.public MemFree
|
||||
.public MemZero
|
||||
.public MultiplyByFixedPoint
|
||||
.public PointsToZero
|
||||
.public SHOP_ITEM_CHANCES
|
||||
.public SetMonsterLevelAndId
|
||||
.public SetShouldBoostHiddenStairsSpawnChance
|
||||
.public SetShouldBoostKecleonShopSpawnChance
|
||||
.public ShouldBoostHiddenStairsSpawnChance
|
||||
.public ShouldBoostKecleonShopSpawnChance
|
||||
.public SpawnEnemyTrapAtPos
|
||||
.public SpawnMonster
|
||||
.public TREASURE_BOX_1_ITEM_IDS
|
||||
.public UnloadFile
|
||||
.public UpdateMinimap
|
||||
.public UpdateTrapsVisibility
|
||||
.public ZInit8
|
||||
.public _s32_div_f
|
||||
.public ov10_022C4B34
|
||||
.public ov10_022C6C75
|
||||
.public ov10_022C6C77
|
||||
.public ov10_022C6C78
|
||||
.public ov10_022C6C79
|
||||
.public ov29_022E6694
|
||||
.public ov29_022E7BD0
|
||||
.public ov29_022EA370
|
||||
.public ov29_023365E8
|
||||
.public ov29_02336694
|
||||
.public ov29_023442B8
|
||||
.public ov29_02348BE8
|
||||
.public ov29_023502F0
|
||||
.public ov29_023502F4
|
||||
.public ov29_02353050
|
||||
.public ov29_02353110
|
||||
.public ov29_023534F0
|
||||
.public ov29_0237CFC0
|
||||
File diff suppressed because it is too large
Load Diff
2645
asm/overlay_29_02341E6C.s
Normal file
2645
asm/overlay_29_02341E6C.s
Normal file
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,8 @@ enum terrain_type
|
||||
TERRAIN_TYPE_NATURAL_JUNCTION = 1 << 3, // x8
|
||||
TERRAIN_TYPE_IMPASSABLE_WALL = 1 << 4, // x10
|
||||
TERRAIN_TYPE_SHOP = 1 << 5, // x20
|
||||
TERRAIN_TYPE_IN_MONSTER_HOUSE = 1 << 6, // x40
|
||||
TERRAIN_TYPE_UNBREAKABLE = 1 << 8, // x100 // Cannot be broken by Absolute Mover. Set naturally on key doors.
|
||||
TERRAIN_TYPE_STAIRS = 1 << 9, // x200
|
||||
};
|
||||
|
||||
|
||||
8
include/dungeon_generation.h
Normal file
8
include/dungeon_generation.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef PMDSKY_DUNGEON_GENERATION_H
|
||||
#define PMDSKY_DUNGEON_GENERATION_H
|
||||
|
||||
#include "dungeon_mode.h"
|
||||
|
||||
void GenerateSecondaryTerrainFormations(bool8 test_flag, struct floor_properties *floor_props);
|
||||
|
||||
#endif //PMDSKY_DUNGEON_GENERATION_H
|
||||
@@ -871,10 +871,11 @@ struct floor_properties {
|
||||
// 0xC: Maximum number of secondary structures that can be generated on the floor
|
||||
u8 max_secondary_structures;
|
||||
// 0xD: room_flags: 1-byte bitfield
|
||||
bool8 f_secondary_structures : 1; // Whether secondary structures are allowed
|
||||
u8 room_flags_unk1 : 1;
|
||||
bool8 f_room_imperfections : 1; // Whether room imperfections are allowed
|
||||
u8 room_flags_unk3 : 5;
|
||||
u8 room_flags;
|
||||
// bool8 f_secondary_structures : 1; // Whether secondary structures are allowed
|
||||
// u8 room_flags_unk1 : 1;
|
||||
// bool8 f_room_imperfections : 1; // Whether room imperfections are allowed
|
||||
// u8 room_flags_unk3 : 5;
|
||||
|
||||
u8 field_0xe;
|
||||
u8 item_density; // 0xF: Controls how many items will be spawned
|
||||
@@ -1034,30 +1035,34 @@ struct display_data {
|
||||
u8 field_0x47;
|
||||
};
|
||||
|
||||
// Used during floor generation to keep track of what entities should be spawned where
|
||||
struct spawn_flags {
|
||||
bool8 f_stairs : 1;
|
||||
bool8 f_item : 1;
|
||||
bool8 f_trap : 1;
|
||||
bool8 f_monster : 1;
|
||||
u8 spawn_flags_unk4 : 4;
|
||||
u8 spawn_flags_unk8 : 8;
|
||||
};
|
||||
|
||||
// Used during dungeon play to record the visibility of a tile.
|
||||
struct visibility_flags {
|
||||
// If f_revealed == true and f_visited == false, the tile will appear as gray on the map.
|
||||
// This happens, e.g., when a Luminous Orb is used.
|
||||
bool8 f_revealed : 1; // Revealed on the map.
|
||||
bool8 f_visited : 1; // Visited by the player
|
||||
u8 visibility_flags_unk2 : 6;
|
||||
u8 visibility_flags_unk8 : 8;
|
||||
enum spawn_flags
|
||||
{
|
||||
SPAWN_FLAG_STAIRS = 1 << 0, // x1 - This tile has the stairs.
|
||||
SPAWN_FLAG_ITEM = 1 << 1, // x2 - This tile has an item on it.
|
||||
SPAWN_FLAG_TRAP = 1 << 2, // x4 - This tile has a trap on it.
|
||||
SPAWN_FLAG_MONSTER = 1 << 3, // x8 - This tile has a monster on it.
|
||||
SPAWN_FLAG_SPECIAL_TILE = 1 << 4, // x10 - This is a special tile, such as for Kecleon Shops, items, and traps.
|
||||
SPAWN_FLAG_UNK5 = 1 << 5, // 0x20 - Not fully understood field relating to Secondary Structures. Set to true for all tiles in secondary structure rooms except for Cross or Dot rooms.
|
||||
SPAWN_FLAG_UNK6 = 1 << 6, // 0x40 - Not fully understood field. In the dungeon algorithm, it is set to true on a Warp tile.
|
||||
SPAWN_FLAG_UNK7 = 1 << 7, // 0x80 - Not fully understood field. In the dungeon algorithm, it is set to true for all tiles in a Divider secondary structure room.
|
||||
};
|
||||
|
||||
// These flags seem to occupy the same memory location, so the meaning is context-dependent.
|
||||
union spawn_or_visibility_flags {
|
||||
struct spawn_flags spawn;
|
||||
struct visibility_flags visibility;
|
||||
u16 spawn;
|
||||
// bool8 f_stairs : 1;
|
||||
// bool8 f_item : 1;
|
||||
// bool8 f_trap : 1;
|
||||
// bool8 f_monster : 1;
|
||||
// u8 spawn_flags_unk4 : 4;
|
||||
// u8 spawn_flags_unk8 : 8;
|
||||
u16 visibility;
|
||||
// If f_revealed == true and f_visited == false, the tile will appear as gray on the map.
|
||||
// This happens, e.g., when a Luminous Orb is used.
|
||||
// bool8 f_revealed : 1; // Revealed on the map.
|
||||
// bool8 f_visited : 1; // Visited by the player
|
||||
// u8 visibility_flags_unk2 : 6;
|
||||
// u8 visibility_flags_unk8 : 8;
|
||||
};
|
||||
|
||||
// Information about the rooms on the current floor
|
||||
|
||||
@@ -48,4 +48,6 @@ static inline s32 Max(s32 a, s32 b)
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
#define ARRAY_COUNT(array) (sizeof(array) / sizeof((array)[0]))
|
||||
|
||||
#endif //PMDSKY_UTIL_H
|
||||
|
||||
2
main.lsf
2
main.lsf
@@ -531,6 +531,8 @@ Overlay OVY_29
|
||||
Object asm/overlay_29_0233861C.o
|
||||
Object src/overlay_29_02340CAC.o
|
||||
Object asm/overlay_29_02340CE4.o
|
||||
Object src/dungeon_generation.o
|
||||
Object asm/overlay_29_02341E6C.o
|
||||
Object src/fixed_room_data.o
|
||||
Object asm/overlay_29_02344178.o
|
||||
Object src/overlay_29_02344AF8.o
|
||||
|
||||
291
src/dungeon_generation.c
Normal file
291
src/dungeon_generation.c
Normal file
@@ -0,0 +1,291 @@
|
||||
#include "dungeon_generation.h"
|
||||
#include "dg_random.h"
|
||||
#include "dungeon_map_access.h"
|
||||
#include "dungeon_util_static.h"
|
||||
#include "overlay_29_02340CAC.h"
|
||||
|
||||
extern const s32 ov29_02353030[8];
|
||||
|
||||
extern void SetSecondaryTerrainOnWall(struct tile *tile);
|
||||
|
||||
// Helper functions for terrain flags
|
||||
static inline void SetTerrainFlags(struct tile *tile, u32 terrain_flags)
|
||||
{
|
||||
tile->terrain_flags &= ~(TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY);
|
||||
tile->terrain_flags |= terrain_flags;
|
||||
}
|
||||
|
||||
static inline void SetTerrainNormal(struct tile *tile)
|
||||
{
|
||||
SetTerrainFlags(tile, TERRAIN_TYPE_NORMAL);
|
||||
}
|
||||
|
||||
static inline void SetTerrainWall(struct tile *tile)
|
||||
{
|
||||
SetTerrainFlags(tile, TERRAIN_TYPE_WALL);
|
||||
}
|
||||
|
||||
void GenerateSecondaryTerrainFormations(bool8 test_flag, struct floor_properties *floor_props)
|
||||
{
|
||||
s32 numToGen;
|
||||
s32 num_tiles_fill;
|
||||
s32 densityN;
|
||||
s32 x, y;
|
||||
|
||||
if (!(floor_props->room_flags & test_flag))
|
||||
return;
|
||||
|
||||
// Generate 1-3 "river+lake" formations
|
||||
numToGen = ov29_02353030[DungeonRandInt(ARRAY_COUNT(ov29_02353030))];
|
||||
for (;numToGen != 0; numToGen--) {
|
||||
// Randomly pick between starting from the bottom going up, or from the top going down
|
||||
s32 offsetX, offsetY;
|
||||
s32 dir_x, dir_y;
|
||||
bool8 dir_y_upwards;
|
||||
s32 steps_until_lake;
|
||||
s32 j;
|
||||
|
||||
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;
|
||||
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 )
|
||||
continue;
|
||||
if (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)
|
||||
{
|
||||
s32 xx = x;
|
||||
s32 yy = y;
|
||||
xx += offsetX;
|
||||
yy += offsetY;
|
||||
if (!PosIsOutOfBounds(xx, yy)) {
|
||||
SetSecondaryTerrainOnWall(GetTileSafe(x + offsetX , y + offsetY));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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)
|
||||
|
||||
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 (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) {
|
||||
s32 yy = y;
|
||||
yy += offsetY;
|
||||
if (!PosIsOutOfBounds(x + offsetX, yy))
|
||||
SetSecondaryTerrainOnWall(GetTileSafe(x + offsetX , y + offsetY));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 < floor_props->secondary_terrain_density; densityN++) {
|
||||
s32 x, y;
|
||||
bool8 table[10][10];
|
||||
s32 rnd_x, rnd_y;
|
||||
s32 n;
|
||||
|
||||
// Try to pick a random tile in the interior to seed the "lake"
|
||||
// Incredibly unlikely to fail
|
||||
|
||||
rnd_y = 0;
|
||||
rnd_x = 0;
|
||||
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++) {
|
||||
struct 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->terrain_flags & (TERRAIN_TYPE_SHOP | TERRAIN_TYPE_IN_MONSTER_HOUSE | TERRAIN_TYPE_UNBREAKABLE) || (tile->spawn_or_visibility_flags.spawn & 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user