Removed ability set as field on items.

This commit is contained in:
Sam 2021-04-29 19:34:14 -04:00
parent a37174d6f2
commit a35b8b4aad
23 changed files with 215 additions and 195 deletions

View File

@ -1,244 +1,244 @@
// Maps a tool kind to a set of abilities
// A set of abilities is a primary, a secondary, and a vec of all extra abilities
({
Sword: (
Tool(Sword): (
primary: "common.abilities.sword.triplestrike",
secondary: "common.abilities.sword.dash",
abilities: [
(Some(Sword(UnlockSpin)), "common.abilities.sword.spin"),
],
),
Axe: (
Tool(Axe): (
primary: "common.abilities.axe.doublestrike",
secondary: "common.abilities.axe.spin",
abilities: [
(Some(Axe(UnlockLeap)), "common.abilities.axe.leap"),
],
),
Hammer: (
Tool(Hammer): (
primary: "common.abilities.hammer.singlestrike",
secondary: "common.abilities.hammer.charged",
abilities: [
(Some(Hammer(UnlockLeap)), "common.abilities.hammer.leap"),
],
),
Bow: (
Tool(Bow): (
primary: "common.abilities.bow.basic",
secondary: "common.abilities.bow.charged",
abilities: [
(Some(Bow(UnlockRepeater)), "common.abilities.bow.repeater"),
],
),
Unique(Husk): (
Tool(Unique(Husk)): (
primary: "common.abilities.unique.husk.singlestrike",
secondary: "common.abilities.unique.husk.triplestrike",
abilities: [],
),
Spear: (
Tool(Spear): (
primary: "common.abilities.spear.doublestrike",
secondary: "common.abilities.spear.dash",
abilities: [],
),
HammerSimple: (
Tool(HammerSimple): (
primary: "common.abilities.hammersimple.doublestrike",
secondary: "common.abilities.hammersimple.doublestrike",
abilities: [],
),
AxeSimple: (
Tool(AxeSimple): (
primary: "common.abilities.axesimple.doublestrike",
secondary: "common.abilities.axesimple.dash",
abilities: [],
),
SwordSimple: (
Tool(SwordSimple): (
primary: "common.abilities.swordsimple.doublestrike",
secondary: "common.abilities.swordsimple.dash",
abilities: [
],
),
StaffSimple: (
Tool(StaffSimple): (
primary: "common.abilities.staffsimple.firebomb",
secondary: "common.abilities.staffsimple.flamethrower",
abilities: [],
),
BowSimple: (
Tool(BowSimple): (
primary: "common.abilities.bowsimple.basic",
secondary: "common.abilities.bowsimple.basic",
abilities: [
],
),
Staff: (
Tool(Staff): (
primary: "common.abilities.staff.firebomb",
secondary: "common.abilities.staff.flamethrower",
abilities: [
(Some(Staff(UnlockShockwave)), "common.abilities.staff.fireshockwave"),
],
),
Sceptre: (
Tool(Sceptre): (
primary: "common.abilities.sceptre.lifestealbeam",
secondary: "common.abilities.sceptre.healingbeam",
abilities: [
(Some(Sceptre(UnlockAura)), "common.abilities.sceptre.wardingaura"),
],
),
Dagger: (
Tool(Dagger): (
primary: "common.abilities.dagger.tempbasic",
secondary: "common.abilities.dagger.tempbasic",
abilities: [],
),
Shield: (
Tool(Shield): (
primary: "common.abilities.shield.tempbasic",
secondary: "common.abilities.shield.block",
abilities: [],
),
Unique(StoneGolemFist): (
Tool(Unique(StoneGolemFist)): (
primary: "common.abilities.unique.stonegolemfist.singlestrike",
secondary: "common.abilities.unique.stonegolemfist.shockwave",
abilities: [
(None, "common.abilities.unique.stonegolemfist.spin"),
],
),
Unique(BeastClaws): (
Tool(Unique(BeastClaws)): (
primary: "common.abilities.unique.beastclaws.basic",
secondary: "common.abilities.unique.beastclaws.basic",
abilities: [],
),
Unique(WendigoMagic): (
Tool(Unique(WendigoMagic)): (
primary: "common.abilities.unique.wendigomagic.frostbomb",
secondary: "common.abilities.unique.wendigomagic.singlestrike",
abilities: [],
),
Unique(TidalClaws): (
Tool(Unique(TidalClaws)): (
primary: "common.abilities.staff.flamethrower",
secondary: "common.abilities.unique.wendigomagic.singlestrike",
abilities: [],
),
Unique(QuadMedQuick): (
Tool(Unique(QuadMedQuick)): (
primary: "common.abilities.unique.quadmedquick.triplestrike",
secondary: "common.abilities.unique.quadmedquick.dash",
abilities: [],
),
Unique(QuadMedJump): (
Tool(Unique(QuadMedJump)): (
primary: "common.abilities.unique.quadmedjump.leap",
secondary: "common.abilities.unique.quadmedjump.doublestrike",
abilities: [
(None, "common.abilities.unique.quadmedjump.quickleap"),
],
),
Unique(QuadMedCharge): (
Tool(Unique(QuadMedCharge)): (
primary: "common.abilities.unique.quadmedcharge.doublestrike",
secondary: "common.abilities.unique.quadmedcharge.dash",
abilities: [],
),
Unique(QuadMedHoof): (
Tool(Unique(QuadMedHoof)): (
primary: "common.abilities.unique.quadmedhoof.basic",
secondary: "common.abilities.unique.quadmedhoof.basic",
abilities: [],
),
Unique(QuadMedBasic): (
Tool(Unique(QuadMedBasic)): (
primary: "common.abilities.unique.quadmedbasic.singlestrike",
secondary: "common.abilities.unique.quadmedbasic.triplestrike",
abilities: [],
),
Unique(QuadLowRanged): (
Tool(Unique(QuadLowRanged)): (
primary: "common.abilities.unique.quadlowranged.singlestrike",
secondary: "common.abilities.unique.quadlowranged.firebomb",
abilities: [],
),
Unique(QuadLowBreathe): (
Tool(Unique(QuadLowBreathe)): (
primary: "common.abilities.unique.quadlowbreathe.flamethrower",
secondary: "common.abilities.unique.quadlowbreathe.triplestrike",
abilities: [
(None, "common.abilities.unique.quadlowbreathe.dash"),
],
),
Unique(QuadLowTail): (
Tool(Unique(QuadLowTail)): (
primary: "common.abilities.unique.quadlowtail.charged",
secondary: "common.abilities.unique.quadlowtail.triplestrike",
abilities: [],
),
Unique(QuadLowQuick): (
Tool(Unique(QuadLowQuick)): (
primary: "common.abilities.unique.quadlowquick.dash",
secondary: "common.abilities.unique.quadlowquick.quadstrike",
abilities: [],
),
Unique(QuadLowBasic): (
Tool(Unique(QuadLowBasic)): (
primary: "common.abilities.unique.quadlowbasic.triplestrike",
secondary: "common.abilities.unique.quadlowbasic.singlestrike",
abilities: [],
),
Unique(QuadLowBeam): (
Tool(Unique(QuadLowBeam)): (
primary: "common.abilities.unique.quadlowbeam.healingbeam",
secondary: "common.abilities.unique.quadlowbreathe.triplestrike",
abilities: [
(None, "common.abilities.unique.quadlowbreathe.dash"),
],
),
Unique(QuadSmallBasic): (
Tool(Unique(QuadSmallBasic)): (
primary: "common.abilities.unique.quadsmallbasic.singlestrike",
secondary: "common.abilities.unique.quadsmallbasic.singlestrike",
abilities: [],
),
Unique(TheropodBasic): (
Tool(Unique(TheropodBasic)): (
primary: "common.abilities.unique.theropodbasic.triplestrike",
secondary: "common.abilities.unique.theropodbasic.triplestrike",
abilities: [],
),
Unique(TheropodBird): (
Tool(Unique(TheropodBird)): (
primary: "common.abilities.unique.theropodbird.triplestrike",
secondary: "common.abilities.unique.theropodbird.triplestrike",
abilities: [],
),
Unique(TheropodCharge): (
Tool(Unique(TheropodCharge)): (
primary: "common.abilities.unique.theropodbird.triplestrike",
secondary: "common.abilities.unique.theropodbasic.dash",
abilities: [],
),
Unique(ObjectTurret): (
Tool(Unique(ObjectTurret)): (
primary: "common.abilities.unique.turret.arrows",
secondary: "common.abilities.unique.turret.arrows",
abilities: [],
),
Unique(MindflayerStaff): (
primary: "common.abilities.unique.mindflayer.cursedflames",
secondary: "common.abilities.unique.mindflayer.necroticvortex",
abilities: [
(None, "common.abilities.unique.mindflayer.dimensionaldoor"),
(None, "common.abilities.unique.mindflayer.summonminions"),
],
),
Unique(BirdLargeBreathe): (
// Tool(Unique(MindflayerStaff)): (
// primary: "common.abilities.unique.mindflayer.cursedflames",
// secondary: "common.abilities.unique.mindflayer.necroticvortex",
// abilities: [
// (None, "common.abilities.unique.mindflayer.dimensionaldoor"),
// (None, "common.abilities.unique.mindflayer.summonminions"),
// ],
// ),
Tool(Unique(BirdLargeBreathe)): (
primary: "common.abilities.unique.birdlargebreathe.firebomb",
secondary: "common.abilities.unique.birdlargebreathe.triplestrike",
abilities: [
(None, "common.abilities.unique.birdlargebreathe.flamethrower"),
],
),
Unique(BirdLargeFire): (
Tool(Unique(BirdLargeFire)): (
primary: "common.abilities.unique.birdlargefire.firebomb",
secondary: "common.abilities.unique.birdlargefire.triplestrike",
abilities: [
(None, "common.abilities.unique.birdlargefire.fireshockwave"),
],
),
Debug: (
Tool(Debug): (
primary: "common.abilities.debug.forwardboost",
secondary: "common.abilities.debug.upboost",
abilities: [
(None, "common.abilities.debug.possess"),
],
),
Farming: (
Tool(Farming): (
primary: "common.abilities.farming.basic",
secondary: "common.abilities.farming.basic",
abilities: [],
),
Pick: (
Tool(Pick): (
primary: "common.abilities.pick.swing",
secondary: "common.abilities.pick.swing",
abilities: [],
),
Empty: (
Tool(Empty): (
primary: "common.abilities.empty.basic",
secondary: "common.abilities.empty.basic",
abilities: [],

View File

@ -2,7 +2,7 @@ ItemDef(
name: "Mindflayer Staff",
description: "Placeholder",
kind: Tool((
kind: Unique(MindflayerStaff),
kind: Staff,
hands: Two,
stats: Direct((
equip_time_secs: 0.01,

View File

@ -4,7 +4,7 @@ pub mod tool;
// Reexports
pub use modular::{ModularComponent, ModularComponentKind, ModularComponentTag};
pub use tool::{AbilitySet, Hands, MaterialStatManifest, Tool, ToolKind, UniqueKind};
pub use tool::{AbilitySet, AbilitySpec, Hands, MaterialStatManifest, Tool, ToolKind, UniqueKind};
use crate::{
assets::{self, AssetExt, Error},
@ -28,6 +28,7 @@ use serde::{de, Deserialize, Serialize, Serializer};
use specs::{Component, DerefFlaggedStorage};
use specs_idvs::IdvStorage;
use std::{fmt, sync::Arc};
use tracing::error;
use vek::Rgb;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@ -275,17 +276,19 @@ pub struct ItemDef {
pub tags: Vec<ItemTag>,
#[serde(default)]
pub slots: u16,
ability_map: AbilityMap,
/// Used to specify a custom ability set for a weapon. Leave None (or don't
/// include field in ItemDef) to use default ability set for weapon kind.
pub ability_set: Option<String>,
}
impl PartialEq for ItemDef {
fn eq(&self, other: &Self) -> bool { self.item_definition_id == other.item_definition_id }
}
// TODO: Look into removing ItemConfig and just using AbilitySet
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ItemConfig {
pub abilities: AbilitySet<CharacterAbility>,
pub block_ability: Option<CharacterAbility>,
}
#[derive(Debug)]
@ -293,19 +296,34 @@ pub enum ItemConfigError {
BadItemKind,
}
impl TryFrom<(&ItemKind, &[Item], &AbilityMap, &MaterialStatManifest)> for ItemConfig {
impl TryFrom<(&Item, &AbilityMap, &MaterialStatManifest)> for ItemConfig {
type Error = ItemConfigError;
fn try_from(
(item_kind, components, map, msm): (&ItemKind, &[Item], &AbilityMap, &MaterialStatManifest),
(item, ability_map, msm): (&Item, &AbilityMap, &MaterialStatManifest),
) -> Result<Self, Self::Error> {
if let ItemKind::Tool(tool) = item_kind {
let abilities = tool.get_abilities(msm, components, map);
if let ItemKind::Tool(tool) = &item.kind {
// If no custom ability set is specified, fall back to abilityset of tool kind.
let ability_set_key = item
.item_def
.ability_set
.as_ref()
.map_or(AbilitySpec::Tool(tool.kind), |set| {
AbilitySpec::Custom(set.to_string())
});
Ok(ItemConfig {
abilities,
block_ability: None,
})
let abilities = if let Some(set) = ability_map.get_ability_set(&ability_set_key) {
set.clone().modified_by_tool(&tool, msm, &item.components)
} else {
error!(
"No AbilitySet in the ability map for specification: {:?} falling back to \
default",
ability_set_key
);
Default::default()
};
Ok(ItemConfig { abilities })
} else {
Err(ItemConfigError::BadItemKind)
}
@ -395,10 +413,6 @@ impl assets::Compound for ItemDef {
.load_owned::<RawItemDef>(specifier)
.or_else(|e| modular::synthesize_modular_asset(specifier).ok_or(e))?;
let ability_map_handle =
cache.load::<AbilityMap>("common.abilities.weapon_ability_manifest")?;
let ability_map = ability_map_handle.read().clone();
let RawItemDef {
name,
description,
@ -406,6 +420,7 @@ impl assets::Compound for ItemDef {
quality,
tags,
slots,
ability_set,
} = raw;
// Some commands like /give_item provide the asset specifier separated with \
@ -422,7 +437,7 @@ impl assets::Compound for ItemDef {
quality,
tags,
slots,
ability_map,
ability_set,
})
}
}
@ -437,6 +452,7 @@ struct RawItemDef {
tags: Vec<ItemTag>,
#[serde(default)]
slots: u16,
ability_set: Option<String>,
}
impl assets::Asset for RawItemDef {
@ -474,13 +490,18 @@ impl Item {
pub fn new_from_item_def(
inner_item: Arc<ItemDef>,
input_components: &[Item],
ability_map: &AbilityMap,
msm: &MaterialStatManifest,
) -> Self {
let mut components = Vec::new();
if inner_item.is_modular() {
// recipe ensures that types match (i.e. no axe heads on a sword hilt, or double
// sword blades)
components.extend(input_components.iter().map(|comp| comp.duplicate(msm)));
components.extend(
input_components
.iter()
.map(|comp| comp.duplicate(ability_map, msm)),
);
}
let mut item = Item {
@ -491,7 +512,7 @@ impl Item {
item_def: inner_item,
item_config: None,
};
item.update_item_config(msm);
item.update_item_config(ability_map, msm);
item
}
@ -499,8 +520,10 @@ impl Item {
/// Panics if the asset does not exist.
pub fn new_from_asset_expect(asset_specifier: &str) -> Self {
let inner_item = Arc::<ItemDef>::load_expect_cloned(asset_specifier);
// TODO: Figure out better way to get msm and ability_map
let msm = MaterialStatManifest::default();
Item::new_from_item_def(inner_item, &[], &msm)
let ability_map = AbilityMap::default();
Item::new_from_item_def(inner_item, &[], &ability_map, &msm)
}
/// Creates a Vec containing one of each item that matches the provided
@ -513,14 +536,20 @@ impl Item {
/// it exists
pub fn new_from_asset(asset: &str) -> Result<Self, Error> {
let inner_item = Arc::<ItemDef>::load_cloned(asset)?;
// TODO: Get msm and ability_map less hackily
let msm = MaterialStatManifest::default();
Ok(Item::new_from_item_def(inner_item, &[], &msm))
let ability_map = AbilityMap::default();
Ok(Item::new_from_item_def(inner_item, &[], &ability_map, &msm))
}
/// Duplicates an item, creating an exact copy but with a new item ID
pub fn duplicate(&self, msm: &MaterialStatManifest) -> Self {
let mut new_item =
Item::new_from_item_def(Arc::clone(&self.item_def), &self.components, msm);
pub fn duplicate(&self, ability_map: &AbilityMap, msm: &MaterialStatManifest) -> Self {
let mut new_item = Item::new_from_item_def(
Arc::clone(&self.item_def),
&self.components,
ability_map,
msm,
);
new_item.set_amount(self.amount()).expect(
"`new_item` has the same `item_def` and as an invariant, \
self.set_amount(self.amount()) should always succeed.",
@ -529,7 +558,7 @@ impl Item {
|(new_item_slot, old_item_slot)| {
*new_item_slot = old_item_slot
.as_ref()
.map(|old_item| old_item.duplicate(msm));
.map(|old_item| old_item.duplicate(ability_map, msm));
},
);
new_item
@ -596,22 +625,22 @@ impl Item {
}
}
pub fn add_component(&mut self, component: Item, msm: &MaterialStatManifest) {
pub fn add_component(
&mut self,
component: Item,
ability_map: &AbilityMap,
msm: &MaterialStatManifest,
) {
// TODO: hook for typechecking (not needed atm if this is only used by DB
// persistence, but will definitely be needed once enhancement slots are
// added to prevent putting a sword into another sword)
self.components.push(component);
// adding a component changes the stats, so recalculate the ItemConfig
self.update_item_config(msm);
self.update_item_config(ability_map, msm);
}
fn update_item_config(&mut self, msm: &MaterialStatManifest) {
if let Ok(item_config) = ItemConfig::try_from((
self.kind(),
self.components(),
&self.item_def.ability_map,
msm,
)) {
fn update_item_config(&mut self, ability_map: &AbilityMap, msm: &MaterialStatManifest) {
if let Ok(item_config) = ItemConfig::try_from((&*self, ability_map, msm)) {
self.item_config = Some(Box::new(item_config));
}
}

View File

@ -208,6 +208,7 @@ fn make_component_def(
quality,
tags: vec![ItemTag::ModularComponent(tag)],
slots: 0,
ability_set: None,
};
(identifier, item)
}
@ -230,6 +231,7 @@ fn make_weapon_def(toolkind: ToolKind) -> (String, RawItemDef) {
quality,
tags: Vec::new(),
slots: 0,
ability_set: None,
};
(identifier, item)
}
@ -282,6 +284,7 @@ fn make_tagexample_def(
quality,
tags: vec![ItemTag::ModularComponent(tag)],
slots: 0,
ability_set: None,
};
(identifier, item)
}

View File

@ -11,7 +11,6 @@ use std::{
ops::{AddAssign, DivAssign, MulAssign, Sub},
time::Duration,
};
use tracing::error;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ToolKind {
@ -167,6 +166,7 @@ impl Asset for MaterialStatManifest {
impl Default for MaterialStatManifest {
fn default() -> MaterialStatManifest {
// TODO: Don't do this, loading a default should have no ability to panic
MaterialStatManifest::load_expect_cloned("common.material_stats_manifest")
}
}
@ -310,23 +310,6 @@ impl Tool {
Duration::from_secs_f32(self.stats.resolve_stats(msm, components).equip_time_secs)
}
pub fn get_abilities(
&self,
msm: &MaterialStatManifest,
components: &[Item],
map: &AbilityMap,
) -> AbilitySet<CharacterAbility> {
if let Some(set) = map.0.get(&self.kind).cloned() {
set.modified_by_tool(&self, msm, components)
} else {
error!(
"ToolKind: {:?} has no AbilitySet in the ability map falling back to default",
&self.kind
);
Default::default()
}
}
pub fn can_block(&self) -> bool {
matches!(
self.kind,
@ -386,17 +369,32 @@ impl Default for AbilitySet<CharacterAbility> {
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum AbilitySpec {
Tool(ToolKind),
Custom(String),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AbilityMap<T = CharacterAbility>(HashMap<ToolKind, AbilitySet<T>>);
pub struct AbilityMap<T = CharacterAbility>(HashMap<AbilitySpec, AbilitySet<T>>);
impl Default for AbilityMap {
fn default() -> Self {
let mut map = HashMap::new();
map.insert(ToolKind::Empty, AbilitySet::default());
AbilityMap(map)
// TODO: Revert to old default
if let Ok(map) = Self::load_cloned("common.abilities.ability_set_manifest") {
map
} else {
let mut map = HashMap::new();
map.insert(AbilitySpec::Tool(ToolKind::Empty), AbilitySet::default());
AbilityMap(map)
}
}
}
impl<T> AbilityMap<T> {
pub fn get_ability_set(&self, key: &AbilitySpec) -> Option<&AbilitySet<T>> { self.0.get(key) }
}
impl Asset for AbilityMap<String> {
type Loader = assets::RonLoader;
@ -416,7 +414,7 @@ impl assets::Compound for AbilityMap {
.iter()
.map(|(kind, set)| {
(
*kind,
kind.clone(),
// expect cannot fail because CharacterAbility always
// provides a default value in case of failure
set.map_ref(|s| cache.load_expect(&s).cloned()),
@ -451,7 +449,6 @@ pub enum UniqueKind {
TheropodCharge,
ObjectTurret,
WoodenSpear,
MindflayerStaff,
BirdLargeBreathe,
BirdLargeFire,
}

View File

@ -8,7 +8,7 @@ use tracing::{debug, trace, warn};
use crate::{
comp::{
inventory::{
item::{ItemDef, ItemKind, MaterialStatManifest, TagExampleInfo},
item::{tool::AbilityMap, ItemDef, ItemKind, MaterialStatManifest, TagExampleInfo},
loadout::Loadout,
slot::{EquipSlot, Slot, SlotError},
},
@ -377,9 +377,14 @@ impl Inventory {
}
/// Remove just one item from the slot
pub fn take(&mut self, inv_slot_id: InvSlotId, msm: &MaterialStatManifest) -> Option<Item> {
pub fn take(
&mut self,
inv_slot_id: InvSlotId,
ability_map: &AbilityMap,
msm: &MaterialStatManifest,
) -> Option<Item> {
if let Some(Some(item)) = self.slot_mut(inv_slot_id) {
let mut return_item = item.duplicate(msm);
let mut return_item = item.duplicate(ability_map, msm);
if item.is_stackable() && item.amount() > 1 {
item.decrease_amount(1).ok()?;
@ -399,11 +404,12 @@ impl Inventory {
pub fn take_half(
&mut self,
inv_slot_id: InvSlotId,
ability_map: &AbilityMap,
msm: &MaterialStatManifest,
) -> Option<Item> {
if let Some(Some(item)) = self.slot_mut(inv_slot_id) {
if item.is_stackable() && item.amount() > 1 {
let mut return_item = item.duplicate(msm);
let mut return_item = item.duplicate(ability_map, msm);
let returning_amount = item.amount() / 2;
item.decrease_amount(returning_amount).ok()?;
return_item.set_amount(returning_amount).expect(

View File

@ -1,7 +1,7 @@
use crate::{
assets::{self, AssetExt, AssetHandle},
comp::{
item::{modular, ItemDef, ItemTag, MaterialStatManifest},
item::{modular, tool::AbilityMap, ItemDef, ItemTag, MaterialStatManifest},
Inventory, Item,
},
terrain::SpriteKind,
@ -29,6 +29,7 @@ impl Recipe {
pub fn perform(
&self,
inv: &mut Inventory,
ability_map: &AbilityMap,
msm: &MaterialStatManifest,
) -> Result<Option<(Item, u32)>, Vec<(&RecipeInput, u32)>> {
// Get ingredient cells from inventory,
@ -39,7 +40,7 @@ impl Recipe {
.for_each(|(pos, n)| {
(0..n).for_each(|_| {
let component = inv
.take(pos, msm)
.take(pos, ability_map, msm)
.expect("Expected item to exist in inventory");
components.push(component);
})
@ -47,7 +48,7 @@ impl Recipe {
for i in 0..self.output.1 {
let crafted_item =
Item::new_from_item_def(Arc::clone(&self.output.0), &components, msm);
Item::new_from_item_def(Arc::clone(&self.output.0), &components, ability_map, msm);
if let Err(item) = inv.push(crafted_item) {
return Ok(Some((item, self.output.1 - i)));
}

View File

@ -16,7 +16,7 @@ use common::{
self,
aura::{Aura, AuraKind, AuraTarget},
buff::{BuffCategory, BuffData, BuffKind, BuffSource},
inventory::item::MaterialStatManifest,
inventory::item::{tool::AbilityMap, MaterialStatManifest},
invite::InviteKind,
ChatType, Inventory, Item, LightEmitter, WaypointArea,
},
@ -332,6 +332,7 @@ fn handle_give_item(
}
});
} else {
let ability_map = server.state.ecs().read_resource::<AbilityMap>();
let msm = server.state.ecs().read_resource::<MaterialStatManifest>();
// This item can't stack. Give each item in a loop.
server
@ -342,7 +343,7 @@ fn handle_give_item(
.map(|mut inv| {
for i in 0..give_amount {
// NOTE: Deliberately ignores items that couldn't be pushed.
if inv.push(item.duplicate(&msm)).is_err() {
if inv.push(item.duplicate(&ability_map, &msm)).is_err() {
res = Err(format!(
"Player inventory full. Gave {} of {} items.",
i, give_amount

View File

@ -6,7 +6,7 @@ use vek::{Rgb, Vec3};
use common::{
comp::{
self,
item::{self, MaterialStatManifest},
item::{self, tool::AbilityMap, MaterialStatManifest},
slot::{self, Slot},
},
consts::MAX_PICKUP_RANGE,
@ -138,7 +138,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
};
// NOTE: We dup the item for message purposes.
let item_msg = item.duplicate(&state.ecs().read_resource::<MaterialStatManifest>());
let item_msg = item.duplicate(
&state.ecs().read_resource::<AbilityMap>(),
&state.ecs().read_resource::<MaterialStatManifest>(),
);
// Next, we try to equip the picked up item
let event = match inventory.try_equip(item).or_else(|returned_item| {
@ -198,8 +201,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
if let Some(item) = comp::Item::try_reclaim_from_block(block) {
// NOTE: We dup the item for message purposes.
let item_msg =
item.duplicate(&state.ecs().read_resource::<MaterialStatManifest>());
let item_msg = item.duplicate(
&state.ecs().read_resource::<AbilityMap>(),
&state.ecs().read_resource::<MaterialStatManifest>(),
);
let (event, item_was_added) = match inventory.push(item) {
Ok(_) => (
Some(comp::InventoryUpdate::new(
@ -276,6 +281,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
Some(comp::InventoryUpdateEvent::Used)
} else if let Some(item) = inventory.take(
slot,
&state.ecs().read_resource::<AbilityMap>(),
&state.ecs().read_resource::<item::MaterialStatManifest>(),
) {
match item.kind() {
@ -476,6 +482,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.expect("We know entity exists since we got its inventory.");
},
comp::InventoryManip::SplitSwap(slot, target) => {
let ability_map = state.ecs().read_resource::<AbilityMap>();
let msm = state.ecs().read_resource::<MaterialStatManifest>();
// If both slots have items and we're attemping to split from one stack
@ -495,7 +502,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
}
let item = match slot {
Slot::Inventory(slot) => inventory.take_half(slot, &msm),
Slot::Inventory(slot) => inventory.take_half(slot, &ability_map, &msm),
Slot::Equip(_) => None,
};
@ -546,9 +553,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
drop(inventories);
},
comp::InventoryManip::SplitDrop(slot) => {
let ability_map = &state.ecs().read_resource::<AbilityMap>();
let msm = state.ecs().read_resource::<MaterialStatManifest>();
let item = match slot {
Slot::Inventory(slot) => inventory.take_half(slot, &msm),
Slot::Inventory(slot) => inventory.take_half(slot, &ability_map, &msm),
Slot::Equip(_) => None,
};
@ -615,6 +623,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.and_then(|r| {
r.perform(
&mut inventory,
&state.ecs().read_resource::<AbilityMap>(),
&state.ecs().read_resource::<item::MaterialStatManifest>(),
)
.ok()
@ -631,6 +640,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
// Drop the item if there wasn't enough space
if let Some(Some((item, amount))) = craft_result {
let ability_map = &state.ecs().read_resource::<AbilityMap>();
let msm = state.ecs().read_resource::<MaterialStatManifest>();
for _ in 0..amount {
dropped_items.push((
@ -640,7 +650,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
state
.read_component_copied::<comp::Ori>(entity)
.unwrap_or_default(),
item.duplicate(&msm),
item.duplicate(ability_map, &msm),
));
}
}

View File

@ -2,7 +2,10 @@ use crate::Server;
use common::{
comp::{
agent::{Agent, AgentEvent},
inventory::{item::MaterialStatManifest, Inventory},
inventory::{
item::{tool::AbilityMap, MaterialStatManifest},
Inventory,
},
},
trade::{PendingTrade, ReducedInventory, TradeAction, TradeId, TradeResult, Trades},
};
@ -251,6 +254,7 @@ fn commit_trade(ecs: &specs::World, trade: &PendingTrade) -> TradeResult {
}
}
let mut items = [Vec::new(), Vec::new()];
let ability_map = ecs.read_resource::<AbilityMap>();
let msm = ecs.read_resource::<MaterialStatManifest>();
for who in [0, 1].iter().cloned() {
for (slot, quantity) in trade.offers[who].iter() {
@ -259,7 +263,7 @@ fn commit_trade(ecs: &specs::World, trade: &PendingTrade) -> TradeResult {
inventories
.get_mut(entities[who])
.expect(invmsg)
.take(*slot, &msm)
.take(*slot, &ability_map, &msm)
.map(|item| items[who].push(item));
}
}

View File

@ -222,7 +222,7 @@ impl Server {
)?);
let ability_map = comp::item::tool::AbilityMap::<CharacterAbility>::load_expect_cloned(
"common.abilities.weapon_ability_manifest",
"common.abilities.ability_set_manifest",
);
state.ecs_mut().insert(ability_map);

View File

@ -11,7 +11,7 @@ use common::{
character::CharacterId,
comp::{
inventory::{
item::MaterialStatManifest,
item::{tool::AbilityMap, MaterialStatManifest},
loadout::{Loadout, LoadoutError},
loadout_builder::LoadoutBuilder,
slot::InvSlotId,
@ -37,6 +37,7 @@ pub struct ItemModelPair {
// server
lazy_static! {
pub static ref MATERIAL_STATS_MANIFEST: MaterialStatManifest = MaterialStatManifest::default();
pub static ref ABILITY_MAP: AbilityMap = AbilityMap::default();
}
/// Returns a vector that contains all item rows to upsert; parent is
@ -317,7 +318,7 @@ pub fn convert_inventory_from_database_items(
}
} else if let Some(&j) = item_indices.get(&db_item.parent_container_item_id) {
if let Some(Some(parent)) = inventory.slot_mut(slot(&inventory_items[j].position)?) {
parent.add_component(item, &MATERIAL_STATS_MANIFEST);
parent.add_component(item, &ABILITY_MAP, &MATERIAL_STATS_MANIFEST);
} else {
return Err(PersistenceError::ConversionError(format!(
"Parent slot {} for component {} was empty even though it occurred earlier in \
@ -373,7 +374,7 @@ pub fn convert_loadout_from_database_items(
} else if let Some(&j) = item_indices.get(&db_item.parent_container_item_id) {
loadout
.update_item_at_slot_using_persistence_key(&database_items[j].position, |parent| {
parent.add_component(item, &MATERIAL_STATS_MANIFEST);
parent.add_component(item, &ABILITY_MAP, &MATERIAL_STATS_MANIFEST);
})
.map_err(convert_error)?;
} else {

View File

@ -1536,7 +1536,8 @@ impl<'a> AgentData<'a> {
Some(ToolKind::Unique(UniqueKind::TheropodBasic)) => Tactic::Theropod,
Some(ToolKind::Unique(UniqueKind::TheropodBird)) => Tactic::Theropod,
Some(ToolKind::Unique(UniqueKind::ObjectTurret)) => Tactic::Turret,
Some(ToolKind::Unique(UniqueKind::MindflayerStaff)) => Tactic::Mindflayer,
// TODO: Figure this out
// Some(ToolKind::Unique(UniqueKind::MindflayerStaff)) => Tactic::Mindflayer,
Some(ToolKind::Unique(UniqueKind::BirdLargeBreathe)) => Tactic::BirdLargeBreathe,
Some(ToolKind::Unique(UniqueKind::BirdLargeFire)) => Tactic::BirdLargeFire,
_ => Tactic::Melee,

View File

@ -1,9 +1,9 @@
use common::{
comp::{
item::MaterialStatManifest, Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState,
Collider, Combo, Density, Energy, Group, Health, Inventory, Item, LightEmitter, Mass,
MountState, Mounting, Ori, Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky,
Vel,
item::{tool::AbilityMap, MaterialStatManifest},
Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider, Combo, Density,
Energy, Group, Health, Inventory, Item, LightEmitter, Mass, MountState, Mounting, Ori,
Player, Poise, Pos, Scale, Shockwave, SkillSet, Stats, Sticky, Vel,
},
uid::Uid,
};
@ -65,6 +65,7 @@ pub struct TrackedComps<'a> {
pub character_state: ReadStorage<'a, CharacterState>,
pub shockwave: ReadStorage<'a, Shockwave>,
pub beam_segment: ReadStorage<'a, BeamSegment>,
pub ability_map: ReadExpect<'a, AbilityMap>,
pub msm: ReadExpect<'a, MaterialStatManifest>,
}
impl<'a> TrackedComps<'a> {
@ -124,7 +125,7 @@ impl<'a> TrackedComps<'a> {
.map(|c| comps.push(c.into()));
self.item
.get(entity)
.map(|item| item.duplicate(&self.msm))
.map(|item| item.duplicate(&self.ability_map, &self.msm))
.map(|c| comps.push(c.into()));
self.scale
.get(entity)

View File

@ -2,10 +2,7 @@ use super::{
super::{vek::*, Animation},
BipedLargeSkeleton, SkeletonAttr,
};
use common::{
comp::item::{ToolKind, UniqueKind},
states::utils::StageSection,
};
use common::{comp::item::ToolKind, states::utils::StageSection};
use std::f32::consts::PI;
pub struct BeamAnimation;
@ -62,9 +59,7 @@ impl Animation for BeamAnimation {
next.hand_l.orientation = Quaternion::rotation_x(0.0);
next.hand_r.orientation = Quaternion::rotation_x(0.0);
match active_tool_kind {
Some(ToolKind::StaffSimple)
| Some(ToolKind::Sceptre)
| Some(ToolKind::Unique(UniqueKind::MindflayerStaff)) => {
Some(ToolKind::StaffSimple) | Some(ToolKind::Sceptre) | Some(ToolKind::Staff) => {
let (move1base, move2shake, _move2base, move3) = match stage_section {
Some(StageSection::Buildup) => (
(anim_time.powf(0.25)).min(1.0),

View File

@ -2,10 +2,7 @@ use super::{
super::{vek::*, Animation},
BipedLargeSkeleton, SkeletonAttr,
};
use common::{
comp::item::{ToolKind, UniqueKind},
states::utils::StageSection,
};
use common::{comp::item::ToolKind, states::utils::StageSection};
use std::f32::consts::PI;
pub struct BlinkAnimation;
@ -81,7 +78,7 @@ impl Animation for BlinkAnimation {
next.hand_r.orientation = Quaternion::rotation_x(0.0);
match active_tool_kind {
Some(ToolKind::StaffSimple) | Some(ToolKind::Unique(UniqueKind::MindflayerStaff)) => {
Some(ToolKind::StaffSimple) | Some(ToolKind::Staff) => {
next.head.orientation =
Quaternion::rotation_x(move1 * -0.3) * Quaternion::rotation_y(move1 * -0.1);
next.control_l.position = Vec3::new(-1.0, 3.0, 12.0);

View File

@ -2,10 +2,7 @@ use super::{
super::{vek::*, Animation},
BipedLargeSkeleton, SkeletonAttr,
};
use common::{
comp::item::{ToolKind, UniqueKind},
states::utils::StageSection,
};
use common::{comp::item::ToolKind, states::utils::StageSection};
use std::f32::consts::PI;
pub struct SpinMeleeAnimation;
@ -84,7 +81,7 @@ impl Animation for SpinMeleeAnimation {
next.hand_r.orientation = Quaternion::rotation_x(0.0);
match active_tool_kind {
Some(ToolKind::StaffSimple) | Some(ToolKind::Unique(UniqueKind::MindflayerStaff)) => {
Some(ToolKind::StaffSimple) | Some(ToolKind::Staff) => {
next.head.orientation = Quaternion::rotation_x(move1 * -0.3 + move2 * 0.5);
next.control_l.position = Vec3::new(
-1.0 + move1 * -10.0 + move2 * -10.0,

View File

@ -171,8 +171,7 @@ impl Animation for StunnedAnimation {
next.control.orientation =
Quaternion::rotation_x(-1.0 + short * 0.2) * Quaternion::rotation_y(-1.8);
},
Some(ToolKind::StaffSimple)
| Some(ToolKind::Unique(UniqueKind::MindflayerStaff)) => {
Some(ToolKind::StaffSimple) | Some(ToolKind::Staff) => {
next.control_l.position = Vec3::new(-1.0, 3.0, 12.0);
next.control_r.position = Vec3::new(1.0, 2.0, 2.0);

View File

@ -2,10 +2,7 @@ use super::{
super::{vek::*, Animation},
BipedLargeSkeleton, SkeletonAttr,
};
use common::{
comp::item::{ToolKind, UniqueKind},
states::utils::StageSection,
};
use common::{comp::item::ToolKind, states::utils::StageSection};
use std::f32::consts::PI;
pub struct SummonAnimation;
@ -85,7 +82,7 @@ impl Animation for SummonAnimation {
next.hand_r.orientation = Quaternion::rotation_x(0.0);
match active_tool_kind {
Some(ToolKind::StaffSimple) | Some(ToolKind::Unique(UniqueKind::MindflayerStaff)) => {
Some(ToolKind::StaffSimple) | Some(ToolKind::Staff) => {
next.head.orientation = Quaternion::rotation_x(0.0);
next.control_l.position = Vec3::new(-1.0, 3.0, 12.0);
next.control_r.position = Vec3::new(

View File

@ -210,8 +210,7 @@ impl Animation for WieldAnimation {
next.control.orientation =
Quaternion::rotation_x(-1.0 + short * 0.2) * Quaternion::rotation_y(-1.8);
},
Some(ToolKind::StaffSimple)
| Some(ToolKind::Unique(UniqueKind::MindflayerStaff)) => {
Some(ToolKind::StaffSimple) | Some(ToolKind::Staff) => {
next.control_l.position = Vec3::new(-1.0, 3.0, 12.0);
next.control_r.position = Vec3::new(1.0, 2.0, 2.0);

View File

@ -2345,7 +2345,6 @@ impl Hud {
let skillsets = ecs.read_storage::<comp::SkillSet>();
let character_states = ecs.read_storage::<comp::CharacterState>();
let controllers = ecs.read_storage::<comp::Controller>();
let ability_map = ecs.fetch::<comp::item::tool::AbilityMap>();
let bodies = ecs.read_storage::<comp::Body>();
// Combo floater stuffs
self.floaters
@ -2397,7 +2396,6 @@ impl Hud {
item_tooltip_manager,
&mut self.slot_manager,
i18n,
&ability_map,
&msm,
combo,
)

View File

@ -23,7 +23,7 @@ use common::comp::{
self,
inventory::slot::EquipSlot,
item::{
tool::{AbilityMap, Tool, ToolKind},
tool::{Tool, ToolKind},
Hands, Item, ItemKind, MaterialStatManifest,
},
Energy, Health, Inventory, SkillSet,
@ -153,7 +153,6 @@ pub struct Skillbar<'a> {
pulse: f32,
#[conrod(common_builder)]
common: widget::CommonBuilder,
ability_map: &'a AbilityMap,
msm: &'a MaterialStatManifest,
combo: Option<ComboFloater>,
}
@ -179,7 +178,6 @@ impl<'a> Skillbar<'a> {
item_tooltip_manager: &'a mut ItemTooltipManager,
slot_manager: &'a mut slots::SlotManager,
localized_strings: &'a Localization,
ability_map: &'a AbilityMap,
msm: &'a MaterialStatManifest,
combo: Option<ComboFloater>,
) -> Self {
@ -203,7 +201,6 @@ impl<'a> Skillbar<'a> {
item_tooltip_manager,
slot_manager,
localized_strings,
ability_map,
msm,
combo,
}
@ -448,14 +445,7 @@ impl<'a> Widget for Skillbar<'a> {
.set(state.ids.stamina_txt, ui);
}
// Slots
let content_source = (
self.hotbar,
self.inventory,
self.energy,
self.skillset,
self.ability_map,
self.msm,
); // TODO: avoid this
let content_source = (self.hotbar, self.inventory, self.energy, self.skillset); // TODO: avoid this
let image_source = (self.item_imgs, self.imgs);
let mut slot_maker = SlotMaker {
// TODO: is a separate image needed for the frame?
@ -740,9 +730,11 @@ impl<'a> Widget for Skillbar<'a> {
.middle_of(state.ids.m2_slot_bg)
.image_color(if let Some((item, tool)) = tool {
if self.energy.current()
>= tool
.get_abilities(&self.msm, item.components(), self.ability_map)
>= item
.item_config_expect()
.abilities
.secondary
.clone()
.adjusted_by_skills(self.skillset, Some(tool.kind))
.get_energy_cost()
{

View File

@ -6,8 +6,8 @@ use super::{
use crate::ui::slot::{self, SlotKey, SumSlot};
use common::comp::{
item::{
tool::{AbilityMap, Hands, ToolKind},
ItemKind, MaterialStatManifest,
tool::{Hands, ToolKind},
ItemKind,
},
slot::InvSlotId,
Energy, Inventory, SkillSet,
@ -122,14 +122,7 @@ pub enum HotbarImage {
SceptreAura,
}
type HotbarSource<'a> = (
&'a hotbar::State,
&'a Inventory,
&'a Energy,
&'a SkillSet,
&'a AbilityMap,
&'a MaterialStatManifest,
);
type HotbarSource<'a> = (&'a hotbar::State, &'a Inventory, &'a Energy, &'a SkillSet);
type HotbarImageSource<'a> = (&'a ItemImgs, &'a img_ids::Imgs);
impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
@ -137,7 +130,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
fn image_key(
&self,
(hotbar, inventory, energy, skillset, ability_map, msm): &HotbarSource<'a>,
(hotbar, inventory, energy, skillset): &HotbarSource<'a>,
) -> Option<(Self::ImageKey, Option<Color>)> {
hotbar.get(*self).and_then(|contents| match contents {
hotbar::SlotContents::Inventory(idx) => inventory
@ -169,10 +162,8 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
hotbar_image(tool.kind).map(|i| {
(
i,
if let Some(skill) = tool
.get_abilities(&msm, item.components(), ability_map)
.abilities
.get(0)
if let Some(skill) =
item.item_config_expect().abilities.abilities.get(0)
{
if energy.current()
>= skill
@ -219,8 +210,9 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
hotbar_image(tool.kind).map(|i| {
(
i,
if let Some(skill) = tool
.get_abilities(&msm, item.components(), ability_map)
if let Some(skill) = item
.item_config_expect()
.abilities
.abilities
.get(skill_index)
{
@ -245,7 +237,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
})
}
fn amount(&self, (hotbar, inventory, _, _, _, _): &HotbarSource<'a>) -> Option<u32> {
fn amount(&self, (hotbar, inventory, _, _): &HotbarSource<'a>) -> Option<u32> {
hotbar
.get(*self)
.and_then(|content| match content {