general cleanup, hooks and android build fix
This commit is contained in:
parent
334d1530c0
commit
5efd3f3c92
16
Cargo.toml
16
Cargo.toml
|
@ -15,14 +15,6 @@ test = false
|
||||||
bench = false
|
bench = false
|
||||||
required-features = ["exe"]
|
required-features = ["exe"]
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "drsandroid"
|
|
||||||
path = "src/main_android.rs"
|
|
||||||
crate-type = ["cdylib"]
|
|
||||||
test = false
|
|
||||||
bench = false
|
|
||||||
required-features = ["android"]
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = 'thin'
|
lto = 'thin'
|
||||||
panic = 'abort'
|
panic = 'abort'
|
||||||
|
@ -30,12 +22,6 @@ panic = 'abort'
|
||||||
[profile.dev.package."*"]
|
[profile.dev.package."*"]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
[profile.dev.build-override]
|
|
||||||
opt-level = 1
|
|
||||||
|
|
||||||
[profile.release.build-override]
|
|
||||||
opt-level = 1
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["scripting", "backend-sdl", "ogg-playback", "netplay", "exe"]
|
default = ["scripting", "backend-sdl", "ogg-playback", "netplay", "exe"]
|
||||||
ogg-playback = ["lewton"]
|
ogg-playback = ["lewton"]
|
||||||
|
@ -45,6 +31,7 @@ backend-glutin = ["winit", "glutin"]
|
||||||
scripting = ["lua-ffi"]
|
scripting = ["lua-ffi"]
|
||||||
netplay = []
|
netplay = []
|
||||||
editor = []
|
editor = []
|
||||||
|
hooks = ["libc"]
|
||||||
exe = []
|
exe = []
|
||||||
android = []
|
android = []
|
||||||
|
|
||||||
|
@ -64,6 +51,7 @@ image = { version = "0.23", default-features = false, features = ["png", "bmp"]
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
lewton = { version = "0.10.2", optional = true }
|
lewton = { version = "0.10.2", optional = true }
|
||||||
|
libc = { version = "0.2", optional = true }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
lua-ffi = { git = "https://github.com/doukutsu-rs/lua-ffi.git", rev = "1ef3caf772d72068297ddf75df06fd2ef8c1daab", optional = true }
|
lua-ffi = { git = "https://github.com/doukutsu-rs/lua-ffi.git", rev = "1ef3caf772d72068297ddf75df06fd2ef8c1daab", optional = true }
|
||||||
lru = "0.6.0"
|
lru = "0.6.0"
|
||||||
|
|
|
@ -18,7 +18,7 @@ android {
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters 'x86', 'arm64-v8a'
|
abiFilters 'x86', 'arm64-v8a', 'armeabi-v7a'
|
||||||
}
|
}
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
|
@ -69,13 +69,14 @@ println("cargo target: ${project.buildDir.getAbsolutePath()}/rust-target")
|
||||||
cargoNdk {
|
cargoNdk {
|
||||||
targets = [
|
targets = [
|
||||||
"x86",
|
"x86",
|
||||||
|
"arm",
|
||||||
"arm64"
|
"arm64"
|
||||||
]
|
]
|
||||||
librariesNames = ["libdrsembedded.so"]
|
librariesNames = ["libdrsandroid.so"]
|
||||||
//targetDirectory = "${project.buildDir.getAbsolutePath()}/rust-target"
|
//targetDirectory = "${project.buildDir.getAbsolutePath()}/rust-target"
|
||||||
module = "../"
|
module = "../drsandroid/"
|
||||||
extraCargoEnv = ["ANDROID_NDK_HOME": android.ndkDirectory]
|
extraCargoEnv = ["ANDROID_NDK_HOME": android.ndkDirectory]
|
||||||
extraCargoBuildArguments = ["--no-default-features", "--features", "backend-glutin ogg-playback scripting"]
|
extraCargoBuildArguments = []
|
||||||
verbose = true
|
verbose = true
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
android:screenOrientation="sensorLandscape"
|
android:screenOrientation="sensorLandscape"
|
||||||
android:launchMode="standard"
|
android:launchMode="standard"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize">
|
android:configChanges="orientation|keyboardHidden|screenSize">
|
||||||
<meta-data android:name="android.app.lib_name" android:value="doukutsu_rs" />
|
<meta-data android:name="android.app.lib_name" android:value="drsandroid" />
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
|
2
build.rs
2
build.rs
|
@ -1,6 +1,4 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
// #[cfg(feature = "generate-gl")]
|
// #[cfg(feature = "generate-gl")]
|
||||||
// use gl_generator::{Api, Fallbacks, Profile, Registry};
|
// use gl_generator::{Api, Fallbacks, Profile, Registry};
|
||||||
|
|
|
@ -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"] }
|
|
@ -2,4 +2,4 @@
|
||||||
#[cfg_attr(target_os = "android", ndk_glue::main())]
|
#[cfg_attr(target_os = "android", ndk_glue::main())]
|
||||||
pub fn android_main() {
|
pub fn android_main() {
|
||||||
doukutsu_rs::init().unwrap();
|
doukutsu_rs::init().unwrap();
|
||||||
}
|
}
|
26
src/caret.rs
26
src/caret.rs
|
@ -24,6 +24,32 @@ pub enum CaretType {
|
||||||
PushJumpKey,
|
PushJumpKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CaretType {
|
||||||
|
pub fn from_int(id: usize) -> Option<CaretType> {
|
||||||
|
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 struct Caret {
|
||||||
pub ctype: CaretType,
|
pub ctype: CaretType,
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::cmp::Ordering;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
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, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde::de::{SeqAccess, Visitor};
|
use serde::de::{SeqAccess, Visitor};
|
||||||
use serde::ser::SerializeTupleStruct;
|
use serde::ser::SerializeTupleStruct;
|
||||||
|
@ -21,6 +21,7 @@ lazy_static! {
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct Flag(u32);
|
pub struct Flag(u32);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
|
|
||||||
|
@ -63,6 +64,7 @@ impl Flag {
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct Equipment(u16);
|
pub struct Equipment(u16);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
|
|
||||||
|
@ -88,6 +90,7 @@ bitfield! {
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct Condition(u16);
|
pub struct Condition(u16);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
|
|
||||||
|
@ -106,6 +109,7 @@ bitfield! {
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct ControlFlags(u16);
|
pub struct ControlFlags(u16);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
|
|
||||||
|
@ -121,6 +125,7 @@ bitfield! {
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct BulletFlag(u16);
|
pub struct BulletFlag(u16);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
pub flag_x01, set_flag_x01: 0; // 0x01
|
pub flag_x01, set_flag_x01: 0; // 0x01
|
||||||
|
@ -257,6 +262,7 @@ impl<T: Num + PartialOrd + Copy> Point<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct Rect<T: Num + PartialOrd + Copy = isize> {
|
pub struct Rect<T: Num + PartialOrd + Copy = isize> {
|
||||||
pub left: T,
|
pub left: T,
|
||||||
pub top: T,
|
pub top: T,
|
||||||
|
|
|
@ -37,7 +37,7 @@ impl Flash {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameEntity<()> for 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 {
|
match self.state {
|
||||||
FlashState::None => {}
|
FlashState::None => {}
|
||||||
FlashState::Cross(x, y, tick) => {
|
FlashState::Cross(x, y, tick) => {
|
||||||
|
|
|
@ -1,30 +1,79 @@
|
||||||
use crate::entity::GameEntity;
|
use crate::entity::GameEntity;
|
||||||
use crate::inventory::Inventory;
|
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::frame::Frame;
|
use crate::frame::Frame;
|
||||||
use crate::shared_game_state::SharedGameState;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::GameResult;
|
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 {
|
pub struct InventoryUI {
|
||||||
text_y_pos: usize,
|
text_y_pos: usize,
|
||||||
tick: usize,
|
tick: usize,
|
||||||
|
current_script: usize,
|
||||||
|
focus: InventoryFocus,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InventoryUI {
|
impl InventoryUI {
|
||||||
pub fn new() -> InventoryUI {
|
pub fn new() -> InventoryUI {
|
||||||
InventoryUI {
|
InventoryUI { text_y_pos: 24, tick: 0, current_script: 0, focus: InventoryFocus::None }
|
||||||
text_y_pos: 24,
|
}
|
||||||
tick: 0,
|
}
|
||||||
|
|
||||||
|
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 {
|
match self.focus {
|
||||||
fn tick(&mut self, state: &mut SharedGameState, custom: &mut Inventory) -> GameResult<()> {
|
InventoryFocus::None => {
|
||||||
|
self.focus = InventoryFocus::Weapons;
|
||||||
|
state.textscript_vm.start_script(1004);
|
||||||
|
}
|
||||||
|
InventoryFocus::Weapons => {}
|
||||||
|
InventoryFocus::Items => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tick = self.tick.wrapping_add(1);
|
||||||
|
|
||||||
Ok(())
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,8 @@ pub struct BoosterConsts {
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct MyCharConsts {
|
pub struct MyCharConsts {
|
||||||
pub display_bounds: Rect<usize>,
|
pub display_bounds: Rect<u32>,
|
||||||
pub hit_bounds: Rect<usize>,
|
pub hit_bounds: Rect<u32>,
|
||||||
pub life: u16,
|
pub life: u16,
|
||||||
pub max_life: u16,
|
pub max_life: u16,
|
||||||
pub control_mode: ControlMode,
|
pub control_mode: ControlMode,
|
||||||
|
|
|
@ -3,8 +3,6 @@ use serde::{Deserialize, Serialize};
|
||||||
use crate::common::Rect;
|
use crate::common::Rect;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||||
|
|
||||||
// 360/369 (97.56%) NPCs defined
|
|
||||||
pub struct NPCConsts {
|
pub struct NPCConsts {
|
||||||
// pub n000_null: () // Defined in code
|
// pub n000_null: () // Defined in code
|
||||||
|
|
||||||
|
@ -1062,9 +1060,6 @@ pub struct NPCConsts {
|
||||||
#[serde(default = "default_n360_credits_thank_you")]
|
#[serde(default = "default_n360_credits_thank_you")]
|
||||||
pub n360_credits_thank_you: Rect<u16>,
|
pub n360_credits_thank_you: Rect<u16>,
|
||||||
|
|
||||||
#[serde(default = "default_n361_gaudi_dashing")]
|
|
||||||
pub n361_gaudi_dashing: [Rect<u16>; 4],
|
|
||||||
|
|
||||||
#[serde(default = "default_b01_omega")]
|
#[serde(default = "default_b01_omega")]
|
||||||
pub b01_omega: [Rect<u16>; 10],
|
pub b01_omega: [Rect<u16>; 10],
|
||||||
|
|
||||||
|
@ -4744,15 +4739,6 @@ fn default_n360_credits_thank_you() -> Rect<u16> {
|
||||||
Rect { left: 0, top: 176, right: 48, bottom: 184 }
|
Rect { left: 0, top: 176, right: 48, bottom: 184 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_n361_gaudi_dashing() -> [Rect<u16>; 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<u16>; 10] {
|
fn default_b01_omega() -> [Rect<u16>; 10] {
|
||||||
[
|
[
|
||||||
Rect { left: 0, top: 0, right: 80, bottom: 56 },
|
Rect { left: 0, top: 0, right: 80, bottom: 56 },
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use imgui::DrawData;
|
use imgui::DrawData;
|
||||||
|
|
||||||
use crate::common::{Color, Point, Rect};
|
use crate::common::{Color, Rect};
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use crate::framework::graphics::BlendMode;
|
use crate::framework::graphics::BlendMode;
|
||||||
|
@ -21,7 +21,7 @@ pub trait BackendRenderer {
|
||||||
|
|
||||||
fn present(&mut self) -> GameResult;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ impl BackendTexture for NullTexture {
|
||||||
(self.0, self.1)
|
(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<imgui::Context>);
|
pub struct NullRenderer(RefCell<imgui::Context>);
|
||||||
|
|
||||||
impl BackendRenderer for NullRenderer {
|
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)))
|
Ok(Box::new(NullTexture(width, height)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_texture(&mut self, width: u16, height: u16, data: &[u8]) -> GameResult<Box<dyn BackendTexture>> {
|
fn create_texture(&mut self, width: u16, height: u16, _data: &[u8]) -> GameResult<Box<dyn BackendTexture>> {
|
||||||
Ok(Box::new(NullTexture(width, height)))
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_render_target(&mut self, texture: Option<&Box<dyn BackendTexture>>) -> GameResult {
|
fn set_render_target(&mut self, _texture: Option<&Box<dyn BackendTexture>>) -> GameResult {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_rect(&mut self, rect: Rect<isize>, color: Color) -> GameResult {
|
fn draw_rect(&mut self, _rect: Rect<isize>, _color: Color) -> GameResult {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_outline_rect(&mut self, rect: Rect<isize>, line_width: usize, color: Color) -> GameResult {
|
fn draw_outline_rect(&mut self, _rect: Rect<isize>, _line_width: usize, _color: Color) -> GameResult {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ impl BackendRenderer for NullRenderer {
|
||||||
unsafe { Ok(&mut *self.0.as_ptr()) }
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use imgui::internal::RawWrapper;
|
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::event::{Event, WindowEvent};
|
||||||
use sdl2::keyboard::Scancode;
|
use sdl2::keyboard::Scancode;
|
||||||
use sdl2::mouse::{Cursor, SystemCursor};
|
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::backend::{Backend, BackendEventLoop, BackendRenderer, BackendTexture, SpriteBatchCommand};
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::{GameError, GameResult};
|
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::keyboard::ScanCode;
|
||||||
use crate::framework::ui::init_imgui;
|
use crate::framework::ui::init_imgui;
|
||||||
use crate::Game;
|
use crate::Game;
|
||||||
|
@ -121,7 +121,7 @@ impl BackendEventLoop for SDL2EventLoop {
|
||||||
imgui.io_mut().display_size = [ctx.screen_size.0, ctx.screen_size.1];
|
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) {
|
pub fn handle_event(&mut self, imgui: &mut imgui::Context, event: &Event) {
|
||||||
use sdl2::keyboard;
|
|
||||||
use sdl2::mouse::MouseButton;
|
use sdl2::mouse::MouseButton;
|
||||||
|
|
||||||
fn set_mod(imgui: &mut imgui::Context, keymod: keyboard::Mod) {
|
fn set_mod(imgui: &mut imgui::Context, keymod: keyboard::Mod) {
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
use std::env;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::SeekFrom;
|
use std::io::SeekFrom;
|
||||||
use std::path;
|
use std::path;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use directories::ProjectDirs;
|
|
||||||
|
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::{GameError, GameResult};
|
use crate::framework::error::{GameError, GameResult};
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{BufRead, Read, Seek, Write};
|
use std::io::{Read, Seek, Write};
|
||||||
use std::path::{self, Path, PathBuf};
|
use std::path::{self, Path, PathBuf};
|
||||||
|
|
||||||
use crate::framework::error::{GameError, GameResult};
|
use crate::framework::error::{GameError, GameResult};
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,6 @@ use crate::engine_constants::EngineConstants;
|
||||||
use crate::shared_game_state::SharedGameState;
|
use crate::shared_game_state::SharedGameState;
|
||||||
use crate::weapon::{Weapon, WeaponLevel, WeaponType};
|
use crate::weapon::{Weapon, WeaponLevel, WeaponType};
|
||||||
use crate::player::{Player, TargetPlayer};
|
use crate::player::{Player, TargetPlayer};
|
||||||
use crate::caret::CaretType;
|
|
||||||
use crate::common::Direction;
|
|
||||||
use crate::weapon::bullet::BulletManager;
|
use crate::weapon::bullet::BulletManager;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
|
@ -43,6 +43,8 @@ mod frame;
|
||||||
mod framework;
|
mod framework;
|
||||||
mod input;
|
mod input;
|
||||||
mod inventory;
|
mod inventory;
|
||||||
|
#[cfg(feature = "hooks")]
|
||||||
|
mod hooks;
|
||||||
mod live_debugger;
|
mod live_debugger;
|
||||||
mod macros;
|
mod macros;
|
||||||
mod map;
|
mod map;
|
||||||
|
|
|
@ -19,7 +19,6 @@ pub enum ScriptType {
|
||||||
pub struct LiveDebugger {
|
pub struct LiveDebugger {
|
||||||
map_selector_visible: bool,
|
map_selector_visible: bool,
|
||||||
events_visible: bool,
|
events_visible: bool,
|
||||||
hacks_visible: bool,
|
|
||||||
flags_visible: bool,
|
flags_visible: bool,
|
||||||
npc_inspector_visible: bool,
|
npc_inspector_visible: bool,
|
||||||
last_stage_id: usize,
|
last_stage_id: usize,
|
||||||
|
@ -37,7 +36,6 @@ impl LiveDebugger {
|
||||||
Self {
|
Self {
|
||||||
map_selector_visible: false,
|
map_selector_visible: false,
|
||||||
events_visible: false,
|
events_visible: false,
|
||||||
hacks_visible: false,
|
|
||||||
flags_visible: false,
|
flags_visible: false,
|
||||||
npc_inspector_visible: false,
|
npc_inspector_visible: false,
|
||||||
last_stage_id: usize::MAX,
|
last_stage_id: usize::MAX,
|
||||||
|
|
|
@ -2,7 +2,6 @@ use std::io;
|
||||||
|
|
||||||
use byteorder::{LE, ReadBytesExt};
|
use byteorder::{LE, ReadBytesExt};
|
||||||
|
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
|
|
||||||
use crate::str;
|
use crate::str;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use num_traits::clamp;
|
use num_traits::clamp;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
|
|
||||||
use crate::common::Direction;
|
use crate::common::Direction;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
|
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use num_traits::{abs, clamp};
|
use num_traits::{abs, clamp};
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl NPC {
|
||||||
5 => {
|
5 => {
|
||||||
self.action_num = 6;
|
self.action_num = 6;
|
||||||
self.anim_num = 5;
|
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 => {
|
6 => {
|
||||||
self.anim_num = 5;
|
self.anim_num = 5;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use num_traits::{abs, clamp};
|
use num_traits::{abs, clamp};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use num_traits::clamp;
|
use num_traits::clamp;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ use num_traits::clamp;
|
||||||
|
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
use crate::common::{Direction, Rect};
|
use crate::common::{Direction, Rect};
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use crate::npc::{NPCList, NPC};
|
use crate::npc::{NPCList, NPC};
|
||||||
use crate::player::Player;
|
use crate::player::Player;
|
||||||
|
@ -451,7 +450,7 @@ impl NPC {
|
||||||
self.damage = 0;
|
self.damage = 0;
|
||||||
self.npc_flags.set_shootable(false);
|
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);
|
self.create_xp_drop(state, npc_list);
|
||||||
|
|
||||||
state.sound_manager.play_sfx(71);
|
state.sound_manager.play_sfx(71);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::common::{CDEG_RAD, Direction};
|
use crate::common::{CDEG_RAD, Direction};
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use crate::npc::list::NPCList;
|
use crate::npc::list::NPCList;
|
||||||
use crate::npc::NPC;
|
use crate::npc::NPC;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
|
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
|
|
|
@ -1045,7 +1045,7 @@ impl NPC {
|
||||||
|
|
||||||
pub(crate) fn tick_n125_hidden_item(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
pub(crate) fn tick_n125_hidden_item(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
|
||||||
if self.life < 990 {
|
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);
|
self.cond.set_alive(false);
|
||||||
state.sound_manager.play_sfx(70);
|
state.sound_manager.play_sfx(70);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use num_traits::abs;
|
use num_traits::abs;
|
||||||
|
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use crate::npc::NPC;
|
use crate::npc::NPC;
|
||||||
use crate::player::Player;
|
use crate::player::Player;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use num_traits::clamp;
|
use num_traits::clamp;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
|
|
||||||
use crate::common::Direction;
|
use crate::common::Direction;
|
||||||
|
|
|
@ -2,7 +2,6 @@ use num_traits::{abs, clamp};
|
||||||
|
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
use crate::common::{Direction, CDEG_RAD};
|
use crate::common::{Direction, CDEG_RAD};
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use crate::npc::list::NPCList;
|
use crate::npc::list::NPCList;
|
||||||
use crate::npc::NPC;
|
use crate::npc::NPC;
|
||||||
|
@ -113,7 +112,7 @@ impl NPC {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.life <= 100 {
|
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);
|
state.sound_manager.play_sfx(25);
|
||||||
self.cond.set_alive(false);
|
self.cond.set_alive(false);
|
||||||
|
|
||||||
|
@ -571,7 +570,7 @@ impl NPC {
|
||||||
let parent = self.get_parent_ref_mut(npc_list);
|
let parent = self.get_parent_ref_mut(npc_list);
|
||||||
if parent.is_none() || parent.as_ref().unwrap().npc_type == 3 {
|
if parent.is_none() || parent.as_ref().unwrap().npc_type == 3 {
|
||||||
self.vanish(state);
|
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(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,7 +667,7 @@ impl NPC {
|
||||||
if self.action_counter > 50 {
|
if self.action_counter > 50 {
|
||||||
state.sound_manager.play_sfx(25);
|
state.sound_manager.play_sfx(25);
|
||||||
self.vanish(state);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use num_traits::abs;
|
use num_traits::abs;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use num_traits::clamp;
|
|
||||||
|
|
||||||
use crate::common::Direction;
|
use crate::common::Direction;
|
||||||
use crate::npc::list::NPCList;
|
use crate::npc::list::NPCList;
|
||||||
|
@ -213,7 +211,7 @@ impl NPC {
|
||||||
if self.action_num != 14 {
|
if self.action_num != 14 {
|
||||||
self.vel_y += 0x40;
|
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 {
|
if self.vel_y > 0x5ff {
|
||||||
self.vel_y = 0x5ff;
|
self.vel_y = 0x5ff;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use num_traits::clamp;
|
|
||||||
|
|
||||||
use crate::common::Direction;
|
use crate::common::Direction;
|
||||||
use crate::npc::NPC;
|
use crate::npc::NPC;
|
||||||
|
@ -149,7 +147,7 @@ impl NPC {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.vel_y += 0x40;
|
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 {
|
if self.vel_y > 0x5ff {
|
||||||
self.vel_y = 0x5ff;
|
self.vel_y = 0x5ff;
|
||||||
|
@ -254,7 +252,7 @@ impl NPC {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.vel_y += 0x40;
|
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 {
|
if self.vel_y > 0x5ff {
|
||||||
self.vel_y = 0x5ff;
|
self.vel_y = 0x5ff;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
|
|
||||||
use crate::npc::NPC;
|
use crate::npc::NPC;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
|
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
|
|
|
@ -3,7 +3,6 @@ use num_traits::{abs, clamp};
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
use crate::common::{Direction, Rect, CDEG_RAD};
|
use crate::common::{Direction, Rect, CDEG_RAD};
|
||||||
use crate::components::flash::Flash;
|
use crate::components::flash::Flash;
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use crate::npc::boss::BossNPC;
|
use crate::npc::boss::BossNPC;
|
||||||
use crate::npc::list::NPCList;
|
use crate::npc::list::NPCList;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
use crate::common::{Direction, Rect};
|
use crate::common::{Direction, Rect};
|
||||||
use crate::components::flash::Flash;
|
use crate::components::flash::Flash;
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use crate::npc::boss::BossNPC;
|
use crate::npc::boss::BossNPC;
|
||||||
use crate::npc::list::NPCList;
|
use crate::npc::list::NPCList;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::cell::{Cell, UnsafeCell};
|
use std::cell::{Cell, UnsafeCell};
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::{GameResult, GameError};
|
use crate::framework::error::{GameResult, GameError};
|
||||||
|
|
||||||
use crate::npc::NPC;
|
use crate::npc::NPC;
|
||||||
|
|
|
@ -51,6 +51,7 @@ bitfield! {
|
||||||
|
|
||||||
/// Represents an NPC object.
|
/// Represents an NPC object.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct NPC {
|
pub struct NPC {
|
||||||
pub id: u16,
|
pub id: u16,
|
||||||
pub npc_type: 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,
|
/// Raw direction value set by TSC because some NPCs have it set outside 0-4 range,
|
||||||
/// breaking the direction type.
|
/// breaking the direction type.
|
||||||
pub tsc_direction: u16,
|
pub tsc_direction: u16,
|
||||||
pub display_bounds: Rect<usize>,
|
|
||||||
pub hit_bounds: Rect<usize>,
|
|
||||||
pub parent_id: u16,
|
pub parent_id: u16,
|
||||||
pub action_num: u16,
|
pub action_num: u16,
|
||||||
pub anim_num: u16,
|
pub anim_num: u16,
|
||||||
|
@ -92,8 +91,11 @@ pub struct NPC {
|
||||||
pub event_num: u16,
|
pub event_num: u16,
|
||||||
pub action_counter: u16,
|
pub action_counter: u16,
|
||||||
pub action_counter2: u16,
|
pub action_counter2: u16,
|
||||||
|
pub action_counter3: u16,
|
||||||
pub anim_counter: u16,
|
pub anim_counter: u16,
|
||||||
pub anim_rect: Rect<u16>,
|
pub anim_rect: Rect<u16>,
|
||||||
|
pub display_bounds: Rect<u32>,
|
||||||
|
pub hit_bounds: Rect<u32>,
|
||||||
pub rng: Xoroshiro32PlusPlus,
|
pub rng: Xoroshiro32PlusPlus,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +134,7 @@ impl NPC {
|
||||||
event_num: 0,
|
event_num: 0,
|
||||||
action_counter: 0,
|
action_counter: 0,
|
||||||
action_counter2: 0,
|
action_counter2: 0,
|
||||||
|
action_counter3: 0,
|
||||||
anim_counter: 0,
|
anim_counter: 0,
|
||||||
anim_rect: Rect { left: 0, top: 0, right: 0, bottom: 0 },
|
anim_rect: Rect { left: 0, top: 0, right: 0, bottom: 0 },
|
||||||
rng: Xoroshiro32PlusPlus::new(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),
|
355 => self.tick_n355_quote_and_curly_on_balrog(state, npc_list),
|
||||||
358 => self.tick_n358_misery_credits(state),
|
358 => self.tick_n358_misery_credits(state),
|
||||||
359 => self.tick_n359_water_droplet_generator(state, players, npc_list),
|
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 {
|
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 } }
|
fn offset_y(&self) -> i32 { if self.size >= 3 && !self.cond.drs_boss() { -0x1000 } else { 0 } }
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn hit_bounds(&self) -> &Rect<usize> {
|
fn hit_bounds(&self) -> &Rect<u32> {
|
||||||
&self.hit_bounds
|
&self.hit_bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,26 +561,26 @@ impl NPCTable {
|
||||||
self.entries.get(npc_type as usize)
|
self.entries.get(npc_type as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_display_bounds(&self, npc_type: u16) -> Rect<usize> {
|
pub fn get_display_bounds(&self, npc_type: u16) -> Rect<u32> {
|
||||||
if let Some(npc) = self.entries.get(npc_type as usize) {
|
if let Some(npc) = self.entries.get(npc_type as usize) {
|
||||||
Rect {
|
Rect {
|
||||||
left: npc.display_bounds.left as usize * 0x200,
|
left: npc.display_bounds.left as u32 * 0x200,
|
||||||
top: npc.display_bounds.top as usize * 0x200,
|
top: npc.display_bounds.top as u32 * 0x200,
|
||||||
right: npc.display_bounds.right as usize * 0x200,
|
right: npc.display_bounds.right as u32 * 0x200,
|
||||||
bottom: npc.display_bounds.bottom as usize * 0x200,
|
bottom: npc.display_bounds.bottom as u32 * 0x200,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Rect { left: 0, top: 0, right: 0, bottom: 0 }
|
Rect { left: 0, top: 0, right: 0, bottom: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_hit_bounds(&self, npc_type: u16) -> Rect<usize> {
|
pub fn get_hit_bounds(&self, npc_type: u16) -> Rect<u32> {
|
||||||
if let Some(npc) = self.entries.get(npc_type as usize) {
|
if let Some(npc) = self.entries.get(npc_type as usize) {
|
||||||
Rect {
|
Rect {
|
||||||
left: npc.hit_bounds.left as usize * 0x200,
|
left: npc.hit_bounds.left as u32 * 0x200,
|
||||||
top: npc.hit_bounds.top as usize * 0x200,
|
top: npc.hit_bounds.top as u32 * 0x200,
|
||||||
right: npc.hit_bounds.right as usize * 0x200,
|
right: npc.hit_bounds.right as u32 * 0x200,
|
||||||
bottom: npc.hit_bounds.bottom as usize * 0x200,
|
bottom: npc.hit_bounds.bottom as u32 * 0x200,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Rect { left: 0, top: 0, right: 0, bottom: 0 }
|
Rect { left: 0, top: 0, right: 0, bottom: 0 }
|
||||||
|
|
|
@ -75,6 +75,7 @@ impl NPC {
|
||||||
parent_id: 0,
|
parent_id: 0,
|
||||||
action_counter: 0,
|
action_counter: 0,
|
||||||
action_counter2: 0,
|
action_counter2: 0,
|
||||||
|
action_counter3: 0,
|
||||||
anim_counter: 0,
|
anim_counter: 0,
|
||||||
anim_rect: Rect::new(0, 0, 0, 0),
|
anim_rect: Rect::new(0, 0, 0, 0),
|
||||||
rng: Xoroshiro32PlusPlus::new(0),
|
rng: Xoroshiro32PlusPlus::new(0),
|
||||||
|
@ -231,9 +232,9 @@ impl NPCList {
|
||||||
}
|
}
|
||||||
|
|
||||||
match npc.size {
|
match npc.size {
|
||||||
1 => { self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right, 3, 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, 7, 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, 12, 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);
|
state.game_flags.set(npc.flag_num as usize, true);
|
||||||
|
|
||||||
match npc.size {
|
match npc.size {
|
||||||
1 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right, 3, 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, 7, 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, 12, state, &npc.rng),
|
3 => self.create_death_smoke(npc.x, npc.y, npc.display_bounds.right as usize, 12, state, &npc.rng),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub trait PhysicalEntity {
|
||||||
fn offset_x(&self) -> i32 { 0 }
|
fn offset_x(&self) -> i32 { 0 }
|
||||||
fn offset_y(&self) -> i32 { 0 }
|
fn offset_y(&self) -> i32 { 0 }
|
||||||
|
|
||||||
fn hit_bounds(&self) -> &Rect<usize>;
|
fn hit_bounds(&self) -> &Rect<u32>;
|
||||||
|
|
||||||
fn set_x(&mut self, x: i32);
|
fn set_x(&mut self, x: i32);
|
||||||
fn set_y(&mut self, y: i32);
|
fn set_y(&mut self, y: i32);
|
||||||
|
|
|
@ -57,8 +57,8 @@ pub struct Player {
|
||||||
pub flags: Flag,
|
pub flags: Flag,
|
||||||
pub equip: Equipment,
|
pub equip: Equipment,
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
pub display_bounds: Rect<usize>,
|
pub display_bounds: Rect<u32>,
|
||||||
pub hit_bounds: Rect<usize>,
|
pub hit_bounds: Rect<u32>,
|
||||||
pub control_mode: ControlMode,
|
pub control_mode: ControlMode,
|
||||||
pub question: bool,
|
pub question: bool,
|
||||||
pub booster_fuel: u32,
|
pub booster_fuel: u32,
|
||||||
|
|
|
@ -38,7 +38,7 @@ impl PhysicalEntity for Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn hit_bounds(&self) -> &Rect<usize> {
|
fn hit_bounds(&self) -> &Rect<u32> {
|
||||||
&self.hit_bounds
|
&self.hit_bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl PlayerSkin for BasicPlayerSkin {
|
||||||
PlayerAnimationState::FallingUpsideDown => 10,
|
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 {
|
+ match self.appearance {
|
||||||
PlayerAppearanceState::Default => 0,
|
PlayerAppearanceState::Default => 0,
|
||||||
PlayerAppearanceState::MimigaMask => 32,
|
PlayerAppearanceState::MimigaMask => 32,
|
||||||
|
|
|
@ -63,7 +63,7 @@ impl GameProfile {
|
||||||
let weapon_type: Option<WeaponType> = FromPrimitive::from_u8(weapon.weapon_id as u8);
|
let weapon_type: Option<WeaponType> = FromPrimitive::from_u8(weapon.weapon_id as u8);
|
||||||
|
|
||||||
if let Some(wtype) = weapon_type {
|
if let Some(wtype) = weapon_type {
|
||||||
let w = game_scene.inventory_player1.add_weapon_data(
|
game_scene.inventory_player1.add_weapon_data(
|
||||||
wtype,
|
wtype,
|
||||||
weapon.ammo as u16,
|
weapon.ammo as u16,
|
||||||
weapon.max_ammo as u16,
|
weapon.max_ammo as u16,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use log::info;
|
use log::info;
|
||||||
use num_traits::{abs, clamp};
|
|
||||||
|
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
use crate::common::{Color, Direction, FadeDirection, FadeState, fix9_scale, interpolate_fix9_scale, Rect};
|
use crate::common::{Color, Direction, FadeDirection, FadeState, fix9_scale, interpolate_fix9_scale, Rect};
|
||||||
use crate::components::boss_life_bar::BossLifeBar;
|
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::flash::Flash;
|
||||||
use crate::components::hud::HUD;
|
use crate::components::hud::HUD;
|
||||||
|
use crate::components::inventory::InventoryUI;
|
||||||
use crate::components::stage_select::StageSelect;
|
use crate::components::stage_select::StageSelect;
|
||||||
use crate::entity::GameEntity;
|
use crate::entity::GameEntity;
|
||||||
use crate::frame::{Frame, UpdateTarget};
|
use crate::frame::{Frame, UpdateTarget};
|
||||||
|
@ -26,13 +26,12 @@ use crate::player::{Player, TargetPlayer};
|
||||||
use crate::rng::XorShift;
|
use crate::rng::XorShift;
|
||||||
use crate::scene::Scene;
|
use crate::scene::Scene;
|
||||||
use crate::scene::title_scene::TitleScene;
|
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::stage::{BackgroundType, Stage};
|
||||||
use crate::text_script::{ConfirmSelection, ScriptMode, TextScriptExecutionState, TextScriptLine, TextScriptVM};
|
use crate::text_script::{ConfirmSelection, ScriptMode, TextScriptExecutionState, TextScriptLine, TextScriptVM};
|
||||||
use crate::texture_set::SizedBatch;
|
use crate::texture_set::SizedBatch;
|
||||||
use crate::weapon::bullet::BulletManager;
|
use crate::weapon::bullet::BulletManager;
|
||||||
use crate::weapon::WeaponType;
|
use crate::weapon::WeaponType;
|
||||||
use crate::components::inventory::InventoryUI;
|
|
||||||
|
|
||||||
pub struct GameScene {
|
pub struct GameScene {
|
||||||
pub tick: u32,
|
pub tick: u32,
|
||||||
|
@ -53,7 +52,6 @@ pub struct GameScene {
|
||||||
pub boss: BossNPC,
|
pub boss: BossNPC,
|
||||||
pub bullet_manager: BulletManager,
|
pub bullet_manager: BulletManager,
|
||||||
pub intro_mode: bool,
|
pub intro_mode: bool,
|
||||||
water_visible: bool,
|
|
||||||
tex_background_name: String,
|
tex_background_name: String,
|
||||||
tex_tileset_name: String,
|
tex_tileset_name: String,
|
||||||
map_name_counter: u16,
|
map_name_counter: u16,
|
||||||
|
@ -109,7 +107,6 @@ impl GameScene {
|
||||||
boss: BossNPC::new(),
|
boss: BossNPC::new(),
|
||||||
bullet_manager: BulletManager::new(),
|
bullet_manager: BulletManager::new(),
|
||||||
intro_mode: false,
|
intro_mode: false,
|
||||||
water_visible: true,
|
|
||||||
tex_background_name,
|
tex_background_name,
|
||||||
tex_tileset_name,
|
tex_tileset_name,
|
||||||
map_name_counter: 0,
|
map_name_counter: 0,
|
||||||
|
@ -471,7 +468,7 @@ impl GameScene {
|
||||||
// switch version uses 1xxx flag to show a flipped version of face
|
// switch version uses 1xxx flag to show a flipped version of face
|
||||||
let flip = state.textscript_vm.face > 1000;
|
let flip = state.textscript_vm.face > 1000;
|
||||||
// x1xx flag shows a talking animation
|
// 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;
|
let face_num = state.textscript_vm.face % 100;
|
||||||
|
|
||||||
batch.add_rect_flip(
|
batch.add_rect_flip(
|
||||||
|
@ -827,12 +824,12 @@ impl GameScene {
|
||||||
let mut rect = Rect::new(0, 0, 16, 16);
|
let mut rect = Rect::new(0, 0, 16, 16);
|
||||||
let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time, state.scale);
|
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_x = (frame_x as i32 / 16).clamp(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_y = (frame_y as i32 / 16).clamp(0, self.stage.map.height as i32) as usize;
|
||||||
let tile_end_x =
|
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 =
|
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 {
|
if layer == TileLayer::Snack {
|
||||||
rect = state.constants.world.snack_rect;
|
rect = state.constants.world.snack_rect;
|
||||||
|
@ -898,7 +895,7 @@ impl GameScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
if npc.npc_flags.shootable() {
|
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.life == 0 {
|
||||||
if npc.npc_flags.show_damage() {
|
if npc.npc_flags.show_damage() {
|
||||||
|
@ -1000,7 +997,7 @@ impl GameScene {
|
||||||
npc = unsafe { self.boss.parts.get_unchecked_mut(0) };
|
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 {
|
if npc.life == 0 {
|
||||||
npc.life = npc.id;
|
npc.life = npc.id;
|
||||||
|
@ -1017,7 +1014,7 @@ impl GameScene {
|
||||||
self.npc_list.create_death_smoke(
|
self.npc_list.create_death_smoke(
|
||||||
npc.x,
|
npc.x,
|
||||||
npc.y,
|
npc.y,
|
||||||
npc.display_bounds.right,
|
npc.display_bounds.right as usize,
|
||||||
destroy_count,
|
destroy_count,
|
||||||
state,
|
state,
|
||||||
&npc.rng,
|
&npc.rng,
|
||||||
|
@ -1156,14 +1153,14 @@ impl GameScene {
|
||||||
UpdateTarget::Player => {
|
UpdateTarget::Player => {
|
||||||
if self.player2.cond.alive()
|
if self.player2.cond.alive()
|
||||||
&& !self.player2.cond.hidden()
|
&& !self.player2.cond.hidden()
|
||||||
&& abs(self.player1.x - self.player2.x) < 240 * 0x200
|
&& (self.player1.x - self.player2.x).abs() < 240 * 0x200
|
||||||
&& abs(self.player1.y - self.player2.y) < 200 * 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_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_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_x = self.frame.target_x.clamp(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_y = self.frame.target_y.clamp(self.player1.y, self.player1.y);
|
||||||
} else {
|
} else {
|
||||||
self.frame.target_x = self.player1.target_x;
|
self.frame.target_x = self.player1.target_x;
|
||||||
self.frame.target_y = self.player1.target_y;
|
self.frame.target_y = self.player1.target_y;
|
||||||
|
@ -1189,8 +1186,18 @@ impl GameScene {
|
||||||
self.frame.update(state, &self.stage);
|
self.frame.update(state, &self.stage);
|
||||||
|
|
||||||
if state.control_flags.control_enabled() {
|
if state.control_flags.control_enabled() {
|
||||||
self.inventory_player1.tick_weapons(state, &mut self.player1, TargetPlayer::Player1, &mut self.bullet_manager);
|
self.inventory_player1.tick_weapons(
|
||||||
self.inventory_player2.tick_weapons(state, &mut self.player2, TargetPlayer::Player2, &mut self.bullet_manager);
|
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_player1.tick(state, (&self.player1, &mut self.inventory_player1))?;
|
||||||
self.hud_player2.tick(state, (&self.player2, &mut self.inventory_player2))?;
|
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 hit_rect_size = hit_rect_size * hit_rect_size;
|
||||||
|
|
||||||
let x = (npc.x + npc.offset_x()) / (16 * 0x200);
|
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);
|
let text = format!("{}:{}:{}", npc.id, npc.npc_type, npc.action_num);
|
||||||
state.font.draw_colored_text(
|
state.font.draw_colored_text_scaled(
|
||||||
text.chars(),
|
text.chars(),
|
||||||
((npc.x - self.frame.x) / 0x200) as f32,
|
((npc.x - self.frame.x) / 0x200) as f32,
|
||||||
((npc.y - self.frame.y) / 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),
|
((npc.id & 0xf0) as u8, (npc.cond.0 >> 8) as u8, (npc.id & 0x0f << 4) as u8, 255),
|
||||||
&state.constants,
|
&state.constants,
|
||||||
&mut state.texture_set,
|
&mut state.texture_set,
|
||||||
|
@ -1354,7 +1362,7 @@ impl Scene for GameScene {
|
||||||
match state.textscript_vm.mode {
|
match state.textscript_vm.mode {
|
||||||
ScriptMode::Map if state.control_flags.tick_world() => self.tick_world(state)?,
|
ScriptMode::Map if state.control_flags.tick_world() => self.tick_world(state)?,
|
||||||
ScriptMode::StageSelect => self.stage_select.tick(state, (&self.player1, &self.player2))?,
|
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)))?;*/
|
.scale(Vector2::new(1.0 / state.scale, 1.0 / state.scale)))?;*/
|
||||||
self.draw_black_bars(state, ctx)?;
|
self.draw_black_bars(state, ctx)?;
|
||||||
|
|
||||||
if state.control_flags.control_enabled() {
|
match state.textscript_vm.mode {
|
||||||
self.hud_player1.draw(state, ctx, &self.frame)?;
|
ScriptMode::Map if state.control_flags.control_enabled() => {
|
||||||
self.hud_player2.draw(state, ctx, &self.frame)?;
|
self.hud_player1.draw(state, ctx, &self.frame)?;
|
||||||
self.boss_life_bar.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() {
|
if self.player2.cond.alive() && !self.player2.cond.hidden() {
|
||||||
let y = interpolate_fix9_scale(
|
let y = interpolate_fix9_scale(
|
||||||
self.player2.prev_y - self.frame.prev_y,
|
self.player2.prev_y - self.frame.prev_y,
|
||||||
self.player2.y - self.frame.y,
|
self.player2.y - self.frame.y,
|
||||||
state.frame_time,
|
state.frame_time,
|
||||||
);
|
);
|
||||||
let y = clamp(y, 8.0, state.canvas_size.1 - 8.0 - state.font.line_height(&state.constants));
|
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 {
|
if self.player2.x + 8 * 0x200 < self.frame.x {
|
||||||
state.font.draw_colored_text(
|
state.font.draw_colored_text(
|
||||||
P2_LEFT_TEXT.chars(),
|
P2_LEFT_TEXT.chars(),
|
||||||
9.0,
|
9.0,
|
||||||
y + 1.0,
|
y + 1.0,
|
||||||
(0, 0, 130, 255),
|
(0, 0, 130, 255),
|
||||||
&state.constants,
|
&state.constants,
|
||||||
&mut state.texture_set,
|
&mut state.texture_set,
|
||||||
ctx,
|
ctx,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
state.font.draw_colored_text(
|
state.font.draw_colored_text(
|
||||||
P2_LEFT_TEXT.chars(),
|
P2_LEFT_TEXT.chars(),
|
||||||
8.0,
|
8.0,
|
||||||
y,
|
y,
|
||||||
(96, 96, 255, 255),
|
(96, 96, 255, 255),
|
||||||
&state.constants,
|
&state.constants,
|
||||||
&mut state.texture_set,
|
&mut state.texture_set,
|
||||||
ctx,
|
ctx,
|
||||||
)?;
|
)?;
|
||||||
} else if self.player2.x - 8 * 0x200 > self.frame.x + state.canvas_size.0 as i32 * 0x200 {
|
} 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);
|
let width = state.font.text_width(P2_RIGHT_TEXT.chars(), &state.constants);
|
||||||
|
|
||||||
state.font.draw_colored_text(
|
state.font.draw_colored_text(
|
||||||
P2_RIGHT_TEXT.chars(),
|
P2_RIGHT_TEXT.chars(),
|
||||||
state.canvas_size.0 - width - 8.0 + 1.0,
|
state.canvas_size.0 - width - 8.0 + 1.0,
|
||||||
y + 1.0,
|
y + 1.0,
|
||||||
(0, 0, 130, 255),
|
(0, 0, 130, 255),
|
||||||
&state.constants,
|
&state.constants,
|
||||||
&mut state.texture_set,
|
&mut state.texture_set,
|
||||||
ctx,
|
ctx,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
state.font.draw_colored_text(
|
state.font.draw_colored_text(
|
||||||
P2_RIGHT_TEXT.chars(),
|
P2_RIGHT_TEXT.chars(),
|
||||||
state.canvas_size.0 - width - 8.0,
|
state.canvas_size.0 - width - 8.0,
|
||||||
y,
|
y,
|
||||||
(96, 96, 255, 255),
|
(96, 96, 255, 255),
|
||||||
&state.constants,
|
&state.constants,
|
||||||
&mut state.texture_set,
|
&mut state.texture_set,
|
||||||
ctx,
|
ctx,
|
||||||
)?;
|
)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
ScriptMode::StageSelect => self.stage_select.draw(state, ctx, &self.frame)?,
|
||||||
|
ScriptMode::Inventory => self.inventory_ui.draw(state, ctx, &self.frame)?,
|
||||||
if state.textscript_vm.mode == ScriptMode::StageSelect {
|
_ => {}
|
||||||
self.stage_select.draw(state, ctx, &self.frame)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.draw_fade(state, ctx)?;
|
self.draw_fade(state, ctx)?;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::{GameResult, GameError};
|
use crate::framework::error::{GameResult, GameError};
|
||||||
|
|
||||||
use crate::common::Rect;
|
|
||||||
use crate::scene::Scene;
|
use crate::scene::Scene;
|
||||||
use crate::shared_game_state::SharedGameState;
|
use crate::shared_game_state::SharedGameState;
|
||||||
|
|
||||||
pub struct NoDataScene {
|
pub struct NoDataScene {
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
flag: bool,
|
flag: bool,
|
||||||
err: String,
|
err: String,
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ pub struct NoDataScene {
|
||||||
impl NoDataScene {
|
impl NoDataScene {
|
||||||
pub fn new(err: GameError) -> Self {
|
pub fn new(err: GameError) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
flag: false,
|
flag: false,
|
||||||
err: err.to_string(),
|
err: err.to_string(),
|
||||||
}
|
}
|
||||||
|
@ -23,9 +24,12 @@ impl NoDataScene {
|
||||||
static REL_URL: &str = "https://github.com/doukutsu-rs/game-data/releases";
|
static REL_URL: &str = "https://github.com/doukutsu-rs/game-data/releases";
|
||||||
|
|
||||||
impl Scene for NoDataScene {
|
impl Scene for NoDataScene {
|
||||||
|
#[allow(unused)]
|
||||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
{
|
{
|
||||||
|
use crate::common::Rect;
|
||||||
|
|
||||||
if !self.flag {
|
if !self.flag {
|
||||||
self.flag = true;
|
self.flag = true;
|
||||||
let _ = std::fs::create_dir("/sdcard/doukutsu/");
|
let _ = std::fs::create_dir("/sdcard/doukutsu/");
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::shared_game_state::{SharedGameState, TimingMode};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
#[allow(unused)]
|
||||||
enum CurrentMenu {
|
enum CurrentMenu {
|
||||||
MainMenu,
|
MainMenu,
|
||||||
OptionMenu,
|
OptionMenu,
|
||||||
|
|
|
@ -2,20 +2,20 @@ use std::ops::Div;
|
||||||
|
|
||||||
use bitvec::vec::BitVec;
|
use bitvec::vec::BitVec;
|
||||||
use chrono::{Datelike, Local};
|
use chrono::{Datelike, Local};
|
||||||
use num_traits::clamp;
|
|
||||||
use num_traits::real::Real;
|
|
||||||
|
|
||||||
use crate::bmfont_renderer::BMFontRenderer;
|
use crate::bmfont_renderer::BMFontRenderer;
|
||||||
use crate::caret::{Caret, CaretType};
|
use crate::caret::{Caret, CaretType};
|
||||||
use crate::common::{ControlFlags, Direction, FadeState};
|
use crate::common::{ControlFlags, Direction, FadeState};
|
||||||
use crate::engine_constants::EngineConstants;
|
use crate::engine_constants::EngineConstants;
|
||||||
|
use crate::framework::{filesystem, graphics};
|
||||||
use crate::framework::backend::BackendTexture;
|
use crate::framework::backend::BackendTexture;
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use crate::framework::graphics::{create_texture_mutable, set_render_target};
|
use crate::framework::graphics::{create_texture_mutable, set_render_target};
|
||||||
use crate::framework::keyboard::ScanCode;
|
use crate::framework::keyboard::ScanCode;
|
||||||
use crate::framework::vfs::OpenOptions;
|
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::input::touch_controls::TouchControls;
|
||||||
use crate::npc::NPCTable;
|
use crate::npc::NPCTable;
|
||||||
use crate::profile::GameProfile;
|
use crate::profile::GameProfile;
|
||||||
|
@ -153,6 +153,9 @@ impl SharedGameState {
|
||||||
|
|
||||||
println!("lookup path: {:#?}", texture_set.paths);
|
println!("lookup path: {:#?}", texture_set.paths);
|
||||||
|
|
||||||
|
#[cfg(feature = "hooks")]
|
||||||
|
init_hooks();
|
||||||
|
|
||||||
Ok(SharedGameState {
|
Ok(SharedGameState {
|
||||||
timing_mode: TimingMode::_50Hz,
|
timing_mode: TimingMode::_50Hz,
|
||||||
control_flags: ControlFlags(0),
|
control_flags: ControlFlags(0),
|
||||||
|
@ -193,9 +196,7 @@ impl SharedGameState {
|
||||||
ScanCode::F3 => self.settings.god_mode = !self.settings.god_mode,
|
ScanCode::F3 => self.settings.god_mode = !self.settings.god_mode,
|
||||||
ScanCode::F4 => self.settings.infinite_booster = !self.settings.infinite_booster,
|
ScanCode::F4 => self.settings.infinite_booster = !self.settings.infinite_booster,
|
||||||
ScanCode::F5 => self.settings.subpixel_coords = !self.settings.subpixel_coords,
|
ScanCode::F5 => self.settings.subpixel_coords = !self.settings.subpixel_coords,
|
||||||
ScanCode::F6 => {
|
ScanCode::F6 => self.settings.motion_interpolation = !self.settings.motion_interpolation,
|
||||||
self.settings.motion_interpolation = !self.settings.motion_interpolation
|
|
||||||
}
|
|
||||||
ScanCode::F7 => self.set_speed(1.0),
|
ScanCode::F7 => self.set_speed(1.0),
|
||||||
ScanCode::F8 => {
|
ScanCode::F8 => {
|
||||||
if self.settings.speed > 0.2 {
|
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 {
|
pub fn save_game(&mut self, game_scene: &mut GameScene, ctx: &mut Context) -> GameResult {
|
||||||
if let Ok(data) = filesystem::open_options(
|
if let Ok(data) = filesystem::open_options(ctx, "/Profile.dat", OpenOptions::new().write(true).create(true)) {
|
||||||
ctx,
|
|
||||||
"/Profile.dat",
|
|
||||||
OpenOptions::new().write(true).create(true),
|
|
||||||
) {
|
|
||||||
let profile = GameProfile::dump(self, game_scene);
|
let profile = GameProfile::dump(self, game_scene);
|
||||||
profile.write_save(data)?;
|
profile.write_save(data)?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -315,10 +312,7 @@ impl SharedGameState {
|
||||||
pub fn handle_resize(&mut self, ctx: &mut Context) -> GameResult {
|
pub fn handle_resize(&mut self, ctx: &mut Context) -> GameResult {
|
||||||
self.screen_size = graphics::screen_size(ctx);
|
self.screen_size = graphics::screen_size(ctx);
|
||||||
self.scale = self.screen_size.1.div(230.0).floor().max(1.0);
|
self.scale = self.screen_size.1.div(230.0).floor().max(1.0);
|
||||||
self.canvas_size = (
|
self.canvas_size = (self.screen_size.0 / self.scale, self.screen_size.1 / self.scale);
|
||||||
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);
|
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) {
|
pub fn create_caret(&mut self, x: i32, y: i32, ctype: CaretType, direct: Direction) {
|
||||||
self.carets
|
self.carets.push(Caret::new(x, y, ctype, direct, &self.constants));
|
||||||
.push(Caret::new(x, y, ctype, direct, &self.constants));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_speed(&mut self, value: f64) {
|
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;
|
self.frame_time = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -248,7 +248,7 @@ where
|
||||||
let mut state = PlaybackState::Stopped;
|
let mut state = PlaybackState::Stopped;
|
||||||
let mut saved_state: PlaybackStateType = PlaybackStateType::None;
|
let mut saved_state: PlaybackStateType = PlaybackStateType::None;
|
||||||
let mut speed = 1.0;
|
let mut speed = 1.0;
|
||||||
let mut org_engine = OrgPlaybackEngine::new(&bank);
|
let mut org_engine = OrgPlaybackEngine::new();
|
||||||
#[cfg(feature = "ogg-playback")]
|
#[cfg(feature = "ogg-playback")]
|
||||||
let mut ogg_engine = OggPlaybackEngine::new();
|
let mut ogg_engine = OggPlaybackEngine::new();
|
||||||
let mut pixtone = PixTonePlayback::new();
|
let mut pixtone = PixTonePlayback::new();
|
||||||
|
|
|
@ -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 {
|
pub fn get_state(&self) -> SavedOggPlaybackState {
|
||||||
SavedOggPlaybackState {
|
SavedOggPlaybackState {
|
||||||
|
@ -120,13 +122,13 @@ impl OggPlaybackEngine {
|
||||||
let mut buf = match music.read_dec_packet_itl() {
|
let mut buf = match music.read_dec_packet_itl() {
|
||||||
Ok(Some(buf)) => buf,
|
Ok(Some(buf)) => buf,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
if let Err(e) = music.seek_absgp_pg(0) {
|
if let Err(_) = music.seek_absgp_pg(0) {
|
||||||
vec![0, 1000]
|
vec![0, 1000]
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(_) => {
|
||||||
vec![0, 1000]
|
vec![0, 1000]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -145,11 +147,11 @@ impl OggPlaybackEngine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resample_buffer(&self, mut data: Vec<i16>, sample_rate: u32, channels: u8) -> Vec<i16> {
|
fn resample_buffer(&self, mut data: Vec<i16>, sample_rate: u32, _channels: u8) -> Vec<i16> {
|
||||||
if sample_rate != self.output_format.sample_rate {
|
if sample_rate != self.output_format.sample_rate {
|
||||||
let mut tmp_data = Vec::new();
|
let mut tmp_data = Vec::new();
|
||||||
let mut pos = 0.0;
|
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 {
|
loop {
|
||||||
if pos >= data.len() as f32 {
|
if pos >= data.len() as f32 {
|
||||||
|
|
|
@ -41,7 +41,7 @@ impl Clone for SavedOrganyaPlaybackState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OrgPlaybackEngine {
|
impl OrgPlaybackEngine {
|
||||||
pub fn new(samples: &SoundBank) -> Self {
|
pub fn new() -> Self {
|
||||||
let mut buffers: [MaybeUninit<RenderBuffer>; 136] = unsafe { MaybeUninit::uninit().assume_init() };
|
let mut buffers: [MaybeUninit<RenderBuffer>; 136] = unsafe { MaybeUninit::uninit().assume_init() };
|
||||||
|
|
||||||
for buffer in buffers.iter_mut() {
|
for buffer in buffers.iter_mut() {
|
||||||
|
|
|
@ -206,6 +206,7 @@ pub struct PixTonePlayback {
|
||||||
pub playback_state: Vec<PlaybackState>,
|
pub playback_state: Vec<PlaybackState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
impl PixTonePlayback {
|
impl PixTonePlayback {
|
||||||
pub fn new() -> PixTonePlayback {
|
pub fn new() -> PixTonePlayback {
|
||||||
PixTonePlayback {
|
PixTonePlayback {
|
||||||
|
|
|
@ -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<u16>) {
|
pub fn add_rect_scaled(&mut self, mut x: f32, mut y: f32, scale_x: f32, scale_y: f32, rect: &common::Rect<u16>) {
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ use crate::common::Direction;
|
||||||
use crate::player::{Player, TargetPlayer};
|
use crate::player::{Player, TargetPlayer};
|
||||||
use crate::shared_game_state::SharedGameState;
|
use crate::shared_game_state::SharedGameState;
|
||||||
use crate::weapon::bullet::BulletManager;
|
use crate::weapon::bullet::BulletManager;
|
||||||
use crate::weapon::WeaponLevel::Level1;
|
|
||||||
use crate::weapon::{Weapon, WeaponLevel};
|
use crate::weapon::{Weapon, WeaponLevel};
|
||||||
|
|
||||||
impl Weapon {
|
impl Weapon {
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::ops::{Add, Sub};
|
|
||||||
|
|
||||||
use num_traits::clamp;
|
use num_traits::clamp;
|
||||||
|
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
|
@ -105,8 +103,8 @@ pub struct Bullet {
|
||||||
pub anim_counter: u16,
|
pub anim_counter: u16,
|
||||||
pub action_num: u16,
|
pub action_num: u16,
|
||||||
pub action_counter: u16,
|
pub action_counter: u16,
|
||||||
pub hit_bounds: Rect<usize>,
|
pub hit_bounds: Rect<u32>,
|
||||||
pub display_bounds: Rect<usize>,
|
pub display_bounds: Rect<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bullet {
|
impl Bullet {
|
||||||
|
@ -152,16 +150,16 @@ impl Bullet {
|
||||||
action_num: 0,
|
action_num: 0,
|
||||||
action_counter: 0,
|
action_counter: 0,
|
||||||
display_bounds: Rect::new(
|
display_bounds: Rect::new(
|
||||||
bullet.display_bounds.left as usize * 0x200,
|
bullet.display_bounds.left as u32 * 0x200,
|
||||||
bullet.display_bounds.top as usize * 0x200,
|
bullet.display_bounds.top as u32 * 0x200,
|
||||||
bullet.display_bounds.right as usize * 0x200,
|
bullet.display_bounds.right as u32 * 0x200,
|
||||||
bullet.display_bounds.bottom as usize * 0x200,
|
bullet.display_bounds.bottom as u32 * 0x200,
|
||||||
),
|
),
|
||||||
hit_bounds: Rect::new(
|
hit_bounds: Rect::new(
|
||||||
bullet.block_hit_width as usize * 0x200,
|
bullet.block_hit_width as u32 * 0x200,
|
||||||
bullet.block_hit_height as usize * 0x200,
|
bullet.block_hit_height as u32 * 0x200,
|
||||||
bullet.block_hit_width as usize * 0x200,
|
bullet.block_hit_width as u32 * 0x200,
|
||||||
bullet.block_hit_height as usize * 0x200,
|
bullet.block_hit_height as u32 * 0x200,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1515,7 +1513,7 @@ impl PhysicalEntity for Bullet {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn hit_bounds(&self) -> &Rect<usize> {
|
fn hit_bounds(&self) -> &Rect<u32> {
|
||||||
&self.hit_bounds
|
&self.hit_bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue