mod world; mod state; mod events; mod time; mod generators; mod creature; mod site; mod ui; mod entity; mod game; mod item; use ui::App; use noise::{Perlin, ScalePoint, Add, NoiseFn, ScaleBias}; use noise::utils::{NoiseMapBuilder, PlaneMapBuilder}; use image::{RgbImage, Rgb}; use rand::prelude::*; use world::World; use std::{io}; use tui::{ backend::CrosstermBackend, Terminal }; use crossterm::{ event::{DisableMouseCapture, EnableMouseCapture}, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; const N_TOWNS: usize = 10; const WORLD_SIZE: usize = 256; struct BorderNoise { pub center: [f64; 2], pub radius: f64, pub falloff: f64, } impl BorderNoise { pub fn new(center: [f64; 2], radius: f64, falloff: f64) -> BorderNoise { BorderNoise { center: center, radius: radius, falloff: falloff } } } impl NoiseFn for BorderNoise { fn get(&self, _point: [f64; 2]) -> f64 { let dist = ( (self.center[0] - _point[0]).powi(2) + (self.center[1] - _point[1]).powi(2) ).sqrt(); if dist > self.radius { 1.0 - ((dist - self.radius) * self.falloff) } else { 1.0 } } } fn build_world() -> World { let mut rng = rand::thread_rng(); let map_center = WORLD_SIZE / 2; let height = Add::new( ScaleBias::new( Add::new( ScalePoint::new(Perlin::new(rng.gen::())) .set_x_scale(0.04) .set_y_scale(0.04), ScalePoint::new(Perlin::new(rng.gen::())) .set_x_scale(0.011) .set_y_scale(0.011), ), ).set_scale(2000.0).set_bias(1000.0), BorderNoise::new( [map_center as f64, map_center as f64], WORLD_SIZE as f64 * 0.4, 100.0 ), ); let plane = PlaneMapBuilder::<_, 2>::new(&height) .set_size(WORLD_SIZE, WORLD_SIZE) .set_x_bounds(0.0, WORLD_SIZE as f64) .set_y_bounds(0.0, WORLD_SIZE as f64) .build(); let mut img = RgbImage::new(WORLD_SIZE as u32, WORLD_SIZE as u32); let mut world = world::World::new(WORLD_SIZE); for x in 0..WORLD_SIZE { for y in 0..WORLD_SIZE { let h = plane.get_value(x, y); let t = world::Terrain::from_height(h); world.map[x][y] = world::WorldCell::new(t); img.put_pixel(x as u32, y as u32, Rgb(t.to_color())); } } world } fn main() -> Result<(), io::Error> { // build game state let mut world_state = state::GameState::new(build_world()); world_state.time = world_state.time.add_years(100); let mut rng = rand::thread_rng(); for _ in 0..N_TOWNS { world_state.time = world_state.time.add_days(rng.gen_range(0..360*3)); world_state.found_town(); } world_state.build_tavern(); // insert state into game let game = game::Game::new(world_state); // setup terminal enable_raw_mode()?; let mut stdout = io::stdout(); execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend)?; let mut app = App::new(game); loop { terminal.draw(|f| app.draw(f))?; if !app.step() { break; } // terminal.draw(|f| app.draw(f))?; } // restore terminal disable_raw_mode()?; execute!( terminal.backend_mut(), LeaveAlternateScreen, DisableMouseCapture )?; terminal.show_cursor()?; Ok(()) }