HGQBLQKZ52X34DL7DTPIHWVGO7MPIEPLN7B6IFDU2BBQVGOD7GCQC mod player_input;use crate::prelude::*;pub fn build_scheduler () -> Schedule {Schedule::builder().build()}
use crate::prelude::*;pub fn spawn_player (ecs: &mut World, pos: Point) {ecs.push((Player,pos,Render {color: ColorPair::new(WHITE, BLACK),glyph: to_cp437('@')}));}
use crate::prelude::*;const NUM_ROOMS: usize = 20;pub struct MapBuilder {pub map : Map,pub rooms : Vec<Rect>,pub player_start : Point,}impl MapBuilder {pub fn new(rng: &mut RandomNumberGenerator) -> Self {let mut mb = MapBuilder{map : Map::new(),rooms : Vec::new(),player_start : Point::zero(),};mb.fill(TileType::Wall);mb.build_random_rooms(rng);mb.build_corridors(rng);mb.player_start = mb.rooms[0].center();// (1)mb}fn fill(&mut self, tile : TileType) {self.map.tiles.iter_mut().for_each(|t| *t = tile);}fn build_random_rooms(&mut self, rng : &mut RandomNumberGenerator) {// (2)while self.rooms.len() < NUM_ROOMS {// (3)let room = Rect::with_size(// (4)rng.range(1, SCREEN_WIDTH - 10),rng.range(1, SCREEN_HEIGHT - 10),rng.range(2, 10),rng.range(2, 10),);let mut overlap = false;// (5)for r in self.rooms.iter() {if r.intersect(&room) {overlap = true;}}if !overlap {// (6)room.for_each(|p| {if p.x > 0 && p.x < SCREEN_WIDTH && p.y > 0&& p.y < SCREEN_HEIGHT{let idx = map_idx(p.x, p.y);self.map.tiles[idx] = TileType::Floor;}});self.rooms.push(room)}}}fn apply_horizontal_tunnel(&mut self, x1:i32, x2:i32, y:i32) {use std::cmp::{min, max};for x in min(x1,x2) ..= max(x1,x2) {if let Some(idx) = self.map.try_idx(Point::new(x, y)) {self.map.tiles[idx as usize] = TileType::Floor;}}}fn apply_vertical_tunnel(&mut self, y1:i32, y2:i32, x:i32) {use std::cmp::{min, max};for y in min(y1,y2) ..= max(y1,y2) {if let Some(idx) = self.map.try_idx(Point::new(x, y)) {self.map.tiles[idx as usize] = TileType::Floor;}}}fn build_corridors(&mut self, rng: &mut RandomNumberGenerator) {let mut rooms = self.rooms.clone();rooms.sort_by(|a,b| a.center().x.cmp(&b.center().x));// (7)for (i, room) in rooms.iter().enumerate().skip(1) {// (8)let prev = rooms[i-1].center();// (9)let new = room.center();if rng.range(0,2) == 1 {// (10)self.apply_horizontal_tunnel(prev.x, new.x, prev.y);self.apply_vertical_tunnel(prev.y, new.y, new.x);} else {self.apply_vertical_tunnel(prev.y, new.y, prev.x);self.apply_horizontal_tunnel(prev.x, new.x, new.y);}}}}
use crate::prelude::*;const NUM_TILES: usize = (SCREEN_WIDTH * SCREEN_HEIGHT) as usize;#[derive(Copy, Clone, PartialEq)]pub enum TileType {Wall,Floor,}pub fn map_idx(x: i32, y: i32) -> usize {((y * SCREEN_WIDTH) + x) as usize}pub struct Map {pub tiles: Vec<TileType>,}impl Map {pub fn new() -> Self {Self {tiles: vec![TileType::Floor; NUM_TILES],}}pub fn in_bounds(&self, point : Point) -> bool {point.x >= 0 && point.x < SCREEN_WIDTH && point.y >= 0 && point.y < SCREEN_HEIGHT}pub fn try_idx(&self, point : Point) -> Option<usize> {if !self.in_bounds(point) {None} else {Some(map_idx(point.x, point.y))}}pub fn can_enter_tile(&self, point : Point) -> bool {self.in_bounds(point) && self.tiles[map_idx(point.x, point.y)]==TileType::Floor}pub fn render(&self, ctx: &mut BTerm, camera: &Camera) {// ctx.set_active_console(0);// for y in camera.top_y .. camera.bottom_y {// for x in camera.left_x .. camera.right_x {// if self.in_bounds(Point::new(x, y)) {// let idx = map_idx(x, y);// match self.tiles[idx] {// TileType::Floor => {// ctx.set(// x - camera.left_x,// y - camera.top_y,// WHITE,// BLACK,// to_cp437('.')// );// }// TileType::Wall => {// ctx.set(// x - camera.left_x,// y - camera.top_y,// WHITE,// BLACK,// to_cp437('#')// );// }// }// }// }// }}}
#![warn(clippy::pedantic)]mod map;mod map_builder;mod camera;mod components;mod spawner;mod systems;mod prelude {pub use bracket_lib::prelude::*;pub use legion::*;pub use legion::world::SubWorld;pub use legion::systems::CommandBuffer;pub const SCREEN_WIDTH: i32 = 80;pub const SCREEN_HEIGHT: i32 = 50;pub const DISPLAY_WIDTH: i32 = SCREEN_WIDTH / 2;pub const DISPLAY_HEIGHT: i32 = SCREEN_HEIGHT / 2;pub use crate::map::*;pub use crate::map_builder::*;pub use crate::camera::*;pub use crate::components::*;pub use crate::spawner::*;pub use crate::systems::*;}use prelude::*;struct State {ecs: World,resources: Resources,systems: Schedule}impl State {fn new () -> Self {let mut ecs = World::default();let mut resources = Resources::default();let mut rng = RandomNumberGenerator::new();let map_builder = MapBuilder::new(&mut rng);spawn_player(&mut ecs, map_builder.player_start);resources.insert(map_builder.map);resources.insert(Camera::new(map_builder.player_start));Self {ecs,resources,systems: build_scheduler()}}}impl GameState for State {fn tick (&mut self, ctx: &mut BTerm) {ctx.set_active_console(0);ctx.cls();ctx.set_active_console(1);ctx.cls();self.resources.insert(ctx.key);self.systems.execute(&mut self.ecs, &mut self.resources);}}fn main() -> BError {let context = BTermBuilder::new().with_title("Dungeon Crawler").with_fps_cap(30.0).with_dimensions(DISPLAY_WIDTH, DISPLAY_HEIGHT).with_tile_dimensions(32, 32).with_resource_path("resources/").with_font("dungeonfont.png", 32, 32).with_simple_console(DISPLAY_WIDTH, DISPLAY_HEIGHT, "dungeonfont.png").with_simple_console_no_bg(DISPLAY_WIDTH, DISPLAY_HEIGHT, "dungeonfont.png").build()?;main_loop(context, State::new())}
pub use crate::prelude::*;#[derive(Clone, Copy, Debug, PartialEq)]pub struct Render {pub color: ColorPair,pub glyph: FontCharType}#[derive(Clone, Copy, Debug, PartialEq)]pub struct Player;
use crate::prelude::*;pub struct Camera {pub left_x: i32,pub right_x: i32,pub top_y: i32,pub bottom_y: i32}impl Camera {pub fn new (player_position: Point) -> Self {Self {left_x: player_position.x - DISPLAY_WIDTH / 2,right_x: player_position.x + DISPLAY_WIDTH / 2,top_y: player_position.y - DISPLAY_HEIGHT / 2,bottom_y: player_position.y + DISPLAY_HEIGHT / 2}}pub fn on_player_move (&mut self, player_position: Point) {self.left_x = player_position.x - DISPLAY_WIDTH / 2;self.right_x = player_position.x + DISPLAY_WIDTH / 2;self.top_y = player_position.y - DISPLAY_HEIGHT / 2;self.bottom_y = player_position.y + DISPLAY_HEIGHT / 2;}}