render: use tileset atlas for all entity and tile rendering; anims

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Idb42cff72368e26d8d44db79ba9c413a6a6a6964
This commit is contained in:
raf 2026-04-28 15:32:56 +03:00
commit 5b640dcefd
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
7 changed files with 556 additions and 90 deletions

View file

@ -5,6 +5,7 @@
#include "movement.h"
#include "rng/rng.h"
#include "settings.h"
#include "tileset/tileset.h"
#include <string.h>
// Forward declaration
@ -25,6 +26,12 @@ void enemy_spawn(Enemy enemies[], int *count, Map *map, Player *p, int floor) {
if (floor >= 4)
max_type = 3;
// Get the player's starting room (first room) to exclude from enemy spawn
Room *start_room = NULL;
if (map->room_count > 0) {
start_room = &map->rooms[0];
}
for (int i = 0; i < num_enemies; i++) {
// Find random floor position
int ex, ey;
@ -35,6 +42,14 @@ void enemy_spawn(Enemy enemies[], int *count, Map *map, Player *p, int floor) {
continue;
}
// Don't spawn in the starting room
if (start_room != NULL) {
if (ex >= start_room->x && ex < start_room->x + start_room->w && ey >= start_room->y &&
ey < start_room->y + start_room->h) {
continue;
}
}
// Don't spawn on other enemies
if (is_enemy_at(enemies, *count, ex, ey)) {
continue;
@ -125,6 +140,27 @@ void enemy_spawn(Enemy enemies[], int *count, Map *map, Player *p, int floor) {
}
e.cooldown = e.speed;
// Initialize animation state
e.anim_state = ENEMY_ANIM_IDLE;
e.anim_frame = 0;
e.anim_timer = 0;
e.facing_right = (e.position.x < p->position.x) ? 1 : 0;
// Set sprite tile ID based on enemy type
switch (e.type) {
case ENEMY_GOBLIN:
e.sprite_tile_id = SPRITE_ENEMY_GOBLIN;
break;
case ENEMY_SKELETON:
e.sprite_tile_id = SPRITE_ENEMY_SKELETON;
break;
case ENEMY_ORC:
e.sprite_tile_id = SPRITE_ENEMY_ORC;
break;
default:
e.sprite_tile_id = SPRITE_ENEMY_GOBLIN;
break;
}
enemies[i] = e;
(*count)++;
}
@ -275,6 +311,9 @@ void enemy_act(Enemy *e, Player *p, Map *map, Enemy *all_enemies, int enemy_coun
// Attack if adjacent to player
if (can_see && can_see_entity(map, e->position.x, e->position.y, p->position.x, p->position.y, 1)) {
e->anim_state = ENEMY_ANIM_ATTACK;
e->anim_timer = 12;
e->facing_right = (e->position.x < p->position.x) ? 1 : 0;
combat_enemy_attack(e, p);
propagate_alert(e, all_enemies, enemy_count);
return;
@ -282,14 +321,30 @@ void enemy_act(Enemy *e, Player *p, Map *map, Enemy *all_enemies, int enemy_coun
// Move toward player if visible
if (can_see) {
int old_x = e->position.x;
int old_y = e->position.y;
enemy_move_toward_player(e, p, map, all_enemies, enemy_count);
if (e->position.x != old_x || e->position.y != old_y) {
e->anim_state = ENEMY_ANIM_WALK;
e->anim_timer = 8;
e->facing_right = (e->position.x < p->position.x) ? 1 : 0;
}
propagate_alert(e, all_enemies, enemy_count);
return;
}
// If alert but can't see player, move toward last known position
if (e->alert) {
int old_x = e->position.x;
int old_y = e->position.y;
enemy_move_to_last_known(e, map, all_enemies, enemy_count);
if (e->position.x != old_x || e->position.y != old_y) {
e->anim_state = ENEMY_ANIM_WALK;
e->anim_timer = 8;
if (e->position.x != old_x) {
e->facing_right = (e->position.x < old_x) ? 0 : 1;
}
}
return;
}
@ -304,6 +359,17 @@ void enemy_update_all(Enemy enemies[], int count, Player *p, Map *map) {
if (!e->alive)
continue;
// Update animation timer
if (e->anim_timer > 0) {
e->anim_timer--;
if (e->anim_timer <= 0) {
e->anim_state = ENEMY_ANIM_IDLE;
e->anim_frame = 0;
} else if (e->anim_state == ENEMY_ANIM_WALK) {
e->anim_frame = (e->anim_timer / 4) % 2;
}
}
e->cooldown -= e->speed;
if (e->cooldown <= 0) {
enemy_act(e, p, map, enemies, count);