mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-11-22 21:52:46 +00:00
Initial jukebox scene
This commit is contained in:
parent
1fe00d25c6
commit
dfcf2e2f3f
|
@ -1667,6 +1667,7 @@ impl EngineConstants {
|
|||
self.tex_sizes.insert("bkMoon".to_owned(), (427, 240));
|
||||
self.tex_sizes.insert("bkFog".to_owned(), (427, 240));
|
||||
self.tex_sizes.insert("ui".to_owned(), (128, 32));
|
||||
self.tex_sizes.insert("uimusic".to_owned(), (192, 144));
|
||||
self.title.logo_rect = Rect { left: 0, top: 0, right: 214, bottom: 62 };
|
||||
self.inventory_dim_color = Color::from_rgba(0, 0, 32, 150);
|
||||
self.textscript.encoding = TextScriptEncoding::UTF8;
|
||||
|
|
|
@ -9,9 +9,7 @@ pub struct CombinedMenuController {
|
|||
|
||||
impl CombinedMenuController {
|
||||
pub fn new() -> CombinedMenuController {
|
||||
CombinedMenuController {
|
||||
controllers: Vec::new(),
|
||||
}
|
||||
CombinedMenuController { controllers: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn update(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
|
@ -91,4 +89,24 @@ impl CombinedMenuController {
|
|||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn trigger_shift_left(&self) -> bool {
|
||||
for cont in &self.controllers {
|
||||
if cont.trigger_prev_weapon() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn trigger_shift_right(&self) -> bool {
|
||||
for cont in &self.controllers {
|
||||
if cont.trigger_next_weapon() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
277
src/scene/jukebox_scene.rs
Normal file
277
src/scene/jukebox_scene.rs
Normal file
|
@ -0,0 +1,277 @@
|
|||
use itertools::Itertools;
|
||||
|
||||
use crate::common::Color;
|
||||
use crate::common::Rect;
|
||||
use crate::components::background::Background;
|
||||
use crate::frame::Frame;
|
||||
use crate::framework::context::Context;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::framework::filesystem;
|
||||
use crate::input::combined_menu_controller::CombinedMenuController;
|
||||
use crate::input::touch_controls::TouchControlType;
|
||||
use crate::map::Map;
|
||||
use crate::scene::title_scene::TitleScene;
|
||||
use crate::scene::Scene;
|
||||
use crate::shared_game_state::{SharedGameState, TileSize};
|
||||
use crate::stage::{BackgroundType, NpcType, Stage, StageData, StageTexturePaths, Tileset};
|
||||
pub struct JukeboxScene {
|
||||
selected_song: u16,
|
||||
song_list: Vec<String>,
|
||||
soundtracks: Vec<String>,
|
||||
controller: CombinedMenuController,
|
||||
background: Background,
|
||||
frame: Frame,
|
||||
stage: Stage,
|
||||
textures: StageTexturePaths,
|
||||
}
|
||||
|
||||
impl JukeboxScene {
|
||||
pub fn new() -> JukeboxScene {
|
||||
let fake_stage = Stage {
|
||||
map: Map { width: 0, height: 0, tiles: vec![], attrib: [0; 0x100], tile_size: TileSize::Tile16x16 },
|
||||
data: StageData {
|
||||
name: "".to_string(),
|
||||
map: "".to_string(),
|
||||
boss_no: 0,
|
||||
tileset: Tileset { name: "0".to_string() },
|
||||
pxpack_data: None,
|
||||
background: crate::stage::Background::new("bkMoon"),
|
||||
background_type: BackgroundType::Outside,
|
||||
background_color: Color { r: 0.0, g: 0.0, b: 0.0, a: 0.0 },
|
||||
npc1: NpcType::new("0"),
|
||||
npc2: NpcType::new("0"),
|
||||
},
|
||||
};
|
||||
|
||||
let mut textures = StageTexturePaths::new();
|
||||
textures.update(&fake_stage);
|
||||
|
||||
JukeboxScene {
|
||||
selected_song: 0,
|
||||
song_list: Vec::new(),
|
||||
soundtracks: Vec::new(),
|
||||
controller: CombinedMenuController::new(),
|
||||
background: Background::new(),
|
||||
frame: Frame::new(),
|
||||
stage: fake_stage,
|
||||
textures,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Scene for JukeboxScene {
|
||||
fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
self.controller.add(state.settings.create_player1_controller());
|
||||
self.controller.add(state.settings.create_player2_controller());
|
||||
|
||||
self.song_list = state.constants.music_table.iter().filter(|song| !song.contains("fanfale")).cloned().collect();
|
||||
|
||||
let mut soundtrack_entries = state.constants.soundtracks.keys().map(|s| s.to_owned()).collect_vec();
|
||||
soundtrack_entries.push("Organya".to_owned());
|
||||
|
||||
if let Ok(dir) = filesystem::read_dir(ctx, "/Soundtracks/") {
|
||||
for entry in dir {
|
||||
if filesystem::is_dir(ctx, &entry) {
|
||||
let filename = entry.file_name().unwrap().to_string_lossy().to_string();
|
||||
|
||||
if !soundtrack_entries.contains(&filename) {
|
||||
soundtrack_entries.push(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.soundtracks = soundtrack_entries.clone();
|
||||
state.settings.soundtrack = "Organya".to_owned();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
self.controller.update(state, ctx)?;
|
||||
self.controller.update_trigger();
|
||||
|
||||
self.background.tick()?;
|
||||
|
||||
let mut song = self.selected_song as i16
|
||||
+ if self.controller.trigger_right() {
|
||||
1
|
||||
} else if self.controller.trigger_left() {
|
||||
-1
|
||||
} else if self.controller.trigger_down() {
|
||||
8
|
||||
} else if self.controller.trigger_up() {
|
||||
-8
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if song < 0 {
|
||||
song += self.song_list.len() as i16;
|
||||
} else {
|
||||
song %= self.song_list.len() as i16;
|
||||
};
|
||||
|
||||
self.selected_song = song as u16;
|
||||
|
||||
if self.controller.trigger_ok() {
|
||||
let song_id = state
|
||||
.constants
|
||||
.music_table
|
||||
.iter()
|
||||
.position(|song_comp| song_comp == &self.song_list[song as usize])
|
||||
.unwrap_or(0);
|
||||
|
||||
state.sound_manager.play_song(song_id, &state.constants, &state.settings, ctx)?;
|
||||
}
|
||||
|
||||
if self.controller.trigger_shift_left() {
|
||||
self.soundtracks.rotate_left(1);
|
||||
state.settings.soundtrack = self.soundtracks.last().unwrap().to_string();
|
||||
state.sound_manager.reload_songs(&state.constants, &state.settings, ctx)?;
|
||||
}
|
||||
|
||||
if self.controller.trigger_shift_right() {
|
||||
self.soundtracks.rotate_right(1);
|
||||
state.settings.soundtrack = self.soundtracks.last().unwrap().to_string();
|
||||
state.sound_manager.reload_songs(&state.constants, &state.settings, ctx)?;
|
||||
}
|
||||
|
||||
if self.controller.trigger_back() {
|
||||
state.next_scene = Some(Box::new(TitleScene::new()));
|
||||
}
|
||||
|
||||
// todo Touch controls
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
self.background.draw(state, ctx, &self.frame, &self.textures, &self.stage)?;
|
||||
|
||||
let block_size = 32.0;
|
||||
let buffer = 4.0;
|
||||
let init_x = (state.canvas_size.0 / 2.0) - (block_size * 4.0) - 10.0;
|
||||
let init_y = (state.canvas_size.1 / 2.0) - (block_size * 2.0);
|
||||
|
||||
let num_songs = self.song_list.len();
|
||||
let mut rect = Rect { left: 0_u16, top: 0, right: 0, bottom: 0 };
|
||||
|
||||
fn selected(mut rect: Rect<u16>, offset: u16) -> Rect<u16> {
|
||||
rect.left += offset;
|
||||
rect.right += offset;
|
||||
rect
|
||||
}
|
||||
|
||||
// Draw Song Boxes
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "uimusic")?;
|
||||
|
||||
for iter in 0..num_songs {
|
||||
rect.left = (iter as u16 % 8) * 24;
|
||||
rect.top = (iter as u16 / 8) * 24;
|
||||
rect.right = rect.left + 24;
|
||||
rect.bottom = rect.top + 24;
|
||||
|
||||
batch.add_rect(
|
||||
init_x + (iter % 8) as f32 * (block_size + buffer),
|
||||
init_y + (iter / 8) as f32 * (block_size + buffer),
|
||||
&rect,
|
||||
);
|
||||
}
|
||||
|
||||
batch.draw(ctx)?;
|
||||
|
||||
// Draw Selection Boxes
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "ui")?;
|
||||
|
||||
for iter in 0..num_songs {
|
||||
let left = (iter as u16 % 8) as f32 * (block_size + buffer) - 4.0;
|
||||
let top = (iter as u16 / 8) as f32 * (block_size + buffer) - 4.0;
|
||||
let right = left + block_size - buffer;
|
||||
let bottom = top + block_size - buffer;
|
||||
|
||||
let selected_offset = if iter == self.selected_song as usize { 16 } else { 0 };
|
||||
|
||||
batch.add_rect(
|
||||
init_x + left,
|
||||
init_y + top,
|
||||
&selected(state.constants.title.menu_left_top, selected_offset),
|
||||
);
|
||||
batch.add_rect(
|
||||
init_x + right,
|
||||
init_y + top,
|
||||
&selected(state.constants.title.menu_right_top, selected_offset),
|
||||
);
|
||||
batch.add_rect(
|
||||
init_x + left,
|
||||
init_y + bottom,
|
||||
&selected(state.constants.title.menu_left_bottom, selected_offset),
|
||||
);
|
||||
batch.add_rect(
|
||||
init_x + right,
|
||||
init_y + bottom,
|
||||
&selected(state.constants.title.menu_right_bottom, selected_offset),
|
||||
);
|
||||
|
||||
let mut rect = state.constants.title.menu_top;
|
||||
let mut rect2 = state.constants.title.menu_bottom;
|
||||
let mut x = init_x + left + rect.height() as f32;
|
||||
let mut y = init_y + top + rect.height() as f32;
|
||||
let mut width = (block_size - buffer) as u16 - rect2.height();
|
||||
let mut height = (block_size - buffer) as u16 - rect2.height();
|
||||
|
||||
while width > 0 {
|
||||
rect.right = if width >= rect.width() {
|
||||
width = width.saturating_sub(rect.width());
|
||||
rect.right
|
||||
} else {
|
||||
let old_width = width;
|
||||
width = 0;
|
||||
rect.left + old_width
|
||||
};
|
||||
rect2.right = rect.right;
|
||||
|
||||
batch.add_rect(x, y - rect.height() as f32, &selected(rect, selected_offset));
|
||||
batch.add_rect(x, y + block_size - buffer - rect.height() as f32, &selected(rect2, selected_offset));
|
||||
x += rect.width() as f32;
|
||||
}
|
||||
|
||||
x = init_x + left;
|
||||
rect = state.constants.title.menu_left;
|
||||
rect2 = state.constants.title.menu_right;
|
||||
while height > 0 {
|
||||
rect.bottom = if height >= rect.height() {
|
||||
height = height.saturating_sub(rect.height());
|
||||
rect.bottom
|
||||
} else {
|
||||
let old_height = height;
|
||||
height = 0;
|
||||
rect.top + old_height
|
||||
};
|
||||
rect2.bottom = rect.bottom;
|
||||
|
||||
batch.add_rect(x, y, &selected(rect, selected_offset));
|
||||
batch.add_rect(x + block_size - buffer, y, &selected(rect2, selected_offset));
|
||||
y += rect.height() as f32;
|
||||
}
|
||||
}
|
||||
|
||||
batch.draw(ctx)?;
|
||||
|
||||
// Write Soundtrack name
|
||||
|
||||
let text = &state.settings.soundtrack;
|
||||
|
||||
let width = state.font.text_width(text.chars(), &state.constants);
|
||||
state.font.draw_text(
|
||||
text.chars(),
|
||||
((state.canvas_size.0 - width) / 2.0).floor(),
|
||||
20.0,
|
||||
&state.constants,
|
||||
&mut state.texture_set,
|
||||
ctx,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ use crate::shared_game_state::SharedGameState;
|
|||
#[cfg(feature = "editor")]
|
||||
pub mod editor_scene;
|
||||
pub mod game_scene;
|
||||
pub mod jukebox_scene;
|
||||
pub mod loading_scene;
|
||||
pub mod no_data_scene;
|
||||
pub mod title_scene;
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::map::Map;
|
|||
use crate::menu::save_select_menu::SaveSelectMenu;
|
||||
use crate::menu::settings_menu::SettingsMenu;
|
||||
use crate::menu::{Menu, MenuEntry, MenuSelectionResult};
|
||||
use crate::scene::jukebox_scene::JukeboxScene;
|
||||
use crate::scene::Scene;
|
||||
use crate::shared_game_state::{MenuCharacter, SharedGameState, TileSize};
|
||||
use crate::stage::{BackgroundType, NpcType, Stage, StageData, StageTexturePaths, Tileset};
|
||||
|
@ -149,6 +150,11 @@ impl Scene for TitleScene {
|
|||
} else {
|
||||
self.main_menu.push_entry(MenuEntry::Hidden);
|
||||
}
|
||||
if state.constants.is_switch {
|
||||
self.main_menu.push_entry(MenuEntry::Active("Jukebox".to_string()));
|
||||
} else {
|
||||
self.main_menu.push_entry(MenuEntry::Hidden);
|
||||
}
|
||||
self.main_menu.push_entry(MenuEntry::Active("Quit".to_string()));
|
||||
|
||||
self.settings_menu.init(state, ctx)?;
|
||||
|
@ -204,6 +210,9 @@ impl Scene for TitleScene {
|
|||
}
|
||||
}
|
||||
MenuSelectionResult::Selected(4, _) => {
|
||||
state.next_scene = Some(Box::new(JukeboxScene::new()));
|
||||
}
|
||||
MenuSelectionResult::Selected(5, _) => {
|
||||
state.shutdown();
|
||||
}
|
||||
_ => {}
|
||||
|
|
Loading…
Reference in a new issue