mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-10-01 23:09:38 +00:00
add skip flags, fix pre-save 'do you want to retry'
This commit is contained in:
parent
0db2e02181
commit
4f34e33b57
|
@ -222,6 +222,7 @@ impl Scene for TitleScene {
|
||||||
},
|
},
|
||||||
CurrentMenu::StartGame => {
|
CurrentMenu::StartGame => {
|
||||||
if self.tick == 10 {
|
if self.tick == 10 {
|
||||||
|
state.reset_skip_flags();
|
||||||
state.start_new_game(ctx)?;
|
state.start_new_game(ctx)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ use crate::stage::StageData;
|
||||||
use crate::str;
|
use crate::str;
|
||||||
use crate::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
|
use crate::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
|
||||||
use crate::texture_set::TextureSet;
|
use crate::texture_set::TextureSet;
|
||||||
|
use bitvec::array::BitArray;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||||
pub enum TimingMode {
|
pub enum TimingMode {
|
||||||
|
@ -89,6 +90,7 @@ pub struct SharedGameState {
|
||||||
pub timing_mode: TimingMode,
|
pub timing_mode: TimingMode,
|
||||||
pub control_flags: ControlFlags,
|
pub control_flags: ControlFlags,
|
||||||
pub game_flags: BitVec,
|
pub game_flags: BitVec,
|
||||||
|
pub skip_flags: BitVec,
|
||||||
pub fade_state: FadeState,
|
pub fade_state: FadeState,
|
||||||
/// RNG used by game state, using it for anything else might cause unintended side effects and break replays.
|
/// RNG used by game state, using it for anything else might cause unintended side effects and break replays.
|
||||||
pub game_rng: XorShift,
|
pub game_rng: XorShift,
|
||||||
|
@ -160,6 +162,7 @@ impl SharedGameState {
|
||||||
timing_mode: TimingMode::_50Hz,
|
timing_mode: TimingMode::_50Hz,
|
||||||
control_flags: ControlFlags(0),
|
control_flags: ControlFlags(0),
|
||||||
game_flags: bitvec::bitvec![0; 8000],
|
game_flags: bitvec::bitvec![0; 8000],
|
||||||
|
skip_flags: bitvec::bitvec![0; 64],
|
||||||
fade_state: FadeState::Hidden,
|
fade_state: FadeState::Hidden,
|
||||||
game_rng: XorShift::new(0),
|
game_rng: XorShift::new(0),
|
||||||
effect_rng: XorShift::new(123),
|
effect_rng: XorShift::new(123),
|
||||||
|
@ -364,4 +367,24 @@ impl SharedGameState {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset_skip_flags(&mut self) {
|
||||||
|
self.skip_flags = bitvec::bitvec![0; 64];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_skip_flag(&mut self, id: usize, value: bool) {
|
||||||
|
if id < self.skip_flags.len() {
|
||||||
|
self.skip_flags.set(id, value);
|
||||||
|
} else {
|
||||||
|
log::warn!("Attempted to set an out-of-bounds skip flag {}:", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_skip_flag(&self, id: usize) -> bool {
|
||||||
|
if let Some(flag) = self.skip_flags.get(id) {
|
||||||
|
*flag
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,16 +262,18 @@ pub enum OpCode {
|
||||||
SSS,
|
SSS,
|
||||||
|
|
||||||
// ---- Cave Story+ specific opcodes ----
|
// ---- Cave Story+ specific opcodes ----
|
||||||
/// <ACHxxxx, triggers a Steam achievement.
|
/// <ACHxxxx, triggers a Steam achievement. No-op in EGS/Humble Bundle version.
|
||||||
ACH,
|
ACH,
|
||||||
|
|
||||||
// ---- Cave Story+ (Switch) specific opcodes ----
|
// ---- Cave Story+ (Switch) specific opcodes ----
|
||||||
/// <HM2, HMC for non-executor player.
|
/// <HM2, HMC only for executor player.
|
||||||
HM2,
|
HM2,
|
||||||
/// <2MVxxxx, Put another player near the player who executed the event.
|
/// <2MVxxxx, Put another player near the player who executed the event.
|
||||||
/// 0000 - puts player on left side of executor player
|
/// 0000 - puts player on left side of executor player
|
||||||
/// 0001 - puts player on right side of executor player
|
/// 0001 - puts player on right side of executor player
|
||||||
/// other values - Unknown purpose for now
|
/// 0002-0010 - unused
|
||||||
|
/// 0011.. - the first 3 digits are distance in pixels, the last digit is a flag
|
||||||
|
/// - if it's 1 put the player on right side of the player, otherwise put it on left
|
||||||
#[strum(serialize = "2MV")]
|
#[strum(serialize = "2MV")]
|
||||||
S2MV,
|
S2MV,
|
||||||
/// <INJxxxx:yyyy:zzzz, Jumps to event zzzz if amount of item xxxx equals yyyy
|
/// <INJxxxx:yyyy:zzzz, Jumps to event zzzz if amount of item xxxx equals yyyy
|
||||||
|
@ -279,7 +281,7 @@ pub enum OpCode {
|
||||||
/// <I+Nxxxx:yyyy, Adds item xxxx with maximum amount of yyyy
|
/// <I+Nxxxx:yyyy, Adds item xxxx with maximum amount of yyyy
|
||||||
#[strum(serialize = "I+N")]
|
#[strum(serialize = "I+N")]
|
||||||
IpN,
|
IpN,
|
||||||
/// <FF-xxxx:yyyy, Set flags in range xxxx-yyyy to false
|
/// <FF-xxxx:yyyy, Sets first flag in range xxxx-yyyy to false
|
||||||
#[strum(serialize = "FF-")]
|
#[strum(serialize = "FF-")]
|
||||||
FFm,
|
FFm,
|
||||||
/// <PSHxxxx, Pushes text script state to stack and starts event xxxx
|
/// <PSHxxxx, Pushes text script state to stack and starts event xxxx
|
||||||
|
@ -757,7 +759,8 @@ impl TextScriptVM {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TextScriptExecutionState::Reset => {
|
TextScriptExecutionState::Reset => {
|
||||||
state.start_intro(ctx)?;
|
state.reset();
|
||||||
|
state.start_new_game(ctx)?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -937,8 +940,13 @@ impl TextScriptVM {
|
||||||
exec_state = TextScriptExecutionState::WaitInput(event, cursor.position() as u32, 0);
|
exec_state = TextScriptExecutionState::WaitInput(event, cursor.position() as u32, 0);
|
||||||
}
|
}
|
||||||
OpCode::FLp | OpCode::FLm => {
|
OpCode::FLp | OpCode::FLm => {
|
||||||
let flag_num = read_cur_varint(&mut cursor)? as usize;
|
let flag_num = read_cur_varint(&mut cursor)? as u16;
|
||||||
state.game_flags.set(flag_num, op == OpCode::FLp);
|
state.set_flag(flag_num as usize, op == OpCode::FLp);
|
||||||
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
|
}
|
||||||
|
OpCode::SKp | OpCode::SKm => {
|
||||||
|
let flag_num = read_cur_varint(&mut cursor)? as u16;
|
||||||
|
state.set_skip_flag(flag_num as usize, op == OpCode::SKp);
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
OpCode::FFm => {
|
OpCode::FFm => {
|
||||||
|
@ -1023,6 +1031,17 @@ impl TextScriptVM {
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
OpCode::SKJ => {
|
||||||
|
let flag_id = read_cur_varint(&mut cursor)? as u16;
|
||||||
|
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||||
|
|
||||||
|
if state.get_skip_flag(flag_id as usize) {
|
||||||
|
state.textscript_vm.clear_text_box();
|
||||||
|
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
||||||
|
} else {
|
||||||
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
OpCode::EVE => {
|
OpCode::EVE => {
|
||||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||||
|
|
||||||
|
@ -1035,7 +1054,7 @@ impl TextScriptVM {
|
||||||
let saved_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
let saved_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
state.textscript_vm.stack.push(saved_state);
|
state.textscript_vm.stack.push(saved_state);
|
||||||
|
|
||||||
// TODO: it's a jump but we don't know if it cleans the textbox yet.
|
state.textscript_vm.clear_text_box();
|
||||||
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
||||||
}
|
}
|
||||||
OpCode::POP => {
|
OpCode::POP => {
|
||||||
|
@ -1231,11 +1250,30 @@ impl TextScriptVM {
|
||||||
partner.x = executor.x + if param == 0 { -16 * 0x200 } else { 16 * 0x200 };
|
partner.x = executor.x + if param == 0 { -16 * 0x200 } else { 16 * 0x200 };
|
||||||
partner.y = executor.y;
|
partner.y = executor.y;
|
||||||
}
|
}
|
||||||
_ => {
|
2..=10 => {
|
||||||
log::warn!("stub: <2MV unknown param");
|
log::warn!("<2MV unknown param");
|
||||||
|
}
|
||||||
|
// what the fuck
|
||||||
|
i => {
|
||||||
|
let distance = i as i32 / 10;
|
||||||
|
|
||||||
|
partner.vel_x = 0;
|
||||||
|
partner.vel_y = 0;
|
||||||
|
partner.x = executor.x + if (param % 10) == 1 { distance * 0x200 } else { -distance * 0x200 };
|
||||||
|
partner.y = executor.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut npc = NPC::create(4, &state.npc_table);
|
||||||
|
npc.cond.set_alive(true);
|
||||||
|
npc.x = partner.x;
|
||||||
|
npc.y = partner.y;
|
||||||
|
|
||||||
|
game_scene.npc_list.spawn(0x100, npc.clone())?;
|
||||||
|
game_scene.npc_list.spawn(0x100, npc.clone())?;
|
||||||
|
game_scene.npc_list.spawn(0x100, npc.clone())?;
|
||||||
|
game_scene.npc_list.spawn(0x100, npc)?;
|
||||||
|
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
OpCode::UNI => {
|
OpCode::UNI => {
|
||||||
|
@ -1657,8 +1695,6 @@ impl TextScriptVM {
|
||||||
}
|
}
|
||||||
// One operand codes
|
// One operand codes
|
||||||
OpCode::MPp
|
OpCode::MPp
|
||||||
| OpCode::SKm
|
|
||||||
| OpCode::SKp
|
|
||||||
| OpCode::UNJ
|
| OpCode::UNJ
|
||||||
| OpCode::MPJ
|
| OpCode::MPJ
|
||||||
| OpCode::XX1
|
| OpCode::XX1
|
||||||
|
@ -1669,15 +1705,6 @@ impl TextScriptVM {
|
||||||
|
|
||||||
log::warn!("unimplemented opcode: {:?} {}", op, par_a);
|
log::warn!("unimplemented opcode: {:?} {}", op, par_a);
|
||||||
|
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
|
||||||
}
|
|
||||||
// Two operand codes
|
|
||||||
OpCode::SKJ => {
|
|
||||||
let par_a = read_cur_varint(&mut cursor)?;
|
|
||||||
let par_b = read_cur_varint(&mut cursor)?;
|
|
||||||
|
|
||||||
log::warn!("unimplemented opcode: {:?} {} {}", op, par_a, par_b);
|
|
||||||
|
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue