basic equippables
This commit is contained in:
parent
595ec61332
commit
8d04c40389
8 changed files with 330 additions and 36 deletions
|
|
@ -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,
|
||||||
|
|
|
||||||
46
src/gui.rs
46
src/gui.rs
|
|
@ -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>();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
34
src/main.rs
34
src/main.rs
|
|
@ -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>();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue