EncumbranceSystem {}

This commit is contained in:
Llywelwyn 2023-08-13 15:42:56 +01:00
parent 0ef3a51e56
commit 0344f87da8
14 changed files with 282 additions and 30 deletions

View file

@ -3,6 +3,8 @@
"id": "potion_health",
"name": { "name": "potion of health", "plural": "potions of health" },
"renderable": { "glyph": "!", "fg": "#FF00FF", "bg": "#000000", "order": 2 },
"weight": 1,
"value": 50,
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
"effects": { "provides_healing": "12" }
},
@ -10,6 +12,8 @@
"id": "potion_health_weak",
"name": { "name": "potion of lesser health", "plural": "potions of lesser health" },
"renderable": { "glyph": "!", "fg": "#FF00FF", "bg": "#000000", "order": 2 },
"weight": 1,
"value": 25,
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
"effects": { "provides_healing": "6" }
},
@ -17,6 +21,8 @@
"id": "scroll_magicmissile",
"name": { "name": "scroll of magic missile", "plural": "scrolls of magic missile" },
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 0.5,
"value": 50,
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
"effects": { "ranged": "12", "damage": "10" }
},
@ -24,6 +30,8 @@
"id": "scroll_fireball",
"name": { "name": "scroll of fireball", "plural": "scrolls of fireball" },
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 0.5,
"value": 150,
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
"effects": { "ranged": "10", "damage": "15", "aoe": "3" }
},
@ -31,6 +39,8 @@
"id": "scroll_fireball_c",
"name": { "name": "cursed scroll of fireball", "plural": "cursed scrolls of fireball" },
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 0.5,
"value": 150,
"flags": ["CONSUMABLE", "DESTRUCTIBLE", "CURSED"],
"effects": { "ranged": "10", "damage": "15", "aoe": "3" }
},
@ -38,6 +48,8 @@
"id": "scroll_confusion",
"name": { "name": "scroll of confusion", "plural": "scrolls of confusion" },
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 0.5,
"value": 100,
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
"effects": { "ranged": "10", "confusion": "4" }
},
@ -45,6 +57,8 @@
"id": "scroll_magicmap",
"name": { "name": "scroll of magic mapping", "plural": "scrolls of magic mapping" },
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 0.5,
"value": 50,
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
"effects": { "magicmapper": "" }
},
@ -52,6 +66,8 @@
"id": "scroll_magicmap_c",
"name": { "name": "cursed scroll of magic mapping", "plural": "cursed scrolls of magic mapping" },
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 0.5,
"value": 50,
"flags": ["CONSUMABLE", "DESTRUCTIBLE", "CURSED"],
"effects": { "magicmapper": "" }
},
@ -59,20 +75,26 @@
"id": "equip_dagger",
"name": { "name": "dagger", "plural": "daggers" },
"renderable": { "glyph": ")", "fg": "#808080", "bg": "#000000", "order": 2 },
"weight": 130,
"value": 2,
"flags": ["EQUIP_MELEE", "FINESSE"],
"effects": { "base_damage": "1d4"}
"effects": { "base_damage": "1d4" }
},
{
"id": "equip_shortsword",
"name": { "name": "shortsword", "plural": "shortswords" },
"renderable": { "glyph": ")", "fg": "#C0C0C0", "bg": "#000000", "order": 2 },
"weight": 2,
"value": 10,
"flags": ["EQUIP_MELEE", "STRENGTH"],
"effects": { "base_damage": "1d6"}
"effects": { "base_damage": "1d6" }
},
{
"id": "equip_longsword",
"name": { "name": "longsword", "plural": "longswords" },
"renderable": { "glyph": ")", "fg": "#FFF8DC", "bg": "#000000", "order": 2 },
"weight": 3,
"value": 15,
"flags": ["EQUIP_MELEE", "STRENGTH"],
"effects": { "base_damage": "1d8" }
},
@ -80,6 +102,8 @@
"id": "equip_smallshield",
"name": { "name": "buckler", "plural": "bucklers" },
"renderable": { "glyph": "[", "fg": "#808080", "bg": "#000000", "order": 2 },
"weight": 2,
"value": 5,
"flags": ["EQUIP_SHIELD"],
"effects": { "ac": "1" }
},
@ -87,6 +111,8 @@
"id": "equip_mediumshield",
"name": { "name": "medium shield", "plural": "medium shields" },
"renderable": { "glyph": "[", "fg": "#C0C0C0", "bg": "#000000", "order": 2 },
"weight": 6,
"value": 10,
"flags": ["EQUIP_SHIELD"],
"effects": { "ac": "2", "melee_power_bonus": "-1" }
},
@ -94,6 +120,8 @@
"id": "equip_largeshield",
"name": { "name": "large shield", "plural": "large shields" },
"renderable": { "glyph": "[", "fg": "#FFF8DC", "bg": "#000000", "order": 2 },
"weight": 12,
"value": 35,
"flags": ["EQUIP_SHIELD"],
"effects": { "ac": "4", "melee_power_bonus": "-2" }
},
@ -101,6 +129,8 @@
"id": "equip_body_weakleather",
"name": { "name": "leather jacket", "plural": "leather jackets" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 8,
"value": 5,
"flags": ["EQUIP_BODY"],
"effects": { "ac": "1" }
},
@ -108,6 +138,8 @@
"id": "equip_body_leather",
"name": { "name": "leather chestpiece", "plural": "leather chestpiece" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 10,
"value": 10,
"flags": ["EQUIP_BODY"],
"effects": { "ac": "2" }
},
@ -115,6 +147,8 @@
"id": "equip_body_studdedleather",
"name": { "name": "studded leather chestpiece", "plural": "studded leather chestpieces" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 13,
"value": 45,
"flags": ["EQUIP_BODY"],
"effects": { "ac": "3" }
},
@ -122,6 +156,8 @@
"id": "equip_body_ringmail_o",
"name": { "name": "orcish ring mail", "plural": "orcish ring mail" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 45,
"value": 50,
"flags": ["EQUIP_BODY"],
"effects": { "ac": "3" }
},
@ -129,6 +165,8 @@
"id": "equip_body_ringmail",
"name": { "name": "ring mail", "plural": "ring mail" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 45,
"value": 70,
"flags": ["EQUIP_BODY"],
"effects": { "ac": "4" }
},
@ -136,6 +174,8 @@
"id": "equip_head_leather",
"name": { "name": "leather cap", "plural": "leather caps" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 2,
"value": 10,
"flags": ["EQUIP_HEAD"],
"effects": { "ac": "1" }
},
@ -143,6 +183,8 @@
"id": "equip_head_elvish",
"name": { "name": "elvish leather helm", "plural": "elvish leather helms" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 2,
"value": 25,
"flags": ["EQUIP_HEAD"],
"effects": { "ac": "2" }
},
@ -150,6 +192,8 @@
"id": "equip_head_o",
"name": { "name": "orcish helm", "plural": "orcish helm" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 6,
"value": 25,
"flags": ["EQUIP_HEAD"],
"effects": { "ac": "2" }
},
@ -157,6 +201,8 @@
"id": "equip_head_iron",
"name": { "name": "iron helm", "plural": "iron helm" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 10,
"value": 45,
"flags": ["EQUIP_HEAD"],
"effects": { "ac": "3" }
},
@ -164,12 +210,16 @@
"id": "equip_feet_leather",
"name": { "name": "leather shoes", "plural": "leather shoes" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 2,
"value": 10,
"flags": ["EQUIP_FEET"]
},
{
"id": "equip_feet_elvish",
"name": { "name": "elvish leather shoes", "plural": "elvish leather shoes" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 2,
"value": 25,
"flags": ["EQUIP_FEET"],
"effects": { "ac": "1" }
},
@ -177,6 +227,8 @@
"id": "equip_feet_o",
"name": { "name": "orcish boots", "plural": "orcish boots" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 6,
"value": 25,
"flags": ["EQUIP_FEET"],
"effects": { "ac": "1" }
},
@ -184,6 +236,8 @@
"id": "equip_feet_iron",
"name": { "name": "iron boots", "plural": "iron boots" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 10,
"value": 45,
"flags": ["EQUIP_FEET"],
"effects": { "ac": "2" }
},
@ -191,6 +245,8 @@
"id": "equip_neck_protection",
"name": { "name": "amulet of protection", "plural": "amulets of protection" },
"renderable": { "glyph": "\"", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 1,
"value": 200,
"flags": ["EQUIP_NECK"],
"effects": { "ac": "1" }
},
@ -198,6 +254,8 @@
"id": "equip_back_protection",
"name": { "name": "cloak of protection", "plural": "cloaks of protection" },
"renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 },
"weight": 1,
"value": 200,
"flags": ["EQUIP_BACK"],
"effects": { "ac": "1" }
},
@ -205,6 +263,8 @@
"id": "wand_magicmissile",
"name": { "name": "wand of magic missile", "plural": "wands of magic missile" },
"renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 2,
"value": 100,
"flags": ["WAND"],
"effects": { "ranged": "12", "damage": "10" }
},
@ -212,6 +272,8 @@
"id": "wand_fireball",
"name": { "name": "wand of fireball", "plural": "wands of fireball" },
"renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 2,
"value": 300,
"flags": ["WAND"],
"effects": { "ranged": "10", "damage": "15", "aoe": "3" }
},
@ -219,6 +281,8 @@
"id": "wand_confusion",
"name": { "name": "wand of confusion", "plural": "wands of confusion" },
"renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 2,
"value": 200,
"flags": ["WAND"],
"effects": { "ranged": "10", "confusion": "4" }
},
@ -226,6 +290,8 @@
"id": "wand_digging",
"name": { "name": "wand of digging", "plural": "wands of digging" },
"renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
"weight": 2,
"value": 300,
"flags": ["WAND"],
"effects": { "ranged": "10", "digger": "" }
},
@ -233,12 +299,16 @@
"id": "food_rations",
"name": { "name": "rations", "plural": "rations" },
"renderable": { "glyph": "%", "fg": "#FFA07A", "bg": "#000000", "order": 2 },
"weight": 1,
"value": 1,
"flags": ["FOOD", "CONSUMABLE"]
},
{
"id": "food_apple",
"name": { "name": "apple", "plural": "apples" },
"renderable": { "glyph": "%", "fg": "#00FF00", "bg": "#000000", "order": 2 },
"weight": 0.5,
"value": 1,
"flags": ["FOOD", "CONSUMABLE"]
}
]

