summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--assets/asm/placeholder.asm7
-rw-r--r--audio/src/channel.rs5
-rw-r--r--audio/src/data.rs46
-rw-r--r--audio/src/lib.rs12
-rw-r--r--audio/src/program.rs17
-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
10 files changed, 155 insertions, 76 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 53073e2..2dbae44 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -185,6 +185,7 @@ name = "game"
version = "0.1.0"
dependencies = [
"argh",
+ "audio",
"dungeon",
"graphics",
]
diff --git a/assets/asm/placeholder.asm b/assets/asm/placeholder.asm
new file mode 100644
index 0000000..6e4e060
--- /dev/null
+++ b/assets/asm/placeholder.asm
@@ -0,0 +1,7 @@
+; note this file does not play anything!
+; its just a placeholder for not yet
+; created audio
+
+; single pause to not
+; cause infinite loop
+-
diff --git a/audio/src/channel.rs b/audio/src/channel.rs
index 48d416b..b74792e 100644
--- a/audio/src/channel.rs
+++ b/audio/src/channel.rs
@@ -149,6 +149,11 @@ impl Channels {
}
}
}
+impl Default for Channels {
+ fn default() -> Self {
+ Self::new()
+ }
+}
pub struct Device<'s> {
pub channels: Arc<Atomic<Channels>>,
diff --git a/audio/src/data.rs b/audio/src/data.rs
deleted file mode 100644
index 934e186..0000000
--- a/audio/src/data.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-use crate::program::Track;
-use std::fs;
-
-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 Data {
- pub explore: Track,
- pub megalovania: Track,
- pub test: Track,
-}
-impl Data {
- pub fn load() -> crate::Result<Self> {
- let explore = load_asm!(
- "assets/asm/explore_melody.asm",
- "assets/asm/explore_harmony1.asm",
- "assets/asm/explore_harmony2.asm"
- );
- let megalovania = load_asm!(
- "assets/asm/megalovania_melody.asm",
- "assets/asm/megalovania_base.asm"
- );
- let test = load_asm!("assets/asm/test.asm");
- Ok(Self {
- explore,
- megalovania,
- test,
- })
- }
-}
diff --git a/audio/src/lib.rs b/audio/src/lib.rs
index 814bcd0..8158c35 100644
--- a/audio/src/lib.rs
+++ b/audio/src/lib.rs
@@ -3,12 +3,12 @@
use raylib::audio::RaylibAudio;
use std::{
collections::BinaryHeap,
+ rc::Rc,
sync::atomic::Ordering,
time::{Duration, Instant},
};
use channel::Device;
-use data::Data;
use crate::{
channel::Channels,
@@ -16,9 +16,8 @@ use crate::{
};
mod channel;
-mod data;
mod parse;
-mod program;
+pub mod program;
/// The `Error` type used within this crate
pub type Error = Box<dyn std::error::Error>;
@@ -36,7 +35,6 @@ pub struct Audio {
device: Device<'static>,
last: Instant,
queue: BinaryHeap<Program>,
- pub data: Data,
}
impl Audio {
pub fn load() -> crate::Result<Self> {
@@ -53,17 +51,15 @@ impl Audio {
let device = Device::load(handle)?;
let last = Instant::now();
let queue = BinaryHeap::new();
- let data = Data::load()?;
Ok(Self {
device,
last,
queue,
- data,
})
}
- pub fn schedule(&mut self, track: Track, priority: u32, looping: bool) {
+ pub fn schedule(&mut self, track: Rc<Track>, priority: u32, looping: bool) {
let program = Program::new(track, priority, looping);
self.queue.push(program);
}
@@ -86,7 +82,7 @@ impl Audio {
res
}
// make the output quiet!
- None => Channels::new(),
+ None => Channels::default(),
};
self.device.channels.store(channels, Ordering::Relaxed);
self.last = Instant::now();
diff --git a/audio/src/program.rs b/audio/src/program.rs
index b775e24..cd050e3 100644
--- a/audio/src/program.rs
+++ b/audio/src/program.rs
@@ -52,22 +52,23 @@ use Instruction as I;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Track {
- pub ins: Rc<Vec<Instruction>>,
+ pub ins: Vec<Instruction>,
}
impl Track {
pub fn parse(src: &str) -> parse::Result<Self> {
- let ins = Rc::new(parse::parse(src)?);
+ let ins = parse::parse(src)?;
Ok(Self { ins })
}
- pub fn merge(self, other: Self) -> Self {
+ #[must_use]
+ pub fn merge(&self, other: &Self) -> Self {
let mut res = vec![];
let mut l = 0;
let mut r = 0;
let mut l_pause = 0;
let mut r_pause = 0;
- let l_ins = self.ins;
- let r_ins = other.ins;
+ let l_ins = &self.ins;
+ let r_ins = &other.ins;
loop {
if l >= l_ins.len() && r >= r_ins.len() {
@@ -124,7 +125,7 @@ impl Track {
}
}
- Self { ins: Rc::new(res) }
+ Self { ins: res }
}
}
impl fmt::Display for Track {
@@ -141,7 +142,7 @@ impl fmt::Display for Track {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Program {
- track: Track,
+ track: Rc<Track>,
priority: u32,
looping: bool,
pc: usize,
@@ -150,7 +151,7 @@ pub struct Program {
channels: Channels,
}
impl Program {
- pub const fn new(track: Track, priority: u32, looping: bool) -> Self {
+ pub const fn new(track: Rc<Track>, priority: u32, looping: bool) -> Self {
Self {
track,
priority,
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),
+ })
+ }
+}