1
0
Fork 0
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:
Alula 2020-08-28 03:41:14 +02:00
parent c703203506
commit 1758aa5740
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
5 changed files with 194 additions and 16 deletions

View file

@ -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 {

View file

@ -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),

View file

@ -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(())

View file

@ -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));

View file

@ -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);
}
}