View file

@ -23,6 +23,18 @@
"renderable": { "glyph": "-", "fg": "#AAAAAA", "bg": "#000000", "order": 2 },
"flags": ["PROP"]
},
{
"id": "prop_hay",
"name": "hay",
"renderable": { "glyph": "%", "fg": "#c7ad39", "bg": "#000000", "order": 2 },
"flags": ["PROP"]
},
{
"id": "prop_statue",
"name": "statue",
"renderable": { "glyph": "@", "fg": "#ffffff", "bg": "#000000", "order": 2 },
"flags": ["PROP"]
},
{
"id": "prop_bed",
"name": "bed",

View file

@ -0,0 +1,84 @@
use crate::{gamelog, Attributes, Burden, EquipmentChanged, Equipped, InBackpack, Item, Pools};
use rltk::prelude::*;
use specs::prelude::*;
use std::collections::HashMap;
pub struct EncumbranceSystem {}
impl<'a> System<'a> for EncumbranceSystem {
#[allow(clippy::type_complexity)]
type SystemData = (
WriteStorage<'a, EquipmentChanged>,
Entities<'a>,
ReadStorage<'a, Item>,
ReadStorage<'a, InBackpack>,
ReadStorage<'a, Equipped>,
WriteStorage<'a, Pools>,
ReadStorage<'a, Attributes>,
ReadExpect<'a, Entity>,
WriteStorage<'a, Burden>,
);
fn run(&mut self, data: Self::SystemData) {
let (mut equip_dirty, entities, items, backpacks, wielded, mut pools, attributes, player, mut burdened) = data;
if equip_dirty.is_empty() {
return;
}
// Build update map
let mut to_update: HashMap<Entity, f32> = HashMap::new();
for (entity, _dirty) in (&entities, &equip_dirty).join() {
to_update.insert(entity, 0.0);
}
equip_dirty.clear();
// Total up equipped items
for (item, equipped) in (&items, &wielded).join() {
if to_update.contains_key(&equipped.owner) {
let totals = to_update.get_mut(&equipped.owner).unwrap();
*totals += item.weight;
}
}
// Total carried items
for (item, carried) in (&items, &backpacks).join() {
if to_update.contains_key(&carried.owner) {
let totals = to_update.get_mut(&carried.owner).unwrap();
*totals += item.weight;
}
}
// Apply to pools
for (entity, weight) in to_update.iter() {
if let Some(pool) = pools.get_mut(*entity) {
pool.weight = *weight;
if let Some(attr) = attributes.get(*entity) {
let carry_capacity_lbs = (attr.strength.base + attr.strength.modifiers) * 10;
if pool.weight as i32 > 3 * carry_capacity_lbs {
// Overloaded
burdened
.insert(*entity, Burden { level: crate::BurdenLevel::Overloaded })
.expect("Failed to insert Burden");
if *entity == *player {
gamelog::Logger::new().append("You're overloaded!").log();
}
} else if pool.weight as i32 > 2 * carry_capacity_lbs {
// Strained
burdened
.insert(*entity, Burden { level: crate::BurdenLevel::Strained })
.expect("Failed to insert Burden");
if *entity == *player {
gamelog::Logger::new().append("You're strained.").log();
}
} else if pool.weight as i32 > carry_capacity_lbs {
// Burdened
burdened
.insert(*entity, Burden { level: crate::BurdenLevel::Burdened })
.expect("Failed to insert Burden");
if *entity == *player {
gamelog::Logger::new().append("You're burdened.").log();
}
} else {
burdened.remove(*entity);
}
}
}
}
}
}

View file

@ -1,4 +1,4 @@
use crate::{Clock, Energy, Name, Position, RunState, TakingTurn, LOG_TICKS};
use crate::{Burden, BurdenLevel, Clock, Energy, Name, Position, RunState, TakingTurn, LOG_TICKS};
use rltk::prelude::*;
use specs::prelude::*;
@ -12,6 +12,7 @@ impl<'a> System<'a> for EnergySystem {
type SystemData = (
ReadStorage<'a, Clock>,
WriteStorage<'a, Energy>,
ReadStorage<'a, Burden>,
ReadStorage<'a, Position>,
WriteStorage<'a, TakingTurn>,
Entities<'a>,
@ -22,7 +23,7 @@ impl<'a> System<'a> for EnergySystem {
);
fn run(&mut self, data: Self::SystemData) {
let (clock, mut energies, positions, mut turns, entities, mut rng, mut runstate, player, names) = data;
let (clock, mut energies, burdens, positions, mut turns, entities, mut rng, mut runstate, player, names) = data;
// If not ticking, do nothing.
if *runstate != RunState::Ticking {
return;
@ -44,8 +45,17 @@ impl<'a> System<'a> for EnergySystem {
}
// EVERYTHING ELSE
for (entity, energy, _pos) in (&entities, &mut energies, &positions).join() {
let burden_modifier = if let Some(burden) = burdens.get(entity) {
match burden.level {
BurdenLevel::Burdened => 0.75,
BurdenLevel::Strained => 0.5,
BurdenLevel::Overloaded => 0.25,
}
} else {
1.0
};
// Every entity has a POTENTIAL equal to their speed.
let mut energy_potential: i32 = energy.speed;
let mut energy_potential: i32 = (energy.speed as f32 * burden_modifier) as i32;
// Increment current energy by NORMAL_SPEED for every
// whole number of NORMAL_SPEEDS in their POTENTIAL.
while energy_potential >= NORMAL_SPEED {

View file

@ -6,3 +6,5 @@ mod quip_system;
pub use quip_system::QuipSystem;
mod regen_system;
pub use regen_system::RegenSystem;
mod encumbrance_system;
pub use encumbrance_system::EncumbranceSystem;

View file

@ -143,6 +143,7 @@ pub struct Pools {
pub xp: i32,
pub bac: i32,
pub level: i32,
pub weight: f32,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
@ -201,7 +202,25 @@ impl SufferDamage {
}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Item {}
pub struct Item {
pub weight: f32, // in lbs
pub value: f32, // base
}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct EquipmentChanged {}
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
pub enum BurdenLevel {
Burdened,
Strained,
Overloaded,
}
#[derive(Component, Serialize, Deserialize, Clone)]
pub struct Burden {
pub level: BurdenLevel,
}
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
pub enum EquipmentSlot {

View file

@ -1,7 +1,7 @@
use super::{
camera, gamelog, gamesystem, rex_assets::RexAssets, ArmourClassBonus, Attributes, Equipped, Hidden, HungerClock,
HungerState, InBackpack, Map, Name, Player, Point, Pools, Position, Prop, Renderable, RunState, Skill, Skills,
State, Viewshed,
camera, gamelog, gamesystem, rex_assets::RexAssets, ArmourClassBonus, Attributes, Burden, Equipped, Hidden,
HungerClock, HungerState, InBackpack, Map, Name, Player, Point, Pools, Position, Prop, Renderable, RunState, Skill,
Skills, State, Viewshed,
};
use rltk::{Rltk, VirtualKeyCode, RGB};
use specs::prelude::*;
@ -49,6 +49,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
let attributes = ecs.read_storage::<Attributes>();
let players = ecs.read_storage::<Player>();
let hunger = ecs.read_storage::<HungerClock>();
let burden = ecs.read_storage::<Burden>();
let skills = ecs.read_storage::<Skills>();
for (_player, stats, attributes, hunger, skills) in (&players, &pools, &attributes, &hunger, &skills).join() {
// Draw hp/mana bars
@ -56,7 +57,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
ctx,
2,
53,
26,
22,
stats.hit_points.current,
stats.hit_points.max,
RGB::from_u8(0, 255, 0),
@ -66,7 +67,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
ctx,
2,
54,
26,
22,
stats.mana.current,
stats.mana.max,
RGB::named(rltk::BLUE),
@ -84,11 +85,11 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
}
}
let armour_class = stats.bac - attributes.dexterity.bonus - skill_ac_bonus - armour_ac_bonus;
ctx.print_color(30, 53, RGB::named(rltk::PINK), RGB::named(rltk::BLACK), "AC");
ctx.print_color(32, 53, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), armour_class);
ctx.print_color(26, 53, RGB::named(rltk::PINK), RGB::named(rltk::BLACK), "AC");
ctx.print_color(28, 53, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), armour_class);
// Draw level
ctx.print_color(
30,
26,
54,
RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK),
@ -124,25 +125,46 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
ctx.print_color_right(70, 53, RGB::named(rltk::RED), RGB::named(rltk::BLACK), "Fainting")
}
}
// Burden
if let Some(burden) = burden.get(*player_entity) {
match burden.level {
crate::BurdenLevel::Burdened => {
ctx.print_color_right(70, 50, RGB::named(rltk::BROWN1), RGB::named(rltk::BLACK), "Burdened")
}
crate::BurdenLevel::Strained => {
ctx.print_color_right(70, 50, RGB::named(rltk::ORANGE), RGB::named(rltk::BLACK), "Strained")
}
crate::BurdenLevel::Overloaded => {
ctx.print_color_right(70, 50, RGB::named(rltk::RED), RGB::named(rltk::BLACK), "Overloaded")
}
}
}
// Draw equipment
let names = ecs.read_storage::<Name>();
let mut equipment: Vec<String> = Vec::new();
for (_equipped, name) in (&equipped, &names).join().filter(|item| item.0.owner == *player_entity) {
equipment.push(format!("- {} (worn)", &name.name));
equipment.push(format!("{} (worn)", &name.name));
}
let mut y = 1;
if !equipment.is_empty() {
ctx.print_color(72, y, RGB::named(rltk::BLACK), RGB::named(rltk::WHITE), "Equipment");
for item in equipment {
y += 1;
ctx.print_color(72, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), item);
ctx.print_color(72, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "-");
ctx.print_color(74, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), item);
}
y += 2;
}
// Draw consumables
ctx.print_color(72, y, RGB::named(rltk::BLACK), RGB::named(rltk::WHITE), "Backpack");
ctx.print_color(
81,
y,
RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK),
&format!("[{:.1}/{} lbs]", stats.weight, (attributes.strength.base + attributes.strength.modifiers) * 10),
);
y += 1;
let (player_inventory, _inventory_ids) = get_player_inventory(&ecs);
y = print_options(player_inventory, 72, y, ctx).0;

View file

@ -1,8 +1,9 @@
use super::{
gamelog, Confusion, Consumable, Cursed, Destructible, Digger, Equippable, Equipped, HungerClock, HungerState,
InBackpack, InflictsDamage, MagicMapper, Map, Name, ParticleBuilder, Point, Pools, Position, ProvidesHealing,
ProvidesNutrition, RandomNumberGenerator, RunState, SufferDamage, TileType, Viewshed, Wand, WantsToDropItem,
WantsToPickupItem, WantsToRemoveItem, WantsToUseItem, AOE, DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME,
gamelog, Confusion, Consumable, Cursed, Destructible, Digger, EquipmentChanged, Equippable, Equipped, HungerClock,
HungerState, InBackpack, InflictsDamage, MagicMapper, Map, Name, ParticleBuilder, Point, Pools, Position,
ProvidesHealing, ProvidesNutrition, RandomNumberGenerator, RunState, SufferDamage, TileType, Viewshed, Wand,
WantsToDropItem, WantsToPickupItem, WantsToRemoveItem, WantsToUseItem, AOE, DEFAULT_PARTICLE_LIFETIME,
LONG_PARTICLE_LIFETIME,
};
use specs::prelude::*;
@ -16,14 +17,18 @@ impl<'a> System<'a> for ItemCollectionSystem {
WriteStorage<'a, Position>,
ReadStorage<'a, Name>,
WriteStorage<'a, InBackpack>,
WriteStorage<'a, EquipmentChanged>,
);
fn run(&mut self, data: Self::SystemData) {
let (player_entity, mut wants_pickup, mut positions, names, mut backpack) = data;
let (player_entity, mut wants_pickup, mut positions, names, mut backpack, mut equipment_changed) = data;
for pickup in wants_pickup.join() {
positions.remove(pickup.item);
backpack.insert(pickup.item, InBackpack { owner: pickup.collected_by }).expect("Unable to pickup item.");
equipment_changed
.insert(pickup.collected_by, EquipmentChanged {})
.expect("Unable to insert EquipmentChanged.");
if pickup.collected_by == *player_entity {
gamelog::Logger::new()
@ -41,7 +46,8 @@ impl<'a> System<'a> for ItemCollectionSystem {
// Grouping together components because of type complexity issues - SystemData was too large.
// This is a temporary solution that'll be fixed once inventory use is refactored into separate
// systems.
type EquipComponents<'a> = (ReadStorage<'a, Equippable>, WriteStorage<'a, Equipped>);
type EquipComponents<'a> =
(ReadStorage<'a, Equippable>, WriteStorage<'a, Equipped>, WriteStorage<'a, EquipmentChanged>);
pub struct ItemUseSystem {}
impl<'a> System<'a> for ItemUseSystem {
@ -100,12 +106,15 @@ impl<'a> System<'a> for ItemUseSystem {
mut confused,
magic_mapper,
mut runstate,
(equippable, mut equipped),
(equippable, mut equipped, mut equipment_changed),
mut backpack,
mut viewsheds,
) = data;
for (entity, wants_to_use) in (&entities, &wants_to_use).join() {
// Could probably limit this insert only to if something is consumed/equipped/etc., but this is
// safer and items aren't used nearly frequently enough for this to cause performance issues.
equipment_changed.insert(entity, EquipmentChanged {}).expect("Unable to insert EquipmentChanged.");
let mut verb = "use";
let mut used_item = true;
let mut aoe_item = false;
@ -413,12 +422,14 @@ impl<'a> System<'a> for ItemDropSystem {
ReadStorage<'a, Name>,
WriteStorage<'a, Position>,
WriteStorage<'a, InBackpack>,
WriteStorage<'a, EquipmentChanged>,
);
fn run(&mut self, data: Self::SystemData) {
let (player_entity, entities, mut wants_drop, names, mut positions, mut backpack) = data;
let (player_entity, entities, mut wants_drop, names, mut positions, mut backpack, mut equipment_changed) = data;
for (entity, to_drop) in (&entities, &wants_drop).join() {
equipment_changed.insert(entity, EquipmentChanged {}).expect("Unable to insert EquipmentChanged.");
let mut dropper_pos: Position = Position { x: 0, y: 0 };
{
let dropped_pos = positions.get(entity).unwrap();

View file

@ -96,6 +96,7 @@ impl State {
let mut vis = VisibilitySystem {};
let mut regen_system = ai::RegenSystem {};
let mut energy = ai::EnergySystem {};
let mut encumbrance_system = ai::EncumbranceSystem {};
let mut turn_status_system = ai::TurnStatusSystem {};
let mut quip_system = ai::QuipSystem {};
let mut mob = MonsterAI {};
@ -113,6 +114,7 @@ impl State {
mapindex.run_now(&self.ecs);
vis.run_now(&self.ecs);
regen_system.run_now(&self.ecs);
encumbrance_system.run_now(&self.ecs);
energy.run_now(&self.ecs);
turn_status_system.run_now(&self.ecs);
quip_system.run_now(&self.ecs);
@ -491,6 +493,7 @@ fn main() -> rltk::BError {
gs.ecs.register::<Position>();
gs.ecs.register::<OtherLevelPosition>();
gs.ecs.register::<Renderable>();
gs.ecs.register::<Burden>();
gs.ecs.register::<Prop>();
gs.ecs.register::<Player>();
gs.ecs.register::<Clock>();
@ -516,6 +519,7 @@ fn main() -> rltk::BError {
gs.ecs.register::<Energy>();
gs.ecs.register::<TakingTurn>();
gs.ecs.register::<Equippable>();
gs.ecs.register::<EquipmentChanged>();
gs.ecs.register::<Equipped>();
gs.ecs.register::<MeleeWeapon>();
gs.ecs.register::<NaturalAttacks>();

View file

@ -127,14 +127,14 @@ impl TownBuilder {
) {
for idx in available_building_tiles.iter() {
if rng.roll_dice(1, 40) == 1 {
let roll = rng.roll_dice(1, 6);
let roll = rng.roll_dice(1, 7);
match roll {
1 => build_data.spawn_list.push((*idx, "npc_fisher".to_string())),
2 => build_data.spawn_list.push((*idx, "npc_dockworker".to_string())),
3 => build_data.spawn_list.push((*idx, "npc_drunk".to_string())),
4 => build_data.spawn_list.push((*idx, "npc_townsperson".to_string())),
5 => build_data.spawn_list.push((*idx, "npc_guard".to_string())),
_ => {
6 => {
let animal_roll = rng.roll_dice(1, 3);
match animal_roll {
1 => build_data.spawn_list.push((*idx, "chicken_little".to_string())),
@ -142,6 +142,14 @@ impl TownBuilder {
_ => build_data.spawn_list.push((*idx, "dog_little".to_string())),
}
}
_ => {
let prop_roll = rng.roll_dice(1, 3);
match prop_roll {
1 => build_data.spawn_list.push((*idx, "prop_hay".to_string())),
2 => build_data.spawn_list.push((*idx, "prop_statue".to_string())),
_ => {}
}
}
}
}
}

View file

@ -6,6 +6,8 @@ pub struct Item {
pub id: String,
pub name: Name,
pub renderable: Option<Renderable>,
pub weight: Option<f32>,
pub value: Option<f32>,
pub flags: Option<Vec<String>>,
pub effects: Option<HashMap<String, String>>,
}

View file

@ -114,7 +114,7 @@ pub fn spawn_named_item(raws: &RawMaster, ecs: &mut World, key: &str, pos: Spawn
let mut eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
eb = eb.with(Name { name: item_template.name.name.clone(), plural: item_template.name.plural.clone() });
eb = eb.with(Item {});
eb = eb.with(Item { weight: item_template.weight.unwrap_or(0.0), value: item_template.value.unwrap_or(0.0) });
eb = spawn_position(pos, eb, key, raws);
if let Some(renderable) = &item_template.renderable {
@ -312,8 +312,10 @@ pub fn spawn_named_mob(
bac: mob_bac,
hit_points: Pool { current: mob_hp, max: mob_hp },
mana: Pool { current: mob_mana, max: mob_mana },
weight: 0.0,
};
eb = eb.with(pools);
eb = eb.with(EquipmentChanged {});
let mut skills = Skills { skills: HashMap::new() };
skills.skills.insert(Skill::Melee, 0);

View file

@ -55,6 +55,7 @@ pub fn save_game(ecs: &mut World) {
Attributes,
BlocksTile,
BlocksVisibility,
Burden,
Bystander,
Clock,
Confusion,
@ -66,6 +67,7 @@ pub fn save_game(ecs: &mut World) {
Energy,
EntityMoved,
EntryTrigger,
EquipmentChanged,
Equippable,
Equipped,
GrantsXP,
@ -165,6 +167,7 @@ pub fn load_game(ecs: &mut World) {
Attributes,
BlocksTile,
BlocksVisibility,
Burden,
Bystander,
Clock,
Confusion,
@ -176,6 +179,7 @@ pub fn load_game(ecs: &mut World) {
Energy,
EntityMoved,
EntryTrigger,
EquipmentChanged,
Equippable,
Equipped,
GrantsXP,

View file

@ -1,7 +1,7 @@
use super::{
ai::NORMAL_SPEED, gamesystem, gamesystem::attr_bonus, random_table::RandomTable, raws, Attribute, Attributes,
Clock, Energy, HungerClock, HungerState, Map, Name, Player, Pool, Pools, Position, Rect, Renderable, SerializeMe,
Skill, Skills, TileType, Viewshed,
Clock, Energy, EquipmentChanged, HungerClock, HungerState, Map, Name, Player, Pool, Pools, Position, Rect,
Renderable, SerializeMe, Skill, Skills, TileType, Viewshed,
};
use rltk::{RandomNumberGenerator, RGB};
use specs::prelude::*;
@ -53,7 +53,9 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
xp: 0,
level: 1,
bac: 10,
weight: 0.0,
})
.with(EquipmentChanged {})
.with(skills)
.with(Energy { current: 0, speed: NORMAL_SPEED })
.marked::<SimpleMarker<SerializeMe>>()