map: expand tile system with doors
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I5704e8f954f6f935954c46ef8af40b836a6a6964
This commit is contained in:
parent
ceb657add8
commit
2f5c959500
3 changed files with 176 additions and 11 deletions
|
|
@ -2,6 +2,7 @@
|
||||||
#include "rng/rng.h"
|
#include "rng/rng.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
@ -20,7 +21,8 @@ void map_init(Map *map) {
|
||||||
int is_floor(const Map *map, int x, int y) {
|
int is_floor(const Map *map, int x, int y) {
|
||||||
if (!in_bounds(x, y, MAP_WIDTH, MAP_HEIGHT))
|
if (!in_bounds(x, y, MAP_WIDTH, MAP_HEIGHT))
|
||||||
return 0;
|
return 0;
|
||||||
return map->tiles[y][x] == TILE_FLOOR || map->tiles[y][x] == TILE_STAIRS;
|
return map->tiles[y][x] == TILE_FLOOR || map->tiles[y][x] == TILE_STAIRS || map->tiles[y][x] == TILE_DOOR_OPEN ||
|
||||||
|
map->tiles[y][x] == TILE_DOOR_RUINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_room_center(Room *room, int *cx, int *cy) {
|
void get_room_center(Room *room, int *cx, int *cy) {
|
||||||
|
|
@ -109,6 +111,32 @@ static int generate_rooms(Map *map, Room *rooms, int floor) {
|
||||||
return room_count;
|
return room_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if a tile is at a room boundary (adjacent to wall but inside room)
|
||||||
|
static int is_room_boundary(Map *map, int x, int y) {
|
||||||
|
// Must be floor
|
||||||
|
if (map->tiles[y][x] != TILE_FLOOR)
|
||||||
|
return 0;
|
||||||
|
// Must have at least one adjacent wall
|
||||||
|
if (in_bounds(x - 1, y, MAP_WIDTH, MAP_HEIGHT) && map->tiles[y][x - 1] == TILE_WALL)
|
||||||
|
return 1;
|
||||||
|
if (in_bounds(x + 1, y, MAP_WIDTH, MAP_HEIGHT) && map->tiles[y][x + 1] == TILE_WALL)
|
||||||
|
return 1;
|
||||||
|
if (in_bounds(x, y - 1, MAP_WIDTH, MAP_HEIGHT) && map->tiles[y - 1][x] == TILE_WALL)
|
||||||
|
return 1;
|
||||||
|
if (in_bounds(x, y + 1, MAP_WIDTH, MAP_HEIGHT) && map->tiles[y + 1][x] == TILE_WALL)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place doors at corridor-room junctions
|
||||||
|
// DISABLED: Door placement removed per user request
|
||||||
|
static void place_doors(Map *map, Room *rooms, int room_count) {
|
||||||
|
(void)map;
|
||||||
|
(void)rooms;
|
||||||
|
(void)room_count;
|
||||||
|
// No-op: doors disabled
|
||||||
|
}
|
||||||
|
|
||||||
// Connect all rooms with corridors
|
// Connect all rooms with corridors
|
||||||
static void connect_rooms(Map *map, Room *rooms, int room_count) {
|
static void connect_rooms(Map *map, Room *rooms, int room_count) {
|
||||||
for (int i = 0; i < room_count - 1; i++) {
|
for (int i = 0; i < room_count - 1; i++) {
|
||||||
|
|
@ -125,6 +153,9 @@ static void connect_rooms(Map *map, Room *rooms, int room_count) {
|
||||||
carve_h_corridor(map, cx1, cx2, cy2);
|
carve_h_corridor(map, cx1, cx2, cy2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Place doors after all corridors are carved
|
||||||
|
place_doors(map, rooms, room_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place stairs in the last room (furthest from start)
|
// Place stairs in the last room (furthest from start)
|
||||||
|
|
@ -134,8 +165,43 @@ static void place_stairs(Map *map, Room *rooms, int room_count) {
|
||||||
int cx, cy;
|
int cx, cy;
|
||||||
get_room_center(last_room, &cx, &cy);
|
get_room_center(last_room, &cx, &cy);
|
||||||
|
|
||||||
// Place stairs at center of last room
|
// Ensure stairs are placed on a floor tile, not a wall
|
||||||
|
if (in_bounds(cx, cy, MAP_WIDTH, MAP_HEIGHT) && map->tiles[cy][cx] == TILE_FLOOR) {
|
||||||
|
map->tiles[cy][cx] = TILE_STAIRS;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3x3 fallback
|
||||||
|
for (int dy = -1; dy <= 1; dy++) {
|
||||||
|
for (int dx = -1; dx <= 1; dx++) {
|
||||||
|
int nx = cx + dx;
|
||||||
|
int ny = cy + dy;
|
||||||
|
if (in_bounds(nx, ny, MAP_WIDTH, MAP_HEIGHT) && map->tiles[ny][nx] == TILE_FLOOR) {
|
||||||
|
map->tiles[ny][nx] = TILE_STAIRS;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expanded fallback: scan the room for any floor tile
|
||||||
|
for (int dy = 0; dy < last_room->h; dy++) {
|
||||||
|
for (int dx = 0; dx < last_room->w; dx++) {
|
||||||
|
int nx = last_room->x + dx;
|
||||||
|
int ny = last_room->y + dy;
|
||||||
|
if (in_bounds(nx, ny, MAP_WIDTH, MAP_HEIGHT) && map->tiles[ny][nx] == TILE_FLOOR) {
|
||||||
|
map->tiles[ny][nx] = TILE_STAIRS;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final fallback: force the center tile to stairs regardless of type
|
||||||
|
fprintf(stderr, "Warning: No floor tile found for stairs at room center (%d, %d). Forcing stairs placement.\n", cx,
|
||||||
|
cy);
|
||||||
if (in_bounds(cx, cy, MAP_WIDTH, MAP_HEIGHT)) {
|
if (in_bounds(cx, cy, MAP_WIDTH, MAP_HEIGHT)) {
|
||||||
|
if (map->tiles[cy][cx] == TILE_WALL) {
|
||||||
|
map->tiles[cy][cx] = TILE_FLOOR;
|
||||||
|
}
|
||||||
map->tiles[cy][cx] = TILE_STAIRS;
|
map->tiles[cy][cx] = TILE_STAIRS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
114
src/common.h
114
src/common.h
|
|
@ -9,7 +9,7 @@ typedef struct {
|
||||||
} Vec2;
|
} Vec2;
|
||||||
|
|
||||||
// Tile types
|
// Tile types
|
||||||
typedef enum { TILE_WALL, TILE_FLOOR, TILE_STAIRS } TileType;
|
typedef enum { TILE_WALL, TILE_FLOOR, TILE_STAIRS, TILE_DOOR_CLOSED, TILE_DOOR_OPEN, TILE_DOOR_RUINED } TileType;
|
||||||
|
|
||||||
// Status effect types
|
// Status effect types
|
||||||
typedef enum { EFFECT_NONE, EFFECT_POISON, EFFECT_STUN, EFFECT_BLEED, EFFECT_WEAKEN, EFFECT_BURN } StatusEffectType;
|
typedef enum { EFFECT_NONE, EFFECT_POISON, EFFECT_STUN, EFFECT_BLEED, EFFECT_WEAKEN, EFFECT_BURN } StatusEffectType;
|
||||||
|
|
@ -49,69 +49,165 @@ typedef struct {
|
||||||
typedef enum { ITEM_POTION, ITEM_WEAPON, ITEM_ARMOR } ItemType;
|
typedef enum { ITEM_POTION, ITEM_WEAPON, ITEM_ARMOR } ItemType;
|
||||||
|
|
||||||
// Item
|
// Item
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
ItemType type;
|
ItemType type;
|
||||||
|
|
||||||
int power;
|
int power;
|
||||||
|
|
||||||
int floor;
|
int floor;
|
||||||
|
|
||||||
int picked_up;
|
int picked_up;
|
||||||
|
|
||||||
DamageClass dmg_class;
|
DamageClass dmg_class;
|
||||||
|
|
||||||
int crit_chance;
|
int crit_chance;
|
||||||
|
|
||||||
int crit_multiplier;
|
int crit_multiplier;
|
||||||
|
|
||||||
int status_chance;
|
int status_chance;
|
||||||
|
|
||||||
|
// rendering
|
||||||
|
|
||||||
|
int sprite_tile_id; // tile ID for rendering
|
||||||
|
|
||||||
} Item;
|
} Item;
|
||||||
|
|
||||||
|
// Player animation states
|
||||||
|
typedef enum { PLAYER_ANIM_IDLE, PLAYER_ANIM_WALK, PLAYER_ANIM_ATTACK } PlayerAnimState;
|
||||||
|
|
||||||
// Player
|
// Player
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Vec2 position;
|
Vec2 position;
|
||||||
|
|
||||||
int hp, max_hp;
|
int hp, max_hp;
|
||||||
|
|
||||||
int attack;
|
int attack;
|
||||||
|
|
||||||
int defense;
|
int defense;
|
||||||
|
|
||||||
int floor;
|
int floor;
|
||||||
|
|
||||||
int step_count;
|
int step_count;
|
||||||
int speed; // actions per 100 ticks (100 = 1 action per turn)
|
|
||||||
|
int speed; // actions per 100 ticks (100 = 1 action per turn)
|
||||||
|
|
||||||
int cooldown; // countdown to next action (0 = can act)
|
int cooldown; // countdown to next action (0 = can act)
|
||||||
int dodge; // dodge chance percentage
|
|
||||||
int block; // flat damage reduction on successful block roll
|
int dodge; // dodge chance percentage
|
||||||
|
|
||||||
|
int block; // flat damage reduction on successful block roll
|
||||||
|
|
||||||
Item equipped_weapon;
|
Item equipped_weapon;
|
||||||
|
|
||||||
int has_weapon;
|
int has_weapon;
|
||||||
|
|
||||||
Item equipped_armor;
|
Item equipped_armor;
|
||||||
|
|
||||||
int has_armor;
|
int has_armor;
|
||||||
|
|
||||||
Item inventory[MAX_INVENTORY];
|
Item inventory[MAX_INVENTORY];
|
||||||
|
|
||||||
int inventory_count;
|
int inventory_count;
|
||||||
|
|
||||||
// status effects
|
// status effects
|
||||||
|
|
||||||
StatusEffect effects[MAX_EFFECTS];
|
StatusEffect effects[MAX_EFFECTS];
|
||||||
|
|
||||||
int effect_count;
|
int effect_count;
|
||||||
|
|
||||||
|
// animation
|
||||||
|
|
||||||
|
PlayerAnimState anim_state;
|
||||||
|
|
||||||
|
int anim_frame; // current animation frame
|
||||||
|
|
||||||
|
int anim_timer; // frames until next frame
|
||||||
|
|
||||||
|
int facing_right; // 1 = facing right, 0 = facing left
|
||||||
|
|
||||||
|
// rendering
|
||||||
|
|
||||||
|
int sprite_tile_id; // tile ID for rendering
|
||||||
|
|
||||||
|
// visual effects
|
||||||
|
|
||||||
|
int flash_timer; // damage flash frames remaining
|
||||||
|
|
||||||
} Player;
|
} Player;
|
||||||
|
|
||||||
// Enemy types
|
// Enemy types
|
||||||
typedef enum { ENEMY_GOBLIN, ENEMY_SKELETON, ENEMY_ORC } EnemyType;
|
typedef enum { ENEMY_GOBLIN, ENEMY_SKELETON, ENEMY_ORC } EnemyType;
|
||||||
|
|
||||||
|
// Enemy animation states
|
||||||
|
typedef enum { ENEMY_ANIM_IDLE, ENEMY_ANIM_WALK, ENEMY_ANIM_ATTACK } EnemyAnimState;
|
||||||
|
|
||||||
// Enemy
|
// Enemy
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Vec2 position;
|
Vec2 position;
|
||||||
|
|
||||||
int hp;
|
int hp;
|
||||||
|
|
||||||
int max_hp;
|
int max_hp;
|
||||||
|
|
||||||
int attack;
|
int attack;
|
||||||
|
|
||||||
int alive;
|
int alive;
|
||||||
|
|
||||||
EnemyType type;
|
EnemyType type;
|
||||||
int speed; // actions per 100 ticks
|
|
||||||
|
int speed; // actions per 100 ticks
|
||||||
|
|
||||||
int cooldown; // countdown to next action
|
int cooldown; // countdown to next action
|
||||||
int dodge; // dodge chance percentage
|
|
||||||
int block; // flat damage reduction
|
int dodge; // dodge chance percentage
|
||||||
|
|
||||||
|
int block; // flat damage reduction
|
||||||
|
|
||||||
int resistance[NUM_DMG_CLASSES];
|
int resistance[NUM_DMG_CLASSES];
|
||||||
|
|
||||||
DamageClass dmg_class;
|
DamageClass dmg_class;
|
||||||
|
|
||||||
int status_chance;
|
int status_chance;
|
||||||
|
|
||||||
int crit_chance; // crit chance percentage (0-100)
|
int crit_chance; // crit chance percentage (0-100)
|
||||||
int crit_mult; // crit damage multiplier percentage (e.g. 150 = 1.5x)
|
|
||||||
|
int crit_mult; // crit damage multiplier percentage (e.g. 150 = 1.5x)
|
||||||
|
|
||||||
// vision
|
// vision
|
||||||
|
|
||||||
int vision_range;
|
int vision_range;
|
||||||
int alert; // 1 = aware of player, searching
|
|
||||||
|
int alert; // 1 = aware of player, searching
|
||||||
|
|
||||||
int last_known_x; // last position where enemy saw player
|
int last_known_x; // last position where enemy saw player
|
||||||
|
|
||||||
int last_known_y;
|
int last_known_y;
|
||||||
|
|
||||||
// status effects
|
// status effects
|
||||||
|
|
||||||
StatusEffect effects[MAX_EFFECTS];
|
StatusEffect effects[MAX_EFFECTS];
|
||||||
|
|
||||||
int effect_count;
|
int effect_count;
|
||||||
|
|
||||||
|
// animation
|
||||||
|
|
||||||
|
EnemyAnimState anim_state;
|
||||||
|
|
||||||
|
int anim_frame; // current animation frame
|
||||||
|
|
||||||
|
int anim_timer; // frames until next frame
|
||||||
|
|
||||||
|
int facing_right; // 1 = facing right, 0 = facing left
|
||||||
|
|
||||||
|
// rendering
|
||||||
|
|
||||||
|
int sprite_tile_id; // tile ID for rendering
|
||||||
|
|
||||||
} Enemy;
|
} Enemy;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,4 +83,7 @@
|
||||||
#define ENEMY_VIEW_RANGE 6
|
#define ENEMY_VIEW_RANGE 6
|
||||||
#define ENEMY_PATROL_MOVE_CHANCE 30
|
#define ENEMY_PATROL_MOVE_CHANCE 30
|
||||||
|
|
||||||
|
// Visual polish
|
||||||
|
#define DRAW_GRID_LINES 1
|
||||||
|
|
||||||
#endif // SETTINGS_H
|
#endif // SETTINGS_H
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue