mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-12-02 09:30:20 +00:00
teleporter slot menu
This commit is contained in:
parent
69331f6925
commit
ebe070b77e
|
|
@ -212,6 +212,8 @@ pub struct TextScriptConsts {
|
|||
pub get_item_top_right: Rect<usize>,
|
||||
pub get_item_right: Rect<usize>,
|
||||
pub get_item_bottom_right: Rect<usize>,
|
||||
pub stage_select_text: Rect<usize>,
|
||||
pub cursor: [Rect<usize>; 2],
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1177,6 +1179,11 @@ impl EngineConstants {
|
|||
get_item_top_right: Rect { left: 240, top: 0, right: 244, bottom: 8 },
|
||||
get_item_right: Rect { left: 240, top: 8, right: 244, bottom: 16 },
|
||||
get_item_bottom_right: Rect { left: 240, top: 16, right: 244, bottom: 24 },
|
||||
stage_select_text: Rect { left: 80, top: 64, right: 144, bottom: 72 },
|
||||
cursor: [
|
||||
Rect { left: 80, top: 88, right: 112, bottom: 104 },
|
||||
Rect { left: 80, top: 104, right: 112, bottom: 120 },
|
||||
],
|
||||
},
|
||||
title: TitleConsts {
|
||||
logo_rect: Rect { left: 0, top: 0, right: 144, bottom: 40 },
|
||||
|
|
|
|||
|
|
@ -12,13 +12,14 @@ use crate::inventory::{Inventory, TakeExperienceResult};
|
|||
use crate::npc::NPCMap;
|
||||
use crate::physics::PhysicalEntity;
|
||||
use crate::player::Player;
|
||||
use crate::rng::RNG;
|
||||
use crate::scene::Scene;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::stage::{BackgroundType, Stage};
|
||||
use crate::text_script::{ConfirmSelection, TextScriptExecutionState, TextScriptVM};
|
||||
use crate::text_script::{ConfirmSelection, ScriptMode, TextScriptExecutionState, TextScriptVM};
|
||||
use crate::texture_set::SizedBatch;
|
||||
use crate::ui::Components;
|
||||
use crate::weapon::WeaponType;
|
||||
use itertools::Itertools;
|
||||
|
||||
pub struct GameScene {
|
||||
pub tick: usize,
|
||||
|
|
@ -29,11 +30,13 @@ pub struct GameScene {
|
|||
pub stage_id: usize,
|
||||
pub npc_map: NPCMap,
|
||||
pub bullet_manager: BulletManager,
|
||||
pub current_teleport_slot: u8,
|
||||
tex_background_name: String,
|
||||
tex_tileset_name: String,
|
||||
life_bar: u16,
|
||||
life_bar_counter: u16,
|
||||
map_name_counter: u16,
|
||||
stage_select_text_y_pos: usize,
|
||||
weapon_x_pos: isize,
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +84,8 @@ impl GameScene {
|
|||
life_bar: 0,
|
||||
life_bar_counter: 0,
|
||||
map_name_counter: 0,
|
||||
stage_select_text_y_pos: 54,
|
||||
current_teleport_slot: 0,
|
||||
weapon_x_pos: 16,
|
||||
})
|
||||
}
|
||||
|
|
@ -740,7 +745,7 @@ impl GameScene {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn tick_npc_bullet_collissions(&mut self, state: &mut SharedGameState) {
|
||||
fn tick_npc_bullet_collissions(&mut self, state: &mut SharedGameState) {
|
||||
let mut dead_npcs = Vec::new();
|
||||
|
||||
for npc_id in self.npc_map.npc_ids.iter() {
|
||||
|
|
@ -830,49 +835,11 @@ impl GameScene {
|
|||
self.npc_map.garbage_collect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Scene for GameScene {
|
||||
fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
state.textscript_vm.set_scene_script(self.stage.load_text_script(&state.base_path, &state.constants, ctx)?);
|
||||
state.textscript_vm.suspend = false;
|
||||
fn tick_world(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
self.stage_select_text_y_pos = 54;
|
||||
self.current_teleport_slot = 0;
|
||||
|
||||
let npcs = self.stage.load_npcs(&state.base_path, ctx)?;
|
||||
for npc_data in npcs.iter() {
|
||||
log::info!("creating npc: {:?}", npc_data);
|
||||
|
||||
let npc = self.npc_map.create_npc_from_data(&state.npc_table, npc_data);
|
||||
if npc.npc_flags.appear_when_flag_set() {
|
||||
if let Some(true) = state.game_flags.get(npc_data.flag_num as usize) {
|
||||
npc.cond.set_alive(true);
|
||||
}
|
||||
} else if npc.npc_flags.hide_unless_flag_set() {
|
||||
if let Some(false) = state.game_flags.get(npc_data.flag_num as usize) {
|
||||
npc.cond.set_alive(true);
|
||||
}
|
||||
} else {
|
||||
npc.cond.set_alive(true);
|
||||
}
|
||||
}
|
||||
|
||||
state.npc_table.tileset_name = self.tex_tileset_name.to_owned();
|
||||
state.npc_table.tex_npc1_name = ["Npc/", &self.stage.data.npc1.filename()].join("");
|
||||
state.npc_table.tex_npc2_name = ["Npc/", &self.stage.data.npc2.filename()].join("");
|
||||
|
||||
self.player.target_x = self.player.x;
|
||||
self.player.target_y = self.player.y;
|
||||
self.frame.immediate_update(state, &self.player, &self.stage);
|
||||
|
||||
// self.inventory.add_weapon(WeaponType::PolarStar, 0);
|
||||
// self.inventory.add_xp(120, state);
|
||||
// self.player.equip.set_booster_2_0(true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
state.update_key_trigger();
|
||||
|
||||
if state.control_flags.tick_world() {
|
||||
self.player.current_weapon = {
|
||||
if let Some(weapon) = self.inventory.get_current_weapon_mut() {
|
||||
weapon.wtype as u8
|
||||
|
|
@ -929,7 +896,6 @@ impl Scene for GameScene {
|
|||
self.bullet_manager.tick_bullets(state, &self.player, &mut self.stage);
|
||||
|
||||
self.frame.update(state, &self.player, &self.stage);
|
||||
}
|
||||
|
||||
if state.control_flags.control_enabled() {
|
||||
if let Some(weapon) = self.inventory.get_current_weapon_mut() {
|
||||
|
|
@ -963,6 +929,144 @@ impl Scene for GameScene {
|
|||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tick_stage_select(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||
let slot_count = state.teleporter_slots.iter()
|
||||
.filter(|&&(index, _event_num)| index != 0)
|
||||
.count();
|
||||
|
||||
if self.stage_select_text_y_pos > 46 {
|
||||
self.stage_select_text_y_pos -= 1;
|
||||
}
|
||||
|
||||
if state.key_trigger.left() {
|
||||
if self.current_teleport_slot == 0 {
|
||||
self.current_teleport_slot = slot_count.saturating_sub(1) as u8;
|
||||
} else {
|
||||
self.current_teleport_slot -= 1;
|
||||
}
|
||||
} else if state.key_trigger.right() {
|
||||
if self.current_teleport_slot == slot_count.saturating_sub(1) as u8 {
|
||||
self.current_teleport_slot = 0;
|
||||
} else {
|
||||
self.current_teleport_slot += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if state.key_trigger.left() || state.key_trigger.right() {
|
||||
state.sound_manager.play_sfx(1);
|
||||
if let Some(&(index, _event_num)) = state.teleporter_slots.get(self.current_teleport_slot as usize) {
|
||||
state.textscript_vm.start_script(1000 + index);
|
||||
} else {
|
||||
state.textscript_vm.start_script(1000);
|
||||
}
|
||||
}
|
||||
|
||||
if state.key_trigger.jump() | state.key_trigger.fire() {
|
||||
state.textscript_vm.set_mode(ScriptMode::Map);
|
||||
state.control_flags.set_tick_world(true);
|
||||
state.control_flags.set_control_enabled(true);
|
||||
state.control_flags.set_interactions_disabled(false);
|
||||
|
||||
if state.key_trigger.jump() {
|
||||
if let Some(&(_index, event_num)) = state.teleporter_slots.get(self.current_teleport_slot as usize) {
|
||||
state.textscript_vm.start_script(event_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_stage_select(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "StageImage")?;
|
||||
|
||||
let slot_count = state.teleporter_slots.iter()
|
||||
.filter(|&&(index, _event_num)| index != 0)
|
||||
.count();
|
||||
let slot_offset = ((state.canvas_size.0 - 40.0 * slot_count as f32) / 2.0).floor();
|
||||
let mut slot_rect = Rect::new(0,0,0,0);
|
||||
|
||||
for i in 0..slot_count {
|
||||
let index = state.teleporter_slots[i].0;
|
||||
|
||||
slot_rect.left = 32 * (index as usize % 8);
|
||||
slot_rect.top = 16 * (index as usize / 8);
|
||||
slot_rect.right = slot_rect.left + 32;
|
||||
slot_rect.bottom = slot_rect.top + 16;
|
||||
|
||||
batch.add_rect(slot_offset + i as f32 * 40.0, 64.0, &slot_rect);
|
||||
}
|
||||
|
||||
batch.draw(ctx)?;
|
||||
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "TextBox")?;
|
||||
|
||||
batch.add_rect(128.0, self.stage_select_text_y_pos as f32, &state.constants.textscript.stage_select_text);
|
||||
if slot_count > 0 {
|
||||
batch.add_rect(slot_offset + self.current_teleport_slot as f32 * 40.0, 64.0, &state.constants.textscript.cursor[self.tick / 2 % 2]);
|
||||
}
|
||||
|
||||
batch.draw(ctx)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Scene for GameScene {
|
||||
fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
let seed = (self.player.max_life as i32)
|
||||
.wrapping_add(self.player.x as i32)
|
||||
.wrapping_add(self.player.y as i32)
|
||||
.wrapping_add(self.stage_id as i32)
|
||||
.wrapping_mul(7);
|
||||
state.game_rng = RNG::new(seed);
|
||||
state.textscript_vm.set_scene_script(self.stage.load_text_script(&state.base_path, &state.constants, ctx)?);
|
||||
state.textscript_vm.suspend = false;
|
||||
|
||||
let npcs = self.stage.load_npcs(&state.base_path, ctx)?;
|
||||
for npc_data in npcs.iter() {
|
||||
log::info!("creating npc: {:?}", npc_data);
|
||||
|
||||
let npc = self.npc_map.create_npc_from_data(&state.npc_table, npc_data);
|
||||
if npc.npc_flags.appear_when_flag_set() {
|
||||
if let Some(true) = state.game_flags.get(npc_data.flag_num as usize) {
|
||||
npc.cond.set_alive(true);
|
||||
}
|
||||
} else if npc.npc_flags.hide_unless_flag_set() {
|
||||
if let Some(false) = state.game_flags.get(npc_data.flag_num as usize) {
|
||||
npc.cond.set_alive(true);
|
||||
}
|
||||
} else {
|
||||
npc.cond.set_alive(true);
|
||||
}
|
||||
}
|
||||
|
||||
state.npc_table.tileset_name = self.tex_tileset_name.to_owned();
|
||||
state.npc_table.tex_npc1_name = ["Npc/", &self.stage.data.npc1.filename()].join("");
|
||||
state.npc_table.tex_npc2_name = ["Npc/", &self.stage.data.npc2.filename()].join("");
|
||||
|
||||
self.player.target_x = self.player.x;
|
||||
self.player.target_y = self.player.y;
|
||||
self.frame.immediate_update(state, &self.player, &self.stage);
|
||||
|
||||
// self.inventory.add_weapon(WeaponType::PolarStar, 0);
|
||||
// self.inventory.add_xp(120, state);
|
||||
// self.player.equip.set_booster_2_0(true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
state.update_key_trigger();
|
||||
|
||||
match state.textscript_vm.mode {
|
||||
ScriptMode::Map if state.control_flags.tick_world() => self.tick_world(state)?,
|
||||
ScriptMode::StageSelect => self.tick_stage_select(state)?,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.map_name_counter > 0 {
|
||||
self.map_name_counter -= 1;
|
||||
}
|
||||
|
|
@ -1017,6 +1121,10 @@ impl Scene for GameScene {
|
|||
self.draw_hud(state, ctx)?;
|
||||
}
|
||||
|
||||
if state.textscript_vm.mode == ScriptMode::StageSelect {
|
||||
self.draw_stage_select(state, ctx)?;
|
||||
}
|
||||
|
||||
self.draw_fade(state, ctx)?;
|
||||
if self.map_name_counter > 0 {
|
||||
let width = state.font.text_width(self.stage.data.name.chars(), &state.constants);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::scene::Scene;
|
|||
use crate::sound::SoundManager;
|
||||
use crate::stage::StageData;
|
||||
use crate::str;
|
||||
use crate::text_script::{TextScriptExecutionState, TextScriptVM};
|
||||
use crate::text_script::{TextScriptExecutionState, TextScriptVM, ScriptMode};
|
||||
use crate::texture_set::TextureSet;
|
||||
use crate::ggez::graphics::Canvas;
|
||||
|
||||
|
|
@ -52,6 +52,7 @@ pub struct SharedGameState {
|
|||
pub game_rng: RNG,
|
||||
pub effect_rng: RNG,
|
||||
pub quake_counter: u16,
|
||||
pub teleporter_slots: Vec<(u16, u16)>,
|
||||
pub carets: Vec<Caret>,
|
||||
pub key_state: KeyState,
|
||||
pub key_trigger: KeyState,
|
||||
|
|
@ -109,6 +110,7 @@ impl SharedGameState {
|
|||
game_rng: RNG::new(0),
|
||||
effect_rng: RNG::new(Instant::now().elapsed().as_nanos() as i32),
|
||||
quake_counter: 0,
|
||||
teleporter_slots: Vec::with_capacity(8),
|
||||
carets: Vec::with_capacity(32),
|
||||
key_state: KeyState(0),
|
||||
key_trigger: KeyState(0),
|
||||
|
|
@ -177,13 +179,14 @@ impl SharedGameState {
|
|||
self.game_flags = bitvec::bitvec![0; 8000];
|
||||
self.fade_state = FadeState::Hidden;
|
||||
self.game_rng = RNG::new(0);
|
||||
self.teleporter_slots.clear();
|
||||
self.quake_counter = 0;
|
||||
self.carets.clear();
|
||||
self.key_state.0 = 0;
|
||||
self.key_trigger.0 = 0;
|
||||
self.key_old = 0;
|
||||
self.new_npcs.clear();
|
||||
self.textscript_vm.reset();
|
||||
self.textscript_vm.set_mode(ScriptMode::Map);
|
||||
self.textscript_vm.suspend = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -390,12 +390,26 @@ pub struct Scripts {
|
|||
}
|
||||
|
||||
impl Scripts {
|
||||
pub fn find_script(&self, event_num: u16) -> Option<&Vec<u8>> {
|
||||
pub fn find_script(&self, mode: ScriptMode, event_num: u16) -> Option<&Vec<u8>> {
|
||||
match mode {
|
||||
ScriptMode::Map => {
|
||||
if let Some(tsc) = self.scene_script.event_map.get(&event_num) {
|
||||
return Some(tsc);
|
||||
} else if let Some(tsc) = self.global_script.event_map.get(&event_num) {
|
||||
return Some(tsc);
|
||||
}
|
||||
}
|
||||
ScriptMode::Inventory => {
|
||||
if let Some(tsc) = self.inventory_script.event_map.get(&event_num) {
|
||||
return Some(tsc);
|
||||
}
|
||||
}
|
||||
ScriptMode::StageSelect => {
|
||||
if let Some(tsc) = self.stage_select_script.event_map.get(&event_num) {
|
||||
return Some(tsc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
|
@ -473,7 +487,10 @@ impl TextScriptVM {
|
|||
self.line_3.clear();
|
||||
}
|
||||
|
||||
pub fn set_mode(&mut self, mode: ScriptMode) {}
|
||||
pub fn set_mode(&mut self, mode: ScriptMode) {
|
||||
self.reset();
|
||||
self.mode = mode;
|
||||
}
|
||||
|
||||
pub fn start_script(&mut self, event_num: u16) {
|
||||
self.reset();
|
||||
|
|
@ -505,7 +522,7 @@ impl TextScriptVM {
|
|||
break;
|
||||
}
|
||||
|
||||
if let Some(bytecode) = state.textscript_vm.scripts.find_script(event) {
|
||||
if let Some(bytecode) = state.textscript_vm.scripts.find_script(state.textscript_vm.mode, event) {
|
||||
let mut cursor = Cursor::new(bytecode);
|
||||
cursor.seek(SeekFrom::Start(ip as u64))?;
|
||||
|
||||
|
|
@ -613,7 +630,7 @@ impl TextScriptVM {
|
|||
let mut exec_state = state.textscript_vm.state;
|
||||
let mut tick_npc = 0u16;
|
||||
|
||||
if let Some(bytecode) = state.textscript_vm.scripts.find_script(event) {
|
||||
if let Some(bytecode) = state.textscript_vm.scripts.find_script(state.textscript_vm.mode, event) {
|
||||
let mut cursor = Cursor::new(bytecode);
|
||||
cursor.seek(SeekFrom::Start(ip as u64))?;
|
||||
|
||||
|
|
@ -656,6 +673,29 @@ impl TextScriptVM {
|
|||
|
||||
exec_state = TextScriptExecutionState::Ended;
|
||||
}
|
||||
OpCode::SLP => {
|
||||
state.textscript_vm.set_mode(ScriptMode::StageSelect);
|
||||
|
||||
let event_num = if let Some(slot) = state.teleporter_slots.get(game_scene.current_teleport_slot as usize) {
|
||||
1000 + slot.0
|
||||
} else {
|
||||
1000
|
||||
};
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
||||
}
|
||||
OpCode::PSp => {
|
||||
let index = read_cur_varint(&mut cursor)? as u16;
|
||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
|
||||
if let Some(slot) = state.teleporter_slots.iter_mut().find(|s| s.0 == index) {
|
||||
slot.1 = event_num;
|
||||
} else {
|
||||
state.teleporter_slots.push((index, event_num));
|
||||
}
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::PRI => {
|
||||
state.control_flags.set_tick_world(false);
|
||||
state.control_flags.set_control_enabled(false);
|
||||
|
|
@ -1250,7 +1290,7 @@ impl TextScriptVM {
|
|||
// Zero operands
|
||||
OpCode::CAT | OpCode::CIL | OpCode::CPS | OpCode::KE2 |
|
||||
OpCode::CRE | OpCode::CSS | OpCode::FLA | OpCode::MLP |
|
||||
OpCode::SAT | OpCode::SLP | OpCode::SPS | OpCode::FR2 |
|
||||
OpCode::SAT | OpCode::SPS | OpCode::FR2 |
|
||||
OpCode::STC | OpCode::SVP | OpCode::TUR | OpCode::HM2 => {
|
||||
log::warn!("unimplemented opcode: {:?}", op);
|
||||
|
||||
|
|
@ -1268,7 +1308,7 @@ impl TextScriptVM {
|
|||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// Two operand codes
|
||||
OpCode::SKJ | OpCode::SMP | OpCode::PSp => {
|
||||
OpCode::SKJ | OpCode::SMP => {
|
||||
let par_a = read_cur_varint(&mut cursor)?;
|
||||
let par_b = read_cur_varint(&mut cursor)?;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue