mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-11-26 15:23:38 +00:00
implement a lot of item related opcodes and some minor bug fixes
This commit is contained in:
parent
a94aef5e58
commit
931d5a58ee
|
@ -42,4 +42,41 @@ impl Inventory {
|
|||
pub fn has_item(&self, item_id: u16) -> bool {
|
||||
self.items.iter().any(|item| item.0 == item_id)
|
||||
}
|
||||
|
||||
pub fn add_weapon(&mut self, weapon_id: u16, max_ammo: u16) {
|
||||
if !self.has_weapon(weapon_id) {
|
||||
self.weapons.push(Weapon {
|
||||
id: weapon_id,
|
||||
level: 1,
|
||||
experience: 0,
|
||||
ammo: max_ammo,
|
||||
max_ammo,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_weapon(&mut self, weapon_id: u16) {
|
||||
self.weapons.retain(|weapon| weapon.id != weapon_id);
|
||||
}
|
||||
|
||||
pub fn get_current_weapon(&mut self) -> Option<&mut Weapon> {
|
||||
self.weapons.get_mut(self.current_weapon as usize)
|
||||
}
|
||||
|
||||
pub fn refill_all_ammo(&mut self) {
|
||||
for weapon in self.weapons.iter_mut() {
|
||||
weapon.ammo = weapon.max_ammo;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_all_weapon_xp(&mut self) {
|
||||
for weapon in self.weapons.iter_mut() {
|
||||
weapon.level = 1;
|
||||
weapon.experience = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_weapon(&self, weapon_id: u16) -> bool {
|
||||
self.weapons.iter().any(|weapon| weapon.id == weapon_id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,17 +62,17 @@ impl LiveDebugger {
|
|||
));
|
||||
|
||||
if ui.button(im_str!("Map Selector"), [0.0, 0.0]) {
|
||||
self.map_selector_visible = true;
|
||||
self.map_selector_visible = !self.map_selector_visible;
|
||||
}
|
||||
|
||||
ui.same_line(0.0);
|
||||
if ui.button(im_str!("Events"), [0.0, 0.0]) {
|
||||
self.events_visible = true;
|
||||
self.events_visible = !self.events_visible;
|
||||
}
|
||||
|
||||
ui.same_line(0.0);
|
||||
if ui.button(im_str!("Hacks"), [0.0, 0.0]) {
|
||||
self.hacks_visible = true;
|
||||
self.hacks_visible = !self.hacks_visible;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -95,6 +95,7 @@ pub struct SharedGameState {
|
|||
pub sound_manager: SoundManager,
|
||||
pub constants: EngineConstants,
|
||||
pub scale: f32,
|
||||
pub god_mode: bool,
|
||||
pub speed_hack: bool,
|
||||
pub canvas_size: (f32, f32),
|
||||
pub screen_size: (f32, f32),
|
||||
|
@ -183,6 +184,7 @@ impl Game {
|
|||
sound_manager: SoundManager::new(ctx)?,
|
||||
constants,
|
||||
scale,
|
||||
god_mode: false,
|
||||
speed_hack: false,
|
||||
screen_size,
|
||||
canvas_size,
|
||||
|
@ -236,6 +238,7 @@ impl Game {
|
|||
KeyCode::X => { state.key_state.set_fire(true) }
|
||||
KeyCode::A => { state.key_state.set_weapon_prev(true) }
|
||||
KeyCode::S => { state.key_state.set_weapon_next(true) }
|
||||
KeyCode::F11 => { state.god_mode = !state.god_mode }
|
||||
KeyCode::F12 => { state.set_speed_hack(!state.speed_hack) }
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -287,6 +287,24 @@ impl NPCMap {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_alive(&self, npc_id: u16) -> bool {
|
||||
if let Some(npc) = self.npcs.get(&npc_id) {
|
||||
return npc.cond.alive();
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn is_alive_by_event(&self, event_num: u16) -> bool {
|
||||
for npc in self.npcs.values() {
|
||||
if npc.cond.alive() && npc.event_num == event_num {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NPCTableEntry {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::clone::Clone;
|
||||
|
||||
use num_traits::clamp;
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::{clamp, FromPrimitive};
|
||||
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{Condition, Equipment, Flag};
|
||||
|
@ -8,11 +9,10 @@ use crate::common::{Direction, Rect};
|
|||
use crate::entity::GameEntity;
|
||||
use crate::frame::Frame;
|
||||
use crate::ggez::{Context, GameResult};
|
||||
use crate::SharedGameState;
|
||||
use crate::str;
|
||||
use crate::inventory::Inventory;
|
||||
use crate::SharedGameState;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum ControlMode {
|
||||
Normal = 0,
|
||||
|
@ -488,7 +488,7 @@ impl Player {
|
|||
}
|
||||
|
||||
pub fn damage(&mut self, hp: isize, state: &mut SharedGameState) {
|
||||
if self.shock_counter > 0 {
|
||||
if state.god_mode || self.shock_counter > 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::str::FromStr;
|
|||
use byteorder::ReadBytesExt;
|
||||
use itertools::Itertools;
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::{FromPrimitive, clamp};
|
||||
use num_traits::{clamp, FromPrimitive};
|
||||
|
||||
use crate::{SharedGameState, str};
|
||||
use crate::bitfield;
|
||||
|
@ -18,6 +18,7 @@ use crate::common::{Direction, FadeDirection, FadeState};
|
|||
use crate::entity::GameEntity;
|
||||
use crate::ggez::{Context, GameResult};
|
||||
use crate::ggez::GameError::ParseError;
|
||||
use crate::player::ControlMode;
|
||||
use crate::scene::game_scene::GameScene;
|
||||
|
||||
/// Engine's text script VM operation codes.
|
||||
|
@ -216,6 +217,7 @@ pub enum TextScriptExecutionState {
|
|||
Msg(u16, u32, u32, u8),
|
||||
WaitTicks(u16, u32, u16),
|
||||
WaitInput(u16, u32),
|
||||
WaitStanding(u16, u32),
|
||||
WaitConfirmation(u16, u32, u16, u8, ConfirmSelection),
|
||||
WaitFade(u16, u32),
|
||||
}
|
||||
|
@ -480,6 +482,12 @@ impl TextScriptVM {
|
|||
|
||||
break;
|
||||
}
|
||||
TextScriptExecutionState::WaitStanding(event, ip) => {
|
||||
if game_scene.player.flags.hit_bottom_wall() {
|
||||
state.textscript_vm.state = TextScriptExecutionState::Running(event, ip);
|
||||
}
|
||||
break;
|
||||
}
|
||||
TextScriptExecutionState::WaitInput(event, ip) => {
|
||||
if state.key_trigger.jump() || state.key_trigger.fire() {
|
||||
state.textscript_vm.state = TextScriptExecutionState::Running(event, ip);
|
||||
|
@ -605,6 +613,9 @@ impl TextScriptVM {
|
|||
|
||||
exec_state = TextScriptExecutionState::WaitTicks(event, cursor.position() as u32, ticks);
|
||||
}
|
||||
OpCode::WAS => {
|
||||
exec_state = TextScriptExecutionState::WaitStanding(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::NOD => {
|
||||
exec_state = TextScriptExecutionState::WaitInput(event, cursor.position() as u32);
|
||||
}
|
||||
|
@ -622,6 +633,46 @@ impl TextScriptVM {
|
|||
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;
|
||||
|
||||
if game_scene.player.inventory.has_item(item_id) {
|
||||
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
||||
} else {
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
}
|
||||
OpCode::AMJ => {
|
||||
let weapon = read_cur_varint(&mut cursor)? as u16;
|
||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
if game_scene.player.inventory.has_weapon(weapon) {
|
||||
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
||||
} else {
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
}
|
||||
OpCode::NCJ => {
|
||||
let npc_id = read_cur_varint(&mut cursor)? as u16;
|
||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
if game_scene.npc_map.is_alive(npc_id) {
|
||||
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
||||
} else {
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
}
|
||||
OpCode::ECJ => {
|
||||
let npc_event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
if game_scene.npc_map.is_alive_by_event(npc_event_num) {
|
||||
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
||||
} else {
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
}
|
||||
OpCode::EVE => {
|
||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
|
@ -735,8 +786,19 @@ impl TextScriptVM {
|
|||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::UNI => {
|
||||
let control_mode = read_cur_varint(&mut cursor)? as u8;
|
||||
|
||||
let mode: Option<ControlMode> = FromPrimitive::from_u8(control_mode);
|
||||
if let Some(mode) = mode {
|
||||
game_scene.player.control_mode = mode;
|
||||
}
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::FAI => {
|
||||
let fade_type = read_cur_varint(&mut cursor)? as usize;
|
||||
|
||||
if let Some(direction) = FadeDirection::from_int(fade_type) {
|
||||
state.fade_state = FadeState::FadeIn(15, direction);
|
||||
}
|
||||
|
@ -745,6 +807,7 @@ impl TextScriptVM {
|
|||
}
|
||||
OpCode::FAO => {
|
||||
let fade_type = read_cur_varint(&mut cursor)? as usize;
|
||||
|
||||
if let Some(direction) = FadeDirection::from_int(fade_type) {
|
||||
state.fade_state = FadeState::FadeOut(-15, direction.opposite());
|
||||
}
|
||||
|
@ -894,6 +957,35 @@ impl TextScriptVM {
|
|||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::MNP => {
|
||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
let x = read_cur_varint(&mut cursor)? as isize;
|
||||
let y = read_cur_varint(&mut cursor)? as isize;
|
||||
let direction = read_cur_varint(&mut cursor)? as usize;
|
||||
|
||||
for npc_id in game_scene.npc_map.npc_ids.iter() {
|
||||
if let Some(npc) = game_scene.npc_map.npcs.get_mut(npc_id) {
|
||||
if npc.cond.alive() && npc.event_num == event_num {
|
||||
npc.x = x * 16 * 0x200;
|
||||
npc.y = y * 16 * 0x200;
|
||||
|
||||
if direction == 4 {
|
||||
npc.direction = if game_scene.player.x < npc.x {
|
||||
Direction::Right
|
||||
} else {
|
||||
Direction::Left
|
||||
};
|
||||
} else if let Some(dir) = Direction::from_int(direction) {
|
||||
npc.direction = dir;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::LIp => {
|
||||
let life = read_cur_varint(&mut cursor)? as usize;
|
||||
|
||||
|
@ -901,23 +993,60 @@ impl TextScriptVM {
|
|||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::ITp => {
|
||||
let item_id = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
game_scene.player.inventory.add_item(item_id);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::ITm => {
|
||||
let item_id = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
game_scene.player.inventory.remove_item(item_id);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::AMp => {
|
||||
let weapon_id = read_cur_varint(&mut cursor)? as u16;
|
||||
let max_ammo = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
game_scene.player.inventory.add_weapon(weapon_id, max_ammo);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::AMm => {
|
||||
let weapon_id = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
game_scene.player.inventory.remove_weapon(weapon_id);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::AEp => {
|
||||
game_scene.player.inventory.refill_all_ammo();
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::ZAM => {
|
||||
game_scene.player.inventory.reset_all_weapon_xp();
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// unimplemented opcodes
|
||||
// Zero operands
|
||||
OpCode::AEp | OpCode::CAT | OpCode::CIL | OpCode::CPS |
|
||||
OpCode::CRE | OpCode::CSS | OpCode::ESC | OpCode::FLA |
|
||||
OpCode::INI | OpCode::LDP | OpCode::MLP |
|
||||
OpCode::SAT | OpCode::SLP | OpCode::SPS |
|
||||
OpCode::STC | OpCode::SVP | OpCode::TUR | OpCode::WAS | OpCode::ZAM => {
|
||||
OpCode::STC | OpCode::SVP | OpCode::TUR => {
|
||||
log::warn!("unimplemented opcode: {:?}", op);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// One operand codes
|
||||
OpCode::BOA | OpCode::BSL | OpCode::FOB | OpCode::UNI |
|
||||
OpCode::NUM | OpCode::DNA |
|
||||
OpCode::BOA | OpCode::BSL | OpCode::FOB | OpCode::NUM | OpCode::DNA |
|
||||
OpCode::MPp | OpCode::SKm | OpCode::SKp | OpCode::EQp | OpCode::EQm |
|
||||
OpCode::ITp | OpCode::ITm | OpCode::AMm | OpCode::UNJ | OpCode::MPJ |
|
||||
OpCode::XX1 | OpCode::SIL | OpCode::SOU |
|
||||
OpCode::UNJ | OpCode::MPJ | OpCode::XX1 | OpCode::SIL | OpCode::SOU |
|
||||
OpCode::SSS | OpCode::ACH => {
|
||||
let par_a = read_cur_varint(&mut cursor)?;
|
||||
|
||||
|
@ -926,8 +1055,7 @@ impl TextScriptVM {
|
|||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// Two operand codes
|
||||
OpCode::AMp | OpCode::NCJ | OpCode::ECJ |
|
||||
OpCode::ITJ | OpCode::SKJ | OpCode::AMJ | OpCode::SMP | OpCode::PSp => {
|
||||
OpCode::SKJ | OpCode::SMP | OpCode::PSp => {
|
||||
let par_a = read_cur_varint(&mut cursor)?;
|
||||
let par_b = read_cur_varint(&mut cursor)?;
|
||||
|
||||
|
@ -946,7 +1074,7 @@ impl TextScriptVM {
|
|||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// Four operand codes
|
||||
OpCode::MNP | OpCode::SNP => {
|
||||
OpCode::SNP => {
|
||||
let par_a = read_cur_varint(&mut cursor)?;
|
||||
let par_b = read_cur_varint(&mut cursor)?;
|
||||
let par_c = read_cur_varint(&mut cursor)?;
|
||||
|
|
Loading…
Reference in a new issue