stats: track all gameplay statistics during player actions

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ie94380572d2256dda45ce7bfcf347c7f6a6a6964
This commit is contained in:
raf 2026-04-08 10:26:30 +03:00
commit 1d5688526f
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF

View file

@ -115,6 +115,7 @@ static void init_floor(GameState *gs, int floor_num) {
// Initialize player position if first floor // Initialize player position if first floor
if (floor_num == 1) { if (floor_num == 1) {
player_init(&gs->player, start_x, start_y); player_init(&gs->player, start_x, start_y);
gs->floors_reached = 1;
} else { } else {
// Move player to new floor position // Move player to new floor position
gs->player.x = start_x; gs->player.x = start_x;
@ -190,7 +191,8 @@ static void post_action(GameState *gs, Enemy *attacked_enemy) {
audio_play_dodge(gs); audio_play_dodge(gs);
} else { } else {
if (combat_get_last_damage() > 0) if (combat_get_last_damage() > 0)
spawn_floating_text(gs, ex, ey, combat_get_last_damage(), combat_was_critical()); gs->damage_dealt += combat_get_last_damage();
spawn_floating_text(gs, ex, ey, combat_get_last_damage(), combat_was_critical());
audio_play_attack(gs); audio_play_attack(gs);
if (combat_was_blocked()) { if (combat_was_blocked()) {
spawn_floating_label(gs, ex, ey - 10, "BLOCK", EFFECT_NONE); spawn_floating_label(gs, ex, ey - 10, "BLOCK", EFFECT_NONE);
@ -199,6 +201,7 @@ static void post_action(GameState *gs, Enemy *attacked_enemy) {
if (combat_was_critical()) { if (combat_was_critical()) {
spawn_floating_label(gs, ex + 8, ey - 10, "CRIT!", EFFECT_NONE); spawn_floating_label(gs, ex + 8, ey - 10, "CRIT!", EFFECT_NONE);
audio_play_crit(gs); audio_play_crit(gs);
gs->crits_landed++;
} }
StatusEffectType applied = combat_get_applied_effect(); StatusEffectType applied = combat_get_applied_effect();
if (applied != EFFECT_NONE) { if (applied != EFFECT_NONE) {
@ -208,6 +211,7 @@ static void post_action(GameState *gs, Enemy *attacked_enemy) {
if (!attacked_enemy->alive) { if (!attacked_enemy->alive) {
spawn_floating_label(gs, ex, ey - 20, "SLAIN", EFFECT_NONE); spawn_floating_label(gs, ex, ey - 20, "SLAIN", EFFECT_NONE);
audio_play_enemy_death(gs); audio_play_enemy_death(gs);
gs->total_kills++;
} }
} }
} }
@ -219,6 +223,8 @@ static void post_action(GameState *gs, Enemy *attacked_enemy) {
if (combat_was_player_damage() && combat_get_last_damage() > 0) { if (combat_was_player_damage() && combat_get_last_damage() > 0) {
audio_play_player_damage(gs); audio_play_player_damage(gs);
gs->screen_shake = 8; gs->screen_shake = 8;
gs->damage_taken += combat_get_last_damage();
gs->times_hit++;
spawn_floating_text(gs, gs->player.x * TILE_SIZE + 8, gs->player.y * TILE_SIZE, combat_get_last_damage(), spawn_floating_text(gs, gs->player.x * TILE_SIZE + 8, gs->player.y * TILE_SIZE, combat_get_last_damage(),
combat_was_critical()); combat_was_critical());
} }
@ -309,6 +315,7 @@ static int handle_inventory_input(GameState *gs) {
if (item != NULL) { if (item != NULL) {
if (item->type == ITEM_POTION) { if (item->type == ITEM_POTION) {
player_use_item(&gs->player, item); player_use_item(&gs->player, item);
gs->potions_used++;
player_remove_inventory_item(&gs->player, gs->inv_selected); player_remove_inventory_item(&gs->player, gs->inv_selected);
gs->last_message = "Used potion!"; gs->last_message = "Used potion!";
gs->message_timer = 60; gs->message_timer = 60;
@ -350,6 +357,8 @@ static int handle_descend_input(GameState *gs) {
if (IsKeyPressed(KEY_Y)) { if (IsKeyPressed(KEY_Y)) {
if (gs->player.floor < NUM_FLOORS) { if (gs->player.floor < NUM_FLOORS) {
audio_play_stairs(gs); audio_play_stairs(gs);
if (gs->player.floor + 1 > gs->floors_reached)
gs->floors_reached = gs->player.floor + 1;
init_floor(gs, gs->player.floor + 1); init_floor(gs, gs->player.floor + 1);
gs->last_message = "Descended to next floor!"; gs->last_message = "Descended to next floor!";
gs->message_timer = 60; gs->message_timer = 60;
@ -383,6 +392,7 @@ static int handle_movement_input(GameState *gs) {
Item *item = get_item_at_floor(gs->items, gs->item_count, gs->player.x, gs->player.y); Item *item = get_item_at_floor(gs->items, gs->item_count, gs->player.x, gs->player.y);
if (item != NULL) { if (item != NULL) {
if (player_pickup(&gs->player, item)) { if (player_pickup(&gs->player, item)) {
gs->items_collected++;
char pickup_msg[64]; char pickup_msg[64];
snprintf(pickup_msg, sizeof(pickup_msg), "Picked up %s", item_get_name(item)); snprintf(pickup_msg, sizeof(pickup_msg), "Picked up %s", item_get_name(item));
add_log(gs, pickup_msg); add_log(gs, pickup_msg);
@ -400,6 +410,7 @@ static int handle_movement_input(GameState *gs) {
// Check for item usage (U key - use first potion) // Check for item usage (U key - use first potion)
if (IsKeyPressed(KEY_U)) { if (IsKeyPressed(KEY_U)) {
if (gs->player.inventory_count > 0 && player_use_first_item(&gs->player)) { if (gs->player.inventory_count > 0 && player_use_first_item(&gs->player)) {
gs->potions_used++;
gs->last_message = "Used potion!"; gs->last_message = "Used potion!";
gs->message_timer = 60; gs->message_timer = 60;
audio_play_item_pickup(gs); audio_play_item_pickup(gs);
@ -509,6 +520,7 @@ static void game_loop(void) {
memset(&gs, 0, sizeof(GameState)); memset(&gs, 0, sizeof(GameState));
gs.game_over = 0; gs.game_over = 0;
gs.game_won = 0; gs.game_won = 0;
load_audio_assets(&gs);
init_floor(&gs, 1); init_floor(&gs, 1);
} }
} }
@ -554,13 +566,15 @@ static void game_loop(void) {
// Draw game over screen // Draw game over screen
if (gs.game_over) { if (gs.game_over) {
render_game_over(); // Compute final score
gs.final_score = gs.total_kills * 100 + gs.items_collected * 30 + gs.floors_reached * 200 + gs.crits_landed * 25 +
gs.damage_dealt * 2 - gs.damage_taken * 2 - gs.times_hit * 15;
if (gs.game_won) { if (gs.game_won) {
// Draw win message gs.final_score = (gs.final_score * 3) / 2;
const char *win_msg = "YOU WIN! ESCAPED THE DUNGEON!";
int msg_w = MeasureText(win_msg, 30);
DrawText(win_msg, (SCREEN_WIDTH - msg_w) / 2, SCREEN_HEIGHT / 2 - 80, 30, GOLD);
} }
render_end_screen(gs.game_won, gs.total_kills, gs.items_collected, gs.damage_dealt, gs.damage_taken,
gs.crits_landed, gs.times_hit, gs.potions_used, gs.floors_reached, gs.turn_count,
gs.final_score);
} }
EndDrawing(); EndDrawing();