1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-11-30 08:08:18 +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);
impl Debug;
pub has_booster_0_8, set_booster_0_8: 0;
pub has_map, set_map: 1;
pub has_arms_barrier, set_arms_barrier: 2;
pub has_turbocharge, set_turbocharge: 3;
pub has_air_tank, set_air_tank: 4;
pub has_booster_2_0, set_booster_2_0: 5;
pub has_mimiga_mask, set_mimiga_mask: 6;
pub has_whimsical_star, set_whimsical_star: 7;
pub has_nikumaru, set_nikumaru: 8;
// 7 bits wasted, thx pixel
pub has_booster_0_8, set_booster_0_8: 0; // 0x01 / 0001
pub has_map, set_map: 1; // 0x02 / 0002
pub has_arms_barrier, set_arms_barrier: 2; // 0x04 / 0004
pub has_turbocharge, set_turbocharge: 3; // 0x08 / 0008
pub has_air_tank, set_air_tank: 4; // 0x10 / 0016
pub has_booster_2_0, set_booster_2_0: 5; // 0x20 / 0032
pub has_mimiga_mask, set_mimiga_mask: 6; // 0x40 / 0064
pub has_whimsical_star, set_whimsical_star: 7; // 0x080 / 0128
pub has_nikumaru, set_nikumaru: 8; // 0x100 / 0256
// 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! {
@ -82,9 +90,10 @@ bitfield! {
pub struct ControlFlags(u16);
impl Debug;
pub flag_x01, set_flag_x01: 0;
pub control_enabled, set_control_enabled: 1;
pub interactions_disabled, set_interactions_disabled: 2;
pub tick_world, set_tick_world: 0; // 0x01
pub control_enabled, set_control_enabled: 1; // 0x02
pub interactions_disabled, set_interactions_disabled: 2; // 0x04
pub credits_running, set_credits_running: 3; // 0x08
// engine specific flags
pub wind, set_wind: 15;

View file

@ -180,7 +180,7 @@ impl LiveDebugger {
assert_eq!(self.event_ids.len(), self.events.len());
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.textscript_vm.start_script(event_num);
}

View file

@ -73,7 +73,7 @@ impl NPC {
self.anim_num += 1;
if self.anim_num > 6 {
self.anim_num = 5;
// todo play sound 26
state.sound_manager.play_sfx(26);
state.quake_counter = 8;
}
@ -170,7 +170,7 @@ impl NPC {
}
self.vel_y = -0x5ff;
// todo play sound 30
state.sound_manager.play_sfx(30);
if self.direction == Direction::Left {
self.vel_x = -0x100;
@ -185,7 +185,7 @@ impl NPC {
self.action_counter = 0;
self.action_num = 1;
// tood play sound 23
state.sound_manager.play_sfx(23);
if self.anim_num != 0 {
self.anim_num = 0;

View file

@ -376,10 +376,6 @@ impl NPCMap {
}
}).collect_vec();
if !dead_npcs.is_empty() {
println!("deleting npcs: {:?}", dead_npcs);
}
for npc_id in dead_npcs.iter() {
self.npc_ids.remove(npc_id);
self.npcs.remove(npc_id);

View file

@ -560,7 +560,7 @@ impl Player {
if self.life == 0 {
state.sound_manager.play_sfx(17);
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.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() {
state.control_flags.set_flag_x01(true);
state.control_flags.set_tick_world(true);
state.control_flags.set_interactions_disabled(true);
state.textscript_vm.start_script(npc.event_num);
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 {
state.control_flags.set_flag_x01(true);
state.control_flags.set_tick_world(true);
state.control_flags.set_interactions_disabled(true);
state.textscript_vm.start_script(npc.event_num);
}

View file

@ -48,7 +48,7 @@ pub struct GameProfile {
impl GameProfile {
pub fn apply(&self, state: &mut SharedGameState, game_scene: &mut GameScene, ctx: &mut Context) {
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.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() {
state.control_flags.set_flag_x01(true);
state.control_flags.set_tick_world(true);
state.control_flags.set_interactions_disabled(true);
state.textscript_vm.start_script(npc.event_num);
} else {
@ -706,7 +706,7 @@ impl Scene for GameScene {
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
state.update_key_trigger();
if self.tick == 0 || state.control_flags.flag_x01() {
if state.control_flags.tick_world() {
self.player.current_weapon = {
if let Some(weapon) = self.inventory.get_current_weapon_mut() {
weapon.wtype as u8

View file

@ -29,8 +29,8 @@ pub enum TimingMode {
impl TimingMode {
pub fn get_delta(self) -> usize {
match self {
TimingMode::_50Hz => { 1000 / 50 - 1 }
TimingMode::_60Hz => { 1000 / 60 - 1 }
TimingMode::_50Hz => { 1000 / 50 }
TimingMode::_60Hz => { 1000 / 60 }
TimingMode::FrameSynchronized => { 0 }
}
}

View file

@ -356,10 +356,10 @@ impl TextScriptVM {
match state.textscript_vm.state {
TextScriptExecutionState::Ended => {
state.control_flags.set_interactions_disabled(false);
break;
}
TextScriptExecutionState::Running(event, ip) => {
state.control_flags.set_flag_x01(true);
state.control_flags.set_interactions_disabled(true);
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);
}
}
OpCode::_END | OpCode::END => {
state.control_flags.set_flag_x01(true);
OpCode::_END => {
exec_state = TextScriptExecutionState::Ended;
}
OpCode::END => {
state.control_flags.set_tick_world(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_background_visible(false);
game_scene.player.cond.set_interacted(false);
game_scene.player.update_target = true;
exec_state = TextScriptExecutionState::Ended;
}
OpCode::PRI => {
state.control_flags.set_flag_x01(false);
state.control_flags.set_tick_world(false);
state.control_flags.set_control_enabled(false);
game_scene.player.shock_counter = 0;
@ -529,7 +532,7 @@ impl TextScriptVM {
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
}
OpCode::KEY => {
state.control_flags.set_flag_x01(true);
state.control_flags.set_tick_world(true);
state.control_flags.set_control_enabled(false);
game_scene.player.up = false;
@ -538,7 +541,7 @@ impl TextScriptVM {
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
}
OpCode::FRE => {
state.control_flags.set_flag_x01(true);
state.control_flags.set_tick_world(true);
state.control_flags.set_control_enabled(true);
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
@ -737,6 +740,7 @@ impl TextScriptVM {
new_scene.player.x = pos_x;
new_scene.player.y = pos_y;
state.control_flags.set_tick_world(true);
state.textscript_vm.flags.0 = 0;
state.textscript_vm.face = 0;
state.textscript_vm.item = 0;
@ -1042,19 +1046,26 @@ impl TextScriptVM {
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.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);
}
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;
}
// unimplemented opcodes
// Zero operands
OpCode::CAT | OpCode::CIL | OpCode::CPS |
OpCode::CRE | OpCode::CSS | OpCode::FLA |
OpCode::INI | OpCode::MLP |
OpCode::CRE | OpCode::CSS | OpCode::FLA | OpCode::MLP |
OpCode::SAT | OpCode::SLP | OpCode::SPS |
OpCode::STC | OpCode::SVP | OpCode::TUR => {
log::warn!("unimplemented opcode: {:?}", op);