basic equippables

This commit is contained in:
Llywelwyn 2023-07-11 07:43:35 +01:00
parent 595ec61332
commit 8d04c40389
8 changed files with 330 additions and 36 deletions

View file

@ -84,6 +84,33 @@ impl SufferDamage {
#[derive(Component, Debug, Serialize, Deserialize, Clone)] #[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Item {} pub struct Item {}
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
pub enum EquipmentSlot {
Melee,
Shield,
}
#[derive(Component, ConvertSaveload, Clone)]
pub struct MeleePowerBonus {
pub amount: i32,
}
#[derive(Component, ConvertSaveload, Clone)]
pub struct DefenceBonus {
pub amount: i32,
}
#[derive(Component, Serialize, Deserialize, Clone)]
pub struct Equippable {
pub slot: EquipmentSlot,
}
#[derive(Component, ConvertSaveload, Clone)]
pub struct Equipped {
pub owner: Entity,
pub slot: EquipmentSlot,
}
#[derive(Component, Debug, Serialize, Deserialize, Clone)] #[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Cursed {} pub struct Cursed {}
@ -131,6 +158,11 @@ pub struct WantsToDropItem {
pub item: Entity, pub item: Entity,
} }
#[derive(Component, Debug, ConvertSaveload)]
pub struct WantsToRemoveItem {
pub item: Entity,
}
#[derive(Component, Debug, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload)]
pub struct WantsToUseItem { pub struct WantsToUseItem {
pub item: Entity, pub item: Entity,

View file

@ -1,6 +1,6 @@
use super::{ use super::{
gamelog, rex_assets::RexAssets, CombatStats, InBackpack, Map, Name, Player, Point, Position, RunState, State, gamelog, rex_assets::RexAssets, CombatStats, Equipped, InBackpack, Map, Name, Player, Point, Position, RunState,
Viewshed, State, Viewshed,
}; };
use rltk::{Rltk, VirtualKeyCode, RGB}; use rltk::{Rltk, VirtualKeyCode, RGB};
use specs::prelude::*; use specs::prelude::*;
@ -202,6 +202,48 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option
} }
} }
pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entity>) {
let player_entity = gs.ecs.fetch::<Entity>();
let names = gs.ecs.read_storage::<Name>();
let backpack = gs.ecs.read_storage::<Equipped>();
let entities = gs.ecs.entities();
let inventory = (&backpack, &names).join().filter(|item| item.0.owner == *player_entity);
let count = inventory.count();
let mut y = (25 - (count / 2)) as i32;
ctx.draw_box(15, y - 2, 31, (count + 3) as i32, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK));
ctx.print_color(18, y - 2, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "Remove what?");
ctx.print_color(18, y + count as i32 + 1, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "ESC to cancel");
let mut equippable: Vec<Entity> = Vec::new();
let mut j = 0;
for (entity, _pack, name) in (&entities, &backpack, &names).join().filter(|item| item.1.owner == *player_entity) {
ctx.set(17, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), rltk::to_cp437('('));
ctx.set(18, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 97 + j as rltk::FontCharType);
ctx.set(19, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), rltk::to_cp437(')'));
ctx.print(21, y, &name.name.to_string());
equippable.push(entity);
y += 1;
j += 1;
}
match ctx.key {
None => (ItemMenuResult::NoResponse, None),
Some(key) => match key {
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
_ => {
let selection = rltk::letter_to_option(key);
if selection > -1 && selection < count as i32 {
return (ItemMenuResult::Selected, Some(equippable[selection as usize]));
}
(ItemMenuResult::NoResponse, None)
}
},
}
}
pub fn ranged_target(gs: &mut State, ctx: &mut Rltk, range: i32, aoe: i32) -> (ItemMenuResult, Option<Point>) { pub fn ranged_target(gs: &mut State, ctx: &mut Rltk, range: i32, aoe: i32) -> (ItemMenuResult, Option<Point>) {
let player_entity = gs.ecs.fetch::<Entity>(); let player_entity = gs.ecs.fetch::<Entity>();
let player_pos = gs.ecs.fetch::<Point>(); let player_pos = gs.ecs.fetch::<Point>();

View file

@ -1,7 +1,8 @@
use super::{ use super::{
gamelog, CombatStats, Confusion, Consumable, Cursed, Destructible, InBackpack, InflictsDamage, MagicMapper, Map, gamelog, CombatStats, Confusion, Consumable, Cursed, Destructible, Equippable, Equipped, InBackpack,
Name, ParticleBuilder, Point, Position, ProvidesHealing, RunState, SufferDamage, WantsToDropItem, InflictsDamage, MagicMapper, Map, Name, ParticleBuilder, Point, Position, ProvidesHealing, RunState, SufferDamage,
WantsToPickupItem, WantsToUseItem, AOE, DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME, WantsToDropItem, WantsToPickupItem, WantsToRemoveItem, WantsToUseItem, AOE, DEFAULT_PARTICLE_LIFETIME,
LONG_PARTICLE_LIFETIME,
}; };
use specs::prelude::*; use specs::prelude::*;
@ -59,6 +60,9 @@ impl<'a> System<'a> for ItemUseSystem {
WriteStorage<'a, Confusion>, WriteStorage<'a, Confusion>,
ReadStorage<'a, MagicMapper>, ReadStorage<'a, MagicMapper>,
WriteExpect<'a, RunState>, WriteExpect<'a, RunState>,
ReadStorage<'a, Equippable>,
WriteStorage<'a, Equipped>,
WriteStorage<'a, InBackpack>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
@ -81,6 +85,9 @@ impl<'a> System<'a> for ItemUseSystem {
mut confused, mut confused,
magic_mapper, magic_mapper,
mut runstate, mut runstate,
equippable,
mut equipped,
mut backpack,
) = data; ) = data;
for (entity, wants_to_use) in (&entities, &wants_to_use).join() { for (entity, wants_to_use) in (&entities, &wants_to_use).join() {
@ -153,6 +160,48 @@ impl<'a> System<'a> for ItemUseSystem {
} }
} }
// EQUIPMENT
let item_equippable = equippable.get(wants_to_use.item);
match item_equippable {
None => {}
Some(can_equip) => {
let target_slot = can_equip.slot;
let target = targets[0];
// Room any items target has in item's slot
let mut to_unequip: Vec<Entity> = Vec::new();
for (item_entity, already_equipped, _name) in (&entities, &equipped, &names).join() {
if already_equipped.owner == target && already_equipped.slot == target_slot {
to_unequip.push(item_entity);
if target == *player_entity {
gamelog::Logger::new()
.append("You unequip the")
.item_name_n(&item_being_used.name)
.period()
.log();
}
}
}
for item in to_unequip.iter() {
equipped.remove(*item);
backpack.insert(*item, InBackpack { owner: target }).expect("Unable to insert backpack");
}
// Wield the item
equipped
.insert(wants_to_use.item, Equipped { owner: target, slot: target_slot })
.expect("Unable to insert equipped component");
backpack.remove(wants_to_use.item);
if target == *player_entity {
gamelog::Logger::new()
.append("You equip the")
.item_name_n(&item_being_used.name)
.period()
.log();
}
}
}
// HEALING ITEM // HEALING ITEM
let item_heals = provides_healing.get(wants_to_use.item); let item_heals = provides_healing.get(wants_to_use.item);
match item_heals { match item_heals {
@ -339,3 +388,22 @@ impl<'a> System<'a> for ItemDropSystem {
wants_drop.clear(); wants_drop.clear();
} }
} }
pub struct ItemRemoveSystem {}
impl<'a> System<'a> for ItemRemoveSystem {
#[allow(clippy::type_complexity)]
type SystemData =
(Entities<'a>, WriteStorage<'a, WantsToRemoveItem>, WriteStorage<'a, Equipped>, WriteStorage<'a, InBackpack>);
fn run(&mut self, data: Self::SystemData) {
let (entities, mut wants_remove, mut equipped, mut backpack) = data;
for (entity, to_remove) in (&entities, &wants_remove).join() {
equipped.remove(to_remove.item);
backpack.insert(to_remove.item, InBackpack { owner: entity }).expect("Unable to insert backpack");
}
wants_remove.clear();
}
}

