diff --git a/assets/sounds/crit.wav b/assets/sounds/crit.wav new file mode 100644 index 0000000..d38dd49 Binary files /dev/null and b/assets/sounds/crit.wav differ diff --git a/src/audio.c b/src/audio.c index ed81cc5..578a8a6 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1,5 +1,6 @@ #include "audio.h" #include "raylib.h" +#include "common.h" #include #include @@ -70,85 +71,80 @@ void audio_play_move(void) { play_tone(200.0f, 0.05f, 0.3f); } -void audio_play_attack(void) { +void audio_play_attack(GameState *gs) { // Mid-range hit sound // play_tone(400.0f, 0.1f, 0.5f); int choice = GetRandomValue(1, 3); - Sound attack; switch (choice) { case 1: - attack = LoadSound("./assets/sounds/sword1.wav"); + PlaySound(gs->sounds.attack1); break; case 2: - attack = LoadSound("./assets/sounds/sword2.wav"); + PlaySound(gs->sounds.attack2); break; case 3: - attack = LoadSound("./assets/sounds/sword3.wav"); + PlaySound(gs->sounds.attack3); break; default: - attack = LoadSound("./assets/sounds/sword1.wav"); + PlaySound(gs->sounds.attack1); break; } - PlaySound(attack); } -void audio_play_item_pickup(void) { +void audio_play_item_pickup(GameState *gs) { // High-pitched pickup sound play_tone(800.0f, 0.15f, 0.4f); - Sound pickup = LoadSound("./assets/sounds/itempickup.wav"); - PlaySound(pickup); + PlaySound(gs->sounds.pickup); } -void audio_play_enemy_death(void) { +void audio_play_enemy_death(GameState *gs) { // Descending death sound play_tone(300.0f, 0.1f, 0.5f); play_tone(150.0f, 0.15f, 0.4f); } -void audio_play_player_damage(void) { +void audio_play_player_damage(GameState *gs) { // Harsh damage sound play_tone(150.0f, 0.1f, 0.6f); play_tone(100.0f, 0.1f, 0.4f); } -void audio_play_stairs(void) { +void audio_play_stairs(GameState *gs) { // Ascending stairs sound - Sound staircase = LoadSound("./assets/sounds/levelcomplete.wav"); - PlaySound(staircase); + PlaySound(gs->sounds.staircase); } -void audio_play_dodge(void) { +void audio_play_dodge(GameState *gs) { // High-pitched whoosh // play_tone(900.0f, 0.08f, 0.3f); int choice = GetRandomValue(1, 3); - Sound dodge; switch (choice) { case 1: - dodge = LoadSound("./assets/sounds/dodge1.wav"); + PlaySound(gs->sounds.dodge1); break; case 2: - dodge = LoadSound("./assets/sounds/dodge2.wav"); + PlaySound(gs->sounds.dodge2); break; case 3: - dodge = LoadSound("./assets/sounds/dodge3.wav"); + PlaySound(gs->sounds.dodge3); break; default: - dodge = LoadSound("./assets/sounds/dodge1.wav"); + PlaySound(gs->sounds.dodge1); break; } - PlaySound(dodge); + return; } -void audio_play_block(void) { +void audio_play_block(GameState *gs) { // Low-then-mid metallic clang play_tone(250.0f, 0.06f, 0.5f); play_tone(350.0f, 0.04f, 0.3f); } -void audio_play_crit(void) { +void audio_play_crit(GameState *gs) { // Sharp crack with high-pitched follow - play_tone(600.0f, 0.05f, 0.7f); - play_tone(900.0f, 0.1f, 0.5f); + audio_play_attack(gs); + PlaySound(gs->sounds.crit); } void audio_play_proc(void) { diff --git a/src/audio.h b/src/audio.h index 3c2cb36..56ecd92 100644 --- a/src/audio.h +++ b/src/audio.h @@ -1,5 +1,6 @@ #ifndef AUDIO_H #define AUDIO_H +#include "common.h" // Initialize audio system void audio_init(void); @@ -11,28 +12,28 @@ void audio_close(void); void audio_play_move(void); // Play attack sound -void audio_play_attack(void); +void audio_play_attack(GameState *gs); // Play item pickup sound -void audio_play_item_pickup(void); +void audio_play_item_pickup(GameState *gs); // Play enemy death sound -void audio_play_enemy_death(void); +void audio_play_enemy_death(GameState *gs); // Play player damage sound -void audio_play_player_damage(void); +void audio_play_player_damage(GameState *gs); // Play stairs/level change sound -void audio_play_stairs(void); +void audio_play_stairs(GameState *gs); // Play dodge sound -void audio_play_dodge(void); +void audio_play_dodge(GameState *gs); // Play block sound -void audio_play_block(void); +void audio_play_block(GameState *gs); // Play critical hit sound -void audio_play_crit(void); +void audio_play_crit(GameState *gs); // Play status effect proc sound void audio_play_proc(void); diff --git a/src/common.h b/src/common.h index 9af8771..bd8454d 100644 --- a/src/common.h +++ b/src/common.h @@ -2,6 +2,7 @@ #define COMMON_H #include "settings.h" +#include // Tile types typedef enum { TILE_WALL, TILE_FLOOR, TILE_STAIRS } TileType; @@ -112,6 +113,15 @@ typedef struct { StatusEffectType effect_type; // used to pick color for proc labels } FloatingText; +// AudioAssets +typedef struct { + Sound attack1, attack2, attack3; + Sound pickup; + Sound staircase; + Sound dodge1, dodge2, dodge3; + Sound crit; +} AudioAssets; + // GameState - encapsulates all game state for testability and save/load typedef struct { Player player; @@ -139,6 +149,8 @@ typedef struct { int screen_shake; // frames of screen shake remaining int shake_x; int shake_y; + AudioAssets sounds; } GameState; + #endif // COMMON_H diff --git a/src/main.c b/src/main.c index 153429e..073b84f 100644 --- a/src/main.c +++ b/src/main.c @@ -187,18 +187,18 @@ static void post_action(GameState *gs, Enemy *attacked_enemy) { if (combat_was_dodged()) { spawn_floating_label(gs, ex, ey, "DODGE", EFFECT_NONE); - audio_play_dodge(); + audio_play_dodge(gs); } else { if (combat_get_last_damage() > 0) spawn_floating_text(gs, ex, ey, combat_get_last_damage(), combat_was_critical()); - audio_play_attack(); + audio_play_attack(gs); if (combat_was_blocked()) { spawn_floating_label(gs, ex, ey - 10, "BLOCK", EFFECT_NONE); - audio_play_block(); + audio_play_block(gs); } if (combat_was_critical()) { spawn_floating_label(gs, ex + 8, ey - 10, "CRIT!", EFFECT_NONE); - audio_play_crit(); + audio_play_crit(gs); } StatusEffectType applied = combat_get_applied_effect(); if (applied != EFFECT_NONE) { @@ -207,7 +207,7 @@ static void post_action(GameState *gs, Enemy *attacked_enemy) { } if (!attacked_enemy->alive) { spawn_floating_label(gs, ex, ey - 20, "SLAIN", EFFECT_NONE); - audio_play_enemy_death(); + audio_play_enemy_death(gs); } } } @@ -217,7 +217,7 @@ static void post_action(GameState *gs, Enemy *attacked_enemy) { // Check if player took damage if (combat_was_player_damage() && combat_get_last_damage() > 0) { - audio_play_player_damage(); + audio_play_player_damage(gs); gs->screen_shake = 8; spawn_floating_text(gs, gs->player.x * TILE_SIZE + 8, gs->player.y * TILE_SIZE, combat_get_last_damage(), combat_was_critical()); @@ -349,7 +349,7 @@ static int handle_inventory_input(GameState *gs) { static int handle_descend_input(GameState *gs) { if (IsKeyPressed(KEY_Y)) { if (gs->player.floor < NUM_FLOORS) { - audio_play_stairs(); + audio_play_stairs(gs); init_floor(gs, gs->player.floor + 1); gs->last_message = "Descended to next floor!"; gs->message_timer = 60; @@ -388,7 +388,7 @@ static int handle_movement_input(GameState *gs) { add_log(gs, pickup_msg); gs->last_message = "Picked up item!"; gs->message_timer = 60; - audio_play_item_pickup(); + audio_play_item_pickup(gs); } else { gs->last_message = "Inventory full!"; gs->message_timer = 60; @@ -402,7 +402,7 @@ static int handle_movement_input(GameState *gs) { if (gs->player.inventory_count > 0 && player_use_first_item(&gs->player)) { gs->last_message = "Used potion!"; gs->message_timer = 60; - audio_play_item_pickup(); + audio_play_item_pickup(gs); return 1; } } @@ -468,11 +468,24 @@ static int handle_input(GameState *gs) { return handle_movement_input(gs); } +void load_audio_assets(GameState *gs) { + gs->sounds.attack1 = LoadSound("./assets/sounds/sword1.wav"); + gs->sounds.attack2 = LoadSound("./assets/sounds/sword2.wav"); + gs->sounds.attack3 = LoadSound("./assets/sounds/sword3.wav"); + gs->sounds.pickup = LoadSound("./assets/sounds/itempickup.wav"); + gs->sounds.staircase = LoadSound("./assets/sounds/levelcomplete.wav"); + gs->sounds.dodge1 = LoadSound("./assets/sounds/dodge1.wav"); + gs->sounds.dodge2 = LoadSound("./assets/sounds/dodge2.wav"); + gs->sounds.dodge3 = LoadSound("./assets/sounds/dodge3.wav"); + gs->sounds.crit = LoadSound("./assets/sounds/crit.wav"); + return; +} + // Main game loop static void game_loop(void) { GameState gs; memset(&gs, 0, sizeof(GameState)); - + load_audio_assets(&gs); // Initialize first floor rng_seed(12345); init_floor(&gs, 1);