From b087c645d628548ad32cd0c251c39fb8d128697c Mon Sep 17 00:00:00 2001 From: Alula <6276139+alula@users.noreply.github.com> Date: Fri, 8 Jan 2021 20:25:46 +0100 Subject: [PATCH] android changes --- src/input/touch_controls.rs | 8 ---- src/lib.rs | 4 ++ src/rng.rs | 2 +- src/scene/loading_scene.rs | 60 ++++++++++++++++--------- src/scene/mod.rs | 1 + src/scene/no_data_scene.rs | 88 +++++++++++++++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 30 deletions(-) create mode 100644 src/scene/no_data_scene.rs diff --git a/src/input/touch_controls.rs b/src/input/touch_controls.rs index a30bfb7..e13893e 100644 --- a/src/input/touch_controls.rs +++ b/src/input/touch_controls.rs @@ -99,14 +99,6 @@ impl TouchControls { } pub fn draw(&self, canvas_size: (f32, f32), constants: &EngineConstants, texture_set: &mut TextureSet, ctx: &mut Context) -> GameResult { - let batch = texture_set.get_or_load_batch(ctx, constants, "Caret")?; - let rect = Rect::new_size(104, 120, 24, 24); - for point in self.points.iter() { - batch.add_rect(point.position.0 as f32 - 12.0, point.position.1 as f32 - 12.0, &rect); - } - - batch.draw(ctx)?; - if self.control_type == TouchControlType::Controls { let batch = texture_set.get_or_load_batch(ctx, constants, "builtin/touch")?; let color = (255, 255, 255, 160); diff --git a/src/lib.rs b/src/lib.rs index 815a62d..d7d86d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,6 +249,10 @@ pub fn android_main() { request_perms().expect("Failed to attach to the JVM and request storage permissions."); env::set_var("CAVESTORY_DATA_DIR", "/storage/emulated/0/doukutsu"); + + let _ = std::fs::create_dir("/storage/emulated/0/doukutsu/"); + let _ = std::fs::write("/storage/emulated/0/doukutsu/.nomedia", b""); + init().unwrap(); } diff --git a/src/rng.rs b/src/rng.rs index 78422c9..c88a332 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -5,7 +5,7 @@ pub trait RNG { fn next(&self) -> i32; fn range(&self, range: Range) -> i32 { - range.start.wrapping_add((self.next() >> 2) % (range.end.wrapping_sub(range.start).wrapping_add(1))) + range.start.saturating_add((self.next() >> 2) % range.len() as i32) } } diff --git a/src/scene/loading_scene.rs b/src/scene/loading_scene.rs index d9cf57a..c760954 100644 --- a/src/scene/loading_scene.rs +++ b/src/scene/loading_scene.rs @@ -1,5 +1,7 @@ use ggez::{Context, filesystem, GameResult}; + use crate::npc::NPCTable; +use crate::scene::no_data_scene::NoDataScene; use crate::scene::Scene; use crate::shared_game_state::SharedGameState; use crate::stage::StageData; @@ -15,30 +17,40 @@ impl LoadingScene { tick: 0, } } + + fn load_stuff(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + let stages = StageData::load_stage_table(ctx, &state.base_path)?; + state.stages = stages; + let npc_tbl = filesystem::open(ctx, [&state.base_path, "/npc.tbl"].join(""))?; + let npc_table = NPCTable::load_from(npc_tbl)?; + state.npc_table = npc_table; + let head_tsc = filesystem::open(ctx, [&state.base_path, "/Head.tsc"].join(""))?; + let head_script = TextScript::load_from(head_tsc, &state.constants)?; + state.textscript_vm.set_global_script(head_script); + + let arms_item_tsc = filesystem::open(ctx, [&state.base_path, "/ArmsItem.tsc"].join(""))?; + let arms_item_script = TextScript::load_from(arms_item_tsc, &state.constants)?; + state.textscript_vm.set_inventory_script(arms_item_script); + + let stage_select_tsc = filesystem::open(ctx, [&state.base_path, "/StageSelect.tsc"].join(""))?; + let stage_select_script = TextScript::load_from(stage_select_tsc, &state.constants)?; + state.textscript_vm.set_stage_select_script(stage_select_script); + + state.start_intro(ctx)?; + + Ok(()) + } } impl Scene for LoadingScene { fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { // deferred to let the loading image draw if self.tick == 1 { - let stages = StageData::load_stage_table(ctx, &state.base_path)?; - state.stages = stages; - let npc_tbl = filesystem::open(ctx, [&state.base_path, "/npc.tbl"].join(""))?; - let npc_table = NPCTable::load_from(npc_tbl)?; - state.npc_table = npc_table; - let head_tsc = filesystem::open(ctx, [&state.base_path, "/Head.tsc"].join(""))?; - let head_script = TextScript::load_from(head_tsc, &state.constants)?; - state.textscript_vm.set_global_script(head_script); + if let Err(err) = self.load_stuff(state, ctx) { + log::error!("Failed to load game data: {}", err); - let arms_item_tsc = filesystem::open(ctx, [&state.base_path, "/ArmsItem.tsc"].join(""))?; - let arms_item_script = TextScript::load_from(arms_item_tsc, &state.constants)?; - state.textscript_vm.set_inventory_script(arms_item_script); - - let stage_select_tsc = filesystem::open(ctx, [&state.base_path, "/StageSelect.tsc"].join(""))?; - let stage_select_script = TextScript::load_from(stage_select_tsc, &state.constants)?; - state.textscript_vm.set_stage_select_script(stage_select_script); - - state.start_intro(ctx)?; + state.next_scene = Some(Box::new(NoDataScene::new(err))); + } } self.tick += 1; @@ -46,11 +58,17 @@ impl Scene for LoadingScene { } fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { - let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "Loading")?; + match state.texture_set.get_or_load_batch(ctx, &state.constants, "Loading") { + Ok(batch) => { + batch.add(((state.canvas_size.0 - batch.width() as f32) / 2.0).floor(), + ((state.canvas_size.1 - batch.height() as f32) / 2.0).floor()); + batch.draw(ctx)?; + } + Err(err) => { + state.next_scene = Some(Box::new(NoDataScene::new(err))); + } + } - batch.add(((state.canvas_size.0 - batch.width() as f32) / 2.0).floor(), - ((state.canvas_size.1 - batch.height() as f32) / 2.0).floor()); - batch.draw(ctx)?; Ok(()) } } diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 036b8c3..f0357b0 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -5,6 +5,7 @@ use crate::ui::Components; pub mod game_scene; pub mod loading_scene; +pub mod no_data_scene; pub mod title_scene; /// Implement this trait on any object that represents an interactive game screen. diff --git a/src/scene/no_data_scene.rs b/src/scene/no_data_scene.rs new file mode 100644 index 0000000..5706e04 --- /dev/null +++ b/src/scene/no_data_scene.rs @@ -0,0 +1,88 @@ +use ggez::{Context, GameError, GameResult}; + +use crate::common::Rect; +use crate::scene::Scene; +use crate::shared_game_state::SharedGameState; + +pub struct NoDataScene { + flag: bool, + err: String, +} + +impl NoDataScene { + pub fn new(err: GameError) -> Self { + Self { + flag: false, + err: err.to_string(), + } + } +} + +static REL_URL: &str = "https://github.com/doukutsu-rs/game-data/releases"; + +impl Scene for NoDataScene { + fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + + #[cfg(target_os = "android")] + { + if !self.flag { + self.flag = true; + let _ = std::fs::create_dir("/sdcard/doukutsu/"); + let _ = std::fs::write("/sdcard/doukutsu/extract game data here.txt", REL_URL); + let _ = std::fs::write("/sdcard/doukutsu/.nomedia", b""); + } + + let screen = Rect::new(0, 0, state.canvas_size.0 as isize, state.canvas_size.1 as isize); + if state.touch_controls.consume_click_in(screen) { + if let Err(err) = webbrowser::open(REL_URL) { + self.err = err.to_string(); + } + } + } + Ok(()) + } + + fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + { + let die = "doukutsu-rs internal error"; + let die_width = state.font.text_width(die.chars().clone(), &state.constants); + state.font.draw_colored_text(die.chars(), (state.canvas_size.0 - die_width) / 2.0, 10.0, + (255, 100, 100, 255), &state.constants, &mut state.texture_set, ctx)?; + } + + { + let ftl = "Failed to load game data."; + let ftl_width = state.font.text_width(ftl.chars().clone(), &state.constants); + state.font.draw_colored_text(ftl.chars(), (state.canvas_size.0 - ftl_width) / 2.0, 30.0, + (255, 100, 100, 255), &state.constants, &mut state.texture_set, ctx)?; + } + + #[cfg(target_os = "android")] + { + let ftl = "It's likely that you haven't extracted the game data properly."; + let ftl2 = "Click here to open the guide."; + let ftl_width = state.font.text_width(ftl.chars().clone(), &state.constants); + let ftl2_width = state.font.text_width(ftl2.chars().clone(), &state.constants); + let ftl3_width = state.font.text_width(REL_URL.chars().clone(), &state.constants); + + state.font.draw_colored_text(ftl.chars(), (state.canvas_size.0 - ftl_width) / 2.0, 60.0, + (255, 255, 0, 255), &state.constants, &mut state.texture_set, ctx)?; + + + state.font.draw_colored_text(ftl2.chars(), (state.canvas_size.0 - ftl2_width) / 2.0, 80.0, + (255, 255, 0, 255), &state.constants, &mut state.texture_set, ctx)?; + + state.font.draw_colored_text(REL_URL.chars(), (state.canvas_size.0 - ftl3_width) / 2.0, 100.0, + (255, 255, 0, 255), &state.constants, &mut state.texture_set, ctx)?; + } + + { + let err_width = state.font.text_width(self.err.chars().clone(), &state.constants); + state.font.draw_text(self.err.chars(), (state.canvas_size.0 - err_width) / 2.0, 140.0, + &state.constants, &mut state.texture_set, ctx)?; + } + + + Ok(()) + } +}