#include "map.h" #include "rng.h" #include "utils.h" #include void map_init(Map *map) { // Fill entire map with walls for (int y = 0; y < MAP_HEIGHT; y++) { for (int x = 0; x < MAP_WIDTH; x++) { map->tiles[y][x] = TILE_WALL; } } map->room_count = 0; } int is_floor(Map *map, int x, int y) { if (!in_bounds(x, y, MAP_WIDTH, MAP_HEIGHT)) return 0; return map->tiles[y][x] == TILE_FLOOR || map->tiles[y][x] == TILE_STAIRS; } void get_room_center(Room *room, int *cx, int *cy) { *cx = room->x + room->w / 2; *cy = room->y + room->h / 2; } // Carve a room into the map static void carve_room(Map *map, Room *room) { for (int y = room->y; y < room->y + room->h; y++) { for (int x = room->x; x < room->x + room->w; x++) { if (in_bounds(x, y, MAP_WIDTH, MAP_HEIGHT)) { map->tiles[y][x] = TILE_FLOOR; } } } } // Carve a horizontal corridor static void carve_h_corridor(Map *map, int x1, int x2, int y) { int start = (x1 < x2) ? x1 : x2; int end = (x1 < x2) ? x2 : x1; for (int x = start; x <= end; x++) { if (in_bounds(x, y, MAP_WIDTH, MAP_HEIGHT)) { map->tiles[y][x] = TILE_FLOOR; } } } // Carve a vertical corridor static void carve_v_corridor(Map *map, int x, int y1, int y2) { int start = (y1 < y2) ? y1 : y2; int end = (y1 < y2) ? y2 : y1; for (int y = start; y <= end; y++) { if (in_bounds(x, y, MAP_WIDTH, MAP_HEIGHT)) { map->tiles[y][x] = TILE_FLOOR; } } } // Check if a room overlaps with existing rooms static int room_overlaps(Room *rooms, int count, Room *new_room) { // Add padding to prevent rooms from touching for (int i = 0; i < count; i++) { Room *r = &rooms[i]; if (!(new_room->x > r->x + r->w || new_room->x + new_room->w < r->x || new_room->y > r->y + r->h || new_room->y + new_room->h < r->y)) { return 1; } } return 0; } // Generate rooms for this floor static int generate_rooms(Map *map, Room *rooms, int floor) { int room_count = 0; int attempts = 0; int max_attempts = 100; // Room count varies by floor, but capped at max_rooms int target_rooms = 5 + (floor % 3) + rng_int(0, 3); if (target_rooms > MAX_ROOMS) target_rooms = MAX_ROOMS; while (room_count < target_rooms && attempts < max_attempts) { attempts++; // Random room dimensions int w = rng_int(5, 12); int h = rng_int(5, 10); // Random position (within map bounds with 1-tile border) int x = rng_int(2, MAP_WIDTH - w - 2); int y = rng_int(2, MAP_HEIGHT - h - 2); Room new_room = {x, y, w, h}; // Check for overlap if (!room_overlaps(rooms, room_count, &new_room)) { rooms[room_count] = new_room; carve_room(map, &new_room); room_count++; } } return room_count; } // Connect all rooms with corridors static void connect_rooms(Map *map, Room *rooms, int room_count) { for (int i = 0; i < room_count - 1; i++) { int cx1, cy1, cx2, cy2; get_room_center(&rooms[i], &cx1, &cy1); get_room_center(&rooms[i + 1], &cx2, &cy2); // Carve L-shaped corridor between rooms if (rng_int(0, 1) == 0) { carve_h_corridor(map, cx1, cx2, cy1); carve_v_corridor(map, cx2, cy1, cy2); } else { carve_v_corridor(map, cx1, cy1, cy2); carve_h_corridor(map, cx1, cx2, cy2); } } } // Place stairs in the last room (furthest from start) static void place_stairs(Map *map, Room *rooms, int room_count) { if (room_count > 0) { Room *last_room = &rooms[room_count - 1]; int cx, cy; get_room_center(last_room, &cx, &cy); // Place stairs at center of last room if (in_bounds(cx, cy, MAP_WIDTH, MAP_HEIGHT)) { map->tiles[cy][cx] = TILE_STAIRS; } } } // Get a random floor tile (for player/enemy spawn) void get_random_floor_tile(Map *map, int *x, int *y, int attempts) { *x = -1; *y = -1; for (int i = 0; i < attempts; i++) { int tx = rng_int(1, MAP_WIDTH - 2); int ty = rng_int(1, MAP_HEIGHT - 2); if (map->tiles[ty][tx] == TILE_FLOOR) { *x = tx; *y = ty; return; } } // Fallback: search from top-left for (int ty = 1; ty < MAP_HEIGHT - 1; ty++) { for (int tx = 1; tx < MAP_WIDTH - 1; tx++) { if (map->tiles[ty][tx] == TILE_FLOOR) { *x = tx; *y = ty; return; } } } } void dungeon_generate(Dungeon *d, Map *map, int floor_num) { // Seed RNG with floor number for deterministic generation rng_seed(floor_num * 12345); // Initialize map to all walls map_init(map); // Generate rooms map->room_count = generate_rooms(map, map->rooms, floor_num); // Connect rooms with corridors connect_rooms(map, map->rooms, map->room_count); // Place stairs in last room place_stairs(map, map->rooms, map->room_count); // Store dungeon state d->current_floor = floor_num; d->room_count = map->room_count; memcpy(d->rooms, map->rooms, sizeof(Room) * map->room_count); }