1
0
Fork 0
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:
Alula 2020-09-25 14:55:28 +02:00
parent 0636a949ad
commit 2b148fe3ed
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
10 changed files with 55 additions and 39 deletions

View file

@ -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;

View file

@ -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);
} }

View file

@ -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;

View file

@ -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);

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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);

View file

@ -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

View file

@ -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 }
} }
} }

View file

@ -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);