1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-07-15 17:25:37 +00:00

refactor: split tilemap out

This commit is contained in:
Alula 2022-01-05 05:50:16 +01:00
parent ac58602ed0
commit 3b1a5f149e
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
11 changed files with 335 additions and 235 deletions

View file

@ -1,3 +1,5 @@
use std::ops::Deref;
use crate::common::{Color, Rect};
use crate::entity::GameEntity;
use crate::frame::Frame;
@ -16,7 +18,7 @@ impl FallingIsland {
}
impl GameEntity<()> for FallingIsland {
fn tick(&mut self, state: &mut SharedGameState, custom: ()) -> GameResult {
fn tick(&mut self, _state: &mut SharedGameState, _custom: ()) -> GameResult {
Ok(())
}
@ -43,7 +45,11 @@ impl GameEntity<()> for FallingIsland {
static RECT_ISLAND: Rect<u16> = Rect { left: 160, top: 0, right: 200, bottom: 24 };
static RECT_TERRAIN: Rect<u16> = Rect { left: 160, top: 48, right: 320, bottom: 80 };
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &state.npc_table.tex_npc1_name)?;
let batch = state.texture_set.get_or_load_batch(
ctx,
&state.constants,
&state.npc_table.stage_textures.deref().borrow().npc1,
)?;
batch.add_rect(off_x + 80.0, 80.0, &RECT_BG);
batch.add_rect(off_x + (pos_x as f32 / 512.0) - 20.0, (pos_y as f32 / 512.0) - 12.0, &RECT_ISLAND);
batch.add_rect(off_x + 80.0, 128.0, &RECT_TERRAIN);

View file

@ -8,3 +8,4 @@ pub mod inventory;
pub mod number_popup;
pub mod stage_select;
pub mod water_renderer;
pub mod tilemap;

173
src/components/tilemap.rs Normal file
View file

@ -0,0 +1,173 @@
use crate::common::Rect;
use crate::frame::Frame;
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::shared_game_state::{SharedGameState, TileSize};
use crate::stage::{BackgroundType, Stage, StageTexturePaths};
pub struct Tilemap;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum TileLayer {
Background,
Middleground,
Foreground,
Snack,
}
impl Tilemap {
pub fn new() -> Self {
Tilemap
}
pub fn draw(
&self,
state: &mut SharedGameState,
ctx: &mut Context,
frame: &Frame,
layer: TileLayer,
textures: &StageTexturePaths,
stage: &Stage,
) -> GameResult {
if stage.map.tile_size == TileSize::Tile8x8 && layer == TileLayer::Snack {
return Ok(());
}
let tex = match layer {
TileLayer::Snack => "Npc/NpcSym",
TileLayer::Background => &textures.tileset_bg,
TileLayer::Middleground => &textures.tileset_mg,
TileLayer::Foreground => &textures.tileset_fg,
};
let (layer_offset, layer_width, layer_height, uses_layers) =
if let Some(pxpack_data) = stage.data.pxpack_data.as_ref() {
match layer {
TileLayer::Background => {
(pxpack_data.offset_bg as usize, pxpack_data.size_bg.0, pxpack_data.size_bg.1, true)
}
TileLayer::Middleground => {
(pxpack_data.offset_mg as usize, pxpack_data.size_mg.0, pxpack_data.size_mg.1, true)
}
_ => (0, pxpack_data.size_fg.0, pxpack_data.size_fg.1, true),
}
} else {
(0, stage.map.width, stage.map.height, false)
};
if !uses_layers && layer == TileLayer::Middleground {
return Ok(());
}
let tile_size = state.tile_size.as_int();
let tile_sizef = state.tile_size.as_float();
let halft = tile_size / 2;
let halftf = tile_sizef / 2.0;
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, tex)?;
let mut rect = Rect::new(0, 0, tile_size as u16, tile_size as u16);
let (mut frame_x, mut frame_y) = frame.xy_interpolated(state.frame_time);
if let Some(pxpack_data) = stage.data.pxpack_data.as_ref() {
let (fx, fy) = match layer {
TileLayer::Background => pxpack_data.scroll_bg.transform_camera_pos(frame_x, frame_y),
TileLayer::Middleground => pxpack_data.scroll_mg.transform_camera_pos(frame_x, frame_y),
_ => pxpack_data.scroll_fg.transform_camera_pos(frame_x, frame_y),
};
frame_x = fx;
frame_y = fy;
}
let tile_start_x = (frame_x as i32 / tile_size).clamp(0, layer_width as i32) as usize;
let tile_start_y = (frame_y as i32 / tile_size).clamp(0, layer_height as i32) as usize;
let tile_end_x =
((frame_x as i32 + 8 + state.canvas_size.0 as i32) / tile_size + 1).clamp(0, layer_width as i32) as usize;
let tile_end_y = ((frame_y as i32 + halft + state.canvas_size.1 as i32) / tile_size + 1)
.clamp(0, layer_height as i32) as usize;
if layer == TileLayer::Snack {
rect = state.constants.world.snack_rect;
}
for y in tile_start_y..tile_end_y {
for x in tile_start_x..tile_end_x {
let tile = *stage.map.tiles.get((y * layer_width as usize) + x + layer_offset).unwrap();
match layer {
_ if uses_layers => {
if tile == 0 {
continue;
}
let tile_size = tile_size as u16;
rect.left = (tile as u16 % 16) * tile_size;
rect.top = (tile as u16 / 16) * tile_size;
rect.right = rect.left + tile_size;
rect.bottom = rect.top + tile_size;
}
TileLayer::Background => {
if stage.map.attrib[tile as usize] >= 0x20 {
continue;
}
let tile_size = tile_size as u16;
rect.left = (tile as u16 % 16) * tile_size;
rect.top = (tile as u16 / 16) * tile_size;
rect.right = rect.left + tile_size;
rect.bottom = rect.top + tile_size;
}
TileLayer::Foreground => {
let attr = stage.map.attrib[tile as usize];
if attr < 0x40 || attr >= 0x80 || attr == 0x43 {
continue;
}
let tile_size = tile_size as u16;
rect.left = (tile as u16 % 16) * tile_size;
rect.top = (tile as u16 / 16) * tile_size;
rect.right = rect.left + tile_size;
rect.bottom = rect.top + tile_size;
}
TileLayer::Snack => {
if stage.map.attrib[tile as usize] != 0x43 {
continue;
}
}
_ => {}
}
batch.add_rect(
(x as f32 * tile_sizef - halftf) - frame_x,
(y as f32 * tile_sizef - halftf) - frame_y,
&rect,
);
}
}
batch.draw(ctx)?;
if layer == TileLayer::Foreground && stage.data.background_type == BackgroundType::Water {
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &textures.background)?;
let rect_top = Rect { left: 0, top: 0, right: 32, bottom: 16 };
let rect_middle = Rect { left: 0, top: 16, right: 32, bottom: 48 };
let tile_start_x = frame_x as i32 / 32;
let tile_end_x = (frame_x + 16.0 + state.canvas_size.0) as i32 / 32 + 1;
let water_y = state.water_level as f32 / 512.0;
let tile_count_y = (frame_y + 16.0 + state.canvas_size.1 - water_y) as i32 / 32 + 1;
for x in tile_start_x..tile_end_x {
batch.add_rect((x as f32 * 32.0) - frame_x, water_y - frame_y, &rect_top);
for y in 0..tile_count_y {
batch.add_rect((x as f32 * 32.0) - frame_x, (y as f32 * 32.0) + water_y - frame_y, &rect_middle);
}
}
batch.draw(ctx)?;
}
Ok(())
}
}

