mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-03-25 19:40:27 +00:00
tsc: implement fading
This commit is contained in:
parent
c703203506
commit
1758aa5740
|
@ -8,14 +8,49 @@ use std::cell::RefCell;
|
|||
use std::io::Cursor;
|
||||
|
||||
use byteorder::ReadBytesExt;
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::Num;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
pub enum FadeDirection {
|
||||
Left = 0,
|
||||
Up,
|
||||
Right,
|
||||
Down,
|
||||
Center,
|
||||
}
|
||||
|
||||
|
||||
impl FadeDirection {
|
||||
pub fn from_int(val: usize) -> Option<FadeDirection> {
|
||||
match val {
|
||||
0 => { Some(FadeDirection::Left) }
|
||||
1 => { Some(FadeDirection::Up) }
|
||||
2 => { Some(FadeDirection::Right) }
|
||||
3 => { Some(FadeDirection::Down) }
|
||||
4 => { Some(FadeDirection::Center) }
|
||||
_ => { None }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum FadeState {
|
||||
Visible,
|
||||
FadeIn(i8, FadeDirection),
|
||||
Hidden,
|
||||
FadeOut(i8, FadeDirection),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
pub enum Direction {
|
||||
Left = 0,
|
||||
Up = 1,
|
||||
Right = 2,
|
||||
Bottom = 3,
|
||||
Up,
|
||||
Right,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
|
|
|
@ -16,12 +16,13 @@ use std::{env, mem};
|
|||
use std::path;
|
||||
use std::time::Instant;
|
||||
|
||||
use bitvec::vec::BitVec;
|
||||
use log::*;
|
||||
use pretty_env_logger::env_logger::Env;
|
||||
use winit::{ElementState, Event, KeyboardInput, WindowEvent};
|
||||
|
||||
use crate::caret::{Caret, CaretType};
|
||||
use crate::common::Direction;
|
||||
use crate::common::{Direction, FadeState};
|
||||
use crate::engine_constants::EngineConstants;
|
||||
use crate::ggez::{Context, ContextBuilder, event, filesystem, GameResult};
|
||||
use crate::ggez::conf::{WindowMode, WindowSetup};
|
||||
|
@ -39,7 +40,6 @@ use crate::stage::StageData;
|
|||
use crate::text_script::TextScriptVM;
|
||||
use crate::texture_set::TextureSet;
|
||||
use crate::ui::UI;
|
||||
use bitvec::vec::BitVec;
|
||||
|
||||
mod caret;
|
||||
mod common;
|
||||
|
@ -94,6 +94,7 @@ struct Game {
|
|||
pub struct SharedGameState {
|
||||
pub control_flags: ControlFlags,
|
||||
pub game_flags: BitVec,
|
||||
pub fade_state: FadeState,
|
||||
pub game_rng: RNG,
|
||||
pub effect_rng: RNG,
|
||||
pub carets: Vec<Caret>,
|
||||
|
@ -161,6 +162,7 @@ impl Game {
|
|||
state: SharedGameState {
|
||||
control_flags: ControlFlags(0),
|
||||
game_flags: bitvec::bitvec![0; 8000],
|
||||
fade_state: FadeState::Hidden,
|
||||
game_rng: RNG::new(0),
|
||||
effect_rng: RNG::new(Instant::now().elapsed().as_nanos() as i32),
|
||||
carets: Vec::with_capacity(32),
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use log::info;
|
||||
|
||||
use crate::common::Rect;
|
||||
use crate::common::{FadeDirection, FadeState, Rect};
|
||||
use crate::entity::GameEntity;
|
||||
use crate::frame::Frame;
|
||||
use crate::ggez::{Context, GameResult, timer};
|
||||
use crate::ggez::graphics::{Drawable, DrawParam, Text, TextFragment};
|
||||
use crate::ggez::{Context, GameResult, graphics, timer};
|
||||
use crate::ggez::graphics::{Color, Drawable, DrawParam, Text, TextFragment};
|
||||
use crate::ggez::nalgebra::clamp;
|
||||
use crate::player::Player;
|
||||
use crate::scene::Scene;
|
||||
|
@ -23,6 +23,7 @@ pub struct GameScene {
|
|||
tex_background_name: String,
|
||||
tex_caret_name: String,
|
||||
tex_face_name: String,
|
||||
tex_fade_name: String,
|
||||
tex_hud_name: String,
|
||||
tex_npcsym_name: String,
|
||||
tex_tileset_name: String,
|
||||
|
@ -53,6 +54,7 @@ impl GameScene {
|
|||
let tex_background_name = stage.data.background.filename();
|
||||
let tex_caret_name = str!("Caret");
|
||||
let tex_face_name = str!("Face");
|
||||
let tex_fade_name = str!("Fade");
|
||||
let tex_hud_name = str!("TextBox");
|
||||
let tex_npcsym_name = str!("Npc/NpcSym");
|
||||
let tex_tileset_name = ["Stage/", &stage.data.tileset.filename()].join("");
|
||||
|
@ -70,6 +72,7 @@ impl GameScene {
|
|||
tex_background_name,
|
||||
tex_caret_name,
|
||||
tex_face_name,
|
||||
tex_fade_name,
|
||||
tex_hud_name,
|
||||
tex_npcsym_name,
|
||||
tex_tileset_name,
|
||||
|
@ -210,6 +213,91 @@ impl GameScene {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_fade(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
match state.fade_state {
|
||||
FadeState::Visible => { return Ok(()); }
|
||||
FadeState::Hidden => {
|
||||
graphics::clear(ctx, Color::from_rgb(0, 0, 32));
|
||||
}
|
||||
FadeState::FadeIn(tick, direction) | FadeState::FadeOut(tick, direction) => {
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_fade_name)?;
|
||||
let mut rect = Rect::<usize>::new(0, 0, 16, 16);
|
||||
|
||||
match direction {
|
||||
FadeDirection::Left | FadeDirection::Right => {
|
||||
let mut frame = tick;
|
||||
|
||||
for x in (0..(state.canvas_size.0 as isize + 16)).step_by(16) {
|
||||
if frame > 15 { frame = 15; } else { frame += 1; }
|
||||
|
||||
if frame >= 0 {
|
||||
rect.left = frame as usize * 16;
|
||||
rect.right = rect.left + 16;
|
||||
|
||||
for y in (0..(state.canvas_size.1 as isize + 16)).step_by(16) {
|
||||
if direction == FadeDirection::Left {
|
||||
batch.add_rect(state.canvas_size.0 - x as f32, y as f32, &rect);
|
||||
} else {
|
||||
batch.add_rect(x as f32, y as f32, &rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FadeDirection::Up | FadeDirection::Down => {
|
||||
let mut frame = tick;
|
||||
|
||||
for y in (0..(state.canvas_size.1 as isize + 16)).step_by(16) {
|
||||
if frame > 15 { frame = 15; } else { frame += 1; }
|
||||
|
||||
if frame >= 0 {
|
||||
rect.left = frame as usize * 16;
|
||||
rect.right = rect.left + 16;
|
||||
|
||||
for x in (0..(state.canvas_size.0 as isize + 16)).step_by(16) {
|
||||
if direction == FadeDirection::Down {
|
||||
batch.add_rect(x as f32, y as f32, &rect);
|
||||
} else {
|
||||
batch.add_rect(x as f32, state.canvas_size.1 - y as f32, &rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FadeDirection::Center => {
|
||||
let center_x = (state.canvas_size.0 / 2.0 - 8.0) as isize;
|
||||
let center_y = (state.canvas_size.1 / 2.0 - 8.0) as isize;
|
||||
let mut start_frame = tick;
|
||||
|
||||
for x in (0..(center_x + 16)).step_by(16) {
|
||||
let mut frame = start_frame;
|
||||
|
||||
for y in (0..(center_y + 16)).step_by(16) {
|
||||
if frame > 15 { frame = 15; } else { frame += 1; }
|
||||
|
||||
if frame >= 0 {
|
||||
rect.left = frame as usize * 16;
|
||||
rect.right = rect.left + 16;
|
||||
|
||||
batch.add_rect((center_x - x) as f32, (center_y + y) as f32, &rect);
|
||||
batch.add_rect((center_x - x) as f32, (center_y - y) as f32, &rect);
|
||||
batch.add_rect((center_x + x) as f32, (center_y + y) as f32, &rect);
|
||||
batch.add_rect((center_x + x) as f32, (center_y - y) as f32, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
start_frame += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
batch.draw(ctx)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_black_bars(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -349,6 +437,24 @@ impl Scene for GameScene {
|
|||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
state.update_key_trigger();
|
||||
|
||||
if self.tick % 2 == 0 {
|
||||
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;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if state.control_flags.flag_x01() {
|
||||
self.player.tick(state, ctx)?;
|
||||
|
||||
|
@ -393,6 +499,7 @@ impl Scene for GameScene {
|
|||
self.draw_hud(state, ctx)?;
|
||||
self.draw_number(state.canvas_size.0 - 8.0, 8.0, timer::fps(ctx) as usize, Alignment::Right, state, ctx)?;
|
||||
|
||||
self.draw_fade(state, ctx)?;
|
||||
self.draw_text_boxes(state, ctx)?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::scene::Scene;
|
|||
use crate::SharedGameState;
|
||||
use crate::stage::StageData;
|
||||
use crate::text_script::{TextScript, TextScriptExecutionState};
|
||||
use crate::common::FadeState;
|
||||
|
||||
pub struct LoadingScene {
|
||||
tick: usize,
|
||||
|
@ -29,6 +30,7 @@ impl Scene for LoadingScene {
|
|||
let mut next_scene = GameScene::new(state, ctx, 13)?;
|
||||
next_scene.player.x = 10 * 16 * 0x200;
|
||||
next_scene.player.y = 8 * 16 * 0x200;
|
||||
state.fade_state = FadeState::Hidden;
|
||||
state.textscript_vm.state = TextScriptExecutionState::Running(200, 0);
|
||||
|
||||
state.next_scene = Some(Box::new(next_scene));
|
||||
|
|
|
@ -13,6 +13,7 @@ use num_traits::FromPrimitive;
|
|||
|
||||
use crate::{SharedGameState, str};
|
||||
use crate::bitfield;
|
||||
use crate::common::{FadeState, FadeDirection};
|
||||
use crate::ggez::{Context, GameResult};
|
||||
use crate::ggez::GameError::ParseError;
|
||||
use crate::scene::game_scene::GameScene;
|
||||
|
@ -187,12 +188,14 @@ pub enum TextScriptLine {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum TextScriptExecutionState {
|
||||
Ended,
|
||||
Running(u16, u32),
|
||||
Msg(u16, u32, u32, u8),
|
||||
WaitTicks(u16, u32, u32),
|
||||
WaitInput(u16, u32),
|
||||
WaitFade(u16, u32),
|
||||
}
|
||||
|
||||
pub struct TextScriptVM {
|
||||
|
@ -368,7 +371,6 @@ impl TextScriptVM {
|
|||
cursor.seek(SeekFrom::Start(ip as u64))?;
|
||||
|
||||
let (consumed, chr) = read_cur_wtf8(&mut cursor, remaining);
|
||||
println!("char: {} {} {}", chr, remaining, consumed);
|
||||
|
||||
match chr {
|
||||
'\n' if state.textscript_vm.current_line == TextScriptLine::Line1 => {
|
||||
|
@ -419,6 +421,12 @@ impl TextScriptVM {
|
|||
}
|
||||
break;
|
||||
}
|
||||
TextScriptExecutionState::WaitFade(event, ip) => {
|
||||
if state.fade_state == FadeState::Hidden || state.fade_state == FadeState::Visible {
|
||||
state.textscript_vm.state = TextScriptExecutionState::Running(event, ip);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -552,6 +560,14 @@ impl TextScriptVM {
|
|||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::CLO => {
|
||||
state.textscript_vm.flags.set_render(false);
|
||||
state.textscript_vm.flags.set_background_visible(false);
|
||||
state.textscript_vm.flags.set_flag_x10(false);
|
||||
state.textscript_vm.flags.set_position_top(false);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::TRA => {
|
||||
let map_id = read_cur_varint(&mut cursor)? as usize;
|
||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
|
@ -570,27 +586,43 @@ impl TextScriptVM {
|
|||
state.next_scene = Some(Box::new(new_scene));
|
||||
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
exec_state = TextScriptExecutionState::WaitFade(event, cursor.position() as u32);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
exec_state = TextScriptExecutionState::WaitFade(event, cursor.position() as u32);
|
||||
}
|
||||
// unimplemented opcodes
|
||||
// Zero operands
|
||||
OpCode::AEp | OpCode::CAT | OpCode::CIL | OpCode::CLO | OpCode::CPS |
|
||||
OpCode::AEp | OpCode::CAT | OpCode::CIL | OpCode::CPS |
|
||||
OpCode::CRE | OpCode::CSS | OpCode::ESC | OpCode::FLA | OpCode::FMU |
|
||||
OpCode::HMC | OpCode::INI | OpCode::LDP | OpCode::MLP |
|
||||
OpCode::MNA | OpCode::MS2 | OpCode::MS3 |
|
||||
OpCode::RMU | OpCode::SAT | OpCode::SLP | OpCode::SMC | OpCode::SPS |
|
||||
OpCode::STC | OpCode::SVP | OpCode::TUR | OpCode::WAS | OpCode::ZAM => {
|
||||
println!("unimplemented opcode: {:?}", op);
|
||||
log::warn!("unimplemented opcode: {:?}", op);
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// One operand codes
|
||||
OpCode::BOA | OpCode::BSL | OpCode::FOB | OpCode::FOM | OpCode::QUA | OpCode::UNI |
|
||||
OpCode::MYB | OpCode::MYD | OpCode::FAI | OpCode::FAO |
|
||||
OpCode::MYB | OpCode::MYD |
|
||||
OpCode::GIT | OpCode::NUM | OpCode::DNA | OpCode::DNP |
|
||||
OpCode::MPp | OpCode::SKm | OpCode::SKp | OpCode::EQp | OpCode::EQm |
|
||||
OpCode::ITp | OpCode::ITm | OpCode::AMm | OpCode::UNJ | OpCode::MPJ | OpCode::YNJ |
|
||||
OpCode::XX1 | OpCode::SIL | OpCode::LIp | OpCode::SOU | OpCode::CMU |
|
||||
OpCode::SSS | OpCode::ACH => {
|
||||
let par_a = read_cur_varint(&mut cursor)?;
|
||||
println!("unimplemented opcode: {:?} {}", op, par_a);
|
||||
log::warn!("unimplemented opcode: {:?} {}", op, par_a);
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// Two operand codes
|
||||
|
@ -598,7 +630,7 @@ impl TextScriptVM {
|
|||
OpCode::ITJ | OpCode::SKJ | OpCode::AMJ | OpCode::SMP | OpCode::PSp => {
|
||||
let par_a = read_cur_varint(&mut cursor)?;
|
||||
let par_b = read_cur_varint(&mut cursor)?;
|
||||
println!("unimplemented opcode: {:?} {} {}", op, par_a, par_b);
|
||||
log::warn!("unimplemented opcode: {:?} {} {}", op, par_a, par_b);
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// Three operand codes
|
||||
|
@ -606,7 +638,7 @@ impl TextScriptVM {
|
|||
let par_a = read_cur_varint(&mut cursor)?;
|
||||
let par_b = read_cur_varint(&mut cursor)?;
|
||||
let par_c = read_cur_varint(&mut cursor)?;
|
||||
println!("unimplemented opcode: {:?} {} {} {}", op, par_a, par_b, par_c);
|
||||
log::warn!("unimplemented opcode: {:?} {} {} {}", op, par_a, par_b, par_c);
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// Four operand codes
|
||||
|
@ -615,7 +647,7 @@ impl TextScriptVM {
|
|||
let par_b = read_cur_varint(&mut cursor)?;
|
||||
let par_c = read_cur_varint(&mut cursor)?;
|
||||
let par_d = read_cur_varint(&mut cursor)?;
|
||||
println!("unimplemented opcode: {:?} {} {} {} {}", op, par_a, par_b, par_c, par_d);
|
||||
log::warn!("unimplemented opcode: {:?} {} {} {} {}", op, par_a, par_b, par_c, par_d);
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue