mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-03-24 19:09:22 +00:00
add carets and fix booster
This commit is contained in:
parent
1993720f34
commit
ef9ca2e89a
|
@ -1,6 +1,6 @@
|
|||
# doukutsu-rs
|
||||
|
||||
A re-implementation of Cave Story (Doukutsu Monogatari) engine written in [Rust](https://www.rust-lang.org/), aiming for accuracy and cleaner code.
|
||||
A re-implementation of Cave Story (Doukutsu Monogatari) engine written in [Rust](https://www.rust-lang.org/), aiming for behavior accuracy and cleaner code.
|
||||
Later plans might involve turning it into a fully-featured modding tool with live debugging and stuff.
|
||||
|
||||
**The project is still in a very early state and nowhere near being playable. Expect lots of breaking changes and bugs**
|
||||
|
@ -26,7 +26,7 @@ The engine should work fine with [CSE2-Enhanced](https://github.com/Clownacy/CSE
|
|||
|
||||
The project is a result of me wanting to build something in a new programming language for memes.
|
||||
|
||||
I had an idea of writing my own CS engine long time before and I would've very likely picked C++17/20+SDL2, but after
|
||||
I had an idea of writing my own CS engine long time before and I would've very likely picked C++17/20 and SDL2, but after
|
||||
all I've picked Rust instead because it seemed quite interesting for me.
|
||||
|
||||
Would 90% of end-users running this thing care about the programming language software was written in? After all who tf cares if the performance is the same (and maybe a slightly better), but you also get a lot of various benefits?
|
||||
|
|
132
src/caret.rs
Normal file
132
src/caret.rs
Normal file
|
@ -0,0 +1,132 @@
|
|||
use crate::bitfield;
|
||||
use crate::common::{Direction, Rect};
|
||||
use crate::engine_constants::EngineConstants;
|
||||
|
||||
bitfield! {
|
||||
pub struct Cond(u16);
|
||||
impl Debug;
|
||||
|
||||
pub visible, set_visible: 7;
|
||||
}
|
||||
|
||||
#[derive(Debug, EnumIter, PartialEq, Eq, Hash, Copy, Clone)]
|
||||
pub enum CaretType {
|
||||
None,
|
||||
Bubble,
|
||||
ProjectileDissipation,
|
||||
Shoot,
|
||||
SnakeAfterimage,
|
||||
Zzz,
|
||||
SnakeAfterimage2,
|
||||
Exhaust,
|
||||
DrownedQuote,
|
||||
QuestionMark,
|
||||
LevelUp,
|
||||
HurtParticles,
|
||||
Explosion,
|
||||
SmallParticles,
|
||||
Unknown,
|
||||
SmallProjectileDissipation,
|
||||
Empty,
|
||||
PushJumpKey,
|
||||
}
|
||||
|
||||
pub struct Caret {
|
||||
pub ctype: CaretType,
|
||||
pub x: isize,
|
||||
pub y: isize,
|
||||
pub vel_x: isize,
|
||||
pub vel_y: isize,
|
||||
pub offset_x: isize,
|
||||
pub offset_y: isize,
|
||||
pub cond: Cond,
|
||||
pub direct: Direction,
|
||||
pub anim_rect: Rect<usize>,
|
||||
anim_num: usize,
|
||||
anim_wait: isize,
|
||||
}
|
||||
|
||||
impl Caret {
|
||||
pub fn new(x: isize, y: isize, ctype: CaretType, direct: Direction, constants: &EngineConstants) -> Self {
|
||||
let (offset_x, offset_y) = constants.caret.offsets[ctype as usize];
|
||||
Self {
|
||||
ctype,
|
||||
x,
|
||||
y,
|
||||
vel_x: 0,
|
||||
vel_y: 0,
|
||||
offset_x,
|
||||
offset_y,
|
||||
cond: Cond(0x80),
|
||||
direct,
|
||||
anim_rect: Rect::<usize>::new(0, 0, 0, 0),
|
||||
anim_num: 0,
|
||||
anim_wait: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, constants: &EngineConstants) {
|
||||
match self.ctype {
|
||||
CaretType::None => {}
|
||||
CaretType::Bubble => {}
|
||||
CaretType::ProjectileDissipation => {}
|
||||
CaretType::Shoot => {}
|
||||
CaretType::SnakeAfterimage | CaretType::SnakeAfterimage2 => { // dupe, unused
|
||||
}
|
||||
CaretType::Zzz => {}
|
||||
CaretType::Exhaust => {
|
||||
self.anim_wait += 1;
|
||||
if self.anim_wait > 1 {
|
||||
self.anim_wait = 0;
|
||||
self.anim_num += 1;
|
||||
}
|
||||
|
||||
if self.anim_num >= constants.caret.exhaust_rects.len() {
|
||||
self.cond.set_visible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
self.anim_rect = constants.caret.exhaust_rects[self.anim_num];
|
||||
|
||||
match self.direct {
|
||||
Direction::Left => { self.x -= 0x400; }
|
||||
Direction::Up => { self.y -= 0x400; }
|
||||
Direction::Right => { self.x += 0x400; }
|
||||
Direction::Bottom => { self.y += 0x400; }
|
||||
}
|
||||
}
|
||||
CaretType::DrownedQuote => {}
|
||||
CaretType::QuestionMark => {
|
||||
self.anim_wait += 1;
|
||||
if self.anim_wait < 5 {
|
||||
self.y -= 0x800;
|
||||
}
|
||||
|
||||
if self.anim_wait == 32 {
|
||||
self.cond.set_visible(false);
|
||||
}
|
||||
|
||||
self.anim_rect = match self.direct {
|
||||
Direction::Left => { constants.caret.question_left_rect }
|
||||
Direction::Right => { constants.caret.question_right_rect }
|
||||
_ => { self.anim_rect }
|
||||
}
|
||||
}
|
||||
CaretType::LevelUp => {}
|
||||
CaretType::HurtParticles => {}
|
||||
CaretType::Explosion => {}
|
||||
CaretType::SmallParticles => {}
|
||||
CaretType::Unknown => {
|
||||
// not implemented because it was apparently broken in og game?
|
||||
self.cond.set_visible(false);
|
||||
}
|
||||
CaretType::SmallProjectileDissipation => {}
|
||||
CaretType::Empty => {}
|
||||
CaretType::PushJumpKey => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_dead(&self) -> bool {
|
||||
!self.cond.visible()
|
||||
}
|
||||
}
|
|
@ -25,6 +25,15 @@ impl Direction {
|
|||
_ => { None }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opposite(&self) -> Direction {
|
||||
match self {
|
||||
Direction::Left => { Direction::Right }
|
||||
Direction::Up => { Direction::Bottom }
|
||||
Direction::Right => { Direction::Left }
|
||||
Direction::Bottom => { Direction::Up }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use log::info;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use log::info;
|
||||
use maplit::hashmap;
|
||||
|
||||
use crate::common::{Direction, Rect};
|
||||
|
@ -21,6 +21,7 @@ pub struct PhysicsConsts {
|
|||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct BoosterConsts {
|
||||
pub fuel: usize,
|
||||
pub b2_0_up: isize,
|
||||
pub b2_0_up_nokey: isize,
|
||||
pub b2_0_down: isize,
|
||||
|
@ -36,8 +37,8 @@ pub struct MyCharConsts {
|
|||
pub direction: Direction,
|
||||
pub view: Rect<usize>,
|
||||
pub hit: Rect<usize>,
|
||||
pub life: u16,
|
||||
pub max_life: u16,
|
||||
pub life: usize,
|
||||
pub max_life: usize,
|
||||
pub unit: u8,
|
||||
pub air_physics: PhysicsConsts,
|
||||
pub water_physics: PhysicsConsts,
|
||||
|
@ -45,20 +46,45 @@ pub struct MyCharConsts {
|
|||
pub animations_right: [Rect<usize>; 12],
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CaretConsts {
|
||||
pub offsets: [(isize, isize); 18],
|
||||
pub bubble_left_rects: Vec<Rect<usize>>,
|
||||
pub bubble_right_rects: Vec<Rect<usize>>,
|
||||
pub exhaust_rects: Vec<Rect<usize>>,
|
||||
pub question_left_rect: Rect<usize>,
|
||||
pub question_right_rect: Rect<usize>,
|
||||
}
|
||||
|
||||
impl Clone for CaretConsts {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
offsets: self.offsets,
|
||||
bubble_left_rects: self.bubble_left_rects.clone(),
|
||||
bubble_right_rects: self.bubble_right_rects.clone(),
|
||||
exhaust_rects: self.exhaust_rects.clone(),
|
||||
question_left_rect: self.question_left_rect,
|
||||
question_right_rect: self.question_right_rect,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EngineConstants {
|
||||
pub is_cs_plus: bool,
|
||||
pub my_char: MyCharConsts,
|
||||
pub booster: BoosterConsts,
|
||||
pub caret: CaretConsts,
|
||||
pub tex_sizes: HashMap<String, (usize, usize)>,
|
||||
}
|
||||
|
||||
impl Clone for EngineConstants {
|
||||
fn clone(&self) -> Self {
|
||||
EngineConstants {
|
||||
Self {
|
||||
is_cs_plus: self.is_cs_plus,
|
||||
my_char: self.my_char,
|
||||
booster: self.booster,
|
||||
caret: self.caret.clone(),
|
||||
tex_sizes: self.tex_sizes.clone(),
|
||||
}
|
||||
}
|
||||
|
@ -128,11 +154,57 @@ impl EngineConstants {
|
|||
],
|
||||
},
|
||||
booster: BoosterConsts {
|
||||
fuel: 50,
|
||||
b2_0_up: -0x5ff,
|
||||
b2_0_up_nokey: -0x5ff,
|
||||
b2_0_down: 0x5ff,
|
||||
b2_0_left: -0x5ff,
|
||||
b2_0_right: 0x5ff
|
||||
b2_0_right: 0x5ff,
|
||||
},
|
||||
caret: CaretConsts {
|
||||
offsets: [
|
||||
(0, 0),
|
||||
(4 * 0x200, 4 * 0x200),
|
||||
(8 * 0x200, 8 * 0x200),
|
||||
(8 * 0x200, 8 * 0x200),
|
||||
(8 * 0x200, 8 * 0x200),
|
||||
(4 * 0x200, 4 * 0x200),
|
||||
(8 * 0x200, 8 * 0x200),
|
||||
(4 * 0x200, 4 * 0x200),
|
||||
(8 * 0x200, 8 * 0x200),
|
||||
(8 * 0x200, 8 * 0x200),
|
||||
(28 * 0x200, 8 * 0x200),
|
||||
(4 * 0x200, 4 * 0x200),
|
||||
(16 * 0x200, 16 * 0x200),
|
||||
(4 * 0x200, 4 * 0x200),
|
||||
(20 * 0x200, 20 * 0x200),
|
||||
(4 * 0x200, 4 * 0x200),
|
||||
(20 * 0x200, 4 * 0x200),
|
||||
(52 * 0x200, 4 * 0x200),
|
||||
],
|
||||
bubble_left_rects: vec![
|
||||
Rect { left: 0, top: 64, right: 8, bottom: 72 },
|
||||
Rect { left: 8, top: 64, right: 16, bottom: 72 },
|
||||
Rect { left: 16, top: 64, right: 24, bottom: 72 },
|
||||
Rect { left: 24, top: 64, right: 32, bottom: 72 },
|
||||
],
|
||||
bubble_right_rects: vec![
|
||||
Rect { left: 64, top: 24, right: 72, bottom: 32 },
|
||||
Rect { left: 72, top: 24, right: 80, bottom: 32 },
|
||||
Rect { left: 80, top: 24, right: 88, bottom: 32 },
|
||||
Rect { left: 88, top: 24, right: 96, bottom: 32 },
|
||||
],
|
||||
exhaust_rects: vec![
|
||||
Rect { left: 56, top: 0, right: 64, bottom: 8 },
|
||||
Rect { left: 64, top: 0, right: 72, bottom: 8 },
|
||||
Rect { left: 72, top: 0, right: 80, bottom: 8 },
|
||||
Rect { left: 80, top: 0, right: 88, bottom: 8 },
|
||||
Rect { left: 88, top: 0, right: 96, bottom: 8 },
|
||||
Rect { left: 96, top: 0, right: 104, bottom: 8 },
|
||||
Rect { left: 104, top: 0, right: 112, bottom: 8 },
|
||||
],
|
||||
question_left_rect: Rect { left: 0, top: 80, right: 16, bottom: 96 },
|
||||
question_right_rect: Rect { left: 48, top: 64, right: 64, bottom: 80 },
|
||||
},
|
||||
tex_sizes: hashmap! {
|
||||
str!("ArmsImage") => (256, 16),
|
||||
|
@ -257,6 +329,7 @@ impl EngineConstants {
|
|||
info!("Applying Cave Story+ constants patches...");
|
||||
|
||||
self.is_cs_plus = true;
|
||||
self.tex_sizes.insert(str!("Caret"), (320, 320));
|
||||
self.tex_sizes.insert(str!("MyChar"), (200, 384));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
//!
|
||||
//! ```
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![deny(missing_docs)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![deny(unused_results)]
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use crate::ggez::{Context, GameResult};
|
||||
use imgui::{Condition, im_str, ImStr, ImString, Window};
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::ggez::{Context, GameResult};
|
||||
use crate::scene::game_scene::GameScene;
|
||||
use crate::SharedGameState;
|
||||
|
||||
pub struct LiveDebugger {
|
||||
selected_item: i32,
|
||||
map_selector_visible: bool,
|
||||
stages: Vec<ImString>,
|
||||
error: Option<ImString>,
|
||||
}
|
||||
|
@ -15,21 +16,37 @@ impl LiveDebugger {
|
|||
pub fn new() -> Self {
|
||||
Self {
|
||||
selected_item: -1,
|
||||
map_selector_visible: false,
|
||||
stages: vec![],
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_ingame(&mut self, game_scene: &mut GameScene, state: &mut SharedGameState, ctx: &mut Context, ui: &mut imgui::Ui) -> GameResult {
|
||||
/*Window::new(im_str!("Live Debugger"))
|
||||
Window::new(im_str!("Live Debugger"))
|
||||
.position([5.0, 5.0], Condition::FirstUseEver)
|
||||
.size([300.0, 100.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
ui.text(format!(
|
||||
"Player position: ({:.1},{:.1})",
|
||||
state.player.x as f32 / 512.0,
|
||||
state.player.y as f32 / 512.0,
|
||||
game_scene.player.x as f32 / 512.0,
|
||||
game_scene.player.y as f32 / 512.0,
|
||||
));
|
||||
});*/
|
||||
|
||||
ui.text(format!(
|
||||
"Player velocity: ({:.1},{:.1})",
|
||||
game_scene.player.vel_x as f32 / 512.0,
|
||||
game_scene.player.vel_y as f32 / 512.0,
|
||||
));
|
||||
|
||||
ui.text(format!(
|
||||
"Booster fuel: ({})", game_scene.player.booster_fuel
|
||||
));
|
||||
|
||||
if ui.button(im_str!("Map Selector"), [0.0, 0.0]) {
|
||||
self.map_selector_visible = true;
|
||||
}
|
||||
});
|
||||
|
||||
if self.error.is_some() {
|
||||
Window::new(im_str!("Error!"))
|
||||
|
@ -47,39 +64,41 @@ impl LiveDebugger {
|
|||
});
|
||||
}
|
||||
|
||||
Window::new(im_str!("Map selector"))
|
||||
.resizable(false)
|
||||
.collapsed(true, Condition::FirstUseEver)
|
||||
.size([240.0, 280.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
if self.stages.is_empty() {
|
||||
for s in state.stages.iter() {
|
||||
self.stages.push(ImString::new(s.name.to_owned()));
|
||||
}
|
||||
|
||||
self.selected_item = match state.stages.iter().find_position(|s| s.name == game_scene.stage.data.name) {
|
||||
Some((pos, _)) => { pos as i32 }
|
||||
_ => { -1 }
|
||||
};
|
||||
}
|
||||
let stages: Vec<&ImStr> = self.stages.iter().map(|e| e.as_ref()).collect();
|
||||
|
||||
ui.push_item_width(-1.0);
|
||||
ui.list_box(im_str!(""), &mut self.selected_item, &stages, 10);
|
||||
|
||||
if ui.button(im_str!("Load"), [0.0, 0.0]) {
|
||||
match GameScene::new(state, ctx, self.selected_item as usize) {
|
||||
Ok(mut scene) => {
|
||||
scene.player.x = (scene.stage.map.width / 2 * 16 * 0x200) as isize;
|
||||
scene.player.y = (scene.stage.map.height / 2 * 16 * 0x200) as isize;
|
||||
state.next_scene = Some(Box::new(scene));
|
||||
if self.map_selector_visible {
|
||||
Window::new(im_str!("Map selector"))
|
||||
.resizable(false)
|
||||
.position([5.0, 35.0], Condition::FirstUseEver)
|
||||
.size([240.0, 280.0], Condition::FirstUseEver)
|
||||
.build(ui, || {
|
||||
if self.stages.is_empty() {
|
||||
for s in state.stages.iter() {
|
||||
self.stages.push(ImString::new(s.name.to_owned()));
|
||||
}
|
||||
Err(e) => {
|
||||
self.error = Some(ImString::new(e.to_string()));
|
||||
|
||||
self.selected_item = match state.stages.iter().find_position(|s| s.name == game_scene.stage.data.name) {
|
||||
Some((pos, _)) => { pos as i32 }
|
||||
_ => { -1 }
|
||||
};
|
||||
}
|
||||
let stages: Vec<&ImStr> = self.stages.iter().map(|e| e.as_ref()).collect();
|
||||
|
||||
ui.push_item_width(-1.0);
|
||||
ui.list_box(im_str!(""), &mut self.selected_item, &stages, 10);
|
||||
|
||||
if ui.button(im_str!("Load"), [0.0, 0.0]) {
|
||||
match GameScene::new(state, ctx, self.selected_item as usize) {
|
||||
Ok(mut scene) => {
|
||||
scene.player.x = (scene.stage.map.width / 2 * 16 * 0x200) as isize;
|
||||
scene.player.y = (scene.stage.map.height / 2 * 16 * 0x200) as isize;
|
||||
state.next_scene = Some(Box::new(scene));
|
||||
}
|
||||
Err(e) => {
|
||||
self.error = Some(ImString::new(e.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
19
src/main.rs
19
src/main.rs
|
@ -35,7 +35,10 @@ use crate::sound::SoundManager;
|
|||
use crate::stage::StageData;
|
||||
use crate::texture_set::TextureSet;
|
||||
use crate::ui::UI;
|
||||
use crate::caret::{Caret, CaretType};
|
||||
use crate::common::Direction;
|
||||
|
||||
mod caret;
|
||||
mod common;
|
||||
mod engine_constants;
|
||||
mod entity;
|
||||
|
@ -46,12 +49,14 @@ mod live_debugger;
|
|||
mod map;
|
||||
mod player;
|
||||
mod player_hit;
|
||||
mod rng;
|
||||
mod scene;
|
||||
mod stage;
|
||||
mod sound;
|
||||
mod text_script;
|
||||
mod texture_set;
|
||||
mod ui;
|
||||
mod weapon;
|
||||
|
||||
bitfield! {
|
||||
pub struct KeyState(u16);
|
||||
|
@ -86,6 +91,7 @@ struct Game {
|
|||
|
||||
pub struct SharedGameState {
|
||||
pub flags: GameFlags,
|
||||
pub carets: Vec<Caret>,
|
||||
pub key_state: KeyState,
|
||||
pub key_trigger: KeyState,
|
||||
pub texture_set: TextureSet,
|
||||
|
@ -107,6 +113,18 @@ impl SharedGameState {
|
|||
self.key_old = self.key_state.0;
|
||||
self.key_trigger = KeyState(trigger);
|
||||
}
|
||||
|
||||
pub fn tick_carets(&mut self) {
|
||||
for caret in self.carets.iter_mut() {
|
||||
caret.tick(&self.constants);
|
||||
}
|
||||
|
||||
self.carets.retain(|c| !c.is_dead());
|
||||
}
|
||||
|
||||
pub fn create_caret(&mut self, x: isize, y: isize, ctype: CaretType, direct: Direction) {
|
||||
self.carets.push(Caret::new(x, y, ctype, direct, &self.constants));
|
||||
}
|
||||
}
|
||||
|
||||
impl Game {
|
||||
|
@ -137,6 +155,7 @@ impl Game {
|
|||
def_matrix: DrawParam::new().to_matrix(),
|
||||
state: SharedGameState {
|
||||
flags: GameFlags(0),
|
||||
carets: Vec::new(),
|
||||
key_state: KeyState(0),
|
||||
key_trigger: KeyState(0),
|
||||
texture_set: TextureSet::new(base_path),
|
||||
|
|
290
src/player.rs
290
src/player.rs
|
@ -1,11 +1,11 @@
|
|||
use crate::ggez::{Context, GameResult};
|
||||
use num_traits::clamp;
|
||||
|
||||
use crate::bitfield;
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{Direction, Rect};
|
||||
use crate::engine_constants::PhysicsConsts;
|
||||
use crate::entity::GameEntity;
|
||||
use crate::frame::Frame;
|
||||
use crate::ggez::{Context, GameResult};
|
||||
use crate::SharedGameState;
|
||||
use crate::str;
|
||||
|
||||
|
@ -69,31 +69,30 @@ bitfield! {
|
|||
pub struct Player {
|
||||
pub x: isize,
|
||||
pub y: isize,
|
||||
pub xm: isize,
|
||||
pub ym: isize,
|
||||
pub vel_x: isize,
|
||||
pub vel_y: isize,
|
||||
pub target_x: isize,
|
||||
pub target_y: isize,
|
||||
pub life: usize,
|
||||
pub max_life: usize,
|
||||
pub cond: Cond,
|
||||
pub flags: Flags,
|
||||
pub equip: Equip,
|
||||
pub direction: Direction,
|
||||
pub view: Rect<usize>,
|
||||
pub hit: Rect<usize>,
|
||||
pub life: u16,
|
||||
pub max_life: u16,
|
||||
pub unit: u8,
|
||||
pub air_physics: PhysicsConsts,
|
||||
pub water_physics: PhysicsConsts,
|
||||
pub question: bool,
|
||||
pub booster_fuel: usize,
|
||||
index_x: isize,
|
||||
index_y: isize,
|
||||
sprash: bool,
|
||||
ques: bool,
|
||||
up: bool,
|
||||
down: bool,
|
||||
shock: u8,
|
||||
shock_counter: u8,
|
||||
booster_switch: u8,
|
||||
star: u8,
|
||||
bubble: u8,
|
||||
boost_sw: u8,
|
||||
boost_cnt: isize,
|
||||
exp_wait: isize,
|
||||
exp_count: isize,
|
||||
anim_num: usize,
|
||||
|
@ -111,31 +110,30 @@ impl Player {
|
|||
Ok(Player {
|
||||
x: 0,
|
||||
y: 0,
|
||||
xm: 0,
|
||||
ym: 0,
|
||||
vel_x: 0,
|
||||
vel_y: 0,
|
||||
target_x: 0,
|
||||
target_y: 0,
|
||||
life: constants.my_char.life,
|
||||
max_life: constants.my_char.max_life,
|
||||
cond: Cond(constants.my_char.cond),
|
||||
flags: Flags(constants.my_char.flags),
|
||||
equip: Equip(constants.my_char.equip),
|
||||
direction: constants.my_char.direction.clone(),
|
||||
view: constants.my_char.view,
|
||||
hit: constants.my_char.hit,
|
||||
life: constants.my_char.life,
|
||||
max_life: constants.my_char.max_life,
|
||||
unit: constants.my_char.unit,
|
||||
air_physics: constants.my_char.air_physics,
|
||||
water_physics: constants.my_char.water_physics,
|
||||
question: false,
|
||||
booster_fuel: 0,
|
||||
index_x: 0,
|
||||
index_y: 0,
|
||||
sprash: false,
|
||||
ques: false,
|
||||
up: false,
|
||||
down: false,
|
||||
shock: 0,
|
||||
shock_counter: 0,
|
||||
booster_switch: 0,
|
||||
star: 0,
|
||||
bubble: 0,
|
||||
boost_sw: 0,
|
||||
boost_cnt: 0,
|
||||
exp_wait: 0,
|
||||
exp_count: 0,
|
||||
anim_num: 0,
|
||||
|
@ -145,42 +143,42 @@ impl Player {
|
|||
})
|
||||
}
|
||||
|
||||
fn tick_normal(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult<()> {
|
||||
fn tick_normal(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.cond.cond_x02() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let physics = if self.flags.underwater() { &self.water_physics } else { &self.air_physics };
|
||||
let physics = if self.flags.underwater() { state.constants.my_char.water_physics } else { state.constants.my_char.air_physics };
|
||||
|
||||
self.ques = false;
|
||||
self.question = false;
|
||||
|
||||
if !state.flags.control_enabled() {
|
||||
self.boost_sw = 0;
|
||||
self.booster_switch = 0;
|
||||
}
|
||||
|
||||
// todo: split those into separate procedures and refactor (try to not break the logic!)
|
||||
|
||||
// ground movement
|
||||
if self.flags.flag_x08() || self.flags.flag_x10() || self.flags.flag_x20() {
|
||||
self.boost_sw = 0;
|
||||
self.booster_switch = 0;
|
||||
|
||||
if self.equip.has_booster_0_8() || self.equip.has_booster_2_0() {
|
||||
self.boost_cnt = 50;
|
||||
self.booster_fuel = state.constants.booster.fuel;
|
||||
} else {
|
||||
self.boost_cnt = 0;
|
||||
self.booster_fuel = 0;
|
||||
}
|
||||
|
||||
if state.flags.control_enabled() {
|
||||
if state.key_trigger.only_down() && state.key_state.only_down() && !self.cond.cond_x01() && state.flags.flag_x04() {
|
||||
if state.key_trigger.only_down() && state.key_state.only_down() && !self.cond.cond_x01() && !state.flags.flag_x04() {
|
||||
self.cond.set_cond_x01(true);
|
||||
self.ques = true;
|
||||
self.question = true;
|
||||
} else {
|
||||
if state.key_state.left() && self.xm > -physics.max_dash {
|
||||
self.xm -= physics.dash_ground;
|
||||
if state.key_state.left() && self.vel_x > -physics.max_dash {
|
||||
self.vel_x -= physics.dash_ground;
|
||||
}
|
||||
|
||||
if state.key_state.right() && self.xm < physics.max_dash {
|
||||
self.xm += physics.dash_ground;
|
||||
if state.key_state.right() && self.vel_x < physics.max_dash {
|
||||
self.vel_x += physics.dash_ground;
|
||||
}
|
||||
|
||||
if state.key_state.left() {
|
||||
|
@ -194,62 +192,61 @@ impl Player {
|
|||
}
|
||||
|
||||
if !self.cond.cond_x20() {
|
||||
if self.xm < 0 {
|
||||
if self.xm > -physics.resist {
|
||||
self.xm = 0;
|
||||
if self.vel_x < 0 {
|
||||
if self.vel_x > -physics.resist {
|
||||
self.vel_x = 0;
|
||||
} else {
|
||||
self.xm += physics.resist;
|
||||
self.vel_x += physics.resist;
|
||||
}
|
||||
} else if self.xm > 0 {
|
||||
if self.xm < physics.resist {
|
||||
self.xm = 0;
|
||||
}
|
||||
if self.vel_x > 0 {
|
||||
if self.vel_x < physics.resist {
|
||||
self.vel_x = 0;
|
||||
} else {
|
||||
self.xm -= physics.resist;
|
||||
self.vel_x -= physics.resist;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // air movement
|
||||
if state.flags.control_enabled() {
|
||||
if (self.equip.has_booster_0_8() || self.equip.has_booster_2_0()) && state.key_trigger.jump() && self.boost_cnt != 0 {
|
||||
if state.key_trigger.jump() && self.booster_fuel != 0 {
|
||||
if self.equip.has_booster_0_8() {
|
||||
self.boost_sw = 1;
|
||||
self.booster_switch = 1;
|
||||
|
||||
if self.ym > 0x100 { // 0.5fix9
|
||||
self.ym /= 2;
|
||||
if self.vel_y > 0x100 { // 0.5fix9
|
||||
self.vel_y /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if self.equip.has_booster_2_0() {
|
||||
} else if self.equip.has_booster_2_0() {
|
||||
if state.key_state.up() {
|
||||
self.boost_sw = 2;
|
||||
self.xm = 0;
|
||||
self.ym = state.constants.booster.b2_0_up;
|
||||
self.booster_switch = 2;
|
||||
self.vel_x = 0;
|
||||
self.vel_y = state.constants.booster.b2_0_up;
|
||||
} else if state.key_state.left() {
|
||||
self.boost_sw = 2;
|
||||
self.xm = 0;
|
||||
self.ym = state.constants.booster.b2_0_left;
|
||||
self.booster_switch = 1;
|
||||
self.vel_x = state.constants.booster.b2_0_left;
|
||||
self.vel_y = 0;
|
||||
} else if state.key_state.right() {
|
||||
self.boost_sw = 2;
|
||||
self.xm = 0;
|
||||
self.ym = state.constants.booster.b2_0_right;
|
||||
self.booster_switch = 1;
|
||||
self.vel_x = state.constants.booster.b2_0_right;
|
||||
self.vel_y = 0;
|
||||
} else if state.key_state.down() {
|
||||
self.boost_sw = 2;
|
||||
self.xm = 0;
|
||||
self.ym = state.constants.booster.b2_0_down;
|
||||
self.booster_switch = 3;
|
||||
self.vel_x = 0;
|
||||
self.vel_y = state.constants.booster.b2_0_down;
|
||||
} else {
|
||||
self.boost_sw = 2;
|
||||
self.xm = 0;
|
||||
self.ym = state.constants.booster.b2_0_up_nokey;
|
||||
self.booster_switch = 2;
|
||||
self.vel_x = 0;
|
||||
self.vel_y = state.constants.booster.b2_0_up_nokey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if state.key_state.left() && self.xm > -physics.max_dash {
|
||||
self.xm -= physics.dash_air;
|
||||
if state.key_state.left() && self.vel_x > -physics.max_dash {
|
||||
self.vel_x -= physics.dash_air;
|
||||
}
|
||||
|
||||
if state.key_state.right() && self.xm < physics.max_dash {
|
||||
self.xm += physics.dash_air;
|
||||
if state.key_state.right() && self.vel_x < physics.max_dash {
|
||||
self.vel_x += physics.dash_air;
|
||||
}
|
||||
|
||||
if state.key_state.left() {
|
||||
|
@ -261,16 +258,16 @@ impl Player {
|
|||
}
|
||||
}
|
||||
|
||||
if self.equip.has_booster_2_0() && self.boost_sw != 0 && !state.key_state.jump() || self.boost_cnt == 0 {
|
||||
match self.boost_sw {
|
||||
1 => { self.xm /= 2 }
|
||||
2 => { self.ym /= 2 }
|
||||
if self.equip.has_booster_2_0() && self.booster_switch != 0 && (!state.key_state.jump() || self.booster_fuel == 0) {
|
||||
match self.booster_switch {
|
||||
1 => { self.vel_x /= 2 }
|
||||
2 => { self.vel_y /= 2 }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if self.boost_cnt == 0 || !state.key_state.jump() {
|
||||
self.boost_cnt = 0;
|
||||
if self.booster_fuel == 0 || !state.key_state.jump() {
|
||||
self.booster_switch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,7 +278,7 @@ impl Player {
|
|||
|
||||
if state.key_trigger.jump() && (self.flags.flag_x08() || self.flags.flag_x10() || self.flags.flag_x20()) {
|
||||
if !self.flags.force_up() {
|
||||
self.ym = -physics.jump;
|
||||
self.vel_y = -physics.jump;
|
||||
// todo: PlaySoundObject(15, SOUND_MODE_PLAY);
|
||||
}
|
||||
}
|
||||
|
@ -293,110 +290,107 @@ impl Player {
|
|||
}
|
||||
|
||||
// booster losing fuel
|
||||
if self.boost_sw != 0 && self.boost_cnt != 0 {
|
||||
self.boost_cnt -= 1;
|
||||
if self.booster_switch != 0 && self.booster_fuel != 0 {
|
||||
self.booster_fuel -= 1;
|
||||
}
|
||||
|
||||
// wind / current forces
|
||||
|
||||
if self.flags.force_left() {
|
||||
self.xm -= 0x88;
|
||||
self.vel_x -= 0x88;
|
||||
}
|
||||
if self.flags.force_up() {
|
||||
self.ym -= 0x80;
|
||||
self.vel_y -= 0x80;
|
||||
}
|
||||
if self.flags.force_right() {
|
||||
self.xm += 0x80;
|
||||
self.vel_x += 0x80;
|
||||
}
|
||||
if self.flags.force_down() {
|
||||
self.ym += 0x55;
|
||||
self.vel_y += 0x55;
|
||||
}
|
||||
|
||||
if self.equip.has_booster_2_0() && self.boost_sw != 0 {
|
||||
match self.boost_sw {
|
||||
if self.equip.has_booster_2_0() && self.booster_switch != 0 {
|
||||
match self.booster_switch {
|
||||
1 => {
|
||||
if self.flags.flag_x01() || self.flags.flag_x04() {
|
||||
self.ym = -0x100; // -0.5fix9
|
||||
self.vel_y = -0x100; // -0.5fix9
|
||||
}
|
||||
|
||||
if self.direction == Direction::Left {
|
||||
self.xm -= 0x20; // 0.1fix9
|
||||
self.vel_x -= 0x20; // 0.1fix9
|
||||
}
|
||||
if self.direction == Direction::Right {
|
||||
self.xm += 0x20; // 0.1fix9
|
||||
self.vel_x += 0x20; // 0.1fix9
|
||||
}
|
||||
|
||||
// todo: particles and sound
|
||||
if state.key_trigger.jump() || self.boost_cnt % 3 == 1 {
|
||||
if self.direction == Direction::Left {
|
||||
// SetCaret(self.x + 2 * 0x200, self.y + 2 * 0x200, 7, 2);
|
||||
}
|
||||
if self.direction == Direction::Right {
|
||||
// SetCaret(self.x + 2 * 0x200, self.y + 2 * 0x200, 7, 0);
|
||||
// todo: sound
|
||||
if state.key_trigger.jump() || self.booster_fuel % 3 == 1 {
|
||||
if self.direction == Direction::Left || self.direction == Direction::Right {
|
||||
state.create_caret(self.x + 0x400, self.y + 0x400, CaretType::Exhaust, self.direction.opposite());
|
||||
}
|
||||
// PlaySoundObject(113, SOUND_MODE_PLAY);
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
self.ym -= 0x20;
|
||||
self.vel_y -= 0x20;
|
||||
|
||||
// todo: particles and sound
|
||||
if state.key_trigger.jump() || self.boost_cnt % 3 == 1 {
|
||||
// SetCaret(self.x, self.y + 6 * 0x200, 7, 3);
|
||||
// todo: sound
|
||||
if state.key_trigger.jump() || self.booster_fuel % 3 == 1 {
|
||||
state.create_caret(self.x, self.y + 6 * 0x200, CaretType::Exhaust, Direction::Bottom);
|
||||
// PlaySoundObject(113, SOUND_MODE_PLAY);
|
||||
}
|
||||
}
|
||||
// todo: particles and sound
|
||||
3 if state.key_trigger.jump() || self.boost_cnt % 3 == 1 => {
|
||||
// SetCaret(self.x, self.y + 6 * 0x200, 7, 1);
|
||||
// todo: sound
|
||||
3 if state.key_trigger.jump() || self.booster_fuel % 3 == 1 => {
|
||||
state.create_caret(self.x, self.y + 6 * 0x200, CaretType::Exhaust, Direction::Up);
|
||||
// PlaySoundObject(113, SOUND_MODE_PLAY);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if self.flags.force_up() {
|
||||
self.ym += physics.gravity_air;
|
||||
} else if self.equip.has_booster_0_8() && self.boost_sw != 0 && self.ym > -0x400 {
|
||||
self.ym -= 0x20;
|
||||
self.vel_y += physics.gravity_air;
|
||||
} else if self.equip.has_booster_0_8() && self.booster_switch != 0 && self.vel_y > -0x400 {
|
||||
self.vel_y -= 0x20;
|
||||
|
||||
if self.boost_cnt % 3 == 0 {
|
||||
// SetCaret(self.x, self.y + self.hit.bottom as isize / 2, 7, 3);
|
||||
if self.booster_fuel % 3 == 0 {
|
||||
state.create_caret(self.x, self.y + self.hit.bottom as isize / 2, CaretType::Exhaust, Direction::Bottom);
|
||||
// PlaySoundObject(113, SOUND_MODE_PLAY);
|
||||
}
|
||||
|
||||
// bounce off of ceiling
|
||||
if self.flags.flag_x02() {
|
||||
self.ym = 0x200; // 1.0fix9
|
||||
self.vel_y = 0x200; // 1.0fix9
|
||||
}
|
||||
} else if self.ym < 0 && state.flags.control_enabled() && state.key_state.jump() {
|
||||
self.ym += physics.gravity_air;
|
||||
} else if self.vel_y < 0 && state.flags.control_enabled() && state.key_state.jump() {
|
||||
self.vel_y += physics.gravity_air;
|
||||
} else {
|
||||
self.ym += physics.gravity_ground;
|
||||
self.vel_y += physics.gravity_ground;
|
||||
}
|
||||
|
||||
if !state.flags.control_enabled() || !state.key_trigger.jump() {
|
||||
if self.flags.flag_x10() && self.xm < 0 {
|
||||
self.ym = -self.xm;
|
||||
if self.flags.flag_x10() && self.vel_x < 0 {
|
||||
self.vel_y = -self.vel_x;
|
||||
}
|
||||
|
||||
if self.flags.flag_x20() && self.xm > 0 {
|
||||
self.ym = self.xm;
|
||||
if self.flags.flag_x20() && self.vel_x > 0 {
|
||||
self.vel_y = self.vel_x;
|
||||
}
|
||||
|
||||
if (self.flags.flag_x08() && self.flags.flag_x80000() && self.xm < 0)
|
||||
|| (self.flags.flag_x08() && self.flags.flag_x10000() && self.xm > 0)
|
||||
if (self.flags.flag_x08() && self.flags.flag_x80000() && self.vel_x < 0)
|
||||
|| (self.flags.flag_x08() && self.flags.flag_x10000() && self.vel_x > 0)
|
||||
|| (self.flags.flag_x08() && self.flags.flag_x20000() && self.flags.flag_x40000()) {
|
||||
self.ym = 0x400; // 2.0fix9
|
||||
self.vel_y = 0x400; // 2.0fix9
|
||||
}
|
||||
}
|
||||
|
||||
let max_move = if self.flags.underwater() && !(self.flags.force_left() || self.flags.force_up() || self.flags.force_right() || self.flags.force_down()) {
|
||||
self.water_physics.max_move
|
||||
physics.max_move
|
||||
} else {
|
||||
self.air_physics.max_move
|
||||
physics.max_move
|
||||
};
|
||||
|
||||
self.xm = clamp(self.xm, -max_move, max_move);
|
||||
self.ym = clamp(self.ym, -max_move, max_move);
|
||||
self.vel_x = clamp(self.vel_x, -max_move, max_move);
|
||||
self.vel_y = clamp(self.vel_y, -max_move, max_move);
|
||||
|
||||
// todo: water splashing
|
||||
|
||||
|
@ -406,7 +400,7 @@ impl Player {
|
|||
|
||||
// spike damage
|
||||
if self.flags.flag_x400() {
|
||||
//self.damage(10); // todo: borrow checker yells at me
|
||||
self.damage(10);
|
||||
}
|
||||
|
||||
// camera
|
||||
|
@ -423,14 +417,14 @@ impl Player {
|
|||
}
|
||||
|
||||
if state.flags.control_enabled() && state.key_state.up() {
|
||||
self.index_x -= 0x200; // 1.0fix9
|
||||
if self.index_x < -0x8000 { // -64.0fix9
|
||||
self.index_x = -0x8000;
|
||||
self.index_y -= 0x200; // 1.0fix9
|
||||
if self.index_y < -0x8000 { // -64.0fix9
|
||||
self.index_y = -0x8000;
|
||||
}
|
||||
} else if state.flags.control_enabled() && state.key_state.down() {
|
||||
self.index_x += 0x200; // 1.0fix9
|
||||
if self.index_x > 0x8000 { // -64.0fix9
|
||||
self.index_x = 0x8000;
|
||||
self.index_y += 0x200; // 1.0fix9
|
||||
if self.index_y > 0x8000 { // -64.0fix9
|
||||
self.index_y = 0x8000;
|
||||
}
|
||||
} else {
|
||||
if self.index_y > 0x200 { // 1.0fix9
|
||||
|
@ -445,16 +439,16 @@ impl Player {
|
|||
self.target_x = self.x + self.index_x;
|
||||
self.target_y = self.y + self.index_y;
|
||||
|
||||
if self.xm > physics.resist || self.xm < -physics.resist {
|
||||
self.x += self.xm;
|
||||
if self.vel_x > physics.resist || self.vel_x < -physics.resist {
|
||||
self.x += self.vel_x;
|
||||
}
|
||||
|
||||
self.y += self.ym;
|
||||
self.y += self.vel_y;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tick_stream(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult<()> {
|
||||
fn tick_stream(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -518,7 +512,7 @@ impl Player {
|
|||
} else if state.key_state.down() {
|
||||
self.anim_num = 10;
|
||||
} else {
|
||||
self.anim_num = if self.ym > 0 { 1 } else { 3 };
|
||||
self.anim_num = if self.vel_y > 0 { 1 } else { 3 };
|
||||
}
|
||||
|
||||
match self.direction {
|
||||
|
@ -532,11 +526,29 @@ impl Player {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn damage(&mut self, hp: isize) {}
|
||||
pub fn damage(&mut self, hp: isize) {
|
||||
if self.shock_counter > 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
// PlaySoundObject(16, SOUND_MODE_PLAY); // todo: damage sound
|
||||
self.shock_counter = 128;
|
||||
self.cond.set_cond_x01(false);
|
||||
|
||||
if self.unit != 1 {
|
||||
self.vel_y = -0x400; // -2.0fix9
|
||||
}
|
||||
|
||||
self.life = if hp >= self.life as isize { 0 } else { (self.life as isize - hp) as usize };
|
||||
|
||||
if self.equip.has_whimsical_star() && self.star > 0 {
|
||||
self.star -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GameEntity for Player {
|
||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult<()> {
|
||||
fn tick(&mut self, state: &mut SharedGameState, _ctx: &mut Context) -> GameResult {
|
||||
if !self.cond.visible() {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -545,8 +557,8 @@ impl GameEntity for Player {
|
|||
self.exp_wait -= 1;
|
||||
}
|
||||
|
||||
if self.shock != 0 {
|
||||
self.shock -= 1;
|
||||
if self.shock_counter != 0 {
|
||||
self.shock_counter -= 1;
|
||||
} else if self.exp_count != 0 {
|
||||
// SetValueView(&self.x, &self.y, self.exp_count); // todo: damage popup
|
||||
self.exp_count = 0;
|
||||
|
@ -558,10 +570,10 @@ impl GameEntity for Player {
|
|||
// AirProcess(); // todo
|
||||
}
|
||||
|
||||
self.tick_normal(state, ctx)?;
|
||||
self.tick_normal(state)?;
|
||||
}
|
||||
1 => {
|
||||
self.tick_stream(state, ctx)?;
|
||||
self.tick_stream(state)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ use num_traits::clamp;
|
|||
use crate::player::Player;
|
||||
use crate::stage::Stage;
|
||||
use crate::SharedGameState;
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
|
||||
const OFF_X: &[isize; 4] = &[0, 1, 0, 1];
|
||||
const OFF_Y: &[isize; 4] = &[0, 0, 1, 1];
|
||||
|
@ -16,12 +18,12 @@ impl Player {
|
|||
&& (self.x - self.hit.right as isize) > x * 0x10 * 0x200 {
|
||||
self.x = ((x * 0x10 + 8) * 0x200) + self.hit.right as isize;
|
||||
|
||||
if self.xm < -0x180 {
|
||||
self.xm = -0x180;
|
||||
if self.vel_x < -0x180 {
|
||||
self.vel_x = -0x180;
|
||||
}
|
||||
|
||||
if !state.key_state.left() && self.xm < 0 {
|
||||
self.xm = 0;
|
||||
if !state.key_state.left() && self.vel_x < 0 {
|
||||
self.vel_x = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x01(true);
|
||||
|
@ -34,12 +36,12 @@ impl Player {
|
|||
&& (self.x + self.hit.right as isize) < x * 0x10 * 0x200 {
|
||||
self.x = ((x * 0x10 - 8) * 0x200) - self.hit.right as isize;
|
||||
|
||||
if self.xm > 0x180 {
|
||||
self.xm = 0x180;
|
||||
if self.vel_x > 0x180 {
|
||||
self.vel_x = 0x180;
|
||||
}
|
||||
|
||||
if !state.key_state.right() && self.xm > 0 {
|
||||
self.xm = 0;
|
||||
if !state.key_state.right() && self.vel_x > 0 {
|
||||
self.vel_x = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x04(true);
|
||||
|
@ -52,12 +54,12 @@ impl Player {
|
|||
&& (self.y - self.hit.top as isize) > y * 0x10 * 0x200 {
|
||||
self.y = ((y * 0x10 + 8) * 0x200) + self.hit.top as isize;
|
||||
|
||||
if !self.cond.cond_x02() && self.ym < -0x200 {
|
||||
if !self.cond.cond_x02() && self.vel_y < -0x200 {
|
||||
// PutLittleStar(); todo
|
||||
}
|
||||
|
||||
if self.ym < 0 {
|
||||
self.ym = 0;
|
||||
if self.vel_y < 0 {
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x02(true);
|
||||
|
@ -70,12 +72,12 @@ impl Player {
|
|||
&& ((self.y + self.hit.bottom as isize) < y * 0x10 * 0x200) {
|
||||
self.y = ((y * 0x10 - 8) * 0x200) - self.hit.bottom as isize;
|
||||
|
||||
if self.ym > 0x400 {
|
||||
if self.vel_y > 0x400 {
|
||||
// PlaySoundObject(23, SOUND_MODE_PLAY); todo
|
||||
}
|
||||
|
||||
if self.ym > 0 {
|
||||
self.ym = 0;
|
||||
if self.vel_y > 0 {
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x08(true);
|
||||
|
@ -89,12 +91,12 @@ impl Player {
|
|||
&& (self.y + self.hit.bottom as isize) > (y * 0x10 - 8) * 0x200 {
|
||||
self.y = (y * 0x10 * 0x200) - ((self.x - x * 0x10 * 0x200) / 2) + 0x800 + self.hit.top as isize;
|
||||
|
||||
if !self.cond.cond_x02() && self.ym < -0x200 {
|
||||
if !self.cond.cond_x02() && self.vel_y < -0x200 {
|
||||
// PutLittleStar(); todo
|
||||
}
|
||||
|
||||
if self.ym < 0 {
|
||||
self.ym = 0;
|
||||
if self.vel_y < 0 {
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x02(true);
|
||||
|
@ -108,12 +110,12 @@ impl Player {
|
|||
&& (self.y + self.hit.bottom as isize) > (y * 0x10 - 8) * 0x200 {
|
||||
self.y = (y * 0x10 * 0x200) - ((self.x - x * 0x10 * 0x200) / 2) - 0x800 + self.hit.top as isize;
|
||||
|
||||
if !self.cond.cond_x02() && self.ym < -0x200 {
|
||||
if !self.cond.cond_x02() && self.vel_y < -0x200 {
|
||||
// PutLittleStar(); todo
|
||||
}
|
||||
|
||||
if self.ym < 0 {
|
||||
self.ym = 0;
|
||||
if self.vel_y < 0 {
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x02(true);
|
||||
|
@ -127,12 +129,12 @@ impl Player {
|
|||
&& (self.y + self.hit.bottom as isize) > (y * 0x10 - 8) * 0x200 {
|
||||
self.y = (y * 0x10 * 0x200) + ((self.x - x * 0x10 * 0x200) / 2) - 0x800 + self.hit.top as isize;
|
||||
|
||||
if !self.cond.cond_x02() && self.ym < -0x200 {
|
||||
if !self.cond.cond_x02() && self.vel_y < -0x200 {
|
||||
// PutLittleStar(); todo
|
||||
}
|
||||
|
||||
if self.ym < 0 {
|
||||
self.ym = 0;
|
||||
if self.vel_y < 0 {
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x02(true);
|
||||
|
@ -146,12 +148,12 @@ impl Player {
|
|||
&& (self.y + self.hit.bottom as isize) > (y * 0x10 - 8) * 0x200 {
|
||||
self.y = (y * 0x10 * 0x200) + ((self.x - x * 0x10 * 0x200) / 2) + 0x800 + self.hit.top as isize;
|
||||
|
||||
if !self.cond.cond_x02() && self.ym < -0x200 {
|
||||
if !self.cond.cond_x02() && self.vel_y < -0x200 {
|
||||
// PutLittleStar(); todo
|
||||
}
|
||||
|
||||
if self.ym < 0 {
|
||||
self.ym = 0;
|
||||
if self.vel_y < 0 {
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x02(true);
|
||||
|
@ -167,12 +169,12 @@ impl Player {
|
|||
&& (self.y - self.hit.top as isize) < (y * 0x10 + 8) * 0x200 {
|
||||
self.y = (y * 0x10 * 0x200) + ((self.x - x * 0x10 * 0x200) / 2) - 0x800 - self.hit.bottom as isize;
|
||||
|
||||
if self.ym > 0x400 {
|
||||
if self.vel_y > 0x400 {
|
||||
// PlaySoundObject(23, SOUND_MODE_PLAY); todo
|
||||
}
|
||||
|
||||
if self.ym > 0 {
|
||||
self.ym = 0;
|
||||
if self.vel_y > 0 {
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x20(true);
|
||||
|
@ -189,12 +191,12 @@ impl Player {
|
|||
&& (self.y - self.hit.top as isize) < (y * 0x10 + 8) * 0x200 {
|
||||
self.y = (y * 0x10 * 0x200) + ((self.x - x * 0x10 * 0x200) / 2) + 0x800 - self.hit.bottom as isize;
|
||||
|
||||
if self.ym > 0x400 {
|
||||
if self.vel_y > 0x400 {
|
||||
// PlaySoundObject(23, SOUND_MODE_PLAY); todo
|
||||
}
|
||||
|
||||
if self.ym > 0 {
|
||||
self.ym = 0;
|
||||
if self.vel_y > 0 {
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x20(true);
|
||||
|
@ -211,12 +213,12 @@ impl Player {
|
|||
&& (self.y - self.hit.top as isize) < (y * 0x10 + 8) * 0x200 {
|
||||
self.y = (y * 0x10 * 0x200) - ((self.x - x * 0x10 * 0x200) / 2) + 0x800 - self.hit.bottom as isize;
|
||||
|
||||
if self.ym > 0x400 {
|
||||
if self.vel_y > 0x400 {
|
||||
// PlaySoundObject(23, SOUND_MODE_PLAY); todo
|
||||
}
|
||||
|
||||
if self.ym > 0 {
|
||||
self.ym = 0;
|
||||
if self.vel_y > 0 {
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x10(true);
|
||||
|
@ -233,12 +235,12 @@ impl Player {
|
|||
&& (self.y - self.hit.top as isize) < (y * 0x10 + 8) * 0x200 {
|
||||
self.y = (y * 0x10 * 0x200) - ((self.x - x * 0x10 * 0x200) / 2) - 0x800 - self.hit.bottom as isize;
|
||||
|
||||
if self.ym > 0x400 {
|
||||
if self.vel_y > 0x400 {
|
||||
// PlaySoundObject(23, SOUND_MODE_PLAY); todo
|
||||
}
|
||||
|
||||
if self.ym > 0 {
|
||||
self.ym = 0;
|
||||
if self.vel_y > 0 {
|
||||
self.vel_y = 0;
|
||||
}
|
||||
|
||||
self.flags.set_flag_x10(true);
|
||||
|
@ -309,4 +311,10 @@ impl Player {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick_npc_collisions(&mut self, state: &mut SharedGameState, stage: &Stage) {
|
||||
if self.question {
|
||||
state.create_caret(self.x, self.y, CaretType::QuestionMark, Direction::Left);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
22
src/rng.rs
Normal file
22
src/rng.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
/// Stateful RNG
|
||||
pub struct RNG {
|
||||
pub seed: u32,
|
||||
}
|
||||
|
||||
impl RNG {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
seed: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> u32 {
|
||||
// MSVC LCG values
|
||||
self.seed = self.seed.wrapping_mul(214013).wrapping_add(2531011);
|
||||
self.seed
|
||||
}
|
||||
|
||||
pub fn range(&mut self, start: i32, end: i32) -> i32 {
|
||||
start + (self.next() % (end - start) as u32) as i32
|
||||
}
|
||||
}
|
|
@ -17,9 +17,10 @@ pub struct GameScene {
|
|||
pub stage: Stage,
|
||||
pub frame: Frame,
|
||||
pub player: Player,
|
||||
tex_tileset_name: String,
|
||||
tex_background_name: String,
|
||||
tex_caret_name: String,
|
||||
tex_hud_name: String,
|
||||
tex_tileset_name: String,
|
||||
life_bar: usize,
|
||||
life_bar_count: usize,
|
||||
}
|
||||
|
@ -43,9 +44,10 @@ impl GameScene {
|
|||
info!("Loaded stage: {}", stage.data.name);
|
||||
info!("Map size: {}x{}", stage.map.width, stage.map.height);
|
||||
|
||||
let tex_tileset_name = ["Stage/", &stage.data.tileset.filename()].join("");
|
||||
let tex_background_name = stage.data.background.filename();
|
||||
let tex_caret_name = str!("Caret");
|
||||
let tex_hud_name = str!("TextBox");
|
||||
let tex_tileset_name = ["Stage/", &stage.data.tileset.filename()].join("");
|
||||
|
||||
Ok(Self {
|
||||
tick: 0,
|
||||
|
@ -56,9 +58,10 @@ impl GameScene {
|
|||
y: 0,
|
||||
wait: 16,
|
||||
},
|
||||
tex_tileset_name,
|
||||
tex_background_name,
|
||||
tex_caret_name,
|
||||
tex_hud_name,
|
||||
tex_tileset_name,
|
||||
life_bar: 3,
|
||||
life_bar_count: 0,
|
||||
})
|
||||
|
@ -176,6 +179,19 @@ impl GameScene {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_carets(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_caret_name)?;
|
||||
|
||||
for caret in state.carets.iter() {
|
||||
batch.add_rect((((caret.x - caret.offset_x) / 0x200) - (self.frame.x / 0x200)) as f32,
|
||||
(((caret.y - caret.offset_y) / 0x200) - (self.frame.y / 0x200)) as f32,
|
||||
&caret.anim_rect);
|
||||
}
|
||||
|
||||
batch.draw(ctx)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_tiles(&self, state: &mut SharedGameState, ctx: &mut Context, layer: TileLayer) -> GameResult {
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_tileset_name)?;
|
||||
let mut rect = Rect::<usize>::new(0, 0, 16, 16);
|
||||
|
@ -226,7 +242,7 @@ impl Scene for GameScene {
|
|||
state.sound_manager.play_song(ctx)?;
|
||||
//self.player.x = 700 * 0x200;
|
||||
//self.player.y = 1000 * 0x200;
|
||||
//self.player.equip.set_booster_2_0(true);
|
||||
self.player.equip.set_booster_2_0(true);
|
||||
state.flags.set_flag_x01(true);
|
||||
state.flags.set_control_enabled(true);
|
||||
Ok(())
|
||||
|
@ -239,7 +255,9 @@ impl Scene for GameScene {
|
|||
self.player.tick(state, ctx)?;
|
||||
|
||||
self.player.flags.0 = 0;
|
||||
state.tick_carets();
|
||||
self.player.tick_map_collisions(state, &self.stage);
|
||||
self.player.tick_npc_collisions(state, &self.stage);
|
||||
|
||||
self.frame.update(state, &self.player, &self.stage);
|
||||
}
|
||||
|
@ -269,6 +287,7 @@ impl Scene for GameScene {
|
|||
self.draw_tiles(state, ctx, TileLayer::Background)?;
|
||||
self.player.draw(state, ctx, &self.frame)?;
|
||||
self.draw_tiles(state, ctx, TileLayer::Foreground)?;
|
||||
self.draw_carets(state, ctx)?;
|
||||
|
||||
self.draw_hud(state, ctx)?;
|
||||
self.draw_number(state.canvas_size.0 - 8.0, 8.0, timer::fps(ctx) as usize, Alignment::Right, state, ctx)?;
|
||||
|
|
|
@ -57,6 +57,10 @@ impl SizedBatch {
|
|||
}
|
||||
|
||||
pub fn add_rect(&mut self, x: f32, y: f32, rect: &common::Rect<usize>) {
|
||||
if (rect.right - rect.left) == 0 || (rect.bottom - rect.top) == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let param = DrawParam::new()
|
||||
.src(Rect::new(rect.left as f32 / self.width as f32,
|
||||
rect.top as f32 / self.height as f32,
|
||||
|
|
3
src/weapon.rs
Normal file
3
src/weapon.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub struct Weapon {
|
||||
|
||||
}
|
Loading…
Reference in a new issue