doukutsu-rs/src/player/mod.rs

743 lines
26 KiB
Rust
Raw Normal View History

2020-08-27 22:29:10 +00:00
use std::clone::Clone;
2020-08-18 16:46:07 +00:00
2021-01-27 18:20:47 +00:00
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use num_derive::FromPrimitive;
2020-09-21 23:53:46 +00:00
use num_traits::clamp;
2020-08-31 18:33:01 +00:00
2020-08-20 18:31:47 +00:00
use crate::caret::CaretType;
2020-11-02 01:38:39 +00:00
use crate::common::{Condition, Direction, Equipment, Flag, interpolate_fix9_scale, Rect};
2020-08-18 16:46:07 +00:00
use crate::entity::GameEntity;
2020-08-19 13:11:34 +00:00
use crate::frame::Frame;
2020-11-28 19:25:51 +00:00
use crate::input::dummy_player_controller::DummyPlayerController;
use crate::input::player_controller::PlayerController;
use crate::npc::NPC;
use crate::rng::RNG;
use crate::shared_game_state::SharedGameState;
use crate::npc::list::NPCList;
2020-08-18 16:46:07 +00:00
2020-11-28 19:25:51 +00:00
mod player_hit;
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive)]
2020-08-31 19:46:03 +00:00
#[repr(u8)]
pub enum ControlMode {
Normal = 0,
IronHead,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2020-11-02 01:38:39 +00:00
#[repr(u8)]
pub enum PlayerAppearance {
Quote = 0,
2020-11-27 18:19:12 +00:00
/// Cave Story+ player skins
2020-11-02 01:38:39 +00:00
YellowQuote,
HumanQuote,
HalloweenQuote,
ReindeerQuote,
Curly,
}
2020-11-28 19:25:51 +00:00
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum TargetPlayer {
Player1,
Player2,
}
impl TargetPlayer {
#[inline]
pub fn index(self) -> usize {
self as usize
}
}
2020-08-27 22:29:10 +00:00
#[derive(Clone)]
2020-08-18 16:46:07 +00:00
pub struct Player {
2021-01-01 01:46:01 +00:00
pub x: i32,
pub y: i32,
pub vel_x: i32,
pub vel_y: i32,
pub target_x: i32,
pub target_y: i32,
pub prev_x: i32,
pub prev_y: i32,
2020-09-16 13:21:30 +00:00
pub life: u16,
pub max_life: u16,
2020-09-04 23:08:33 +00:00
pub cond: Condition,
pub flags: Flag,
pub equip: Equipment,
2020-08-18 16:46:07 +00:00
pub direction: Direction,
2020-09-04 23:08:33 +00:00
pub display_bounds: Rect<usize>,
pub hit_bounds: Rect<usize>,
2020-08-31 19:46:03 +00:00
pub control_mode: ControlMode,
2020-08-20 18:31:47 +00:00
pub question: bool,
2021-01-01 01:46:01 +00:00
pub booster_fuel: u32,
pub up: bool,
pub down: bool,
pub shock_counter: u8,
pub current_weapon: u8,
pub stars: u8,
pub damage: u16,
2020-10-30 14:24:12 +00:00
pub air_counter: u16,
pub air: u16,
2020-11-02 01:38:39 +00:00
pub appearance: PlayerAppearance,
2020-11-28 19:25:51 +00:00
pub controller: Box<dyn PlayerController>,
weapon_offset_y: i8,
2021-01-01 01:46:01 +00:00
index_x: i32,
index_y: i32,
splash: bool,
2020-08-20 18:31:47 +00:00
booster_switch: u8,
2020-08-18 16:46:07 +00:00
bubble: u8,
2020-10-30 14:24:12 +00:00
damage_counter: u16,
damage_taken: i16,
2020-09-04 23:08:33 +00:00
anim_num: u16,
anim_counter: u16,
anim_rect: Rect<u16>,
weapon_rect: Rect<u16>,
2020-08-18 16:46:07 +00:00
}
impl Player {
pub fn new(state: &mut SharedGameState) -> Player {
2020-08-19 13:11:34 +00:00
let constants = &state.constants;
Player {
2020-08-18 16:46:07 +00:00
x: 0,
y: 0,
2020-08-20 18:31:47 +00:00
vel_x: 0,
vel_y: 0,
2020-08-18 16:46:07 +00:00
target_x: 0,
target_y: 0,
prev_x: 0,
prev_y: 0,
2020-08-20 18:31:47 +00:00
life: constants.my_char.life,
max_life: constants.my_char.max_life,
cond: Condition(0),
2020-09-04 23:08:33 +00:00
flags: Flag(0),
equip: Equipment(0),
direction: Direction::Right,
display_bounds: constants.my_char.display_bounds,
hit_bounds: constants.my_char.hit_bounds,
2020-08-31 19:46:03 +00:00
control_mode: constants.my_char.control_mode,
2020-08-20 18:31:47 +00:00
question: false,
booster_fuel: 0,
2020-08-18 16:46:07 +00:00
index_x: 0,
index_y: 0,
splash: false,
2020-08-18 16:46:07 +00:00
up: false,
down: false,
current_weapon: 0,
weapon_offset_y: 0,
2020-08-20 18:31:47 +00:00
shock_counter: 0,
booster_switch: 0,
stars: 0,
damage: 0,
2020-10-30 14:24:12 +00:00
air_counter: 0,
air: 0,
2020-11-02 01:38:39 +00:00
appearance: PlayerAppearance::Quote,
2020-11-28 19:25:51 +00:00
controller: Box::new(DummyPlayerController::new()),
2020-08-18 16:46:07 +00:00
bubble: 0,
2020-10-30 14:24:12 +00:00
damage_counter: 0,
damage_taken: 0,
2020-08-18 16:46:07 +00:00
anim_num: 0,
2020-09-04 23:08:33 +00:00
anim_counter: 0,
2020-08-18 16:46:07 +00:00
anim_rect: constants.my_char.animations_right[0],
weapon_rect: Rect::new(0, 0, 0, 0),
2020-08-25 23:37:42 +00:00
}
2020-08-18 16:46:07 +00:00
}
pub fn get_texture_offset(&self) -> u16 {
2020-11-27 18:19:12 +00:00
(self.appearance as u16 % 6) * 64 + if self.equip.has_mimiga_mask() { 32 } else { 0 }
2020-11-02 01:38:39 +00:00
}
fn tick_normal(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
2020-10-30 14:24:12 +00:00
if !state.control_flags.interactions_disabled() && state.control_flags.control_enabled() {
if self.equip.has_air_tank() {
self.air = 1000;
self.air_counter = 0;
2020-11-07 17:17:01 +00:00
} else if !state.settings.god_mode && self.flags.in_water() {
2020-10-30 14:24:12 +00:00
self.air_counter = 60;
if self.air > 0 {
self.air -= 1;
2021-02-10 20:14:09 +00:00
} else if state.get_flag(4000) {
state.textscript_vm.start_script(1100);
2020-10-30 14:24:12 +00:00
} else {
self.cond.set_hidden(true);
state.create_caret(self.x, self.y, CaretType::DrownedQuote, self.direction);
state.textscript_vm.start_script(41);
2020-10-30 14:24:12 +00:00
}
} else {
self.air = 1000;
if self.air_counter > 0 {
self.air_counter -= 1;
}
}
}
2020-08-28 02:12:13 +00:00
if self.cond.hidden() {
2020-08-18 16:46:07 +00:00
return Ok(());
}
2020-10-30 14:24:12 +00:00
let physics = if self.flags.in_water() {
state.constants.my_char.water_physics
} else {
state.constants.my_char.air_physics
};
2020-08-18 16:46:07 +00:00
2020-08-20 18:31:47 +00:00
self.question = false;
2020-08-18 16:46:07 +00:00
2020-08-27 02:43:21 +00:00
if !state.control_flags.control_enabled() {
2020-08-20 18:31:47 +00:00
self.booster_switch = 0;
2020-08-18 16:46:07 +00:00
}
// ground movement
2020-08-31 18:33:01 +00:00
if self.flags.hit_bottom_wall() || self.flags.hit_right_slope() || self.flags.hit_left_slope() {
2020-08-20 18:31:47 +00:00
self.booster_switch = 0;
2020-08-18 16:46:07 +00:00
2020-11-01 19:05:29 +00:00
if state.settings.infinite_booster {
2021-01-01 01:46:01 +00:00
self.booster_fuel = u32::MAX;
2020-11-01 19:05:29 +00:00
} else if self.equip.has_booster_0_8() || self.equip.has_booster_2_0() {
2020-08-20 18:31:47 +00:00
self.booster_fuel = state.constants.booster.fuel;
2020-08-18 16:46:07 +00:00
} else {
2020-08-20 18:31:47 +00:00
self.booster_fuel = 0;
2020-08-18 16:46:07 +00:00
}
2020-08-27 02:43:21 +00:00
if state.control_flags.control_enabled() {
2020-11-28 19:25:51 +00:00
let trigger_only_down = self.controller.trigger_down()
&& !self.controller.trigger_up()
&& !self.controller.trigger_left()
&& !self.controller.trigger_right();
let only_down = self.controller.move_down()
&& !self.controller.move_up()
&& !self.controller.move_left()
&& !self.controller.move_right();
if trigger_only_down && only_down && !self.cond.interacted() && !state.control_flags.interactions_disabled() {
2020-08-31 19:46:03 +00:00
self.cond.set_interacted(true);
2020-08-20 18:31:47 +00:00
self.question = true;
2020-08-18 16:46:07 +00:00
} else {
2020-11-28 19:25:51 +00:00
if self.controller.move_left() && self.vel_x > -physics.max_dash {
2020-08-20 18:31:47 +00:00
self.vel_x -= physics.dash_ground;
2020-08-18 16:46:07 +00:00
}
2020-11-28 19:25:51 +00:00
if self.controller.move_right() && self.vel_x < physics.max_dash {
2020-08-20 18:31:47 +00:00
self.vel_x += physics.dash_ground;
2020-08-18 16:46:07 +00:00
}
2020-11-28 19:25:51 +00:00
if self.controller.move_left() {
2020-08-18 16:46:07 +00:00
self.direction = Direction::Left;
}
2020-11-28 19:25:51 +00:00
if self.controller.move_right() {
2020-08-18 16:46:07 +00:00
self.direction = Direction::Right;
}
}
}
if !self.cond.increase_acceleration() {
2020-08-20 18:31:47 +00:00
if self.vel_x < 0 {
if self.vel_x > -physics.resist {
self.vel_x = 0;
2020-08-18 16:46:07 +00:00
} else {
2020-08-20 18:31:47 +00:00
self.vel_x += physics.resist;
2020-08-18 16:46:07 +00:00
}
2020-08-20 18:31:47 +00:00
}
if self.vel_x > 0 {
if self.vel_x < physics.resist {
self.vel_x = 0;
2020-08-18 16:46:07 +00:00
} else {
2020-08-20 18:31:47 +00:00
self.vel_x -= physics.resist;
2020-08-18 16:46:07 +00:00
}
}
}
} else { // air movement
2020-08-27 02:43:21 +00:00
if state.control_flags.control_enabled() {
2020-11-28 19:25:51 +00:00
if self.controller.trigger_jump() && self.booster_fuel != 0 {
2020-08-18 16:46:07 +00:00
if self.equip.has_booster_0_8() {
2020-08-20 18:31:47 +00:00
self.booster_switch = 1;
2020-08-18 16:46:07 +00:00
2020-08-20 18:31:47 +00:00
if self.vel_y > 0x100 { // 0.5fix9
self.vel_y /= 2;
2020-08-18 16:46:07 +00:00
}
} else if state.settings.infinite_booster || self.equip.has_booster_2_0() {
2020-11-28 19:25:51 +00:00
if self.controller.move_up() {
2020-08-20 18:31:47 +00:00
self.booster_switch = 2;
self.vel_x = 0;
self.vel_y = state.constants.booster.b2_0_up;
2020-11-28 19:25:51 +00:00
} else if self.controller.move_left() {
2020-08-20 18:31:47 +00:00
self.booster_switch = 1;
self.vel_x = state.constants.booster.b2_0_left;
self.vel_y = 0;
2020-11-28 19:25:51 +00:00
} else if self.controller.move_right() {
2020-08-20 18:31:47 +00:00
self.booster_switch = 1;
self.vel_x = state.constants.booster.b2_0_right;
self.vel_y = 0;
2020-11-28 19:25:51 +00:00
} else if self.controller.move_down() {
2020-08-20 18:31:47 +00:00
self.booster_switch = 3;
self.vel_x = 0;
self.vel_y = state.constants.booster.b2_0_down;
2020-08-18 16:46:07 +00:00
} else {
2020-08-20 18:31:47 +00:00
self.booster_switch = 2;
self.vel_x = 0;
self.vel_y = state.constants.booster.b2_0_up_nokey;
2020-08-18 16:46:07 +00:00
}
}
}
2020-11-28 19:25:51 +00:00
if self.controller.move_left() && self.vel_x > -physics.max_dash {
2020-08-20 18:31:47 +00:00
self.vel_x -= physics.dash_air;
2020-08-18 16:46:07 +00:00
}
2020-11-28 19:25:51 +00:00
if self.controller.move_right() && self.vel_x < physics.max_dash {
2020-08-20 18:31:47 +00:00
self.vel_x += physics.dash_air;
2020-08-18 16:46:07 +00:00
}
2020-11-28 19:25:51 +00:00
if self.controller.look_left() {
2020-08-18 16:46:07 +00:00
self.direction = Direction::Left;
}
2020-11-28 19:25:51 +00:00
if self.controller.look_right() {
2020-08-18 16:46:07 +00:00
self.direction = Direction::Right;
}
}
2020-11-01 19:05:29 +00:00
if (state.settings.infinite_booster || self.equip.has_booster_2_0()) && self.booster_switch != 0
2020-11-28 19:25:51 +00:00
&& (!self.controller.jump() || self.booster_fuel == 0) {
2020-08-20 18:31:47 +00:00
match self.booster_switch {
1 => { self.vel_x /= 2 }
2 => { self.vel_y /= 2 }
2020-08-18 16:46:07 +00:00
_ => {}
}
}
2020-11-28 19:25:51 +00:00
if self.booster_fuel == 0 || !self.controller.jump() {
2020-08-20 18:31:47 +00:00
self.booster_switch = 0;
2020-08-18 16:46:07 +00:00
}
}
// jumping
2020-08-27 02:43:21 +00:00
if state.control_flags.control_enabled() {
2020-11-28 19:25:51 +00:00
self.up = self.controller.move_up();
self.down = self.controller.move_down() && !self.flags.hit_bottom_wall();
2020-08-18 16:46:07 +00:00
2020-11-28 19:25:51 +00:00
if self.controller.trigger_jump() && (self.flags.hit_bottom_wall()
|| self.flags.hit_right_slope()
|| self.flags.hit_left_slope())
&& !self.flags.force_up() {
2020-08-25 23:37:42 +00:00
self.vel_y = -physics.jump;
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(15);
2020-08-18 16:46:07 +00:00
}
}
// stop interacting when moved
2020-11-28 19:25:51 +00:00
if state.control_flags.control_enabled() && (self.controller.move_left()
|| self.controller.move_right()
|| self.controller.move_up()
|| self.controller.jump()
|| self.controller.shoot()) {
2020-08-31 19:46:03 +00:00
self.cond.set_interacted(false);
2020-08-18 16:46:07 +00:00
}
// booster losing fuel
2020-08-20 18:31:47 +00:00
if self.booster_switch != 0 && self.booster_fuel != 0 {
self.booster_fuel -= 1;
2020-08-18 16:46:07 +00:00
}
// wind / current forces
if self.flags.force_left() {
2020-08-20 18:31:47 +00:00
self.vel_x -= 0x88;
2020-08-18 16:46:07 +00:00
}
if self.flags.force_up() {
2020-08-20 18:31:47 +00:00
self.vel_y -= 0x80;
2020-08-18 16:46:07 +00:00
}
if self.flags.force_right() {
2020-11-01 19:05:29 +00:00
self.vel_x += 0x88;
2020-08-18 16:46:07 +00:00
}
if self.flags.force_down() {
2020-08-20 18:31:47 +00:00
self.vel_y += 0x55;
2020-08-18 16:46:07 +00:00
}
2020-11-01 19:05:29 +00:00
if (state.settings.infinite_booster || self.equip.has_booster_2_0()) && self.booster_switch != 0 {
2020-08-20 18:31:47 +00:00
match self.booster_switch {
2020-08-18 16:46:07 +00:00
1 => {
2020-08-31 18:33:01 +00:00
if self.flags.hit_left_wall() || self.flags.hit_right_wall() {
2020-08-20 18:31:47 +00:00
self.vel_y = -0x100; // -0.5fix9
2020-08-18 16:46:07 +00:00
}
if self.direction == Direction::Left {
2020-08-20 18:31:47 +00:00
self.vel_x -= 0x20; // 0.1fix9
2020-08-18 16:46:07 +00:00
}
if self.direction == Direction::Right {
2020-08-20 18:31:47 +00:00
self.vel_x += 0x20; // 0.1fix9
2020-08-18 16:46:07 +00:00
}
2020-11-28 19:25:51 +00:00
if self.controller.trigger_jump() || self.booster_fuel % 3 == 1 {
2020-08-20 18:31:47 +00:00
if self.direction == Direction::Left || self.direction == Direction::Right {
state.create_caret(self.x + 0x400, self.y + 0x400, CaretType::Exhaust, self.direction.opposite());
2020-08-18 16:46:07 +00:00
}
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(113);
2020-08-18 16:46:07 +00:00
}
}
2 => {
2020-08-20 18:31:47 +00:00
self.vel_y -= 0x20;
2020-08-18 16:46:07 +00:00
2020-11-28 19:25:51 +00:00
if self.controller.trigger_jump() || self.booster_fuel % 3 == 1 {
2020-08-20 18:31:47 +00:00
state.create_caret(self.x, self.y + 6 * 0x200, CaretType::Exhaust, Direction::Bottom);
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(113);
2020-08-18 16:46:07 +00:00
}
}
2020-11-28 19:25:51 +00:00
3 if self.controller.trigger_jump() || self.booster_fuel % 3 == 1 => {
2020-08-20 18:31:47 +00:00
state.create_caret(self.x, self.y + 6 * 0x200, CaretType::Exhaust, Direction::Up);
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(113);
2020-08-18 16:46:07 +00:00
}
_ => {}
}
} else if self.flags.force_up() {
2020-08-20 18:31:47 +00:00
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;
2020-08-18 16:46:07 +00:00
2020-08-20 18:31:47 +00:00
if self.booster_fuel % 3 == 0 {
2021-01-01 01:46:01 +00:00
state.create_caret(self.x, self.y + self.hit_bounds.bottom as i32 / 2, CaretType::Exhaust, Direction::Bottom);
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(113);
2020-08-18 16:46:07 +00:00
}
// bounce off of ceiling
2020-08-31 18:33:01 +00:00
if self.flags.hit_top_wall() {
2020-08-20 18:31:47 +00:00
self.vel_y = 0x200; // 1.0fix9
2020-08-18 16:46:07 +00:00
}
2020-11-28 19:25:51 +00:00
} else if self.vel_y < 0 && state.control_flags.control_enabled() && self.controller.jump() {
2020-08-20 18:31:47 +00:00
self.vel_y += physics.gravity_air;
2020-08-18 16:46:07 +00:00
} else {
2020-08-20 18:31:47 +00:00
self.vel_y += physics.gravity_ground;
2020-08-18 16:46:07 +00:00
}
2020-11-28 19:25:51 +00:00
if !state.control_flags.control_enabled() || !self.controller.trigger_jump() {
2020-08-31 18:33:01 +00:00
if self.flags.hit_right_slope() && self.vel_x < 0 {
2020-08-20 18:31:47 +00:00
self.vel_y = -self.vel_x;
2020-08-18 16:46:07 +00:00
}
2020-08-31 18:33:01 +00:00
if self.flags.hit_left_slope() && self.vel_x > 0 {
2020-08-20 18:31:47 +00:00
self.vel_y = self.vel_x;
2020-08-18 16:46:07 +00:00
}
2020-08-31 18:33:01 +00:00
if (self.flags.hit_bottom_wall() && self.flags.hit_right_bigger_half() && self.vel_x < 0)
|| (self.flags.hit_bottom_wall() && self.flags.hit_left_bigger_half() && self.vel_x > 0)
|| (self.flags.hit_bottom_wall() && self.flags.hit_left_smaller_half() && self.flags.hit_right_smaller_half()) {
2020-08-20 18:31:47 +00:00
self.vel_y = 0x400; // 2.0fix9
2020-08-18 16:46:07 +00:00
}
}
2020-08-31 18:33:01 +00:00
let max_move = if self.flags.in_water() && !(self.flags.force_left() || self.flags.force_up() || self.flags.force_right() || self.flags.force_down()) {
2020-08-25 23:37:42 +00:00
state.constants.my_char.water_physics.max_move
2020-08-18 16:46:07 +00:00
} else {
2020-08-25 23:37:42 +00:00
state.constants.my_char.air_physics.max_move
2020-08-18 16:46:07 +00:00
};
2020-08-20 18:31:47 +00:00
self.vel_x = clamp(self.vel_x, -max_move, max_move);
self.vel_y = clamp(self.vel_y, -max_move, max_move);
2020-08-18 16:46:07 +00:00
2020-09-24 13:22:56 +00:00
if !self.splash && self.flags.in_water() {
let vertical_splash = !self.flags.hit_bottom_wall() && self.vel_y > 0x200;
let horizontal_splash = self.vel_x > 0x200 || self.vel_x < -0x200;
2020-11-01 19:05:29 +00:00
if vertical_splash || horizontal_splash {
let mut droplet = NPC::create(73, &state.npc_table);
droplet.cond.set_alive(true);
droplet.y = self.y;
droplet.direction = if self.flags.water_splash_facing_right() { Direction::Right } else { Direction::Left };
2020-09-24 13:22:56 +00:00
2020-11-01 19:05:29 +00:00
for _ in 0..7 {
2021-01-01 01:46:01 +00:00
droplet.x = self.x + (state.game_rng.range(-8..8) * 0x200) as i32;
2020-10-29 22:14:53 +00:00
droplet.vel_x = if vertical_splash {
2021-01-01 01:46:01 +00:00
(self.vel_x + state.game_rng.range(-0x200..0x200) as i32) - (self.vel_x / 2)
2020-09-24 13:22:56 +00:00
} else if horizontal_splash {
2021-01-01 01:46:01 +00:00
self.vel_x + state.game_rng.range(-0x200..0x200) as i32
2020-09-24 13:22:56 +00:00
} else {
2021-01-01 01:46:01 +00:00
0 as i32
2020-09-24 13:22:56 +00:00
};
2021-01-01 01:46:01 +00:00
droplet.vel_y = state.game_rng.range(-0x200..0x80) as i32;
2020-09-24 13:22:56 +00:00
let _ = npc_list.spawn(0x100, droplet.clone());
2020-09-24 13:22:56 +00:00
}
state.sound_manager.play_sfx(56);
}
self.splash = true;
}
2020-08-18 16:46:07 +00:00
2020-08-31 18:33:01 +00:00
if !self.flags.in_water() {
self.splash = false;
2020-08-18 16:46:07 +00:00
}
// spike damage
2020-08-31 18:33:01 +00:00
if self.flags.hit_by_spike() {
self.damage(10, state, npc_list);
2020-08-18 16:46:07 +00:00
}
// camera
2020-11-01 19:05:29 +00:00
self.index_x = clamp(self.index_x + self.direction.vector_x() * 0x200, -0x8000, 0x8000);
2020-08-18 16:46:07 +00:00
2020-12-02 11:47:40 +00:00
if state.control_flags.control_enabled() && self.controller.look_up() {
2020-08-20 18:31:47 +00:00
self.index_y -= 0x200; // 1.0fix9
if self.index_y < -0x8000 { // -64.0fix9
self.index_y = -0x8000;
2020-08-18 16:46:07 +00:00
}
2020-12-02 11:47:40 +00:00
} else if state.control_flags.control_enabled() && self.controller.look_down() {
2020-08-20 18:31:47 +00:00
self.index_y += 0x200; // 1.0fix9
if self.index_y > 0x8000 { // -64.0fix9
self.index_y = 0x8000;
2020-08-18 16:46:07 +00:00
}
} else {
if self.index_y > 0x200 { // 1.0fix9
self.index_y -= 0x200;
}
if self.index_y < -0x200 { // 1.0fix9
self.index_y += 0x200;
}
}
2020-11-01 19:39:57 +00:00
self.target_x = self.x + self.index_x;
self.target_y = self.y + self.index_y;
2020-08-18 16:46:07 +00:00
2020-08-20 18:31:47 +00:00
if self.vel_x > physics.resist || self.vel_x < -physics.resist {
self.x += self.vel_x;
2020-08-18 16:46:07 +00:00
}
2020-08-20 18:31:47 +00:00
self.y += self.vel_y;
2020-08-18 16:46:07 +00:00
Ok(())
}
fn tick_ironhead(&mut self, _state: &mut SharedGameState) -> GameResult {
2020-08-31 19:46:03 +00:00
// todo ironhead boss controls
2020-08-18 16:46:07 +00:00
Ok(())
}
2020-09-16 13:21:30 +00:00
fn tick_animation(&mut self, state: &mut SharedGameState) {
2020-08-28 02:12:13 +00:00
if self.cond.hidden() {
2020-08-18 16:46:07 +00:00
return;
}
2020-08-31 18:33:01 +00:00
if self.flags.hit_bottom_wall() {
2020-08-31 19:46:03 +00:00
if self.cond.interacted() {
2020-08-18 16:46:07 +00:00
self.anim_num = 11;
2020-11-28 19:25:51 +00:00
} else if state.control_flags.control_enabled() && self.controller.move_up() && (self.controller.move_left() || self.controller.move_right()) {
2020-08-31 19:46:03 +00:00
self.cond.set_fallen(true);
2020-08-18 16:46:07 +00:00
2020-09-04 23:08:33 +00:00
self.anim_counter += 1;
if self.anim_counter > 4 {
self.anim_counter = 0;
2020-08-18 16:46:07 +00:00
self.anim_num += 1;
if self.anim_num == 7 || self.anim_num == 9 {
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(24);
2020-08-18 16:46:07 +00:00
}
}
if self.anim_num > 9 || self.anim_num < 6 {
self.anim_num = 6;
}
2020-11-28 19:25:51 +00:00
} else if state.control_flags.control_enabled() && (self.controller.move_left() || self.controller.move_right()) {
2020-08-31 19:46:03 +00:00
self.cond.set_fallen(true);
2020-08-18 16:46:07 +00:00
2020-09-04 23:08:33 +00:00
self.anim_counter += 1;
if self.anim_counter > 4 {
self.anim_counter = 0;
2020-08-18 16:46:07 +00:00
self.anim_num += 1;
if self.anim_num == 2 || self.anim_num == 4 {
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(24);
2020-08-18 16:46:07 +00:00
}
}
if self.anim_num > 4 || self.anim_num < 1 {
self.anim_num = 1;
}
2020-11-28 19:25:51 +00:00
} else if state.control_flags.control_enabled() && self.controller.move_up() {
2020-08-31 19:46:03 +00:00
if self.cond.fallen() {
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(24);
2020-08-18 16:46:07 +00:00
}
2020-08-31 19:46:03 +00:00
self.cond.set_fallen(false);
2020-08-18 16:46:07 +00:00
self.anim_num = 5;
} else {
2020-08-31 19:46:03 +00:00
if self.cond.fallen() {
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(24);
2020-08-18 16:46:07 +00:00
}
2020-08-31 19:46:03 +00:00
self.cond.set_fallen(false);
2020-08-18 16:46:07 +00:00
self.anim_num = 0;
}
2020-11-28 19:25:51 +00:00
} else if self.controller.look_up() {
2020-08-18 16:46:07 +00:00
self.anim_num = 6;
2020-11-28 19:25:51 +00:00
} else if self.controller.look_down() {
2020-08-18 16:46:07 +00:00
self.anim_num = 10;
} else {
2020-08-20 18:31:47 +00:00
self.anim_num = if self.vel_y > 0 { 1 } else { 3 };
2020-08-18 16:46:07 +00:00
}
self.weapon_offset_y = 0;
self.weapon_rect.left = (self.current_weapon as u16 % 13) * 24;
self.weapon_rect.top = (self.current_weapon as u16 / 13) * 96;
self.weapon_rect.right = self.weapon_rect.left + 24;
self.weapon_rect.bottom = self.weapon_rect.top + 16;
2020-08-18 16:46:07 +00:00
match self.direction {
Direction::Left => {
2020-09-04 23:08:33 +00:00
self.anim_rect = state.constants.my_char.animations_left[self.anim_num as usize];
2020-08-18 16:46:07 +00:00
}
Direction::Right => {
self.weapon_rect.top += 16;
self.weapon_rect.bottom += 16;
2020-09-04 23:08:33 +00:00
self.anim_rect = state.constants.my_char.animations_right[self.anim_num as usize];
2020-08-18 16:46:07 +00:00
}
_ => {}
}
if self.up {
self.weapon_offset_y = -4;
self.weapon_rect.top += 32;
self.weapon_rect.bottom += 32;
} else if self.down {
self.weapon_offset_y = 4;
self.weapon_rect.top += 64;
self.weapon_rect.bottom += 64;
}
if self.anim_num == 1 || self.anim_num == 3 || self.anim_num == 6 || self.anim_num == 8 {
self.weapon_rect.top += 1;
}
2020-11-02 01:38:39 +00:00
let offset = self.get_texture_offset();
self.anim_rect.top += offset;
self.anim_rect.bottom += offset;
2020-08-18 16:46:07 +00:00
}
2021-01-01 01:46:01 +00:00
pub fn damage(&mut self, hp: i32, state: &mut SharedGameState, npc_list: &NPCList) {
2020-09-29 00:43:55 +00:00
if state.settings.god_mode || self.shock_counter > 0 {
2020-08-20 18:31:47 +00:00
return;
}
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(16);
2020-08-20 18:31:47 +00:00
self.shock_counter = 128;
2020-08-31 19:46:03 +00:00
self.cond.set_interacted(false);
2020-08-20 18:31:47 +00:00
2020-08-31 19:46:03 +00:00
if self.control_mode == ControlMode::Normal {
2020-08-20 18:31:47 +00:00
self.vel_y = -0x400; // -2.0fix9
}
2020-09-16 13:21:30 +00:00
self.life = self.life.saturating_sub(hp as u16);
2020-08-20 18:31:47 +00:00
if self.equip.has_whimsical_star() && self.stars > 0 {
self.stars -= 1;
2020-08-20 18:31:47 +00:00
}
2020-09-09 16:25:39 +00:00
self.damage = self.damage.saturating_add(hp as u16);
2020-09-09 16:25:39 +00:00
if self.life == 0 {
2020-09-16 13:21:30 +00:00
state.sound_manager.play_sfx(17);
2020-09-09 16:25:39 +00:00
self.cond.0 = 0;
state.control_flags.set_tick_world(true);
2020-09-21 23:53:46 +00:00
state.control_flags.set_interactions_disabled(true);
2020-09-09 16:25:39 +00:00
state.textscript_vm.start_script(40);
2020-11-14 01:24:32 +00:00
state.create_caret(self.x, self.y, CaretType::Explosion, Direction::Left);
let mut npc = NPC::create(4, &state.npc_table);
2020-11-14 01:24:32 +00:00
npc.cond.set_alive(true);
for _ in 0..0x40 {
2021-01-01 01:46:01 +00:00
npc.x = self.x + state.game_rng.range(-10..10) as i32 * 0x200;
npc.y = self.y + state.game_rng.range(-10..10) as i32 * 0x200;
2020-11-14 01:24:32 +00:00
let _ = npc_list.spawn(0x100, npc.clone());
2020-11-14 01:24:32 +00:00
}
2020-09-09 16:25:39 +00:00
}
2020-08-20 18:31:47 +00:00
}
2020-08-18 16:46:07 +00:00
}
impl GameEntity<&NPCList> for Player {
fn tick(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
2020-08-31 18:33:01 +00:00
if !self.cond.alive() {
2020-08-18 16:46:07 +00:00
return Ok(());
}
2020-10-30 14:24:12 +00:00
if self.damage_counter != 0 {
self.damage_counter -= 1;
2020-08-18 16:46:07 +00:00
}
2020-08-20 18:31:47 +00:00
if self.shock_counter != 0 {
self.shock_counter -= 1;
2020-10-30 14:24:12 +00:00
} else if self.damage_taken != 0 {
// todo: damage popup
2020-10-30 14:24:12 +00:00
self.damage_taken = 0;
2020-08-18 16:46:07 +00:00
}
2020-08-31 19:46:03 +00:00
// todo: add additional control modes like NXEngine has such as noclip?
match self.control_mode {
ControlMode::Normal => self.tick_normal(state, npc_list)?,
2020-10-30 14:24:12 +00:00
ControlMode::IronHead => self.tick_ironhead(state)?,
2020-08-18 16:46:07 +00:00
}
self.cond.set_increase_acceleration(false);
2020-08-19 13:11:34 +00:00
self.tick_animation(state);
2020-08-18 16:46:07 +00:00
Ok(())
}
2020-09-04 23:08:33 +00:00
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult<> {
if !self.cond.alive() || self.cond.hidden() || (self.shock_counter / 2 % 2 != 0) {
2020-08-18 16:46:07 +00:00
return Ok(());
}
if self.current_weapon != 0 {
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "Arms")?;
match self.direction {
Direction::Left => {
batch.add_rect(
2021-01-01 01:46:01 +00:00
interpolate_fix9_scale(self.prev_x - self.display_bounds.left as i32 - frame.prev_x,
self.x - self.display_bounds.left as i32 - frame.x,
2020-11-07 17:17:01 +00:00
state.frame_time) - 8.0,
2021-01-01 01:46:01 +00:00
interpolate_fix9_scale(self.prev_y - self.display_bounds.left as i32 - frame.prev_y,
self.y - self.display_bounds.left as i32 - frame.y,
2020-11-07 17:17:01 +00:00
state.frame_time) + self.weapon_offset_y as f32,
&self.weapon_rect,
);
}
Direction::Right => {
batch.add_rect(
2021-01-01 01:46:01 +00:00
interpolate_fix9_scale(self.prev_x - self.display_bounds.left as i32 - frame.prev_x,
self.x - self.display_bounds.left as i32 - frame.x,
2020-11-07 17:17:01 +00:00
state.frame_time),
2021-01-01 01:46:01 +00:00
interpolate_fix9_scale(self.prev_y - self.display_bounds.left as i32 - frame.prev_y,
self.y - self.display_bounds.left as i32 - frame.y,
2020-11-07 17:17:01 +00:00
state.frame_time) + self.weapon_offset_y as f32,
&self.weapon_rect,
);
}
_ => {}
}
batch.draw(ctx)?;
}
2020-08-18 16:46:07 +00:00
2021-02-10 20:14:09 +00:00
{
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "MyChar")?;
batch.add_rect(
interpolate_fix9_scale(self.prev_x - self.display_bounds.left as i32 - frame.prev_x,
self.x - self.display_bounds.left as i32 - frame.x,
state.frame_time),
interpolate_fix9_scale(self.prev_y - self.display_bounds.left as i32 - frame.prev_y,
self.y - self.display_bounds.left as i32 - frame.y,
state.frame_time),
&self.anim_rect,
);
batch.draw(ctx)?;
}
2020-08-18 16:46:07 +00:00
Ok(())
}
}