diff --git a/assets/sounds/block1.wav b/assets/sounds/block1.wav new file mode 100644 index 0000000..8008803 Binary files /dev/null and b/assets/sounds/block1.wav differ diff --git a/assets/sounds/block2.wav b/assets/sounds/block2.wav new file mode 100644 index 0000000..e133a6a Binary files /dev/null and b/assets/sounds/block2.wav differ diff --git a/assets/sounds/block3.wav b/assets/sounds/block3.wav new file mode 100644 index 0000000..4a3e1e6 Binary files /dev/null and b/assets/sounds/block3.wav differ 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/assets/sounds/dodge1.wav b/assets/sounds/dodge1.wav new file mode 100644 index 0000000..05b1f71 Binary files /dev/null and b/assets/sounds/dodge1.wav differ diff --git a/assets/sounds/dodge2.wav b/assets/sounds/dodge2.wav new file mode 100644 index 0000000..942ba60 Binary files /dev/null and b/assets/sounds/dodge2.wav differ diff --git a/assets/sounds/dodge3.wav b/assets/sounds/dodge3.wav new file mode 100644 index 0000000..9b0a8c0 Binary files /dev/null and b/assets/sounds/dodge3.wav differ diff --git a/assets/sounds/itempickup.wav b/assets/sounds/itempickup.wav new file mode 100644 index 0000000..714878e Binary files /dev/null and b/assets/sounds/itempickup.wav differ diff --git a/assets/sounds/levelcomplete.wav b/assets/sounds/levelcomplete.wav new file mode 100644 index 0000000..f3abfd0 Binary files /dev/null and b/assets/sounds/levelcomplete.wav differ diff --git a/assets/sounds/sword1.wav b/assets/sounds/sword1.wav new file mode 100644 index 0000000..6afe429 Binary files /dev/null and b/assets/sounds/sword1.wav differ diff --git a/assets/sounds/sword2.wav b/assets/sounds/sword2.wav new file mode 100644 index 0000000..b4d997f Binary files /dev/null and b/assets/sounds/sword2.wav differ diff --git a/assets/sounds/sword3.wav b/assets/sounds/sword3.wav new file mode 100644 index 0000000..633b2ac Binary files /dev/null and b/assets/sounds/sword3.wav differ diff --git a/assets/sounds/uiclick1.wav b/assets/sounds/uiclick1.wav new file mode 100644 index 0000000..e431c89 Binary files /dev/null and b/assets/sounds/uiclick1.wav differ diff --git a/assets/sounds/uiclick2.wav b/assets/sounds/uiclick2.wav new file mode 100644 index 0000000..485932c Binary files /dev/null and b/assets/sounds/uiclick2.wav differ diff --git a/src/audio.c b/src/audio.c index b273369..36db553 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,50 +71,79 @@ 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); + // play_tone(400.0f, 0.1f, 0.5f); + int choice = GetRandomValue(1, 3); + switch (choice) { + case 1: + PlaySound(gs->sounds.attack1); + break; + case 2: + PlaySound(gs->sounds.attack2); + break; + case 3: + PlaySound(gs->sounds.attack3); + break; + default: + PlaySound(gs->sounds.attack1); + break; + } } -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); + 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 - play_tone(400.0f, 0.1f, 0.3f); - play_tone(600.0f, 0.1f, 0.3f); - play_tone(800.0f, 0.15f, 0.3f); + 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); + // play_tone(900.0f, 0.08f, 0.3f); + int choice = GetRandomValue(1, 3); + switch (choice) { + case 1: + PlaySound(gs->sounds.dodge1); + break; + case 2: + PlaySound(gs->sounds.dodge2); + break; + case 3: + PlaySound(gs->sounds.dodge3); + break; + default: + PlaySound(gs->sounds.dodge1); + break; + } + 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 8313f81..073b84f 100644 --- a/src/main.c +++ b/src/main.c @@ -65,12 +65,18 @@ static void spawn_floating_label(GameState *gs, int x, int y, const char *label, static const char *proc_label_for(StatusEffectType effect) { switch (effect) { - case EFFECT_POISON: return "POISON!"; - case EFFECT_BLEED: return "BLEED!"; - case EFFECT_BURN: return "BURN!"; - case EFFECT_STUN: return "STUN!"; - case EFFECT_WEAKEN: return "WEAKEN!"; - default: return ""; + case EFFECT_POISON: + return "POISON!"; + case EFFECT_BLEED: + return "BLEED!"; + case EFFECT_BURN: + return "BURN!"; + case EFFECT_STUN: + return "STUN!"; + case EFFECT_WEAKEN: + return "WEAKEN!"; + default: + return ""; } } @@ -181,17 +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(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) { @@ -200,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); } } } @@ -210,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()); @@ -342,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; @@ -381,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; @@ -395,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; } } @@ -461,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); @@ -553,7 +573,8 @@ static void game_loop(void) { int main(void) { // Initialize audio audio_init(); - + // Initialize random number generator + SetRandomSeed(88435); // Initialize window InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT + 60, "Roguelike"); SetTargetFPS(60);