extern crate blit;
extern crate direct_gui;
extern crate minifb;
extern crate specs;
extern crate line_drawing;
extern crate rand;
extern crate cgmath;
extern crate collision;
#[macro_use]
extern crate specs_derive;
mod draw;
mod physics;
mod terrain;
mod projectile;
mod ai;
mod level;
mod geom;
mod gui;
use minifb::*;
use specs::{World, DispatcherBuilder, Join};
use std::time::{SystemTime, Duration};
use std::thread::sleep;
use std::collections::HashMap;
use draw::*;
use physics::*;
use terrain::*;
use projectile::*;
use ai::*;
use level::*;
use geom::*;
use gui::*;
const WIDTH: usize = 640;
const HEIGHT: usize = 320;
const GRAVITY: f64 = 98.1;
macro_rules! load_resource {
($resources:expr; $render:expr; sprite => $e:expr) => {{
$resources.insert($e.to_string(), $render.add_buf_from_memory($e, include_bytes!(concat!("../resources/sprites/", $e, ".png.blit"))))
}};
($resources:expr; $render:expr; mask => $e:expr) => {{
$resources.insert($e.to_string(), $render.add_buf_from_memory($e, include_bytes!(concat!("../resources/masks/", $e, ".png.blit"))))
}};
}
fn main() {
let mut buffer: Vec<u32> = vec![0; (WIDTH * HEIGHT) as usize];
let mut render = Render::new((WIDTH, HEIGHT));
let mut resources = HashMap::new();
load_resource!(resources; render; sprite => "ally-melee1");
load_resource!(resources; render; sprite => "ally-archer1");
load_resource!(resources; render; sprite => "enemy-melee1");
load_resource!(resources; render; sprite => "enemy-archer1");
load_resource!(resources; render; sprite => "projectile1");
load_resource!(resources; render; mask => "bighole1");
let mut world = World::new();
world.register::<PixelParticle>();
world.register::<MaskId>();
world.register::<Sprite>();
world.register::<Line>();
world.register::<TerrainMask>();
world.register::<TerrainCollapse>();
world.register::<WorldPosition>();
world.register::<Point>();
world.register::<BoundingBox>();
world.register::<Velocity>();
world.register::<UnitState>();
world.register::<Health>();
world.register::<Walk>();
world.register::<Destination>();
world.register::<Ally>();
world.register::<Enemy>();
world.register::<Turret>();
world.register::<TurretOffset>();
world.register::<Melee>();
world.register::<Projectile>();
world.register::<ProjectileSprite>();
world.register::<ProjectileBoundingBox>();
world.register::<IgnoreCollision>();
world.register::<Arrow>();
world.register::<Damage>();
world.add_resource(Terrain::new((WIDTH, HEIGHT)));
world.add_resource(Gravity(GRAVITY));
world.add_resource(DeltaTime::new(1.0 / 60.0));
world.add_resource(Images(resources));
render.draw_background_from_memory(include_bytes!("../resources/sprites/background.png.blit"));
render.draw_terrain_from_memory(&mut *world.write_resource::<Terrain>(), include_bytes!("../resources/sprites/level.png.blit"));
place_turrets(&mut world, 1);
let mut dispatcher = DispatcherBuilder::new()
.add(ProjectileSystem, "projectile", &[])
.add(ArrowSystem, "arrow", &["projectile"])
.add(ProjectileCollisionSystem, "projectile_collision", &["projectile"])
.add(TerrainCollapseSystem, "terrain_collapse", &["projectile"])
.add(WalkSystem, "walk", &[])
.add(MeleeSystem, "melee", &["walk"])
.add(TurretUnitSystem, "turret_unit", &["walk"])
.add(TurretSystem, "turret", &["turret_unit"])
.add(SpriteSystem, "sprite", &["projectile", "walk"])
.add(ParticleSystem, "particle", &[])
.build();
let options = WindowOptions {
scale: Scale::X2,
..WindowOptions::default()
};
let title = format!("Castle Game {} - Press ESC to exit.", env!("CARGO_PKG_VERSION"));
let mut window = Window::new(&title, WIDTH, HEIGHT, options).expect("Unable to open window");
window.set_cursor_style(CursorStyle::Crosshair);
let mut gui = IngameGui::new((WIDTH as i32, HEIGHT as i32));
let mut time = SystemTime::now();
while window.is_open() && !window.is_key_down(Key::Escape) {
{
let mut delta = world.write_resource::<DeltaTime>();
*delta = DeltaTime(time.elapsed().unwrap());
time = SystemTime::now();
}
window.get_mouse_pos(MouseMode::Discard).map(|mouse| {
gui.handle_mouse((mouse.0 as i32, mouse.1 as i32), window.get_mouse_down(MouseButton::Left));
});
dispatcher.dispatch(&mut world.res);
world.maintain();
let sprites = world.read::<Sprite>();
let lines = world.read::<Line>();
let pixels = world.read::<PixelParticle>();
let terrain_masks = world.read::<TerrainMask>();
for entity in world.entities().join() {
if let Some(sprite) = sprites.get(entity) {
render.draw_foreground(sprite).unwrap();
}
if let Some(line) = lines.get(entity) {
render.draw_foreground_line(line.p1, line.p2, line.color);
}
if let Some(pixel) = pixels.get(entity) {
render.draw_foreground_pixel(pixel.pos, pixel.color);
}
if let Some(mask) = terrain_masks.get(entity) {
render.draw_mask_terrain(&mut *world.write_resource::<Terrain>(), mask).unwrap();
let _ = world.entities().delete(entity);
}
}
render.draw_final_buffer(&mut buffer, &*world.write_resource::<Terrain>());
gui.render(&mut buffer);
window.update_with_buffer(&buffer).unwrap();
sleep(Duration::from_millis(1));
}
}