diff --git a/src/camera.rs b/src/camera.rs index 412479b..db9d9b6 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -7,7 +7,20 @@ use super::data::prelude::*; const SHOW_BOUNDARIES: bool = false; -pub fn get_screen_bounds(ecs: &World) -> (i32, i32, i32, i32, i32, i32) { +pub fn get_offset() -> (i32, i32) { + return (1, 10); +} + +pub struct ScreenBounds { + pub min_x: i32, + pub max_x: i32, + pub min_y: i32, + pub max_y: i32, + pub x_offset: i32, + pub y_offset: i32, +} + +pub fn get_screen_bounds(ecs: &World) -> ScreenBounds { let player_pos = ecs.fetch::(); let map = ecs.fetch::(); let (x_chars, y_chars, mut x_offset, mut y_offset) = (VIEWPORT_W, VIEWPORT_H, 1, 10); @@ -30,7 +43,11 @@ pub fn get_screen_bounds(ecs: &World) -> (i32, i32, i32, i32, i32, i32) { let max_x = min_x + (x_chars as i32); let max_y = min_y + (y_chars as i32); - (min_x, max_x, min_y, max_y, x_offset, y_offset) + ScreenBounds { min_x, max_x, min_y, max_y, x_offset, y_offset } +} + +pub fn in_bounds(x: i32, y: i32, upper_x: i32, upper_y: i32) -> bool { + x >= 0 && x < upper_x && y >= 0 && y < upper_y } pub fn render_camera(ecs: &World, ctx: &mut BTerm) { @@ -64,7 +81,7 @@ pub fn render_camera(ecs: &World, ctx: &mut BTerm) { Rect::with_size(x * 16 + x_offset * 16, y * 16 + y_offset * 16, 16, 16), 0, tint, - id + 0 // Ya ); ctx.set_active_console(TILE_LAYER); } diff --git a/src/main.rs b/src/main.rs index 97b7739..060fe2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -146,18 +146,60 @@ fn setup(gfx: &mut Graphics) -> State { gs } +const ASCII_MODE: bool = false; // Change this to config setting +const SHOW_BOUNDARIES: bool = false; // Config setting +use notan::draw::Draw; +fn draw_camera(ecs: &World, draw: &mut Draw, atlas: &HashMap) { + let map = ecs.fetch::(); + let bounds = crate::camera::get_screen_bounds(ecs); + render_map_in_view(&*map, ecs, draw, bounds); +} + +use crate::camera::ScreenBounds; +fn render_map_in_view(map: &Map, ecs: &World, draw: &mut Draw, bounds: ScreenBounds) { + for tile_y in bounds.min_y..bounds.max_y { + for tile_x in bounds.min_x..bounds.max_x { + if crate::camera::in_bounds(tile_x, tile_y, map.width, map.height) { + let idx = map.xy_idx(tile_x, tile_y); + if map.revealed_tiles[idx] { + if ASCII_MODE { + let (glyph, fg, bg) = crate::map::themes::get_tile_renderables_for_id( + idx, + &*map, + Some(*ecs.fetch::()), + None + ); + // TODO: Draw ASCII + } else { + let (id, tint) = crate::map::themes::get_sprite_for_id( + idx, + &*map, + Some(*ecs.fetch::()) + ); + let px = idx_to_px( + map.xy_idx(tile_x + bounds.x_offset, tile_y + bounds.y_offset), + &map + ); + draw.image(atlas.get(id).unwrap()).position(px.0, px.1); + } + } + } else if SHOW_BOUNDARIES { + // TODO: Draw boundaries + } + } + } +} fn draw(app: &mut App, gfx: &mut Graphics, gs: &mut State) { let mut draw = gfx.create_draw(); draw.clear(Color::BLACK); // Draw map + draw_camera(&gs.ecs, &mut draw, &gs.atlas); + // Draw player (replace this with draw entities). let map = gs.ecs.fetch::(); - for (i, _tile) in map.tiles.iter().enumerate() { - let px = idx_to_px(i, &map); - draw.image(gs.atlas.get("floor_grass_d").unwrap()).position(px.0, px.1); - } let ppos = gs.ecs.fetch::(); - let px = idx_to_px(map.xy_idx(ppos.x, ppos.y), &map); + let offsets = crate::camera::get_offset(); + let px = idx_to_px(map.xy_idx(ppos.x + offsets.0, ppos.y + offsets.1), &map); draw.image(gs.atlas.get("ui_heart_full").unwrap()).position(px.0, px.1); // Render batch gfx.render(&draw); diff --git a/src/map/themes.rs b/src/map/themes.rs index bd6fcf3..92ee89b 100644 --- a/src/map/themes.rs +++ b/src/map/themes.rs @@ -5,21 +5,21 @@ use crate::data::ids::*; use bracket_lib::prelude::*; use std::ops::{ Add, Mul }; -pub fn get_sprite_for_id(idx: usize, map: &Map, other_pos: Option) -> (usize, RGBA) { +pub fn get_sprite_for_id(idx: usize, map: &Map, other_pos: Option) -> (&str, RGBA) { let x = (idx as i32) % map.width; let y = (idx as i32) / map.width; - let tile = map.tiles[idx]; - let base = match tile { + let sprite = map.tiles[idx].sprite(); + /*let base = match tile { TileType::Wall => wall_sprite(tile.sprite(), map, x, y), _ => tile.sprite(), }; - let sprite_id = pick_variant(base, tile.variants(), idx, map); + let sprite_id = pick_variant(base, tile.variants(), idx, map);*/ let tint = if !map.visible_tiles[idx] { RGBA::from_f32(0.75, 0.75, 0.75, 1.0) } else { RGBA::named(WHITE) }; - return (sprite_id, tint); + return (sprite, tint); } /// Gets the renderables for a tile, with darkening/offset/post-processing/etc. Passing a val for "debug" will ignore viewshed. pub fn get_tile_renderables_for_id( diff --git a/src/map/tiletype.rs b/src/map/tiletype.rs index beb483c..e07d324 100644 --- a/src/map/tiletype.rs +++ b/src/map/tiletype.rs @@ -30,27 +30,27 @@ pub enum TileType { } impl TileType { - pub fn sprite(&self) -> usize { + pub fn sprite(&self) -> &str { match self { - TileType::ImpassableMountain => STATUE, - TileType::Wall => WALL_BASE, - TileType::DeepWater => WATER_DEEP, - TileType::Fence => WALL_BASE, - TileType::Bars => WALL_BASE, - TileType::Floor => FLOOR, - TileType::WoodFloor => FLOOR_WOOD, - TileType::Gravel => FLOOR, - TileType::Road => PATH_GRASS, - TileType::Grass => FLOOR_GRASS, - TileType::Foliage => FLOOR_GRASS, - TileType::HeavyFoliage => FLOOR_GRASS, - TileType::Sand => FLOOR, - TileType::ShallowWater => WATER_DEEP, - TileType::Bridge => FLOOR, - TileType::DownStair => STAIR_D, - TileType::UpStair => STAIR_A, - TileType::ToLocal(_) => MUSHROOM, - TileType::ToOvermap(_) => MUSHROOM_ORANGE, + TileType::ImpassableMountain => "statue_warrior", + TileType::Wall => "wall_cave_h_a", + TileType::DeepWater => "water", + TileType::Fence => "wall_cave_h_a", + TileType::Bars => "wall_cave_h_a", + TileType::Floor => "floor_cobble_a", + TileType::WoodFloor => "floor_wood_a", + TileType::Gravel => "floor_cobble_b", + TileType::Road => "floor_cobble_c", + TileType::Grass => "floor_grass_a", + TileType::Foliage => "floor_grass_b", + TileType::HeavyFoliage => "floor_grass_c", + TileType::Sand => "floor_cobble_c", + TileType::ShallowWater => "water", + TileType::Bridge => "floor_cobble_a", + TileType::DownStair => "wall_cave_stair_down", + TileType::UpStair => "wall_cave_stair_up", + TileType::ToLocal(_) => "wall_crypt_stair_down", + TileType::ToOvermap(_) => "wall_crypt_stair_up", } } diff --git a/src/player.rs b/src/player.rs index 422b4ad..306ec64 100644 --- a/src/player.rs +++ b/src/player.rs @@ -40,6 +40,8 @@ use std::cmp::{ max, min }; use crate::data::events::*; use crate::data::ids::*; use crate::gui::with_article; +use notan::prelude::*; +use std::collections::HashMap; pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState { let mut positions = ecs.write_storage::(); @@ -645,195 +647,117 @@ fn get_item(ecs: &mut World) -> RunState { } } -use notan::prelude::*; +fn try_descend(ecs: &mut World) -> RunState { + let dest = try_change_level(ecs, false); + let curr_map_id = ecs.fetch::().id; + return match dest { + Destination::None => RunState::AwaitingInput, + Destination::NextLevel => RunState::GoToLevel(curr_map_id + 1, TileType::UpStair), + Destination::PreviousLevel => RunState::GoToLevel(curr_map_id - 1, TileType::DownStair), + Destination::ToLocal(id) => RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)), + Destination::ToOvermap(id) => RunState::GoToLevel(id, TileType::ToOvermap(id)), + }; +} +fn try_ascend(ecs: &mut World) -> RunState { + let dest = try_change_level(ecs, true); + let curr_map_id = ecs.fetch::().id; + return match dest { + Destination::None => RunState::AwaitingInput, + Destination::NextLevel => RunState::GoToLevel(curr_map_id + 1, TileType::UpStair), + Destination::PreviousLevel => RunState::GoToLevel(curr_map_id - 1, TileType::DownStair), + Destination::ToLocal(id) => RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)), + Destination::ToOvermap(id) => RunState::GoToLevel(id, TileType::ToOvermap(id)), + }; +} + pub fn player_input(gs: &mut State, ctx: &mut App, on_overmap: bool) -> RunState { let key = &ctx.keyboard; - if key.was_pressed(KeyCode::Numpad4) { - return try_move_player(-1, 0, &mut gs.ecs); - } else if key.was_pressed(KeyCode::Numpad6) { - return try_move_player(1, 0, &mut gs.ecs); - } else if key.was_pressed(KeyCode::Numpad8) { - return try_move_player(0, -1, &mut gs.ecs); - } else if key.was_pressed(KeyCode::Numpad2) { - return try_move_player(0, 1, &mut gs.ecs); - } else if key.was_pressed(KeyCode::Numpad9) { - return try_move_player(1, -1, &mut gs.ecs); - } else if key.was_pressed(KeyCode::Numpad7) { - return try_move_player(-1, -1, &mut gs.ecs); - } else if key.was_pressed(KeyCode::Numpad3) { - return try_move_player(1, 1, &mut gs.ecs); - } else if key.was_pressed(KeyCode::Numpad1) { - return try_move_player(-1, 1, &mut gs.ecs); - } else if key.was_pressed(KeyCode::Period) { - if key.shift() { - let dest = try_change_level(&mut gs.ecs, false); - let curr_map_id = gs.ecs.fetch::().id; - return match dest { - // If we have no destination, do nothing. - Destination::None => RunState::AwaitingInput, - // If we want to go to the next level, go to the up-stair tile of id + 1. - Destination::NextLevel => RunState::GoToLevel(curr_map_id + 1, TileType::UpStair), - // If we want to go to the previous level, go to the down-stair tile of id - 1. - Destination::PreviousLevel => - RunState::GoToLevel(curr_map_id - 1, TileType::DownStair), - Destination::ToLocal(id) => RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)), - Destination::ToOvermap(id) => RunState::GoToLevel(id, TileType::ToOvermap(id)), - }; - } else { - return skip_turn(&mut gs.ecs); // (Wait a turn) - } - } else if key.was_pressed(KeyCode::Comma) { - if key.shift() { - let dest = try_change_level(&mut gs.ecs, false); - let curr_map_id = gs.ecs.fetch::().id; - return match dest { - // If we have no destination, do nothing. - Destination::None => RunState::AwaitingInput, - // If we want to go to the next level, go to the up-stair tile of id + 1. - Destination::NextLevel => RunState::GoToLevel(curr_map_id + 1, TileType::UpStair), - // If we want to go to the previous level, go to the down-stair tile of id - 1. - Destination::PreviousLevel => - RunState::GoToLevel(curr_map_id - 1, TileType::DownStair), - Destination::ToLocal(id) => RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)), - Destination::ToOvermap(id) => RunState::GoToLevel(id, TileType::ToOvermap(id)), - }; - } else { - return skip_turn(&mut gs.ecs); // (Wait a turn) + // Movement + for keycode in key.pressed.iter() { + match *keycode { + KeyCode::Numpad1 | KeyCode::B => { + return try_move_player(-1, 1, &mut gs.ecs); + } + KeyCode::Numpad2 | KeyCode::Down | KeyCode::J => { + return try_move_player(0, 1, &mut gs.ecs); + } + KeyCode::Numpad3 | KeyCode::N => { + return try_move_player(1, 1, &mut gs.ecs); + } + KeyCode::Numpad4 | KeyCode::Left | KeyCode::H => { + return try_move_player(-1, 0, &mut gs.ecs); + } + KeyCode::Numpad6 | KeyCode::Right | KeyCode::L => { + return try_move_player(1, 0, &mut gs.ecs); + } + KeyCode::Numpad7 | KeyCode::Y => { + return try_move_player(-1, -1, &mut gs.ecs); + } + KeyCode::Numpad8 | KeyCode::Up | KeyCode::K => { + return try_move_player(0, -1, &mut gs.ecs); + } + KeyCode::Numpad9 | KeyCode::U => { + return try_move_player(1, -1, &mut gs.ecs); + } + KeyCode::Period => { + if key.shift() { + return try_descend(&mut gs.ecs); + } + return skip_turn(&mut gs.ecs); + } + KeyCode::Comma => { + if key.shift() { + return try_ascend(&mut gs.ecs); + } + } + KeyCode::Slash => { + if key.shift() { + return RunState::HelpScreen; + } + } + KeyCode::C => { + if !on_overmap { + return RunState::ActionWithDirection { function: try_door }; + } + } + KeyCode::O => { + if !on_overmap { + return RunState::ActionWithDirection { function: open }; + } + } + KeyCode::F => { + if !on_overmap { + return RunState::ActionWithDirection { function: kick }; + } + } + KeyCode::G => { + return get_item(&mut gs.ecs); + } + KeyCode::I => { + return RunState::ShowInventory; + } + KeyCode::D => { + return RunState::ShowDropItem; + } + KeyCode::R => { + return RunState::ShowRemoveItem; + } + KeyCode::Minus => { + return RunState::ShowCheatMenu; + } + KeyCode::Escape => { + return RunState::SaveGame; + } + KeyCode::X => { + let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) = get_screen_bounds(&gs.ecs); + let ppos = gs.ecs.fetch::(); + let (x, y) = (ppos.x + x_offset - min_x, ppos.y + y_offset - min_y); + return RunState::Farlook { x, y }; + } + _ => {} } } return RunState::AwaitingInput; - - /*match ctx.key { - None => { - return RunState::AwaitingInput; - } - Some(key) => - match key { - // Cardinals - VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => { - return try_move_player(-1, 0, &mut gs.ecs); - } - VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => { - return try_move_player(1, 0, &mut gs.ecs); - } - VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => { - return try_move_player(0, -1, &mut gs.ecs); - } - VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => { - return try_move_player(0, 1, &mut gs.ecs); - } - // Diagonals - VirtualKeyCode::Numpad9 | VirtualKeyCode::U => { - return try_move_player(1, -1, &mut gs.ecs); - } - VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => { - return try_move_player(-1, -1, &mut gs.ecs); - } - VirtualKeyCode::Numpad3 | VirtualKeyCode::N => { - return try_move_player(1, 1, &mut gs.ecs); - } - VirtualKeyCode::Numpad1 | VirtualKeyCode::B => { - return try_move_player(-1, 1, &mut gs.ecs); - } - // id - VirtualKeyCode::Period => { - if ctx.shift { - let dest = try_change_level(&mut gs.ecs, false); - let curr_map_id = gs.ecs.fetch::().id; - return match dest { - // If we have no destination, do nothing. - Destination::None => RunState::AwaitingInput, - // If we want to go to the next level, go to the up-stair tile of id + 1. - Destination::NextLevel => - RunState::GoToLevel(curr_map_id + 1, TileType::UpStair), - // If we want to go to the previous level, go to the down-stair tile of id - 1. - Destination::PreviousLevel => - RunState::GoToLevel(curr_map_id - 1, TileType::DownStair), - Destination::ToLocal(id) => - RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)), - Destination::ToOvermap(id) => - RunState::GoToLevel(id, TileType::ToOvermap(id)), - }; - } else { - return skip_turn(&mut gs.ecs); // (Wait a turn) - } - } - VirtualKeyCode::Comma => { - if ctx.shift { - let dest = try_change_level(&mut gs.ecs, true); - let curr_map_id = gs.ecs.fetch::().id; - return match dest { - Destination::None => RunState::AwaitingInput, - Destination::NextLevel => - RunState::GoToLevel(curr_map_id + 1, TileType::UpStair), - Destination::PreviousLevel => - RunState::GoToLevel(curr_map_id - 1, TileType::DownStair), - Destination::ToLocal(id) => - RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)), - Destination::ToOvermap(id) => - RunState::GoToLevel(id, TileType::ToOvermap(id)), - }; - } - } - VirtualKeyCode::Slash => { - if ctx.shift { - return RunState::HelpScreen; - } - } - VirtualKeyCode::NumpadDecimal => { - return skip_turn(&mut gs.ecs); - } - - // Items - VirtualKeyCode::C => { - if !on_overmap { - return RunState::ActionWithDirection { function: try_door }; - } - } - VirtualKeyCode::O => { - if !on_overmap { - return RunState::ActionWithDirection { function: open }; - } - } - VirtualKeyCode::F => { - if !on_overmap { - return RunState::ActionWithDirection { function: kick }; - } - } - VirtualKeyCode::G => { - return get_item(&mut gs.ecs); - } - VirtualKeyCode::I => { - return RunState::ShowInventory; - } - VirtualKeyCode::D => { - return RunState::ShowDropItem; - } - VirtualKeyCode::R => { - return RunState::ShowRemoveItem; - } - // Other - VirtualKeyCode::Minus => { - return RunState::ShowCheatMenu; - } - VirtualKeyCode::Escape => { - return RunState::SaveGame; - } - VirtualKeyCode::X => { - let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) = get_screen_bounds( - &gs.ecs, - ctx - ); - let ppos = gs.ecs.fetch::(); - let (x, y) = (ppos.x + x_offset - min_x, ppos.y + y_offset - min_y); - return RunState::Farlook { x, y }; - } - _ => { - return RunState::AwaitingInput; - } - } - } - return RunState::AwaitingInput;*/ } fn try_change_level(ecs: &mut World, backtracking: bool) -> Destination { diff --git a/src/states/state.rs b/src/states/state.rs index 1a212a8..5c99206 100644 --- a/src/states/state.rs +++ b/src/states/state.rs @@ -296,6 +296,8 @@ impl State { } damage_system::delete_the_dead(&mut self.ecs); } + + // Deprecated fn tick(&mut self, ctx: &mut BTerm) { let mut new_runstate; {