From 5efd3f3c92f76463c85495a5597e07c81d55ed03 Mon Sep 17 00:00:00 2001
From: Alula <6276139+alula@users.noreply.github.com>
Date: Mon, 29 Mar 2021 23:19:07 +0200
Subject: [PATCH] general cleanup, hooks and android build fix
---
Cargo.toml | 16 +-
app/app/build.gradle | 9 +-
app/app/src/main/AndroidManifest.xml | 2 +-
build.rs | 2 -
drsandroid/Cargo.toml | 14 +
src/main_android.rs => drsandroid/src/lib.rs | 2 +-
src/caret.rs | 26 ++
src/common.rs | 8 +-
src/components/flash.rs | 2 +-
src/components/inventory.rs | 71 ++++-
src/engine_constants/mod.rs | 4 +-
src/engine_constants/npcs.rs | 14 -
src/framework/backend.rs | 4 +-
src/framework/backend_null.rs | 16 +-
src/framework/backend_sdl2.rs | 7 +-
src/framework/filesystem.rs | 4 -
src/framework/vfs.rs | 2 +-
src/hooks.rs | 276 +++++++++++++++++++
src/inventory.rs | 2 -
src/lib.rs | 2 +
src/live_debugger.rs | 2 -
src/map.rs | 1 -
src/npc/ai/balrog.rs | 1 -
src/npc/ai/booster.rs | 1 -
src/npc/ai/chaco.rs | 1 -
src/npc/ai/characters.rs | 1 -
src/npc/ai/curly.rs | 2 +-
src/npc/ai/egg_corridor.rs | 1 -
src/npc/ai/first_cave.rs | 1 -
src/npc/ai/grasstown.rs | 3 +-
src/npc/ai/igor.rs | 1 -
src/npc/ai/intro.rs | 1 -
src/npc/ai/misc.rs | 2 +-
src/npc/ai/outer_wall.rs | 1 -
src/npc/ai/pickups.rs | 1 -
src/npc/ai/quote.rs | 1 -
src/npc/ai/sand_zone.rs | 7 +-
src/npc/ai/santa.rs | 1 -
src/npc/ai/sue.rs | 4 +-
src/npc/ai/toroko.rs | 6 +-
src/npc/ai/weapon_trail.rs | 1 -
src/npc/boss/balfrog.rs | 1 -
src/npc/boss/monster_x.rs | 1 -
src/npc/boss/omega.rs | 1 -
src/npc/list.rs | 1 -
src/npc/mod.rs | 37 ++-
src/npc/utils.rs | 13 +-
src/physics.rs | 2 +-
src/player/mod.rs | 4 +-
src/player/player_hit.rs | 2 +-
src/player/skin/basic.rs | 2 +-
src/profile.rs | 2 +-
src/scene/game_scene.rs | 163 +++++------
src/scene/no_data_scene.rs | 6 +-
src/scene/title_scene.rs | 1 +
src/shared_game_state.rs | 29 +-
src/sound/mod.rs | 2 +-
src/sound/ogg_playback.rs | 12 +-
src/sound/org_playback.rs | 2 +-
src/sound/pixtone.rs | 1 +
src/texture_set.rs | 2 +-
src/weapon/bubbler.rs | 1 -
src/weapon/bullet.rs | 24 +-
63 files changed, 581 insertions(+), 251 deletions(-)
create mode 100644 drsandroid/Cargo.toml
rename src/main_android.rs => drsandroid/src/lib.rs (98%)
create mode 100644 src/hooks.rs
diff --git a/Cargo.toml b/Cargo.toml
index 323be58..346b116 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,14 +15,6 @@ test = false
bench = false
required-features = ["exe"]
-[[example]]
-name = "drsandroid"
-path = "src/main_android.rs"
-crate-type = ["cdylib"]
-test = false
-bench = false
-required-features = ["android"]
-
[profile.release]
lto = 'thin'
panic = 'abort'
@@ -30,12 +22,6 @@ panic = 'abort'
[profile.dev.package."*"]
opt-level = 3
-[profile.dev.build-override]
-opt-level = 1
-
-[profile.release.build-override]
-opt-level = 1
-
[features]
default = ["scripting", "backend-sdl", "ogg-playback", "netplay", "exe"]
ogg-playback = ["lewton"]
@@ -45,6 +31,7 @@ backend-glutin = ["winit", "glutin"]
scripting = ["lua-ffi"]
netplay = []
editor = []
+hooks = ["libc"]
exe = []
android = []
@@ -64,6 +51,7 @@ image = { version = "0.23", default-features = false, features = ["png", "bmp"]
itertools = "0.10"
lazy_static = "1.4.0"
lewton = { version = "0.10.2", optional = true }
+libc = { version = "0.2", optional = true }
log = "0.4"
lua-ffi = { git = "https://github.com/doukutsu-rs/lua-ffi.git", rev = "1ef3caf772d72068297ddf75df06fd2ef8c1daab", optional = true }
lru = "0.6.0"
diff --git a/app/app/build.gradle b/app/app/build.gradle
index 8c9fc1b..7d00ea2 100644
--- a/app/app/build.gradle
+++ b/app/app/build.gradle
@@ -18,7 +18,7 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
- abiFilters 'x86', 'arm64-v8a'
+ abiFilters 'x86', 'arm64-v8a', 'armeabi-v7a'
}
externalNativeBuild {
@@ -69,13 +69,14 @@ println("cargo target: ${project.buildDir.getAbsolutePath()}/rust-target")
cargoNdk {
targets = [
"x86",
+ "arm",
"arm64"
]
- librariesNames = ["libdrsembedded.so"]
+ librariesNames = ["libdrsandroid.so"]
//targetDirectory = "${project.buildDir.getAbsolutePath()}/rust-target"
- module = "../"
+ module = "../drsandroid/"
extraCargoEnv = ["ANDROID_NDK_HOME": android.ndkDirectory]
- extraCargoBuildArguments = ["--no-default-features", "--features", "backend-glutin ogg-playback scripting"]
+ extraCargoBuildArguments = []
verbose = true
buildTypes {
diff --git a/app/app/src/main/AndroidManifest.xml b/app/app/src/main/AndroidManifest.xml
index 0b31cbc..5bccf18 100644
--- a/app/app/src/main/AndroidManifest.xml
+++ b/app/app/src/main/AndroidManifest.xml
@@ -29,7 +29,7 @@
android:screenOrientation="sensorLandscape"
android:launchMode="standard"
android:configChanges="orientation|keyboardHidden|screenSize">
-
+
diff --git a/build.rs b/build.rs
index 96a3ac1..d26903c 100644
--- a/build.rs
+++ b/build.rs
@@ -1,6 +1,4 @@
use std::env;
-use std::fs::File;
-use std::path::PathBuf;
// #[cfg(feature = "generate-gl")]
// use gl_generator::{Api, Fallbacks, Profile, Registry};
diff --git a/drsandroid/Cargo.toml b/drsandroid/Cargo.toml
new file mode 100644
index 0000000..9b0f207
--- /dev/null
+++ b/drsandroid/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "drsandroid"
+version = "0.1.0"
+authors = ["Alula"]
+edition = "2018"
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+ndk = "0.2"
+ndk-glue = "0.2"
+ndk-sys = "0.2"
+doukutsu-rs = { path = "../", default-features = false, features = ["android", "backend-glutin", "ogg-playback", "scripting"] }
diff --git a/src/main_android.rs b/drsandroid/src/lib.rs
similarity index 98%
rename from src/main_android.rs
rename to drsandroid/src/lib.rs
index aaf1695..f1a2832 100644
--- a/src/main_android.rs
+++ b/drsandroid/src/lib.rs
@@ -2,4 +2,4 @@
#[cfg_attr(target_os = "android", ndk_glue::main())]
pub fn android_main() {
doukutsu_rs::init().unwrap();
-}
\ No newline at end of file
+}
diff --git a/src/caret.rs b/src/caret.rs
index 755bc07..05a9d67 100644
--- a/src/caret.rs
+++ b/src/caret.rs
@@ -24,6 +24,32 @@ pub enum CaretType {
PushJumpKey,
}
+impl CaretType {
+ pub fn from_int(id: usize) -> Option {
+ match id {
+ 0 => Some(CaretType::None),
+ 1 => Some(CaretType::Bubble),
+ 2 => Some(CaretType::ProjectileDissipation),
+ 3 => Some(CaretType::Shoot),
+ 4 => Some(CaretType::SnakeAfterimage),
+ 5 => Some(CaretType::Zzz),
+ 6 => Some(CaretType::SnakeAfterimage2),
+ 7 => Some(CaretType::Exhaust),
+ 8 => Some(CaretType::DrownedQuote),
+ 9 => Some(CaretType::QuestionMark),
+ 10 => Some(CaretType::LevelUp),
+ 11 => Some(CaretType::HurtParticles),
+ 12 => Some(CaretType::Explosion),
+ 13 => Some(CaretType::LittleParticles),
+ 14 => Some(CaretType::Unknown),
+ 15 => Some(CaretType::SmallProjectileDissipation),
+ 16 => Some(CaretType::Empty),
+ 17 => Some(CaretType::PushJumpKey),
+ _ => None,
+ }
+ }
+}
+
pub struct Caret {
pub ctype: CaretType,
pub x: i32,
diff --git a/src/common.rs b/src/common.rs
index 08a34fb..28ce1d1 100644
--- a/src/common.rs
+++ b/src/common.rs
@@ -2,7 +2,7 @@ use std::cmp::Ordering;
use std::fmt;
use lazy_static::lazy_static;
-use num_traits::{abs, AsPrimitive, Num};
+use num_traits::{abs, Num};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeTupleStruct;
@@ -21,6 +21,7 @@ lazy_static! {
bitfield! {
#[derive(Clone, Copy)]
+ #[repr(C)]
pub struct Flag(u32);
impl Debug;
@@ -63,6 +64,7 @@ impl Flag {
bitfield! {
#[derive(Clone, Copy)]
+ #[repr(C)]
pub struct Equipment(u16);
impl Debug;
@@ -88,6 +90,7 @@ bitfield! {
bitfield! {
#[derive(Clone, Copy)]
+ #[repr(C)]
pub struct Condition(u16);
impl Debug;
@@ -106,6 +109,7 @@ bitfield! {
bitfield! {
#[derive(Clone, Copy, Serialize, Deserialize)]
+ #[repr(C)]
pub struct ControlFlags(u16);
impl Debug;
@@ -121,6 +125,7 @@ bitfield! {
bitfield! {
#[derive(Clone, Copy)]
+ #[repr(C)]
pub struct BulletFlag(u16);
impl Debug;
pub flag_x01, set_flag_x01: 0; // 0x01
@@ -257,6 +262,7 @@ impl Point {
}
#[derive(Debug, Clone, Copy)]
+#[repr(C)]
pub struct Rect {
pub left: T,
pub top: T,
diff --git a/src/components/flash.rs b/src/components/flash.rs
index 6dc4809..746051a 100644
--- a/src/components/flash.rs
+++ b/src/components/flash.rs
@@ -37,7 +37,7 @@ impl Flash {
}
impl GameEntity<()> for Flash {
- fn tick(&mut self, state: &mut SharedGameState, _custom: ()) -> GameResult<()> {
+ fn tick(&mut self, _state: &mut SharedGameState, _custom: ()) -> GameResult<()> {
match self.state {
FlashState::None => {}
FlashState::Cross(x, y, tick) => {
diff --git a/src/components/inventory.rs b/src/components/inventory.rs
index e825a1e..dda8e85 100644
--- a/src/components/inventory.rs
+++ b/src/components/inventory.rs
@@ -1,30 +1,79 @@
use crate::entity::GameEntity;
-use crate::inventory::Inventory;
-use crate::framework::context::Context;
use crate::frame::Frame;
-use crate::shared_game_state::SharedGameState;
+use crate::framework::context::Context;
use crate::framework::error::GameResult;
+use crate::inventory::Inventory;
+use crate::player::Player;
+use crate::shared_game_state::SharedGameState;
+use crate::text_script::ScriptMode;
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+#[repr(u8)]
+enum InventoryFocus {
+ None,
+ Weapons,
+ Items,
+}
pub struct InventoryUI {
text_y_pos: usize,
tick: usize,
+ current_script: usize,
+ focus: InventoryFocus,
}
impl InventoryUI {
pub fn new() -> InventoryUI {
- InventoryUI {
- text_y_pos: 24,
- tick: 0,
+ InventoryUI { text_y_pos: 24, tick: 0, current_script: 0, focus: InventoryFocus::None }
+ }
+}
+
+impl GameEntity<(&mut Player, &mut Inventory)> for InventoryUI {
+ fn tick(
+ &mut self,
+ state: &mut SharedGameState,
+ (player, inventory): (&mut Player, &mut Inventory),
+ ) -> GameResult<()> {
+ if state.control_flags.control_enabled()
+ && (player.controller.trigger_inventory() || player.controller.trigger_menu_back())
+ {
+ self.focus = InventoryFocus::None;
+ state.textscript_vm.reset();
+ state.textscript_vm.set_mode(ScriptMode::Map);
+ return Ok(());
}
- }
-}
-impl GameEntity<&mut Inventory> for InventoryUI {
- fn tick(&mut self, state: &mut SharedGameState, custom: &mut Inventory) -> GameResult<()> {
+ match self.focus {
+ InventoryFocus::None => {
+ self.focus = InventoryFocus::Weapons;
+ state.textscript_vm.start_script(1004);
+ }
+ InventoryFocus::Weapons => {}
+ InventoryFocus::Items => {}
+ }
+
+ self.tick = self.tick.wrapping_add(1);
+
Ok(())
}
- fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult<()> {
+ fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, _frame: &Frame) -> GameResult<()> {
+ let mut y = 8.0;
+
+ let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "TextBox")?;
+ for i in 0..=18 {
+ let rect = match i {
+ 0 => &state.constants.textscript.inventory_rect_top,
+ 18 => &state.constants.textscript.inventory_rect_bottom,
+ _ => &state.constants.textscript.inventory_rect_middle,
+ };
+
+ batch.add_rect(((state.canvas_size.0 - 244.0) / 2.0).floor(), y, rect);
+ y += 8.0;
+ }
+
+ batch.draw(ctx)?;
+
Ok(())
}
}
diff --git a/src/engine_constants/mod.rs b/src/engine_constants/mod.rs
index b8de0e5..afe3ca8 100644
--- a/src/engine_constants/mod.rs
+++ b/src/engine_constants/mod.rs
@@ -36,8 +36,8 @@ pub struct BoosterConsts {
#[derive(Debug, Copy, Clone)]
pub struct MyCharConsts {
- pub display_bounds: Rect,
- pub hit_bounds: Rect,
+ pub display_bounds: Rect,
+ pub hit_bounds: Rect,
pub life: u16,
pub max_life: u16,
pub control_mode: ControlMode,
diff --git a/src/engine_constants/npcs.rs b/src/engine_constants/npcs.rs
index c4a422f..219211f 100644
--- a/src/engine_constants/npcs.rs
+++ b/src/engine_constants/npcs.rs
@@ -3,8 +3,6 @@ use serde::{Deserialize, Serialize};
use crate::common::Rect;
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
-
-// 360/369 (97.56%) NPCs defined
pub struct NPCConsts {
// pub n000_null: () // Defined in code
@@ -1062,9 +1060,6 @@ pub struct NPCConsts {
#[serde(default = "default_n360_credits_thank_you")]
pub n360_credits_thank_you: Rect,
- #[serde(default = "default_n361_gaudi_dashing")]
- pub n361_gaudi_dashing: [Rect; 4],
-
#[serde(default = "default_b01_omega")]
pub b01_omega: [Rect; 10],
@@ -4744,15 +4739,6 @@ fn default_n360_credits_thank_you() -> Rect {
Rect { left: 0, top: 176, right: 48, bottom: 184 }
}
-fn default_n361_gaudi_dashing() -> [Rect; 4] {
- [
- Rect { left: 48, top: 48, right: 72, bottom: 72 },
- Rect { left: 72, top: 48, right: 96, bottom: 72 },
- Rect { left: 48, top: 72, right: 72, bottom: 96 },
- Rect { left: 72, top: 72, right: 96, bottom: 96 },
- ]
-}
-
fn default_b01_omega() -> [Rect; 10] {
[
Rect { left: 0, top: 0, right: 80, bottom: 56 },
diff --git a/src/framework/backend.rs b/src/framework/backend.rs
index 2359db8..c0250a3 100644
--- a/src/framework/backend.rs
+++ b/src/framework/backend.rs
@@ -1,6 +1,6 @@
use imgui::DrawData;
-use crate::common::{Color, Point, Rect};
+use crate::common::{Color, Rect};
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::framework::graphics::BlendMode;
@@ -21,7 +21,7 @@ pub trait BackendRenderer {
fn present(&mut self) -> GameResult;
- fn prepare_draw(&mut self, width: f32, height: f32) -> GameResult {
+ fn prepare_draw(&mut self, _width: f32, _height: f32) -> GameResult {
Ok(())
}
diff --git a/src/framework/backend_null.rs b/src/framework/backend_null.rs
index 52d6017..6a24cf2 100644
--- a/src/framework/backend_null.rs
+++ b/src/framework/backend_null.rs
@@ -66,7 +66,7 @@ impl BackendTexture for NullTexture {
(self.0, self.1)
}
- fn add(&mut self, command: SpriteBatchCommand) {
+ fn add(&mut self, _command: SpriteBatchCommand) {
}
@@ -82,7 +82,7 @@ impl BackendTexture for NullTexture {
pub struct NullRenderer(RefCell);
impl BackendRenderer for NullRenderer {
- fn clear(&mut self, color: Color) {
+ fn clear(&mut self, _color: Color) {
}
@@ -94,23 +94,23 @@ impl BackendRenderer for NullRenderer {
Ok(Box::new(NullTexture(width, height)))
}
- fn create_texture(&mut self, width: u16, height: u16, data: &[u8]) -> GameResult> {
+ fn create_texture(&mut self, width: u16, height: u16, _data: &[u8]) -> GameResult> {
Ok(Box::new(NullTexture(width, height)))
}
- fn set_blend_mode(&mut self, blend: BlendMode) -> GameResult {
+ fn set_blend_mode(&mut self, _blend: BlendMode) -> GameResult {
Ok(())
}
- fn set_render_target(&mut self, texture: Option<&Box>) -> GameResult {
+ fn set_render_target(&mut self, _texture: Option<&Box>) -> GameResult {
Ok(())
}
- fn draw_rect(&mut self, rect: Rect, color: Color) -> GameResult {
+ fn draw_rect(&mut self, _rect: Rect, _color: Color) -> GameResult {
Ok(())
}
- fn draw_outline_rect(&mut self, rect: Rect, line_width: usize, color: Color) -> GameResult {
+ fn draw_outline_rect(&mut self, _rect: Rect, _line_width: usize, _color: Color) -> GameResult {
Ok(())
}
@@ -118,7 +118,7 @@ impl BackendRenderer for NullRenderer {
unsafe { Ok(&mut *self.0.as_ptr()) }
}
- fn render_imgui(&mut self, draw_data: &DrawData) -> GameResult {
+ fn render_imgui(&mut self, _draw_data: &DrawData) -> GameResult {
Ok(())
}
}
diff --git a/src/framework/backend_sdl2.rs b/src/framework/backend_sdl2.rs
index 83816b3..93f82ab 100644
--- a/src/framework/backend_sdl2.rs
+++ b/src/framework/backend_sdl2.rs
@@ -4,7 +4,7 @@ use std::collections::HashMap;
use std::rc::Rc;
use imgui::internal::RawWrapper;
-use imgui::{ConfigFlags, DrawCmd, DrawData, ImString, Key, MouseCursor, TextureId, Ui};
+use imgui::{ConfigFlags, DrawCmd, DrawData, ImString, Key, MouseCursor, TextureId};
use sdl2::event::{Event, WindowEvent};
use sdl2::keyboard::Scancode;
use sdl2::mouse::{Cursor, SystemCursor};
@@ -17,7 +17,7 @@ use crate::common::{Color, Rect};
use crate::framework::backend::{Backend, BackendEventLoop, BackendRenderer, BackendTexture, SpriteBatchCommand};
use crate::framework::context::Context;
use crate::framework::error::{GameError, GameResult};
-use crate::framework::graphics::{imgui_context, BlendMode};
+use crate::framework::graphics::{BlendMode};
use crate::framework::keyboard::ScanCode;
use crate::framework::ui::init_imgui;
use crate::Game;
@@ -121,7 +121,7 @@ impl BackendEventLoop for SDL2EventLoop {
imgui.io_mut().display_size = [ctx.screen_size.0, ctx.screen_size.1];
}
}
- state.handle_resize(ctx);
+ state.handle_resize(ctx).unwrap();
}
_ => {}
},
@@ -858,7 +858,6 @@ impl ImguiSdl2 {
}
pub fn handle_event(&mut self, imgui: &mut imgui::Context, event: &Event) {
- use sdl2::keyboard;
use sdl2::mouse::MouseButton;
fn set_mod(imgui: &mut imgui::Context, keymod: keyboard::Mod) {
diff --git a/src/framework/filesystem.rs b/src/framework/filesystem.rs
index f2cc450..4b99300 100644
--- a/src/framework/filesystem.rs
+++ b/src/framework/filesystem.rs
@@ -1,11 +1,7 @@
-use std::env;
use std::fmt;
use std::io;
use std::io::SeekFrom;
use std::path;
-use std::path::PathBuf;
-
-use directories::ProjectDirs;
use crate::framework::context::Context;
use crate::framework::error::{GameError, GameResult};
diff --git a/src/framework/vfs.rs b/src/framework/vfs.rs
index 0c73324..96f1f72 100644
--- a/src/framework/vfs.rs
+++ b/src/framework/vfs.rs
@@ -12,7 +12,7 @@
use std::collections::VecDeque;
use std::fmt::{self, Debug};
use std::fs;
-use std::io::{BufRead, Read, Seek, Write};
+use std::io::{Read, Seek, Write};
use std::path::{self, Path, PathBuf};
use crate::framework::error::{GameError, GameResult};
diff --git a/src/hooks.rs b/src/hooks.rs
new file mode 100644
index 0000000..b5878ed
--- /dev/null
+++ b/src/hooks.rs
@@ -0,0 +1,276 @@
+use crate::caret::CaretType;
+use crate::common::Direction;
+use crate::npc::list::NPCList;
+use crate::npc::NPC;
+use crate::player::Player;
+use crate::rng::RNG;
+use crate::shared_game_state::SharedGameState;
+use crate::stage::Stage;
+use crate::weapon::bullet::BulletManager;
+
+pub struct CHooks {
+ handle_npc: unsafe extern "C" fn(callbacks: *const Callbacks, ctx: *const CtxData),
+}
+
+pub struct Callbacks {
+ random: unsafe extern "C" fn(ctx: *mut CtxData, min: i32, max: i32) -> i32,
+ play_sfx: unsafe extern "C" fn(ctx: *mut CtxData, id: u8),
+ set_quake: unsafe extern "C" fn(ctx: *mut CtxData, ticks: u16),
+ set_caret: unsafe extern "C" fn(ctx: *mut CtxData, x: i32, y: i32, id: u16, direction: u8),
+ get_flag: unsafe extern "C" fn(ctx: *mut CtxData, id: u16) -> bool,
+ get_map_data: unsafe extern "C" fn(ctx: *mut CtxData) -> MapData,
+ get_player_info: unsafe extern "C" fn(ctx: *mut CtxData) -> PlayerInfo,
+ update_player_info: unsafe extern "C" fn(ctx: *mut CtxData, player_info: *const PlayerInfo),
+ destroy_npc: unsafe extern "C" fn(ctx: *mut CtxData, npc: *mut NPC),
+ vanish_npc: unsafe extern "C" fn(ctx: *mut CtxData, npc: *mut NPC),
+ create_npc: unsafe extern "C" fn(
+ ctx: *mut CtxData,
+ npc_id: u16,
+ x: i32,
+ y: i32,
+ vel_x: i32,
+ vel_y: i32,
+ direction: u16,
+ parent: u16,
+ min_id: u16,
+ ),
+ get_npc: unsafe extern "C" fn(ctx: *mut CtxData, npc_id: u16) -> *mut NPC,
+ current_npc: unsafe extern "C" fn(ctx: *mut CtxData) -> *mut NPC,
+}
+
+#[repr(C)]
+pub struct PlayerInfo {
+ x: i32,
+ y: i32,
+ vel_x: i32,
+ vel_y: i32,
+ flags: u32,
+ anim_num: u16,
+ cond: u16,
+ shock: u8,
+ direct: u8,
+ up: bool,
+ down: bool,
+}
+
+#[repr(C)]
+pub struct MapData {
+ tiles: *const u8,
+ attrib: *const u8,
+ width: u16,
+ height: u16,
+}
+
+static mut HOOKS: *mut CHooks = std::ptr::null_mut();
+struct CtxData<'a, 'b, 'c, 'd, 'e, 'f>(
+ &'a mut NPC,
+ &'b mut SharedGameState,
+ &'c mut Player,
+ &'d NPCList,
+ &'e mut Stage,
+ &'f BulletManager,
+);
+
+pub fn init_hooks() {
+ #[cfg(target_os = "linux")]
+ unsafe {
+ let module: *mut libc::c_void = libc::dlopen(b"./libdrshooks.so\0".as_ptr() as *const _, libc::RTLD_NOW);
+ if module.is_null() {
+ let error = libc::dlerror();
+ let message = std::ffi::CString::from_raw(error).to_string_lossy().to_string();
+
+ log::warn!("Cannot initialize hooks?: {}", message);
+ return;
+ }
+
+ log::info!("Loaded libhooks...");
+
+ let symbol: *mut libc::c_void = libc::dlsym(module, b"drs_hooks_init\0".as_ptr() as *const _);
+
+ if symbol.is_null() {
+ log::warn!("initialization function hasn't been found in libhooks.");
+ return;
+ }
+
+ let init: unsafe extern "C" fn() -> *mut CHooks = std::mem::transmute(symbol);
+ HOOKS = (init)();
+ }
+
+ #[cfg(target_os = "windows")]
+ unsafe {
+ use winapi::um::libloaderapi::LoadLibraryA;
+ use winapi::um::libloaderapi::GetProcAddress;
+ use winapi::um::errhandlingapi::GetLastError;
+
+ let module = LoadLibraryA(b"drshooks.dll\0".as_ptr() as *const _);
+
+ if module.is_null() {
+ let error = GetLastError();
+
+ log::warn!("Cannot initialize hooks?: {:#x}", error);
+ return;
+ }
+
+ log::info!("Loaded libhooks...");
+
+ let symbol = GetProcAddress(module, b"drs_hooks_init\0".as_ptr() as *const _);
+
+ if symbol.is_null() {
+ log::warn!("initialization function hasn't been found in libhooks.");
+ return;
+ }
+
+ let init: unsafe extern "C" fn() -> *mut CHooks = std::mem::transmute(symbol);
+ HOOKS = (init)();
+ }
+}
+
+pub fn reload_hooks() {}
+
+pub fn run_npc_hook(
+ npc: &mut NPC,
+ state: &mut SharedGameState,
+ players: [&mut Player; 2],
+ npc_list: &NPCList,
+ stage: &mut Stage,
+ bullet_manager: &BulletManager,
+) {
+ unsafe {
+ let mut ctx_data = CtxData(npc, state, players[0], npc_list, stage, bullet_manager);
+
+ unsafe extern "C" fn random(ctx: *mut CtxData, min: i32, max: i32) -> i32 {
+ let ctx = &*ctx;
+
+ ctx.0.rng.range(min..max)
+ };
+
+ unsafe extern "C" fn play_sfx(ctx: *mut CtxData, id: u8) {
+ (*ctx).1.sound_manager.play_sfx(id);
+ }
+
+ unsafe extern "C" fn set_quake(ctx: *mut CtxData, ticks: u16) {
+ (*ctx).1.quake_counter = ticks;
+ }
+
+ unsafe extern "C" fn set_caret(ctx: *mut CtxData, x: i32, y: i32, id: u16, direction: u8) {
+ (*ctx).1.create_caret(
+ x,
+ y,
+ CaretType::from_int(id as usize).unwrap_or(CaretType::None),
+ Direction::from_int_facing(direction as usize).unwrap_or(Direction::Left),
+ );
+ }
+
+ unsafe extern "C" fn get_flag(ctx: *mut CtxData, id: u16) -> bool {
+ (*ctx).1.get_flag(id as usize)
+ }
+
+ unsafe extern "C" fn get_map_data(ctx: *mut CtxData) -> MapData {
+ let stage = &(*ctx).4;
+
+ MapData {
+ tiles: stage.map.tiles.as_ptr(),
+ attrib: stage.map.attrib.as_ptr(),
+ width: stage.map.width,
+ height: stage.map.height,
+ }
+ }
+
+ unsafe extern "C" fn get_player_info(ctx: *mut CtxData) -> PlayerInfo {
+ let player = &(*ctx).2;
+
+ PlayerInfo {
+ x: player.x,
+ y: player.y,
+ vel_x: player.vel_x,
+ vel_y: player.vel_y,
+ flags: player.flags.0,
+ anim_num: player.anim_num,
+ cond: player.cond.0,
+ shock: player.shock_counter,
+ direct: player.direction as u8,
+ up: player.up,
+ down: player.down
+ }
+ }
+
+ unsafe extern "C" fn update_player_info(ctx: *mut CtxData, player_info: *const PlayerInfo) {
+ let mut player = &mut (*ctx).2;
+ let player_info = &(*player_info);
+
+ player.x = player_info.x;
+ player.y = player_info.y;
+ player.vel_x = player_info.vel_x;
+ player.vel_y = player_info.vel_y;
+ player.flags.0 = player_info.flags;
+ player.cond.0 = player_info.cond;
+ player.direction = Direction::from_int(player_info.direct as usize).unwrap_or(Direction::Left);
+ }
+
+ unsafe extern "C" fn create_npc(
+ ctx: *mut CtxData,
+ npc_id: u16,
+ x: i32,
+ y: i32,
+ vel_x: i32,
+ vel_y: i32,
+ direction: u16,
+ parent: u16,
+ min_id: u16,
+ ) {
+ let ctx = &*ctx;
+
+ let mut npc = NPC::create(npc_id, &ctx.1.npc_table);
+ npc.cond.set_alive(true);
+ npc.x = x;
+ npc.y = y;
+ npc.vel_x = vel_x;
+ npc.vel_y = vel_y;
+ npc.direction = Direction::from_int(direction as usize).unwrap_or(Direction::Left);
+ npc.tsc_direction = direction;
+ npc.parent_id = parent;
+
+ let _ = ctx.3.spawn(min_id, npc);
+ };
+
+ unsafe extern "C" fn get_npc(ctx: *mut CtxData, npc_id: u16) -> *mut NPC {
+ (*ctx).3.get_npc(npc_id as usize).unwrap() as *mut NPC
+ }
+
+ unsafe extern "C" fn destroy_npc(ctx: *mut CtxData, npc: *mut NPC) {
+ let npc = &mut (*npc);
+
+ npc.cond.set_explode_die(true);
+ }
+
+ unsafe extern "C" fn vanish_npc(ctx: *mut CtxData, npc: *mut NPC) {
+ let npc = &mut (*npc);
+
+ npc.vanish((*ctx).1);
+ }
+
+ unsafe extern "C" fn current_npc(ctx: *mut CtxData) -> *mut NPC {
+ (*ctx).0 as *mut NPC
+ }
+
+ let callbacks = Callbacks {
+ random,
+ play_sfx,
+ set_quake,
+ set_caret,
+ get_flag,
+ get_map_data,
+ get_player_info,
+ update_player_info,
+ destroy_npc,
+ vanish_npc,
+ create_npc,
+ get_npc,
+ current_npc,
+ };
+
+ if let Some(hook) = HOOKS.as_ref() {
+ (hook.handle_npc)(&callbacks as *const Callbacks, &mut ctx_data as *mut CtxData);
+ }
+ }
+}
diff --git a/src/inventory.rs b/src/inventory.rs
index 35995fc..de1aaf5 100644
--- a/src/inventory.rs
+++ b/src/inventory.rs
@@ -4,8 +4,6 @@ use crate::engine_constants::EngineConstants;
use crate::shared_game_state::SharedGameState;
use crate::weapon::{Weapon, WeaponLevel, WeaponType};
use crate::player::{Player, TargetPlayer};
-use crate::caret::CaretType;
-use crate::common::Direction;
use crate::weapon::bullet::BulletManager;
#[derive(Clone, Copy)]
diff --git a/src/lib.rs b/src/lib.rs
index 05755e2..ab5dc60 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -43,6 +43,8 @@ mod frame;
mod framework;
mod input;
mod inventory;
+#[cfg(feature = "hooks")]
+mod hooks;
mod live_debugger;
mod macros;
mod map;
diff --git a/src/live_debugger.rs b/src/live_debugger.rs
index 76b589a..117e930 100644
--- a/src/live_debugger.rs
+++ b/src/live_debugger.rs
@@ -19,7 +19,6 @@ pub enum ScriptType {
pub struct LiveDebugger {
map_selector_visible: bool,
events_visible: bool,
- hacks_visible: bool,
flags_visible: bool,
npc_inspector_visible: bool,
last_stage_id: usize,
@@ -37,7 +36,6 @@ impl LiveDebugger {
Self {
map_selector_visible: false,
events_visible: false,
- hacks_visible: false,
flags_visible: false,
npc_inspector_visible: false,
last_stage_id: usize::MAX,
diff --git a/src/map.rs b/src/map.rs
index 53950d1..13fd6b3 100644
--- a/src/map.rs
+++ b/src/map.rs
@@ -2,7 +2,6 @@ use std::io;
use byteorder::{LE, ReadBytesExt};
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::str;
diff --git a/src/npc/ai/balrog.rs b/src/npc/ai/balrog.rs
index d76f668..fcf1fc8 100644
--- a/src/npc/ai/balrog.rs
+++ b/src/npc/ai/balrog.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use num_traits::clamp;
diff --git a/src/npc/ai/booster.rs b/src/npc/ai/booster.rs
index 456acf4..d957c46 100644
--- a/src/npc/ai/booster.rs
+++ b/src/npc/ai/booster.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::common::Direction;
diff --git a/src/npc/ai/chaco.rs b/src/npc/ai/chaco.rs
index 2f7177e..5f636e3 100644
--- a/src/npc/ai/chaco.rs
+++ b/src/npc/ai/chaco.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::caret::CaretType;
diff --git a/src/npc/ai/characters.rs b/src/npc/ai/characters.rs
index 9c742bb..0b553a2 100644
--- a/src/npc/ai/characters.rs
+++ b/src/npc/ai/characters.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use num_traits::{abs, clamp};
diff --git a/src/npc/ai/curly.rs b/src/npc/ai/curly.rs
index 6db356c..5a16b75 100644
--- a/src/npc/ai/curly.rs
+++ b/src/npc/ai/curly.rs
@@ -49,7 +49,7 @@ impl NPC {
5 => {
self.action_num = 6;
self.anim_num = 5;
- npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right, 8, state, &self.rng);
+ npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right as usize, 8, state, &self.rng);
}
6 => {
self.anim_num = 5;
diff --git a/src/npc/ai/egg_corridor.rs b/src/npc/ai/egg_corridor.rs
index b2697bb..452ae21 100644
--- a/src/npc/ai/egg_corridor.rs
+++ b/src/npc/ai/egg_corridor.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use num_traits::{abs, clamp};
diff --git a/src/npc/ai/first_cave.rs b/src/npc/ai/first_cave.rs
index 8225295..c84938a 100644
--- a/src/npc/ai/first_cave.rs
+++ b/src/npc/ai/first_cave.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use num_traits::clamp;
diff --git a/src/npc/ai/grasstown.rs b/src/npc/ai/grasstown.rs
index 5945b3d..dc49ddb 100644
--- a/src/npc/ai/grasstown.rs
+++ b/src/npc/ai/grasstown.rs
@@ -3,7 +3,6 @@ use num_traits::clamp;
use crate::caret::CaretType;
use crate::common::{Direction, Rect};
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::npc::{NPCList, NPC};
use crate::player::Player;
@@ -451,7 +450,7 @@ impl NPC {
self.damage = 0;
self.npc_flags.set_shootable(false);
- npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right, 8, state, &self.rng);
+ npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right as usize, 8, state, &self.rng);
self.create_xp_drop(state, npc_list);
state.sound_manager.play_sfx(71);
diff --git a/src/npc/ai/igor.rs b/src/npc/ai/igor.rs
index 1aca8aa..f2b9b9e 100644
--- a/src/npc/ai/igor.rs
+++ b/src/npc/ai/igor.rs
@@ -1,5 +1,4 @@
use crate::common::{CDEG_RAD, Direction};
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::npc::list::NPCList;
use crate::npc::NPC;
diff --git a/src/npc/ai/intro.rs b/src/npc/ai/intro.rs
index 51b36f5..c08a252 100644
--- a/src/npc/ai/intro.rs
+++ b/src/npc/ai/intro.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::caret::CaretType;
diff --git a/src/npc/ai/misc.rs b/src/npc/ai/misc.rs
index 56725ec..073bc1c 100644
--- a/src/npc/ai/misc.rs
+++ b/src/npc/ai/misc.rs
@@ -1045,7 +1045,7 @@ impl NPC {
pub(crate) fn tick_n125_hidden_item(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
if self.life < 990 {
- npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right, 8, state, &self.rng);
+ npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right as usize, 8, state, &self.rng);
self.cond.set_alive(false);
state.sound_manager.play_sfx(70);
diff --git a/src/npc/ai/outer_wall.rs b/src/npc/ai/outer_wall.rs
index 3a53237..2f16a05 100644
--- a/src/npc/ai/outer_wall.rs
+++ b/src/npc/ai/outer_wall.rs
@@ -1,6 +1,5 @@
use num_traits::abs;
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::npc::NPC;
use crate::player::Player;
diff --git a/src/npc/ai/pickups.rs b/src/npc/ai/pickups.rs
index a2804c6..61d712d 100644
--- a/src/npc/ai/pickups.rs
+++ b/src/npc/ai/pickups.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use num_traits::clamp;
diff --git a/src/npc/ai/quote.rs b/src/npc/ai/quote.rs
index fc3f390..ae6d700 100644
--- a/src/npc/ai/quote.rs
+++ b/src/npc/ai/quote.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::common::Direction;
diff --git a/src/npc/ai/sand_zone.rs b/src/npc/ai/sand_zone.rs
index 9e72c0a..2b68d21 100644
--- a/src/npc/ai/sand_zone.rs
+++ b/src/npc/ai/sand_zone.rs
@@ -2,7 +2,6 @@ use num_traits::{abs, clamp};
use crate::caret::CaretType;
use crate::common::{Direction, CDEG_RAD};
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::npc::list::NPCList;
use crate::npc::NPC;
@@ -113,7 +112,7 @@ impl NPC {
}
if self.life <= 100 {
- npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right, 8, state, &self.rng);
+ npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right as usize, 8, state, &self.rng);
state.sound_manager.play_sfx(25);
self.cond.set_alive(false);
@@ -571,7 +570,7 @@ impl NPC {
let parent = self.get_parent_ref_mut(npc_list);
if parent.is_none() || parent.as_ref().unwrap().npc_type == 3 {
self.vanish(state);
- npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right, 4, state, &self.rng);
+ npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right as usize, 4, state, &self.rng);
return Ok(());
}
@@ -668,7 +667,7 @@ impl NPC {
if self.action_counter > 50 {
state.sound_manager.play_sfx(25);
self.vanish(state);
- npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right, 8, state, &self.rng);
+ npc_list.create_death_smoke(self.x, self.y, self.display_bounds.right as usize, 8, state, &self.rng);
}
}
_ => {}
diff --git a/src/npc/ai/santa.rs b/src/npc/ai/santa.rs
index 1743ca0..cbc7da0 100644
--- a/src/npc/ai/santa.rs
+++ b/src/npc/ai/santa.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use num_traits::abs;
diff --git a/src/npc/ai/sue.rs b/src/npc/ai/sue.rs
index 928b962..e1a0e10 100644
--- a/src/npc/ai/sue.rs
+++ b/src/npc/ai/sue.rs
@@ -1,6 +1,4 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
-use num_traits::clamp;
use crate::common::Direction;
use crate::npc::list::NPCList;
@@ -213,7 +211,7 @@ impl NPC {
if self.action_num != 14 {
self.vel_y += 0x40;
- self.vel_x = clamp(self.vel_x, -0x400, 0x400);
+ self.vel_x = self.vel_x.clamp(-0x400, 0x400);
if self.vel_y > 0x5ff {
self.vel_y = 0x5ff;
}
diff --git a/src/npc/ai/toroko.rs b/src/npc/ai/toroko.rs
index 18802b9..71d6e41 100644
--- a/src/npc/ai/toroko.rs
+++ b/src/npc/ai/toroko.rs
@@ -1,6 +1,4 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
-use num_traits::clamp;
use crate::common::Direction;
use crate::npc::NPC;
@@ -149,7 +147,7 @@ impl NPC {
}
self.vel_y += 0x40;
- self.vel_x = clamp(self.vel_x, -0x400, 0x400);
+ self.vel_x = self.vel_x.clamp(-0x400, 0x400);
if self.vel_y > 0x5ff {
self.vel_y = 0x5ff;
@@ -254,7 +252,7 @@ impl NPC {
}
self.vel_y += 0x40;
- self.vel_x = clamp(self.vel_x, -0x400, 0x400);
+ self.vel_x = self.vel_x.clamp(-0x400, 0x400);
if self.vel_y > 0x5ff {
self.vel_y = 0x5ff;
diff --git a/src/npc/ai/weapon_trail.rs b/src/npc/ai/weapon_trail.rs
index d7c0a12..5d1d8a2 100644
--- a/src/npc/ai/weapon_trail.rs
+++ b/src/npc/ai/weapon_trail.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::npc::NPC;
diff --git a/src/npc/boss/balfrog.rs b/src/npc/boss/balfrog.rs
index 59a0ffe..6f7f598 100644
--- a/src/npc/boss/balfrog.rs
+++ b/src/npc/boss/balfrog.rs
@@ -1,4 +1,3 @@
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::caret::CaretType;
diff --git a/src/npc/boss/monster_x.rs b/src/npc/boss/monster_x.rs
index f135a4d..66e64de 100644
--- a/src/npc/boss/monster_x.rs
+++ b/src/npc/boss/monster_x.rs
@@ -3,7 +3,6 @@ use num_traits::{abs, clamp};
use crate::caret::CaretType;
use crate::common::{Direction, Rect, CDEG_RAD};
use crate::components::flash::Flash;
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::npc::boss::BossNPC;
use crate::npc::list::NPCList;
diff --git a/src/npc/boss/omega.rs b/src/npc/boss/omega.rs
index c9b4fdd..c27e548 100644
--- a/src/npc/boss/omega.rs
+++ b/src/npc/boss/omega.rs
@@ -1,7 +1,6 @@
use crate::caret::CaretType;
use crate::common::{Direction, Rect};
use crate::components::flash::Flash;
-use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::npc::boss::BossNPC;
use crate::npc::list::NPCList;
diff --git a/src/npc/list.rs b/src/npc/list.rs
index 84377fe..94a2adc 100644
--- a/src/npc/list.rs
+++ b/src/npc/list.rs
@@ -1,7 +1,6 @@
use std::cell::{Cell, UnsafeCell};
use std::mem::MaybeUninit;
-use crate::framework::context::Context;
use crate::framework::error::{GameResult, GameError};
use crate::npc::NPC;
diff --git a/src/npc/mod.rs b/src/npc/mod.rs
index 324f50f..255020f 100644
--- a/src/npc/mod.rs
+++ b/src/npc/mod.rs
@@ -51,6 +51,7 @@ bitfield! {
/// Represents an NPC object.
#[derive(Debug, Clone)]
+#[repr(C)]
pub struct NPC {
pub id: u16,
pub npc_type: u16,
@@ -83,8 +84,6 @@ pub struct NPC {
/// Raw direction value set by TSC because some NPCs have it set outside 0-4 range,
/// breaking the direction type.
pub tsc_direction: u16,
- pub display_bounds: Rect,
- pub hit_bounds: Rect,
pub parent_id: u16,
pub action_num: u16,
pub anim_num: u16,
@@ -92,8 +91,11 @@ pub struct NPC {
pub event_num: u16,
pub action_counter: u16,
pub action_counter2: u16,
+ pub action_counter3: u16,
pub anim_counter: u16,
pub anim_rect: Rect,
+ pub display_bounds: Rect,
+ pub hit_bounds: Rect,
pub rng: Xoroshiro32PlusPlus,
}
@@ -132,6 +134,7 @@ impl NPC {
event_num: 0,
action_counter: 0,
action_counter2: 0,
+ action_counter3: 0,
anim_counter: 0,
anim_rect: Rect { left: 0, top: 0, right: 0, bottom: 0 },
rng: Xoroshiro32PlusPlus::new(0),
@@ -319,7 +322,13 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager)> for NP
355 => self.tick_n355_quote_and_curly_on_balrog(state, npc_list),
358 => self.tick_n358_misery_credits(state),
359 => self.tick_n359_water_droplet_generator(state, players, npc_list),
- _ => Ok(()),
+ _ => {
+ #[cfg(feature = "hooks")]
+ {
+ crate::hooks::run_npc_hook(self, state, players, npc_list, stage, bullet_manager);
+ }
+ Ok(())
+ },
}?;
if self.shock > 0 {
@@ -394,7 +403,7 @@ impl PhysicalEntity for NPC {
fn offset_y(&self) -> i32 { if self.size >= 3 && !self.cond.drs_boss() { -0x1000 } else { 0 } }
#[inline(always)]
- fn hit_bounds(&self) -> &Rect {
+ fn hit_bounds(&self) -> &Rect {
&self.hit_bounds
}
@@ -552,26 +561,26 @@ impl NPCTable {
self.entries.get(npc_type as usize)
}
- pub fn get_display_bounds(&self, npc_type: u16) -> Rect {
+ pub fn get_display_bounds(&self, npc_type: u16) -> Rect {
if let Some(npc) = self.entries.get(npc_type as usize) {
Rect {
- left: npc.display_bounds.left as usize * 0x200,
- top: npc.display_bounds.top as usize * 0x200,
- right: npc.display_bounds.right as usize * 0x200,
- bottom: npc.display_bounds.bottom as usize * 0x200,
+ left: npc.display_bounds.left as u32 * 0x200,
+ top: npc.display_bounds.top as u32 * 0x200,
+ right: npc.display_bounds.right as u32 * 0x200,
+ bottom: npc.display_bounds.bottom as u32 * 0x200,
}
} else {
Rect { left: 0, top: 0, right: 0, bottom: 0 }
}
}
- pub fn get_hit_bounds(&self, npc_type: u16) -> Rect {
+ pub fn get_hit_bounds(&self, npc_type: u16) -> Rect {
if let Some(npc) = self.entries.get(npc_type as usize) {
Rect {
- left: npc.hit_bounds.left as usize * 0x200,
- top: npc.hit_bounds.top as usize * 0x200,
- right: npc.hit_bounds.right as usize * 0x200,
- bottom: npc.hit_bounds.bottom as usize * 0x200,
+ left: npc.hit_bounds.left as u32 * 0x200,
+ top: npc.hit_bounds.top as u32 * 0x200,
+ right: npc.hit_bounds.right as u32 * 0x200,
+ bottom: npc.hit_bounds.bottom as u32 * 0x200,
}
} else {
Rect { left: 0, top: 0, right: 0, bottom: 0 }
diff --git a/src/npc/utils.rs b/src/npc/utils.rs
index 551c765..f9fc4fa 100644
--- a/src/npc/utils.rs
+++ b/src/npc/utils.rs
@@ -75,6 +75,7 @@ impl NPC {
parent_id: 0,
action_counter: 0,
action_counter2: 0,
+ action_counter3: 0,
anim_counter: 0,
anim_rect: Rect::new(0, 0, 0, 0),
rng: Xoroshiro32PlusPlus::new(0),
@@ -231,9 +232,9 @@ impl NPCList {
}
match npc.size {
- 1 => { self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right, 3, state, &npc.rng); }
- 2 => { self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right, 7, state, &npc.rng); }
- 3 => { self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right, 12, state, &npc.rng); }
+ 1 => { self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 3, state, &npc.rng); }
+ 2 => { self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 7, state, &npc.rng); }
+ 3 => { self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 12, state, &npc.rng); }
_ => {}
};
@@ -297,9 +298,9 @@ impl NPCList {
state.game_flags.set(npc.flag_num as usize, true);
match npc.size {
- 1 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right, 3, state, &npc.rng),
- 2 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right, 7, state, &npc.rng),
- 3 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right, 12, state, &npc.rng),
+ 1 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 3, state, &npc.rng),
+ 2 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 7, state, &npc.rng),
+ 3 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 12, state, &npc.rng),
_ => {}
};
}
diff --git a/src/physics.rs b/src/physics.rs
index 1b056f1..ae66e2e 100644
--- a/src/physics.rs
+++ b/src/physics.rs
@@ -25,7 +25,7 @@ pub trait PhysicalEntity {
fn offset_x(&self) -> i32 { 0 }
fn offset_y(&self) -> i32 { 0 }
- fn hit_bounds(&self) -> &Rect;
+ fn hit_bounds(&self) -> &Rect;
fn set_x(&mut self, x: i32);
fn set_y(&mut self, y: i32);
diff --git a/src/player/mod.rs b/src/player/mod.rs
index 9f4e614..7609d12 100644
--- a/src/player/mod.rs
+++ b/src/player/mod.rs
@@ -57,8 +57,8 @@ pub struct Player {
pub flags: Flag,
pub equip: Equipment,
pub direction: Direction,
- pub display_bounds: Rect,
- pub hit_bounds: Rect,
+ pub display_bounds: Rect,
+ pub hit_bounds: Rect,
pub control_mode: ControlMode,
pub question: bool,
pub booster_fuel: u32,
diff --git a/src/player/player_hit.rs b/src/player/player_hit.rs
index 5be44fe..a164751 100644
--- a/src/player/player_hit.rs
+++ b/src/player/player_hit.rs
@@ -38,7 +38,7 @@ impl PhysicalEntity for Player {
}
#[inline(always)]
- fn hit_bounds(&self) -> &Rect {
+ fn hit_bounds(&self) -> &Rect {
&self.hit_bounds
}
diff --git a/src/player/skin/basic.rs b/src/player/skin/basic.rs
index 45adf4d..5611520 100644
--- a/src/player/skin/basic.rs
+++ b/src/player/skin/basic.rs
@@ -49,7 +49,7 @@ impl PlayerSkin for BasicPlayerSkin {
PlayerAnimationState::FallingUpsideDown => 10,
};
- let y_offset = if self.direction == Direction::Left { 0 } else { 16 }
+ let y_offset = if direction == Direction::Left { 0 } else { 16 }
+ match self.appearance {
PlayerAppearanceState::Default => 0,
PlayerAppearanceState::MimigaMask => 32,
diff --git a/src/profile.rs b/src/profile.rs
index 238c280..572d3b5 100644
--- a/src/profile.rs
+++ b/src/profile.rs
@@ -63,7 +63,7 @@ impl GameProfile {
let weapon_type: Option = FromPrimitive::from_u8(weapon.weapon_id as u8);
if let Some(wtype) = weapon_type {
- let w = game_scene.inventory_player1.add_weapon_data(
+ game_scene.inventory_player1.add_weapon_data(
wtype,
weapon.ammo as u16,
weapon.max_ammo as u16,
diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs
index e7f327c..bd57f19 100644
--- a/src/scene/game_scene.rs
+++ b/src/scene/game_scene.rs
@@ -1,12 +1,12 @@
use log::info;
-use num_traits::{abs, clamp};
use crate::caret::CaretType;
use crate::common::{Color, Direction, FadeDirection, FadeState, fix9_scale, interpolate_fix9_scale, Rect};
use crate::components::boss_life_bar::BossLifeBar;
-use crate::components::draw_common::{Alignment, draw_number};
+use crate::components::draw_common::{Alignment};
use crate::components::flash::Flash;
use crate::components::hud::HUD;
+use crate::components::inventory::InventoryUI;
use crate::components::stage_select::StageSelect;
use crate::entity::GameEntity;
use crate::frame::{Frame, UpdateTarget};
@@ -26,13 +26,12 @@ use crate::player::{Player, TargetPlayer};
use crate::rng::XorShift;
use crate::scene::Scene;
use crate::scene::title_scene::TitleScene;
-use crate::shared_game_state::{Season, SharedGameState};
+use crate::shared_game_state::{SharedGameState};
use crate::stage::{BackgroundType, Stage};
use crate::text_script::{ConfirmSelection, ScriptMode, TextScriptExecutionState, TextScriptLine, TextScriptVM};
use crate::texture_set::SizedBatch;
use crate::weapon::bullet::BulletManager;
use crate::weapon::WeaponType;
-use crate::components::inventory::InventoryUI;
pub struct GameScene {
pub tick: u32,
@@ -53,7 +52,6 @@ pub struct GameScene {
pub boss: BossNPC,
pub bullet_manager: BulletManager,
pub intro_mode: bool,
- water_visible: bool,
tex_background_name: String,
tex_tileset_name: String,
map_name_counter: u16,
@@ -109,7 +107,6 @@ impl GameScene {
boss: BossNPC::new(),
bullet_manager: BulletManager::new(),
intro_mode: false,
- water_visible: true,
tex_background_name,
tex_tileset_name,
map_name_counter: 0,
@@ -471,7 +468,7 @@ impl GameScene {
// switch version uses 1xxx flag to show a flipped version of face
let flip = state.textscript_vm.face > 1000;
// x1xx flag shows a talking animation
- let talking = (state.textscript_vm.face % 1000) > 100;
+ let _talking = (state.textscript_vm.face % 1000) > 100;
let face_num = state.textscript_vm.face % 100;
batch.add_rect_flip(
@@ -827,12 +824,12 @@ impl GameScene {
let mut rect = Rect::new(0, 0, 16, 16);
let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time, state.scale);
- let tile_start_x = clamp(frame_x as i32 / 16, 0, self.stage.map.width as i32) as usize;
- let tile_start_y = clamp(frame_y as i32 / 16, 0, self.stage.map.height as i32) as usize;
+ let tile_start_x = (frame_x as i32 / 16).clamp(0, self.stage.map.width as i32) as usize;
+ let tile_start_y = (frame_y as i32 / 16).clamp(0, self.stage.map.height as i32) as usize;
let tile_end_x =
- clamp((frame_x as i32 + 8 + state.canvas_size.0 as i32) / 16 + 1, 0, self.stage.map.width as i32) as usize;
+ ((frame_x as i32 + 8 + state.canvas_size.0 as i32) / 16 + 1).clamp(0, self.stage.map.width as i32) as usize;
let tile_end_y =
- clamp((frame_y as i32 + 8 + state.canvas_size.1 as i32) / 16 + 1, 0, self.stage.map.height as i32) as usize;
+ ((frame_y as i32 + 8 + state.canvas_size.1 as i32) / 16 + 1).clamp(0, self.stage.map.height as i32) as usize;
if layer == TileLayer::Snack {
rect = state.constants.world.snack_rect;
@@ -898,7 +895,7 @@ impl GameScene {
}
if npc.npc_flags.shootable() {
- npc.life = clamp((npc.life as i32).saturating_sub(bullet.damage as i32), 0, u16::MAX as i32) as u16;
+ npc.life = (npc.life as i32).saturating_sub(bullet.damage as i32).clamp(0, u16::MAX as i32) as u16;
if npc.life == 0 {
if npc.npc_flags.show_damage() {
@@ -1000,7 +997,7 @@ impl GameScene {
npc = unsafe { self.boss.parts.get_unchecked_mut(0) };
}
- npc.life = clamp((npc.life as i32).saturating_sub(bullet.damage as i32), 0, u16::MAX as i32) as u16;
+ npc.life = (npc.life as i32).saturating_sub(bullet.damage as i32).clamp(0, u16::MAX as i32) as u16;
if npc.life == 0 {
npc.life = npc.id;
@@ -1017,7 +1014,7 @@ impl GameScene {
self.npc_list.create_death_smoke(
npc.x,
npc.y,
- npc.display_bounds.right,
+ npc.display_bounds.right as usize,
destroy_count,
state,
&npc.rng,
@@ -1156,14 +1153,14 @@ impl GameScene {
UpdateTarget::Player => {
if self.player2.cond.alive()
&& !self.player2.cond.hidden()
- && abs(self.player1.x - self.player2.x) < 240 * 0x200
- && abs(self.player1.y - self.player2.y) < 200 * 0x200
+ && (self.player1.x - self.player2.x).abs() < 240 * 0x200
+ && (self.player1.y - self.player2.y).abs() < 200 * 0x200
{
self.frame.target_x = (self.player1.target_x * 2 + self.player2.target_x) / 3;
self.frame.target_y = (self.player1.target_y * 2 + self.player2.target_y) / 3;
- self.frame.target_x = clamp(self.frame.target_x, self.player1.x - 0x8000, self.player1.x + 0x8000);
- self.frame.target_y = clamp(self.frame.target_y, self.player1.y, self.player1.y);
+ self.frame.target_x = self.frame.target_x.clamp(self.player1.x - 0x8000, self.player1.x + 0x8000);
+ self.frame.target_y = self.frame.target_y.clamp(self.player1.y, self.player1.y);
} else {
self.frame.target_x = self.player1.target_x;
self.frame.target_y = self.player1.target_y;
@@ -1189,8 +1186,18 @@ impl GameScene {
self.frame.update(state, &self.stage);
if state.control_flags.control_enabled() {
- self.inventory_player1.tick_weapons(state, &mut self.player1, TargetPlayer::Player1, &mut self.bullet_manager);
- self.inventory_player2.tick_weapons(state, &mut self.player2, TargetPlayer::Player2, &mut self.bullet_manager);
+ self.inventory_player1.tick_weapons(
+ state,
+ &mut self.player1,
+ TargetPlayer::Player1,
+ &mut self.bullet_manager,
+ );
+ self.inventory_player2.tick_weapons(
+ state,
+ &mut self.player2,
+ TargetPlayer::Player2,
+ &mut self.bullet_manager,
+ );
self.hud_player1.tick(state, (&self.player1, &mut self.inventory_player1))?;
self.hud_player2.tick(state, (&self.player2, &mut self.inventory_player2))?;
@@ -1214,7 +1221,7 @@ impl GameScene {
}
{
- let hit_rect_size = clamp(npc.hit_rect_size(), 1, 4);
+ let hit_rect_size = npc.hit_rect_size().clamp(1, 4);
let hit_rect_size = hit_rect_size * hit_rect_size;
let x = (npc.x + npc.offset_x()) / (16 * 0x200);
@@ -1246,10 +1253,11 @@ impl GameScene {
}
let text = format!("{}:{}:{}", npc.id, npc.npc_type, npc.action_num);
- state.font.draw_colored_text(
+ state.font.draw_colored_text_scaled(
text.chars(),
((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
+ 0.5,
((npc.id & 0xf0) as u8, (npc.cond.0 >> 8) as u8, (npc.id & 0x0f << 4) as u8, 255),
&state.constants,
&mut state.texture_set,
@@ -1354,7 +1362,7 @@ impl Scene for GameScene {
match state.textscript_vm.mode {
ScriptMode::Map if state.control_flags.tick_world() => self.tick_world(state)?,
ScriptMode::StageSelect => self.stage_select.tick(state, (&self.player1, &self.player2))?,
- ScriptMode::Inventory => self.inventory_ui.tick(state, &mut self.inventory_player1)?,
+ ScriptMode::Inventory => self.inventory_ui.tick(state, (&mut self.player1, &mut self.inventory_player1))?,
_ => {}
}
@@ -1481,67 +1489,68 @@ impl Scene for GameScene {
.scale(Vector2::new(1.0 / state.scale, 1.0 / state.scale)))?;*/
self.draw_black_bars(state, ctx)?;
- if state.control_flags.control_enabled() {
- self.hud_player1.draw(state, ctx, &self.frame)?;
- self.hud_player2.draw(state, ctx, &self.frame)?;
- self.boss_life_bar.draw(state, ctx, &self.frame)?;
+ match state.textscript_vm.mode {
+ ScriptMode::Map if state.control_flags.control_enabled() => {
+ self.hud_player1.draw(state, ctx, &self.frame)?;
+ self.hud_player2.draw(state, ctx, &self.frame)?;
+ self.boss_life_bar.draw(state, ctx, &self.frame)?;
- if self.player2.cond.alive() && !self.player2.cond.hidden() {
- let y = interpolate_fix9_scale(
- self.player2.prev_y - self.frame.prev_y,
- self.player2.y - self.frame.y,
- state.frame_time,
- );
- let y = clamp(y, 8.0, state.canvas_size.1 - 8.0 - state.font.line_height(&state.constants));
+ if self.player2.cond.alive() && !self.player2.cond.hidden() {
+ let y = interpolate_fix9_scale(
+ self.player2.prev_y - self.frame.prev_y,
+ self.player2.y - self.frame.y,
+ state.frame_time,
+ );
+ let y = y.clamp(8.0, state.canvas_size.1 - 8.0 - state.font.line_height(&state.constants));
- if self.player2.x + 8 * 0x200 < self.frame.x {
- state.font.draw_colored_text(
- P2_LEFT_TEXT.chars(),
- 9.0,
- y + 1.0,
- (0, 0, 130, 255),
- &state.constants,
- &mut state.texture_set,
- ctx,
- )?;
+ if self.player2.x + 8 * 0x200 < self.frame.x {
+ state.font.draw_colored_text(
+ P2_LEFT_TEXT.chars(),
+ 9.0,
+ y + 1.0,
+ (0, 0, 130, 255),
+ &state.constants,
+ &mut state.texture_set,
+ ctx,
+ )?;
- state.font.draw_colored_text(
- P2_LEFT_TEXT.chars(),
- 8.0,
- y,
- (96, 96, 255, 255),
- &state.constants,
- &mut state.texture_set,
- ctx,
- )?;
- } else if self.player2.x - 8 * 0x200 > self.frame.x + state.canvas_size.0 as i32 * 0x200 {
- let width = state.font.text_width(P2_RIGHT_TEXT.chars(), &state.constants);
+ state.font.draw_colored_text(
+ P2_LEFT_TEXT.chars(),
+ 8.0,
+ y,
+ (96, 96, 255, 255),
+ &state.constants,
+ &mut state.texture_set,
+ ctx,
+ )?;
+ } else if self.player2.x - 8 * 0x200 > self.frame.x + state.canvas_size.0 as i32 * 0x200 {
+ let width = state.font.text_width(P2_RIGHT_TEXT.chars(), &state.constants);
- state.font.draw_colored_text(
- P2_RIGHT_TEXT.chars(),
- state.canvas_size.0 - width - 8.0 + 1.0,
- y + 1.0,
- (0, 0, 130, 255),
- &state.constants,
- &mut state.texture_set,
- ctx,
- )?;
+ state.font.draw_colored_text(
+ P2_RIGHT_TEXT.chars(),
+ state.canvas_size.0 - width - 8.0 + 1.0,
+ y + 1.0,
+ (0, 0, 130, 255),
+ &state.constants,
+ &mut state.texture_set,
+ ctx,
+ )?;
- state.font.draw_colored_text(
- P2_RIGHT_TEXT.chars(),
- state.canvas_size.0 - width - 8.0,
- y,
- (96, 96, 255, 255),
- &state.constants,
- &mut state.texture_set,
- ctx,
- )?;
+ state.font.draw_colored_text(
+ P2_RIGHT_TEXT.chars(),
+ state.canvas_size.0 - width - 8.0,
+ y,
+ (96, 96, 255, 255),
+ &state.constants,
+ &mut state.texture_set,
+ ctx,
+ )?;
+ }
}
}
- }
-
- if state.textscript_vm.mode == ScriptMode::StageSelect {
- self.stage_select.draw(state, ctx, &self.frame)?;
+ ScriptMode::StageSelect => self.stage_select.draw(state, ctx, &self.frame)?,
+ ScriptMode::Inventory => self.inventory_ui.draw(state, ctx, &self.frame)?,
+ _ => {}
}
self.draw_fade(state, ctx)?;
diff --git a/src/scene/no_data_scene.rs b/src/scene/no_data_scene.rs
index 853aaab..0b83090 100644
--- a/src/scene/no_data_scene.rs
+++ b/src/scene/no_data_scene.rs
@@ -1,11 +1,11 @@
use crate::framework::context::Context;
use crate::framework::error::{GameResult, GameError};
-use crate::common::Rect;
use crate::scene::Scene;
use crate::shared_game_state::SharedGameState;
pub struct NoDataScene {
+ #[cfg(target_os = "android")]
flag: bool,
err: String,
}
@@ -13,6 +13,7 @@ pub struct NoDataScene {
impl NoDataScene {
pub fn new(err: GameError) -> Self {
Self {
+ #[cfg(target_os = "android")]
flag: false,
err: err.to_string(),
}
@@ -23,9 +24,12 @@ impl NoDataScene {
static REL_URL: &str = "https://github.com/doukutsu-rs/game-data/releases";
impl Scene for NoDataScene {
+ #[allow(unused)]
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
#[cfg(target_os = "android")]
{
+ use crate::common::Rect;
+
if !self.flag {
self.flag = true;
let _ = std::fs::create_dir("/sdcard/doukutsu/");
diff --git a/src/scene/title_scene.rs b/src/scene/title_scene.rs
index abe75b1..3371226 100644
--- a/src/scene/title_scene.rs
+++ b/src/scene/title_scene.rs
@@ -10,6 +10,7 @@ use crate::shared_game_state::{SharedGameState, TimingMode};
#[derive(PartialEq, Eq, Copy, Clone)]
#[repr(u8)]
+#[allow(unused)]
enum CurrentMenu {
MainMenu,
OptionMenu,
diff --git a/src/shared_game_state.rs b/src/shared_game_state.rs
index ca3c46f..2673426 100644
--- a/src/shared_game_state.rs
+++ b/src/shared_game_state.rs
@@ -2,20 +2,20 @@ use std::ops::Div;
use bitvec::vec::BitVec;
use chrono::{Datelike, Local};
-use num_traits::clamp;
-use num_traits::real::Real;
use crate::bmfont_renderer::BMFontRenderer;
use crate::caret::{Caret, CaretType};
use crate::common::{ControlFlags, Direction, FadeState};
use crate::engine_constants::EngineConstants;
+use crate::framework::{filesystem, graphics};
use crate::framework::backend::BackendTexture;
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::framework::graphics::{create_texture_mutable, set_render_target};
use crate::framework::keyboard::ScanCode;
use crate::framework::vfs::OpenOptions;
-use crate::framework::{filesystem, graphics};
+#[cfg(feature = "hooks")]
+use crate::hooks::init_hooks;
use crate::input::touch_controls::TouchControls;
use crate::npc::NPCTable;
use crate::profile::GameProfile;
@@ -153,6 +153,9 @@ impl SharedGameState {
println!("lookup path: {:#?}", texture_set.paths);
+ #[cfg(feature = "hooks")]
+ init_hooks();
+
Ok(SharedGameState {
timing_mode: TimingMode::_50Hz,
control_flags: ControlFlags(0),
@@ -193,9 +196,7 @@ impl SharedGameState {
ScanCode::F3 => self.settings.god_mode = !self.settings.god_mode,
ScanCode::F4 => self.settings.infinite_booster = !self.settings.infinite_booster,
ScanCode::F5 => self.settings.subpixel_coords = !self.settings.subpixel_coords,
- ScanCode::F6 => {
- self.settings.motion_interpolation = !self.settings.motion_interpolation
- }
+ ScanCode::F6 => self.settings.motion_interpolation = !self.settings.motion_interpolation,
ScanCode::F7 => self.set_speed(1.0),
ScanCode::F8 => {
if self.settings.speed > 0.2 {
@@ -260,11 +261,7 @@ impl SharedGameState {
}
pub fn save_game(&mut self, game_scene: &mut GameScene, ctx: &mut Context) -> GameResult {
- if let Ok(data) = filesystem::open_options(
- ctx,
- "/Profile.dat",
- OpenOptions::new().write(true).create(true),
- ) {
+ if let Ok(data) = filesystem::open_options(ctx, "/Profile.dat", OpenOptions::new().write(true).create(true)) {
let profile = GameProfile::dump(self, game_scene);
profile.write_save(data)?;
} else {
@@ -315,10 +312,7 @@ impl SharedGameState {
pub fn handle_resize(&mut self, ctx: &mut Context) -> GameResult {
self.screen_size = graphics::screen_size(ctx);
self.scale = self.screen_size.1.div(230.0).floor().max(1.0);
- self.canvas_size = (
- self.screen_size.0 / self.scale,
- self.screen_size.1 / self.scale,
- );
+ self.canvas_size = (self.screen_size.0 / self.scale, self.screen_size.1 / self.scale);
let (width, height) = (self.screen_size.0 as u16, self.screen_size.1 as u16);
@@ -338,12 +332,11 @@ impl SharedGameState {
}
pub fn create_caret(&mut self, x: i32, y: i32, ctype: CaretType, direct: Direction) {
- self.carets
- .push(Caret::new(x, y, ctype, direct, &self.constants));
+ self.carets.push(Caret::new(x, y, ctype, direct, &self.constants));
}
pub fn set_speed(&mut self, value: f64) {
- self.settings.speed = clamp(value, 0.1, 3.0);
+ self.settings.speed = value.clamp(0.1, 3.0);
self.frame_time = 0.0;
}
diff --git a/src/sound/mod.rs b/src/sound/mod.rs
index dc557fb..5dcfce6 100644
--- a/src/sound/mod.rs
+++ b/src/sound/mod.rs
@@ -248,7 +248,7 @@ where
let mut state = PlaybackState::Stopped;
let mut saved_state: PlaybackStateType = PlaybackStateType::None;
let mut speed = 1.0;
- let mut org_engine = OrgPlaybackEngine::new(&bank);
+ let mut org_engine = OrgPlaybackEngine::new();
#[cfg(feature = "ogg-playback")]
let mut ogg_engine = OggPlaybackEngine::new();
let mut pixtone = PixTonePlayback::new();
diff --git a/src/sound/ogg_playback.rs b/src/sound/ogg_playback.rs
index 6f391dc..a45b432 100644
--- a/src/sound/ogg_playback.rs
+++ b/src/sound/ogg_playback.rs
@@ -39,7 +39,9 @@ impl OggPlaybackEngine {
}
}
- pub fn set_sample_rate(&mut self, sample_rate: usize) {}
+ pub fn set_sample_rate(&mut self, sample_rate: usize) {
+ self.output_format.sample_rate = sample_rate as u32;
+ }
pub fn get_state(&self) -> SavedOggPlaybackState {
SavedOggPlaybackState {
@@ -120,13 +122,13 @@ impl OggPlaybackEngine {
let mut buf = match music.read_dec_packet_itl() {
Ok(Some(buf)) => buf,
Ok(None) => {
- if let Err(e) = music.seek_absgp_pg(0) {
+ if let Err(_) = music.seek_absgp_pg(0) {
vec![0, 1000]
} else {
return;
}
}
- Err(e) => {
+ Err(_) => {
vec![0, 1000]
}
};
@@ -145,11 +147,11 @@ impl OggPlaybackEngine {
}
}
- fn resample_buffer(&self, mut data: Vec, sample_rate: u32, channels: u8) -> Vec {
+ fn resample_buffer(&self, mut data: Vec, sample_rate: u32, _channels: u8) -> Vec {
if sample_rate != self.output_format.sample_rate {
let mut tmp_data = Vec::new();
let mut pos = 0.0;
- let mut phase = sample_rate as f32 / self.output_format.sample_rate as f32;
+ let phase = sample_rate as f32 / self.output_format.sample_rate as f32;
loop {
if pos >= data.len() as f32 {
diff --git a/src/sound/org_playback.rs b/src/sound/org_playback.rs
index def61ce..918ce20 100644
--- a/src/sound/org_playback.rs
+++ b/src/sound/org_playback.rs
@@ -41,7 +41,7 @@ impl Clone for SavedOrganyaPlaybackState {
}
impl OrgPlaybackEngine {
- pub fn new(samples: &SoundBank) -> Self {
+ pub fn new() -> Self {
let mut buffers: [MaybeUninit; 136] = unsafe { MaybeUninit::uninit().assume_init() };
for buffer in buffers.iter_mut() {
diff --git a/src/sound/pixtone.rs b/src/sound/pixtone.rs
index 5c84cea..5582e32 100644
--- a/src/sound/pixtone.rs
+++ b/src/sound/pixtone.rs
@@ -206,6 +206,7 @@ pub struct PixTonePlayback {
pub playback_state: Vec,
}
+#[allow(unused)]
impl PixTonePlayback {
pub fn new() -> PixTonePlayback {
PixTonePlayback {
diff --git a/src/texture_set.rs b/src/texture_set.rs
index 9b9976a..e8943d0 100644
--- a/src/texture_set.rs
+++ b/src/texture_set.rs
@@ -128,7 +128,7 @@ impl SizedBatch {
}
pub fn add_rect_scaled(&mut self, mut x: f32, mut y: f32, scale_x: f32, scale_y: f32, rect: &common::Rect) {
- if (rect.right - rect.left) == 0 || (rect.bottom - rect.top) == 0 {
+ if (rect.right.saturating_sub(rect.left)) == 0 || (rect.bottom.saturating_sub(rect.top)) == 0 {
return;
}
diff --git a/src/weapon/bubbler.rs b/src/weapon/bubbler.rs
index 5276e6e..8395604 100644
--- a/src/weapon/bubbler.rs
+++ b/src/weapon/bubbler.rs
@@ -3,7 +3,6 @@ use crate::common::Direction;
use crate::player::{Player, TargetPlayer};
use crate::shared_game_state::SharedGameState;
use crate::weapon::bullet::BulletManager;
-use crate::weapon::WeaponLevel::Level1;
use crate::weapon::{Weapon, WeaponLevel};
impl Weapon {
diff --git a/src/weapon/bullet.rs b/src/weapon/bullet.rs
index dc9c6ea..f641f6a 100644
--- a/src/weapon/bullet.rs
+++ b/src/weapon/bullet.rs
@@ -1,5 +1,3 @@
-use std::ops::{Add, Sub};
-
use num_traits::clamp;
use crate::caret::CaretType;
@@ -105,8 +103,8 @@ pub struct Bullet {
pub anim_counter: u16,
pub action_num: u16,
pub action_counter: u16,
- pub hit_bounds: Rect,
- pub display_bounds: Rect,
+ pub hit_bounds: Rect,
+ pub display_bounds: Rect,
}
impl Bullet {
@@ -152,16 +150,16 @@ impl Bullet {
action_num: 0,
action_counter: 0,
display_bounds: Rect::new(
- bullet.display_bounds.left as usize * 0x200,
- bullet.display_bounds.top as usize * 0x200,
- bullet.display_bounds.right as usize * 0x200,
- bullet.display_bounds.bottom as usize * 0x200,
+ bullet.display_bounds.left as u32 * 0x200,
+ bullet.display_bounds.top as u32 * 0x200,
+ bullet.display_bounds.right as u32 * 0x200,
+ bullet.display_bounds.bottom as u32 * 0x200,
),
hit_bounds: Rect::new(
- bullet.block_hit_width as usize * 0x200,
- bullet.block_hit_height as usize * 0x200,
- bullet.block_hit_width as usize * 0x200,
- bullet.block_hit_height as usize * 0x200,
+ bullet.block_hit_width as u32 * 0x200,
+ bullet.block_hit_height as u32 * 0x200,
+ bullet.block_hit_width as u32 * 0x200,
+ bullet.block_hit_height as u32 * 0x200,
),
}
}
@@ -1515,7 +1513,7 @@ impl PhysicalEntity for Bullet {
}
#[inline(always)]
- fn hit_bounds(&self) -> &Rect {
+ fn hit_bounds(&self) -> &Rect {
&self.hit_bounds
}