1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-07-30 17:21:01 +00:00

Compare commits

...

7 commits

Author SHA1 Message Date
Alula ecabff27a8
rework cutscene skipping 2021-05-02 06:06:51 +02:00
Alula ad6a330ae0
make lua function casing match docs 2021-05-02 04:05:21 +02:00
Alula d83f58fe1b
add support for map flags 2021-05-02 04:04:52 +02:00
Alula 4f34e33b57
add skip flags, fix pre-save 'do you want to retry' 2021-05-02 02:09:54 +02:00
Alula 0db2e02181
fix rectangle rendering 2021-05-02 02:08:24 +02:00
Alula 490f02f2fe
stop eating CPU time when window is in background 2021-05-02 02:07:44 +02:00
Alula d6316aa718
fix balfrog 2021-04-28 22:58:07 +02:00
12 changed files with 414 additions and 169 deletions

View file

@ -77,6 +77,19 @@ impl BMFontRenderer {
self.draw_colored_text(iter, x, y, (255, 255, 255, 255), constants, texture_set, ctx)
}
pub fn draw_text_with_shadow<I: Iterator<Item = char> + Clone>(
&self,
iter: I,
x: f32,
y: f32,
constants: &EngineConstants,
texture_set: &mut TextureSet,
ctx: &mut Context,
) -> GameResult {
self.draw_colored_text(iter.clone(), x + 1.0, y + 1.0, (0, 0, 0, 150), constants, texture_set, ctx)?;
self.draw_colored_text(iter, x, y, (255, 255, 255, 255), constants, texture_set, ctx)
}
pub fn draw_colored_text_scaled<I: Iterator<Item = char>>(
&self,
iter: I,

View file

@ -24,6 +24,7 @@ use crate::framework::render_opengl::{GLContext, OpenGLRenderer};
use crate::framework::ui::init_imgui;
use crate::Game;
use crate::GAME_SUSPENDED;
use std::time::Duration;
pub struct SDL2Backend {
context: Sdl,
@ -176,6 +177,7 @@ impl BackendEventLoop for SDL2EventLoop {
{
let mutex = GAME_SUSPENDED.lock().unwrap();
if *mutex {
std::thread::sleep(Duration::from_millis(10));
continue;
}
}

View file

@ -27,6 +27,7 @@ pub struct OpenGLTexture {
texture_id: u32,
framebuffer_id: u32,
locs: Locs,
program: GLuint,
vbo: GLuint,
vertices: Vec<VertexData>,
context_active: Arc<RefCell<bool>>,
@ -187,6 +188,7 @@ impl BackendTexture for OpenGLTexture {
gl.gl.BindTexture(gl::TEXTURE_2D, self.texture_id);
gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.vbo);
gl.gl.UseProgram(self.program);
gl.gl.EnableVertexAttribArray(self.locs.position);
gl.gl.EnableVertexAttribArray(self.locs.uv);
gl.gl.EnableVertexAttribArray(self.locs.color);
@ -347,8 +349,10 @@ struct Locs {
struct ImguiData {
initialized: bool,
program: GLuint,
locs: Locs,
program_tex: GLuint,
program_fill: GLuint,
tex_locs: Locs,
fill_locs: Locs,
vbo: GLuint,
ebo: GLuint,
font_texture: GLuint,
@ -359,8 +363,10 @@ impl ImguiData {
fn new() -> Self {
ImguiData {
initialized: false,
program: 0,
locs: Locs { texture: 0, proj_mtx: 0, position: 0, uv: 0, color: 0 },
program_tex: 0,
program_fill: 0,
tex_locs: Locs { texture: 0, proj_mtx: 0, position: 0, uv: 0, color: 0 },
fill_locs: Locs { texture: 0, proj_mtx: 0, position: 0, uv: 0, color: 0 },
vbo: 0,
ebo: 0,
font_texture: 0,
@ -372,37 +378,61 @@ impl ImguiData {
self.initialized = true;
let vert_sources = [VERTEX_SHADER_BASIC.as_ptr() as *const GLchar];
let frag_sources = [FRAGMENT_SHADER_TEXTURED.as_ptr() as *const GLchar];
let frag_sources_tex = [FRAGMENT_SHADER_TEXTURED.as_ptr() as *const GLchar];
let frag_sources_fill = [FRAGMENT_SHADER_COLOR.as_ptr() as *const GLchar];
let vert_sources_len = [VERTEX_SHADER_BASIC.len() as GLint - 1];
let frag_sources_len = [FRAGMENT_SHADER_TEXTURED.len() as GLint - 1];
let frag_sources_tex_len = [FRAGMENT_SHADER_TEXTURED.len() as GLint - 1];
let frag_sources_fill_len = [FRAGMENT_SHADER_COLOR.len() as GLint - 1];
unsafe {
self.program = gl.gl.CreateProgram();
self.program_tex = gl.gl.CreateProgram();
self.program_fill = gl.gl.CreateProgram();
let vert_shader = gl.gl.CreateShader(gl::VERTEX_SHADER);
let frag_shader = gl.gl.CreateShader(gl::FRAGMENT_SHADER);
gl.gl.ShaderSource(vert_shader, 1, vert_sources.as_ptr(), vert_sources_len.as_ptr());
gl.gl.ShaderSource(frag_shader, 1, frag_sources.as_ptr(), frag_sources_len.as_ptr());
gl.gl.CompileShader(vert_shader);
let frag_shader_tex = gl.gl.CreateShader(gl::FRAGMENT_SHADER);
let frag_shader_fill = gl.gl.CreateShader(gl::FRAGMENT_SHADER);
gl.gl.CompileShader(frag_shader);
gl.gl.AttachShader(self.program, vert_shader);
gl.gl.AttachShader(self.program, frag_shader);
gl.gl.LinkProgram(self.program);
gl.gl.ShaderSource(vert_shader, 1, vert_sources.as_ptr(), vert_sources_len.as_ptr());
gl.gl.ShaderSource(frag_shader_tex, 1, frag_sources_tex.as_ptr(), frag_sources_tex_len.as_ptr());
gl.gl.ShaderSource(frag_shader_fill, 1, frag_sources_fill.as_ptr(), frag_sources_fill_len.as_ptr());
gl.gl.CompileShader(vert_shader);
gl.gl.CompileShader(frag_shader_tex);
gl.gl.CompileShader(frag_shader_fill);
if !check_shader_compile_status(vert_shader, gl) {
gl.gl.DeleteShader(vert_shader);
}
if !check_shader_compile_status(frag_shader, gl) {
gl.gl.DeleteShader(frag_shader);
if !check_shader_compile_status(frag_shader_tex, gl) {
gl.gl.DeleteShader(frag_shader_tex);
}
self.locs = Locs {
texture: gl.gl.GetUniformLocation(self.program, b"Texture\0".as_ptr() as _),
proj_mtx: gl.gl.GetUniformLocation(self.program, b"ProjMtx\0".as_ptr() as _),
position: gl.gl.GetAttribLocation(self.program, b"Position\0".as_ptr() as _) as _,
uv: gl.gl.GetAttribLocation(self.program, b"UV\0".as_ptr() as _) as _,
color: gl.gl.GetAttribLocation(self.program, b"Color\0".as_ptr() as _) as _,
if !check_shader_compile_status(frag_shader_fill, gl) {
gl.gl.DeleteShader(frag_shader_fill);
}
gl.gl.AttachShader(self.program_tex, vert_shader);
gl.gl.AttachShader(self.program_tex, frag_shader_tex);
gl.gl.LinkProgram(self.program_tex);
gl.gl.AttachShader(self.program_fill, vert_shader);
gl.gl.AttachShader(self.program_fill, frag_shader_fill);
gl.gl.LinkProgram(self.program_fill);
self.tex_locs = Locs {
texture: gl.gl.GetUniformLocation(self.program_tex, b"Texture\0".as_ptr() as _),
proj_mtx: gl.gl.GetUniformLocation(self.program_tex, b"ProjMtx\0".as_ptr() as _),
position: gl.gl.GetAttribLocation(self.program_tex, b"Position\0".as_ptr() as _) as _,
uv: gl.gl.GetAttribLocation(self.program_tex, b"UV\0".as_ptr() as _) as _,
color: gl.gl.GetAttribLocation(self.program_tex, b"Color\0".as_ptr() as _) as _,
};
self.fill_locs = Locs {
texture: gl.gl.GetUniformLocation(self.program_fill, b"Texture\0".as_ptr() as _),
proj_mtx: gl.gl.GetUniformLocation(self.program_fill, b"ProjMtx\0".as_ptr() as _),
position: gl.gl.GetAttribLocation(self.program_fill, b"Position\0".as_ptr() as _) as _,
uv: gl.gl.GetAttribLocation(self.program_fill, b"UV\0".as_ptr() as _) as _,
color: gl.gl.GetAttribLocation(self.program_fill, b"Color\0".as_ptr() as _) as _,
};
self.vbo = return_param(|x| gl.gl.GenBuffers(1, x));
@ -581,9 +611,11 @@ impl BackendRenderer for OpenGLRenderer {
gl.gl.BindBuffer(gl::ARRAY_BUFFER, 0);
gl.gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
gl.gl.UseProgram(self.imgui_data.program);
gl.gl.Uniform1i(self.imgui_data.locs.texture, 0);
gl.gl.UniformMatrix4fv(self.imgui_data.locs.proj_mtx, 1, gl::FALSE, self.def_matrix.as_ptr() as _);
gl.gl.UseProgram(self.imgui_data.program_fill);
gl.gl.UniformMatrix4fv(self.imgui_data.fill_locs.proj_mtx, 1, gl::FALSE, self.def_matrix.as_ptr() as _);
gl.gl.UseProgram(self.imgui_data.program_tex);
gl.gl.Uniform1i(self.imgui_data.tex_locs.texture, 0);
gl.gl.UniformMatrix4fv(self.imgui_data.tex_locs.proj_mtx, 1, gl::FALSE, self.def_matrix.as_ptr() as _);
}
Ok(())
@ -635,7 +667,8 @@ impl BackendRenderer for OpenGLRenderer {
width,
height,
vertices: Vec::new(),
locs: self.imgui_data.locs,
locs: self.imgui_data.tex_locs,
program: self.imgui_data.program_tex,
vbo: self.imgui_data.vbo,
context_active: self.context_active.clone(),
}))
@ -674,7 +707,8 @@ impl BackendRenderer for OpenGLRenderer {
width,
height,
vertices: Vec::new(),
locs: self.imgui_data.locs,
locs: self.imgui_data.tex_locs,
program: self.imgui_data.program_tex,
vbo: self.imgui_data.vbo,
context_active: self.context_active.clone(),
}))
@ -719,11 +753,19 @@ impl BackendRenderer for OpenGLRenderer {
[0.0, 0.0, -1.0, 0.0],
[-1.0, -1.0, 0.0, 1.0],
];
gl.gl.UniformMatrix4fv(self.imgui_data.locs.proj_mtx, 1, gl::FALSE, matrix.as_ptr() as _);
gl.gl.UseProgram(self.imgui_data.program_fill);
gl.gl.UniformMatrix4fv(self.imgui_data.fill_locs.proj_mtx, 1, gl::FALSE, matrix.as_ptr() as _);
gl.gl.UseProgram(self.imgui_data.program_tex);
gl.gl.Uniform1i(self.imgui_data.tex_locs.texture, 0);
gl.gl.UniformMatrix4fv(self.imgui_data.tex_locs.proj_mtx, 1, gl::FALSE, matrix.as_ptr() as _);
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, gl_texture.framebuffer_id);
} else {
gl.gl.UniformMatrix4fv(self.imgui_data.locs.proj_mtx, 1, gl::FALSE, self.def_matrix.as_ptr() as _);
gl.gl.UseProgram(self.imgui_data.program_fill);
gl.gl.UniformMatrix4fv(self.imgui_data.fill_locs.proj_mtx, 1, gl::FALSE, self.def_matrix.as_ptr() as _);
gl.gl.UseProgram(self.imgui_data.program_tex);
gl.gl.Uniform1i(self.imgui_data.tex_locs.texture, 0);
gl.gl.UniformMatrix4fv(self.imgui_data.tex_locs.proj_mtx, 1, gl::FALSE, self.def_matrix.as_ptr() as _);
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, 0);
}
}
@ -755,13 +797,14 @@ impl BackendRenderer for OpenGLRenderer {
gl.gl.BindSampler(0, 0);
}
gl.gl.UseProgram(self.imgui_data.program_fill);
gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.imgui_data.vbo);
gl.gl.EnableVertexAttribArray(self.imgui_data.locs.position);
gl.gl.EnableVertexAttribArray(self.imgui_data.locs.uv);
gl.gl.EnableVertexAttribArray(self.imgui_data.locs.color);
gl.gl.EnableVertexAttribArray(self.imgui_data.fill_locs.position);
gl.gl.EnableVertexAttribArray(self.imgui_data.fill_locs.uv);
gl.gl.EnableVertexAttribArray(self.imgui_data.fill_locs.color);
gl.gl.VertexAttribPointer(
self.imgui_data.locs.position,
self.imgui_data.fill_locs.position,
2,
gl::FLOAT,
gl::FALSE,
@ -770,7 +813,7 @@ impl BackendRenderer for OpenGLRenderer {
);
gl.gl.VertexAttribPointer(
self.imgui_data.locs.uv,
self.imgui_data.fill_locs.uv,
2,
gl::FLOAT,
gl::FALSE,
@ -779,7 +822,7 @@ impl BackendRenderer for OpenGLRenderer {
);
gl.gl.VertexAttribPointer(
self.imgui_data.locs.color,
self.imgui_data.fill_locs.color,
4,
gl::UNSIGNED_BYTE,
gl::TRUE,
@ -842,9 +885,9 @@ impl BackendRenderer for OpenGLRenderer {
[0.0, 0.0, -1.0, 0.0],
[-1.0, 1.0, 0.0, 1.0],
];
gl.gl.UseProgram(self.imgui_data.program);
gl.gl.Uniform1i(self.imgui_data.locs.texture, 0);
gl.gl.UniformMatrix4fv(self.imgui_data.locs.proj_mtx, 1, gl::FALSE, matrix.as_ptr() as _);
gl.gl.UseProgram(self.imgui_data.program_tex);
gl.gl.Uniform1i(self.imgui_data.tex_locs.texture, 0);
gl.gl.UniformMatrix4fv(self.imgui_data.tex_locs.proj_mtx, 1, gl::FALSE, matrix.as_ptr() as _);
if gl.gl.BindSampler.is_loaded() {
gl.gl.BindSampler(0, 0);
@ -853,12 +896,12 @@ impl BackendRenderer for OpenGLRenderer {
// let vao = return_param(|x| gl.gl.GenVertexArrays(1, x));
//gl.gl.BindVertexArray(vao);
gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.imgui_data.vbo);
gl.gl.EnableVertexAttribArray(self.imgui_data.locs.position);
gl.gl.EnableVertexAttribArray(self.imgui_data.locs.uv);
gl.gl.EnableVertexAttribArray(self.imgui_data.locs.color);
gl.gl.EnableVertexAttribArray(self.imgui_data.tex_locs.position);
gl.gl.EnableVertexAttribArray(self.imgui_data.tex_locs.uv);
gl.gl.EnableVertexAttribArray(self.imgui_data.tex_locs.color);
gl.gl.VertexAttribPointer(
self.imgui_data.locs.position,
self.imgui_data.tex_locs.position,
2,
gl::FLOAT,
gl::FALSE,
@ -867,7 +910,7 @@ impl BackendRenderer for OpenGLRenderer {
);
gl.gl.VertexAttribPointer(
self.imgui_data.locs.uv,
self.imgui_data.tex_locs.uv,
2,
gl::FLOAT,
gl::FALSE,
@ -876,7 +919,7 @@ impl BackendRenderer for OpenGLRenderer {
);
gl.gl.VertexAttribPointer(
self.imgui_data.locs.color,
self.imgui_data.tex_locs.color,
4,
gl::UNSIGNED_BYTE,
gl::TRUE,

View file

@ -222,7 +222,8 @@ impl BossNPC {
}
113 => {
if self.parts[0].shock != 0 {
if self.parts[0].action_counter2 / 2 % 2 != 0 {
self.parts[0].action_counter2 += 1;
if (self.parts[0].action_counter2 / 2) & 1 != 0 {
self.parts[0].anim_num = 4;
} else {
self.parts[0].anim_num = 3;
@ -309,9 +310,9 @@ impl BossNPC {
if self.parts[0].anim_counter > 4 {
self.parts[0].action_num = 124;
self.parts[0].anim_num = 5;
self.parts[0].vel_x = -5 * 0x200;
self.parts[0].display_bounds.top = 64 * 0x200;
self.parts[0].display_bounds.bottom = 24 * 0x200;
self.parts[0].vel_y = -0xa00;
self.parts[0].display_bounds.top = 0x8000;
self.parts[0].display_bounds.bottom = 0x3000;
state.sound_manager.play_sfx(25);
}
@ -320,8 +321,8 @@ impl BossNPC {
if self.parts[0].flags.hit_bottom_wall() {
self.parts[0].action_num = 100;
self.parts[0].anim_num = 1;
self.parts[0].display_bounds.top = 48 * 0x200;
self.parts[0].display_bounds.bottom = 16 * 0x200;
self.parts[0].display_bounds.top = 0x6000;
self.parts[0].display_bounds.bottom = 0x2000;
let mut npc = NPC::create(104, &state.npc_table);
for _ in 0..2 {
@ -363,7 +364,7 @@ impl BossNPC {
if self.parts[0].direction == Direction::Right && self.parts[0].x > player.x {
self.parts[0].action_num = 110;
self.parts[0].direction = Direction::Right;
self.parts[0].direction = Direction::Left;
}
state.sound_manager.play_sfx(26);
@ -419,7 +420,7 @@ impl BossNPC {
}
132 => {
self.parts[0].action_counter += 1;
if (self.parts[0].action_counter / 2 % 2) != 0 {
if (self.parts[0].action_counter / 2) & 1 != 0 {
self.parts[0].anim_num = 6;
self.parts[0].display_bounds = Rect {
left: 20 * 0x200,

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

@ -20,9 +20,9 @@ use crate::framework::graphics::{BlendMode, draw_rect, FilterMode};
use crate::framework::ui::Components;
use crate::input::touch_controls::TouchControlType;
use crate::inventory::{Inventory, TakeExperienceResult};
use crate::npc::{NPC, NPCLayer};
use crate::npc::boss::BossNPC;
use crate::npc::list::NPCList;
use crate::npc::{NPC, NPCLayer};
use crate::physics::PhysicalEntity;
use crate::player::{Player, TargetPlayer};
use crate::rng::XorShift;
@ -57,6 +57,7 @@ pub struct GameScene {
tex_background_name: String,
tex_tileset_name: String,
map_name_counter: u16,
skip_counter: u16,
}
#[derive(Debug, EnumIter, PartialEq, Eq, Hash, Copy, Clone)]
@ -71,6 +72,7 @@ const FACE_TEX: &str = "Face";
const SWITCH_FACE_TEX: [&str; 4] = ["Face1", "Face2", "Face3", "Face4"];
const P2_LEFT_TEXT: &str = "< P2";
const P2_RIGHT_TEXT: &str = "P2 >";
const CUTSCENE_SKIP_WAIT: u16 = 50;
impl GameScene {
pub fn new(state: &mut SharedGameState, ctx: &mut Context, id: usize) -> GameResult<Self> {
@ -112,6 +114,7 @@ impl GameScene {
tex_background_name,
tex_tileset_name,
map_name_counter: 0,
skip_counter: 0,
})
}
@ -212,18 +215,19 @@ impl GameScene {
Ok(())
}
fn draw_npc_layer(&self, state: &mut SharedGameState, ctx: &mut Context, layer: NPCLayer) -> GameResult {
fn draw_npc_layer(&self, state: &mut SharedGameState, ctx: &mut Context, layer: NPCLayer) -> GameResult {
for npc in self.npc_list.iter_alive() {
if npc.layer != layer || npc.x < (self.frame.x - 128 * 0x200 - npc.display_bounds.width() as i32 * 0x200)
if npc.layer != layer
|| npc.x < (self.frame.x - 128 * 0x200 - npc.display_bounds.width() as i32 * 0x200)
|| npc.x
> (self.frame.x
+ 128 * 0x200
+ (state.canvas_size.0 as i32 + npc.display_bounds.width() as i32) * 0x200)
&& npc.y < (self.frame.y - 128 * 0x200 - npc.display_bounds.height() as i32 * 0x200)
> (self.frame.x
+ 128 * 0x200
+ (state.canvas_size.0 as i32 + npc.display_bounds.width() as i32) * 0x200)
&& npc.y < (self.frame.y - 128 * 0x200 - npc.display_bounds.height() as i32 * 0x200)
|| npc.y
> (self.frame.y
+ 128 * 0x200
+ (state.canvas_size.1 as i32 + npc.display_bounds.height() as i32) * 0x200)
> (self.frame.y
+ 128 * 0x200
+ (state.canvas_size.1 as i32 + npc.display_bounds.height() as i32) * 0x200)
{
continue;
}
@ -412,10 +416,15 @@ impl GameScene {
return Ok(());
}
let (off_left, off_top, off_right, off_bottom) = crate::framework::graphics::screen_insets_scaled(ctx, state.scale);
let (off_left, off_top, off_right, off_bottom) =
crate::framework::graphics::screen_insets_scaled(ctx, state.scale);
let center = ((state.canvas_size.0 - off_left - off_right) / 2.0).floor();
let top_pos = if state.textscript_vm.flags.position_top() { 32.0 + off_top } else { state.canvas_size.1 as f32 - off_bottom - 66.0 };
let top_pos = if state.textscript_vm.flags.position_top() {
32.0 + off_top
} else {
state.canvas_size.1 as f32 - off_bottom - 66.0
};
let left_pos = off_left + center - 122.0;
{
@ -446,7 +455,7 @@ impl GameScene {
);
batch.add_rect(
center + 32.0,
state.canvas_size.1 - off_bottom- 104.0,
state.canvas_size.1 - off_bottom - 104.0,
&state.constants.textscript.get_item_right,
);
batch.add_rect(
@ -468,11 +477,7 @@ impl GameScene {
state.canvas_size.1 - off_bottom - 96.0
};
batch.add_rect(
center + 56.0,
pos_y,
&state.constants.textscript.textbox_rect_yes_no,
);
batch.add_rect(center + 56.0, pos_y, &state.constants.textscript.textbox_rect_yes_no);
if wait == 0 {
let pos_x = if selection == ConfirmSelection::No { 41.0 } else { 0.0 };
@ -617,7 +622,15 @@ impl GameScene {
)
}
fn draw_light_raycast(&self, world_point_x: i32, world_point_y: i32, (br, bg, bb): (u8, u8, u8), att: u8, angle: Range<i32>, batch: &mut SizedBatch) {
fn draw_light_raycast(
&self,
world_point_x: i32,
world_point_y: i32,
(br, bg, bb): (u8, u8, u8),
att: u8,
angle: Range<i32>,
batch: &mut SizedBatch,
) {
let px = world_point_x as f32 / 512.0;
let py = world_point_y as f32 / 512.0;
@ -649,43 +662,43 @@ impl GameScene {
&& x >= (bx * 16 - 8) as f32
&& x <= (bx * 16 + 8) as f32
&& y >= (by * 16 - 8) as f32
&& y <= (by * 16 + 8) as f32) ||
((tile == 0x50 || tile == 0x70)
&& y <= (by * 16 + 8) as f32)
|| ((tile == 0x50 || tile == 0x70)
&& x >= (bx * 16 - 8) as f32
&& x <= (bx * 16 + 8) as f32
&& y <= ((by as f32 * 16.0) - (x - bx as f32 * 16.0) / 2.0 + 4.0)
&& y >= (by * 16 - 8) as f32) ||
((tile == 0x51 || tile == 0x71)
&& y >= (by * 16 - 8) as f32)
|| ((tile == 0x51 || tile == 0x71)
&& x >= (bx * 16 - 8) as f32
&& x <= (bx * 16 + 8) as f32
&& y <= ((by as f32 * 16.0) - (x - bx as f32 * 16.0) / 2.0 - 4.0)
&& y >= (by * 16 - 8) as f32) ||
((tile == 0x52 || tile == 0x72)
&& y >= (by * 16 - 8) as f32)
|| ((tile == 0x52 || tile == 0x72)
&& x >= (bx * 16 - 8) as f32
&& x <= (bx * 16 + 8) as f32
&& y <= ((by as f32 * 16.0) + (x - bx as f32 * 16.0) / 2.0 - 4.0)
&& y >= (by * 16 - 8) as f32) ||
((tile == 0x53 || tile == 0x73)
&& y >= (by * 16 - 8) as f32)
|| ((tile == 0x53 || tile == 0x73)
&& x >= (bx * 16 - 8) as f32
&& x <= (bx * 16 + 8) as f32
&& y <= ((by as f32 * 16.0) + (x - bx as f32 * 16.0) / 2.0 + 4.0)
&& y >= (by * 16 - 8) as f32) ||
((tile == 0x54 || tile == 0x74)
&& y >= (by * 16 - 8) as f32)
|| ((tile == 0x54 || tile == 0x74)
&& x >= (bx * 16 - 8) as f32
&& x <= (bx * 16 + 8) as f32
&& y >= ((by as f32 * 16.0) + (x - bx as f32 * 16.0) / 2.0 - 4.0)
&& y <= (by * 16 + 8) as f32) ||
((tile == 0x55 || tile == 0x75)
&& y <= (by * 16 + 8) as f32)
|| ((tile == 0x55 || tile == 0x75)
&& x >= (bx * 16 - 8) as f32
&& x <= (bx * 16 + 8) as f32
&& y >= ((by as f32 * 16.0) + (x - bx as f32 * 16.0) / 2.0 + 4.0)
&& y <= (by * 16 + 8) as f32) ||
((tile == 0x56 || tile == 0x76)
&& y <= (by * 16 + 8) as f32)
|| ((tile == 0x56 || tile == 0x76)
&& x >= (bx * 16 - 8) as f32
&& x <= (bx * 16 + 8) as f32
&& y >= ((by as f32 * 16.0) - (x - bx as f32 * 16.0) / 2.0 + 4.0)
&& y <= (by * 16 + 8) as f32) ||
((tile == 0x57 || tile == 0x77)
&& y <= (by * 16 + 8) as f32)
|| ((tile == 0x57 || tile == 0x77)
&& x >= (bx * 16 - 8) as f32
&& x <= (bx * 16 + 8) as f32
&& y >= ((by as f32 * 16.0) - (x - bx as f32 * 16.0) / 2.0 - 4.0)
@ -724,7 +737,9 @@ impl GameScene {
let scale = state.scale;
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "builtin/lightmap/spot")?;
for (player, inv) in [(&self.player1, &self.inventory_player1), (&self.player2, &self.inventory_player2)].iter() {
for (player, inv) in
[(&self.player1, &self.inventory_player1), (&self.player2, &self.inventory_player2)].iter()
{
if player.cond.alive() && !player.cond.hidden() && inv.get_current_weapon().is_some() {
let range = match () {
_ if player.up => 60..120,
@ -1496,42 +1511,73 @@ impl Scene for GameScene {
}
}
match state.textscript_vm.mode {
ScriptMode::Map if state.control_flags.tick_world() => self.tick_world(state)?,
ScriptMode::StageSelect => self.stage_select.tick(state, (ctx, &self.player1, &self.player2))?,
ScriptMode::Inventory => self.inventory_ui.tick(state, (ctx, &mut self.player1, &mut self.inventory_player1))?,
_ => {}
match state.textscript_vm.state {
TextScriptExecutionState::Running(_, _)
| TextScriptExecutionState::WaitTicks(_, _, _)
| TextScriptExecutionState::WaitInput(_, _, _)
| TextScriptExecutionState::Msg(_, _, _, _)
if !state.control_flags.control_enabled() && !state.textscript_vm.flags.cutscene_skip() =>
{
if self.player1.controller.inventory() {
self.skip_counter += 1;
if self.skip_counter >= CUTSCENE_SKIP_WAIT {
state.textscript_vm.flags.set_cutscene_skip(true);
}
} else if self.skip_counter > 0 {
self.skip_counter -= 1;
}
}
_ => {
self.skip_counter = 0;
}
}
if self.map_name_counter > 0 {
self.map_name_counter -= 1;
let mut ticks = 1;
if state.textscript_vm.mode == ScriptMode::Map && state.textscript_vm.flags.cutscene_skip() {
ticks = 4;
}
match state.fade_state {
FadeState::FadeOut(tick, direction) if tick < 15 => {
state.fade_state = FadeState::FadeOut(tick + 1, direction);
for _ in 0..ticks {
match state.textscript_vm.mode {
ScriptMode::Map if state.control_flags.tick_world() => self.tick_world(state)?,
ScriptMode::StageSelect => self.stage_select.tick(state, (ctx, &self.player1, &self.player2))?,
ScriptMode::Inventory => {
self.inventory_ui.tick(state, (ctx, &mut self.player1, &mut self.inventory_player1))?
}
_ => {}
}
FadeState::FadeOut(tick, _) if tick == 15 => {
state.fade_state = FadeState::Hidden;
if self.map_name_counter > 0 {
self.map_name_counter -= 1;
}
FadeState::FadeIn(tick, direction) if tick > -15 => {
state.fade_state = FadeState::FadeIn(tick - 1, direction);
match state.fade_state {
FadeState::FadeOut(tick, direction) if tick < 15 => {
state.fade_state = FadeState::FadeOut(tick + 1, direction);
}
FadeState::FadeOut(tick, _) if tick == 15 => {
state.fade_state = FadeState::Hidden;
}
FadeState::FadeIn(tick, direction) if tick > -15 => {
state.fade_state = FadeState::FadeIn(tick - 1, direction);
}
FadeState::FadeIn(tick, _) if tick == -15 => {
state.fade_state = FadeState::Visible;
}
_ => {}
}
FadeState::FadeIn(tick, _) if tick == -15 => {
state.fade_state = FadeState::Visible;
self.flash.tick(state, ())?;
TextScriptVM::run(state, self, ctx)?;
#[cfg(feature = "scripting")]
state.lua.scene_tick(self);
if state.control_flags.control_enabled() {
self.tick = self.tick.wrapping_add(1);
}
_ => {}
}
self.flash.tick(state, ())?;
TextScriptVM::run(state, self, ctx)?;
#[cfg(feature = "scripting")]
state.lua.scene_tick(self);
if state.control_flags.control_enabled() {
self.tick = self.tick.wrapping_add(1);
}
Ok(())
}
@ -1692,6 +1738,36 @@ impl Scene for GameScene {
}
self.draw_text_boxes(state, ctx)?;
if self.skip_counter > 0 {
let text = format!("Hold {:?} to skip the cutscene", state.settings.player1_key_map.inventory);
let width = state.font.text_width(text.chars(), &state.constants);
let pos_x = state.canvas_size.0 - width - 20.0;
let pos_y = 0.0;
let line_height = state.font.line_height(&state.constants);
let w = (self.skip_counter as f32 / CUTSCENE_SKIP_WAIT as f32) * (width + 20.0) / 2.0;
let mut rect = Rect::new_size((pos_x * state.scale) as isize,
(pos_y * state.scale) as isize,
((20.0 + width) * state.scale) as isize,
((20.0 + line_height) * state.scale) as isize);
draw_rect(ctx, rect, Color::from_rgb(0, 0, 32))?;
rect.right = rect.left + (w * state.scale) as isize;
draw_rect(ctx, rect, Color::from_rgb(160, 181, 222))?;
rect.left = ((state.canvas_size.0 - w) * state.scale) as isize;
rect.right = rect.left + (w * state.scale) as isize;
draw_rect(ctx, rect, Color::from_rgb(160, 181, 222))?;
state.font.draw_text_with_shadow(
text.chars(),
pos_x + 10.0,
pos_y + 10.0,
&state.constants,
&mut state.texture_set,
ctx,
)?;
}
if state.settings.debug_outlines {
self.draw_debug_outlines(state, ctx)?;

View file

@ -222,6 +222,7 @@ impl Scene for TitleScene {
},
CurrentMenu::StartGame => {
if self.tick == 10 {
state.reset_skip_flags();
state.start_new_game(ctx)?;
}
}

View file

@ -16,7 +16,7 @@ doukutsu._handlers = setmetatable({
end,
})
doukutsu._initialize_script = function(script)
doukutsu._initializeScript = function(script)
-- for compatibility with Lua 5.2+, copy-pasted from Lua mailing list
-- http://lua-users.org/lists/lua-l/2010-06/msg00313.html
local _setfenv = setfenv or function(f, t)
@ -45,12 +45,12 @@ doukutsu._initialize_script = function(script)
script()
end
doukutsu.play_sfx = function(id)
__doukutsu:play_sfx(id)
doukutsu.playSfx = function(id)
__doukutsu:playSfx(id)
end
doukutsu.play_song = function(id)
__doukutsu:play_song(id)
doukutsu.playSong = function(id)
__doukutsu:playSong(id)
end
doukutsu.on = function(event, handler)
@ -66,7 +66,7 @@ doukutsu.on = function(event, handler)
return handler
end
doukutsu.remove_handler = function(event, handler)
doukutsu.removeHandler = function(event, handler)
assert(type(event) == "string", "event type must be a string.")
assert(type(handler) == "function", "event handler must be a function.")

View file

@ -87,7 +87,7 @@ impl LuaScriptingState {
}
state.get_global("doukutsu");
state.get_field(-1, "_initialize_script");
state.get_field(-1, "_initializeScript");
state.push_value(-3);
let res = state.pcall(1, 0, 0);

View file

@ -126,10 +126,10 @@ impl LuaObject for LuaPlayer {
vec![
lua_method!("x", LuaPlayer, LuaPlayer::lua_get_x),
lua_method!("y", LuaPlayer, LuaPlayer::lua_get_y),
lua_method!("vel_x", LuaPlayer, LuaPlayer::lua_get_vel_x),
lua_method!("vel_y", LuaPlayer, LuaPlayer::lua_get_vel_y),
lua_method!("set_vel_x", LuaPlayer, LuaPlayer::lua_set_vel_x),
lua_method!("set_vel_y", LuaPlayer, LuaPlayer::lua_set_vel_y),
lua_method!("velX", LuaPlayer, LuaPlayer::lua_get_vel_x),
lua_method!("velX", LuaPlayer, LuaPlayer::lua_get_vel_y),
lua_method!("setVelX", LuaPlayer, LuaPlayer::lua_set_vel_x),
lua_method!("setVelY", LuaPlayer, LuaPlayer::lua_set_vel_y),
]
}
}

View file

@ -30,6 +30,7 @@ use crate::stage::StageData;
use crate::str;
use crate::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
use crate::texture_set::TextureSet;
use bitvec::array::BitArray;
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum TimingMode {
@ -89,6 +90,8 @@ pub struct SharedGameState {
pub timing_mode: TimingMode,
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,
@ -160,6 +163,8 @@ impl SharedGameState {
timing_mode: TimingMode::_50Hz,
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),
@ -233,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);
@ -250,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);
@ -364,4 +373,44 @@ impl SharedGameState {
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
}
}
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

@ -262,16 +262,18 @@ pub enum OpCode {
SSS,
// ---- Cave Story+ specific opcodes ----
/// <ACHxxxx, triggers a Steam achievement.
/// <ACHxxxx, triggers a Steam achievement. No-op in EGS/Humble Bundle version.
ACH,
// ---- Cave Story+ (Switch) specific opcodes ----
/// <HM2, HMC for non-executor player.
/// <HM2, HMC only for executor player.
HM2,
/// <2MVxxxx, Put another player near the player who executed the event.
/// 0000 - puts player on left 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")]
S2MV,
/// <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
#[strum(serialize = "I+N")]
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-")]
FFm,
/// <PSHxxxx, Pushes text script state to stack and starts event xxxx
@ -301,6 +303,7 @@ bitfield! {
pub fast, set_fast: 4;
pub position_top, set_position_top: 5;
pub perma_fast, set_perma_fast: 6;
pub cutscene_skip, set_cutscene_skip: 7;
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
@ -602,10 +605,7 @@ impl TextScriptVM {
}
if remaining > 1 {
let ticks = if state.textscript_vm.flags.fast()
|| game_scene.player1.controller.skip()
|| game_scene.player2.controller.skip()
{
let ticks = if state.textscript_vm.flags.fast() || state.textscript_vm.flags.cutscene_skip() {
0
} else if game_scene.player1.controller.jump()
|| game_scene.player1.controller.shoot()
@ -642,6 +642,8 @@ impl TextScriptVM {
}
}
TextScriptExecutionState::WaitConfirmation(event, ip, no_event, wait, selection) => {
state.textscript_vm.flags.set_cutscene_skip(false);
if wait > 0 {
state.textscript_vm.state =
TextScriptExecutionState::WaitConfirmation(event, ip, no_event, wait - 1, selection);
@ -729,12 +731,11 @@ impl TextScriptVM {
state.touch_controls.control_type = TouchControlType::Dialog;
}
if game_scene.player1.controller.trigger_jump()
if state.textscript_vm.flags.cutscene_skip()
|| game_scene.player1.controller.trigger_jump()
|| game_scene.player1.controller.trigger_shoot()
|| game_scene.player1.controller.skip()
|| game_scene.player2.controller.trigger_jump()
|| game_scene.player2.controller.trigger_shoot()
|| game_scene.player2.controller.skip()
{
state.textscript_vm.state = TextScriptExecutionState::Running(event, ip);
}
@ -757,7 +758,8 @@ impl TextScriptVM {
break;
}
TextScriptExecutionState::Reset => {
state.start_intro(ctx)?;
state.reset();
state.start_new_game(ctx)?;
break;
}
}
@ -806,9 +808,11 @@ impl TextScriptVM {
}
}
OpCode::_END => {
state.textscript_vm.flags.set_cutscene_skip(false);
exec_state = TextScriptExecutionState::Ended;
}
OpCode::END => {
state.textscript_vm.flags.set_cutscene_skip(false);
state.control_flags.set_tick_world(true);
state.control_flags.set_control_enabled(true);
@ -937,8 +941,13 @@ impl TextScriptVM {
exec_state = TextScriptExecutionState::WaitInput(event, cursor.position() as u32, 0);
}
OpCode::FLp | OpCode::FLm => {
let flag_num = read_cur_varint(&mut cursor)? as usize;
state.game_flags.set(flag_num, op == OpCode::FLp);
let flag_num = read_cur_varint(&mut cursor)? as u16;
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);
}
OpCode::FFm => {
@ -966,6 +975,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;
@ -1023,6 +1042,17 @@ impl TextScriptVM {
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 => {
let event_num = read_cur_varint(&mut cursor)? as u16;
@ -1035,7 +1065,7 @@ impl TextScriptVM {
let saved_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
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);
}
OpCode::POP => {
@ -1071,8 +1101,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);
@ -1189,8 +1219,10 @@ impl TextScriptVM {
new_scene.player2.x = pos_x;
new_scene.player2.y = pos_y;
let skip = state.textscript_vm.flags.cutscene_skip();
state.control_flags.set_tick_world(true);
state.textscript_vm.flags.0 = 0;
state.textscript_vm.flags.set_cutscene_skip(skip);
state.textscript_vm.face = 0;
state.textscript_vm.item = 0;
state.textscript_vm.current_line = TextScriptLine::Line1;
@ -1231,11 +1263,31 @@ impl TextScriptVM {
partner.x = executor.x + if param == 0 { -16 * 0x200 } else { 16 * 0x200 };
partner.y = executor.y;
}
_ => {
log::warn!("stub: <2MV unknown param");
2..=10 => {
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;
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);
}
OpCode::UNI => {
@ -1499,7 +1551,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);
}
@ -1515,7 +1567,7 @@ impl TextScriptVM {
let item_id = read_cur_varint(&mut cursor)? as u16;
state.sound_manager.play_sfx(38);
if !game_scene.inventory_player1.has_item(item_id) {
game_scene.inventory_player1.add_item(item_id);
}
@ -1639,6 +1691,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
@ -1656,28 +1715,11 @@ impl TextScriptVM {
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
}
// One operand codes
OpCode::MPp
| OpCode::SKm
| OpCode::SKp
| OpCode::UNJ
| OpCode::MPJ
| OpCode::XX1
| OpCode::SIL
| OpCode::SSS
| OpCode::ACH => {
OpCode::UNJ | OpCode::XX1 | OpCode::SIL | OpCode::SSS | OpCode::ACH => {
let par_a = read_cur_varint(&mut cursor)?;
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);
}
}
@ -1802,7 +1844,7 @@ impl TextScript {
) -> GameResult<Vec<u8>> {
let mut bytecode = Vec::new();
let mut char_buf = Vec::with_capacity(16);
let mut allow_next_event = false;
let mut allow_next_event = true;
while let Some(&chr) = iter.peek() {
match chr {