mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-10-31 19:44:20 +00:00
editor shit
This commit is contained in:
parent
e2afafdfa3
commit
ef84379b62
|
@ -6,7 +6,6 @@ authors = ["Alula"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
#crate-type = ["lib", "cdylib"]
|
|
||||||
crate-type = ["lib"]
|
crate-type = ["lib"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@ -57,6 +56,7 @@ case_insensitive_hashmap = "1.0.0"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
cpal = { git = "https://github.com/doukutsu-rs/cpal.git", rev = "4218ff23242834d36bcdcc0c2e3883985c15b5e0" }
|
cpal = { git = "https://github.com/doukutsu-rs/cpal.git", rev = "4218ff23242834d36bcdcc0c2e3883985c15b5e0" }
|
||||||
directories = "3"
|
directories = "3"
|
||||||
|
downcast = "0.11"
|
||||||
funty = "=1.1.0" # https://github.com/bitvecto-rs/bitvec/issues/105
|
funty = "=1.1.0" # https://github.com/bitvecto-rs/bitvec/issues/105
|
||||||
glutin = { git = "https://github.com/doukutsu-rs/glutin.git", rev = "8dd457b9adb7dbac7ade337246b6356c784272d9", optional = true, default_features = false, features = ["x11"] }
|
glutin = { git = "https://github.com/doukutsu-rs/glutin.git", rev = "8dd457b9adb7dbac7ade337246b6356c784272d9", optional = true, default_features = false, features = ["x11"] }
|
||||||
imgui = "0.8.0"
|
imgui = "0.8.0"
|
||||||
|
@ -76,7 +76,7 @@ serde = { version = "1", features = ["derive"] }
|
||||||
serde_derive = "1"
|
serde_derive = "1"
|
||||||
serde_cbor = { version = "0.11.2", optional = true }
|
serde_cbor = { version = "0.11.2", optional = true }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
simple_logger = { version = "1.13" }
|
simple_logger = { version = "1.16", features = ["colors", "threads"] }
|
||||||
strum = "0.20"
|
strum = "0.20"
|
||||||
strum_macros = "0.20"
|
strum_macros = "0.20"
|
||||||
tokio = { version = "1.12.0", features = ["net"], optional = true }
|
tokio = { version = "1.12.0", features = ["net"], optional = true }
|
||||||
|
|
|
@ -48,12 +48,13 @@ impl Background {
|
||||||
BackgroundType::TiledStatic => {
|
BackgroundType::TiledStatic => {
|
||||||
graphics::clear(ctx, stage.data.background_color);
|
graphics::clear(ctx, stage.data.background_color);
|
||||||
|
|
||||||
let count_x = state.canvas_size.0 as usize / batch.width() + 1;
|
let (bg_width, bg_height) = (batch.width() as i32, batch.height() as i32);
|
||||||
let count_y = state.canvas_size.1 as usize / batch.height() + 1;
|
let count_x = state.canvas_size.0 as i32 / bg_width + 1;
|
||||||
|
let count_y = state.canvas_size.1 as i32 / bg_height + 1;
|
||||||
|
|
||||||
for y in 0..count_y {
|
for y in -1..count_y {
|
||||||
for x in 0..count_x {
|
for x in -1..count_x {
|
||||||
batch.add((x * batch.width()) as f32, (y * batch.height()) as f32);
|
batch.add((x * bg_width) as f32, (y * bg_height) as f32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,12 +70,13 @@ impl Background {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let count_x = state.canvas_size.0 as usize / batch.width() + 2;
|
let (bg_width, bg_height) = (batch.width() as i32, batch.height() as i32);
|
||||||
let count_y = state.canvas_size.1 as usize / batch.height() + 2;
|
let count_x = state.canvas_size.0 as i32 / bg_width + 2;
|
||||||
|
let count_y = state.canvas_size.1 as i32 / bg_height + 2;
|
||||||
|
|
||||||
for y in 0..count_y {
|
for y in -1..count_y {
|
||||||
for x in 0..count_x {
|
for x in -1..count_x {
|
||||||
batch.add((x * batch.width()) as f32 - off_x, (y * batch.height()) as f32 - off_y);
|
batch.add((x * bg_width) as f32 - off_x, (y * bg_height) as f32 - off_y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
285
src/editor/mod.rs
Normal file
285
src/editor/mod.rs
Normal file
|
@ -0,0 +1,285 @@
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use imgui::{Image, MouseButton, Window, WindowFlags};
|
||||||
|
|
||||||
|
use crate::common::{Color, Rect};
|
||||||
|
use crate::components::background::Background;
|
||||||
|
use crate::components::tilemap::{TileLayer, Tilemap};
|
||||||
|
use crate::frame::Frame;
|
||||||
|
use crate::stage::{Stage, StageTexturePaths};
|
||||||
|
use crate::{graphics, Context, GameResult, SharedGameState, I_MAG};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum CurrentTool {
|
||||||
|
Move,
|
||||||
|
Brush,
|
||||||
|
Fill,
|
||||||
|
Rectangle,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EditorInstance {
|
||||||
|
pub stage: Stage,
|
||||||
|
pub stage_id: usize,
|
||||||
|
pub frame: Frame,
|
||||||
|
pub background: Background,
|
||||||
|
pub stage_textures: Rc<RefCell<StageTexturePaths>>,
|
||||||
|
pub tilemap: Tilemap,
|
||||||
|
pub zoom: f32,
|
||||||
|
pub current_tile: u8,
|
||||||
|
pub mouse_pos: (f32, f32),
|
||||||
|
pub want_capture_mouse: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EditorInstance {
|
||||||
|
pub fn new(stage_id: usize, stage: Stage) -> EditorInstance {
|
||||||
|
let stage_textures = {
|
||||||
|
let mut textures = StageTexturePaths::new();
|
||||||
|
textures.update(&stage);
|
||||||
|
Rc::new(RefCell::new(textures))
|
||||||
|
};
|
||||||
|
let mut frame = Frame::new();
|
||||||
|
frame.x = -16 * 0x200;
|
||||||
|
frame.y = -48 * 0x200;
|
||||||
|
|
||||||
|
EditorInstance {
|
||||||
|
stage,
|
||||||
|
stage_id,
|
||||||
|
frame,
|
||||||
|
background: Background::new(),
|
||||||
|
stage_textures,
|
||||||
|
tilemap: Tilemap::new(),
|
||||||
|
zoom: 2.0,
|
||||||
|
current_tile: 0,
|
||||||
|
mouse_pos: (0.0, 0.0),
|
||||||
|
want_capture_mouse: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process(&mut self, state: &mut SharedGameState, ctx: &mut Context, ui: &mut imgui::Ui, tool: CurrentTool) {
|
||||||
|
self.frame.prev_x = self.frame.x;
|
||||||
|
self.frame.prev_y = self.frame.y;
|
||||||
|
self.mouse_pos = (ui.io().mouse_pos[0], ui.io().mouse_pos[1]);
|
||||||
|
self.want_capture_mouse = ui.io().want_capture_mouse;
|
||||||
|
|
||||||
|
let mut drag = false;
|
||||||
|
|
||||||
|
match tool {
|
||||||
|
CurrentTool::Move => {
|
||||||
|
if ui.io().want_capture_mouse {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
drag |= ui.is_mouse_down(MouseButton::Left) || ui.is_mouse_down(MouseButton::Right);
|
||||||
|
}
|
||||||
|
CurrentTool::Brush => {
|
||||||
|
self.palette_window(state, ctx, ui);
|
||||||
|
|
||||||
|
if ui.io().want_capture_mouse {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
drag |= ui.is_mouse_down(MouseButton::Right);
|
||||||
|
|
||||||
|
if !drag && ui.is_mouse_down(MouseButton::Left) {
|
||||||
|
let tile_size = self.stage.map.tile_size.as_int();
|
||||||
|
let halft = tile_size / 2;
|
||||||
|
let stage_mouse_x = (self.frame.x / 0x200) + halft + (self.mouse_pos.0 / self.zoom) as i32;
|
||||||
|
let stage_mouse_y = (self.frame.y / 0x200) + halft + (self.mouse_pos.1 / self.zoom) as i32;
|
||||||
|
let tile_x = stage_mouse_x / tile_size;
|
||||||
|
let tile_y = stage_mouse_y / tile_size;
|
||||||
|
|
||||||
|
if tile_x >= 0
|
||||||
|
&& tile_y >= 0
|
||||||
|
&& tile_x < self.stage.map.width as i32
|
||||||
|
&& tile_y < self.stage.map.height as i32
|
||||||
|
{
|
||||||
|
self.stage.change_tile(tile_x as usize, tile_y as usize, self.current_tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CurrentTool::Fill => {
|
||||||
|
self.palette_window(state, ctx, ui);
|
||||||
|
drag |= ui.is_mouse_down(MouseButton::Right);
|
||||||
|
}
|
||||||
|
CurrentTool::Rectangle => {
|
||||||
|
self.palette_window(state, ctx, ui);
|
||||||
|
drag |= ui.is_mouse_down(MouseButton::Right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if drag {
|
||||||
|
self.frame.x -= (512.0 * ui.io().mouse_delta[0] as f32 / self.zoom) as i32;
|
||||||
|
self.frame.y -= (512.0 * ui.io().mouse_delta[1] as f32 / self.zoom) as i32;
|
||||||
|
self.frame.prev_x = self.frame.x;
|
||||||
|
self.frame.prev_y = self.frame.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tile_cursor(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
|
if self.want_capture_mouse {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let tile_size = self.stage.map.tile_size.as_int();
|
||||||
|
let halft = tile_size / 2;
|
||||||
|
let stage_mouse_x = (self.frame.x / 0x200) + halft + (self.mouse_pos.0 / self.zoom) as i32;
|
||||||
|
let stage_mouse_y = (self.frame.y / 0x200) + halft + (self.mouse_pos.1 / self.zoom) as i32;
|
||||||
|
let tile_x = stage_mouse_x / tile_size;
|
||||||
|
let tile_y = stage_mouse_y / tile_size;
|
||||||
|
let frame_x = self.frame.x as f32 / 512.0;
|
||||||
|
let frame_y = self.frame.y as f32 / 512.0;
|
||||||
|
|
||||||
|
if tile_x < 0 || tile_y < 0 || tile_x >= self.stage.map.width as i32 || tile_y >= self.stage.map.height as i32 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = &self.stage_textures.deref().borrow().tileset_fg;
|
||||||
|
|
||||||
|
if let Ok(batch) = state.texture_set.get_or_load_batch(ctx, &state.constants, name) {
|
||||||
|
let tile_size16 = tile_size as u16;
|
||||||
|
let rect = Rect::new_size(
|
||||||
|
(self.current_tile as u16 % 16) * tile_size16,
|
||||||
|
(self.current_tile as u16 / 16) * tile_size16,
|
||||||
|
tile_size16,
|
||||||
|
tile_size16,
|
||||||
|
);
|
||||||
|
|
||||||
|
batch.add_rect_tinted(
|
||||||
|
(tile_x * tile_size - halft) as f32 - frame_x,
|
||||||
|
(tile_y * tile_size - halft) as f32 - frame_y,
|
||||||
|
(255, 255, 255, 192),
|
||||||
|
&rect,
|
||||||
|
);
|
||||||
|
|
||||||
|
batch.draw(ctx)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn palette_window(&mut self, state: &mut SharedGameState, ctx: &mut Context, ui: &imgui::Ui) {
|
||||||
|
Window::new("Palette")
|
||||||
|
.size([260.0, 260.0], imgui::Condition::Always)
|
||||||
|
.position(ui.io().display_size, imgui::Condition::FirstUseEver)
|
||||||
|
.position_pivot([1.0, 1.0])
|
||||||
|
.resizable(false)
|
||||||
|
.build(ui, || {
|
||||||
|
let name = &self.stage_textures.deref().borrow().tileset_fg;
|
||||||
|
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, name);
|
||||||
|
|
||||||
|
let pos = ui.cursor_screen_pos();
|
||||||
|
let tile_size = self.stage.map.tile_size.as_float();
|
||||||
|
|
||||||
|
if let Ok(batch) = batch {
|
||||||
|
let (scale_x, scale_y) = batch.scale();
|
||||||
|
if let Some(tex) = batch.get_texture() {
|
||||||
|
let (width, height) = tex.dimensions();
|
||||||
|
let (width, height) = (width as f32 / scale_x, height as f32 / scale_y);
|
||||||
|
|
||||||
|
if let Ok(tex_id) = graphics::imgui_texture_id(ctx, tex) {
|
||||||
|
Image::new(tex_id, [width, height]).build(ui);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.set_cursor_screen_pos(pos);
|
||||||
|
ui.invisible_button("##tiles", [width, height]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let draw_list = ui.get_window_draw_list();
|
||||||
|
let cur_pos1 = [
|
||||||
|
pos[0].floor() + tile_size * (self.current_tile % 16) as f32,
|
||||||
|
pos[1].floor() + tile_size * (self.current_tile / 16) as f32,
|
||||||
|
];
|
||||||
|
let cur_pos2 = [cur_pos1[0] + tile_size, cur_pos1[1] + tile_size];
|
||||||
|
draw_list.add_rect(cur_pos1, cur_pos2, [1.0, 0.0, 0.0, 1.0]).thickness(2.0).build();
|
||||||
|
|
||||||
|
if ui.is_mouse_down(MouseButton::Left) {
|
||||||
|
let mouse_pos = ui.io().mouse_pos;
|
||||||
|
let x = (mouse_pos[0] - pos[0]) / tile_size;
|
||||||
|
let y = (mouse_pos[1] - pos[1]) / tile_size;
|
||||||
|
|
||||||
|
if x >= 0.0 && x < 16.0 && y >= 0.0 && y < 16.0 {
|
||||||
|
self.current_tile = (y as u8 * 16 + x as u8) as u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, tool: CurrentTool) -> GameResult {
|
||||||
|
let old_scale = state.scale;
|
||||||
|
set_scale(state, self.zoom);
|
||||||
|
|
||||||
|
let paths = self.stage_textures.deref().borrow();
|
||||||
|
self.background.draw(state, ctx, &self.frame, &*paths, &self.stage)?;
|
||||||
|
|
||||||
|
self.tilemap.draw(state, ctx, &self.frame, TileLayer::Background, &*paths, &self.stage)?;
|
||||||
|
self.tilemap.draw(state, ctx, &self.frame, TileLayer::Middleground, &*paths, &self.stage)?;
|
||||||
|
self.tilemap.draw(state, ctx, &self.frame, TileLayer::Foreground, &*paths, &self.stage)?;
|
||||||
|
self.tilemap.draw(state, ctx, &self.frame, TileLayer::Snack, &*paths, &self.stage)?;
|
||||||
|
|
||||||
|
self.draw_black_bars(state, ctx)?;
|
||||||
|
|
||||||
|
match tool {
|
||||||
|
CurrentTool::Move => (),
|
||||||
|
CurrentTool::Brush | CurrentTool::Fill | CurrentTool::Rectangle => {
|
||||||
|
self.tile_cursor(state, ctx)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_scale(state, old_scale);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_black_bars(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
|
let color = Color::from_rgba(0, 0, 0, 128);
|
||||||
|
let (x, y) = self.frame.xy_interpolated(state.frame_time);
|
||||||
|
let (x, y) = (x * state.scale, y * state.scale);
|
||||||
|
let canvas_w_scaled = state.canvas_size.0 as f32 * state.scale;
|
||||||
|
let canvas_h_scaled = state.canvas_size.1 as f32 * state.scale;
|
||||||
|
let level_width = (self.stage.map.width as f32 - 1.0) * self.stage.map.tile_size.as_float();
|
||||||
|
let level_height = (self.stage.map.height as f32 - 1.0) * self.stage.map.tile_size.as_float();
|
||||||
|
let left_side = -x;
|
||||||
|
let right_side = -x + level_width * state.scale;
|
||||||
|
let upper_side = -y;
|
||||||
|
let lower_side = -y + level_height * state.scale;
|
||||||
|
|
||||||
|
if left_side > 0.0 {
|
||||||
|
let rect = Rect::new(0, upper_side as isize, left_side as isize, lower_side as isize);
|
||||||
|
graphics::draw_rect(ctx, rect, color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if right_side < canvas_w_scaled {
|
||||||
|
let rect = Rect::new(
|
||||||
|
right_side as isize,
|
||||||
|
upper_side as isize,
|
||||||
|
(state.canvas_size.0 * state.scale) as isize,
|
||||||
|
lower_side as isize,
|
||||||
|
);
|
||||||
|
graphics::draw_rect(ctx, rect, color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if upper_side > 0.0 {
|
||||||
|
let rect = Rect::new(0, 0, canvas_w_scaled as isize, upper_side as isize);
|
||||||
|
graphics::draw_rect(ctx, rect, color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if lower_side < canvas_h_scaled {
|
||||||
|
let rect = Rect::new(0, lower_side as isize, canvas_w_scaled as isize, canvas_h_scaled as isize);
|
||||||
|
graphics::draw_rect(ctx, rect, color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_scale(state: &mut SharedGameState, scale: f32) {
|
||||||
|
state.scale = scale;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
I_MAG = state.scale;
|
||||||
|
state.canvas_size = (state.screen_size.0 / state.scale, state.screen_size.1 / state.scale);
|
||||||
|
}
|
||||||
|
}
|
13
src/frame.rs
13
src/frame.rs
|
@ -23,6 +23,19 @@ pub struct Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
|
pub fn new() -> Frame {
|
||||||
|
Frame {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
prev_x: 0,
|
||||||
|
prev_y: 0,
|
||||||
|
update_target: UpdateTarget::Player,
|
||||||
|
target_x: 0,
|
||||||
|
target_y: 0,
|
||||||
|
wait: 16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn xy_interpolated(&self, frame_time: f64) -> (f32, f32) {
|
pub fn xy_interpolated(&self, frame_time: f64) -> (f32, f32) {
|
||||||
if self.prev_x == self.x && self.prev_y == self.y {
|
if self.prev_x == self.x && self.prev_y == self.y {
|
||||||
return (fix9_scale(self.x), fix9_scale(self.y));
|
return (fix9_scale(self.x), fix9_scale(self.y));
|
||||||
|
|
49
src/lib.rs
49
src/lib.rs
|
@ -32,15 +32,17 @@ mod builtin_fs;
|
||||||
mod caret;
|
mod caret;
|
||||||
mod common;
|
mod common;
|
||||||
mod components;
|
mod components;
|
||||||
|
#[cfg(feature = "editor")]
|
||||||
|
mod editor;
|
||||||
mod encoding;
|
mod encoding;
|
||||||
mod engine_constants;
|
mod engine_constants;
|
||||||
mod entity;
|
mod entity;
|
||||||
mod frame;
|
mod frame;
|
||||||
mod framework;
|
mod framework;
|
||||||
mod input;
|
|
||||||
mod inventory;
|
|
||||||
#[cfg(feature = "hooks")]
|
#[cfg(feature = "hooks")]
|
||||||
mod hooks;
|
mod hooks;
|
||||||
|
mod input;
|
||||||
|
mod inventory;
|
||||||
mod live_debugger;
|
mod live_debugger;
|
||||||
mod macros;
|
mod macros;
|
||||||
mod map;
|
mod map;
|
||||||
|
@ -65,6 +67,7 @@ mod weapon;
|
||||||
|
|
||||||
pub struct LaunchOptions {
|
pub struct LaunchOptions {
|
||||||
pub server_mode: bool,
|
pub server_mode: bool,
|
||||||
|
pub editor: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -100,11 +103,12 @@ impl Game {
|
||||||
if let Some(scene) = self.scene.as_mut() {
|
if let Some(scene) = self.scene.as_mut() {
|
||||||
let state_ref = unsafe { &mut *self.state.get() };
|
let state_ref = unsafe { &mut *self.state.get() };
|
||||||
|
|
||||||
let speed = if state_ref.textscript_vm.mode == ScriptMode::Map && state_ref.textscript_vm.flags.cutscene_skip() {
|
let speed =
|
||||||
4.0 * state_ref.settings.speed
|
if state_ref.textscript_vm.mode == ScriptMode::Map && state_ref.textscript_vm.flags.cutscene_skip() {
|
||||||
} else {
|
4.0 * state_ref.settings.speed
|
||||||
1.0 * state_ref.settings.speed
|
} else {
|
||||||
};
|
1.0 * state_ref.settings.speed
|
||||||
|
};
|
||||||
|
|
||||||
match state_ref.settings.timing_mode {
|
match state_ref.settings.timing_mode {
|
||||||
TimingMode::_50Hz | TimingMode::_60Hz => {
|
TimingMode::_50Hz | TimingMode::_60Hz => {
|
||||||
|
@ -114,8 +118,7 @@ impl Game {
|
||||||
if (speed - 1.0).abs() < 0.01 {
|
if (speed - 1.0).abs() < 0.01 {
|
||||||
self.next_tick += state_ref.settings.timing_mode.get_delta() as u128;
|
self.next_tick += state_ref.settings.timing_mode.get_delta() as u128;
|
||||||
} else {
|
} else {
|
||||||
self.next_tick +=
|
self.next_tick += (state_ref.settings.timing_mode.get_delta() as f64 / speed) as u128;
|
||||||
(state_ref.settings.timing_mode.get_delta() as f64 / speed) as u128;
|
|
||||||
}
|
}
|
||||||
self.loops += 1;
|
self.loops += 1;
|
||||||
}
|
}
|
||||||
|
@ -123,8 +126,8 @@ impl Game {
|
||||||
if self.loops == 10 {
|
if self.loops == 10 {
|
||||||
log::warn!("Frame skip is way too high, a long system lag occurred?");
|
log::warn!("Frame skip is way too high, a long system lag occurred?");
|
||||||
self.last_tick = self.start_time.elapsed().as_nanos();
|
self.last_tick = self.start_time.elapsed().as_nanos();
|
||||||
self.next_tick = self.last_tick
|
self.next_tick =
|
||||||
+ (state_ref.settings.timing_mode.get_delta() as f64 / speed) as u128;
|
self.last_tick + (state_ref.settings.timing_mode.get_delta() as f64 / speed) as u128;
|
||||||
self.loops = 0;
|
self.loops = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +201,11 @@ impl Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(options: LaunchOptions) -> GameResult {
|
pub fn init(options: LaunchOptions) -> GameResult {
|
||||||
let _ = simple_logger::init_with_level(log::Level::Info);
|
let _ = simple_logger::SimpleLogger::new()
|
||||||
|
.without_timestamps()
|
||||||
|
.with_colors(true)
|
||||||
|
.with_level(log::Level::Info.to_level_filter())
|
||||||
|
.init();
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
let resource_dir = if let Ok(data_dir) = env::var("CAVESTORY_DATA_DIR") {
|
let resource_dir = if let Ok(data_dir) = env::var("CAVESTORY_DATA_DIR") {
|
||||||
|
@ -264,17 +271,17 @@ pub fn init(options: LaunchOptions) -> GameResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
{
|
{
|
||||||
if let Ok(_) = crate::framework::filesystem::open(&mut context, "/.drs_localstorage") {
|
if let Ok(_) = crate::framework::filesystem::open(&mut context, "/.drs_localstorage") {
|
||||||
let mut user_dir = resource_dir.clone();
|
let mut user_dir = resource_dir.clone();
|
||||||
user_dir.push("_drs_profile");
|
user_dir.push("_drs_profile");
|
||||||
|
|
||||||
let _ = std::fs::create_dir_all(&user_dir);
|
let _ = std::fs::create_dir_all(&user_dir);
|
||||||
mount_user_vfs(&mut context, Box::new(PhysicalFS::new(&user_dir, false)));
|
mount_user_vfs(&mut context, Box::new(PhysicalFS::new(&user_dir, false)));
|
||||||
} else {
|
} else {
|
||||||
mount_user_vfs(&mut context, Box::new(PhysicalFS::new(project_dirs.data_local_dir(), false)));
|
mount_user_vfs(&mut context, Box::new(PhysicalFS::new(project_dirs.data_local_dir(), false)));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if options.server_mode {
|
if options.server_mode {
|
||||||
log::info!("Running in server mode...");
|
log::info!("Running in server mode...");
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -5,13 +5,23 @@ use std::process::exit;
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = std::env::args();
|
let args = std::env::args();
|
||||||
let mut options = doukutsu_rs::LaunchOptions {
|
let mut options = doukutsu_rs::LaunchOptions {
|
||||||
server_mode: false
|
server_mode: false,
|
||||||
|
editor: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg == "--server-mode" {
|
if arg == "--server-mode" {
|
||||||
options.server_mode = true;
|
options.server_mode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if arg == "--editor" {
|
||||||
|
options.editor = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.server_mode && options.editor {
|
||||||
|
eprintln!("Cannot run in server mode and editor mode at the same time.");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = doukutsu_rs::init(options);
|
let result = doukutsu_rs::init(options);
|
||||||
|
|
|
@ -17,6 +17,7 @@ use crate::stage::{PxPackScroll, PxPackStageData, StageData};
|
||||||
static SUPPORTED_PXM_VERSIONS: [u8; 1] = [0x10];
|
static SUPPORTED_PXM_VERSIONS: [u8; 1] = [0x10];
|
||||||
static SUPPORTED_PXE_VERSIONS: [u8; 2] = [0, 0x10];
|
static SUPPORTED_PXE_VERSIONS: [u8; 2] = [0, 0x10];
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
pub width: u16,
|
pub width: u16,
|
||||||
pub height: u16,
|
pub height: u16,
|
||||||
|
|
|
@ -1,19 +1,134 @@
|
||||||
use imgui::MenuItem;
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use downcast::Downcast;
|
||||||
|
use imgui::{Condition, MenuItem, TabItem, TabItemFlags, Window};
|
||||||
|
|
||||||
|
use crate::editor::{CurrentTool, EditorInstance};
|
||||||
|
use crate::framework::keyboard;
|
||||||
|
use crate::framework::keyboard::ScanCode;
|
||||||
use crate::framework::ui::Components;
|
use crate::framework::ui::Components;
|
||||||
|
use crate::scene::game_scene::GameScene;
|
||||||
use crate::scene::title_scene::TitleScene;
|
use crate::scene::title_scene::TitleScene;
|
||||||
|
use crate::stage::Stage;
|
||||||
use crate::{Context, GameResult, Scene, SharedGameState};
|
use crate::{Context, GameResult, Scene, SharedGameState};
|
||||||
|
|
||||||
pub struct EditorScene {}
|
struct ErrorList {
|
||||||
|
errors: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorList {
|
||||||
|
fn new() -> ErrorList {
|
||||||
|
Self { errors: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_or_push_error(&mut self, func: impl FnOnce() -> GameResult<()>) {
|
||||||
|
if let Err(err) = func() {
|
||||||
|
self.errors.push(err.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn catch(error_list: Rc<RefCell<ErrorList>>, func: impl FnOnce() -> GameResult<()>) {
|
||||||
|
error_list.borrow_mut().try_or_push_error(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EditorScene {
|
||||||
|
stage_list: StageListWindow,
|
||||||
|
error_list: Rc<RefCell<ErrorList>>,
|
||||||
|
instances: Vec<EditorInstance>,
|
||||||
|
subscene: Option<Box<GameScene>>,
|
||||||
|
current_tool: CurrentTool,
|
||||||
|
selected_instance: usize,
|
||||||
|
switch_tab: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl EditorScene {
|
impl EditorScene {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
EditorScene {}
|
EditorScene {
|
||||||
|
stage_list: StageListWindow::new(),
|
||||||
|
error_list: Rc::new(RefCell::new(ErrorList::new())),
|
||||||
|
instances: Vec::new(),
|
||||||
|
subscene: None,
|
||||||
|
current_tool: CurrentTool::Move,
|
||||||
|
selected_instance: 0,
|
||||||
|
switch_tab: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exit_editor(&mut self, state: &mut SharedGameState) {
|
fn exit_editor(&mut self, state: &mut SharedGameState) {
|
||||||
state.next_scene = Some(Box::new(TitleScene::new()));
|
state.next_scene = Some(Box::new(TitleScene::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn open_stage(&mut self, state: &mut SharedGameState, ctx: &mut Context, stage_id: usize) {
|
||||||
|
catch(self.error_list.clone(), || {
|
||||||
|
for (idx, instance) in self.instances.iter().enumerate() {
|
||||||
|
if instance.stage_id == stage_id {
|
||||||
|
self.selected_instance = idx;
|
||||||
|
self.switch_tab = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(stage) = state.stages.get(stage_id) {
|
||||||
|
let stage = Stage::load(&state.base_path, stage, ctx)?;
|
||||||
|
|
||||||
|
let new_instance = EditorInstance::new(stage_id, stage);
|
||||||
|
self.instances.push(new_instance);
|
||||||
|
self.selected_instance = self.instances.len() - 1;
|
||||||
|
self.switch_tab = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_stage(&mut self, state: &mut SharedGameState, ctx: &mut Context) {
|
||||||
|
catch(self.error_list.clone(), || {
|
||||||
|
if let Some(instance) = self.instances.get(self.selected_instance) {
|
||||||
|
state.reset();
|
||||||
|
state.textscript_vm.start_script(94);
|
||||||
|
let mut game_scene = GameScene::from_stage(state, ctx, instance.stage.clone(), instance.stage_id)?;
|
||||||
|
game_scene.init(state, ctx)?;
|
||||||
|
game_scene.player1.cond.set_alive(true);
|
||||||
|
game_scene.player1.x = instance.frame.x + (state.canvas_size.0 * 256.0) as i32;
|
||||||
|
game_scene.player1.y = instance.frame.y + (state.canvas_size.1 * 256.0) as i32;
|
||||||
|
state.control_flags.set_control_enabled(true);
|
||||||
|
state.control_flags.set_tick_world(true);
|
||||||
|
state.textscript_vm.suspend = false;
|
||||||
|
self.subscene = Some(Box::new(game_scene));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn perform_actions(&mut self, state: &mut SharedGameState, ctx: &mut Context) {
|
||||||
|
let actions = std::mem::take(&mut self.stage_list.actions);
|
||||||
|
for action in actions.iter() {
|
||||||
|
match action {
|
||||||
|
StageListAction::OpenStage(idx) => self.open_stage(state, ctx, *idx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ExtraWidgetsExt {
|
||||||
|
fn tool_button(&self, label: impl AsRef<str>, active: bool) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExtraWidgetsExt for imgui::Ui<'_> {
|
||||||
|
fn tool_button(&self, label: impl AsRef<str>, active: bool) -> bool {
|
||||||
|
if active {
|
||||||
|
let color = self.style_color(imgui::StyleColor::ButtonActive);
|
||||||
|
let _token1 = self.push_style_color(imgui::StyleColor::Button, color);
|
||||||
|
let _token2 = self.push_style_color(imgui::StyleColor::ButtonHovered, color);
|
||||||
|
let ret = self.button(label);
|
||||||
|
ret
|
||||||
|
} else {
|
||||||
|
self.button(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scene for EditorScene {
|
impl Scene for EditorScene {
|
||||||
|
@ -23,7 +138,64 @@ impl Scene for EditorScene {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult {
|
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
|
let subscene_ref = &mut self.subscene;
|
||||||
|
if subscene_ref.is_some() {
|
||||||
|
subscene_ref.as_mut().unwrap().tick(state, ctx)?;
|
||||||
|
|
||||||
|
if keyboard::is_key_pressed(ctx, ScanCode::Escape) {
|
||||||
|
*subscene_ref = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// hijack scene switches
|
||||||
|
let next_scene = std::mem::take(&mut state.next_scene);
|
||||||
|
if let Some(next_scene) = next_scene {
|
||||||
|
*subscene_ref = if let Ok(game_scene) = next_scene.downcast() {
|
||||||
|
let mut game_scene: Box<GameScene> = game_scene;
|
||||||
|
game_scene.init(state, ctx)?;
|
||||||
|
Some(game_scene)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if subscene_ref.is_none() {
|
||||||
|
state.sound_manager.play_song(0, &state.constants, &state.settings, ctx)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_tick(&mut self, state: &mut SharedGameState) -> GameResult {
|
||||||
|
if let Some(scene) = &mut self.subscene {
|
||||||
|
scene.draw_tick(state)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
|
if let Some(scene) = &self.subscene {
|
||||||
|
scene.draw(state, ctx)?;
|
||||||
|
state.font.draw_text(
|
||||||
|
"Press [ESC] to return.".chars(),
|
||||||
|
4.0,
|
||||||
|
4.0,
|
||||||
|
&state.constants,
|
||||||
|
&mut state.texture_set,
|
||||||
|
ctx,
|
||||||
|
)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(instance) = self.instances.get(self.selected_instance) {
|
||||||
|
instance.draw(state, ctx, self.current_tool)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,12 +203,25 @@ impl Scene for EditorScene {
|
||||||
&mut self,
|
&mut self,
|
||||||
_game_ui: &mut Components,
|
_game_ui: &mut Components,
|
||||||
state: &mut SharedGameState,
|
state: &mut SharedGameState,
|
||||||
_ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
ui: &mut imgui::Ui,
|
ui: &mut imgui::Ui,
|
||||||
) -> GameResult {
|
) -> GameResult {
|
||||||
|
self.perform_actions(state, ctx);
|
||||||
|
|
||||||
|
if let Some(_) = self.subscene {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut menu_bar_size = (0.0, 0.0);
|
||||||
if let Some(menu_bar) = ui.begin_main_menu_bar() {
|
if let Some(menu_bar) = ui.begin_main_menu_bar() {
|
||||||
|
let [menu_bar_w, menu_bar_h] = ui.window_size();
|
||||||
|
menu_bar_size = (menu_bar_w, menu_bar_h);
|
||||||
|
|
||||||
if let Some(menu) = ui.begin_menu("File") {
|
if let Some(menu) = ui.begin_menu("File") {
|
||||||
MenuItem::new("Open stage").shortcut("Ctrl+O").build(ui);
|
if MenuItem::new("Open stage").shortcut("Ctrl+O").build(ui) {
|
||||||
|
self.stage_list.show();
|
||||||
|
}
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
if MenuItem::new("Exit editor").build(ui) {
|
if MenuItem::new("Exit editor").build(ui) {
|
||||||
|
@ -48,6 +233,117 @@ impl Scene for EditorScene {
|
||||||
menu_bar.end();
|
menu_bar.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Window::new("Toolbar")
|
||||||
|
.title_bar(false)
|
||||||
|
.resizable(false)
|
||||||
|
.position([0.0, menu_bar_size.1], Condition::Always)
|
||||||
|
.size([menu_bar_size.0, 0.0], Condition::Always)
|
||||||
|
.build(ui, || {
|
||||||
|
if ui.tool_button("Move", self.current_tool == CurrentTool::Move) {
|
||||||
|
self.current_tool = CurrentTool::Move;
|
||||||
|
}
|
||||||
|
ui.same_line();
|
||||||
|
if ui.tool_button("Brush", self.current_tool == CurrentTool::Brush) {
|
||||||
|
self.current_tool = CurrentTool::Brush;
|
||||||
|
}
|
||||||
|
ui.same_line();
|
||||||
|
if ui.tool_button("Fill", self.current_tool == CurrentTool::Fill) {
|
||||||
|
self.current_tool = CurrentTool::Fill;
|
||||||
|
}
|
||||||
|
ui.same_line();
|
||||||
|
if ui.tool_button("Rectangle", self.current_tool == CurrentTool::Rectangle) {
|
||||||
|
self.current_tool = CurrentTool::Rectangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.same_line();
|
||||||
|
ui.text("|");
|
||||||
|
|
||||||
|
ui.same_line();
|
||||||
|
if ui.button("Test Stage") {
|
||||||
|
self.test_stage(state, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tab) = ui.tab_bar("Stages") {
|
||||||
|
for (idx, inst) in self.instances.iter().enumerate() {
|
||||||
|
let mut flags = TabItemFlags::NO_CLOSE_WITH_MIDDLE_MOUSE_BUTTON;
|
||||||
|
if self.switch_tab && self.selected_instance == idx {
|
||||||
|
self.switch_tab = false;
|
||||||
|
flags |= TabItemFlags::SET_SELECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(item) = TabItem::new(&inst.stage.data.name).flags(flags).begin(ui) {
|
||||||
|
if !self.switch_tab {
|
||||||
|
self.selected_instance = idx;
|
||||||
|
}
|
||||||
|
item.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tab.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.stage_list.action(state, ctx, ui);
|
||||||
|
|
||||||
|
if let Some(instance) = self.instances.get_mut(self.selected_instance) {
|
||||||
|
instance.process(state, ctx, ui, self.current_tool);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct StageListWindow {
|
||||||
|
visible: bool,
|
||||||
|
selected_stage: i32,
|
||||||
|
actions: Vec<StageListAction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StageListAction {
|
||||||
|
OpenStage(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StageListWindow {
|
||||||
|
fn new() -> Self {
|
||||||
|
StageListWindow { visible: false, selected_stage: 0, actions: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show(&mut self) {
|
||||||
|
self.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn action(&mut self, state: &mut SharedGameState, ctx: &mut Context, ui: &mut imgui::Ui) {
|
||||||
|
if !self.visible {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::new("Stage list")
|
||||||
|
.resizable(false)
|
||||||
|
.collapsible(false)
|
||||||
|
.position_pivot([0.5, 0.5])
|
||||||
|
.size([300.0, 352.0], Condition::FirstUseEver)
|
||||||
|
.build(ui, || {
|
||||||
|
let mut stages = Vec::with_capacity(state.stages.len());
|
||||||
|
for stage in state.stages.iter() {
|
||||||
|
stages.push(stage.name.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.push_item_width(-1.0);
|
||||||
|
ui.list_box("", &mut self.selected_stage, &stages, 14);
|
||||||
|
|
||||||
|
ui.disabled(self.selected_stage < 0, || {
|
||||||
|
if ui.button("Open") {
|
||||||
|
self.actions.push(StageListAction::OpenStage(self.selected_stage as usize));
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.same_line();
|
||||||
|
if ui.button("Edit table entry") {}
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.same_line();
|
||||||
|
if ui.button("Cancel") {
|
||||||
|
self.visible = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::rc::Rc;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
use crate::common::{interpolate_fix9_scale, Color, Direction, Rect};
|
use crate::common::{Color, Direction, interpolate_fix9_scale, Rect};
|
||||||
use crate::components::background::Background;
|
use crate::components::background::Background;
|
||||||
use crate::components::boss_life_bar::BossLifeBar;
|
use crate::components::boss_life_bar::BossLifeBar;
|
||||||
use crate::components::credits::Credits;
|
use crate::components::credits::Credits;
|
||||||
|
@ -21,30 +21,30 @@ use crate::components::tilemap::{TileLayer, Tilemap};
|
||||||
use crate::components::water_renderer::WaterRenderer;
|
use crate::components::water_renderer::WaterRenderer;
|
||||||
use crate::entity::GameEntity;
|
use crate::entity::GameEntity;
|
||||||
use crate::frame::{Frame, UpdateTarget};
|
use crate::frame::{Frame, UpdateTarget};
|
||||||
|
use crate::framework::{filesystem, graphics};
|
||||||
use crate::framework::backend::SpriteBatchCommand;
|
use crate::framework::backend::SpriteBatchCommand;
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use crate::framework::graphics::{draw_rect, BlendMode, FilterMode};
|
use crate::framework::graphics::{BlendMode, draw_rect, FilterMode};
|
||||||
use crate::framework::ui::Components;
|
use crate::framework::ui::Components;
|
||||||
use crate::framework::{filesystem, graphics};
|
|
||||||
use crate::input::touch_controls::TouchControlType;
|
use crate::input::touch_controls::TouchControlType;
|
||||||
use crate::inventory::{Inventory, TakeExperienceResult};
|
use crate::inventory::{Inventory, TakeExperienceResult};
|
||||||
use crate::map::WaterParams;
|
use crate::map::WaterParams;
|
||||||
|
use crate::npc::{NPC, NPCLayer};
|
||||||
use crate::npc::boss::BossNPC;
|
use crate::npc::boss::BossNPC;
|
||||||
use crate::npc::list::NPCList;
|
use crate::npc::list::NPCList;
|
||||||
use crate::npc::{NPCLayer, NPC};
|
use crate::physics::{OFFSETS, PhysicalEntity};
|
||||||
use crate::physics::{PhysicalEntity, OFFSETS};
|
|
||||||
use crate::player::{Player, TargetPlayer};
|
use crate::player::{Player, TargetPlayer};
|
||||||
use crate::rng::XorShift;
|
use crate::rng::XorShift;
|
||||||
use crate::scene::title_scene::TitleScene;
|
|
||||||
use crate::scene::Scene;
|
use crate::scene::Scene;
|
||||||
|
use crate::scene::title_scene::TitleScene;
|
||||||
use crate::scripting::tsc::credit_script::CreditScriptVM;
|
use crate::scripting::tsc::credit_script::CreditScriptVM;
|
||||||
use crate::scripting::tsc::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
|
use crate::scripting::tsc::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
|
||||||
use crate::shared_game_state::{SharedGameState, TileSize};
|
use crate::shared_game_state::{SharedGameState, TileSize};
|
||||||
use crate::stage::{BackgroundType, Stage, StageTexturePaths};
|
use crate::stage::{BackgroundType, Stage, StageTexturePaths};
|
||||||
use crate::texture_set::SpriteBatch;
|
use crate::texture_set::SpriteBatch;
|
||||||
use crate::weapon::bullet::BulletManager;
|
|
||||||
use crate::weapon::{Weapon, WeaponType};
|
use crate::weapon::{Weapon, WeaponType};
|
||||||
|
use crate::weapon::bullet::BulletManager;
|
||||||
|
|
||||||
pub struct GameScene {
|
pub struct GameScene {
|
||||||
pub tick: u32,
|
pub tick: u32,
|
||||||
|
@ -96,11 +96,16 @@ impl GameScene {
|
||||||
info!("Loading stage {} ({})", id, &state.stages[id].map);
|
info!("Loading stage {} ({})", id, &state.stages[id].map);
|
||||||
let stage = Stage::load(&state.base_path, &state.stages[id], ctx)?;
|
let stage = Stage::load(&state.base_path, &state.stages[id], ctx)?;
|
||||||
info!("Loaded stage: {}", stage.data.name);
|
info!("Loaded stage: {}", stage.data.name);
|
||||||
|
|
||||||
|
GameScene::from_stage(state, ctx, stage, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_stage(state: &mut SharedGameState, ctx: &mut Context, stage: Stage, id: usize) -> GameResult<Self> {
|
||||||
let mut water_params = WaterParams::new();
|
let mut water_params = WaterParams::new();
|
||||||
let mut water_renderer = WaterRenderer::new();
|
let mut water_renderer = WaterRenderer::new();
|
||||||
|
|
||||||
if let Ok(water_param_file) =
|
if let Ok(water_param_file) =
|
||||||
filesystem::open(ctx, [&state.base_path, "Stage/", &state.stages[id].tileset.name, ".pxw"].join(""))
|
filesystem::open(ctx, [&state.base_path, "Stage/", &state.stages[id].tileset.name, ".pxw"].join(""))
|
||||||
{
|
{
|
||||||
water_params.load_from(water_param_file)?;
|
water_params.load_from(water_param_file)?;
|
||||||
info!("Loaded water parameters file.");
|
info!("Loaded water parameters file.");
|
||||||
|
@ -109,23 +114,9 @@ impl GameScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
let stage_textures = {
|
let stage_textures = {
|
||||||
let background = stage.data.background.filename();
|
let mut textures = StageTexturePaths::new();
|
||||||
let (tileset_fg, tileset_mg, tileset_bg) = if let Some(pxpack_data) = stage.data.pxpack_data.as_ref() {
|
textures.update(&stage);
|
||||||
let t_fg = ["Stage/", &pxpack_data.tileset_fg].join("");
|
Rc::new(RefCell::new(textures))
|
||||||
let t_mg = ["Stage/", &pxpack_data.tileset_mg].join("");
|
|
||||||
let t_bg = ["Stage/", &pxpack_data.tileset_bg].join("");
|
|
||||||
|
|
||||||
(t_fg, t_mg, t_bg)
|
|
||||||
} else {
|
|
||||||
let tex_tileset_name = ["Stage/", &stage.data.tileset.filename()].join("");
|
|
||||||
|
|
||||||
(tex_tileset_name.clone(), tex_tileset_name.clone(), tex_tileset_name)
|
|
||||||
};
|
|
||||||
|
|
||||||
let npc1 = ["Npc/", &stage.data.npc1.filename()].join("");
|
|
||||||
let npc2 = ["Npc/", &stage.data.npc2.filename()].join("");
|
|
||||||
|
|
||||||
Rc::new(RefCell::new(StageTexturePaths { background, tileset_fg, tileset_mg, tileset_bg, npc1, npc2 }))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
@ -149,16 +140,7 @@ impl GameScene {
|
||||||
tilemap: Tilemap::new(),
|
tilemap: Tilemap::new(),
|
||||||
text_boxes: TextBoxes::new(),
|
text_boxes: TextBoxes::new(),
|
||||||
fade: Fade::new(),
|
fade: Fade::new(),
|
||||||
frame: Frame {
|
frame: Frame::new(),
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
prev_x: 0,
|
|
||||||
prev_y: 0,
|
|
||||||
update_target: UpdateTarget::Player,
|
|
||||||
target_x: 0,
|
|
||||||
target_y: 0,
|
|
||||||
wait: 16,
|
|
||||||
},
|
|
||||||
stage_id: id,
|
stage_id: id,
|
||||||
npc_list: NPCList::new(),
|
npc_list: NPCList::new(),
|
||||||
boss: BossNPC::new(),
|
boss: BossNPC::new(),
|
||||||
|
|
|
@ -5,9 +5,9 @@ use crate::npc::NPCTable;
|
||||||
use crate::scene::no_data_scene::NoDataScene;
|
use crate::scene::no_data_scene::NoDataScene;
|
||||||
use crate::scene::Scene;
|
use crate::scene::Scene;
|
||||||
use crate::scripting::tsc::credit_script::CreditScript;
|
use crate::scripting::tsc::credit_script::CreditScript;
|
||||||
|
use crate::scripting::tsc::text_script::TextScript;
|
||||||
use crate::shared_game_state::SharedGameState;
|
use crate::shared_game_state::SharedGameState;
|
||||||
use crate::stage::StageData;
|
use crate::stage::StageData;
|
||||||
use crate::scripting::tsc::text_script::TextScript;
|
|
||||||
|
|
||||||
pub struct LoadingScene {
|
pub struct LoadingScene {
|
||||||
tick: usize,
|
tick: usize,
|
||||||
|
@ -15,9 +15,7 @@ pub struct LoadingScene {
|
||||||
|
|
||||||
impl LoadingScene {
|
impl LoadingScene {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self { tick: 0 }
|
||||||
tick: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_stuff(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
fn load_stuff(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
|
@ -71,8 +69,10 @@ impl Scene for LoadingScene {
|
||||||
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
match state.texture_set.get_or_load_batch(ctx, &state.constants, "Loading") {
|
match state.texture_set.get_or_load_batch(ctx, &state.constants, "Loading") {
|
||||||
Ok(batch) => {
|
Ok(batch) => {
|
||||||
batch.add(((state.canvas_size.0 - batch.width() as f32) / 2.0).floor(),
|
batch.add(
|
||||||
((state.canvas_size.1 - batch.height() as f32) / 2.0).floor());
|
((state.canvas_size.0 - batch.width() as f32) / 2.0).floor(),
|
||||||
|
((state.canvas_size.1 - batch.height() as f32) / 2.0).floor(),
|
||||||
|
);
|
||||||
batch.draw(ctx)?;
|
batch.draw(ctx)?;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
|
@ -1,30 +1,48 @@
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
|
|
||||||
use crate::shared_game_state::SharedGameState;
|
|
||||||
use crate::framework::ui::Components;
|
use crate::framework::ui::Components;
|
||||||
|
use crate::shared_game_state::SharedGameState;
|
||||||
|
|
||||||
|
#[cfg(feature = "editor")]
|
||||||
|
pub mod editor_scene;
|
||||||
pub mod game_scene;
|
pub mod game_scene;
|
||||||
pub mod loading_scene;
|
pub mod loading_scene;
|
||||||
pub mod no_data_scene;
|
pub mod no_data_scene;
|
||||||
pub mod title_scene;
|
pub mod title_scene;
|
||||||
pub mod editor_scene;
|
|
||||||
|
|
||||||
/// Implement this trait on any object that represents an interactive game screen.
|
/// Implement this trait on any object that represents an interactive game screen.
|
||||||
pub trait Scene {
|
pub trait Scene: downcast::Any {
|
||||||
/// Called when the scene is shown.
|
/// Called when the scene is shown.
|
||||||
fn init(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) }
|
fn init(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Called at game tick. Perform any game state updates there.
|
/// Called at game tick. Perform any game state updates there.
|
||||||
fn tick(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) }
|
fn tick(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Called before draws between two ticks to update previous positions used for interpolation.
|
/// Called before draws between two ticks to update previous positions used for interpolation.
|
||||||
/// DO NOT perform updates of the game state there.
|
/// DO NOT perform updates of the game state there.
|
||||||
fn draw_tick(&mut self, _state: &mut SharedGameState) -> GameResult { Ok(()) }
|
fn draw_tick(&mut self, _state: &mut SharedGameState) -> GameResult {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Called during frame rendering operation.
|
/// Called during frame rendering operation.
|
||||||
fn draw(&self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { Ok(()) }
|
fn draw(&self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Independent draw meant for debug overlay, that lets you mutate the game state.
|
/// Independent draw meant for debug overlay, that lets you mutate the game state.
|
||||||
fn imgui_draw(&mut self, _game_ui: &mut Components, _state: &mut SharedGameState, _ctx: &mut Context, _frame: &mut imgui::Ui) -> GameResult { Ok(()) }
|
fn imgui_draw(
|
||||||
|
&mut self,
|
||||||
|
_game_ui: &mut Components,
|
||||||
|
_state: &mut SharedGameState,
|
||||||
|
_ctx: &mut Context,
|
||||||
|
_frame: &mut imgui::Ui,
|
||||||
|
) -> GameResult {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downcast::impl_downcast!(dyn Scene);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::{GameResult, GameError};
|
use crate::framework::error::{GameError, GameResult};
|
||||||
|
|
||||||
use crate::scene::Scene;
|
use crate::scene::Scene;
|
||||||
use crate::shared_game_state::SharedGameState;
|
use crate::shared_game_state::SharedGameState;
|
||||||
|
|
||||||
|
@ -27,23 +26,23 @@ impl Scene for NoDataScene {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
{
|
{
|
||||||
use crate::common::Rect;
|
use crate::common::Rect;
|
||||||
|
|
||||||
if !self.flag {
|
if !self.flag {
|
||||||
self.flag = true;
|
self.flag = true;
|
||||||
let _ = std::fs::create_dir("/sdcard/doukutsu/");
|
let _ = std::fs::create_dir("/sdcard/doukutsu/");
|
||||||
let _ = std::fs::write("/sdcard/doukutsu/extract game data here.txt", REL_URL);
|
let _ = std::fs::write("/sdcard/doukutsu/extract game data here.txt", REL_URL);
|
||||||
let _ = std::fs::write("/sdcard/doukutsu/.nomedia", b"");
|
let _ = std::fs::write("/sdcard/doukutsu/.nomedia", b"");
|
||||||
}
|
}
|
||||||
|
|
||||||
let screen = Rect::new(0, 0, state.canvas_size.0 as isize, state.canvas_size.1 as isize);
|
let screen = Rect::new(0, 0, state.canvas_size.0 as isize, state.canvas_size.1 as isize);
|
||||||
if state.touch_controls.consume_click_in(screen) {
|
if state.touch_controls.consume_click_in(screen) {
|
||||||
if let Err(err) = webbrowser::open(REL_URL) {
|
if let Err(err) = webbrowser::open(REL_URL) {
|
||||||
self.err = err.to_string();
|
self.err = err.to_string();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,43 +50,82 @@ impl Scene for NoDataScene {
|
||||||
{
|
{
|
||||||
let die = "doukutsu-rs internal error";
|
let die = "doukutsu-rs internal error";
|
||||||
let die_width = state.font.text_width(die.chars().clone(), &state.constants);
|
let die_width = state.font.text_width(die.chars().clone(), &state.constants);
|
||||||
state.font.draw_colored_text(die.chars(), (state.canvas_size.0 - die_width) / 2.0, 10.0,
|
state.font.draw_colored_text(
|
||||||
(255, 100, 100, 255), &state.constants, &mut state.texture_set, ctx)?;
|
die.chars(),
|
||||||
|
(state.canvas_size.0 - die_width) / 2.0,
|
||||||
|
10.0,
|
||||||
|
(255, 100, 100, 255),
|
||||||
|
&state.constants,
|
||||||
|
&mut state.texture_set,
|
||||||
|
ctx,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let ftl = "Failed to load game data.";
|
let ftl = "Failed to load game data.";
|
||||||
let ftl_width = state.font.text_width(ftl.chars().clone(), &state.constants);
|
let ftl_width = state.font.text_width(ftl.chars().clone(), &state.constants);
|
||||||
state.font.draw_colored_text(ftl.chars(), (state.canvas_size.0 - ftl_width) / 2.0, 30.0,
|
state.font.draw_colored_text(
|
||||||
(255, 100, 100, 255), &state.constants, &mut state.texture_set, ctx)?;
|
ftl.chars(),
|
||||||
|
(state.canvas_size.0 - ftl_width) / 2.0,
|
||||||
|
30.0,
|
||||||
|
(255, 100, 100, 255),
|
||||||
|
&state.constants,
|
||||||
|
&mut state.texture_set,
|
||||||
|
ctx,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
{
|
{
|
||||||
let ftl = "It's likely that you haven't extracted the game data properly.";
|
let ftl = "It's likely that you haven't extracted the game data properly.";
|
||||||
let ftl2 = "Click here to open the guide.";
|
let ftl2 = "Click here to open the guide.";
|
||||||
let ftl_width = state.font.text_width(ftl.chars().clone(), &state.constants);
|
let ftl_width = state.font.text_width(ftl.chars().clone(), &state.constants);
|
||||||
let ftl2_width = state.font.text_width(ftl2.chars().clone(), &state.constants);
|
let ftl2_width = state.font.text_width(ftl2.chars().clone(), &state.constants);
|
||||||
let ftl3_width = state.font.text_width(REL_URL.chars().clone(), &state.constants);
|
let ftl3_width = state.font.text_width(REL_URL.chars().clone(), &state.constants);
|
||||||
|
|
||||||
state.font.draw_colored_text(ftl.chars(), (state.canvas_size.0 - ftl_width) / 2.0, 60.0,
|
state.font.draw_colored_text(
|
||||||
(255, 255, 0, 255), &state.constants, &mut state.texture_set, ctx)?;
|
ftl.chars(),
|
||||||
|
(state.canvas_size.0 - ftl_width) / 2.0,
|
||||||
|
60.0,
|
||||||
|
(255, 255, 0, 255),
|
||||||
|
&state.constants,
|
||||||
|
&mut state.texture_set,
|
||||||
|
ctx,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
state.font.draw_colored_text(
|
||||||
|
ftl2.chars(),
|
||||||
|
(state.canvas_size.0 - ftl2_width) / 2.0,
|
||||||
|
80.0,
|
||||||
|
(255, 255, 0, 255),
|
||||||
|
&state.constants,
|
||||||
|
&mut state.texture_set,
|
||||||
|
ctx,
|
||||||
|
)?;
|
||||||
|
|
||||||
state.font.draw_colored_text(ftl2.chars(), (state.canvas_size.0 - ftl2_width) / 2.0, 80.0,
|
state.font.draw_colored_text(
|
||||||
(255, 255, 0, 255), &state.constants, &mut state.texture_set, ctx)?;
|
REL_URL.chars(),
|
||||||
|
(state.canvas_size.0 - ftl3_width) / 2.0,
|
||||||
state.font.draw_colored_text(REL_URL.chars(), (state.canvas_size.0 - ftl3_width) / 2.0, 100.0,
|
100.0,
|
||||||
(255, 255, 0, 255), &state.constants, &mut state.texture_set, ctx)?;
|
(255, 255, 0, 255),
|
||||||
}
|
&state.constants,
|
||||||
|
&mut state.texture_set,
|
||||||
|
ctx,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let err_width = state.font.text_width(self.err.chars().clone(), &state.constants);
|
let err_width = state.font.text_width(self.err.chars().clone(), &state.constants);
|
||||||
state.font.draw_text(self.err.chars(), (state.canvas_size.0 - err_width) / 2.0, 140.0,
|
state.font.draw_text(
|
||||||
&state.constants, &mut state.texture_set, ctx)?;
|
self.err.chars(),
|
||||||
|
(state.canvas_size.0 - err_width) / 2.0,
|
||||||
|
140.0,
|
||||||
|
&state.constants,
|
||||||
|
&mut state.texture_set,
|
||||||
|
ctx,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ use crate::framework::error::GameResult;
|
||||||
use crate::framework::graphics;
|
use crate::framework::graphics;
|
||||||
use crate::input::combined_menu_controller::CombinedMenuController;
|
use crate::input::combined_menu_controller::CombinedMenuController;
|
||||||
use crate::input::touch_controls::TouchControlType;
|
use crate::input::touch_controls::TouchControlType;
|
||||||
use crate::menu::settings_menu::SettingsMenu;
|
|
||||||
use crate::menu::{Menu, MenuEntry, MenuSelectionResult};
|
use crate::menu::{Menu, MenuEntry, MenuSelectionResult};
|
||||||
|
use crate::menu::settings_menu::SettingsMenu;
|
||||||
use crate::scene::Scene;
|
use crate::scene::Scene;
|
||||||
use crate::shared_game_state::SharedGameState;
|
use crate::shared_game_state::SharedGameState;
|
||||||
|
|
||||||
|
@ -144,10 +144,10 @@ impl Scene for TitleScene {
|
||||||
}
|
}
|
||||||
MenuSelectionResult::Selected(3, _) => {
|
MenuSelectionResult::Selected(3, _) => {
|
||||||
#[cfg(feature = "editor")]
|
#[cfg(feature = "editor")]
|
||||||
{
|
{
|
||||||
use crate::scene::editor_scene::EditorScene;
|
use crate::scene::editor_scene::EditorScene;
|
||||||
state.next_scene = Some(Box::new(EditorScene::new()));
|
state.next_scene = Some(Box::new(EditorScene::new()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MenuSelectionResult::Selected(4, _) => {
|
MenuSelectionResult::Selected(4, _) => {
|
||||||
state.shutdown();
|
state.shutdown();
|
||||||
|
|
24
src/stage.rs
24
src/stage.rs
|
@ -1,8 +1,8 @@
|
||||||
use std::io::{Cursor, Read};
|
use std::io::{Cursor, Read};
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
|
|
||||||
use byteorder::LE;
|
|
||||||
use byteorder::ReadBytesExt;
|
use byteorder::ReadBytesExt;
|
||||||
|
use byteorder::LE;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use crate::common::Color;
|
use crate::common::Color;
|
||||||
|
@ -511,6 +511,7 @@ impl StageData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Stage {
|
pub struct Stage {
|
||||||
pub map: Map,
|
pub map: Map,
|
||||||
pub data: StageData,
|
pub data: StageData,
|
||||||
|
@ -609,4 +610,25 @@ impl StageTexturePaths {
|
||||||
npc2: "Npc/Npc0".to_owned(),
|
npc2: "Npc/Npc0".to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, stage: &Stage) {
|
||||||
|
self.background = stage.data.background.filename();
|
||||||
|
let (tileset_fg, tileset_mg, tileset_bg) = if let Some(pxpack_data) = stage.data.pxpack_data.as_ref() {
|
||||||
|
let t_fg = ["Stage/", &pxpack_data.tileset_fg].join("");
|
||||||
|
let t_mg = ["Stage/", &pxpack_data.tileset_mg].join("");
|
||||||
|
let t_bg = ["Stage/", &pxpack_data.tileset_bg].join("");
|
||||||
|
|
||||||
|
(t_fg, t_mg, t_bg)
|
||||||
|
} else {
|
||||||
|
let tex_tileset_name = ["Stage/", &stage.data.tileset.filename()].join("");
|
||||||
|
|
||||||
|
(tex_tileset_name.clone(), tex_tileset_name.clone(), tex_tileset_name)
|
||||||
|
};
|
||||||
|
self.tileset_fg = tileset_fg;
|
||||||
|
self.tileset_mg = tileset_mg;
|
||||||
|
self.tileset_bg = tileset_bg;
|
||||||
|
|
||||||
|
self.npc1 = ["Npc/", &stage.data.npc1.filename()].join("");
|
||||||
|
self.npc2 = ["Npc/", &stage.data.npc2.filename()].join("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,8 @@ pub trait SpriteBatch {
|
||||||
fn draw(&mut self, ctx: &mut Context) -> GameResult;
|
fn draw(&mut self, ctx: &mut Context) -> GameResult;
|
||||||
|
|
||||||
fn draw_filtered(&mut self, _filter: FilterMode, _ctx: &mut Context) -> GameResult;
|
fn draw_filtered(&mut self, _filter: FilterMode, _ctx: &mut Context) -> GameResult;
|
||||||
|
|
||||||
|
fn get_texture(&self) -> Option<&Box<dyn BackendTexture>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DummyBatch;
|
pub struct DummyBatch;
|
||||||
|
@ -136,6 +138,10 @@ impl SpriteBatch for DummyBatch {
|
||||||
fn draw_filtered(&mut self, _filter: FilterMode, _ctx: &mut Context) -> GameResult {
|
fn draw_filtered(&mut self, _filter: FilterMode, _ctx: &mut Context) -> GameResult {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_texture(&self) -> Option<&Box<dyn BackendTexture>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubBatch {
|
pub struct SubBatch {
|
||||||
|
@ -309,6 +315,10 @@ impl SpriteBatch for SubBatch {
|
||||||
self.batch.clear();
|
self.batch.clear();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_texture(&self) -> Option<&Box<dyn BackendTexture>> {
|
||||||
|
Some(&self.batch)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpriteBatch for CombinedBatch {
|
impl SpriteBatch for CombinedBatch {
|
||||||
|
@ -395,6 +405,10 @@ impl SpriteBatch for CombinedBatch {
|
||||||
fn draw_filtered(&mut self, filter: FilterMode, ctx: &mut Context) -> GameResult {
|
fn draw_filtered(&mut self, filter: FilterMode, ctx: &mut Context) -> GameResult {
|
||||||
self.main_batch.draw_filtered(filter, ctx)
|
self.main_batch.draw_filtered(filter, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_texture(&self) -> Option<&Box<dyn BackendTexture>> {
|
||||||
|
self.main_batch.get_texture()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextureSet {
|
pub struct TextureSet {
|
||||||
|
|
Loading…
Reference in a new issue