diff --git a/asm/code_804AFAC.s b/asm/code_804AFAC.s index a6c499ff7..0dad9dcae 100644 --- a/asm/code_804AFAC.s +++ b/asm/code_804AFAC.s @@ -6,387 +6,6 @@ .text - thumb_func_start GetGridPositions -GetGridPositions: - push {r4-r7,lr} - mov r7, r8 - push {r7} - adds r7, r0, 0 - mov r8, r1 - adds r5, r2, 0 - adds r6, r3, 0 - movs r4, 0 - cmp r4, r5 - bge _0804D04E - movs r0, 0x38 - adds r1, r5, 0 - bl __divsi3 - adds r2, r7, 0 - adds r1, r5, 0 -_0804D044: - stm r2!, {r4} - adds r4, r0 - subs r1, 0x1 - cmp r1, 0 - bne _0804D044 -_0804D04E: - lsls r0, r5, 2 - adds r0, r7 - str r4, [r0] - movs r4, 0 - lsls r5, r6, 2 - cmp r4, r6 - bge _0804D072 - movs r0, 0x20 - adds r1, r6, 0 - bl __divsi3 - mov r2, r8 - adds r1, r6, 0 -_0804D068: - stm r2!, {r4} - adds r4, r0 - subs r1, 0x1 - cmp r1, 0 - bne _0804D068 -_0804D072: - mov r1, r8 - adds r0, r5, r1 - str r4, [r0] - pop {r3} - mov r8, r3 - pop {r4-r7} - pop {r0} - bx r0 - thumb_func_end GetGridPositions - - thumb_func_start InitDungeonGrid -InitDungeonGrid: - push {r4-r7,lr} - mov r7, r10 - mov r6, r9 - mov r5, r8 - push {r5-r7} - sub sp, 0x8 - mov r8, r0 - adds r5, r1, 0 - mov r9, r2 - movs r2, 0 - cmp r2, r5 - bge _0804D144 - lsrs r0, r5, 31 - adds r0, r5, r0 - asrs r0, 1 - str r0, [sp] - movs r3, 0 -_0804D0A6: - adds r0, r2, 0x1 - mov r10, r0 - mov r4, r9 - cmp r4, 0 - ble _0804D13E - ldr r6, _0804D0D8 - ldrb r6, [r6] - str r6, [sp, 0x4] - lsls r0, r2, 4 - subs r0, r2 - lsls r0, 5 - mov r4, r8 - adds r1, r0, r4 - movs r7, 0 - movs r6, 0x1 - mov r12, r6 - mov r4, r9 -_0804D0C8: - ldr r0, [sp, 0x4] - cmp r0, 0x1 - bne _0804D0DC - ldr r6, [sp] - cmp r2, r6 - blt _0804D0DC - strb r0, [r1, 0x8] - b _0804D102 - .align 2, 0 -_0804D0D8: .4byte gUnknown_202F1AE -_0804D0DC: - ldr r6, _0804D0FC - ldrb r0, [r6] - cmp r0, 0x2 - bne _0804D100 - lsls r0, r5, 1 - adds r0, r5 - cmp r0, 0 - bge _0804D0EE - adds r0, 0x3 -_0804D0EE: - asrs r0, 2 - cmp r2, r0 - blt _0804D100 - mov r0, r12 - strb r0, [r1, 0x8] - b _0804D102 - .align 2, 0 -_0804D0FC: .4byte gUnknown_202F1AE -_0804D100: - strb r3, [r1, 0x8] -_0804D102: - lsls r0, r2, 4 - subs r0, r2 - lsls r0, 5 - add r0, r8 - adds r0, r7, r0 - mov r6, r12 - strb r6, [r0, 0xA] - strb r3, [r0, 0xB] - strb r3, [r0, 0xF] - strb r3, [r0, 0xE] - strb r3, [r0, 0xC] - strb r3, [r0, 0x16] - strb r3, [r0, 0x15] - strb r3, [r0, 0x14] - strb r3, [r0, 0x13] - strb r3, [r0, 0x1A] - strb r3, [r0, 0x19] - strb r3, [r0, 0x18] - strb r3, [r0, 0x17] - strb r3, [r0, 0x9] - strb r3, [r0, 0x11] - strb r3, [r0, 0x10] - strb r3, [r0, 0x12] - strb r3, [r0, 0x1C] - strb r3, [r0, 0x1D] - adds r1, 0x20 - adds r7, 0x20 - subs r4, 0x1 - cmp r4, 0 - bne _0804D0C8 -_0804D13E: - mov r2, r10 - cmp r2, r5 - blt _0804D0A6 -_0804D144: - add sp, 0x8 - pop {r3-r5} - mov r8, r3 - mov r9, r4 - mov r10, r5 - pop {r4-r7} - pop {r0} - bx r0 - thumb_func_end InitDungeonGrid - - thumb_func_start AssignRooms -AssignRooms: - push {r4-r7,lr} - mov r7, r10 - mov r6, r9 - mov r5, r8 - push {r5-r7} - sub sp, 0x114 - str r0, [sp, 0x100] - mov r9, r1 - mov r8, r2 - adds r4, r3, 0 - movs r0, 0x3 - bl DungeonRandInt - adds r3, r0, 0 - cmp r4, 0 - bge _0804D17E - negs r4, r4 - b _0804D180 -_0804D178: - movs r0, 0x1 - strb r0, [r4, 0xA] - b _0804D2B6 -_0804D17E: - adds r4, r3 -_0804D180: - movs r3, 0 - mov r0, r8 - mov r2, r9 - muls r2, r0 - cmp r3, r4 - bge _0804D19A - movs r1, 0x1 -_0804D18E: - mov r5, sp - adds r0, r5, r3 - strb r1, [r0] - adds r3, 0x1 - cmp r3, r4 - blt _0804D18E -_0804D19A: - cmp r3, 0xFF - bgt _0804D1AC - movs r1, 0 -_0804D1A0: - mov r6, sp - adds r0, r6, r3 - strb r1, [r0] - adds r3, 0x1 - cmp r3, 0xFF - ble _0804D1A0 -_0804D1AC: - adds r5, r2, 0 - movs r6, 0x3F -_0804D1B0: - adds r0, r5, 0 - bl DungeonRandInt - adds r4, r0, 0 - adds r0, r5, 0 - bl DungeonRandInt - mov r1, sp - adds r2, r1, r4 - ldrb r3, [r2] - adds r1, r0 - ldrb r0, [r1] - strb r0, [r2] - strb r3, [r1] - subs r6, 0x1 - cmp r6, 0 - bge _0804D1B0 - movs r3, 0 - ldr r0, _0804D24C - str r3, [r0] - movs r7, 0 - mov r12, r0 - cmp r7, r9 - bge _0804D262 -_0804D1E0: - movs r5, 0 - adds r4, r7, 0x1 - str r4, [sp, 0x104] - cmp r5, r8 - bge _0804D25C - lsls r2, r7, 4 - subs r2, r7 - lsls r2, 5 - ldr r6, [sp, 0x100] - adds r0, r2, r6 - mov r1, r9 - movs r4, 0x1 - ands r1, r4 - str r1, [sp, 0x110] - mov r1, r9 - subs r1, 0x1 - adds r0, 0x20 - mov r10, r0 - adds r0, r6, 0 - adds r0, 0x8 - adds r2, r0 - lsrs r0, r1, 31 - adds r1, r0 - asrs r1, 1 -_0804D210: - ldrb r4, [r2] - cmp r4, 0 - bne _0804D254 - mov r6, r12 - ldr r0, [r6] - cmp r0, 0x1F - ble _0804D220 - strb r4, [r2, 0x2] -_0804D220: - mov r6, sp - adds r0, r6, r3 - ldrb r0, [r0] - cmp r0, 0 - beq _0804D250 - movs r0, 0x1 - strb r0, [r2, 0x2] - mov r6, r12 - ldr r0, [r6] - adds r0, 0x1 - str r0, [r6] - ldr r0, [sp, 0x110] - cmp r0, 0 - beq _0804D252 - cmp r7, r1 - bne _0804D252 - cmp r5, 0x1 - bne _0804D252 - mov r6, r10 - strb r4, [r6, 0xA] - b _0804D252 - .align 2, 0 -_0804D24C: .4byte gUnknown_202F1CC -_0804D250: - strb r0, [r2, 0x2] -_0804D252: - adds r3, 0x1 -_0804D254: - adds r2, 0x20 - adds r5, 0x1 - cmp r5, r8 - blt _0804D210 -_0804D25C: - ldr r7, [sp, 0x104] - cmp r7, r9 - blt _0804D1E0 -_0804D262: - mov r1, r12 - ldr r0, [r1] - cmp r0, 0x1 - bgt _0804D2BC - movs r1, 0 - movs r2, 0 -_0804D26E: - movs r7, 0 - cmp r2, r9 - bge _0804D2AC - movs r6, 0 -_0804D276: - movs r5, 0 - cmp r5, r8 - bge _0804D2A4 - lsls r0, r6, 5 - ldr r3, [sp, 0x100] - adds r4, r0, r3 -_0804D282: - ldrb r0, [r4, 0x8] - cmp r0, 0 - bne _0804D29C - movs r0, 0x64 - str r1, [sp, 0x108] - str r2, [sp, 0x10C] - bl DungeonRandInt - ldr r1, [sp, 0x108] - ldr r2, [sp, 0x10C] - cmp r0, 0x3B - bgt _0804D29C - b _0804D178 -_0804D29C: - adds r4, 0x20 - adds r5, 0x1 - cmp r5, r8 - blt _0804D282 -_0804D2A4: - adds r6, 0xF - adds r7, 0x1 - cmp r7, r9 - blt _0804D276 -_0804D2AC: - cmp r2, 0 - bne _0804D2B6 - adds r1, 0x1 - cmp r1, 0xC7 - ble _0804D26E -_0804D2B6: - ldr r1, _0804D2CC - movs r0, 0 - strb r0, [r1] -_0804D2BC: - add sp, 0x114 - pop {r3-r5} - mov r8, r3 - mov r9, r4 - mov r10, r5 - pop {r4-r7} - pop {r0} - bx r0 - .align 2, 0 -_0804D2CC: .4byte gUnknown_202F1AD - thumb_func_end AssignRooms - thumb_func_start CreateRoomsAndAnchors CreateRoomsAndAnchors: push {r4-r7,lr} diff --git a/include/global.h b/include/global.h index 42de541c6..c9f7791a2 100644 --- a/include/global.h +++ b/include/global.h @@ -39,6 +39,13 @@ #define ARRAY_COUNT(array) (sizeof(array) / sizeof((array)[0])) +#define SWAP(a, b, temp) \ +{ \ + temp = a; \ + a = b; \ + b = temp; \ +} + #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) diff --git a/src/code_804AFAC_1.c b/src/code_804AFAC_1.c index 1c62d8ebf..993c7d5ab 100644 --- a/src/code_804AFAC_1.c +++ b/src/code_804AFAC_1.c @@ -22,6 +22,7 @@ extern s16 gUnknown_202F1B0; extern s16 gUnknown_202F1B2; extern s32 gUnknown_202F1C8; extern s32 gUnknown_202F1D0; +extern s32 gUnknown_202F1CC; extern Position gUnknown_202F1D8; struct UnkStruct_202F1B8 @@ -69,6 +70,17 @@ struct FileFixedmapPosStruct u8 y; }; +static inline void SetTerrainNormal(Tile *tile) +{ + tile->terrainType &= ~(TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY); + tile->terrainType |= TERRAIN_TYPE_NORMAL; +} + +static inline u32 GetTerrain(Tile *tile) +{ + return tile->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY); +} + // Some weird-ass regswap prevents the function from being matched - https://decomp.me/scratch/9SUV3 #ifdef NONMATCHING void sub_804AFAC(void) @@ -258,7 +270,7 @@ void sub_804AFAC(void) if (r10) { sub_80506F0(1, unkPtr); } - r4 = (DungeonRandInt(100) < unkPtr->unk19); + r4 = (DungeonRandInt(100) < unkPtr->connectedToTop); sub_804FF08(unkPtr, r4); sub_8050438(unkPtr, r4); sub_804FBE8(); @@ -960,15 +972,15 @@ void sub_804B534(s32 xStart, s32 yStart, s32 maxX, s32 maxY) Tile *tile = GetTileSafe(x, y); tile->terrainType &= ~(TERRAIN_TYPE_UNK_2); - if (tile->room == CORRIDOR_ROOM && ((tile->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL)) { - if (x > 0 && ((GetTile(x - 1, y)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL)) + if (tile->room == CORRIDOR_ROOM && (GetTerrain(tile) == TERRAIN_TYPE_NORMAL)) { + if (x > 0 && (GetTerrain(GetTile(x - 1, y)) == TERRAIN_TYPE_NORMAL)) unkCount++; - if (y > 0 && ((GetTile(x, y - 1)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL)) + if (y > 0 && (GetTerrain(GetTile(x, y - 1)) == TERRAIN_TYPE_NORMAL)) unkCount++; - if (x < DUNGEON_MAX_SIZE_X - 2 && ((GetTile(x + 1, y)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL)) + if (x < DUNGEON_MAX_SIZE_X - 2 && (GetTerrain(GetTile(x + 1, y)) == TERRAIN_TYPE_NORMAL)) unkCount++; // BUG: It should check for y and not x. Not sure if it has any effect, because this function is called only once with maxY equal to DUNGEON_MAX_SIZE_Y - if (x < DUNGEON_MAX_SIZE_Y - 2 && ((GetTile(x, y + 1)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL)) + if (x < DUNGEON_MAX_SIZE_Y - 2 && (GetTerrain(GetTile(x, y + 1)) == TERRAIN_TYPE_NORMAL)) unkCount++; if (unkCount > 2) { @@ -983,30 +995,30 @@ struct GridCell { Position start; Position end; - u8 unk8; - u8 unk9; - u8 unk10; - u8 unk11; - u8 unk12; - u8 unk13; - u8 unk14; - u8 unk15; - u8 unk16; - u8 unk17; - u8 unk18; - u8 unk19; - u8 unk20; - u8 unk21; - u8 unk22; - u8 unk23; - u8 unk24; - u8 unk25; - u8 unk26; - u8 unk27; - u8 unk28; - u8 unk29; - u8 unk30; - u8 unk31; + bool8 isInvalid; + bool8 unk9; + bool8 isRoom; + bool8 isConnected; + bool8 unk12; + bool8 unk13; + bool8 unk14; + bool8 unk15; + bool8 isMazeRoom; + bool8 hasBeenMerged; + bool8 isMerged; + bool8 connectedToTop; + bool8 connectedToBottom; + bool8 connectedToLeft; + bool8 connectedToRight; + bool8 unk23; + bool8 unk24; + bool8 unk25; + bool8 unk26; + bool8 unk27; + bool8 unk28; + bool8 unk29; + bool8 unk30; + bool8 unk31; }; #define GRID_CELL_LEN 15 @@ -2315,26 +2327,26 @@ void GenerateCrossFloor(UnkDungeonGlobal_unk1C574 *unkPtr) // Set all cells as rooms for (x = 0; x < sizeX; x++) { for (y = 0; y < sizeY; y++) { - grid[x][y].unk10 = TRUE; + grid[x][y].isRoom = TRUE; } } // Invalidate the corners - grid[0][0].unk8 = TRUE; - grid[2][0].unk8 = TRUE; - grid[0][2].unk8 = TRUE; - grid[2][2].unk8 = TRUE; + grid[0][0].isInvalid = TRUE; + grid[2][0].isInvalid = TRUE; + grid[0][2].isInvalid = TRUE; + grid[2][2].isInvalid = TRUE; CreateRoomsAndAnchors(grid, sizeX, sizeY, listX, listY, unkPtr->unkD); - grid[0][1].unk22 = TRUE; - grid[1][1].unk21 = TRUE; - grid[1][1].unk22 = TRUE; - grid[2][1].unk21 = TRUE; - grid[1][0].unk20 = TRUE; - grid[1][1].unk19 = TRUE; - grid[1][1].unk20 = TRUE; - grid[1][2].unk19 = TRUE; + grid[0][1].connectedToRight = TRUE; + grid[1][1].connectedToLeft = TRUE; + grid[1][1].connectedToRight = TRUE; + grid[2][1].connectedToLeft = TRUE; + grid[1][0].connectedToBottom = TRUE; + grid[1][1].connectedToTop = TRUE; + grid[1][1].connectedToBottom = TRUE; + grid[1][2].connectedToTop = TRUE; CreateGridCellConnections(grid, sizeX, sizeY, listX, listY, TRUE); EnsureConnectedGrid(grid, sizeX, sizeY, listX, listY); @@ -2370,7 +2382,7 @@ void GenerateBeetleFloor(UnkDungeonGlobal_unk1C574 *unkPtr) // Set all cells as rooms for (x = 0; x < sizeX; x++) { for (y = 0; y < sizeY; y++) { - grid[x][y].unk10 = TRUE; + grid[x][y].isRoom = TRUE; } } @@ -2378,10 +2390,10 @@ void GenerateBeetleFloor(UnkDungeonGlobal_unk1C574 *unkPtr) // Connect rooms in the same row together for (y = 0; y < 3; y++) { - grid[0][y].unk22 = TRUE; - grid[1][y].unk21 = TRUE; - grid[1][y].unk22 = TRUE; - grid[2][y].unk21 = TRUE; + grid[0][y].connectedToRight = TRUE; + grid[1][y].connectedToLeft = TRUE; + grid[1][y].connectedToRight = TRUE; + grid[2][y].connectedToLeft = TRUE; } CreateGridCellConnections(grid, sizeX, sizeY, listX, listY, TRUE); @@ -2413,8 +2425,7 @@ static void MergeRoomsVertically(s32 roomX, s32 room_y1, s32 room_dy, struct Gri for (x = xStart; x < xEnd; x++) { for (y = yStart; y < yEnd; y++) { Tile *tile = GetTileSafe(x, y); - tile->terrainType &= ~(TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY); - tile->terrainType |= TERRAIN_TYPE_NORMAL; + SetTerrainNormal(tile); tile->room = roomId; } } @@ -2423,10 +2434,11 @@ static void MergeRoomsVertically(s32 roomX, s32 room_y1, s32 room_dy, struct Gri grid[roomX][room_y1].end.x = xEnd; grid[roomX][room_y1].start.y = yStart; grid[roomX][room_y1].end.y = yEnd; - grid[roomX][room_y1 + room_dy].unk18 = TRUE; - grid[roomX][room_y1].unk18 = TRUE; - grid[roomX][room_y1 + room_dy].unk11 = FALSE; - grid[roomX][room_y1 + room_dy].unk17 = TRUE; + + grid[roomX][room_y1 + room_dy].isMerged = TRUE; + grid[roomX][room_y1].isMerged = TRUE; + grid[roomX][room_y1 + room_dy].isConnected = FALSE; + grid[roomX][room_y1 + room_dy].hasBeenMerged = TRUE; } // GenerateOuterRoomsFloor - Generates a floor layout with a ring of rooms and nothing on the interior. @@ -2446,14 +2458,14 @@ void GenerateOuterRoomsFloor(s32 sizeX_, s32 sizeY_, UnkDungeonGlobal_unk1C574 * // Make all cells rooms for (x = 0; x < sizeX; x++) { for (y = 0; y < sizeY; y++) { - grid[x][y].unk10 = TRUE; + grid[x][y].isRoom = TRUE; } } // Invalidate all interior cells for (x = 1; x < sizeX - 1; x++) { for (y = 1; y < sizeY - 1; y++) { - grid[x][y].unk8 = TRUE; + grid[x][y].isInvalid = TRUE; } } @@ -2467,8 +2479,8 @@ void GenerateOuterRoomsFloor(s32 sizeX_, s32 sizeY_, UnkDungeonGlobal_unk1C574 * // instead of from the top, but this does not affect the connectivity of the map. for (x = 0; x < sizeX - 1; x++) { if (x != 0) { - grid[x][0].unk22 = TRUE; - grid[x][sizeY-1].unk22 = TRUE; + grid[x][0].connectedToRight = TRUE; + grid[x][sizeY-1].connectedToRight = TRUE; } // Bug: if sizeX <= 2, this branch will never be run. @@ -2476,23 +2488,23 @@ void GenerateOuterRoomsFloor(s32 sizeX_, s32 sizeY_, UnkDungeonGlobal_unk1C574 * // sizeX == 1, no connections will be made between columns here. // This results in an unconnected map for sizeX <= 2. if (x < sizeX - 2) { - grid[x+1][0].unk21 = TRUE; - grid[x+1][sizeY-1].unk21 = TRUE; + grid[x+1][0].connectedToLeft = TRUE; + grid[x+1][sizeY-1].connectedToLeft = TRUE; } } for (y = 0; y < sizeY - 1; y++) { if (y != 0) { - grid[0][y].unk19 = TRUE; - grid[sizeX-1][y].unk19 = TRUE; + grid[0][y].connectedToTop = TRUE; + grid[sizeX-1][y].connectedToTop = TRUE; } // This connection ends up not being set for the bottom row, but this is fine because the other // connection to this room is still correct. The result is that hallways here will be using the opposing end // of the grid cell boundary for their turns compared to top/bottom hallways between other rows. if (y < sizeY - 2) { - grid[0][y].unk20 = TRUE; - grid[sizeX-1][y].unk20 = TRUE; + grid[0][y].connectedToBottom = TRUE; + grid[sizeX-1][y].connectedToBottom = TRUE; } } @@ -2565,7 +2577,7 @@ void sub_804C790(s32 x1, s32 y1, s32 x2, s32 y2, s32 a4, UnkDungeonGlobal_unk1C5 x3 = DungeonRandInt(x1); y3 = DungeonRandInt(y1); r10 = y3 * x1 + x3; - if (grid[x3][y3].unk10) + if (grid[x3][y3].isRoom) break; } sub_8050F90(grid, x1, y1, listX, listY, r10, x2, y2); @@ -2592,16 +2604,14 @@ void GenerateOneRoomMonsterHouseFloor(void) grid[0][0].end.x = DUNGEON_MAX_SIZE_X - 2; grid[0][0].start.y = 2; grid[0][0].end.y = DUNGEON_MAX_SIZE_Y - 2; - grid[0][0].unk10 = TRUE; - grid[0][0].unk11 = TRUE; - grid[0][0].unk8 = FALSE; + + grid[0][0].isRoom = TRUE; + grid[0][0].isConnected = TRUE; + grid[0][0].isInvalid = FALSE; for (x = grid[0][0].start.x; x < grid[0][0].end.x; x++) { for (y = grid[0][0].start.y; y < grid[0][0].end.y; y++) { - Tile *tile = GetTileSafe(x, y); - tile->terrainType &= ~(TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY); - tile->terrainType |= TERRAIN_TYPE_NORMAL; - // Unnecessary call again + SetTerrainNormal(GetTileSafe(x, y)); GetTileSafe(x, y)->room = 0; } } @@ -2640,7 +2650,7 @@ void GenerateTwoRoomsWithMonsterHouseFloor(void) s32 endX = startX + roomSizeX; s32 endY = startY + roomSizeY; - grid[x][y].unk10 = 1; + grid[x][y].isRoom = TRUE; grid[x][y].start.x = startX; grid[x][y].end.x = endX; grid[x][y].start.y = startY; @@ -2648,10 +2658,7 @@ void GenerateTwoRoomsWithMonsterHouseFloor(void) for (currX = startX; currX < endX; currX++) { for (currY = startY; currY < endY; currY++) { - Tile *tile = GetTileSafe(currX, currY); - tile->terrainType &= ~(TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY); - tile->terrainType |= TERRAIN_TYPE_NORMAL; - // Unnecessary call again + SetTerrainNormal(GetTileSafe(currX, currY)); GetTileSafe(currX, currY)->room = currRoomId; } } @@ -2659,8 +2666,8 @@ void GenerateTwoRoomsWithMonsterHouseFloor(void) } } - grid[0][0].unk22 = TRUE; - grid[1][0].unk21 = TRUE; + grid[0][0].connectedToRight = TRUE; + grid[1][0].connectedToLeft = TRUE; CreateGridCellConnections(grid, sizeX, sizeY, listX, listY, FALSE); GenerateMonsterHouse(grid, sizeX, sizeY, 999); @@ -2719,7 +2726,7 @@ void GenerateExtraHallways(struct GridCell grid[GRID_CELL_LEN][GRID_CELL_LEN], s // - connected // - valid // - not a maze room - if (!grid[x][y].unk10 || !grid[x][y].unk11 || grid[x][y].unk8 || grid[x][y].unk16) continue; + if (!grid[x][y].isRoom || !grid[x][y].isConnected || grid[x][y].isInvalid || grid[x][y].isMazeRoom) continue; // Choose a random tile in the room currX = DungeonRandRange(grid[x][y].start.x, grid[x][y].end.x); @@ -2759,7 +2766,7 @@ void GenerateExtraHallways(struct GridCell grid[GRID_CELL_LEN][GRID_CELL_LEN], s // Keep walking until an obstacle is encountered while (1) { - if ((GetTile(currX, currY)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) != TERRAIN_TYPE_NORMAL) + if (GetTerrain(GetTile(currX, currY)) != TERRAIN_TYPE_NORMAL) break; currX += gAdjacentTileOffsets[direction].x; @@ -2767,7 +2774,7 @@ void GenerateExtraHallways(struct GridCell grid[GRID_CELL_LEN][GRID_CELL_LEN], s } // Abort if we reached secondary terrain - if ((GetTile(currX, currY)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_SECONDARY) + if (GetTerrain(GetTile(currX, currY)) == TERRAIN_TYPE_SECONDARY) continue; // Check that the current tile is at least 2 away from the map border @@ -2788,13 +2795,13 @@ void GenerateExtraHallways(struct GridCell grid[GRID_CELL_LEN][GRID_CELL_LEN], s // Make sure the direction 90 degrees counterclockwise isn't an open tile checkX = gAdjacentTileOffsets[(direction + 2) & DIRECTION_MASK_CARDINAL].x; checkY = gAdjacentTileOffsets[(direction + 2) & DIRECTION_MASK_CARDINAL].y; - if ((GetTile(currX + checkX, currY + checkY)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) + if (GetTerrain(GetTile(currX + checkX, currY + checkY)) == TERRAIN_TYPE_NORMAL) continue; // Do the same for 90 degrees clockwise (or 270 counterclockwise) and make sure it's not an open tile checkX2 = gAdjacentTileOffsets[(direction - 2) & DIRECTION_MASK_CARDINAL].x; checkY2 = gAdjacentTileOffsets[(direction - 2) & DIRECTION_MASK_CARDINAL].y; - if ((GetTile(currX + checkX2, currY + checkY2)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) + if (GetTerrain(GetTile(currX + checkX2, currY + checkY2)) == TERRAIN_TYPE_NORMAL) continue; // Number of steps to walk in one direction before turning @@ -2808,40 +2815,43 @@ void GenerateExtraHallways(struct GridCell grid[GRID_CELL_LEN][GRID_CELL_LEN], s // - Reached an impassable wall // - Would result in carving out a 2x2 square (not a hallway at that point) - if (currX <= 1 || currY <= 1 || currX >= DUNGEON_MAX_SIZE_X - 1 || currY >= DUNGEON_MAX_SIZE_Y - 1) break; - if ((GetTile(currX, currY)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) break; - if (GetTile(currX, currY)->terrainType & TERRAIN_TYPE_IMPASSABLE_WALL) break; + if (currX <= 1 || currY <= 1 || currX >= DUNGEON_MAX_SIZE_X - 1 || currY >= DUNGEON_MAX_SIZE_Y - 1) + break; + if (GetTerrain(GetTile(currX, currY)) == TERRAIN_TYPE_NORMAL) + break; + if (GetTile(currX, currY)->terrainType & TERRAIN_TYPE_IMPASSABLE_WALL) + break; willNotMakeSquare = TRUE; // Check Bottom to Right - if (((GetTile(currX + 1, currY)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) && - ((GetTile(currX + 1, currY + 1)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) && - ((GetTile(currX, currY + 1)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL)) + if ((GetTerrain(GetTile(currX + 1, currY)) == TERRAIN_TYPE_NORMAL) && + (GetTerrain(GetTile(currX + 1, currY + 1)) == TERRAIN_TYPE_NORMAL) && + (GetTerrain(GetTile(currX, currY + 1)) == TERRAIN_TYPE_NORMAL)) { willNotMakeSquare = FALSE; } // Check Top to Right - if (((GetTile(currX + 1, currY)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) && - ((GetTile(currX + 1, currY - 1)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) && - ((GetTile(currX, currY - 1)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL)) + if ((GetTerrain(GetTile(currX + 1, currY)) == TERRAIN_TYPE_NORMAL) && + (GetTerrain(GetTile(currX + 1, currY - 1)) == TERRAIN_TYPE_NORMAL) && + (GetTerrain(GetTile(currX, currY - 1)) == TERRAIN_TYPE_NORMAL)) { willNotMakeSquare = FALSE; } // Check Bottom to Left - if (((GetTile(currX - 1, currY)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) && - ((GetTile(currX - 1, currY + 1)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) && - ((GetTile(currX, currY + 1)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL)) + if ((GetTerrain(GetTile(currX - 1, currY)) == TERRAIN_TYPE_NORMAL) && + (GetTerrain(GetTile(currX - 1, currY + 1)) == TERRAIN_TYPE_NORMAL) && + (GetTerrain(GetTile(currX, currY + 1)) == TERRAIN_TYPE_NORMAL)) { willNotMakeSquare = FALSE; } // Check Top to Left - if (((GetTile(currX - 1, currY)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) && - ((GetTile(currX - 1, currY - 1)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) && - ((GetTile(currX, currY - 1)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL)) + if ((GetTerrain(GetTile(currX - 1, currY)) == TERRAIN_TYPE_NORMAL) && + (GetTerrain(GetTile(currX - 1, currY - 1)) == TERRAIN_TYPE_NORMAL) && + (GetTerrain(GetTile(currX, currY - 1)) == TERRAIN_TYPE_NORMAL)) { willNotMakeSquare = FALSE; } @@ -2849,21 +2859,19 @@ void GenerateExtraHallways(struct GridCell grid[GRID_CELL_LEN][GRID_CELL_LEN], s // If TRUE, make the tile open, it will not produce a 2x2 opening // If FALSE, it will abort from neighbor checks so we don't break here if (willNotMakeSquare) { - Tile *tile = GetTileSafe(currX, currY); - tile->terrainType &= ~(TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY); - tile->terrainType |= TERRAIN_TYPE_NORMAL; + SetTerrainNormal(GetTileSafe(currX, currY)); } // Make sure the direction 90 degrees counterclockwise isn't an open tile checkX = gAdjacentTileOffsets[(direction + 2) & DIRECTION_MASK_CARDINAL].x; checkY = gAdjacentTileOffsets[(direction + 2) & DIRECTION_MASK_CARDINAL].y; - if ((GetTile(currX + checkX, currY + checkY)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) + if (GetTerrain(GetTile(currX + checkX, currY + checkY)) == TERRAIN_TYPE_NORMAL) break; // Do the same for 90 degrees clockwise (or 270 counterclockwise) and make sure it's not an open tile checkX2 = gAdjacentTileOffsets[(direction - 2) & DIRECTION_MASK_CARDINAL].x; checkY2 = gAdjacentTileOffsets[(direction - 2) & DIRECTION_MASK_CARDINAL].y; - if ((GetTile(currX + checkX2, currY + checkY2)->terrainType & (TERRAIN_TYPE_NORMAL | TERRAIN_TYPE_SECONDARY)) == TERRAIN_TYPE_NORMAL) + if (GetTerrain(GetTile(currX + checkX2, currY + checkY2)) == TERRAIN_TYPE_NORMAL) break; j--; @@ -2892,4 +2900,173 @@ void GenerateExtraHallways(struct GridCell grid[GRID_CELL_LEN][GRID_CELL_LEN], s } } +// GetGridPositions - Determines the starting positions of grid cells based on the given floor grid dimensions +void GetGridPositions(s32 *listX, s32 *listY, s32 sizeX, s32 sizeY) +{ + s32 i, sum; + + for (i = 0, sum = 0; i < sizeX; i++) { + listX[i] = sum; + sum += DUNGEON_MAX_SIZE_X / sizeX; + } + listX[sizeX] = sum; + + for (i = 0, sum = 0; i < sizeY; i++) { + listY[i] = sum; + sum += DUNGEON_MAX_SIZE_Y / sizeY; + } + listY[sizeY] = sum; +} + +/* + * InitDungeonGrid - Initializes the default state of the dungeon grid + * + * The dungeon grid is an array of grid cells stored in column-major order + * (to give contiguous storage to cells with the same x value), with a fixed column size of 15. + */ +void InitDungeonGrid(struct GridCell grid[GRID_CELL_LEN][GRID_CELL_LEN], s32 sizeX, s32 sizeY) +{ + s32 x, y; + + for (x = 0; x < sizeX; x++) { + for (y = 0; y < sizeY; y++) { + if (gUnknown_202F1AE == 1 && x >= sizeX / 2) { + grid[x][y].isInvalid = TRUE; + } + else if (gUnknown_202F1AE == 2 && x >= (sizeX * 3) / 4) { + grid[x][y].isInvalid = TRUE; + } + else { + grid[x][y].isInvalid = FALSE; + } + + grid[x][y].isRoom = TRUE; + grid[x][y].isConnected = FALSE; + grid[x][y].unk15 = FALSE; + grid[x][y].unk14 = FALSE; + grid[x][y].unk12 = FALSE; + grid[x][y].connectedToRight = FALSE; + grid[x][y].connectedToLeft = FALSE; + grid[x][y].connectedToBottom = FALSE; + grid[x][y].connectedToTop = FALSE; + grid[x][y].unk26 = FALSE; + grid[x][y].unk25 = FALSE; + grid[x][y].unk24 = FALSE; + grid[x][y].unk23 = FALSE; + grid[x][y].unk9 = FALSE; + grid[x][y].hasBeenMerged = FALSE; + grid[x][y].isMazeRoom = FALSE; + grid[x][y].isMerged = FALSE; + grid[x][y].unk28 = FALSE; + grid[x][y].unk29 = FALSE; + } + } +} + +/* + * AssignRooms - Randomly selects a subset of grid cells to become rooms + * + * If number_of_rooms is positive, number_of_rooms + [0..2] will become rooms + * If the selected cells for rooms are invalid, less rooms will be generated. + * The number of rooms assigned will always be at least 2 and always <= MAX_ROOM_COUNT (32). + * + * Any cells which aren't marked as rooms will become hallway anchors (those single 1x1 "rooms") + * which will be connected as hallways later, to "anchor" hallway generation + * + * Primarily Modifies: grid to assign certain grid cells to have isRoom TRUE. + */ +void AssignRooms(struct GridCell grid[GRID_CELL_LEN][GRID_CELL_LEN], s32 sizeX, s32 sizeY, s32 roomsNumber) +{ + bool8 randomRoomBits[256]; + s32 i, nShuffles; + s32 x, y; + s32 attempts; + s32 maxRooms; + // Extra Rooms + i = DungeonRandInt(3); + + // A negative # for room count requests an exact number of rooms + if (roomsNumber < 0) { + roomsNumber = -roomsNumber; + } + else { + roomsNumber += i; + } + + for (i = 0; i < roomsNumber; i++) { + randomRoomBits[i] = TRUE; + } + for (; i < 256; i++) { + randomRoomBits[i] = FALSE; + } + + // Shuffle around the acceptable rooms + maxRooms = sizeX * sizeY; + + for (nShuffles = 0; nShuffles < 64; nShuffles++) { + bool8 temp; + s32 a = DungeonRandInt(maxRooms); + s32 b = DungeonRandInt(maxRooms); + + SWAP(randomRoomBits[a], randomRoomBits[b], temp); + } + + // Counter for randomRoomBits + i = 0; + gUnknown_202F1CC = 0; + for (x = 0; x < sizeX; x++) { + for (y = 0; y < sizeY; y++) { + if (grid[x][y].isInvalid) + continue; + + // There are too many rooms, remove + if (gUnknown_202F1CC >= MAX_ROOM_COUNT) { + grid[x][y].isRoom = FALSE; + } + + // Using the randomly shuffled bits, create or remove the room + if (randomRoomBits[i]) { + grid[x][y].isRoom = TRUE; + gUnknown_202F1CC++; + + // Don't make a room at (x_mid, 1) + if (sizeX % 2 != 0 && x == (sizeX - 1) / 2 && y == 1 ) { + grid[x][y].isRoom = FALSE; + } + } + else { + grid[x][y].isRoom = FALSE; + } + + i++; + } + } + + // We have at least 2 rooms, we're done. + if (gUnknown_202F1CC >= 2) + return; + + for (attempts = 0; attempts < 200; attempts++) { + bool8 enoughRooms = FALSE; + for (x = 0; x < sizeX; x++) { + for (y = 0; y < sizeY; y++) { + if (grid[x][y].isInvalid) + continue; + + if (DungeonRandInt(100) < 60) { + grid[x][y].isRoom = TRUE; + enoughRooms = TRUE; + // This goto is needed to match, it's used to break from two nested loops. + goto LOOP_BREAK; + } + } + } + LOOP_BREAK: + if (enoughRooms) + break; + } + + gUnknown_202F1AD = FALSE; +} + //