static keys - items in inventory will save their assigned key
precursor to cleaning up/modularising inventory display, instead of needing to iterate through every item held to find unique copies, we can just check if the button pressed corresponds to any entity's Key {} index
This commit is contained in:
parent
a7b4f621fb
commit
d11971126c
19 changed files with 445 additions and 122 deletions
|
|
@ -5,7 +5,7 @@
|
||||||
"renderable": { "glyph": "!", "fg": "#FF00FF", "bg": "#000000", "order": 4 },
|
"renderable": { "glyph": "!", "fg": "#FF00FF", "bg": "#000000", "order": 4 },
|
||||||
"weight": 1,
|
"weight": 1,
|
||||||
"value": 50,
|
"value": 50,
|
||||||
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"],
|
||||||
"effects": { "heal": "4d4+2" },
|
"effects": { "heal": "4d4+2" },
|
||||||
"magic": { "class": "uncommon", "naming": "potion" }
|
"magic": { "class": "uncommon", "naming": "potion" }
|
||||||
},
|
},
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
"renderable": { "glyph": "!", "fg": "#FF00FF", "bg": "#000000", "order": 4 },
|
"renderable": { "glyph": "!", "fg": "#FF00FF", "bg": "#000000", "order": 4 },
|
||||||
"weight": 1,
|
"weight": 1,
|
||||||
"value": 25,
|
"value": 25,
|
||||||
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"],
|
||||||
"effects": { "heal": "2d4+2" },
|
"effects": { "heal": "2d4+2" },
|
||||||
"magic": { "class": "uncommon", "naming": "potion" }
|
"magic": { "class": "uncommon", "naming": "potion" }
|
||||||
},
|
},
|
||||||
|
|
@ -401,7 +401,7 @@
|
||||||
"renderable": { "glyph": "%", "fg": "#FFA07A", "bg": "#000000", "order": 4 },
|
"renderable": { "glyph": "%", "fg": "#FFA07A", "bg": "#000000", "order": 4 },
|
||||||
"weight": 1,
|
"weight": 1,
|
||||||
"value": 1,
|
"value": 1,
|
||||||
"flags": ["FOOD", "CONSUMABLE"]
|
"flags": ["FOOD", "CONSUMABLE", "STACKABLE"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "food_apple",
|
"id": "food_apple",
|
||||||
|
|
@ -409,6 +409,6 @@
|
||||||
"renderable": { "glyph": "%", "fg": "#00FF00", "bg": "#000000", "order": 4 },
|
"renderable": { "glyph": "%", "fg": "#00FF00", "bg": "#000000", "order": 4 },
|
||||||
"weight": 0.5,
|
"weight": 0.5,
|
||||||
"value": 1,
|
"value": 1,
|
||||||
"flags": ["FOOD", "CONSUMABLE"]
|
"flags": ["FOOD", "CONSUMABLE", "STACKABLE"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -468,9 +468,20 @@ pub struct IdentifiedItem {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct Stackable {}
|
||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct EquipmentChanged {}
|
pub struct EquipmentChanged {}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct WantsToRemoveKey {}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct Key {
|
||||||
|
pub idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
|
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
|
||||||
pub enum BurdenLevel {
|
pub enum BurdenLevel {
|
||||||
Burdened,
|
Burdened,
|
||||||
|
|
@ -654,6 +665,9 @@ pub struct InBackpack {
|
||||||
pub owner: Entity,
|
pub owner: Entity,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct WantsToAssignKey {}
|
||||||
|
|
||||||
#[derive(Component, Debug, ConvertSaveload)]
|
#[derive(Component, Debug, ConvertSaveload)]
|
||||||
pub struct WantsToPickupItem {
|
pub struct WantsToPickupItem {
|
||||||
pub collected_by: Entity,
|
pub collected_by: Entity,
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ pub const NUTRITION_BLESSED: &str = "Delicious";
|
||||||
|
|
||||||
pub const LEVELUP_PLAYER: &str = "Welcome to experience level";
|
pub const LEVELUP_PLAYER: &str = "Welcome to experience level";
|
||||||
pub const YOU_PICKUP_ITEM: &str = "You pick up the";
|
pub const YOU_PICKUP_ITEM: &str = "You pick up the";
|
||||||
|
pub const NO_MORE_KEYS: &str = "Your backpack cannot accomodate any more items";
|
||||||
pub const YOU_DROP_ITEM: &str = "You drop the";
|
pub const YOU_DROP_ITEM: &str = "You drop the";
|
||||||
pub const YOU_EQUIP_ITEM: &str = "You equip the";
|
pub const YOU_EQUIP_ITEM: &str = "You equip the";
|
||||||
pub const YOU_REMOVE_ITEM: &str = "You unequip your";
|
pub const YOU_REMOVE_ITEM: &str = "You unequip your";
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ pub fn delete_the_dead(ecs: &mut World) {
|
||||||
// For everything that died, increment the event log, and delete.
|
// For everything that died, increment the event log, and delete.
|
||||||
for victim in dead {
|
for victim in dead {
|
||||||
gamelog::record_event(events::EVENT::Turn(1));
|
gamelog::record_event(events::EVENT::Turn(1));
|
||||||
|
// TODO: Delete stuff from inventory? This should be handled elsewhere.
|
||||||
ecs.delete_entity(victim).expect("Unable to delete.");
|
ecs.delete_entity(victim).expect("Unable to delete.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ use specs::prelude::*;
|
||||||
use super::TILESIZE;
|
use super::TILESIZE;
|
||||||
use crate::Fonts;
|
use crate::Fonts;
|
||||||
|
|
||||||
pub fn draw_inventory(ecs: &World, draw: &mut Draw, font: &Fonts) {
|
pub fn draw_inventory(ecs: &World, draw: &mut Draw, font: &Fonts, x: i32, y: i32) {
|
||||||
let inv = super::get_player_inventory(ecs);
|
let inv = super::get_player_inventory(ecs);
|
||||||
let offsets = crate::camera::get_offset();
|
let offsets = crate::camera::get_offset();
|
||||||
super::print_options(
|
super::print_options(
|
||||||
draw,
|
draw,
|
||||||
font,
|
font,
|
||||||
&inv,
|
&inv,
|
||||||
(offsets.x as f32) * TILESIZE,
|
((x as f32) + (offsets.x as f32)) * TILESIZE,
|
||||||
(offsets.y as f32) * TILESIZE
|
((y as f32) + (offsets.y as f32)) * TILESIZE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
115
src/gui/mod.rs
115
src/gui/mod.rs
|
|
@ -1238,13 +1238,13 @@ pub fn show_help(ctx: &mut BTerm) -> YesNoResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
struct DisplayName {
|
struct DisplayName {
|
||||||
singular: String,
|
singular: String,
|
||||||
plural: String,
|
plural: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct UniqueInventoryItem {
|
pub struct UniqueInventoryItem {
|
||||||
display_name: DisplayName,
|
display_name: DisplayName,
|
||||||
rgb: (u8, u8, u8),
|
rgb: (u8, u8, u8),
|
||||||
|
|
@ -1256,6 +1256,75 @@ pub struct UniqueInventoryItem {
|
||||||
|
|
||||||
pub type PlayerInventory = BTreeMap<UniqueInventoryItem, (Entity, i32)>;
|
pub type PlayerInventory = BTreeMap<UniqueInventoryItem, (Entity, i32)>;
|
||||||
|
|
||||||
|
pub fn unique(
|
||||||
|
entity: Entity,
|
||||||
|
names: &ReadStorage<Name>,
|
||||||
|
obfuscated_names: &ReadStorage<ObfuscatedName>,
|
||||||
|
renderables: &ReadStorage<Renderable>,
|
||||||
|
beatitudes: &ReadStorage<Beatitude>,
|
||||||
|
magic_items: &ReadStorage<MagicItem>,
|
||||||
|
charges: Option<&ReadStorage<Charges>>,
|
||||||
|
dm: &MasterDungeonMap
|
||||||
|
) -> UniqueInventoryItem {
|
||||||
|
let item_colour = item_colour(entity, beatitudes);
|
||||||
|
let (singular, plural) = obfuscate_name(
|
||||||
|
entity,
|
||||||
|
names,
|
||||||
|
magic_items,
|
||||||
|
obfuscated_names,
|
||||||
|
beatitudes,
|
||||||
|
dm,
|
||||||
|
charges
|
||||||
|
);
|
||||||
|
let (renderables, glyph) = if let Some(renderable) = renderables.get(entity) {
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(renderable.fg.r * 255.0) as u8,
|
||||||
|
(renderable.fg.g * 255.0) as u8,
|
||||||
|
(renderable.fg.b * 255.0) as u8,
|
||||||
|
),
|
||||||
|
renderable.glyph,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
unreachable!("Item has no renderable component.")
|
||||||
|
};
|
||||||
|
let name = if let Some(name) = names.get(entity) {
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
unreachable!("Item has no name component.")
|
||||||
|
};
|
||||||
|
let beatitude_status = if let Some(beatitude) = beatitudes.get(entity) {
|
||||||
|
match beatitude.buc {
|
||||||
|
BUC::Blessed => 1,
|
||||||
|
BUC::Uncursed => 2,
|
||||||
|
BUC::Cursed => 3,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
UniqueInventoryItem {
|
||||||
|
display_name: DisplayName { singular: singular.clone(), plural },
|
||||||
|
rgb: item_colour,
|
||||||
|
renderables,
|
||||||
|
glyph,
|
||||||
|
beatitude_status,
|
||||||
|
name: name.name.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unique_ecs(ecs: &World, entity: Entity) -> UniqueInventoryItem {
|
||||||
|
return unique(
|
||||||
|
entity,
|
||||||
|
&ecs.read_storage::<Name>(),
|
||||||
|
&ecs.read_storage::<ObfuscatedName>(),
|
||||||
|
&ecs.read_storage::<Renderable>(),
|
||||||
|
&ecs.read_storage::<Beatitude>(),
|
||||||
|
&ecs.read_storage::<MagicItem>(),
|
||||||
|
Some(&ecs.read_storage::<Charges>()),
|
||||||
|
&ecs.fetch::<MasterDungeonMap>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_player_inventory(ecs: &World) -> PlayerInventory {
|
pub fn get_player_inventory(ecs: &World) -> PlayerInventory {
|
||||||
let player_entity = ecs.fetch::<Entity>();
|
let player_entity = ecs.fetch::<Entity>();
|
||||||
let names = ecs.read_storage::<Name>();
|
let names = ecs.read_storage::<Name>();
|
||||||
|
|
@ -1338,39 +1407,23 @@ pub fn show_inventory(gs: &mut State, ctx: &mut App) -> (ItemMenuResult, Option<
|
||||||
return (ItemMenuResult::NoResponse, None);
|
return (ItemMenuResult::NoResponse, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drop_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option<Entity>) {
|
pub fn drop_item_menu(gs: &mut State, ctx: &mut App) -> (ItemMenuResult, Option<Entity>) {
|
||||||
let player_inventory = get_player_inventory(&gs.ecs);
|
let player_inventory = get_player_inventory(&gs.ecs);
|
||||||
let count = player_inventory.len();
|
let count = player_inventory.len();
|
||||||
|
|
||||||
let (x_offset, y_offset) = (1, 10);
|
|
||||||
|
|
||||||
let on_overmap = gs.ecs.fetch::<Map>().overmap;
|
let on_overmap = gs.ecs.fetch::<Map>().overmap;
|
||||||
let message = if !on_overmap {
|
|
||||||
"Drop what? [aA-zZ][Esc.]"
|
|
||||||
} else {
|
|
||||||
"You can't drop items on the overmap [Esc.]"
|
|
||||||
};
|
|
||||||
|
|
||||||
ctx.print_color(1 + x_offset, 1 + y_offset, RGB::named(WHITE), RGB::named(BLACK), message);
|
let key = &ctx.keyboard;
|
||||||
|
for keycode in key.pressed.iter() {
|
||||||
let x = 1 + x_offset;
|
match *keycode {
|
||||||
let y = 3 + y_offset;
|
KeyCode::Escape => {
|
||||||
let width = get_max_inventory_width(&player_inventory);
|
return (ItemMenuResult::Cancel, None);
|
||||||
ctx.draw_box(x, y, width + 2, (count + 1) as i32, RGB::named(WHITE), RGB::named(BLACK));
|
}
|
||||||
|
|
||||||
match ctx.key {
|
|
||||||
None => (ItemMenuResult::NoResponse, None),
|
|
||||||
Some(key) =>
|
|
||||||
match key {
|
|
||||||
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
|
||||||
_ => {
|
_ => {
|
||||||
let selection = letter_to_option(key);
|
let shift = key.shift();
|
||||||
|
let selection = letter_to_option::letter_to_option(*keycode, shift);
|
||||||
if selection > -1 && selection < (count as i32) {
|
if selection > -1 && selection < (count as i32) {
|
||||||
if on_overmap {
|
if on_overmap {
|
||||||
gamelog::Logger
|
gamelog::Logger::new().append("You can't drop items on the overmap.").log();
|
||||||
::new()
|
|
||||||
.append("You can't drop items on the overmap.")
|
|
||||||
.log();
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
ItemMenuResult::Selected,
|
ItemMenuResult::Selected,
|
||||||
|
|
@ -1383,11 +1436,11 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Optio
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
(ItemMenuResult::NoResponse, None)
|
(ItemMenuResult::NoResponse, None)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option<Entity>) {
|
pub fn remove_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option<Entity>) {
|
||||||
let player_entity = gs.ecs.fetch::<Entity>();
|
let player_entity = gs.ecs.fetch::<Entity>();
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@ use crate::{
|
||||||
ObfuscatedName,
|
ObfuscatedName,
|
||||||
Position,
|
Position,
|
||||||
WantsToPickupItem,
|
WantsToPickupItem,
|
||||||
|
WantsToAssignKey,
|
||||||
|
Renderable,
|
||||||
|
Stackable,
|
||||||
};
|
};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use crate::consts::messages;
|
use crate::consts::messages;
|
||||||
|
|
@ -30,9 +33,12 @@ impl<'a> System<'a> for ItemCollectionSystem {
|
||||||
WriteStorage<'a, EquipmentChanged>,
|
WriteStorage<'a, EquipmentChanged>,
|
||||||
ReadStorage<'a, MagicItem>,
|
ReadStorage<'a, MagicItem>,
|
||||||
ReadStorage<'a, ObfuscatedName>,
|
ReadStorage<'a, ObfuscatedName>,
|
||||||
|
ReadStorage<'a, Renderable>,
|
||||||
ReadStorage<'a, Beatitude>,
|
ReadStorage<'a, Beatitude>,
|
||||||
ReadExpect<'a, MasterDungeonMap>,
|
ReadExpect<'a, MasterDungeonMap>,
|
||||||
ReadStorage<'a, Charges>,
|
ReadStorage<'a, Charges>,
|
||||||
|
ReadStorage<'a, WantsToAssignKey>,
|
||||||
|
ReadStorage<'a, Stackable>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
|
@ -45,20 +51,17 @@ impl<'a> System<'a> for ItemCollectionSystem {
|
||||||
mut equipment_changed,
|
mut equipment_changed,
|
||||||
magic_items,
|
magic_items,
|
||||||
obfuscated_names,
|
obfuscated_names,
|
||||||
|
renderables,
|
||||||
beatitudes,
|
beatitudes,
|
||||||
dm,
|
dm,
|
||||||
wands,
|
wands,
|
||||||
|
wants_key,
|
||||||
|
stackable,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
for pickup in wants_pickup.join() {
|
let mut to_remove: Vec<Entity> = Vec::new();
|
||||||
positions.remove(pickup.item);
|
// For every item that wants to be picked up, that *isn't* still waiting on a key assignment.
|
||||||
backpack
|
for (pickup, _key) in (&wants_pickup, !&wants_key).join() {
|
||||||
.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 {
|
if pickup.collected_by == *player_entity {
|
||||||
gamelog::Logger
|
gamelog::Logger
|
||||||
::new()
|
::new()
|
||||||
|
|
@ -82,8 +85,17 @@ impl<'a> System<'a> for ItemCollectionSystem {
|
||||||
.period()
|
.period()
|
||||||
.log();
|
.log();
|
||||||
}
|
}
|
||||||
|
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.");
|
||||||
|
to_remove.push(pickup.collected_by);
|
||||||
|
}
|
||||||
|
for item in to_remove.iter() {
|
||||||
|
wants_pickup.remove(*item);
|
||||||
}
|
}
|
||||||
|
|
||||||
wants_pickup.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ use crate::{
|
||||||
ObfuscatedName,
|
ObfuscatedName,
|
||||||
Position,
|
Position,
|
||||||
WantsToDropItem,
|
WantsToDropItem,
|
||||||
|
WantsToRemoveKey,
|
||||||
};
|
};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use crate::consts::messages;
|
use crate::consts::messages;
|
||||||
|
|
@ -34,6 +35,7 @@ impl<'a> System<'a> for ItemDropSystem {
|
||||||
ReadStorage<'a, ObfuscatedName>,
|
ReadStorage<'a, ObfuscatedName>,
|
||||||
ReadExpect<'a, MasterDungeonMap>,
|
ReadExpect<'a, MasterDungeonMap>,
|
||||||
ReadStorage<'a, Charges>,
|
ReadStorage<'a, Charges>,
|
||||||
|
WriteStorage<'a, WantsToRemoveKey>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
|
@ -50,6 +52,7 @@ impl<'a> System<'a> for ItemDropSystem {
|
||||||
obfuscated_names,
|
obfuscated_names,
|
||||||
dm,
|
dm,
|
||||||
wands,
|
wands,
|
||||||
|
mut keys,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
for (entity, to_drop) in (&entities, &wants_drop).join() {
|
for (entity, to_drop) in (&entities, &wants_drop).join() {
|
||||||
|
|
@ -68,6 +71,9 @@ impl<'a> System<'a> for ItemDropSystem {
|
||||||
backpack.remove(to_drop.item);
|
backpack.remove(to_drop.item);
|
||||||
|
|
||||||
if entity == *player_entity {
|
if entity == *player_entity {
|
||||||
|
keys.insert(to_drop.item, WantsToRemoveKey {}).expect(
|
||||||
|
"Unable to insert WantsToRemoveKey"
|
||||||
|
);
|
||||||
gamelog::Logger
|
gamelog::Logger
|
||||||
::new()
|
::new()
|
||||||
.append(messages::YOU_DROP_ITEM)
|
.append(messages::YOU_DROP_ITEM)
|
||||||
|
|
|
||||||
153
src/inventory/keyhandling.rs
Normal file
153
src/inventory/keyhandling.rs
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
use crate::{
|
||||||
|
gamelog,
|
||||||
|
gui::unique,
|
||||||
|
Beatitude,
|
||||||
|
Charges,
|
||||||
|
MagicItem,
|
||||||
|
MasterDungeonMap,
|
||||||
|
Name,
|
||||||
|
ObfuscatedName,
|
||||||
|
Stackable,
|
||||||
|
Renderable,
|
||||||
|
WantsToAssignKey,
|
||||||
|
WantsToRemoveKey,
|
||||||
|
Key,
|
||||||
|
};
|
||||||
|
use specs::prelude::*;
|
||||||
|
use crate::consts::messages;
|
||||||
|
use bracket_lib::prelude::*;
|
||||||
|
use crate::invkeys::*;
|
||||||
|
|
||||||
|
pub struct KeyHandling {}
|
||||||
|
|
||||||
|
const DEBUG_KEYHANDLING: bool = true;
|
||||||
|
|
||||||
|
impl<'a> System<'a> for KeyHandling {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
type SystemData = (
|
||||||
|
Entities<'a>,
|
||||||
|
WriteStorage<'a, WantsToAssignKey>,
|
||||||
|
WriteStorage<'a, WantsToRemoveKey>,
|
||||||
|
WriteStorage<'a, Key>,
|
||||||
|
ReadStorage<'a, Stackable>,
|
||||||
|
ReadStorage<'a, Name>,
|
||||||
|
ReadStorage<'a, ObfuscatedName>,
|
||||||
|
ReadStorage<'a, Renderable>,
|
||||||
|
ReadStorage<'a, Beatitude>,
|
||||||
|
ReadStorage<'a, MagicItem>,
|
||||||
|
ReadStorage<'a, Charges>,
|
||||||
|
ReadExpect<'a, MasterDungeonMap>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
let (
|
||||||
|
entities,
|
||||||
|
mut wants_keys,
|
||||||
|
mut wants_removekey,
|
||||||
|
mut keys,
|
||||||
|
stackable,
|
||||||
|
names,
|
||||||
|
obfuscated_names,
|
||||||
|
renderables,
|
||||||
|
beatitudes,
|
||||||
|
magic_items,
|
||||||
|
wands,
|
||||||
|
dm,
|
||||||
|
) = data;
|
||||||
|
|
||||||
|
// For every entity that wants to be picked up, that still needs a key assigned.
|
||||||
|
for (e, _wants_key) in (&entities, &wants_keys).join() {
|
||||||
|
if DEBUG_KEYHANDLING {
|
||||||
|
console::log(&format!("KEYHANDLING: Assigning key to {:?}", e));
|
||||||
|
}
|
||||||
|
let (stacks, mut handled, unique) = (
|
||||||
|
if let Some(_) = stackable.get(e) { true } else { false },
|
||||||
|
false,
|
||||||
|
unique(
|
||||||
|
e,
|
||||||
|
&names,
|
||||||
|
&obfuscated_names,
|
||||||
|
&renderables,
|
||||||
|
&beatitudes,
|
||||||
|
&magic_items,
|
||||||
|
Some(&wands),
|
||||||
|
&dm
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if stacks {
|
||||||
|
console::log(&format!("KEYHANDLING: Item is stackable."));
|
||||||
|
let maybe_key = item_exists(&unique);
|
||||||
|
if maybe_key.is_some() {
|
||||||
|
console::log(&format!("KEYHANDLING: Existing stack found for this item."));
|
||||||
|
let key = maybe_key.unwrap();
|
||||||
|
keys.insert(e, Key { idx: key }).expect("Unable to insert Key.");
|
||||||
|
console::log(&format!("KEYHANDLING: Assigned key idx {} to item.", key));
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !handled {
|
||||||
|
console::log(
|
||||||
|
&format!("KEYHANDLING: Item is not stackable, or no existing stack found.")
|
||||||
|
);
|
||||||
|
if let Some(idx) = assign_next_available() {
|
||||||
|
console::log(
|
||||||
|
&format!("KEYHANDLING: Assigned next available index {} to item.", idx)
|
||||||
|
);
|
||||||
|
keys.insert(e, Key { idx }).expect("Unable to insert Key.");
|
||||||
|
register_stackable(stacks, unique, idx);
|
||||||
|
} else {
|
||||||
|
console::log(&format!("KEYHANDLING: No more keys available."));
|
||||||
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
|
.append(messages::NO_MORE_KEYS)
|
||||||
|
.colour(WHITE)
|
||||||
|
.period()
|
||||||
|
.log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (e, _wants_key) in (&entities, &wants_removekey).join() {
|
||||||
|
let idx = keys.get(e).unwrap().idx;
|
||||||
|
if DEBUG_KEYHANDLING {
|
||||||
|
console::log(&format!("KEYHANDLING: Removing key from {:?}", e));
|
||||||
|
}
|
||||||
|
// If the item is *not* stackable, then we can just remove the key and clear the index.
|
||||||
|
if let None = stackable.get(e) {
|
||||||
|
console::log(
|
||||||
|
&format!("KEYHANDLING: Item is not stackable, clearing index {}.", idx)
|
||||||
|
);
|
||||||
|
clear_idx(idx);
|
||||||
|
keys.remove(e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If the item *is* stackable, then we need to check if there are any other items that
|
||||||
|
// share this key assignment, before clearing the index.
|
||||||
|
console::log(
|
||||||
|
&format!(
|
||||||
|
"KEYHANDLING: Item is stackable, checking if any other items share this key."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
let mut sole_item_with_key = true;
|
||||||
|
for (entity, key) in (&entities, &keys).join() {
|
||||||
|
if entity != e && key.idx == idx {
|
||||||
|
console::log(&format!("KEYHANDLING: Another item shares index {}", idx));
|
||||||
|
sole_item_with_key = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If no other items shared this key, free up the index.
|
||||||
|
if sole_item_with_key {
|
||||||
|
console::log(
|
||||||
|
&format!("KEYHANDLING: No other items found, clearing index {}.", idx)
|
||||||
|
);
|
||||||
|
clear_idx(idx);
|
||||||
|
}
|
||||||
|
// Either way, remove the key component from this item, because we're dropping it.
|
||||||
|
console::log(&format!("KEYHANDLING: Removing key component from item."));
|
||||||
|
keys.remove(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
wants_removekey.clear();
|
||||||
|
wants_keys.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ mod equip_system;
|
||||||
mod identification_system;
|
mod identification_system;
|
||||||
mod remove_system;
|
mod remove_system;
|
||||||
mod use_system;
|
mod use_system;
|
||||||
|
mod keyhandling;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
collection_system::ItemCollectionSystem,
|
collection_system::ItemCollectionSystem,
|
||||||
|
|
@ -12,4 +13,5 @@ pub use self::{
|
||||||
identification_system::ItemIdentificationSystem,
|
identification_system::ItemIdentificationSystem,
|
||||||
remove_system::ItemRemoveSystem,
|
remove_system::ItemRemoveSystem,
|
||||||
use_system::ItemUseSystem,
|
use_system::ItemUseSystem,
|
||||||
|
keyhandling::KeyHandling,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
55
src/invkeys.rs
Normal file
55
src/invkeys.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use std::collections::{ HashMap };
|
||||||
|
use specs::prelude::*;
|
||||||
|
use crate::gui::UniqueInventoryItem;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref INVKEYS: Mutex<HashMap<UniqueInventoryItem, usize>> = Mutex::new(HashMap::new());
|
||||||
|
pub static ref ASSIGNEDKEYS: Mutex<Vec<bool>> = Mutex::new(vec![false; 52]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For (de)serialization.
|
||||||
|
pub fn clone_invkeys() -> HashMap<UniqueInventoryItem, usize> {
|
||||||
|
let invkeys = INVKEYS.lock().unwrap();
|
||||||
|
invkeys.clone()
|
||||||
|
}
|
||||||
|
pub fn restore_invkeys(invkeys: HashMap<UniqueInventoryItem, usize>) {
|
||||||
|
INVKEYS.lock().unwrap().clear();
|
||||||
|
INVKEYS.lock().unwrap().extend(invkeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn item_exists(item: &UniqueInventoryItem) -> Option<usize> {
|
||||||
|
let invkeys = INVKEYS.lock().unwrap();
|
||||||
|
use bracket_lib::prelude::*;
|
||||||
|
console::log(&format!("{:?}", item));
|
||||||
|
if invkeys.contains_key(item) {
|
||||||
|
Some(*invkeys.get(item).unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assign_next_available() -> Option<usize> {
|
||||||
|
let mut lock = ASSIGNEDKEYS.lock().unwrap();
|
||||||
|
for (i, key) in lock.iter_mut().enumerate() {
|
||||||
|
if !*key {
|
||||||
|
*key = true;
|
||||||
|
return Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_stackable(stacks: bool, item: UniqueInventoryItem, idx: usize) {
|
||||||
|
if stacks {
|
||||||
|
let mut invkeys = INVKEYS.lock().unwrap();
|
||||||
|
invkeys.insert(item, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_idx(idx: usize) {
|
||||||
|
let mut lock = ASSIGNEDKEYS.lock().unwrap();
|
||||||
|
lock[idx] = false;
|
||||||
|
let mut invkeys = INVKEYS.lock().unwrap();
|
||||||
|
invkeys.retain(|_k, v| *v != idx);
|
||||||
|
}
|
||||||
|
|
@ -35,6 +35,7 @@ pub mod rex_assets;
|
||||||
pub mod spatial;
|
pub mod spatial;
|
||||||
pub mod morgue;
|
pub mod morgue;
|
||||||
pub mod states;
|
pub mod states;
|
||||||
|
pub mod invkeys;
|
||||||
|
|
||||||
pub use components::*;
|
pub use components::*;
|
||||||
use particle_system::ParticleBuilder;
|
use particle_system::ParticleBuilder;
|
||||||
|
|
|
||||||
13
src/main.rs
13
src/main.rs
|
|
@ -133,6 +133,10 @@ fn setup(gfx: &mut Graphics) -> State {
|
||||||
gs.ecs.register::<SpawnParticleLine>();
|
gs.ecs.register::<SpawnParticleLine>();
|
||||||
gs.ecs.register::<HasDamageModifiers>();
|
gs.ecs.register::<HasDamageModifiers>();
|
||||||
gs.ecs.register::<Intrinsics>();
|
gs.ecs.register::<Intrinsics>();
|
||||||
|
gs.ecs.register::<Stackable>();
|
||||||
|
gs.ecs.register::<WantsToAssignKey>();
|
||||||
|
gs.ecs.register::<Key>();
|
||||||
|
gs.ecs.register::<WantsToRemoveKey>();
|
||||||
gs.ecs.register::<SimpleMarker<SerializeMe>>();
|
gs.ecs.register::<SimpleMarker<SerializeMe>>();
|
||||||
gs.ecs.register::<SerializationHelper>();
|
gs.ecs.register::<SerializationHelper>();
|
||||||
gs.ecs.register::<DMSerializationHelper>();
|
gs.ecs.register::<DMSerializationHelper>();
|
||||||
|
|
@ -544,7 +548,12 @@ fn draw(_app: &mut App, gfx: &mut Graphics, gs: &mut State) {
|
||||||
corner_text("Create morgue file? [Y/N]", &mut draw, &gs.font);
|
corner_text("Create morgue file? [Y/N]", &mut draw, &gs.font);
|
||||||
}
|
}
|
||||||
RunState::ShowInventory => {
|
RunState::ShowInventory => {
|
||||||
gui::draw_inventory(&gs.ecs, &mut draw, &gs.font);
|
corner_text("Use what? [aA-zZ]/[Esc.]", &mut draw, &gs.font);
|
||||||
|
gui::draw_inventory(&gs.ecs, &mut draw, &gs.font, 1, 3);
|
||||||
|
}
|
||||||
|
RunState::ShowDropItem => {
|
||||||
|
corner_text("Drop what? [aA-zZ]/[Esc.]", &mut draw, &gs.font);
|
||||||
|
gui::draw_inventory(&gs.ecs, &mut draw, &gs.font, 1, 3);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -558,7 +567,7 @@ fn update(ctx: &mut App, state: &mut State) {
|
||||||
|
|
||||||
fn corner_text(text: &str, draw: &mut Draw, font: &Fonts) {
|
fn corner_text(text: &str, draw: &mut Draw, font: &Fonts) {
|
||||||
let offset = crate::camera::get_offset();
|
let offset = crate::camera::get_offset();
|
||||||
draw.text(&font.n(), &text)
|
draw.text(&font.b(), &text)
|
||||||
.position(((offset.x + 1) as f32) * TILESIZE, ((offset.y + 1) as f32) * TILESIZE)
|
.position(((offset.x + 1) as f32) * TILESIZE, ((offset.y + 1) as f32) * TILESIZE)
|
||||||
.size(FONTSIZE);
|
.size(FONTSIZE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,7 @@ fn random_shape_builder(
|
||||||
end: bool
|
end: bool
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Pick an initial builder
|
// Pick an initial builder
|
||||||
let builder_roll = rng.roll_dice(1, 16);
|
let builder_roll = rng.roll_dice(1, 13);
|
||||||
let mut want_doors = true;
|
let mut want_doors = true;
|
||||||
match builder_roll {
|
match builder_roll {
|
||||||
1 => builder.start_with(CellularAutomataBuilder::new()),
|
1 => builder.start_with(CellularAutomataBuilder::new()),
|
||||||
|
|
@ -317,11 +317,7 @@ fn random_shape_builder(
|
||||||
10 => builder.start_with(DLABuilder::central_attractor()),
|
10 => builder.start_with(DLABuilder::central_attractor()),
|
||||||
11 => builder.start_with(DLABuilder::insectoid()),
|
11 => builder.start_with(DLABuilder::insectoid()),
|
||||||
12 => builder.start_with(VoronoiBuilder::pythagoras()),
|
12 => builder.start_with(VoronoiBuilder::pythagoras()),
|
||||||
13 => builder.start_with(VoronoiBuilder::manhattan()),
|
_ => builder.start_with(VoronoiBuilder::manhattan()),
|
||||||
_ =>
|
|
||||||
builder.start_with(
|
|
||||||
PrefabBuilder::constant(prefab_builder::prefab_levels::WFC_POPULATED)
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'Select' the centre by placing a starting position, and cull everywhere unreachable.
|
// 'Select' the centre by placing a starting position, and cull everywhere unreachable.
|
||||||
|
|
|
||||||
|
|
@ -5,57 +5,8 @@ pub struct PrefabLevel {
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub const WFC_POPULATED: PrefabLevel = PrefabLevel { template: LEVEL_MAP, width: 80, height: 43 };
|
|
||||||
pub const OVERMAP: PrefabLevel = PrefabLevel { template: OVERMAP_TEMPLATE, width: 69, height: 41 };
|
pub const OVERMAP: PrefabLevel = PrefabLevel { template: OVERMAP_TEMPLATE, width: 69, height: 41 };
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
const LEVEL_MAP: &str =
|
|
||||||
"
|
|
||||||
################################################################################
|
|
||||||
# ######################################################## #########
|
|
||||||
# @ ###### ######### #### ################### #######
|
|
||||||
# #### g # ############### #####
|
|
||||||
# #### # # ####### #### ############# ###
|
|
||||||
##### ######### # # ####### ######### #### ##### ###
|
|
||||||
##### ######### ###### ####### o ######### #### ## ##### ###
|
|
||||||
## #### ######### ### ## o ###
|
|
||||||
##### ######### ### #### ####### ## ##### ###
|
|
||||||
##### ######### ### #### ####### # ### ## ##### ###
|
|
||||||
##### ######### ### #### ####### ####### ##### o ###
|
|
||||||
### ## ### #### ####### ################ ###
|
|
||||||
### ## ### o ###### ########### # ############ ###
|
|
||||||
### ## ### ###### ########### ### ###
|
|
||||||
### % ###### ########### # ### ! ## ###
|
|
||||||
### ## ### ###### ## ####### ## ###
|
|
||||||
### ## ### ## ### ##### # ######################## #####
|
|
||||||
### ## ### ## ### ##### # # ###################### #####
|
|
||||||
#### ## ####### ###### ##### ### #### o ########### ###### #####
|
|
||||||
#### ## ####### ###### #### ## #### # ######### ###### ######
|
|
||||||
# ## ####### ###### #### ## #### ############ ##### ######
|
|
||||||
# g ## ####### ###### #### ## % ########### o o #### # #
|
|
||||||
# ## ### #### ## #### # ####### ## ## #### g #
|
|
||||||
####### ####### #### ###### ! ! ### # #
|
|
||||||
###### ##### #### # ###### ### ######
|
|
||||||
##### ##### # ########## ### ######
|
|
||||||
##### ! ### ###### # ########## o##o ### # ##
|
|
||||||
##### ### ####### ## # ###### ### g ##
|
|
||||||
# ## #### ######## ### o ####### ^########^ #### # ##
|
|
||||||
# g # ###### ######## ##### ####### ^ ^ #### ######
|
|
||||||
# ##g#### ###### ######## ################ ##### ######
|
|
||||||
# ## ########## ########## ######## ################# ###### #
|
|
||||||
##### ######### ########## % ######## ################### ######## ## #
|
|
||||||
#### ### ######## ########## ######## #################### ########## # #
|
|
||||||
### ##### ###### ######### ######## ########### ####### # g# #
|
|
||||||
### ##### ############### ### ########### ####### #### #
|
|
||||||
### ##### #### ############## ######## g g ########### #### # ^ #
|
|
||||||
#### ###^#### ############# ######## ##### #### # g# #
|
|
||||||
##### ###### ### ######## ##### g #### ! ####^^ #
|
|
||||||
#!%^## ### ## ########## ######## gg g # > #
|
|
||||||
#!%^ ### ### ############### ######## ##### g #### # g# #
|
|
||||||
# %^## ^ ### ############### ######## ##### ##################
|
|
||||||
################################################################################";
|
|
||||||
|
|
||||||
const OVERMAP_TEMPLATE: &str =
|
const OVERMAP_TEMPLATE: &str =
|
||||||
"
|
"
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ use super::{
|
||||||
Viewshed,
|
Viewshed,
|
||||||
WantsToMelee,
|
WantsToMelee,
|
||||||
WantsToPickupItem,
|
WantsToPickupItem,
|
||||||
|
WantsToAssignKey,
|
||||||
get_dest,
|
get_dest,
|
||||||
Destination,
|
Destination,
|
||||||
DamageType,
|
DamageType,
|
||||||
|
|
@ -640,7 +641,9 @@ fn get_item(ecs: &mut World) -> RunState {
|
||||||
return RunState::AwaitingInput;
|
return RunState::AwaitingInput;
|
||||||
}
|
}
|
||||||
Some(item) => {
|
Some(item) => {
|
||||||
|
let mut assignkey = ecs.write_storage::<WantsToAssignKey>();
|
||||||
let mut pickup = ecs.write_storage::<WantsToPickupItem>();
|
let mut pickup = ecs.write_storage::<WantsToPickupItem>();
|
||||||
|
assignkey.insert(item, WantsToAssignKey {}).expect("Unable to insert WantsToAssignKey");
|
||||||
pickup
|
pickup
|
||||||
.insert(*player_entity, WantsToPickupItem { collected_by: *player_entity, item })
|
.insert(*player_entity, WantsToPickupItem { collected_by: *player_entity, item })
|
||||||
.expect("Unable to insert want to pickup item.");
|
.expect("Unable to insert want to pickup item.");
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ macro_rules! apply_flags {
|
||||||
"IDENTIFY" => $eb = $eb.with(ProvidesIdentify {}),
|
"IDENTIFY" => $eb = $eb.with(ProvidesIdentify {}),
|
||||||
"DIGGER" => $eb = $eb.with(Digger {}),
|
"DIGGER" => $eb = $eb.with(Digger {}),
|
||||||
"MAGICMAP" => $eb = $eb.with(MagicMapper {}),
|
"MAGICMAP" => $eb = $eb.with(MagicMapper {}),
|
||||||
|
"STACKABLE" => $eb = $eb.with(Stackable {}),
|
||||||
// CAN BE DESTROYED BY DAMAGE
|
// CAN BE DESTROYED BY DAMAGE
|
||||||
"DESTRUCTIBLE" => $eb = $eb.with(Destructible {}),
|
"DESTRUCTIBLE" => $eb = $eb.with(Destructible {}),
|
||||||
// --- EQUIP SLOTS ---
|
// --- EQUIP SLOTS ---
|
||||||
|
|
@ -276,6 +277,7 @@ pub fn spawn_named_item(
|
||||||
if known_beatitude && !identified_items.contains(&item_template.name.name) {
|
if known_beatitude && !identified_items.contains(&item_template.name.name) {
|
||||||
dm.identified_items.insert(item_template.name.name.clone());
|
dm.identified_items.insert(item_template.name.name.clone());
|
||||||
}
|
}
|
||||||
|
let needs_key = is_player_owned(&player_entity, &pos);
|
||||||
std::mem::drop(player_entity);
|
std::mem::drop(player_entity);
|
||||||
std::mem::drop(dm);
|
std::mem::drop(dm);
|
||||||
// -- DROP EVERYTHING THAT INVOLVES THE ECS BEFORE THIS POINT ---
|
// -- DROP EVERYTHING THAT INVOLVES THE ECS BEFORE THIS POINT ---
|
||||||
|
|
@ -290,6 +292,9 @@ pub fn spawn_named_item(
|
||||||
value: item_template.value.unwrap_or(0.0),
|
value: item_template.value.unwrap_or(0.0),
|
||||||
});
|
});
|
||||||
eb = spawn_position(pos, eb, key, raws);
|
eb = spawn_position(pos, eb, key, raws);
|
||||||
|
if needs_key {
|
||||||
|
eb = eb.with(WantsToAssignKey {});
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(renderable) = &item_template.renderable {
|
if let Some(renderable) = &item_template.renderable {
|
||||||
eb = eb.with(get_renderable_component(renderable));
|
eb = eb.with(get_renderable_component(renderable));
|
||||||
|
|
@ -387,6 +392,7 @@ pub fn spawn_named_mob(
|
||||||
if raws.mob_index.contains_key(key) {
|
if raws.mob_index.contains_key(key) {
|
||||||
let mob_template = &raws.raws.mobs[raws.mob_index[key]];
|
let mob_template = &raws.raws.mobs[raws.mob_index[key]];
|
||||||
let mut player_level = 1;
|
let mut player_level = 1;
|
||||||
|
let needs_key;
|
||||||
{
|
{
|
||||||
let pools = ecs.read_storage::<Pools>();
|
let pools = ecs.read_storage::<Pools>();
|
||||||
let player_entity = ecs.fetch::<Entity>();
|
let player_entity = ecs.fetch::<Entity>();
|
||||||
|
|
@ -394,12 +400,15 @@ pub fn spawn_named_mob(
|
||||||
if let Some(pool) = player_pool {
|
if let Some(pool) = player_pool {
|
||||||
player_level = pool.level;
|
player_level = pool.level;
|
||||||
}
|
}
|
||||||
|
needs_key = is_player_owned(&player_entity, &pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut eb;
|
let mut eb;
|
||||||
// New entity with a position, name, combatstats, and viewshed
|
// New entity with a position, name, combatstats, and viewshed
|
||||||
eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
|
eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
|
||||||
eb = spawn_position(pos, eb, key, raws);
|
eb = spawn_position(pos, eb, key, raws);
|
||||||
|
if needs_key {
|
||||||
|
eb = eb.with(WantsToAssignKey {});
|
||||||
|
}
|
||||||
eb = eb.with(Name { name: mob_template.name.clone(), plural: mob_template.name.clone() });
|
eb = eb.with(Name { name: mob_template.name.clone(), plural: mob_template.name.clone() });
|
||||||
eb = eb.with(Viewshed {
|
eb = eb.with(Viewshed {
|
||||||
visible_tiles: Vec::new(),
|
visible_tiles: Vec::new(),
|
||||||
|
|
@ -620,10 +629,18 @@ pub fn spawn_named_prop(
|
||||||
pos: SpawnType
|
pos: SpawnType
|
||||||
) -> Option<Entity> {
|
) -> Option<Entity> {
|
||||||
if raws.prop_index.contains_key(key) {
|
if raws.prop_index.contains_key(key) {
|
||||||
|
let needs_key;
|
||||||
|
{
|
||||||
|
let player_entity = ecs.fetch::<Entity>();
|
||||||
|
needs_key = is_player_owned(&player_entity, &pos);
|
||||||
|
}
|
||||||
// ENTITY BUILDER PREP
|
// ENTITY BUILDER PREP
|
||||||
let prop_template = &raws.raws.props[raws.prop_index[key]];
|
let prop_template = &raws.raws.props[raws.prop_index[key]];
|
||||||
let mut eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
|
let mut eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
|
||||||
eb = spawn_position(pos, eb, key, raws);
|
eb = spawn_position(pos, eb, key, raws);
|
||||||
|
if needs_key {
|
||||||
|
eb = eb.with(WantsToAssignKey {});
|
||||||
|
}
|
||||||
// APPLY MANDATORY COMPONENTS FOR A PROP:
|
// APPLY MANDATORY COMPONENTS FOR A PROP:
|
||||||
// - Name
|
// - Name
|
||||||
// - Prop {}
|
// - Prop {}
|
||||||
|
|
@ -691,6 +708,23 @@ fn spawn_position<'a>(
|
||||||
eb
|
eb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_player_owned(player: &Entity, pos: &SpawnType) -> bool {
|
||||||
|
match pos {
|
||||||
|
SpawnType::Carried { by } => {
|
||||||
|
if by == player {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SpawnType::Equipped { by } => {
|
||||||
|
if by == player {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn get_renderable_component(
|
fn get_renderable_component(
|
||||||
renderable: &super::item_structs::Renderable
|
renderable: &super::item_structs::Renderable
|
||||||
) -> crate::components::Renderable {
|
) -> crate::components::Renderable {
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ pub fn save_game(ecs: &mut World) {
|
||||||
InflictsDamage,
|
InflictsDamage,
|
||||||
Intrinsics,
|
Intrinsics,
|
||||||
Item,
|
Item,
|
||||||
|
Key,
|
||||||
KnownSpells,
|
KnownSpells,
|
||||||
LootTable,
|
LootTable,
|
||||||
MagicItem,
|
MagicItem,
|
||||||
|
|
@ -132,17 +133,20 @@ pub fn save_game(ecs: &mut World) {
|
||||||
SpawnParticleBurst,
|
SpawnParticleBurst,
|
||||||
SpawnParticleLine,
|
SpawnParticleLine,
|
||||||
SpawnParticleSimple,
|
SpawnParticleSimple,
|
||||||
|
Stackable,
|
||||||
TakingTurn,
|
TakingTurn,
|
||||||
Telepath,
|
Telepath,
|
||||||
ToHitBonus,
|
ToHitBonus,
|
||||||
Viewshed,
|
Viewshed,
|
||||||
Charges,
|
Charges,
|
||||||
WantsToApproach,
|
WantsToApproach,
|
||||||
|
WantsToAssignKey,
|
||||||
WantsToDropItem,
|
WantsToDropItem,
|
||||||
WantsToFlee,
|
WantsToFlee,
|
||||||
WantsToMelee,
|
WantsToMelee,
|
||||||
WantsToPickupItem,
|
WantsToPickupItem,
|
||||||
WantsToRemoveItem,
|
WantsToRemoveItem,
|
||||||
|
WantsToRemoveKey,
|
||||||
WantsToUseItem,
|
WantsToUseItem,
|
||||||
SerializationHelper,
|
SerializationHelper,
|
||||||
DMSerializationHelper
|
DMSerializationHelper
|
||||||
|
|
@ -235,6 +239,7 @@ pub fn load_game(ecs: &mut World) {
|
||||||
InflictsDamage,
|
InflictsDamage,
|
||||||
Intrinsics,
|
Intrinsics,
|
||||||
Item,
|
Item,
|
||||||
|
Key,
|
||||||
KnownSpells,
|
KnownSpells,
|
||||||
LootTable,
|
LootTable,
|
||||||
MagicItem,
|
MagicItem,
|
||||||
|
|
@ -264,17 +269,20 @@ pub fn load_game(ecs: &mut World) {
|
||||||
SpawnParticleBurst,
|
SpawnParticleBurst,
|
||||||
SpawnParticleLine,
|
SpawnParticleLine,
|
||||||
SpawnParticleSimple,
|
SpawnParticleSimple,
|
||||||
|
Stackable,
|
||||||
TakingTurn,
|
TakingTurn,
|
||||||
Telepath,
|
Telepath,
|
||||||
ToHitBonus,
|
ToHitBonus,
|
||||||
Viewshed,
|
Viewshed,
|
||||||
Charges,
|
Charges,
|
||||||
WantsToApproach,
|
WantsToApproach,
|
||||||
|
WantsToAssignKey,
|
||||||
WantsToDropItem,
|
WantsToDropItem,
|
||||||
WantsToFlee,
|
WantsToFlee,
|
||||||
WantsToMelee,
|
WantsToMelee,
|
||||||
WantsToPickupItem,
|
WantsToPickupItem,
|
||||||
WantsToRemoveItem,
|
WantsToRemoveItem,
|
||||||
|
WantsToRemoveKey,
|
||||||
WantsToUseItem,
|
WantsToUseItem,
|
||||||
SerializationHelper,
|
SerializationHelper,
|
||||||
DMSerializationHelper
|
DMSerializationHelper
|
||||||
|
|
|
||||||
|
|
@ -102,12 +102,13 @@ impl State {
|
||||||
|
|
||||||
fn resolve_entity_decisions(&mut self) {
|
fn resolve_entity_decisions(&mut self) {
|
||||||
let mut trigger_system = trigger_system::TriggerSystem {};
|
let mut trigger_system = trigger_system::TriggerSystem {};
|
||||||
let mut inventory_system = inventory::ItemCollectionSystem {};
|
|
||||||
let mut item_equip_system = inventory::ItemEquipSystem {};
|
let mut item_equip_system = inventory::ItemEquipSystem {};
|
||||||
let mut item_use_system = inventory::ItemUseSystem {};
|
let mut item_use_system = inventory::ItemUseSystem {};
|
||||||
let mut item_drop_system = inventory::ItemDropSystem {};
|
let mut item_drop_system = inventory::ItemDropSystem {};
|
||||||
let mut item_remove_system = inventory::ItemRemoveSystem {};
|
let mut item_remove_system = inventory::ItemRemoveSystem {};
|
||||||
|
let mut inventory_system = inventory::ItemCollectionSystem {};
|
||||||
let mut item_id_system = inventory::ItemIdentificationSystem {};
|
let mut item_id_system = inventory::ItemIdentificationSystem {};
|
||||||
|
let mut key_system = inventory::KeyHandling {};
|
||||||
let mut melee_system = MeleeCombatSystem {};
|
let mut melee_system = MeleeCombatSystem {};
|
||||||
trigger_system.run_now(&self.ecs);
|
trigger_system.run_now(&self.ecs);
|
||||||
inventory_system.run_now(&self.ecs);
|
inventory_system.run_now(&self.ecs);
|
||||||
|
|
@ -116,6 +117,7 @@ impl State {
|
||||||
item_drop_system.run_now(&self.ecs);
|
item_drop_system.run_now(&self.ecs);
|
||||||
item_remove_system.run_now(&self.ecs);
|
item_remove_system.run_now(&self.ecs);
|
||||||
item_id_system.run_now(&self.ecs);
|
item_id_system.run_now(&self.ecs);
|
||||||
|
key_system.run_now(&self.ecs);
|
||||||
melee_system.run_now(&self.ecs);
|
melee_system.run_now(&self.ecs);
|
||||||
|
|
||||||
effects::run_effects_queue(&mut self.ecs);
|
effects::run_effects_queue(&mut self.ecs);
|
||||||
|
|
@ -351,7 +353,29 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// RunState::ShowDropItem
|
RunState::ShowDropItem => {
|
||||||
|
let result = gui::drop_item_menu(self, ctx);
|
||||||
|
match result.0 {
|
||||||
|
gui::ItemMenuResult::Cancel => {
|
||||||
|
new_runstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
|
gui::ItemMenuResult::Selected => {
|
||||||
|
let item = result.1.unwrap();
|
||||||
|
let mut removekey = self.ecs.write_storage::<WantsToRemoveKey>();
|
||||||
|
let mut intent = self.ecs.write_storage::<WantsToDropItem>();
|
||||||
|
removekey
|
||||||
|
.insert(item, WantsToRemoveKey {})
|
||||||
|
.expect("Unable to insert WantsToRemoveKey");
|
||||||
|
intent
|
||||||
|
.insert(*self.ecs.fetch::<Entity>(), WantsToDropItem {
|
||||||
|
item,
|
||||||
|
})
|
||||||
|
.expect("Unable to insert WantsToDropItem");
|
||||||
|
new_runstate = RunState::Ticking;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// RunState::ShowRemoveItem
|
// RunState::ShowRemoveItem
|
||||||
// RunState::ShowTargeting
|
// RunState::ShowTargeting
|
||||||
// RunState::ShowRemoveCurse
|
// RunState::ShowRemoveCurse
|
||||||
|
|
@ -648,7 +672,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RunState::ShowDropItem => {
|
RunState::ShowDropItem => {
|
||||||
let result = gui::drop_item_menu(self, ctx);
|
let result = (gui::ItemMenuResult::Cancel, None); //gui::drop_item_menu(self, ctx);
|
||||||
match result.0 {
|
match result.0 {
|
||||||
gui::ItemMenuResult::Cancel => {
|
gui::ItemMenuResult::Cancel => {
|
||||||
new_runstate = RunState::AwaitingInput;
|
new_runstate = RunState::AwaitingInput;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue