diff --git a/raws/spawns.json b/raws/spawns.json index 42a1425..0819cdc 100644 --- a/raws/spawns.json +++ b/raws/spawns.json @@ -68,7 +68,7 @@ }, { "name": "Health Potion", - "weight": 7, + "weight": 15, "min_depth": 0, "max_depth": 100 }, @@ -82,15 +82,13 @@ "name": "Fireball Scroll", "weight": 2, "min_depth": 0, - "max_depth": 100, - "add_map_depth_to_weight": true + "max_depth": 100 }, { "name": "Confusion Scroll", "weight": 2, "min_depth": 0, - "max_depth": 100, - "add_map_depth_to_weight": true + "max_depth": 100 }, { "name": "Magic Missile Scroll", @@ -236,12 +234,6 @@ "min_depth": 2, "max_depth": 2 }, - { - "name": "Deer", - "weight": 14, - "min_depth": 2, - "max_depth": 2 - }, { "name": "Bandit", "weight": 9, @@ -1753,7 +1745,7 @@ "vision_range": 8, "movement": "static", "attributes": { - "might": 3, + "might": 7, "fitness": 3 }, "skills": { @@ -2090,6 +2082,60 @@ "level": 3, "gold": "3d6" }, + { + "name": "Black Dragon", + "renderable": { + "glyph": "D", + "fg": "#FF0000", + "bg": "#000000", + "order": 1, + "x_size": 2, + "y_size": 2 + }, + "blocks_tile": true, + "vision_range": 12, + "movement": "static", + "attributes": { + "might": 13, + "fitness": 13 + }, + "skills": { + "Melee": 18, + "Defense": 16 + }, + "natural": { + "armor_class": 17, + "attacks": [ + { + "name": "bite", + "hit_bonus": 4, + "damage": "1d10+2" + }, + { + "name": "left_claw", + "hit_bonus": 2, + "damage": "1d10" + }, + { + "name": "right_claw", + "hit_bonus": 2, + "damage": "1d10" + } + ] + }, + "loot_table": "Wyrms", + "faction": "Wyrm", + "level": 6, + "gold": "20d10", + "abilities": [ + { + "spell": "Acid Breath", + "chance": 0.2, + "range": 8.0, + "min_range": 2.0 + } + ] + }, { "name": "Lizardman", "renderable": { @@ -2405,6 +2451,16 @@ "damage_over_time": "4", "particle_line": "▓;#00FF00;400.0" } + }, + { + "name": "Acid Breath", + "mana_cost": 2, + "effects": { + "ranged": "6", + "damage": "10", + "area_of_effect": "3", + "particle": "☼;#00FF00;400.0" + } } ] } \ No newline at end of file diff --git a/src/map_builders/dwarf_fort.rs b/src/map_builders/dwarf_fort.rs index 5096871..86bfed4 100644 --- a/src/map_builders/dwarf_fort.rs +++ b/src/map_builders/dwarf_fort.rs @@ -1,11 +1,11 @@ -use ::rltk::RandomNumberGenerator; +use ::rltk::{DistanceAlg, Point, RandomNumberGenerator}; use super::{ AreaEndingPosition, AreaStartingPosition, BspCorridors, BspDungeonBuilder, BuilderChain, BuilderMap, CorridorSpawner, CullUnreachable, DLABuilder, DistantExit, MetaMapBuilder, RoomDrawer, RoomSort, RoomSorter, VoronoiSpawning, XEnd, XStart, YEnd, YStart, }; -use crate::TileType; +use crate::{tile_walkable, TileType}; pub fn dwarf_fort_builder( new_depth: i32, @@ -25,7 +25,8 @@ pub fn dwarf_fort_builder( .with(CullUnreachable::new()) .with(AreaEndingPosition::new(XEnd::Right, YEnd::Bottom)) .with(VoronoiSpawning::new()) - .with(DistantExit::new()); + .with(DistantExit::new()) + .with(DragonSpawner::new()); chain } @@ -67,3 +68,64 @@ impl DragonsLair { build_data.take_snapshot(); } } + +pub struct DragonSpawner {} + +impl MetaMapBuilder for DragonSpawner { + fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + self.build(rng, build_data); + } +} + +impl DragonSpawner { + #[allow(dead_code)] + pub fn new() -> Box { + Box::new(DragonSpawner {}) + } + + fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + // Find a central location that isn't occupied + let seed_x = build_data.map.width / 2; + let seed_y = build_data.map.height / 2; + let mut available_floors: Vec<(usize, f32)> = Vec::new(); + for (idx, tiletype) in build_data.map.tiles.iter().enumerate() { + if tile_walkable(*tiletype) { + available_floors.push(( + idx, + DistanceAlg::PythagorasSquared.distance2d( + Point::new( + idx as i32 % build_data.map.width, + idx as i32 / build_data.map.width, + ), + Point::new(seed_x, seed_y), + ), + )); + } + } + + if available_floors.is_empty() { + panic!("No valid floors to start on."); + } + + available_floors.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap()); + + let start_x = available_floors[0].0 as i32 % build_data.map.width; + let start_y = available_floors[0].0 as i32 / build_data.map.width; + let dragon_pt = Point::new(start_x, start_y); + + // Remove all spawns within 25 tiles of the drake + let w = build_data.map.width as i32; + build_data.spawn_list.retain(|spawn| { + let spawn_pt = Point::new(spawn.0 as i32 % w, spawn.0 as i32 / 2); + let distance = DistanceAlg::Pythagoras.distance2d(dragon_pt, spawn_pt); + + distance > 25.0 + }); + + // Add the dragon + let dragon_idx = build_data.map.xy_idx(start_x, start_y); + build_data + .spawn_list + .push((dragon_idx, "Black Dragon".to_string())); + } +} diff --git a/src/state.rs b/src/state.rs index f0b0222..e285968 100644 --- a/src/state.rs +++ b/src/state.rs @@ -23,7 +23,7 @@ use crate::visibility_system::VisibilitySystem; use crate::{ai, camera, damage_system, effects, saveload_system, spawner}; /// Whether to show a visual representation of map generation -pub const SHOW_MAPGEN_VISUALIZER: bool = true; +pub const SHOW_MAPGEN_VISUALIZER: bool = false; /// The main actions possible with a vendor #[derive(PartialEq, Copy, Clone)]