View file

@ -118,7 +118,7 @@ impl BackendRenderer for NullRenderer {
Ok(())
}
fn set_clip_rect(&mut self, rect: Option<Rect>) -> GameResult {
fn set_clip_rect(&mut self, _rect: Option<Rect>) -> GameResult {
Ok(())
}

View file

@ -9,7 +9,6 @@ use crate::framework::error::GameResult;
use crate::npc::boss::BossNPC;
use crate::npc::list::NPCList;
use crate::npc::NPC;
use crate::physics::PhysicalEntity;
use crate::player::Player;
use crate::rng::RNG;
use crate::shared_game_state::SharedGameState;

View file

@ -1,4 +1,5 @@
use std::mem::MaybeUninit;
use std::ops::Deref;
use crate::common::{interpolate_fix9_scale, Direction};
use crate::components::flash::Flash;
@ -99,8 +100,11 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
}
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult {
let batch =
state.texture_set.get_or_load_batch(ctx, &state.constants, state.npc_table.tex_npc2_name.as_str())?;
let batch = state.texture_set.get_or_load_batch(
ctx,
&state.constants,
&state.npc_table.stage_textures.deref().borrow().npc2,
)?;
for npc in self.parts.iter().rev() {
if !npc.cond.alive() || npc.cond.hidden() {
@ -114,12 +118,12 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
let (frame_x, frame_y) = frame.xy_interpolated(state.frame_time);
batch.add_rect(
interpolate_fix9_scale(npc.prev_x - off_x,
npc.x - off_x,
state.frame_time) + shock - frame_x,
interpolate_fix9_scale(npc.prev_y - npc.display_bounds.top as i32,
interpolate_fix9_scale(npc.prev_x - off_x, npc.x - off_x, state.frame_time) + shock - frame_x,
interpolate_fix9_scale(
npc.prev_y - npc.display_bounds.top as i32,
npc.y - npc.display_bounds.top as i32,
state.frame_time) - frame_y,
state.frame_time,
) - frame_y,
&npc.anim_rect,
);
}

View file

@ -1047,7 +1047,7 @@ impl BossNPC {
let angle =
if part.action_counter2 != 0 { part.action_counter3 + 0x80 } else { part.action_counter3 + 0x180 };
let angle = ((angle / 2) as f64 * CDEG_RAD);
let angle = (angle / 2) as f64 * CDEG_RAD;
part.x = base.x + 0x30 * (angle.cos() * -512.0) as i32 - 0x1000;
part.y = base.y + 0x50 * (angle.sin() * -512.0) as i32;

View file

@ -1,12 +1,15 @@
use std::cell::{Ref, RefCell};
use std::io;
use std::io::Cursor;
use std::ops::Deref;
use std::rc::Rc;
use byteorder::{ReadBytesExt, LE};
use byteorder::{LE, ReadBytesExt};
use crate::bitfield;
use crate::common::{Condition, interpolate_fix9_scale, Rect};
use crate::common::Direction;
use crate::common::Flag;
use crate::common::{interpolate_fix9_scale, Condition, Rect};
use crate::components::flash::Flash;
use crate::components::number_popup::NumberPopup;
use crate::entity::GameEntity;
@ -19,7 +22,7 @@ use crate::physics::PhysicalEntity;
use crate::player::Player;
use crate::rng::Xoroshiro32PlusPlus;
use crate::shared_game_state::SharedGameState;
use crate::stage::Stage;
use crate::stage::{Stage, StageTexturePaths};
use crate::weapon::bullet::BulletManager;
pub mod ai;
@ -188,7 +191,7 @@ impl NPC {
return Ok(());
}
let texture = state.npc_table.get_texture_name(self.spritesheet_id);
let texture = &*state.npc_table.get_texture_ref(self.spritesheet_id);
if let Some(batch) = state.texture_set.get_or_load_batch(ctx, &state.constants, texture)?.glow() {
let off_x =
@ -592,8 +595,11 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &mut BulletManager, &mu
return Ok(());
}
let texture = state.npc_table.get_texture_name(self.spritesheet_id);
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, texture)?;
let batch = state.texture_set.get_or_load_batch(
ctx,
&state.constants,
&*state.npc_table.get_texture_ref(self.spritesheet_id),
)?;
let off_x =
if self.direction == Direction::Left { self.display_bounds.left } else { self.display_bounds.right } as i32;
@ -741,20 +747,13 @@ pub struct NPCTableEntry {
pub struct NPCTable {
entries: Vec<NPCTableEntry>,
pub tileset_name: String,
pub tex_npc1_name: String,
pub tex_npc2_name: String,
pub stage_textures: Rc<RefCell<StageTexturePaths>>,
}
impl NPCTable {
#[allow(clippy::new_without_default)]
pub fn new() -> NPCTable {
NPCTable {
entries: Vec::new(),
tileset_name: "Stage/Prt0".to_owned(),
tex_npc1_name: "Npc/Npc0".to_owned(),
tex_npc2_name: "Npc/Npc0".to_owned(),
}
NPCTable { entries: Vec::new(), stage_textures: Rc::new(RefCell::new(StageTexturePaths::new())) }
}
pub fn load_from<R: io::Read>(mut data: R) -> GameResult<NPCTable> {
@ -860,26 +859,58 @@ impl NPCTable {
}
}
pub fn get_texture_name(&self, spritesheet_id: u16) -> &str {
pub fn get_texture_ref(&self, spritesheet_id: u16) -> TexRef<'_> {
match spritesheet_id {
0 => "Title",
2 => &self.tileset_name,
6 => "Fade",
8 => "ItemImage",
11 => "Arms",
12 => "ArmsImage",
14 => "StageImage",
15 => "Loading",
16 => "MyChar",
17 => "Bullet",
19 => "Caret",
20 => "Npc/NpcSym",
21 => &self.tex_npc1_name,
22 => &self.tex_npc2_name,
23 => "Npc/NpcRegu",
26 => "TextBox",
27 => "Face",
_ => "Npc/Npc0",
0 => TexRef::from_str("Title"),
2 => TexRef { variant: TexRefVariant::StageTileset(self.stage_textures.deref().borrow()) },
6 => TexRef::from_str("Fade"),
8 => TexRef::from_str("ItemImage"),
11 => TexRef::from_str("Arms"),
12 => TexRef::from_str("ArmsImage"),
14 => TexRef::from_str("StageImage"),
15 => TexRef::from_str("Loading"),
16 => TexRef::from_str("MyChar"),
17 => TexRef::from_str("Bullet"),
19 => TexRef::from_str("Caret"),
20 => TexRef::from_str("Npc/NpcSym"),
21 => TexRef { variant: TexRefVariant::StageNPC1(self.stage_textures.deref().borrow()) },
22 => TexRef { variant: TexRefVariant::StageNPC2(self.stage_textures.deref().borrow()) },
23 => TexRef::from_str("Npc/NpcRegu"),
26 => TexRef::from_str("TextBox"),
27 => TexRef::from_str("Face"),
_ => TexRef::from_str("Npc/Npc0"),
}
}
}
pub struct TexRef<'a> {
variant: TexRefVariant<'a>,
}
enum TexRefVariant<'a> {
Str(&'static str),
StageTileset(Ref<'a, StageTexturePaths>),
StageNPC1(Ref<'a, StageTexturePaths>),
StageNPC2(Ref<'a, StageTexturePaths>),
}
impl TexRef<'_> {
#[inline]
fn from_str(str: &'static str) -> TexRef {
TexRef { variant: TexRefVariant::Str(str) }
}
}
impl Deref for TexRef<'_> {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
match &self.variant {
TexRefVariant::Str(str) => str,
TexRefVariant::StageTileset(paths) => &paths.tileset_fg,
TexRefVariant::StageNPC1(paths) => &paths.npc1,
TexRefVariant::StageNPC2(paths) => &paths.npc2,
}
}
}

View file

@ -868,7 +868,7 @@ impl GameEntity<&NPCList> for Player {
let vec_y = 0x1400;
if let Some(entry) = state.npc_table.get_entry(136) {
let sprite = state.npc_table.get_texture_name(entry.spritesheet_id as u16);
let sprite = &*state.npc_table.get_texture_ref(entry.spritesheet_id as u16);
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, sprite)?;
let (off_x, frame_id) = if self.direction == Direction::Left {

View file

@ -1,9 +1,11 @@
use std::ops::Range;
use std::cell::RefCell;
use std::ops::{Deref, Range};
use std::rc::Rc;
use log::info;
use crate::caret::CaretType;
use crate::common::{Color, Direction, FadeDirection, FadeState, interpolate_fix9_scale, Rect};
use crate::common::{interpolate_fix9_scale, Color, Direction, FadeDirection, FadeState, Rect};
use crate::components::boss_life_bar::BossLifeBar;
use crate::components::credits::Credits;
use crate::components::draw_common::Alignment;
@ -12,35 +14,36 @@ use crate::components::flash::Flash;
use crate::components::hud::HUD;
use crate::components::inventory::InventoryUI;
use crate::components::stage_select::StageSelect;
use crate::components::tilemap::{TileLayer, Tilemap};
use crate::components::water_renderer::WaterRenderer;
use crate::entity::GameEntity;
use crate::frame::{Frame, UpdateTarget};
use crate::framework::{filesystem, graphics};
use crate::framework::backend::SpriteBatchCommand;
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::framework::graphics::{BlendMode, draw_rect, FilterMode};
use crate::framework::graphics::{draw_rect, BlendMode, FilterMode};
use crate::framework::ui::Components;
use crate::framework::{filesystem, graphics};
use crate::input::touch_controls::TouchControlType;
use crate::inventory::{Inventory, TakeExperienceResult};
use crate::map::WaterParams;
use crate::npc::{NPC, NPCLayer};
use crate::npc::boss::BossNPC;
use crate::npc::list::NPCList;
use crate::physics::{OFFSETS, PhysicalEntity};
use crate::npc::{NPCLayer, NPC};
use crate::physics::{PhysicalEntity, OFFSETS};
use crate::player::{Player, TargetPlayer};
use crate::rng::XorShift;
use crate::scene::Scene;
use crate::scene::title_scene::TitleScene;
use crate::scene::Scene;
use crate::scripting::tsc::credit_script::CreditScriptVM;
use crate::scripting::tsc::text_script::{
ConfirmSelection, ScriptMode, TextScriptExecutionState, TextScriptLine, TextScriptVM,
};
use crate::shared_game_state::{SharedGameState, TileSize};
use crate::stage::{BackgroundType, Stage};
use crate::stage::{BackgroundType, Stage, StageTexturePaths};
use crate::texture_set::SpriteBatch;
use crate::weapon::{Weapon, WeaponType};
use crate::weapon::bullet::BulletManager;
use crate::weapon::{Weapon, WeaponType};
pub struct GameScene {
pub tick: u32,
@ -55,6 +58,7 @@ pub struct GameScene {
pub inventory_ui: InventoryUI,
pub hud_player1: HUD,
pub hud_player2: HUD,
pub tilemap: Tilemap,
pub frame: Frame,
pub player1: Player,
pub player2: Player,
@ -66,23 +70,12 @@ pub struct GameScene {
pub bullet_manager: BulletManager,
pub lighting_mode: LightingMode,
pub intro_mode: bool,
tex_background_name: String,
tex_tileset_name: String,
tex_tileset_name_mg: String,
tex_tileset_name_bg: String,
pub stage_textures: Rc<RefCell<StageTexturePaths>>,
map_name_counter: u16,
skip_counter: u16,
inventory_dim: f32,
}
#[derive(Debug, EnumIter, PartialEq, Eq, Hash, Copy, Clone)]
pub enum TileLayer {
Background,
Middleground,
Foreground,
Snack,
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum LightingMode {
None,
@ -113,9 +106,9 @@ impl GameScene {
water_renderer.initialize(stage.map.find_water_regions());
}
let tex_background_name = stage.data.background.filename();
let (tex_tileset_name, tex_tileset_name_mg, tex_tileset_name_bg) =
if let Some(pxpack_data) = stage.data.pxpack_data.as_ref() {
let stage_textures = {
let 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("");
@ -127,6 +120,12 @@ impl GameScene {
(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 {
tick: 0,
stage,
@ -144,6 +143,7 @@ impl GameScene {
inventory_ui: InventoryUI::new(),
hud_player1: HUD::new(Alignment::Left),
hud_player2: HUD::new(Alignment::Right),
tilemap: Tilemap::new(),
frame: Frame {
x: 0,
y: 0,
@ -160,10 +160,7 @@ impl GameScene {
bullet_manager: BulletManager::new(),
lighting_mode: LightingMode::None,
intro_mode: false,
tex_background_name,
tex_tileset_name,
tex_tileset_name_mg,
tex_tileset_name_bg,
stage_textures,
map_name_counter: 0,
skip_counter: 0,
inventory_dim: 0.0,
@ -188,7 +185,11 @@ impl GameScene {
}
fn draw_background(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_background_name)?;
let batch = state.texture_set.get_or_load_batch(
ctx,
&state.constants,
&self.stage_textures.deref().borrow().background,
)?;
let scale = state.scale;
let (frame_x, frame_y) = self.frame.xy_interpolated(state.frame_time);
@ -510,12 +511,7 @@ impl GameScene {
}
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,
);
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::from_rgb(0, 0, 0))?;
}
@ -1319,149 +1315,6 @@ impl GameScene {
Ok(())
}
fn draw_tiles(&self, state: &mut SharedGameState, ctx: &mut Context, layer: TileLayer) -> GameResult {
if state.tile_size == TileSize::Tile8x8 && layer == TileLayer::Snack {
return Ok(());
}
let tex = match layer {
TileLayer::Snack => "Npc/NpcSym",
TileLayer::Background => &self.tex_tileset_name_bg,
TileLayer::Middleground => &self.tex_tileset_name_mg,
TileLayer::Foreground => &self.tex_tileset_name,
};
let (layer_offset, layer_width, layer_height, uses_layers) =
if let Some(pxpack_data) = self.stage.data.pxpack_data.as_ref() {
match layer {
TileLayer::Background => {
(pxpack_data.offset_bg as usize, pxpack_data.size_bg.0, pxpack_data.size_bg.1, true)
}
TileLayer::Middleground => {
(pxpack_data.offset_mg as usize, pxpack_data.size_mg.0, pxpack_data.size_mg.1, true)
}
_ => (0, pxpack_data.size_fg.0, pxpack_data.size_fg.1, true),
}
} else {
(0, self.stage.map.width, self.stage.map.height, false)
};
if !uses_layers && layer == TileLayer::Middleground {
return Ok(());
}
let tile_size = state.tile_size.as_int();
let tile_sizef = state.tile_size.as_float();
let halft = tile_size / 2;
let halftf = tile_sizef / 2.0;
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, tex)?;
let mut rect = Rect::new(0, 0, tile_size as u16, tile_size as u16);
let (mut frame_x, mut frame_y) = self.frame.xy_interpolated(state.frame_time);
if let Some(pxpack_data) = self.stage.data.pxpack_data.as_ref() {
let (fx, fy) = match layer {
TileLayer::Background => pxpack_data.scroll_bg.transform_camera_pos(frame_x, frame_y),
TileLayer::Middleground => pxpack_data.scroll_mg.transform_camera_pos(frame_x, frame_y),
_ => pxpack_data.scroll_fg.transform_camera_pos(frame_x, frame_y),
};
frame_x = fx;
frame_y = fy;
}
let tile_start_x = (frame_x as i32 / tile_size).clamp(0, layer_width as i32) as usize;
let tile_start_y = (frame_y as i32 / tile_size).clamp(0, layer_height as i32) as usize;
let tile_end_x =
((frame_x as i32 + 8 + state.canvas_size.0 as i32) / tile_size + 1).clamp(0, layer_width as i32) as usize;
let tile_end_y = ((frame_y as i32 + halft + state.canvas_size.1 as i32) / tile_size + 1)
.clamp(0, layer_height as i32) as usize;
if layer == TileLayer::Snack {
rect = state.constants.world.snack_rect;
}
for y in tile_start_y..tile_end_y {
for x in tile_start_x..tile_end_x {
let tile = *self.stage.map.tiles.get((y * layer_width as usize) + x + layer_offset).unwrap();
match layer {
_ if uses_layers => {
if tile == 0 {
continue;
}
let tile_size = tile_size as u16;
rect.left = (tile as u16 % 16) * tile_size;
rect.top = (tile as u16 / 16) * tile_size;
rect.right = rect.left + tile_size;
rect.bottom = rect.top + tile_size;
}
TileLayer::Background => {
if self.stage.map.attrib[tile as usize] >= 0x20 {
continue;
}
let tile_size = tile_size as u16;
rect.left = (tile as u16 % 16) * tile_size;
rect.top = (tile as u16 / 16) * tile_size;
rect.right = rect.left + tile_size;
rect.bottom = rect.top + tile_size;
}
TileLayer::Foreground => {
let attr = self.stage.map.attrib[tile as usize];
if attr < 0x40 || attr >= 0x80 || attr == 0x43 {
continue;
}
let tile_size = tile_size as u16;
rect.left = (tile as u16 % 16) * tile_size;
rect.top = (tile as u16 / 16) * tile_size;
rect.right = rect.left + tile_size;
rect.bottom = rect.top + tile_size;
}
TileLayer::Snack => {
if self.stage.map.attrib[tile as usize] != 0x43 {
continue;
}
}
_ => {}
}
batch.add_rect(
(x as f32 * tile_sizef - halftf) - frame_x,
(y as f32 * tile_sizef - halftf) - frame_y,
&rect,
);
}
}
batch.draw(ctx)?;
if layer == TileLayer::Foreground && self.stage.data.background_type == BackgroundType::Water {
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_background_name)?;
let rect_top = Rect { left: 0, top: 0, right: 32, bottom: 16 };
let rect_middle = Rect { left: 0, top: 16, right: 32, bottom: 48 };
let tile_start_x = frame_x as i32 / 32;
let tile_end_x = (frame_x + 16.0 + state.canvas_size.0) as i32 / 32 + 1;
let water_y = state.water_level as f32 / 512.0;
let tile_count_y = (frame_y + 16.0 + state.canvas_size.1 - water_y) as i32 / 32 + 1;
for x in tile_start_x..tile_end_x {
batch.add_rect((x as f32 * 32.0) - frame_x, water_y - frame_y, &rect_top);
for y in 0..tile_count_y {
batch.add_rect((x as f32 * 32.0) - frame_x, (y as f32 * 32.0) + water_y - frame_y, &rect_middle);
}
}
batch.draw(ctx)?;
}
Ok(())
}
fn tick_npc_bullet_collissions(&mut self, state: &mut SharedGameState) {
for npc in self.npc_list.iter_alive() {
if npc.npc_flags.shootable() && npc.npc_flags.interactable() {
@ -1935,9 +1788,7 @@ impl Scene for GameScene {
self.npc_list.spawn_at_slot(npc_data.id, npc)?;
}
state.npc_table.tileset_name = self.tex_tileset_name.to_owned();
state.npc_table.tex_npc1_name = ["Npc/", &self.stage.data.npc1.filename()].join("");
state.npc_table.tex_npc2_name = ["Npc/", &self.stage.data.npc2.filename()].join("");
state.npc_table.stage_textures = self.stage_textures.clone();
/*if state.constants.is_cs_plus {
match state.season {
@ -2154,9 +2005,10 @@ impl Scene for GameScene {
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
//graphics::set_canvas(ctx, Some(&state.game_canvas));
self.draw_background(state, ctx)?;
self.draw_tiles(state, ctx, TileLayer::Background)?;
let stage_textures_ref = &*self.stage_textures.deref().borrow();
self.tilemap.draw(state, ctx, &self.frame, TileLayer::Background, stage_textures_ref, &self.stage)?;
self.draw_npc_layer(state, ctx, NPCLayer::Background)?;
self.draw_tiles(state, ctx, TileLayer::Middleground)?;
self.tilemap.draw(state, ctx, &self.frame, TileLayer::Middleground, stage_textures_ref, &self.stage)?;
if state.settings.shader_effects && self.lighting_mode == LightingMode::BackgroundOnly {
self.draw_light_map(state, ctx)?;
@ -2169,8 +2021,9 @@ impl Scene for GameScene {
self.player1.draw(state, ctx, &self.frame)?;
self.water_renderer.draw(state, ctx, &self.frame)?;
self.draw_tiles(state, ctx, TileLayer::Foreground)?;
self.draw_tiles(state, ctx, TileLayer::Snack)?;
self.tilemap.draw(state, ctx, &self.frame, TileLayer::Foreground, stage_textures_ref, &self.stage)?;
self.tilemap.draw(state, ctx, &self.frame, TileLayer::Snack, stage_textures_ref, &self.stage)?;
self.draw_carets(state, ctx)?;
self.player1.popup.draw(state, ctx, &self.frame)?;
self.player2.popup.draw(state, ctx, &self.frame)?;

View file

@ -5,6 +5,7 @@ use byteorder::LE;
use byteorder::ReadBytesExt;
use log::info;
use crate::common::Color;
use crate::encoding::read_cur_shift_jis;
use crate::engine_constants::EngineConstants;
use crate::framework::context::Context;
@ -13,7 +14,6 @@ use crate::framework::error::GameResult;
use crate::framework::filesystem;
use crate::map::{Map, NPCData};
use crate::scripting::tsc::text_script::TextScript;
use crate::common::Color;
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct NpcType {
@ -175,7 +175,7 @@ impl PxPackScroll {
PxPackScroll::HThreeQuarters => (x * 0.75, y),
PxPackScroll::HHalf => (x * 0.5, y),
PxPackScroll::HQuarter => (x * 0.25, y),
PxPackScroll::V0Half => (x, y) // ???
PxPackScroll::V0Half => (x, y), // ???
}
}
}
@ -577,3 +577,36 @@ impl Stage {
false
}
}
pub struct StageTexturePaths {
/// Path to the stage's background texture.
pub background: String,
/// Path to the stage's foreground tileset texture.
pub tileset_fg: String,
/// Path to the stage's middleground tileset texture.
pub tileset_mg: String,
/// Path to the stage's background tileset texture.
pub tileset_bg: String,
/// Path to the stage's NPC spritesheet 1.
pub npc1: String,
/// Path to the stage's NPC spritesheet 2.
pub npc2: String,
}
impl StageTexturePaths {
pub fn new() -> StageTexturePaths {
StageTexturePaths {
background: "bk0".to_string(),
tileset_fg: "Stage/Prt0".to_owned(),
tileset_mg: "Stage/Prt0".to_owned(),
tileset_bg: "Stage/Prt0".to_owned(),
npc1: "Npc/Npc0".to_owned(),
npc2: "Npc/Npc0".to_owned(),
}
}
}