summaryrefslogtreecommitdiff
path: root/game
diff options
context:
space:
mode:
Diffstat (limited to 'game')
-rw-r--r--game/Cargo.toml1
-rw-r--r--game/src/lib.rs64
-rw-r--r--game/src/main.rs4
-rw-r--r--game/src/music.rs74
4 files changed, 129 insertions, 14 deletions
diff --git a/game/Cargo.toml b/game/Cargo.toml
index 5cdf4af..3371f50 100644
--- a/game/Cargo.toml
+++ b/game/Cargo.toml
@@ -8,6 +8,7 @@ publish.workspace = true
rust-version.workspace = true
[dependencies]
+audio.workspace = true
argh.workspace = true
dungeon.workspace = true
graphics.workspace = true
diff --git a/game/src/lib.rs b/game/src/lib.rs
index 436d488..6e09a37 100644
--- a/game/src/lib.rs
+++ b/game/src/lib.rs
@@ -1,28 +1,53 @@
+use std::rc::Rc;
+
use dungeon::{
Dungeon, UpdateResult, entity::Item, map::Tile, player::PLAYER_INVENTORY_SIZE_USIZE,
player_input::PlayerInput, pos::Direction,
};
use graphics::{Key, Window};
+use crate::music::Music;
+
+mod music;
+
+macro_rules! play_sound {
+ ($self:expr, $sound:expr) => {
+ $self.window.audio().schedule(
+ Rc::clone(&$sound.track),
+ $sound.priority,
+ $sound.looping,
+ );
+ };
+}
+
+/// The `Error` type used within this crate
+pub type Error = Box<dyn std::error::Error>;
+
+/// The `Result` type used witin this crate
+pub type Result<T> = std::result::Result<T, crate::Error>;
+
pub struct Game {
window: Window,
dungeon: Dungeon,
+ music: Music,
// to ensure the most recently-pressed direction key is used:
current_dir: Option<(Direction, Key)>,
}
impl Game {
- pub fn new(window: Window, seed: Option<u64>) -> Self {
+ pub fn new(window: Window, seed: Option<u64>) -> Result<Self> {
+ let music = Music::load()?;
let dungeon = match seed {
Some(s) => Dungeon::new(s),
None => Dungeon::random(),
};
-
- Self {
+ let game = Self {
window,
dungeon,
+ music,
current_dir: None,
- }
+ };
+ Ok(game)
}
fn player_dir(&mut self) -> Option<Direction> {
@@ -79,9 +104,7 @@ impl Game {
}
pub fn run(&mut self) {
- //// debug music
- //let track = self.window.audio().data.test.clone();
- //self.window.audio().schedule(track, 1, true);
+ play_sound!(self, &self.music.background);
// Main game loop
while self.window.is_open() {
@@ -100,19 +123,36 @@ impl Game {
.dungeon
.update(inputs, self.window.delta_time().as_secs_f32());
match result {
- UpdateResult::Default(_action) => {
- // TODO: make noises for player actions
+ UpdateResult::Default(action) => {
+ // items
+ if action.bomb {
+ play_sound!(self, &self.music.use_bomb);
+ } else if action.potion {
+ play_sound!(self, &self.music.use_potion);
+ } else if action.drop_item {
+ play_sound!(self, &self.music.drop_item);
+ } else if action.pickup_item {
+ play_sound!(self, &self.music.pickup_item);
+ }
+
+ // actions
+ if action.attack {
+ play_sound!(self, &self.music.attack);
+ } else if action.walk {
+ // TODO: do we want walking sounds? (were a ghost)
+ }
}
UpdateResult::NextFloor => {
- // TODO: stairs audio
+ play_sound!(self, &self.music.discover);
}
UpdateResult::MessageUpdated(changed) => {
if changed {
- //self.window.audio().speak.play();
+ play_sound!(self, &self.music.speak);
}
}
UpdateResult::GameOver => {
- // TODO: player game over music, very sad
+ self.window.audio().clear();
+ play_sound!(self, &self.music.game_over);
}
UpdateResult::Nothing => {}
}
diff --git a/game/src/main.rs b/game/src/main.rs
index cf82239..353c521 100644
--- a/game/src/main.rs
+++ b/game/src/main.rs
@@ -16,7 +16,7 @@ struct Args {
seed: Option<u64>,
}
-fn run() -> graphics::Result<()> {
+fn run() -> game::Result<()> {
// Parse arguments
let args: Args = argh::from_env();
// Load the window
@@ -24,7 +24,7 @@ fn run() -> graphics::Result<()> {
.vsync(args.vsync)
.verbose(args.verbose)
.build()?;
- Game::new(window, args.seed).run();
+ Game::new(window, args.seed)?.run();
Ok(())
}
diff --git a/game/src/music.rs b/game/src/music.rs
new file mode 100644
index 0000000..366e79d
--- /dev/null
+++ b/game/src/music.rs
@@ -0,0 +1,74 @@
+use audio::program::Track;
+use std::{fs, rc::Rc};
+
+macro_rules! load_asm {
+ ($path:tt) => {{
+ let res = if cfg!(any(feature = "static", target_arch = "wasm32")) {
+ let src = include_str!(concat!("../../", $path));
+ Track::parse(src)
+ } else {
+ let src = fs::read_to_string($path)?;
+ Track::parse(&src)
+ };
+ res.map_err(|mut err| {
+ err.file = Some(String::from($path));
+ err
+ })?
+ }};
+ ($first:tt, $($arg:tt),*) => {
+ load_asm!($first)$(.merge(&load_asm!($arg)))*
+ };
+}
+
+pub struct Sound {
+ pub track: Rc<Track>,
+ pub looping: bool,
+ pub priority: u32,
+}
+impl Sound {
+ fn new(track: Track, looping: bool, priority: u32) -> Self {
+ Self {
+ track: Rc::new(track),
+ looping,
+ priority,
+ }
+ }
+}
+
+pub struct Music {
+ pub attack: Sound,
+ pub discover: Sound,
+ pub background: Sound,
+ pub game_over: Sound,
+ pub speak: Sound,
+ pub use_potion: Sound,
+ pub use_bomb: Sound,
+ pub drop_item: Sound,
+ pub pickup_item: Sound,
+}
+impl Music {
+ pub fn load() -> crate::Result<Self> {
+ // TODO: create REAL audio files
+ let attack = load_asm!("assets/asm/placeholder.asm");
+ let discover = load_asm!("assets/asm/placeholder.asm");
+ let background = load_asm!("assets/asm/placeholder.asm");
+ let game_over = load_asm!("assets/asm/placeholder.asm");
+ let speak = load_asm!("assets/asm/placeholder.asm");
+ let use_potion = load_asm!("assets/asm/placeholder.asm");
+ let use_bomb = load_asm!("assets/asm/placeholder.asm");
+ let drop_item = load_asm!("assets/asm/placeholder.asm");
+ let pickup_item = load_asm!("assets/asm/placeholder.asm");
+
+ Ok(Self {
+ attack: Sound::new(attack, false, 2),
+ discover: Sound::new(discover, false, 3),
+ background: Sound::new(background, true, 1),
+ game_over: Sound::new(game_over, true, 1),
+ speak: Sound::new(speak, false, 2),
+ use_potion: Sound::new(use_potion, false, 2),
+ use_bomb: Sound::new(use_bomb, false, 2),
+ drop_item: Sound::new(drop_item, false, 2),
+ pickup_item: Sound::new(pickup_item, false, 2),
+ })
+ }
+}