add support for map flags

This commit is contained in:
Alula 2021-05-02 04:04:52 +02:00
parent 4f34e33b57
commit d83f58fe1b
No known key found for this signature in database
GPG Key ID: 3E00485503A1D8BA
3 changed files with 72 additions and 13 deletions

View File

@ -1,6 +1,6 @@
use std::io;
use byteorder::{ReadBytesExt, WriteBytesExt, BE, LE};
use byteorder::{BE, LE, ReadBytesExt, WriteBytesExt};
use num_traits::{clamp, FromPrimitive};
use crate::common::{Direction, FadeState};
@ -43,6 +43,7 @@ pub struct GameProfile {
pub weapon_data: [WeaponData; 8],
pub items: [u32; 32],
pub teleporter_slots: [TeleporterSlotData; 8],
pub map_flags: [u8; 128],
pub flags: [u8; 1000],
}
@ -93,6 +94,10 @@ impl GameProfile {
state.teleporter_slots.push((slot.index as u16, slot.event_num as u16));
}
for (idx, &flag) in self.map_flags.iter().enumerate() {
state.set_map_flag(idx, flag != 0);
}
for (idx, &flags) in self.flags.iter().enumerate() {
if flags & 0b00000001 != 0 {
state.game_flags.set(idx * 8, true);
@ -197,6 +202,15 @@ impl GameProfile {
}
}
let mut map_flags = [0u8; 128];
for (idx, map_flag) in state.map_flags.iter().enumerate() {
if let Some(out) = map_flags.get_mut(idx) {
*out = if *map_flag { 1 } else { 0 };
} else {
break;
}
}
let mut bidx = 0;
let mut flags = [0u8; 1000];
for bits in state.game_flags.as_raw_slice() {
@ -204,6 +218,8 @@ impl GameProfile {
for b in bytes.iter() {
if let Some(out) = flags.get_mut(bidx) {
*out = *b;
} else {
break;
}
bidx += 1;
}
@ -226,6 +242,7 @@ impl GameProfile {
weapon_data,
items,
teleporter_slots,
map_flags,
flags,
}
}
@ -333,8 +350,8 @@ impl GameProfile {
slot.event_num = data.read_u32::<LE>()?;
}
let mut something = [0u8; 0x80];
data.read_exact(&mut something)?;
let mut map_flags = [0u8; 0x80];
data.read_exact(&mut map_flags)?;
if data.read_u32::<BE>()? != 0x464c4147 {
return Err(ResourceLoadError(str!("Invalid FLAG signature")));
@ -360,6 +377,7 @@ impl GameProfile {
weapon_data,
items,
teleporter_slots,
map_flags,
flags,
})
}

View File

@ -91,6 +91,7 @@ pub struct SharedGameState {
pub control_flags: ControlFlags,
pub game_flags: BitVec,
pub skip_flags: BitVec,
pub map_flags: BitVec,
pub fade_state: FadeState,
/// RNG used by game state, using it for anything else might cause unintended side effects and break replays.
pub game_rng: XorShift,
@ -163,6 +164,7 @@ impl SharedGameState {
control_flags: ControlFlags(0),
game_flags: bitvec::bitvec![0; 8000],
skip_flags: bitvec::bitvec![0; 64],
map_flags: bitvec::bitvec![0; 64],
fade_state: FadeState::Hidden,
game_rng: XorShift::new(0),
effect_rng: XorShift::new(123),
@ -236,6 +238,8 @@ impl SharedGameState {
next_scene.player1.cond.set_alive(true);
next_scene.player1.x = 10 * 16 * 0x200;
next_scene.player1.y = 8 * 16 * 0x200;
self.reset_map_flags();
self.fade_state = FadeState::Hidden;
self.textscript_vm.state = TextScriptExecutionState::Running(200, 0);
@ -253,6 +257,8 @@ impl SharedGameState {
next_scene.player1.x = 3 * 16 * 0x200;
next_scene.player1.y = 3 * 16 * 0x200;
next_scene.intro_mode = true;
self.reset_map_flags();
self.fade_state = FadeState::Hidden;
self.textscript_vm.state = TextScriptExecutionState::Running(100, 0);
@ -387,4 +393,24 @@ impl SharedGameState {
false
}
}
pub fn reset_map_flags(&mut self) {
self.map_flags = bitvec::bitvec![0; 128];
}
pub fn set_map_flag(&mut self, id: usize, value: bool) {
if id < self.map_flags.len() {
self.map_flags.set(id, value);
} else {
log::warn!("Attempted to set an out-of-bounds map flag {}:", id);
}
}
pub fn get_map_flag(&self, id: usize) -> bool {
if let Some(flag) = self.map_flags.get(id) {
*flag
} else {
false
}
}
}

View File

@ -974,6 +974,16 @@ impl TextScriptVM {
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
}
}
OpCode::MPJ => {
let event_num = read_cur_varint(&mut cursor)? as u16;
if state.get_map_flag(game_scene.stage_id) {
state.textscript_vm.clear_text_box();
exec_state = TextScriptExecutionState::Running(event_num, 0);
} else {
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
}
}
OpCode::ITJ => {
let item_id = read_cur_varint(&mut cursor)? as u16;
let event_num = read_cur_varint(&mut cursor)? as u16;
@ -1090,8 +1100,8 @@ impl TextScriptVM {
npc.x = pos_x as i32 * 16 * 0x200;
npc.y = pos_y as i32 * 16 * 0x200;
game_scene.npc_list.spawn(0x100, npc.clone())?;
game_scene.npc_list.spawn(0x100, npc)?;
let _ = game_scene.npc_list.spawn(0x100, npc.clone());
let _ = game_scene.npc_list.spawn(0x100, npc);
}
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
@ -1269,10 +1279,10 @@ impl TextScriptVM {
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)?;
let _ = game_scene.npc_list.spawn(0x100, npc.clone());
let _ = game_scene.npc_list.spawn(0x100, npc.clone());
let _ = game_scene.npc_list.spawn(0x100, npc.clone());
let _ = game_scene.npc_list.spawn(0x100, npc);
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
}
@ -1537,7 +1547,7 @@ impl TextScriptVM {
npc.direction = direction;
}
game_scene.npc_list.spawn(0x100, npc)?;
let _ = game_scene.npc_list.spawn(0x100, npc);
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
}
@ -1677,6 +1687,13 @@ impl TextScriptVM {
exec_state = TextScriptExecutionState::LoadProfile;
}
OpCode::MPp => {
let stage_id = read_cur_varint(&mut cursor)? as u16;
state.set_map_flag(stage_id as usize, true);
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
}
// unimplemented opcodes
// Zero operands
OpCode::CIL
@ -1694,9 +1711,7 @@ impl TextScriptVM {
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
}
// One operand codes
OpCode::MPp
| OpCode::UNJ
| OpCode::MPJ
OpCode::UNJ
| OpCode::XX1
| OpCode::SIL
| OpCode::SSS