mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-11-25 13:45:46 +00:00
more entities and stuff
This commit is contained in:
parent
f137d84a46
commit
da9bcd3249
|
|
@ -78,7 +78,20 @@ pub struct WorldConsts {
|
|||
pub struct NPCConsts {
|
||||
pub n016_save_point: [Rect<usize>; 8],
|
||||
pub n017_health_refill: [Rect<usize>; 2],
|
||||
pub n018_door_rects: [Rect<usize>; 2],
|
||||
pub n018_door: [Rect<usize>; 2],
|
||||
pub n020_computer: [Rect<usize>; 4],
|
||||
pub n021_chest_open: Rect<usize>,
|
||||
pub n022_teleporter: [Rect<usize>; 2],
|
||||
pub n023_teleporter_lights: [Rect<usize>; 8],
|
||||
pub n027_death_trap: Rect<usize>,
|
||||
pub n029_cthulhu: [Rect<usize>; 4],
|
||||
pub n030_hermit_gunsmith: [Rect<usize>; 3],
|
||||
pub n032_life_capsule: [Rect<usize>; 2],
|
||||
pub n034_bed: [Rect<usize>; 2],
|
||||
pub n035_mannan: [Rect<usize>; 8],
|
||||
pub n037_sign: [Rect<usize>; 2],
|
||||
pub n038_fireplace: [Rect<usize>; 4],
|
||||
pub n039_save_sign: [Rect<usize>; 2],
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
|
@ -256,9 +269,74 @@ impl EngineConstants {
|
|||
Rect { left: 288, top: 0, right: 304, bottom: 16 },
|
||||
Rect { left: 304, top: 0, right: 320, bottom: 16 },
|
||||
],
|
||||
n018_door_rects: [
|
||||
n018_door: [
|
||||
Rect { left: 224, top: 16, right: 240, bottom: 40 },
|
||||
Rect { left: 192, top: 112, right: 208, bottom: 136 },
|
||||
],
|
||||
n020_computer: [
|
||||
Rect { left: 288, top: 16, right: 320, bottom: 40 }, // left
|
||||
Rect { left: 288, top: 40, right: 320, bottom: 64 }, // right
|
||||
Rect { left: 288, top: 40, right: 320, bottom: 64 },
|
||||
Rect { left: 288, top: 64, right: 320, bottom: 88 },
|
||||
],
|
||||
n021_chest_open: Rect { left: 224, top: 40, right: 240, bottom: 48 },
|
||||
n022_teleporter: [
|
||||
Rect { left: 240, top: 16, right: 264, bottom: 48 },
|
||||
Rect { left: 248, top: 152, right: 272, bottom: 184 },
|
||||
],
|
||||
n023_teleporter_lights: [
|
||||
Rect { left: 264, top: 16, right: 288, bottom: 20 },
|
||||
Rect { left: 264, top: 20, right: 288, bottom: 24 },
|
||||
Rect { left: 264, top: 24, right: 288, bottom: 28 },
|
||||
Rect { left: 264, top: 28, right: 288, bottom: 32 },
|
||||
Rect { left: 264, top: 32, right: 288, bottom: 36 },
|
||||
Rect { left: 264, top: 36, right: 288, bottom: 40 },
|
||||
Rect { left: 264, top: 40, right: 288, bottom: 44 },
|
||||
Rect { left: 264, top: 44, right: 288, bottom: 48 },
|
||||
],
|
||||
n027_death_trap: Rect { left: 96, top: 64, right: 128, bottom: 88 },
|
||||
n029_cthulhu: [
|
||||
Rect { left: 0, top: 192, right: 16, bottom: 216 }, // left
|
||||
Rect { left: 16, top: 192, right: 32, bottom: 216 },
|
||||
Rect { left: 0, top: 216, right: 16, bottom: 240 }, // right
|
||||
Rect { left: 16, top: 216, right: 32, bottom: 240 },
|
||||
],
|
||||
n030_hermit_gunsmith: [
|
||||
Rect { left: 48, top: 0, right: 64, bottom: 16 },
|
||||
Rect { left: 48, top: 16, right: 64, bottom: 32 },
|
||||
Rect { left: 0, top: 32, right: 16, bottom: 48 },
|
||||
],
|
||||
n032_life_capsule: [
|
||||
Rect { left: 32, top: 96, right: 48, bottom: 112 },
|
||||
Rect { left: 48, top: 96, right: 64, bottom: 112 },
|
||||
],
|
||||
n034_bed: [
|
||||
Rect { left: 192, top: 48, right: 224, bottom: 64 },
|
||||
Rect { left: 192, top: 184, right: 224, bottom: 200 },
|
||||
],
|
||||
n035_mannan: [
|
||||
Rect { left: 96, top: 64, right: 120, bottom: 96 }, // left
|
||||
Rect { left: 120, top: 64, right: 144, bottom: 96 },
|
||||
Rect { left: 144, top: 64, right: 168, bottom: 96 },
|
||||
Rect { left: 168, top: 64, right: 192, bottom: 96 },
|
||||
Rect { left: 96, top: 96, right: 120, bottom: 128 }, // right
|
||||
Rect { left: 120, top: 96, right: 144, bottom: 128 },
|
||||
Rect { left: 144, top: 96, right: 168, bottom: 128 },
|
||||
Rect { left: 168, top: 96, right: 192, bottom: 128 },
|
||||
],
|
||||
n037_sign: [
|
||||
Rect { left: 192, top: 64, right: 208, bottom: 80 },
|
||||
Rect { left: 208, top: 64, right: 224, bottom: 80 },
|
||||
],
|
||||
n038_fireplace: [
|
||||
Rect { left: 128, top: 64, right: 144, bottom: 80 },
|
||||
Rect { left: 144, top: 64, right: 160, bottom: 80 },
|
||||
Rect { left: 160, top: 64, right: 176, bottom: 80 },
|
||||
Rect { left: 176, top: 64, right: 192, bottom: 80 },
|
||||
],
|
||||
n039_save_sign: [
|
||||
Rect { left: 224, top: 64, right: 240, bottom: 80 },
|
||||
Rect { left: 240, top: 64, right: 256, bottom: 80 },
|
||||
]
|
||||
},
|
||||
tex_sizes: hashmap! {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ use crate::ggez::{Context, GameResult};
|
|||
use crate::frame::Frame;
|
||||
use crate::SharedGameState;
|
||||
|
||||
pub trait GameEntity {
|
||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult;
|
||||
pub trait GameEntity<C> {
|
||||
fn tick(&mut self, state: &mut SharedGameState, custom: C) -> GameResult;
|
||||
|
||||
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ pub struct NPCData {
|
|||
pub id: u16,
|
||||
pub x: i16,
|
||||
pub y: i16,
|
||||
pub flag_id: u16,
|
||||
pub flag_num: u16,
|
||||
pub event_num: u16,
|
||||
pub npc_type: u16,
|
||||
pub flags: u16,
|
||||
|
|
@ -88,7 +88,7 @@ impl NPCData {
|
|||
for i in 0..count {
|
||||
let x = data.read_i16::<LE>()?;
|
||||
let y = data.read_i16::<LE>()?;
|
||||
let flag_id = data.read_u16::<LE>()?;
|
||||
let flag_num = data.read_u16::<LE>()?;
|
||||
let event_num = data.read_u16::<LE>()?;
|
||||
let npc_type = data.read_u16::<LE>()?;
|
||||
let flags = data.read_u16::<LE>()?;
|
||||
|
|
@ -100,7 +100,7 @@ impl NPCData {
|
|||
id: 170 + i as u16,
|
||||
x,
|
||||
y,
|
||||
flag_id,
|
||||
flag_num,
|
||||
event_num,
|
||||
npc_type,
|
||||
flags,
|
||||
|
|
|
|||
|
|
@ -8,8 +8,24 @@ impl NPC {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn tick_n016_save_point(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
if self.direction == Direction::Right {
|
||||
self.npc_flags.set_interactable(false);
|
||||
self.vel_y = -0x200;
|
||||
}
|
||||
}
|
||||
|
||||
if self.flags.hit_bottom_wall() {
|
||||
self.npc_flags.set_interactable(true);
|
||||
}
|
||||
|
||||
self.anim_counter = (self.anim_counter + 1) % 24;
|
||||
self.anim_num = self.anim_counter / 3;
|
||||
self.anim_rect = state.constants.npc.n016_save_point[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -76,8 +92,8 @@ impl NPC {
|
|||
match self.action_num {
|
||||
0 => {
|
||||
match self.direction {
|
||||
Direction::Left => { self.anim_rect = state.constants.npc.n018_door_rects[0] }
|
||||
Direction::Right => { self.anim_rect = state.constants.npc.n018_door_rects[1] }
|
||||
Direction::Left => { self.anim_rect = state.constants.npc.n018_door[0] }
|
||||
Direction::Right => { self.anim_rect = state.constants.npc.n018_door[1] }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -90,4 +106,68 @@ impl NPC {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n020_computer(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n027_death_trap(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
self.anim_rect = state.constants.npc.n027_death_trap;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n032_life_capsule(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.anim_counter = (self.anim_counter + 1) % 4;
|
||||
self.anim_num = self.anim_counter / 2;
|
||||
self.anim_rect = state.constants.npc.n032_life_capsule[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n034_bed(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.direction {
|
||||
Direction::Left => { self.anim_rect = state.constants.npc.n034_bed[0] }
|
||||
Direction::Right => { self.anim_rect = state.constants.npc.n034_bed[1] }
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n037_sign(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.anim_counter = (self.anim_counter + 1) % 4;
|
||||
self.anim_num = self.anim_counter / 2;
|
||||
self.anim_rect = state.constants.npc.n037_sign[self.anim_num as usize];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n038_fireplace(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.action_num {
|
||||
0 => {
|
||||
self.anim_counter = (self.anim_counter + 1) % 16;
|
||||
self.anim_num = self.anim_counter / 4;
|
||||
self.anim_rect = state.constants.npc.n038_fireplace[self.anim_num as usize];
|
||||
}
|
||||
10 => {}
|
||||
11 => {}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tick_n039_save_sign(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
match self.direction {
|
||||
Direction::Left => { self.anim_rect = state.constants.npc.n039_save_sign[0] }
|
||||
Direction::Right => { self.anim_rect = state.constants.npc.n039_save_sign[1] }
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::collections::{BTreeSet, HashMap};
|
|||
use std::io;
|
||||
use std::io::Cursor;
|
||||
|
||||
use bitvec::vec::BitVec;
|
||||
use byteorder::{LE, ReadBytesExt};
|
||||
|
||||
use crate::{bitfield, SharedGameState};
|
||||
|
|
@ -12,6 +13,7 @@ use crate::entity::GameEntity;
|
|||
use crate::frame::Frame;
|
||||
use crate::ggez::{Context, GameResult};
|
||||
use crate::map::NPCData;
|
||||
use crate::player::Player;
|
||||
use crate::str;
|
||||
|
||||
pub mod misc;
|
||||
|
|
@ -58,20 +60,28 @@ pub struct NPC {
|
|||
pub hit_bounds: Rect<usize>,
|
||||
pub action_num: u16,
|
||||
pub anim_num: u16,
|
||||
pub flag_num: u16,
|
||||
pub event_num: u16,
|
||||
pub action_counter: u16,
|
||||
pub anim_counter: u16,
|
||||
pub anim_rect: Rect<usize>,
|
||||
}
|
||||
|
||||
impl GameEntity for NPC {
|
||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
impl GameEntity<&mut Player> for NPC {
|
||||
fn tick(&mut self, state: &mut SharedGameState, scene: &mut Player) -> GameResult {
|
||||
// maybe use macros?
|
||||
match self.npc_type {
|
||||
0 => { NPC::tick_n000_null(self, state) }
|
||||
16 => { NPC::tick_n016_save_point(self, state) }
|
||||
17 => { NPC::tick_n017_health_refill(self, state) }
|
||||
18 => { NPC::tick_n018_door(self, state) }
|
||||
20 => { NPC::tick_n020_computer(self, state) }
|
||||
27 => { NPC::tick_n027_death_trap(self, state) }
|
||||
32 => { NPC::tick_n032_life_capsule(self, state) }
|
||||
34 => { NPC::tick_n034_bed(self, state) }
|
||||
37 => { NPC::tick_n037_sign(self, state) }
|
||||
38 => { NPC::tick_n038_fireplace(self, state) }
|
||||
39 => { NPC::tick_n039_save_sign(self, state) }
|
||||
_ => { Ok(()) }
|
||||
}
|
||||
}
|
||||
|
|
@ -132,10 +142,11 @@ impl NPCMap {
|
|||
target_y: 0,
|
||||
action_num: 0,
|
||||
anim_num: 0,
|
||||
flag_num: data.flag_num,
|
||||
event_num: data.event_num,
|
||||
life: table.get_life(data.npc_type),
|
||||
cond: Condition(0x00),
|
||||
flags: Flag(data.flag_id as u32),
|
||||
flags: Flag(data.flag_num as u32),
|
||||
npc_flags: NPCFlag(data.flags),
|
||||
direction: Direction::Left,
|
||||
display_bounds: table.get_display_bounds(data.npc_type),
|
||||
|
|
@ -151,6 +162,15 @@ impl NPCMap {
|
|||
|
||||
self.npcs.get_mut(&data.id).unwrap()
|
||||
}
|
||||
|
||||
pub fn remove_by_event(&mut self, event_num: u16, game_flags: &mut BitVec) {
|
||||
for npc in self.npcs.values_mut() {
|
||||
if npc.event_num == event_num {
|
||||
npc.cond.set_alive(false);
|
||||
game_flags.set(npc.flag_num as usize, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NPCTableEntry {
|
||||
|
|
@ -275,7 +295,6 @@ impl NPCTable {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get_hit_bounds(&self, npc_type: u16) -> Rect<usize> {
|
||||
if let Some(npc) = self.entries.get(npc_type as usize) {
|
||||
Rect {
|
||||
|
|
|
|||
|
|
@ -501,8 +501,8 @@ impl Player {
|
|||
}
|
||||
}
|
||||
|
||||
impl GameEntity for Player {
|
||||
fn tick(&mut self, state: &mut SharedGameState, _ctx: &mut Context) -> GameResult {
|
||||
impl GameEntity<()> for Player {
|
||||
fn tick(&mut self, state: &mut SharedGameState, _cust: ()) -> GameResult {
|
||||
if !self.cond.alive() {
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -417,11 +417,11 @@ impl Scene for GameScene {
|
|||
for npc_data in npcs.iter() {
|
||||
let npc = self.npc_map.create_npc_from_data(&state.npc_table, npc_data);
|
||||
if npc.npc_flags.appear_when_flag_set() {
|
||||
if let Some(true) = state.game_flags.get(npc_data.flag_id as usize) {
|
||||
if let Some(true) = state.game_flags.get(npc_data.flag_num as usize) {
|
||||
npc.cond.set_alive(true);
|
||||
}
|
||||
} else if npc.npc_flags.hide_unless_flag_set() {
|
||||
if let Some(false) = state.game_flags.get(npc_data.flag_id as usize) {
|
||||
if let Some(false) = state.game_flags.get(npc_data.flag_num as usize) {
|
||||
npc.cond.set_alive(true);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -461,20 +461,20 @@ impl Scene for GameScene {
|
|||
}
|
||||
|
||||
if state.control_flags.flag_x01() {
|
||||
self.player.tick(state, ctx)?;
|
||||
self.player.tick(state, ())?;
|
||||
|
||||
self.player.flags.0 = 0;
|
||||
state.tick_carets();
|
||||
self.player.tick_map_collisions(state, &self.stage);
|
||||
self.player.tick_npc_collisions(state, &mut self.npc_map);
|
||||
|
||||
self.frame.update(state, &self.player, &self.stage);
|
||||
}
|
||||
|
||||
for npc_id in self.npc_map.npc_ids.iter() {
|
||||
if let Some(npc) = self.npc_map.npcs.get_mut(npc_id) {
|
||||
npc.tick(state, ctx)?;
|
||||
for npc_id in self.npc_map.npc_ids.iter() {
|
||||
if let Some(npc) = self.npc_map.npcs.get_mut(npc_id) {
|
||||
npc.tick(state, &mut self.player)?;
|
||||
}
|
||||
}
|
||||
|
||||
self.frame.update(state, &self.player, &self.stage);
|
||||
}
|
||||
|
||||
if state.control_flags.control_enabled() {
|
||||
|
|
@ -518,6 +518,7 @@ impl Scene for GameScene {
|
|||
self.draw_hud(state, ctx)?;
|
||||
}
|
||||
|
||||
self.draw_fade(state, ctx)?;
|
||||
if self.map_name_counter > 0 {
|
||||
let width = state.font.text_width(self.stage.data.name.chars(), &state.constants);
|
||||
state.font.draw_text(self.stage.data.name.chars(),
|
||||
|
|
@ -525,7 +526,6 @@ impl Scene for GameScene {
|
|||
&state.constants, &mut state.texture_set, ctx)?;
|
||||
}
|
||||
|
||||
self.draw_fade(state, ctx)?;
|
||||
self.draw_text_boxes(state, ctx)?;
|
||||
|
||||
self.draw_number(state.canvas_size.0 - 8.0, 8.0, timer::fps(ctx) as usize, Alignment::Right, state, ctx)?;
|
||||
|
|
|
|||
|
|
@ -552,6 +552,7 @@ impl TextScriptVM {
|
|||
}
|
||||
OpCode::MLp => {
|
||||
let life = read_cur_varint(&mut cursor)? as usize;
|
||||
game_scene.player.life += life;
|
||||
game_scene.player.max_life += life;
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
|
|
@ -664,6 +665,13 @@ impl TextScriptVM {
|
|||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::DNP => {
|
||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
game_scene.npc_map.remove_by_event(event_num, &mut state.game_flags);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// unimplemented opcodes
|
||||
// Zero operands
|
||||
OpCode::AEp | OpCode::CAT | OpCode::CIL | OpCode::CPS |
|
||||
|
|
@ -677,7 +685,7 @@ impl TextScriptVM {
|
|||
}
|
||||
// One operand codes
|
||||
OpCode::BOA | OpCode::BSL | OpCode::FOB | OpCode::FOM | OpCode::UNI |
|
||||
OpCode::MYB | OpCode::GIT | OpCode::NUM | OpCode::DNA | OpCode::DNP |
|
||||
OpCode::MYB | OpCode::GIT | OpCode::NUM | OpCode::DNA |
|
||||
OpCode::MPp | OpCode::SKm | OpCode::SKp | OpCode::EQp | OpCode::EQm |
|
||||
OpCode::ITp | OpCode::ITm | OpCode::AMm | OpCode::UNJ | OpCode::MPJ | OpCode::YNJ |
|
||||
OpCode::XX1 | OpCode::SIL | OpCode::LIp | OpCode::SOU |
|
||||
|
|
|
|||
Loading…
Reference in a new issue