123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- extern crate rltk;
- use rltk::{ RGB, RandomNumberGenerator };
- extern crate specs;
- use specs::prelude::*;
- use super::{CombatStats, Player, Renderable, Name, Position, Viewshed, Monster, BlocksTile, Rect, Item,
- Consumable, Ranged, ProvidesHealing, map::MAPWIDTH, InflictsDamage, AreaOfEffect, Confusion, SerializeMe,
- random_table::RandomTable, EquipmentSlot, Equippable, MeleePowerBonus, DefenseBonus, HungerClock,
- HungerState, ProvidesFood, MagicMapper, Hidden, EntryTrigger, SingleActivation, Map, TileType };
- use crate::specs::saveload::{MarkedBuilder, SimpleMarker};
- use std::collections::HashMap;
- /// Spawns the player and returns his/her entity object.
- pub fn player(ecs : &mut World, player_x : i32, player_y : i32) -> Entity {
- ecs
- .create_entity()
- .with(Position { x: player_x, y: player_y })
- .with(Renderable {
- glyph: rltk::to_cp437('@'),
- fg: RGB::named(rltk::YELLOW),
- bg: RGB::named(rltk::BLACK),
- render_order: 0
- })
- .with(Player{})
- .with(Viewshed{ visible_tiles : Vec::new(), range: 8, dirty: true })
- .with(Name{name: "Player".to_string() })
- .with(CombatStats{ max_hp: 30, hp: 30, defense: 2, power: 5 })
- .with(HungerClock{ state: HungerState::WellFed, duration: 20 })
- .marked::<SimpleMarker<SerializeMe>>()
- .build()
- }
- const MAX_MONSTERS : i32 = 4;
- fn room_table(map_depth: i32) -> RandomTable {
- RandomTable::new()
- .add("Goblin", 10)
- .add("Orc", 1 + map_depth)
- .add("Health Potion", 7)
- .add("Fireball Scroll", 2 + map_depth)
- .add("Confusion Scroll", 2 + map_depth)
- .add("Magic Missile Scroll", 4)
- .add("Dagger", 3)
- .add("Shield", 3)
- .add("Longsword", map_depth - 1)
- .add("Tower Shield", map_depth - 1)
- .add("Rations", 10)
- .add("Magic Mapping Scroll", 2)
- .add("Bear Trap", 5)
- }
- /// Fills a room with stuff!
- pub fn spawn_room(ecs: &mut World, room : &Rect, map_depth: i32) {
- let mut possible_targets : Vec<usize> = Vec::new();
- { // Borrow scope - to keep access to the map separated
- let map = ecs.fetch::<Map>();
- for y in room.y1 + 1 .. room.y2 {
- for x in room.x1 + 1 .. room.x2 {
- let idx = map.xy_idx(x, y);
- if map.tiles[idx] == TileType::Floor {
- possible_targets.push(idx);
- }
- }
- }
- }
- spawn_region(ecs, &possible_targets, map_depth);
- }
- /// Fills a region with stuff!
- pub fn spawn_region(ecs: &mut World, area : &[usize], map_depth: i32) {
- let spawn_table = room_table(map_depth);
- let mut spawn_points : HashMap<usize, String> = HashMap::new();
- let mut areas : Vec<usize> = Vec::from(area);
- // Scope to keep the borrow checker happy
- {
- let mut rng = ecs.write_resource::<RandomNumberGenerator>();
- let num_spawns = i32::min(areas.len() as i32, rng.roll_dice(1, MAX_MONSTERS + 3) + (map_depth - 1) - 3);
- if num_spawns == 0 { return; }
- for _i in 0 .. num_spawns {
- let array_index = if areas.len() == 1 { 0usize } else { (rng.roll_dice(1, areas.len() as i32)-1) as usize };
- let map_idx = areas[array_index];
- spawn_points.insert(map_idx, spawn_table.roll(&mut rng));
- areas.remove(array_index);
- }
- }
- // Actually spawn the monsters
- for spawn in spawn_points.iter() {
- spawn_entity(ecs, &spawn);
- }
- }
- /// Spawns a named entity (name in tuple.1) at the location in (tuple.0)
- fn spawn_entity(ecs: &mut World, spawn : &(&usize, &String)) {
- let x = (*spawn.0 % MAPWIDTH) as i32;
- let y = (*spawn.0 / MAPWIDTH) as i32;
- match spawn.1.as_ref() {
- "Goblin" => goblin(ecs, x, y),
- "Orc" => orc(ecs, x, y),
- "Health Potion" => health_potion(ecs, x, y),
- "Fireball Scroll" => fireball_scroll(ecs, x, y),
- "Confusion Scroll" => confusion_scroll(ecs, x, y),
- "Magic Missile Scroll" => magic_missile_scroll(ecs, x, y),
- "Dagger" => dagger(ecs, x, y),
- "Shield" => shield(ecs, x, y),
- "Longsword" => longsword(ecs, x, y),
- "Tower Shield" => tower_shield(ecs, x, y),
- "Rations" => rations(ecs, x, y),
- "Magic Mapping Scroll" => magic_mapping_scroll(ecs, x, y),
- "Bear Trap" => bear_trap(ecs, x, y),
- _ => {}
- }
- }
- fn orc(ecs: &mut World, x: i32, y: i32) { monster(ecs, x, y, rltk::to_cp437('o'), "Orc"); }
- fn goblin(ecs: &mut World, x: i32, y: i32) { monster(ecs, x, y, rltk::to_cp437('g'), "Goblin"); }
- fn monster<S : ToString>(ecs: &mut World, x: i32, y: i32, glyph : u8, name : S) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph,
- fg: RGB::named(rltk::RED),
- bg: RGB::named(rltk::BLACK),
- render_order: 1
- })
- .with(Viewshed{ visible_tiles : Vec::new(), range: 8, dirty: true })
- .with(Monster{})
- .with(Name{ name : name.to_string() })
- .with(BlocksTile{})
- .with(CombatStats{ max_hp: 16, hp: 16, defense: 1, power: 4 })
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn health_potion(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437('¡'),
- fg: RGB::named(rltk::MAGENTA),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Health Potion".to_string() })
- .with(Item{})
- .with(Consumable{})
- .with(ProvidesHealing{ heal_amount: 8 })
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn magic_missile_scroll(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437(')'),
- fg: RGB::named(rltk::CYAN),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Magic Missile Scroll".to_string() })
- .with(Item{})
- .with(Consumable{})
- .with(Ranged{ range: 6 })
- .with(InflictsDamage{ damage: 20 })
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn fireball_scroll(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437(')'),
- fg: RGB::named(rltk::ORANGE),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Fireball Scroll".to_string() })
- .with(Item{})
- .with(Consumable{})
- .with(Ranged{ range: 6 })
- .with(InflictsDamage{ damage: 20 })
- .with(AreaOfEffect{ radius: 3 })
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn confusion_scroll(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437(')'),
- fg: RGB::named(rltk::PINK),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Confusion Scroll".to_string() })
- .with(Item{})
- .with(Consumable{})
- .with(Ranged{ range: 6 })
- .with(Confusion{ turns: 4 })
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn dagger(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437('/'),
- fg: RGB::named(rltk::CYAN),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Dagger".to_string() })
- .with(Item{})
- .with(Equippable{ slot: EquipmentSlot::Melee })
- .with(MeleePowerBonus{ power: 2 })
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn shield(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437('('),
- fg: RGB::named(rltk::CYAN),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Shield".to_string() })
- .with(Item{})
- .with(Equippable{ slot: EquipmentSlot::Shield })
- .with(DefenseBonus{ defense: 1 })
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn longsword(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437('/'),
- fg: RGB::named(rltk::YELLOW),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Longsword".to_string() })
- .with(Item{})
- .with(Equippable{ slot: EquipmentSlot::Melee })
- .with(MeleePowerBonus{ power: 4 })
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn tower_shield(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437('('),
- fg: RGB::named(rltk::YELLOW),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Tower Shield".to_string() })
- .with(Item{})
- .with(Equippable{ slot: EquipmentSlot::Shield })
- .with(DefenseBonus{ defense: 3 })
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn rations(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437('%'),
- fg: RGB::named(rltk::GREEN),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Rations".to_string() })
- .with(Item{})
- .with(ProvidesFood{})
- .with(Consumable{})
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn magic_mapping_scroll(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437(')'),
- fg: RGB::named(rltk::CYAN3),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Scroll of Magic Mapping".to_string() })
- .with(Item{})
- .with(MagicMapper{})
- .with(Consumable{})
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
- fn bear_trap(ecs: &mut World, x: i32, y: i32) {
- ecs.create_entity()
- .with(Position{ x, y })
- .with(Renderable{
- glyph: rltk::to_cp437('^'),
- fg: RGB::named(rltk::RED),
- bg: RGB::named(rltk::BLACK),
- render_order: 2
- })
- .with(Name{ name : "Bear Trap".to_string() })
- .with(Hidden{})
- .with(EntryTrigger{})
- .with(InflictsDamage{ damage: 6 })
- .with(SingleActivation{})
- .marked::<SimpleMarker<SerializeMe>>()
- .build();
- }
|