mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-11-30 16:18:00 +00:00
fix tsc interpreter bugs and various inaccuracies
This commit is contained in:
parent
0636a949ad
commit
2b148fe3ed
|
|
@ -34,16 +34,24 @@ bitfield! {
|
||||||
pub struct Equipment(u16);
|
pub struct Equipment(u16);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
|
|
||||||
pub has_booster_0_8, set_booster_0_8: 0;
|
pub has_booster_0_8, set_booster_0_8: 0; // 0x01 / 0001
|
||||||
pub has_map, set_map: 1;
|
pub has_map, set_map: 1; // 0x02 / 0002
|
||||||
pub has_arms_barrier, set_arms_barrier: 2;
|
pub has_arms_barrier, set_arms_barrier: 2; // 0x04 / 0004
|
||||||
pub has_turbocharge, set_turbocharge: 3;
|
pub has_turbocharge, set_turbocharge: 3; // 0x08 / 0008
|
||||||
pub has_air_tank, set_air_tank: 4;
|
pub has_air_tank, set_air_tank: 4; // 0x10 / 0016
|
||||||
pub has_booster_2_0, set_booster_2_0: 5;
|
pub has_booster_2_0, set_booster_2_0: 5; // 0x20 / 0032
|
||||||
pub has_mimiga_mask, set_mimiga_mask: 6;
|
pub has_mimiga_mask, set_mimiga_mask: 6; // 0x40 / 0064
|
||||||
pub has_whimsical_star, set_whimsical_star: 7;
|
pub has_whimsical_star, set_whimsical_star: 7; // 0x080 / 0128
|
||||||
pub has_nikumaru, set_nikumaru: 8;
|
pub has_nikumaru, set_nikumaru: 8; // 0x100 / 0256
|
||||||
// 7 bits wasted, thx pixel
|
// for custom equips
|
||||||
|
pub unused_1, set_unused_1: 9; // 0x200 / 0512
|
||||||
|
pub unused_2, set_unused_2: 10; // 0x400 / 1024
|
||||||
|
pub unused_3, set_unused_3: 11; // 0x800 / 2048
|
||||||
|
pub unused_4, set_unused_4: 12; // 0x1000 / 4096
|
||||||
|
pub unused_5, set_unused_5: 13; // 0x2000 / 8192
|
||||||
|
// bit 14 and 15 aren't accessible via TSC without abusing overflows (won't work in strict mode)
|
||||||
|
pub unused_6, set_unused_6: 14; // 0x4000 / @384
|
||||||
|
pub unused_7, set_unused_7: 15; // 0x8000 / P768
|
||||||
}
|
}
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
|
|
@ -82,9 +90,10 @@ bitfield! {
|
||||||
pub struct ControlFlags(u16);
|
pub struct ControlFlags(u16);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
|
|
||||||
pub flag_x01, set_flag_x01: 0;
|
pub tick_world, set_tick_world: 0; // 0x01
|
||||||
pub control_enabled, set_control_enabled: 1;
|
pub control_enabled, set_control_enabled: 1; // 0x02
|
||||||
pub interactions_disabled, set_interactions_disabled: 2;
|
pub interactions_disabled, set_interactions_disabled: 2; // 0x04
|
||||||
|
pub credits_running, set_credits_running: 3; // 0x08
|
||||||
|
|
||||||
// engine specific flags
|
// engine specific flags
|
||||||
pub wind, set_wind: 15;
|
pub wind, set_wind: 15;
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ impl LiveDebugger {
|
||||||
assert_eq!(self.event_ids.len(), self.events.len());
|
assert_eq!(self.event_ids.len(), self.events.len());
|
||||||
|
|
||||||
if let Some(&event_num) = self.event_ids.get(self.selected_event as usize) {
|
if let Some(&event_num) = self.event_ids.get(self.selected_event as usize) {
|
||||||
state.control_flags.set_flag_x01(true);
|
state.control_flags.set_tick_world(true);
|
||||||
state.control_flags.set_interactions_disabled(true);
|
state.control_flags.set_interactions_disabled(true);
|
||||||
state.textscript_vm.start_script(event_num);
|
state.textscript_vm.start_script(event_num);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ impl NPC {
|
||||||
self.anim_num += 1;
|
self.anim_num += 1;
|
||||||
if self.anim_num > 6 {
|
if self.anim_num > 6 {
|
||||||
self.anim_num = 5;
|
self.anim_num = 5;
|
||||||
// todo play sound 26
|
state.sound_manager.play_sfx(26);
|
||||||
state.quake_counter = 8;
|
state.quake_counter = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,7 +170,7 @@ impl NPC {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.vel_y = -0x5ff;
|
self.vel_y = -0x5ff;
|
||||||
// todo play sound 30
|
state.sound_manager.play_sfx(30);
|
||||||
|
|
||||||
if self.direction == Direction::Left {
|
if self.direction == Direction::Left {
|
||||||
self.vel_x = -0x100;
|
self.vel_x = -0x100;
|
||||||
|
|
@ -185,7 +185,7 @@ impl NPC {
|
||||||
self.action_counter = 0;
|
self.action_counter = 0;
|
||||||
self.action_num = 1;
|
self.action_num = 1;
|
||||||
|
|
||||||
// tood play sound 23
|
state.sound_manager.play_sfx(23);
|
||||||
|
|
||||||
if self.anim_num != 0 {
|
if self.anim_num != 0 {
|
||||||
self.anim_num = 0;
|
self.anim_num = 0;
|
||||||
|
|
|
||||||
|
|
@ -376,10 +376,6 @@ impl NPCMap {
|
||||||
}
|
}
|
||||||
}).collect_vec();
|
}).collect_vec();
|
||||||
|
|
||||||
if !dead_npcs.is_empty() {
|
|
||||||
println!("deleting npcs: {:?}", dead_npcs);
|
|
||||||
}
|
|
||||||
|
|
||||||
for npc_id in dead_npcs.iter() {
|
for npc_id in dead_npcs.iter() {
|
||||||
self.npc_ids.remove(npc_id);
|
self.npc_ids.remove(npc_id);
|
||||||
self.npcs.remove(npc_id);
|
self.npcs.remove(npc_id);
|
||||||
|
|
|
||||||
|
|
@ -560,7 +560,7 @@ impl Player {
|
||||||
if self.life == 0 {
|
if self.life == 0 {
|
||||||
state.sound_manager.play_sfx(17);
|
state.sound_manager.play_sfx(17);
|
||||||
self.cond.0 = 0;
|
self.cond.0 = 0;
|
||||||
state.control_flags.set_flag_x01(true);
|
state.control_flags.set_tick_world(true);
|
||||||
state.control_flags.set_interactions_disabled(true);
|
state.control_flags.set_interactions_disabled(true);
|
||||||
state.textscript_vm.start_script(40);
|
state.textscript_vm.start_script(40);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
if npc.npc_flags.interactable() && !state.control_flags.interactions_disabled() && flags.0 != 0 && self.cond.interacted() {
|
if npc.npc_flags.interactable() && !state.control_flags.interactions_disabled() && flags.0 != 0 && self.cond.interacted() {
|
||||||
state.control_flags.set_flag_x01(true);
|
state.control_flags.set_tick_world(true);
|
||||||
state.control_flags.set_interactions_disabled(true);
|
state.control_flags.set_interactions_disabled(true);
|
||||||
state.textscript_vm.start_script(npc.event_num);
|
state.textscript_vm.start_script(npc.event_num);
|
||||||
self.cond.set_interacted(false);
|
self.cond.set_interacted(false);
|
||||||
|
|
@ -196,7 +196,7 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
if npc.npc_flags.event_when_touched() && !state.control_flags.interactions_disabled() && flags.0 != 0 {
|
if npc.npc_flags.event_when_touched() && !state.control_flags.interactions_disabled() && flags.0 != 0 {
|
||||||
state.control_flags.set_flag_x01(true);
|
state.control_flags.set_tick_world(true);
|
||||||
state.control_flags.set_interactions_disabled(true);
|
state.control_flags.set_interactions_disabled(true);
|
||||||
state.textscript_vm.start_script(npc.event_num);
|
state.textscript_vm.start_script(npc.event_num);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ pub struct GameProfile {
|
||||||
impl GameProfile {
|
impl GameProfile {
|
||||||
pub fn apply(&self, state: &mut SharedGameState, game_scene: &mut GameScene, ctx: &mut Context) {
|
pub fn apply(&self, state: &mut SharedGameState, game_scene: &mut GameScene, ctx: &mut Context) {
|
||||||
state.fade_state = FadeState::Visible;
|
state.fade_state = FadeState::Visible;
|
||||||
state.control_flags.set_flag_x01(true);
|
state.control_flags.set_tick_world(true);
|
||||||
state.control_flags.set_control_enabled(true);
|
state.control_flags.set_control_enabled(true);
|
||||||
|
|
||||||
state.sound_manager.play_song(self.current_song as usize, &state.constants, ctx);
|
state.sound_manager.play_song(self.current_song as usize, &state.constants, ctx);
|
||||||
|
|
|
||||||
|
|
@ -621,7 +621,7 @@ impl GameScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.player.cond.alive() && npc.npc_flags.event_when_killed() {
|
if self.player.cond.alive() && npc.npc_flags.event_when_killed() {
|
||||||
state.control_flags.set_flag_x01(true);
|
state.control_flags.set_tick_world(true);
|
||||||
state.control_flags.set_interactions_disabled(true);
|
state.control_flags.set_interactions_disabled(true);
|
||||||
state.textscript_vm.start_script(npc.event_num);
|
state.textscript_vm.start_script(npc.event_num);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -706,7 +706,7 @@ impl Scene for GameScene {
|
||||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
state.update_key_trigger();
|
state.update_key_trigger();
|
||||||
|
|
||||||
if self.tick == 0 || state.control_flags.flag_x01() {
|
if state.control_flags.tick_world() {
|
||||||
self.player.current_weapon = {
|
self.player.current_weapon = {
|
||||||
if let Some(weapon) = self.inventory.get_current_weapon_mut() {
|
if let Some(weapon) = self.inventory.get_current_weapon_mut() {
|
||||||
weapon.wtype as u8
|
weapon.wtype as u8
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ pub enum TimingMode {
|
||||||
impl TimingMode {
|
impl TimingMode {
|
||||||
pub fn get_delta(self) -> usize {
|
pub fn get_delta(self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
TimingMode::_50Hz => { 1000 / 50 - 1 }
|
TimingMode::_50Hz => { 1000 / 50 }
|
||||||
TimingMode::_60Hz => { 1000 / 60 - 1 }
|
TimingMode::_60Hz => { 1000 / 60 }
|
||||||
TimingMode::FrameSynchronized => { 0 }
|
TimingMode::FrameSynchronized => { 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -356,10 +356,10 @@ impl TextScriptVM {
|
||||||
|
|
||||||
match state.textscript_vm.state {
|
match state.textscript_vm.state {
|
||||||
TextScriptExecutionState::Ended => {
|
TextScriptExecutionState::Ended => {
|
||||||
|
state.control_flags.set_interactions_disabled(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TextScriptExecutionState::Running(event, ip) => {
|
TextScriptExecutionState::Running(event, ip) => {
|
||||||
state.control_flags.set_flag_x01(true);
|
|
||||||
state.control_flags.set_interactions_disabled(true);
|
state.control_flags.set_interactions_disabled(true);
|
||||||
state.textscript_vm.state = TextScriptVM::execute(event, ip, state, game_scene, ctx)?;
|
state.textscript_vm.state = TextScriptVM::execute(event, ip, state, game_scene, ctx)?;
|
||||||
|
|
||||||
|
|
@ -508,20 +508,23 @@ impl TextScriptVM {
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpCode::_END | OpCode::END => {
|
OpCode::_END => {
|
||||||
state.control_flags.set_flag_x01(true);
|
exec_state = TextScriptExecutionState::Ended;
|
||||||
|
}
|
||||||
|
OpCode::END => {
|
||||||
|
state.control_flags.set_tick_world(true);
|
||||||
state.control_flags.set_control_enabled(true);
|
state.control_flags.set_control_enabled(true);
|
||||||
state.control_flags.set_interactions_disabled(false);
|
|
||||||
|
|
||||||
state.textscript_vm.flags.set_render(false);
|
state.textscript_vm.flags.set_render(false);
|
||||||
state.textscript_vm.flags.set_background_visible(false);
|
state.textscript_vm.flags.set_background_visible(false);
|
||||||
|
|
||||||
|
game_scene.player.cond.set_interacted(false);
|
||||||
game_scene.player.update_target = true;
|
game_scene.player.update_target = true;
|
||||||
|
|
||||||
exec_state = TextScriptExecutionState::Ended;
|
exec_state = TextScriptExecutionState::Ended;
|
||||||
}
|
}
|
||||||
OpCode::PRI => {
|
OpCode::PRI => {
|
||||||
state.control_flags.set_flag_x01(false);
|
state.control_flags.set_tick_world(false);
|
||||||
state.control_flags.set_control_enabled(false);
|
state.control_flags.set_control_enabled(false);
|
||||||
|
|
||||||
game_scene.player.shock_counter = 0;
|
game_scene.player.shock_counter = 0;
|
||||||
|
|
@ -529,7 +532,7 @@ impl TextScriptVM {
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
OpCode::KEY => {
|
OpCode::KEY => {
|
||||||
state.control_flags.set_flag_x01(true);
|
state.control_flags.set_tick_world(true);
|
||||||
state.control_flags.set_control_enabled(false);
|
state.control_flags.set_control_enabled(false);
|
||||||
|
|
||||||
game_scene.player.up = false;
|
game_scene.player.up = false;
|
||||||
|
|
@ -538,7 +541,7 @@ impl TextScriptVM {
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
OpCode::FRE => {
|
OpCode::FRE => {
|
||||||
state.control_flags.set_flag_x01(true);
|
state.control_flags.set_tick_world(true);
|
||||||
state.control_flags.set_control_enabled(true);
|
state.control_flags.set_control_enabled(true);
|
||||||
|
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
|
|
@ -737,6 +740,7 @@ impl TextScriptVM {
|
||||||
new_scene.player.x = pos_x;
|
new_scene.player.x = pos_x;
|
||||||
new_scene.player.y = pos_y;
|
new_scene.player.y = pos_y;
|
||||||
|
|
||||||
|
state.control_flags.set_tick_world(true);
|
||||||
state.textscript_vm.flags.0 = 0;
|
state.textscript_vm.flags.0 = 0;
|
||||||
state.textscript_vm.face = 0;
|
state.textscript_vm.face = 0;
|
||||||
state.textscript_vm.item = 0;
|
state.textscript_vm.item = 0;
|
||||||
|
|
@ -1042,19 +1046,26 @@ impl TextScriptVM {
|
||||||
|
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
OpCode::ESC => {
|
// todo: INI starts intro
|
||||||
|
OpCode::INI | OpCode::ESC => {
|
||||||
state.next_scene = Some(Box::new(TitleScene::new()));
|
state.next_scene = Some(Box::new(TitleScene::new()));
|
||||||
|
state.control_flags.set_tick_world(false);
|
||||||
|
state.control_flags.set_control_enabled(false);
|
||||||
|
state.control_flags.set_interactions_disabled(true);
|
||||||
|
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
OpCode::LDP => {
|
OpCode::LDP => {
|
||||||
|
state.control_flags.set_tick_world(false);
|
||||||
|
state.control_flags.set_control_enabled(false);
|
||||||
|
state.control_flags.set_interactions_disabled(true);
|
||||||
|
|
||||||
exec_state = TextScriptExecutionState::LoadProfile;
|
exec_state = TextScriptExecutionState::LoadProfile;
|
||||||
}
|
}
|
||||||
// unimplemented opcodes
|
// unimplemented opcodes
|
||||||
// Zero operands
|
// Zero operands
|
||||||
OpCode::CAT | OpCode::CIL | OpCode::CPS |
|
OpCode::CAT | OpCode::CIL | OpCode::CPS |
|
||||||
OpCode::CRE | OpCode::CSS | OpCode::FLA |
|
OpCode::CRE | OpCode::CSS | OpCode::FLA | OpCode::MLP |
|
||||||
OpCode::INI | OpCode::MLP |
|
|
||||||
OpCode::SAT | OpCode::SLP | OpCode::SPS |
|
OpCode::SAT | OpCode::SLP | OpCode::SPS |
|
||||||
OpCode::STC | OpCode::SVP | OpCode::TUR => {
|
OpCode::STC | OpCode::SVP | OpCode::TUR => {
|
||||||
log::warn!("unimplemented opcode: {:?}", op);
|
log::warn!("unimplemented opcode: {:?}", op);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue