ai refactor, mob spawns now take into account player level, small fixes
This commit is contained in:
parent
c00418f7c8
commit
6cef899ef6
21 changed files with 301 additions and 148 deletions
|
|
@ -44,8 +44,8 @@
|
|||
"name": "priest",
|
||||
"renderable": { "glyph": "@", "fg": "#FFFFFF", "bg": "#000000", "order": 1 },
|
||||
"flags": ["BYSTANDER", "BLOCKS_TILE"],
|
||||
"quips": ["Light's givings.", "<a quiet prayer>", "Bless you."],
|
||||
"vision_range": 4
|
||||
"vision_range": 4,
|
||||
"quips": ["Light's givings.", "<a quiet prayer>", "Bless you."]
|
||||
},
|
||||
{
|
||||
"id": "npc_miner",
|
||||
|
|
@ -53,8 +53,8 @@
|
|||
"renderable": { "glyph": "@", "fg": "#946123", "bg": "#000000", "order": 1 },
|
||||
"flags": ["BYSTANDER", "BLOCKS_TILE"],
|
||||
"vision_range": 4,
|
||||
"quips": ["You're not borrowing my pick."],
|
||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d8" }]
|
||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d8" }],
|
||||
"quips": ["You're not borrowing my pick."]
|
||||
},
|
||||
{
|
||||
"id": "npc_guard",
|
||||
|
|
@ -63,20 +63,9 @@
|
|||
"flags": ["BYSTANDER", "BLOCKS_TILE"],
|
||||
"level": 2,
|
||||
"vision_range": 4,
|
||||
"quips": ["You wont catch me down the mine.", "Staying out of trouble?"],
|
||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d8" }],
|
||||
"equipped": ["equip_shortsword", "equip_body_leather"]
|
||||
},
|
||||
{
|
||||
"id": "dog_little",
|
||||
"name": "little dog",
|
||||
"renderable": { "glyph": "d", "fg": "#FFFFFF", "bg": "#000000", "order": 1 },
|
||||
"flags": ["BYSTANDER", "BLOCKS_TILE"],
|
||||
"level": 2,
|
||||
"bac": 6,
|
||||
"vision_range": 12,
|
||||
"quips": ["<woof!>", "<bark!>", "<grrr..>"],
|
||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d6" }]
|
||||
"equipped": ["equip_shortsword", "equip_body_leather"],
|
||||
"quips": ["You wont catch me down the mine.", "Staying out of trouble?"]
|
||||
},
|
||||
{
|
||||
"id": "rat",
|
||||
|
|
@ -86,8 +75,7 @@
|
|||
"bac": 6,
|
||||
"vision_range": 8,
|
||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }],
|
||||
"equipped": ["equip_shortsword", "equip_body_leather"],
|
||||
"loot": { "table": "scrolls", "chance": 0.05 }
|
||||
"loot": { "table": "food", "chance": 0.1 }
|
||||
},
|
||||
{
|
||||
"id": "chicken",
|
||||
|
|
@ -111,7 +99,7 @@
|
|||
"id": "sheep_little",
|
||||
"name": "lamb",
|
||||
"renderable": { "glyph": "q", "fg": "#e7e7e7", "bg": "#000000", "order": 1 },
|
||||
"flags": ["BYSTANDER", "BLOCKS_TILE"],
|
||||
"flags": ["BYSTANDER", "BLOCKS_TILE", "SMALL_GROUP"],
|
||||
"bac": 10,
|
||||
"vision_range": 4,
|
||||
"attacks": [{ "name": "kicks", "hit_bonus": 0, "damage": "1d2" }]
|
||||
|
|
@ -132,11 +120,13 @@
|
|||
"flags": ["BYSTANDER", "BLOCKS_TILE", "MULTIATTACK"],
|
||||
"level": 3,
|
||||
"bac": 6,
|
||||
"speed": 16,
|
||||
"vision_range": 8,
|
||||
"attacks": [
|
||||
{ "name": "kicks", "hit_bonus": 0, "damage": "1d6" },
|
||||
{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }
|
||||
]
|
||||
],
|
||||
"quips": ["<a disgruntled neigh>"]
|
||||
},
|
||||
{
|
||||
"id": "horse",
|
||||
|
|
@ -145,6 +135,7 @@
|
|||
"flags": ["MONSTER", "BLOCKS_TILE", "MULTIATTACK"],
|
||||
"level": 5,
|
||||
"bac": 5,
|
||||
"speed": 20,
|
||||
"vision_range": 8,
|
||||
"attacks": [
|
||||
{ "name": "kicks", "hit_bonus": 0, "damage": "1d8" },
|
||||
|
|
@ -158,6 +149,7 @@
|
|||
"flags": ["MONSTER", "BLOCKS_TILE", "MULTIATTACK"],
|
||||
"level": 7,
|
||||
"bac": 4,
|
||||
"speed": 24,
|
||||
"vision_range": 8,
|
||||
"attacks": [
|
||||
{ "name": "kicks", "hit_bonus": 0, "damage": "1d10" },
|
||||
|
|
@ -168,13 +160,25 @@
|
|||
"id": "rat_giant",
|
||||
"name": "giant rat",
|
||||
"renderable": { "glyph": "r", "fg": "#bb8000", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"flags": ["MONSTER", "BLOCKS_TILE", "SMALL_GROUP"],
|
||||
"level": 1,
|
||||
"bac": 7,
|
||||
"vision_range": 8,
|
||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }],
|
||||
"loot": { "table": "scrolls", "chance": 0.05 }
|
||||
},
|
||||
{
|
||||
"id": "dog_little",
|
||||
"name": "little dog",
|
||||
"renderable": { "glyph": "d", "fg": "#FFFFFF", "bg": "#000000", "order": 1 },
|
||||
"flags": ["BYSTANDER", "BLOCKS_TILE"],
|
||||
"level": 2,
|
||||
"bac": 6,
|
||||
"speed": 18,
|
||||
"vision_range": 12,
|
||||
"quips": ["<woof!>", "<bark!>", "<grrr..>"],
|
||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d6" }]
|
||||
},
|
||||
{
|
||||
"id": "dog",
|
||||
"name": "dog",
|
||||
|
|
@ -182,6 +186,7 @@
|
|||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"level": 4,
|
||||
"bac": 5,
|
||||
"speed": 16,
|
||||
"vision_range": 12,
|
||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d6" }]
|
||||
},
|
||||
|
|
@ -192,6 +197,7 @@
|
|||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"level": 6,
|
||||
"bac": 4,
|
||||
"speed": 15,
|
||||
"vision_range": 12,
|
||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "2d4" }]
|
||||
},
|
||||
|
|
@ -201,6 +207,7 @@
|
|||
"renderable": { "glyph": "g", "fg": "#00FF00", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"level": 1,
|
||||
"speed": 9,
|
||||
"vision_range": 12,
|
||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d4" }]
|
||||
},
|
||||
|
|
@ -218,7 +225,7 @@
|
|||
"id": "jackal",
|
||||
"name": "jackal",
|
||||
"renderable": { "glyph": "d", "fg": "#AA5500", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"flags": ["MONSTER", "BLOCKS_TILE", "SMALL_GROUP"],
|
||||
"bac": 7,
|
||||
"vision_range": 12,
|
||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }]
|
||||
|
|
@ -236,7 +243,7 @@
|
|||
"id": "coyote",
|
||||
"name": "coyote",
|
||||
"renderable": { "glyph": "d", "fg": "#6E3215", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"flags": ["MONSTER", "BLOCKS_TILE", "SMALL_GROUP"],
|
||||
"level": 1,
|
||||
"bac": 7,
|
||||
"vision_range": 12,
|
||||
|
|
@ -258,6 +265,7 @@
|
|||
"renderable": { "glyph": "G", "fg": "#00FF00", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"level": 2,
|
||||
"speed": 9,
|
||||
"vision_range": 12,
|
||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d8" }],
|
||||
"loot": { "table": "wands", "chance": 0.05 }
|
||||
|
|
@ -266,29 +274,48 @@
|
|||
"id": "orc",
|
||||
"name": "orc",
|
||||
"renderable": { "glyph": "o", "fg": "#00FF00", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"flags": ["MONSTER", "BLOCKS_TILE", "SMALL_GROUP"],
|
||||
"level": 1,
|
||||
"speed": 9,
|
||||
"vision_range": 12,
|
||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d6" }],
|
||||
"loot": { "table": "equipment", "chance": 0.05 }
|
||||
},
|
||||
{
|
||||
"id": "orc_large",
|
||||
"name": "large orc",
|
||||
"renderable": { "glyph": "o", "fg": "#008000", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"id": "orc_hill",
|
||||
"name": "hill orc",
|
||||
"renderable": { "glyph": "o", "fg": "#dbd830", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE", "LARGE_GROUP"],
|
||||
"level": 2,
|
||||
"vision_range": 12,
|
||||
"speed": 9,
|
||||
"vision_range": 11,
|
||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d6" }],
|
||||
"loot": { "table": "equipment", "chance": 0.05 }
|
||||
},
|
||||
{
|
||||
"id": "orc_captain",
|
||||
"name": "orc captain",
|
||||
"renderable": { "glyph": "o", "fg": "#9331ac", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE", "MULTIATTACK"],
|
||||
"level": 5,
|
||||
"speed": 5,
|
||||
"vision_range": 12,
|
||||
"attacks": [
|
||||
{ "name": "hits", "hit_bonus": 0, "damage": "2d4" },
|
||||
{ "name": "hits", "hit_bonus": 0, "damage": "2d4" }
|
||||
],
|
||||
"loot": { "table": "equipment", "chance": 0.05 }
|
||||
},
|
||||
{
|
||||
"id": "ogre",
|
||||
"name": "ogre",
|
||||
"renderable": { "glyph": "O", "fg": "#00FF00", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"flags": ["MONSTER", "BLOCKS_TILE", "SMALL_GROUP"],
|
||||
"level": 5,
|
||||
"bac": 5,
|
||||
"speed": 10,
|
||||
"vision_range": 8,
|
||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "2d5" }],
|
||||
"loot": { "table": "food", "chance": 0.05 }
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@
|
|||
{
|
||||
"id": "mobs",
|
||||
"table": [
|
||||
{ "id": "sheep_little", "weight": 1, "difficulty": 0},
|
||||
{ "id": "chicken", "weight": 1, "difficulty": 1},
|
||||
{ "id": "rat", "weight": 1, "difficulty": 1},
|
||||
{ "id": "goblin", "weight": 3, "difficulty": 1},
|
||||
|
|
@ -68,19 +69,19 @@
|
|||
{ "id": "fox", "weight": 1, "difficulty": 1},
|
||||
{ "id": "jackal", "weight": 4, "difficulty": 1},
|
||||
{ "id": "deer_little", "weight": 1, "difficulty": 1},
|
||||
{ "id": "sheep_little", "weight": 1, "difficulty": 1},
|
||||
{ "id": "rat_giant", "weight": 2, "difficulty": 2},
|
||||
{ "id": "coyote", "weight": 4, "difficulty": 2},
|
||||
{ "id": "dog_little", "weight": 1, "difficulty": 3},
|
||||
{ "id": "orc", "weight": 2, "difficulty": 3},
|
||||
{ "id": "orc_large", "weight": 1, "difficulty": 3},
|
||||
{ "id": "orc_hill", "weight": 1, "difficulty": 4},
|
||||
{ "id": "goblin_chieftain", "weight": 1, "difficulty": 3},
|
||||
{ "id": "ogre", "weight": 1, "difficulty": 4},
|
||||
{ "id": "horse_little", "weight": 2, "difficulty": 4},
|
||||
{ "id": "dog", "weight": 1, "difficulty": 5},
|
||||
{ "id": "wolf", "weight": 2, "difficulty": 6},
|
||||
{ "id": "orc_captain", "weight": 1, "difficulty": 7},
|
||||
{ "id": "dog_large", "weight": 1, "difficulty": 7},
|
||||
{ "id": "horse", "weight": 2, "difficulty": 7},
|
||||
{ "id": "ogre", "weight": 1, "difficulty": 7},
|
||||
{ "id": "horse_large", "weight": 2, "difficulty": 9}
|
||||
]
|
||||
},
|
||||
|
|
@ -89,7 +90,7 @@
|
|||
"table": [
|
||||
{ "id": "trap_bear", "weight": 2, "difficulty": 1},
|
||||
{ "id": "trap_confusion", "weight": 1, "difficulty": 1},
|
||||
{ "id": "trap_stonefall", "weight": 1, "difficulty": 3}
|
||||
{ "id": "trap_stonefall", "weight": 1, "difficulty": 5}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ impl<'a> System<'a> for EnergySystem {
|
|||
if energy.current >= TURN_COST {
|
||||
energy.current -= TURN_COST;
|
||||
crate::gamelog::record_event("turns", 1);
|
||||
// Handle spawning mobs each turn
|
||||
if LOG_TICKS {
|
||||
console::log(format!("===== TURN {} =====", crate::gamelog::get_event_count("turns")));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
mod energy_system;
|
||||
pub use energy_system::{EnergySystem, NORMAL_SPEED};
|
||||
mod turn_status;
|
||||
pub use turn_status::TurnStatusSystem;
|
||||
mod turn_status_system;
|
||||
pub use turn_status_system::TurnStatusSystem;
|
||||
mod quip_system;
|
||||
pub use quip_system::QuipSystem;
|
||||
|
|
|
|||
38
src/ai/quip_system.rs
Normal file
38
src/ai/quip_system.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use crate::{gamelog, Name, Quips, TakingTurn, Viewshed};
|
||||
use rltk::prelude::*;
|
||||
use specs::prelude::*;
|
||||
|
||||
pub struct QuipSystem {}
|
||||
|
||||
impl<'a> System<'a> for QuipSystem {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
WriteStorage<'a, Quips>,
|
||||
ReadStorage<'a, Name>,
|
||||
ReadStorage<'a, TakingTurn>,
|
||||
ReadExpect<'a, Point>,
|
||||
ReadStorage<'a, Viewshed>,
|
||||
WriteExpect<'a, RandomNumberGenerator>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
let (mut quips, names, turns, player_pos, viewsheds, mut rng) = data;
|
||||
for (quip, name, viewshed, _turn) in (&mut quips, &names, &viewsheds, &turns).join() {
|
||||
if !quip.available.is_empty() && viewshed.visible_tiles.contains(&player_pos) && rng.roll_dice(1, 6) == 1 {
|
||||
let quip_index = if quip.available.len() == 1 {
|
||||
0
|
||||
} else {
|
||||
(rng.roll_dice(1, quip.available.len() as i32) - 1) as usize
|
||||
};
|
||||
gamelog::Logger::new()
|
||||
.append("The")
|
||||
.npc_name(&name.name)
|
||||
.append_n("says \"")
|
||||
.append_n(&quip.available[quip_index])
|
||||
.append("\"")
|
||||
.log();
|
||||
quip.available.remove(quip_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{gamelog, Bystander, EntityMoved, Map, Name, Point, Position, Quips, TakingTurn, Viewshed};
|
||||
use super::{Bystander, EntityMoved, Map, Position, TakingTurn, Viewshed};
|
||||
use specs::prelude::*;
|
||||
|
||||
pub struct BystanderAI {}
|
||||
|
|
@ -13,54 +13,15 @@ impl<'a> System<'a> for BystanderAI {
|
|||
WriteStorage<'a, Position>,
|
||||
WriteStorage<'a, EntityMoved>,
|
||||
WriteExpect<'a, rltk::RandomNumberGenerator>,
|
||||
ReadExpect<'a, Point>,
|
||||
WriteStorage<'a, Quips>,
|
||||
ReadStorage<'a, Name>,
|
||||
ReadStorage<'a, TakingTurn>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
let (
|
||||
mut map,
|
||||
entities,
|
||||
mut viewshed,
|
||||
bystander,
|
||||
mut position,
|
||||
mut entity_moved,
|
||||
mut rng,
|
||||
player_pos,
|
||||
mut quips,
|
||||
names,
|
||||
turns,
|
||||
) = data;
|
||||
let (mut map, entities, mut viewshed, bystander, mut position, mut entity_moved, mut rng, turns) = data;
|
||||
|
||||
for (entity, mut viewshed, _bystander, mut pos, _turn) in
|
||||
(&entities, &mut viewshed, &bystander, &mut position, &turns).join()
|
||||
{
|
||||
// Possibly quip
|
||||
let quip = quips.get_mut(entity);
|
||||
if let Some(quip) = quip {
|
||||
if !quip.available.is_empty()
|
||||
&& viewshed.visible_tiles.contains(&player_pos)
|
||||
&& rng.roll_dice(1, 20) == 1
|
||||
{
|
||||
let name = names.get(entity);
|
||||
let quip_index = if quip.available.len() == 1 {
|
||||
0
|
||||
} else {
|
||||
(rng.roll_dice(1, quip.available.len() as i32) - 1) as usize
|
||||
};
|
||||
gamelog::Logger::new()
|
||||
.append("The")
|
||||
.npc_name(&name.unwrap().name)
|
||||
.append_n("says \"")
|
||||
.append_n(&quip.available[quip_index])
|
||||
.append("\"")
|
||||
.log();
|
||||
quip.available.remove(quip_index);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to move randomly
|
||||
let mut x = pos.x;
|
||||
let mut y = pos.y;
|
||||
|
|
|
|||
|
|
@ -468,7 +468,7 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opti
|
|||
1 + y_offset,
|
||||
RGB::named(rltk::WHITE),
|
||||
RGB::named(rltk::BLACK),
|
||||
"Drop what? [aA-zZ][Esc.]",
|
||||
"Unequip what? [aA-zZ][Esc.]",
|
||||
);
|
||||
|
||||
let mut equippable: Vec<(Entity, String)> = Vec::new();
|
||||
|
|
|
|||
|
|
@ -1,23 +1,29 @@
|
|||
use super::{camera::get_screen_bounds, Attributes, Hidden, Map, Name, Pools, Position, Rltk, World, RGB};
|
||||
use super::{camera::get_screen_bounds, Attributes, Hidden, Map, Name, Pools, Position, Renderable, Rltk, World, RGB};
|
||||
use rltk::prelude::*;
|
||||
use specs::prelude::*;
|
||||
|
||||
struct Tooltip {
|
||||
lines: Vec<String>,
|
||||
lines: Vec<(String, RGB)>,
|
||||
}
|
||||
|
||||
const ATTRIBUTE_COLOUR: RGB = RGB { r: 1.0, g: 0.75, b: 0.8 };
|
||||
const RED_WARNING: RGB = RGB { r: 1.0, g: 0.0, b: 0.0 };
|
||||
const ORANGE_WARNING: RGB = RGB { r: 1.0, g: 0.65, b: 0.0 };
|
||||
const YELLOW_WARNING: RGB = RGB { r: 1.0, g: 1.0, b: 0.0 };
|
||||
const GREEN_WARNING: RGB = RGB { r: 0.0, g: 1.0, b: 0.0 };
|
||||
|
||||
impl Tooltip {
|
||||
fn new() -> Tooltip {
|
||||
return Tooltip { lines: Vec::new() };
|
||||
}
|
||||
fn add<S: ToString>(&mut self, line: S) {
|
||||
self.lines.push(line.to_string());
|
||||
fn add<S: ToString>(&mut self, line: S, fg: RGB) {
|
||||
self.lines.push((line.to_string(), fg));
|
||||
}
|
||||
fn width(&self) -> i32 {
|
||||
let mut max = 0;
|
||||
for s in self.lines.iter() {
|
||||
if s.len() > max {
|
||||
max = s.len();
|
||||
if s.0.len() > max {
|
||||
max = s.0.len();
|
||||
}
|
||||
}
|
||||
return max as i32 + 2i32;
|
||||
|
|
@ -26,23 +32,9 @@ impl Tooltip {
|
|||
return self.lines.len() as i32 + 2i32;
|
||||
}
|
||||
fn render(&self, ctx: &mut Rltk, x: i32, y: i32) {
|
||||
let white = RGB::named(rltk::WHITE);
|
||||
let weak = RGB::named(rltk::CYAN);
|
||||
let strong = RGB::named(rltk::ORANGE);
|
||||
let attribute = RGB::named(rltk::PINK);
|
||||
|
||||
ctx.draw_box(x, y, self.width() - 1, self.height() - 1, RGB::named(WHITE), RGB::named(BLACK));
|
||||
for (i, s) in self.lines.iter().enumerate() {
|
||||
let col = if i == 0 {
|
||||
white
|
||||
} else if s.starts_with('-') {
|
||||
weak
|
||||
} else if s.starts_with('*') {
|
||||
strong
|
||||
} else {
|
||||
attribute
|
||||
};
|
||||
ctx.print_color(x + 1, y + i as i32 + 1, col, RGB::named(BLACK), &s);
|
||||
ctx.print_color(x + 1, y + i as i32 + 1, s.1, RGB::named(BLACK), &s.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +45,7 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
|||
let map = ecs.fetch::<Map>();
|
||||
let names = ecs.read_storage::<Name>();
|
||||
let positions = ecs.read_storage::<Position>();
|
||||
let renderables = ecs.read_storage::<Renderable>();
|
||||
let hidden = ecs.read_storage::<Hidden>();
|
||||
let attributes = ecs.read_storage::<Attributes>();
|
||||
let pools = ecs.read_storage::<Pools>();
|
||||
|
|
@ -77,10 +70,10 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
|||
}
|
||||
|
||||
let mut tooltips: Vec<Tooltip> = Vec::new();
|
||||
for (entity, name, position, _hidden) in (&entities, &names, &positions, !&hidden).join() {
|
||||
for (entity, name, position, renderable, _hidden) in (&entities, &names, &positions, &renderables, !&hidden).join() {
|
||||
if position.x == mouse_pos_adjusted.0 && position.y == mouse_pos_adjusted.1 {
|
||||
let mut tip = Tooltip::new();
|
||||
tip.add(name.name.to_string());
|
||||
tip.add(name.name.to_string(), renderable.fg);
|
||||
// Attributes
|
||||
let attr = attributes.get(entity);
|
||||
if let Some(a) = attr {
|
||||
|
|
@ -101,7 +94,7 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
|||
if s.ends_with(" ") {
|
||||
s.pop();
|
||||
}
|
||||
tip.add(s);
|
||||
tip.add(s, ATTRIBUTE_COLOUR);
|
||||
}
|
||||
}
|
||||
// Pools
|
||||
|
|
@ -110,9 +103,19 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
|||
if let Some(p) = pool {
|
||||
let level_diff: i32 = p.level - player_pool.level;
|
||||
if level_diff <= -2 {
|
||||
tip.add("-weak-");
|
||||
tip.add("-weak-", YELLOW_WARNING);
|
||||
} else if level_diff >= 2 {
|
||||
tip.add("*threatening*");
|
||||
tip.add("*threatening*", ORANGE_WARNING);
|
||||
}
|
||||
let health_percent: f32 = p.hit_points.current as f32 / p.hit_points.max as f32;
|
||||
if health_percent == 1.0 {
|
||||
tip.add("healthy", GREEN_WARNING);
|
||||
} else if health_percent <= 0.25 {
|
||||
tip.add("*critical*", RED_WARNING);
|
||||
} else if health_percent <= 0.5 {
|
||||
tip.add("-bloodied-", ORANGE_WARNING);
|
||||
} else if health_percent <= 0.75 {
|
||||
tip.add("injured", YELLOW_WARNING);
|
||||
}
|
||||
}
|
||||
tooltips.push(tip);
|
||||
|
|
|
|||
20
src/main.rs
20
src/main.rs
|
|
@ -82,7 +82,15 @@ impl State {
|
|||
self.mapgen_timer = 0.0;
|
||||
self.mapgen_history.clear();
|
||||
let mut rng = self.ecs.write_resource::<rltk::RandomNumberGenerator>();
|
||||
let mut builder = map_builders::level_builder(new_id, &mut rng, 100, 50);
|
||||
let mut player_level = 1;
|
||||
{
|
||||
let player = self.ecs.read_storage::<Player>();
|
||||
let pools = self.ecs.read_storage::<Pools>();
|
||||
for (_p, pool) in (&player, &pools).join() {
|
||||
player_level = pool.level;
|
||||
}
|
||||
}
|
||||
let mut builder = map_builders::level_builder(new_id, &mut rng, 100, 50, player_level);
|
||||
builder.build_map(&mut rng);
|
||||
std::mem::drop(rng);
|
||||
self.mapgen_history = builder.build_data.history.clone();
|
||||
|
|
@ -125,6 +133,7 @@ impl State {
|
|||
let mut vis = VisibilitySystem {};
|
||||
let mut energy = ai::EnergySystem {};
|
||||
let mut turn_status_system = ai::TurnStatusSystem {};
|
||||
let mut quip_system = ai::QuipSystem {};
|
||||
let mut mob = MonsterAI {};
|
||||
let mut bystanders = bystander_ai_system::BystanderAI {};
|
||||
let mut trigger_system = trigger_system::TriggerSystem {};
|
||||
|
|
@ -141,6 +150,7 @@ impl State {
|
|||
vis.run_now(&self.ecs);
|
||||
energy.run_now(&self.ecs);
|
||||
turn_status_system.run_now(&self.ecs);
|
||||
quip_system.run_now(&self.ecs);
|
||||
mob.run_now(&self.ecs);
|
||||
bystanders.run_now(&self.ecs);
|
||||
trigger_system.run_now(&self.ecs);
|
||||
|
|
@ -595,11 +605,11 @@ fn main() -> rltk::BError {
|
|||
raws::load_raws();
|
||||
|
||||
gs.ecs.insert(rltk::RandomNumberGenerator::new());
|
||||
gs.ecs.insert(Map::new(1, 64, 64, 0, "New Map"));
|
||||
gs.ecs.insert(Point::new(0, 0));
|
||||
gs.ecs.insert(Map::new(1, 64, 64, 0, "New Map")); // Map
|
||||
gs.ecs.insert(Point::new(0, 0)); // Player pos
|
||||
let player_entity = spawner::player(&mut gs.ecs, 0, 0);
|
||||
gs.ecs.insert(player_entity);
|
||||
gs.ecs.insert(RunState::MapGeneration {});
|
||||
gs.ecs.insert(player_entity); // Player entity
|
||||
gs.ecs.insert(RunState::MapGeneration {}); // RunState
|
||||
gs.ecs.insert(particle_system::ParticleBuilder::new());
|
||||
gs.ecs.insert(rex_assets::RexAssets::new());
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ pub fn forest_builder(
|
|||
width: i32,
|
||||
height: i32,
|
||||
difficulty: i32,
|
||||
initial_player_level: i32,
|
||||
) -> BuilderChain {
|
||||
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "Into the Woods");
|
||||
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "Into the Woods", initial_player_level);
|
||||
chain.start_with(CellularAutomataBuilder::new());
|
||||
chain.with(AreaStartingPosition::new(XStart::CENTRE, YStart::CENTRE));
|
||||
chain.with(CullUnreachable::new());
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ pub struct BuilderMap {
|
|||
pub history: Vec<Map>,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
pub initial_player_level: i32,
|
||||
}
|
||||
|
||||
impl BuilderMap {
|
||||
|
|
@ -94,7 +95,14 @@ pub struct BuilderChain {
|
|||
}
|
||||
|
||||
impl BuilderChain {
|
||||
pub fn new<S: ToString>(new_id: i32, width: i32, height: i32, difficulty: i32, name: S) -> BuilderChain {
|
||||
pub fn new<S: ToString>(
|
||||
new_id: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
difficulty: i32,
|
||||
name: S,
|
||||
initial_player_level: i32,
|
||||
) -> BuilderChain {
|
||||
BuilderChain {
|
||||
starter: None,
|
||||
builders: Vec::new(),
|
||||
|
|
@ -107,6 +115,7 @@ impl BuilderChain {
|
|||
history: Vec::new(),
|
||||
width: width,
|
||||
height: height,
|
||||
initial_player_level: initial_player_level,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -296,9 +305,10 @@ pub fn random_builder(
|
|||
width: i32,
|
||||
height: i32,
|
||||
difficulty: i32,
|
||||
initial_player_level: i32,
|
||||
) -> BuilderChain {
|
||||
rltk::console::log(format!("DEBUGINFO: Building random (ID:{}, DIFF:{})", new_id, difficulty));
|
||||
let mut builder = BuilderChain::new(new_id, width, height, difficulty, "<PLACEHOLDER>");
|
||||
let mut builder = BuilderChain::new(new_id, width, height, difficulty, "<PLACEHOLDER>", initial_player_level);
|
||||
let type_roll = rng.roll_dice(1, 2);
|
||||
let mut want_doors = true;
|
||||
match type_roll {
|
||||
|
|
@ -339,12 +349,18 @@ pub fn random_builder(
|
|||
builder
|
||||
}
|
||||
|
||||
pub fn level_builder(new_id: i32, rng: &mut rltk::RandomNumberGenerator, width: i32, height: i32) -> BuilderChain {
|
||||
pub fn level_builder(
|
||||
new_id: i32,
|
||||
rng: &mut rltk::RandomNumberGenerator,
|
||||
width: i32,
|
||||
height: i32,
|
||||
initial_player_level: i32,
|
||||
) -> BuilderChain {
|
||||
// TODO: With difficulty and ID/depth decoupled, this can be used for branches later.
|
||||
let difficulty = new_id;
|
||||
match new_id {
|
||||
1 => town_builder(new_id, rng, width, height),
|
||||
2 => forest_builder(new_id, rng, width, height, difficulty),
|
||||
_ => random_builder(new_id, rng, width, height, difficulty),
|
||||
1 => town_builder(new_id, rng, width, height, 0, initial_player_level),
|
||||
2 => forest_builder(new_id, rng, width, height, 1, initial_player_level),
|
||||
_ => random_builder(new_id, rng, width, height, difficulty, initial_player_level),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ impl PrefabBuilder {
|
|||
}
|
||||
|
||||
fn char_to_map(&mut self, ch: char, idx: usize, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
let difficulty = (build_data.map.difficulty + build_data.initial_player_level) / 2;
|
||||
match ch {
|
||||
' ' => build_data.map.tiles[idx] = TileType::Floor,
|
||||
'#' => build_data.map.tiles[idx] = TileType::Wall,
|
||||
|
|
@ -102,23 +103,23 @@ impl PrefabBuilder {
|
|||
}
|
||||
'%' => {
|
||||
build_data.map.tiles[idx] = TileType::Floor;
|
||||
build_data.spawn_list.push((idx, spawner::food_table(build_data.map.difficulty).roll(rng)));
|
||||
build_data.spawn_list.push((idx, spawner::food_table(difficulty).roll(rng)));
|
||||
}
|
||||
'!' => {
|
||||
build_data.map.tiles[idx] = TileType::Floor;
|
||||
build_data.spawn_list.push((idx, spawner::potion_table(build_data.map.difficulty).roll(rng)));
|
||||
build_data.spawn_list.push((idx, spawner::potion_table(difficulty).roll(rng)));
|
||||
}
|
||||
'/' => {
|
||||
build_data.map.tiles[idx] = TileType::Floor;
|
||||
build_data.spawn_list.push((idx, spawner::wand_table(build_data.map.difficulty).roll(rng)));
|
||||
build_data.spawn_list.push((idx, spawner::wand_table(difficulty).roll(rng)));
|
||||
}
|
||||
'?' => {
|
||||
build_data.map.tiles[idx] = TileType::Floor;
|
||||
build_data.spawn_list.push((idx, spawner::scroll_table(build_data.map.difficulty).roll(rng)));
|
||||
build_data.spawn_list.push((idx, spawner::scroll_table(difficulty).roll(rng)));
|
||||
}
|
||||
')' => {
|
||||
build_data.map.tiles[idx] = TileType::Floor;
|
||||
build_data.spawn_list.push((idx, spawner::equipment_table(build_data.map.difficulty).roll(rng)));
|
||||
build_data.spawn_list.push((idx, spawner::equipment_table(difficulty).roll(rng)));
|
||||
}
|
||||
_ => {
|
||||
rltk::console::log(format!("Unknown glyph '{}' when loading prefab", (ch as u8) as char));
|
||||
|
|
|
|||
|
|
@ -18,7 +18,13 @@ impl RoomBasedSpawner {
|
|||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
if let Some(rooms) = &build_data.rooms {
|
||||
for room in rooms.iter().skip(1) {
|
||||
spawner::spawn_room(&build_data.map, rng, room, &mut build_data.spawn_list);
|
||||
spawner::spawn_room(
|
||||
&build_data.map,
|
||||
rng,
|
||||
room,
|
||||
&mut build_data.spawn_list,
|
||||
build_data.initial_player_level,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!("RoomBasedSpawner only works after rooms have been created");
|
||||
|
|
|
|||
|
|
@ -18,7 +18,13 @@ impl CorridorSpawner {
|
|||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
if let Some(corridors) = &build_data.corridors {
|
||||
for corridor in corridors.iter() {
|
||||
spawner::spawn_region(&build_data.map, rng, &corridor, &mut build_data.spawn_list);
|
||||
spawner::spawn_region(
|
||||
&build_data.map,
|
||||
rng,
|
||||
&corridor,
|
||||
&mut build_data.spawn_list,
|
||||
build_data.initial_player_level,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!("CorridorSpawner only works after corridors have been created");
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
use super::{BuilderChain, BuilderMap, InitialMapBuilder, Position, TileType};
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn town_builder(new_id: i32, _rng: &mut rltk::RandomNumberGenerator, width: i32, height: i32) -> BuilderChain {
|
||||
let difficulty = 0;
|
||||
pub fn town_builder(
|
||||
new_id: i32,
|
||||
_rng: &mut rltk::RandomNumberGenerator,
|
||||
width: i32,
|
||||
height: i32,
|
||||
difficulty: i32,
|
||||
initial_player_level: i32,
|
||||
) -> BuilderChain {
|
||||
rltk::console::log(format!("DEBUGINFO: Building town (ID:{}, DIFF:{})", new_id, difficulty));
|
||||
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "<PLACEHOLDER>");
|
||||
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "<PLACEHOLDER>", initial_player_level);
|
||||
chain.start_with(TownBuilder::new());
|
||||
|
||||
return chain;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,13 @@ impl VoronoiSpawning {
|
|||
|
||||
// Spawn the entities
|
||||
for area in noise_areas.iter() {
|
||||
spawner::spawn_region(&build_data.map, rng, area.1, &mut build_data.spawn_list);
|
||||
spawner::spawn_region(
|
||||
&build_data.map,
|
||||
rng,
|
||||
area.1,
|
||||
&mut build_data.spawn_list,
|
||||
build_data.initial_player_level,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ pub struct Mob {
|
|||
pub attributes: Option<MobAttributes>,
|
||||
pub skills: Option<HashMap<String, i32>>,
|
||||
pub vision_range: i32,
|
||||
pub quips: Option<Vec<String>>,
|
||||
pub equipped: Option<Vec<String>>,
|
||||
pub loot: Option<LootTableInfo>,
|
||||
pub quips: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ pub fn table_by_name(raws: &RawMaster, key: &str, difficulty: i32) -> RandomTabl
|
|||
use super::SpawnTableEntry;
|
||||
|
||||
let upper_bound = difficulty;
|
||||
let lower_bound = difficulty / 6;
|
||||
let lower_bound = if key != "mobs" { 0 } else { difficulty / 6 };
|
||||
|
||||
let available_options: Vec<&SpawnTableEntry> = spawn_table
|
||||
.table
|
||||
|
|
@ -559,3 +559,26 @@ pub fn roll_on_loot_table(raws: &RawMaster, rng: &mut RandomNumberGenerator, key
|
|||
console::log(format!("DEBUGINFO: Unknown loot table {}", key));
|
||||
return None;
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
pub enum SpawnsAs {
|
||||
Single,
|
||||
SmallGroup,
|
||||
LargeGroup,
|
||||
}
|
||||
|
||||
pub fn check_if_mob_spawns_in_group(raws: &RawMaster, key: &str) -> SpawnsAs {
|
||||
if raws.mob_index.contains_key(key) {
|
||||
let mob_template = &raws.raws.mobs[raws.mob_index[key]];
|
||||
if let Some(flags) = &mob_template.flags {
|
||||
for flag in flags {
|
||||
match flag.as_str() {
|
||||
"SMALL_GROUP" => return SpawnsAs::SmallGroup,
|
||||
"LARGE_GROUP" => return SpawnsAs::LargeGroup,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return SpawnsAs::Single;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,13 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
|||
}
|
||||
|
||||
/// Fills a room with stuff!
|
||||
pub fn spawn_room(map: &Map, rng: &mut RandomNumberGenerator, room: &Rect, spawn_list: &mut Vec<(usize, String)>) {
|
||||
pub fn spawn_room(
|
||||
map: &Map,
|
||||
rng: &mut RandomNumberGenerator,
|
||||
room: &Rect,
|
||||
spawn_list: &mut Vec<(usize, String)>,
|
||||
player_level: i32,
|
||||
) {
|
||||
let mut possible_targets: Vec<usize> = Vec::new();
|
||||
{
|
||||
// Borrow scope - to keep access to the map separated
|
||||
|
|
@ -92,24 +98,26 @@ pub fn spawn_room(map: &Map, rng: &mut RandomNumberGenerator, room: &Rect, spawn
|
|||
}
|
||||
}
|
||||
|
||||
spawn_region(map, rng, &possible_targets, spawn_list);
|
||||
spawn_region(map, rng, &possible_targets, spawn_list, player_level);
|
||||
}
|
||||
|
||||
pub fn spawn_region(map: &Map, rng: &mut RandomNumberGenerator, area: &[usize], spawn_list: &mut Vec<(usize, String)>) {
|
||||
pub fn spawn_region(
|
||||
map: &Map,
|
||||
rng: &mut RandomNumberGenerator,
|
||||
area: &[usize],
|
||||
spawn_list: &mut Vec<(usize, String)>,
|
||||
player_level: i32,
|
||||
) {
|
||||
let mut spawn_points: HashMap<usize, String> = HashMap::new();
|
||||
let mut areas: Vec<usize> = Vec::from(area);
|
||||
let difficulty = map.difficulty;
|
||||
let difficulty = (map.difficulty + player_level) / 2;
|
||||
// If no area, log and return.
|
||||
if areas.len() == 0 {
|
||||
rltk::console::log("DEBUGINFO: No areas capable of spawning mobs!");
|
||||
return;
|
||||
}
|
||||
// Get num of each entity type.
|
||||
let num_mobs = match rng.roll_dice(1, 20) {
|
||||
1..=4 => 1, // 20% chance of spawning 1 mob.
|
||||
5 => 3, // 5% chance of spawning 3 mobs.
|
||||
_ => 0, // 75% chance of spawning 0
|
||||
};
|
||||
let spawn_mob: bool = rng.roll_dice(1, 3) == 1;
|
||||
let num_items = match rng.roll_dice(1, 20) {
|
||||
1..=2 => 1, // 10% chance of spawning 1 item
|
||||
3 => 2, // 5% chance of spawning 2 items
|
||||
|
|
@ -122,15 +130,45 @@ pub fn spawn_region(map: &Map, rng: &mut RandomNumberGenerator, area: &[usize],
|
|||
_ => 0, // 85% chance of spawning nothing
|
||||
};
|
||||
// Roll on each table, getting an entity + spawn point
|
||||
for _i in 0..num_mobs {
|
||||
entity_from_table_to_spawn_list(rng, &mut areas, mob_table(difficulty), &mut spawn_points);
|
||||
if spawn_mob {
|
||||
let key = mob_table(difficulty).roll(rng);
|
||||
let spawn_type = raws::check_if_mob_spawns_in_group(&raws::RAWS.lock().unwrap(), &key);
|
||||
let n = match spawn_type {
|
||||
raws::SpawnsAs::Single => 1,
|
||||
raws::SpawnsAs::SmallGroup => {
|
||||
if rng.roll_dice(1, 2) == 1 {
|
||||
1
|
||||
} else {
|
||||
4
|
||||
}
|
||||
}
|
||||
raws::SpawnsAs::LargeGroup => {
|
||||
if rng.roll_dice(1, 2) == 1 {
|
||||
4
|
||||
} else {
|
||||
11
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut roll = if n == 1 { 1 } else { rng.roll_dice(2, n) };
|
||||
roll = match player_level {
|
||||
0..=2 => i32::min(1, roll / 4),
|
||||
3..=4 => i32::min(1, roll / 2),
|
||||
_ => roll,
|
||||
};
|
||||
for _i in 0..roll {
|
||||
entity_to_spawn_list(rng, &mut areas, key.clone(), &mut spawn_points);
|
||||
}
|
||||
}
|
||||
for _i in 0..num_traps {
|
||||
entity_from_table_to_spawn_list(rng, &mut areas, trap_table(difficulty), &mut spawn_points);
|
||||
let key = trap_table(difficulty).roll(rng);
|
||||
entity_to_spawn_list(rng, &mut areas, key, &mut spawn_points);
|
||||
}
|
||||
for _i in 0..num_items {
|
||||
let spawn_table = get_random_item_category(rng, difficulty);
|
||||
entity_from_table_to_spawn_list(rng, &mut areas, spawn_table, &mut spawn_points);
|
||||
// Player level isn't taken into account for item spawning, to encourage
|
||||
// delving deeper to gear up more quickly.
|
||||
let key = get_random_item_category(rng, map.difficulty).roll(rng);
|
||||
entity_to_spawn_list(rng, &mut areas, key, &mut spawn_points);
|
||||
}
|
||||
// Push entities and their spawn points to map's spawn list
|
||||
for spawn in spawn_points.iter() {
|
||||
|
|
@ -138,10 +176,10 @@ pub fn spawn_region(map: &Map, rng: &mut RandomNumberGenerator, area: &[usize],
|
|||
}
|
||||
}
|
||||
|
||||
fn entity_from_table_to_spawn_list(
|
||||
fn entity_to_spawn_list(
|
||||
rng: &mut RandomNumberGenerator,
|
||||
possible_areas: &mut Vec<usize>,
|
||||
table: RandomTable,
|
||||
key: String,
|
||||
spawn_points: &mut HashMap<usize, String>,
|
||||
) {
|
||||
if possible_areas.len() == 0 {
|
||||
|
|
@ -150,7 +188,7 @@ fn entity_from_table_to_spawn_list(
|
|||
let array_idx =
|
||||
if possible_areas.len() == 1 { 0usize } else { (rng.roll_dice(1, possible_areas.len() as i32) - 1) as usize };
|
||||
let map_idx = possible_areas[array_idx];
|
||||
spawn_points.insert(map_idx, table.roll(rng));
|
||||
spawn_points.insert(map_idx, key);
|
||||
possible_areas.remove(array_idx);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ impl<'a> System<'a> for TriggerSystem {
|
|||
ReadStorage<'a, Name>,
|
||||
WriteExpect<'a, ParticleBuilder>,
|
||||
Entities<'a>,
|
||||
WriteExpect<'a, rltk::RandomNumberGenerator>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
|
|
@ -37,6 +38,7 @@ impl<'a> System<'a> for TriggerSystem {
|
|||
names,
|
||||
mut particle_builder,
|
||||
entities,
|
||||
mut rng,
|
||||
) = data;
|
||||
|
||||
// Iterate entities that moved, and their final position
|
||||
|
|
@ -60,7 +62,12 @@ impl<'a> System<'a> for TriggerSystem {
|
|||
let damage = inflicts_damage.get(*entity_id);
|
||||
if let Some(damage) = damage {
|
||||
particle_builder.damage_taken(pos.x, pos.y);
|
||||
SufferDamage::new_damage(&mut inflict_damage, entity, damage.amount, false);
|
||||
SufferDamage::new_damage(
|
||||
&mut inflict_damage,
|
||||
entity,
|
||||
rng.roll_dice(1, damage.amount),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
let confuses = confusion.get(*entity_id);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue