treewide: the renderer rewrite was promised to me 3000 years ago #21

Open
NotAShelf wants to merge 4 commits from notashelf/push-nmuuvryuwrrl into main
3 changed files with 176 additions and 11 deletions
Showing only changes of commit 2f5c959500 - Show all commits

map: expand tile system with doors

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I5704e8f954f6f935954c46ef8af40b836a6a6964
raf 2026-04-28 15:32:15 +03:00
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF

View file

@ -2,6 +2,7 @@
#include "rng/rng.h"
#include "settings.h"
#include "utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -20,7 +21,8 @@ void map_init(Map *map) {
int is_floor(const 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;
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) {
@ -109,6 +111,32 @@ static int generate_rooms(Map *map, Room *rooms, int floor) {
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
static void connect_rooms(Map *map, Room *rooms, int room_count) {
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);
}
}
// Place doors after all corridors are carved
place_doors(map, rooms, room_count);
}
// 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;
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 (map->tiles[cy][cx] == TILE_WALL) {
map->tiles[cy][cx] = TILE_FLOOR;
}
map->tiles[cy][cx] = TILE_STAIRS;
}
}

View file

@ -9,7 +9,7 @@ typedef struct {
} Vec2;
// 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
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;
// Item
typedef struct {
int x, y;
ItemType type;
int power;
int floor;
int picked_up;
DamageClass dmg_class;
int crit_chance;
int crit_multiplier;
int status_chance;
// rendering
int sprite_tile_id; // tile ID for rendering
} Item;
// Player animation states
typedef enum { PLAYER_ANIM_IDLE, PLAYER_ANIM_WALK, PLAYER_ANIM_ATTACK } PlayerAnimState;
// Player
typedef struct {
Vec2 position;
int hp, max_hp;
int attack;
int defense;
int floor;
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 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;
int has_weapon;
Item equipped_armor;
int has_armor;
Item inventory[MAX_INVENTORY];
int inventory_count;
// status effects
StatusEffect effects[MAX_EFFECTS];
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;
// Enemy types
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
typedef struct {
Vec2 position;
int hp;
int max_hp;
int attack;
int alive;
EnemyType type;
int speed; // actions per 100 ticks
int speed; // actions per 100 ticks
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];
DamageClass dmg_class;
int status_chance;
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
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_y;
// status effects
StatusEffect effects[MAX_EFFECTS];
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;

View file

@ -83,4 +83,7 @@
#define ENEMY_VIEW_RANGE 6
#define ENEMY_PATROL_MOVE_CHANCE 30
// Visual polish
#define DRAW_GRID_LINES 1
#endif // SETTINGS_H