View file

@ -48,6 +48,7 @@ pub enum RunState {
MonsterTurn, MonsterTurn,
ShowInventory, ShowInventory,
ShowDropItem, ShowDropItem,
ShowRemoveItem,
ShowTargeting { range: i32, item: Entity, aoe: i32 }, ShowTargeting { range: i32, item: Entity, aoe: i32 },
MainMenu { menu_selection: gui::MainMenuSelection }, MainMenu { menu_selection: gui::MainMenuSelection },
SaveGame, SaveGame,
@ -71,8 +72,10 @@ impl State {
inventory_system.run_now(&self.ecs); inventory_system.run_now(&self.ecs);
let mut item_use_system = ItemUseSystem {}; let mut item_use_system = ItemUseSystem {};
item_use_system.run_now(&self.ecs); item_use_system.run_now(&self.ecs);
let mut drop_system = ItemDropSystem {}; let mut item_drop_system = ItemDropSystem {};
drop_system.run_now(&self.ecs); item_drop_system.run_now(&self.ecs);
let mut item_remove_system = ItemRemoveSystem {};
item_remove_system.run_now(&self.ecs);
let mut melee_system = MeleeCombatSystem {}; let mut melee_system = MeleeCombatSystem {};
melee_system.run_now(&self.ecs); melee_system.run_now(&self.ecs);
let mut damage_system = DamageSystem {}; let mut damage_system = DamageSystem {};
@ -87,6 +90,7 @@ impl State {
let player = self.ecs.read_storage::<Player>(); let player = self.ecs.read_storage::<Player>();
let backpack = self.ecs.read_storage::<InBackpack>(); let backpack = self.ecs.read_storage::<InBackpack>();
let player_entity = self.ecs.fetch::<Entity>(); let player_entity = self.ecs.fetch::<Entity>();
let equipped = self.ecs.read_storage::<Equipped>();
let mut to_delete: Vec<Entity> = Vec::new(); let mut to_delete: Vec<Entity> = Vec::new();
for entity in entities.join() { for entity in entities.join() {
@ -105,6 +109,12 @@ impl State {
should_delete = false; should_delete = false;
} }
} }
let eq = equipped.get(entity);
if let Some(eq) = eq {
if eq.owner == *player_entity {
should_delete = false;
}
}
if should_delete { if should_delete {
to_delete.push(entity); to_delete.push(entity);
@ -280,6 +290,21 @@ impl GameState for State {
} }
} }
} }
RunState::ShowRemoveItem => {
let result = gui::remove_item_menu(self, ctx);
match result.0 {
gui::ItemMenuResult::Cancel => new_runstate = RunState::AwaitingInput,
gui::ItemMenuResult::NoResponse => {}
gui::ItemMenuResult::Selected => {
let item_entity = result.1.unwrap();
let mut intent = self.ecs.write_storage::<WantsToRemoveItem>();
intent
.insert(*self.ecs.fetch::<Entity>(), WantsToRemoveItem { item: item_entity })
.expect("Unable to insert intent");
new_runstate = RunState::PlayerTurn;
}
}
}
RunState::ShowTargeting { range, item, aoe } => { RunState::ShowTargeting { range, item, aoe } => {
let result = gui::ranged_target(self, ctx, range, aoe); let result = gui::ranged_target(self, ctx, range, aoe);
match result.0 { match result.0 {
@ -397,6 +422,10 @@ fn main() -> rltk::BError {
gs.ecs.register::<WantsToMelee>(); gs.ecs.register::<WantsToMelee>();
gs.ecs.register::<SufferDamage>(); gs.ecs.register::<SufferDamage>();
gs.ecs.register::<Item>(); gs.ecs.register::<Item>();
gs.ecs.register::<Equippable>();
gs.ecs.register::<Equipped>();
gs.ecs.register::<MeleePowerBonus>();
gs.ecs.register::<DefenceBonus>();
gs.ecs.register::<Cursed>(); gs.ecs.register::<Cursed>();
gs.ecs.register::<ProvidesHealing>(); gs.ecs.register::<ProvidesHealing>();
gs.ecs.register::<InflictsDamage>(); gs.ecs.register::<InflictsDamage>();
@ -407,6 +436,7 @@ fn main() -> rltk::BError {
gs.ecs.register::<InBackpack>(); gs.ecs.register::<InBackpack>();
gs.ecs.register::<WantsToPickupItem>(); gs.ecs.register::<WantsToPickupItem>();
gs.ecs.register::<WantsToDropItem>(); gs.ecs.register::<WantsToDropItem>();
gs.ecs.register::<WantsToRemoveItem>();
gs.ecs.register::<WantsToUseItem>(); gs.ecs.register::<WantsToUseItem>();
gs.ecs.register::<Consumable>(); gs.ecs.register::<Consumable>();
gs.ecs.register::<Destructible>(); gs.ecs.register::<Destructible>();

View file

@ -1,4 +1,7 @@
use super::{gamelog, CombatStats, Name, ParticleBuilder, Position, SufferDamage, WantsToMelee}; use super::{
gamelog, CombatStats, DefenceBonus, Equipped, MeleePowerBonus, Name, ParticleBuilder, Position, SufferDamage,
WantsToMelee,
};
use specs::prelude::*; use specs::prelude::*;
pub struct MeleeCombatSystem {} pub struct MeleeCombatSystem {}
@ -13,6 +16,9 @@ impl<'a> System<'a> for MeleeCombatSystem {
WriteStorage<'a, SufferDamage>, WriteStorage<'a, SufferDamage>,
WriteExpect<'a, ParticleBuilder>, WriteExpect<'a, ParticleBuilder>,
ReadStorage<'a, Position>, ReadStorage<'a, Position>,
ReadStorage<'a, Equipped>,
ReadStorage<'a, DefenceBonus>,
ReadStorage<'a, MeleePowerBonus>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
@ -25,6 +31,9 @@ impl<'a> System<'a> for MeleeCombatSystem {
mut inflict_damage, mut inflict_damage,
mut particle_builder, mut particle_builder,
positions, positions,
equipped,
defence_bonuses,
melee_power_bonuses,
) = data; ) = data;
for (entity, wants_melee, name, stats) in (&entities, &wants_melee, &names, &combat_stats).join() { for (entity, wants_melee, name, stats) in (&entities, &wants_melee, &names, &combat_stats).join() {
@ -37,18 +46,20 @@ impl<'a> System<'a> for MeleeCombatSystem {
} }
let target_name = names.get(wants_melee.target).unwrap(); let target_name = names.get(wants_melee.target).unwrap();
let pos = positions.get(wants_melee.target);
if let Some(pos) = pos { let mut offensive_bonus = 0;
particle_builder.request( for (_item_entity, power_bonus, equipped_by) in (&entities, &melee_power_bonuses, &equipped).join() {
pos.x, if equipped_by.owner == entity {
pos.y, offensive_bonus += power_bonus.amount;
rltk::RGB::named(rltk::ORANGE),
rltk::RGB::named(rltk::BLACK),
rltk::to_cp437('‼'),
150.0,
);
} }
let damage = i32::max(0, stats.power - target_stats.defence); }
let mut defensive_bonus = 0;
for (_item_entity, defence_bonus, equipped_by) in (&entities, &defence_bonuses, &equipped).join() {
if equipped_by.owner == wants_melee.target {
defensive_bonus += defence_bonus.amount;
}
}
let damage = i32::max(0, (stats.power + offensive_bonus) - (target_stats.defence + defensive_bonus));
if damage == 0 { if damage == 0 {
if entity == *player_entity { if entity == *player_entity {
@ -96,6 +107,17 @@ impl<'a> System<'a> for MeleeCombatSystem {
.period() .period()
.log(); .log();
} }
let pos = positions.get(wants_melee.target);
if let Some(pos) = pos {
particle_builder.request(
pos.x,
pos.y,
rltk::RGB::named(rltk::ORANGE),
rltk::RGB::named(rltk::BLACK),
rltk::to_cp437('‼'),
150.0,
);
}
SufferDamage::new_damage(&mut inflict_damage, wants_melee.target, damage); SufferDamage::new_damage(&mut inflict_damage, wants_melee.target, damage);
} }
} }

View file

@ -35,20 +35,30 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
} }
if !map.blocked[destination_idx] { if !map.blocked[destination_idx] {
// TODO: Refactor
let mut tile_content = "You see ".to_string();
let names = ecs.read_storage::<Name>(); let names = ecs.read_storage::<Name>();
// Push every entity name in the pile to a vector of strings
let mut item_names: Vec<String> = Vec::new();
let mut some = false;
for entity in map.tile_content[destination_idx].iter() { for entity in map.tile_content[destination_idx].iter() {
if let Some(name) = names.get(*entity) { if let Some(name) = names.get(*entity) {
if tile_content != "You see " { let item_name = &name.name;
tile_content.push_str(", "); item_names.push(item_name.to_string());
} some = true;
tile_content.push_str(&name.name);
} }
} }
if tile_content != "You see " { // If some names were found, append. Logger = logger is necessary
tile_content.push_str("."); // makes logger called a mutable self. It's not the most efficient
gamelog::Logger::new().append(tile_content).log() // but it happens infrequently enough (once per player turn at most)
// that it shouldn't matter.
if some {
let mut logger = gamelog::Logger::new().append("You see a");
for i in 0..item_names.len() {
if i > 0 && i < item_names.len() {
logger = logger.append(", a");
}
logger = logger.item_name_n(&item_names[i]);
}
logger.period().log();
} }
pos.x = min((MAPWIDTH as i32) - 1, max(0, pos.x + delta_x)); pos.x = min((MAPWIDTH as i32) - 1, max(0, pos.x + delta_x));
pos.y = min((MAPHEIGHT as i32) - 1, max(0, pos.y + delta_y)); pos.y = min((MAPHEIGHT as i32) - 1, max(0, pos.y + delta_y));
@ -127,6 +137,7 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
VirtualKeyCode::G => get_item(&mut gs.ecs), VirtualKeyCode::G => get_item(&mut gs.ecs),
VirtualKeyCode::I => return RunState::ShowInventory, VirtualKeyCode::I => return RunState::ShowInventory,
VirtualKeyCode::D => return RunState::ShowDropItem, VirtualKeyCode::D => return RunState::ShowDropItem,
VirtualKeyCode::R => return RunState::ShowRemoveItem,
VirtualKeyCode::Escape => return RunState::SaveGame, VirtualKeyCode::Escape => return RunState::SaveGame,
_ => { _ => {
return RunState::AwaitingInput; return RunState::AwaitingInput;

View file

@ -58,6 +58,10 @@ pub fn save_game(ecs: &mut World) {
SufferDamage, SufferDamage,
WantsToMelee, WantsToMelee,
Item, Item,
Equippable,
Equipped,
MeleePowerBonus,
DefenceBonus,
Cursed, Cursed,
Consumable, Consumable,
Destructible, Destructible,
@ -71,6 +75,7 @@ pub fn save_game(ecs: &mut World) {
WantsToPickupItem, WantsToPickupItem,
WantsToUseItem, WantsToUseItem,
WantsToDropItem, WantsToDropItem,
WantsToRemoveItem,
SerializationHelper SerializationHelper
); );
} }
@ -135,6 +140,10 @@ pub fn load_game(ecs: &mut World) {
SufferDamage, SufferDamage,
WantsToMelee, WantsToMelee,
Item, Item,
Equippable,
Equipped,
MeleePowerBonus,
DefenceBonus,
Cursed, Cursed,
Consumable, Consumable,
Destructible, Destructible,
@ -148,6 +157,7 @@ pub fn load_game(ecs: &mut World) {
WantsToPickupItem, WantsToPickupItem,
WantsToUseItem, WantsToUseItem,
WantsToDropItem, WantsToDropItem,
WantsToRemoveItem,
SerializationHelper SerializationHelper
); );
} }

View file

@ -1,7 +1,7 @@
use super::{ use super::{
random_table::RandomTable, BlocksTile, CombatStats, Confusion, Consumable, Cursed, Destructible, InflictsDamage, random_table::RandomTable, BlocksTile, CombatStats, Confusion, Consumable, Cursed, DefenceBonus, Destructible,
Item, MagicMapper, Monster, Name, Player, Position, ProvidesHealing, Ranged, Rect, Renderable, SerializeMe, EquipmentSlot, Equippable, InflictsDamage, Item, MagicMapper, MeleePowerBonus, Monster, Name, Player, Position,
Viewshed, AOE, MAPWIDTH, ProvidesHealing, Ranged, Rect, Renderable, SerializeMe, Viewshed, AOE, MAPWIDTH,
}; };
use rltk::{console, RandomNumberGenerator, RGB}; use rltk::{console, RandomNumberGenerator, RGB};
use specs::prelude::*; use specs::prelude::*;
@ -116,6 +116,11 @@ pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32) {
"goblin" => goblin(ecs, x, y), "goblin" => goblin(ecs, x, y),
"goblin chieftain" => goblin_chieftain(ecs, x, y), "goblin chieftain" => goblin_chieftain(ecs, x, y),
"orc" => orc(ecs, x, y), "orc" => orc(ecs, x, y),
// Equipment
"dagger" => dagger(ecs, x, y),
"shortsword" => shortsword(ecs, x, y),
"buckler" => buckler(ecs, x, y),
"shield" => shield(ecs, x, y),
// Potions // Potions
"weak health potion" => weak_health_potion(ecs, x, y), "weak health potion" => weak_health_potion(ecs, x, y),
"health potion" => health_potion(ecs, x, y), "health potion" => health_potion(ecs, x, y),
@ -149,14 +154,19 @@ fn mob_table(map_depth: i32) -> RandomTable {
.add("orc", 2 + map_depth); .add("orc", 2 + map_depth);
} }
// 25 potions : 10 scrolls : 2 cursed scrolls // 6 equipment : 10 potions : 10 scrolls : 2 cursed scrolls
fn item_table(_map_depth: i32) -> RandomTable { fn item_table(map_depth: i32) -> RandomTable {
return RandomTable::new() return RandomTable::new()
// Equipment
.add("dagger", 2)
.add("shortsword", map_depth - 1)
.add("buckler", 2)
.add("shield", 1)
// Potions // Potions
.add("weak health potion", 20) .add("weak health potion", 7)
.add("health potion", 5) .add("health potion", 3)
// Scrolls // Scrolls
.add("fireball scroll", 1) .add("fireball scroll", map_depth - 1)
.add("cursed fireball scroll", 1) .add("cursed fireball scroll", 1)
.add("confusion scroll", 2) .add("confusion scroll", 2)
.add("magic missile scroll", 5) .add("magic missile scroll", 5)
@ -337,3 +347,72 @@ fn cursed_magic_map_scroll(ecs: &mut World, x: i32, y: i32) {
.marked::<SimpleMarker<SerializeMe>>() .marked::<SimpleMarker<SerializeMe>>()
.build(); .build();
} }
// EQUIPMENT
fn dagger(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: rltk::to_cp437('/'),
fg: RGB::named(rltk::GREY),
bg: RGB::named(rltk::BLACK),
render_order: 2,
})
.with(Name { name: "dagger".to_string() })
.with(Item {})
.with(Equippable { slot: EquipmentSlot::Melee })
.with(MeleePowerBonus { amount: 1 })
.marked::<SimpleMarker<SerializeMe>>()
.build();
}
fn shortsword(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: rltk::to_cp437('/'),
fg: RGB::named(rltk::GREY),
bg: RGB::named(rltk::BLACK),
render_order: 2,
})
.with(Name { name: "shortsword".to_string() })
.with(Item {})
.with(Equippable { slot: EquipmentSlot::Melee })
.with(MeleePowerBonus { amount: 2 })
.marked::<SimpleMarker<SerializeMe>>()
.build();
}
fn buckler(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: rltk::to_cp437('('),
fg: RGB::named(rltk::GREY),
bg: RGB::named(rltk::BLACK),
render_order: 2,
})
.with(Name { name: "buckler".to_string() })
.with(Item {})
.with(DefenceBonus { amount: 1 })
.with(Equippable { slot: EquipmentSlot::Shield })
.marked::<SimpleMarker<SerializeMe>>()
.build();
}
fn shield(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: rltk::to_cp437('('),
fg: RGB::named(rltk::GREY),
bg: RGB::named(rltk::BLACK),
render_order: 2,
})
.with(Name { name: "shield".to_string() })
.with(Item {})
.with(DefenceBonus { amount: 2 })
.with(MeleePowerBonus { amount: -1 })
.with(Equippable { slot: EquipmentSlot::Shield })
.marked::<SimpleMarker<SerializeMe>>()
.build();
}