Add clothing to player and NPCs
This commit is contained in:
parent
d96d1ce003
commit
5b227115db
280
raws/spawns.json
280
raws/spawns.json
@ -184,6 +184,49 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Dried Sausage",
|
||||
"renderable": {
|
||||
"glyph": "%",
|
||||
"fg": "#00FF00",
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"consumable": {
|
||||
"effects": {
|
||||
"food": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Beer",
|
||||
"renderable": {
|
||||
"glyph": "!",
|
||||
"fg": "#FF00FF",
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"consumable": {
|
||||
"effects": {
|
||||
"provides_healing": "4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Rusty Longsword",
|
||||
"renderable": {
|
||||
"glyph": "/",
|
||||
"fg": "#BB77BB",
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"weapon": {
|
||||
"range": "melee",
|
||||
"attribute": "Might",
|
||||
"base_damage": "1d8-1",
|
||||
"hit_bonus": -1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Dagger",
|
||||
"renderable": {
|
||||
@ -194,7 +237,9 @@
|
||||
},
|
||||
"weapon": {
|
||||
"range": "melee",
|
||||
"power_bonus": 2
|
||||
"attribute": "Quickness",
|
||||
"base_damage": "1d4",
|
||||
"hit_bonus": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -207,7 +252,9 @@
|
||||
},
|
||||
"weapon": {
|
||||
"range": "melee",
|
||||
"power_bonus": 4
|
||||
"attribute": "Might",
|
||||
"base_damage": "1d8",
|
||||
"hit_bonus": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -220,7 +267,9 @@
|
||||
},
|
||||
"weapon": {
|
||||
"range": "melee",
|
||||
"power_bonus": 5
|
||||
"attribute": "Might",
|
||||
"base_damage": "1d8+1",
|
||||
"hit_bonus": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -231,8 +280,9 @@
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"shield": {
|
||||
"defense_bonus": 1
|
||||
"wearable": {
|
||||
"slot": "Shield",
|
||||
"armor_class": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -243,8 +293,102 @@
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"shield": {
|
||||
"defense_bonus": 3
|
||||
"wearable": {
|
||||
"slot": "Shield",
|
||||
"armor_class": 2.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Stained Tunic",
|
||||
"renderable": {
|
||||
"glyph": "[",
|
||||
"fg": "#00FF00",
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"wearable": {
|
||||
"slot": "Torso",
|
||||
"armor_class": 0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Torn Trousers",
|
||||
"renderable": {
|
||||
"glyph": "[",
|
||||
"fg": "#00FFFF",
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"wearable": {
|
||||
"slot": "Legs",
|
||||
"armor_class": 0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Old Boots",
|
||||
"renderable": {
|
||||
"glyph": "[",
|
||||
"fg": "#FF9999",
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"wearable": {
|
||||
"slot": "Legs",
|
||||
"armor_class": 0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Cudgel",
|
||||
"renderable": {
|
||||
"glyph": "/",
|
||||
"fg": "#A52A2A",
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"weapon": {
|
||||
"range": "melee",
|
||||
"attribute": "Quickness",
|
||||
"base_damage": "1d4",
|
||||
"hit_bonus": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Cloth Tunic",
|
||||
"renderable": {
|
||||
"glyph": "[",
|
||||
"fg": "#00FF00",
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"wearable": {
|
||||
"slot": "Torso",
|
||||
"armor_class": 0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Cloth Pants",
|
||||
"renderable": {
|
||||
"glyph": "[",
|
||||
"fg": "#00FFFF",
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"wearable": {
|
||||
"slot": "Legs",
|
||||
"armor_class": 0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Slippers",
|
||||
"renderable": {
|
||||
"glyph": "[",
|
||||
"fg": "#FF9999",
|
||||
"bg": "#000000",
|
||||
"order": 2
|
||||
},
|
||||
"wearable": {
|
||||
"slot": "Legs",
|
||||
"armor_class": 0.1
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -265,7 +409,13 @@
|
||||
},
|
||||
"skills": {
|
||||
"Melee": 2
|
||||
}
|
||||
},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Shady Salesman",
|
||||
@ -278,7 +428,13 @@
|
||||
"blocks_tile": true,
|
||||
"vision_range": 4,
|
||||
"ai": "vendor",
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Patron",
|
||||
@ -296,7 +452,13 @@
|
||||
"Oh my, I drank too much.",
|
||||
"Still saving the world, eh?"
|
||||
],
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Priest",
|
||||
@ -309,7 +471,13 @@
|
||||
"blocks_tile": true,
|
||||
"vision_range": 4,
|
||||
"ai": "bystander",
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Parishioner",
|
||||
@ -327,7 +495,13 @@
|
||||
"I hear there's going to be a good sermon on tea",
|
||||
"Want some cake?"
|
||||
],
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Blacksmith",
|
||||
@ -340,7 +514,13 @@
|
||||
"blocks_tile": true,
|
||||
"vision_range": 4,
|
||||
"ai": "vendor",
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Clothier",
|
||||
@ -353,7 +533,13 @@
|
||||
"blocks_tile": true,
|
||||
"vision_range": 4,
|
||||
"ai": "vendor",
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Alchemist",
|
||||
@ -366,7 +552,13 @@
|
||||
"blocks_tile": true,
|
||||
"vision_range": 4,
|
||||
"ai": "vendor",
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Mom",
|
||||
@ -385,7 +577,13 @@
|
||||
"Be careful in the dungeon!",
|
||||
"Your father would be so proud, were he here."
|
||||
],
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Peasant",
|
||||
@ -401,7 +599,13 @@
|
||||
"quips": [
|
||||
"Why are you in my house?"
|
||||
],
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Dock Worker",
|
||||
@ -419,7 +623,13 @@
|
||||
"Nice weather",
|
||||
"Hello"
|
||||
],
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Fisher",
|
||||
@ -437,7 +647,13 @@
|
||||
"I caught something, but it wasn't a fish!",
|
||||
"Looks like rain"
|
||||
],
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Wannabe Pirate",
|
||||
@ -455,7 +671,13 @@
|
||||
"Grog!",
|
||||
"Booze!"
|
||||
],
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Drunk",
|
||||
@ -473,7 +695,13 @@
|
||||
"Need... more... booze!",
|
||||
"Spare a copper?"
|
||||
],
|
||||
"attributes": {}
|
||||
"attributes": {},
|
||||
"equipped": [
|
||||
"Cudgel",
|
||||
"Cloth Tunic",
|
||||
"Cloth Pants",
|
||||
"Slippers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Rat",
|
||||
@ -493,6 +721,16 @@
|
||||
"skills": {
|
||||
"Melee": -1,
|
||||
"Defense": -1
|
||||
},
|
||||
"natural": {
|
||||
"armor_class": 11,
|
||||
"attacks": [
|
||||
{
|
||||
"name": "bite",
|
||||
"hit_bonus": 0,
|
||||
"damage": "1d4"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -165,6 +165,11 @@ pub struct WantsToRemoveItem {
|
||||
pub enum EquipmentSlot {
|
||||
Melee,
|
||||
Shield,
|
||||
Head,
|
||||
Torso,
|
||||
Legs,
|
||||
Feet,
|
||||
Hands,
|
||||
}
|
||||
|
||||
#[derive(Component, Serialize, Deserialize, Clone)]
|
||||
@ -194,8 +199,9 @@ pub struct MeleeWeapon {
|
||||
}
|
||||
|
||||
#[derive(Component, ConvertSaveload, Clone)]
|
||||
pub struct DefenseBonus {
|
||||
pub defense: i32,
|
||||
pub struct Wearable {
|
||||
pub armor_class: f32,
|
||||
pub slot: EquipmentSlot,
|
||||
}
|
||||
|
||||
#[derive(Component, Serialize, Deserialize, Clone)]
|
||||
|
@ -519,7 +519,7 @@ fn main() -> ::rltk::BError {
|
||||
Equippable,
|
||||
Equipped,
|
||||
MeleeWeapon,
|
||||
DefenseBonus,
|
||||
Wearable,
|
||||
WantsToRemoveItem,
|
||||
ParticleLifetime,
|
||||
HungerClock,
|
||||
|
@ -2,12 +2,13 @@ use ::rltk::{RandomNumberGenerator, RGB};
|
||||
use ::specs::prelude::*;
|
||||
|
||||
use crate::components::{
|
||||
Attributes, HungerClock, HungerState, Name, Pools, Skill, Skills, SufferDamage, WantsToMelee,
|
||||
Attributes, Equipped, HungerClock, HungerState, MeleeWeapon, Name, Pools, Skill, Skills,
|
||||
SufferDamage, WantsToMelee, Wearable,
|
||||
};
|
||||
use crate::game_log::GameLog;
|
||||
use crate::gamesystem::skill_bonus;
|
||||
use crate::particle_system::ParticleBuilder;
|
||||
use crate::Position;
|
||||
use crate::{EquipmentSlot, Position, WeaponAttribute};
|
||||
|
||||
pub struct MeleeCombatSystem {}
|
||||
|
||||
@ -26,6 +27,9 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||
ReadStorage<'a, HungerClock>,
|
||||
ReadStorage<'a, Pools>,
|
||||
WriteExpect<'a, RandomNumberGenerator>,
|
||||
ReadStorage<'a, Equipped>,
|
||||
ReadStorage<'a, MeleeWeapon>,
|
||||
ReadStorage<'a, Wearable>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
@ -42,6 +46,9 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||
hunger_clock,
|
||||
pools,
|
||||
mut rng,
|
||||
equipped_items,
|
||||
meleeweapons,
|
||||
wearables,
|
||||
) = data;
|
||||
|
||||
for (entity, wants_melee, name, attacker_attributes, attacker_skills, attacker_pools) in (
|
||||
@ -61,10 +68,28 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||
if attacker_pools.hit_points.current > 0 && target_pools.hit_points.current > 0 {
|
||||
let target_name = names.get(wants_melee.target).unwrap();
|
||||
|
||||
let mut weapon_info = MeleeWeapon {
|
||||
attribute: WeaponAttribute::Might,
|
||||
hit_bonus: 0,
|
||||
damage_n_dice: 1,
|
||||
damage_die_type: 4,
|
||||
damage_bonus: 0,
|
||||
};
|
||||
|
||||
for (wielded, melee) in (&equipped_items, &meleeweapons).join() {
|
||||
if wielded.owner == entity && wielded.slot == EquipmentSlot::Melee {
|
||||
weapon_info = melee.clone();
|
||||
}
|
||||
}
|
||||
|
||||
let natural_roll = rng.roll_dice(1, 20);
|
||||
let attribute_hit_bonus = attacker_attributes.might.bonus;
|
||||
let attribute_hit_bonus = if weapon_info.attribute == WeaponAttribute::Might {
|
||||
attacker_attributes.might.bonus
|
||||
} else {
|
||||
attacker_attributes.quickness.bonus
|
||||
};
|
||||
let skill_hit_bonus = skill_bonus(Skill::Melee, &*attacker_skills);
|
||||
let weapon_hit_bonus = 0; // TODO: Once weapons support this
|
||||
let weapon_hit_bonus = weapon_info.hit_bonus;
|
||||
let mut status_hit_bonus = 0;
|
||||
if let Some(hc) = hunger_clock.get(entity) {
|
||||
// Well-Fed grants +1
|
||||
@ -78,10 +103,21 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||
+ weapon_hit_bonus
|
||||
+ status_hit_bonus;
|
||||
|
||||
let mut armor_item_bonus_f = 0.0;
|
||||
for (wielded, armor) in (&equipped_items, &wearables).join() {
|
||||
if wielded.owner == wants_melee.target {
|
||||
armor_item_bonus_f += armor.armor_class;
|
||||
}
|
||||
}
|
||||
|
||||
// let base_armor_class = match natural.get(wants_melee.target) {
|
||||
// None => 10,
|
||||
// Some(nat) = nat.armor_class.unwrap_or(10);
|
||||
// };
|
||||
let base_armor_class = 10;
|
||||
let armor_quickness_bonus = target_attributes.quickness.bonus;
|
||||
let armor_skill_bonus = skill_bonus(Skill::Defense, &*target_skills);
|
||||
let armor_item_bonus = 0; // TODO: Once armor supports this
|
||||
let armor_item_bonus = armor_item_bonus_f as i32;
|
||||
let armor_class =
|
||||
base_armor_class + armor_quickness_bonus + armor_skill_bonus + armor_item_bonus;
|
||||
|
||||
@ -90,7 +126,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||
let base_damage = rng.roll_dice(1, 4);
|
||||
let attr_damage_bonus = attacker_attributes.might.bonus;
|
||||
let skill_damage_bonus = skill_bonus(Skill::Melee, &*attacker_skills);
|
||||
let weapon_damage_bonus = 0;
|
||||
let weapon_damage_bonus = weapon_info.damage_bonus;
|
||||
|
||||
let damage = i32::max(
|
||||
0,
|
||||
|
@ -8,7 +8,7 @@ pub struct Item {
|
||||
pub renderable: Option<Renderable>,
|
||||
pub consumable: Option<Consumable>,
|
||||
pub weapon: Option<Weapon>,
|
||||
pub shield: Option<Shield>,
|
||||
pub wearable: Option<Wearable>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
@ -33,6 +33,7 @@ pub struct Weapon {
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Shield {
|
||||
pub defense_bonus: i32,
|
||||
pub struct Wearable {
|
||||
pub armor_class: f32,
|
||||
pub slot: String,
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ pub struct Mob {
|
||||
pub level: Option<i32>,
|
||||
pub hp: Option<i32>,
|
||||
pub mana: Option<i32>,
|
||||
pub equipped: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
|
@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet};
|
||||
|
||||
use ::regex::Regex;
|
||||
use ::specs::prelude::*;
|
||||
use ::specs::saveload::{MarkedBuilder, SimpleMarker};
|
||||
|
||||
use crate::components::*;
|
||||
use crate::gamesystem::{mana_at_level, npc_hp};
|
||||
@ -16,7 +17,7 @@ pub fn parse_dice_string(dice: &str) -> (i32, i32, i32) {
|
||||
let mut die_type = 4;
|
||||
let mut die_bonus = 0;
|
||||
|
||||
for cap in DIC_RE.captures_iter(dice) {
|
||||
for cap in DICE_RE.captures_iter(dice) {
|
||||
if let Some(group) = cap.get(1) {
|
||||
n_dice = group.as_str().parse::<i32>().expect("Not a digit");
|
||||
}
|
||||
@ -33,6 +34,8 @@ pub fn parse_dice_string(dice: &str) -> (i32, i32, i32) {
|
||||
|
||||
pub enum SpawnType {
|
||||
AtPosition { x: i32, y: i32 },
|
||||
Equipped { by: Entity },
|
||||
Carried { by: Entity },
|
||||
}
|
||||
|
||||
pub struct RawMaster {
|
||||
@ -103,17 +106,40 @@ impl RawMaster {
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_position(pos: SpawnType, new_entity: EntityBuilder) -> EntityBuilder {
|
||||
let mut eb = new_entity;
|
||||
fn find_slot_for_equippable_item(tag: &str, raws: &RawMaster) -> EquipmentSlot {
|
||||
if !raws.item_index.contains_key(tag) {
|
||||
panic!("Trying to equip an unknown item: {}", tag);
|
||||
}
|
||||
|
||||
let item_index = raws.item_index[tag];
|
||||
let item = &raws.raws.items[item_index];
|
||||
|
||||
if item.weapon.is_some() {
|
||||
return EquipmentSlot::Melee;
|
||||
} else if let Some(wearable) = &item.wearable {
|
||||
return string_to_slot(&wearable.slot);
|
||||
}
|
||||
|
||||
panic!("Trying to equip {}, but it has not slot tag", tag);
|
||||
}
|
||||
|
||||
fn spawn_position<'a>(
|
||||
pos: SpawnType,
|
||||
new_entity: EntityBuilder<'a>,
|
||||
tag: &str,
|
||||
raws: &RawMaster,
|
||||
) -> EntityBuilder<'a> {
|
||||
let eb = new_entity;
|
||||
|
||||
// Spawn in the specified location
|
||||
match pos {
|
||||
SpawnType::AtPosition { x, y } => {
|
||||
eb = eb.with(Position { x, y });
|
||||
SpawnType::AtPosition { x, y } => eb.with(Position { x, y }),
|
||||
SpawnType::Carried { by } => eb.with(InBackpack { owner: by }),
|
||||
SpawnType::Equipped { by } => {
|
||||
let slot = find_slot_for_equippable_item(tag, raws);
|
||||
eb.with(Equipped { owner: by, slot })
|
||||
}
|
||||
}
|
||||
|
||||
eb
|
||||
}
|
||||
|
||||
fn get_renderable_component(
|
||||
@ -127,19 +153,36 @@ fn get_renderable_component(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string_to_slot(slot: &str) -> EquipmentSlot {
|
||||
match slot {
|
||||
"Shield" => EquipmentSlot::Shield,
|
||||
"Head" => EquipmentSlot::Head,
|
||||
"Torso" => EquipmentSlot::Torso,
|
||||
"Legs" => EquipmentSlot::Legs,
|
||||
"Feet" => EquipmentSlot::Feet,
|
||||
"Hands" => EquipmentSlot::Hands,
|
||||
"Melee" => EquipmentSlot::Melee,
|
||||
_ => {
|
||||
rltk::console::log(format!("Warning: unknown equipment slot type [{}]", slot));
|
||||
|
||||
EquipmentSlot::Melee
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn_named_item(
|
||||
raws: &RawMaster,
|
||||
new_entity: EntityBuilder,
|
||||
ecs: &mut World,
|
||||
key: &str,
|
||||
pos: SpawnType,
|
||||
) -> Option<Entity> {
|
||||
if raws.item_index.contains_key(key) {
|
||||
let item_template = &raws.raws.items[raws.item_index[key]];
|
||||
|
||||
let mut eb = new_entity;
|
||||
let mut eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
|
||||
|
||||
// Spawn in the specified location
|
||||
eb = spawn_position(pos, eb);
|
||||
eb = spawn_position(pos, eb, key, raws);
|
||||
|
||||
// Renderable
|
||||
if let Some(renderable) = &item_template.renderable {
|
||||
@ -196,17 +239,29 @@ pub fn spawn_named_item(
|
||||
eb = eb.with(Equippable {
|
||||
slot: EquipmentSlot::Melee,
|
||||
});
|
||||
eb = eb.with(MeleePowerBonus {
|
||||
power: weapon.power_bonus,
|
||||
});
|
||||
let (n_dice, die_type, bonus) = parse_dice_string(&weapon.base_damage);
|
||||
let mut wpn = MeleeWeapon {
|
||||
attribute: WeaponAttribute::Might,
|
||||
damage_n_dice: n_dice,
|
||||
damage_die_type: die_type,
|
||||
damage_bonus: bonus,
|
||||
hit_bonus: weapon.hit_bonus,
|
||||
};
|
||||
|
||||
wpn.attribute = match weapon.attribute.as_str() {
|
||||
"Quickness" => WeaponAttribute::Quickness,
|
||||
_ => WeaponAttribute::Might,
|
||||
};
|
||||
|
||||
eb = eb.with(wpn);
|
||||
}
|
||||
|
||||
if let Some(shield) = &item_template.shield {
|
||||
eb = eb.with(Equippable {
|
||||
slot: EquipmentSlot::Shield,
|
||||
});
|
||||
eb = eb.with(DefenseBonus {
|
||||
defense: shield.defense_bonus,
|
||||
if let Some(wearable) = &item_template.wearable {
|
||||
let slot = string_to_slot(&wearable.slot);
|
||||
eb = eb.with(Equippable { slot });
|
||||
eb = eb.with(Wearable {
|
||||
slot,
|
||||
armor_class: wearable.armor_class,
|
||||
});
|
||||
}
|
||||
|
||||
@ -218,17 +273,17 @@ pub fn spawn_named_item(
|
||||
|
||||
pub fn spawn_named_mob(
|
||||
raws: &RawMaster,
|
||||
new_entity: EntityBuilder,
|
||||
ecs: &mut World,
|
||||
key: &str,
|
||||
pos: SpawnType,
|
||||
) -> Option<Entity> {
|
||||
if raws.mob_index.contains_key(key) {
|
||||
let mob_template = &raws.raws.mobs[raws.mob_index[key]];
|
||||
|
||||
let mut eb = new_entity;
|
||||
let mut eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
|
||||
|
||||
// Spawn in the specified location
|
||||
eb = spawn_position(pos, eb);
|
||||
eb = spawn_position(pos, eb, key, raws);
|
||||
|
||||
// Renderable
|
||||
if let Some(renderable) = &mob_template.renderable {
|
||||
@ -251,6 +306,10 @@ pub fn spawn_named_mob(
|
||||
});
|
||||
}
|
||||
|
||||
if mob_template.blocks_tile {
|
||||
eb = eb.with(BlocksTile {});
|
||||
}
|
||||
|
||||
let mut mob_fitness = 11;
|
||||
let mut mob_int = 11;
|
||||
let mut attr = Attributes {
|
||||
@ -318,17 +377,22 @@ pub fn spawn_named_mob(
|
||||
}
|
||||
eb = eb.with(skills);
|
||||
|
||||
if mob_template.blocks_tile {
|
||||
eb = eb.with(BlocksTile {});
|
||||
}
|
||||
|
||||
eb = eb.with(Viewshed {
|
||||
visible_tiles: Vec::new(),
|
||||
range: mob_template.vision_range,
|
||||
dirty: true,
|
||||
});
|
||||
|
||||
return Some(eb.build());
|
||||
let new_mob = eb.build();
|
||||
|
||||
// Are they weilding anything?
|
||||
if let Some(wielding) = &mob_template.equipped {
|
||||
for tag in wielding.iter() {
|
||||
spawn_named_entity(raws, ecs, tag, SpawnType::Equipped { by: new_mob });
|
||||
}
|
||||
}
|
||||
|
||||
return Some(new_mob);
|
||||
}
|
||||
|
||||
None
|
||||
@ -336,17 +400,17 @@ pub fn spawn_named_mob(
|
||||
|
||||
pub fn spawn_named_prop(
|
||||
raws: &RawMaster,
|
||||
new_entity: EntityBuilder,
|
||||
ecs: &mut World,
|
||||
key: &str,
|
||||
pos: SpawnType,
|
||||
) -> Option<Entity> {
|
||||
if raws.prop_index.contains_key(key) {
|
||||
let prop_template = &raws.raws.props[raws.prop_index[key]];
|
||||
|
||||
let mut eb = new_entity;
|
||||
let mut eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
|
||||
|
||||
// Spawn in the specified location
|
||||
eb = spawn_position(pos, eb);
|
||||
eb = spawn_position(pos, eb, key, raws);
|
||||
|
||||
// Renderable
|
||||
if let Some(renderable) = &prop_template.renderable {
|
||||
@ -396,16 +460,16 @@ pub fn spawn_named_prop(
|
||||
|
||||
pub fn spawn_named_entity(
|
||||
raws: &RawMaster,
|
||||
new_entity: EntityBuilder,
|
||||
ecs: &mut World,
|
||||
key: &str,
|
||||
pos: SpawnType,
|
||||
) -> Option<Entity> {
|
||||
if raws.item_index.contains_key(key) {
|
||||
return spawn_named_item(raws, new_entity, key, pos);
|
||||
return spawn_named_item(raws, ecs, key, pos);
|
||||
} else if raws.mob_index.contains_key(key) {
|
||||
return spawn_named_mob(raws, new_entity, key, pos);
|
||||
return spawn_named_mob(raws, ecs, key, pos);
|
||||
} else if raws.prop_index.contains_key(key) {
|
||||
return spawn_named_prop(raws, new_entity, key, pos);
|
||||
return spawn_named_prop(raws, ecs, key, pos);
|
||||
}
|
||||
|
||||
None
|
||||
|
@ -76,7 +76,7 @@ pub fn save_game(ecs: &mut World) {
|
||||
Equippable,
|
||||
Equipped,
|
||||
MeleeWeapon,
|
||||
DefenseBonus,
|
||||
Wearable,
|
||||
WantsToRemoveItem,
|
||||
ParticleLifetime,
|
||||
HungerClock,
|
||||
@ -172,7 +172,7 @@ pub fn load_game(ecs: &mut World) {
|
||||
Equippable,
|
||||
Equipped,
|
||||
MeleeWeapon,
|
||||
DefenseBonus,
|
||||
Wearable,
|
||||
WantsToRemoveItem,
|
||||
ParticleLifetime,
|
||||
HungerClock,
|
||||
|
@ -12,7 +12,8 @@ use crate::{Map, Rect, TileType};
|
||||
|
||||
/// Spawns the player and returns their entity object
|
||||
pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||
ecs.create_entity()
|
||||
let player = ecs
|
||||
.create_entity()
|
||||
.with(Position {
|
||||
x: player_x,
|
||||
y: player_y,
|
||||
@ -50,7 +51,47 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||
level: 1,
|
||||
})
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.build()
|
||||
.build();
|
||||
|
||||
// Starting equipment
|
||||
spawn_named_entity(
|
||||
&RAWS.lock().unwrap(),
|
||||
ecs,
|
||||
"Rusty Longsword",
|
||||
SpawnType::Equipped { by: player },
|
||||
);
|
||||
spawn_named_entity(
|
||||
&RAWS.lock().unwrap(),
|
||||
ecs,
|
||||
"Dried Sausage",
|
||||
SpawnType::Carried { by: player },
|
||||
);
|
||||
spawn_named_entity(
|
||||
&RAWS.lock().unwrap(),
|
||||
ecs,
|
||||
"Beer",
|
||||
SpawnType::Carried { by: player },
|
||||
);
|
||||
spawn_named_entity(
|
||||
&RAWS.lock().unwrap(),
|
||||
ecs,
|
||||
"Stained Tunic",
|
||||
SpawnType::Equipped { by: player },
|
||||
);
|
||||
spawn_named_entity(
|
||||
&RAWS.lock().unwrap(),
|
||||
ecs,
|
||||
"Torn Trousers",
|
||||
SpawnType::Equipped { by: player },
|
||||
);
|
||||
spawn_named_entity(
|
||||
&RAWS.lock().unwrap(),
|
||||
ecs,
|
||||
"Old Boots",
|
||||
SpawnType::Equipped { by: player },
|
||||
);
|
||||
|
||||
player
|
||||
}
|
||||
|
||||
const MAX_MONSTERS: i32 = 4;
|
||||
@ -136,7 +177,7 @@ pub fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) {
|
||||
|
||||
let item_result = spawn_named_entity(
|
||||
&RAWS.lock().unwrap(),
|
||||
ecs.create_entity(),
|
||||
ecs,
|
||||
spawn.1,
|
||||
SpawnType::AtPosition { x, y },
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user