From 8bdbf4f7c964826a060372ea0367f4ab5e2564c6 Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Tue, 16 Feb 2021 23:23:08 -0500 Subject: [PATCH 1/2] Implement modular weapons. - Add ItemKind::ModularComponent, Item::components. - Add tool::StatKind::{Direct,Modular} for the modular weapons themselves. - Move ItemConfig from ItemDesc to Item, so components' stats can be taken into account. - Crafting stores into the components field. - Components/recipes/placeholders are created dynamically. - Show which components a modular weapon contains in the tooltip in voxygen. Squashed fixes: - `Item::duplicate` components in `Item::new_from_item_def`. - Speed of 1.0 for now. --- assets/common/items/debug/admin_stick.ron | 4 +- assets/common/items/debug/admin_sword.ron | 4 +- assets/common/items/debug/possess.ron | 4 +- .../items/npc_weapons/bow/saurok_bow.ron | 4 +- .../npc_weapons/hammer/cyclops_hammer.ron | 4 +- .../items/npc_weapons/hammer/ogre_hammer.ron | 4 +- .../items/npc_weapons/hammer/troll_hammer.ron | 4 +- .../npc_weapons/hammer/wendigo_hammer.ron | 4 +- .../npc_weapons/staff/mindflayer_staff.ron | 4 +- .../items/npc_weapons/staff/ogre_staff.ron | 4 +- .../items/npc_weapons/staff/saurok_staff.ron | 4 +- .../npc_weapons/sword/dullahan_sword.ron | 4 +- .../items/npc_weapons/sword/saurok_sword.ron | 4 +- .../items/npc_weapons/unique/beast_claws.ron | 4 +- .../items/npc_weapons/unique/quadlowbasic.ron | 4 +- .../npc_weapons/unique/quadlowbreathe.ron | 4 +- .../items/npc_weapons/unique/quadlowquick.ron | 4 +- .../npc_weapons/unique/quadlowranged.ron | 4 +- .../items/npc_weapons/unique/quadlowtail.ron | 4 +- .../items/npc_weapons/unique/quadmedbasic.ron | 4 +- .../npc_weapons/unique/quadmedcharge.ron | 4 +- .../items/npc_weapons/unique/quadmedhoof.ron | 4 +- .../items/npc_weapons/unique/quadmedjump.ron | 4 +- .../items/npc_weapons/unique/quadmedquick.ron | 4 +- .../npc_weapons/unique/quadsmallbasic.ron | 4 +- .../npc_weapons/unique/stone_golems_fist.ron | 4 +- .../npc_weapons/unique/theropodbasic.ron | 4 +- .../items/npc_weapons/unique/theropodbird.ron | 4 +- .../items/weapons/axe/bloodsteel_axe-0.ron | 4 +- .../items/weapons/axe/bloodsteel_axe-1.ron | 4 +- .../items/weapons/axe/bloodsteel_axe-2.ron | 4 +- .../common/items/weapons/axe/bronze_axe-0.ron | 4 +- .../common/items/weapons/axe/bronze_axe-1.ron | 4 +- .../common/items/weapons/axe/cobalt_axe-0.ron | 4 +- .../common/items/weapons/axe/iron_axe-0.ron | 4 +- .../common/items/weapons/axe/iron_axe-1.ron | 4 +- .../common/items/weapons/axe/iron_axe-2.ron | 4 +- .../common/items/weapons/axe/iron_axe-3.ron | 4 +- .../common/items/weapons/axe/iron_axe-4.ron | 4 +- .../common/items/weapons/axe/iron_axe-5.ron | 4 +- .../common/items/weapons/axe/iron_axe-6.ron | 4 +- .../common/items/weapons/axe/iron_axe-7.ron | 4 +- .../common/items/weapons/axe/iron_axe-8.ron | 4 +- .../common/items/weapons/axe/iron_axe-9.ron | 4 +- .../items/weapons/axe/malachite_axe-0.ron | 4 +- assets/common/items/weapons/axe/orc_axe-0.ron | 4 +- .../common/items/weapons/axe/starter_axe.ron | 4 +- .../common/items/weapons/axe/steel_axe-0.ron | 4 +- .../common/items/weapons/axe/steel_axe-1.ron | 4 +- .../common/items/weapons/axe/steel_axe-2.ron | 4 +- .../common/items/weapons/axe/steel_axe-3.ron | 4 +- .../common/items/weapons/axe/steel_axe-4.ron | 4 +- .../common/items/weapons/axe/steel_axe-5.ron | 4 +- .../common/items/weapons/axe/steel_axe-6.ron | 4 +- .../items/weapons/axe/worn_iron_axe-0.ron | 4 +- .../items/weapons/axe/worn_iron_axe-1.ron | 4 +- .../items/weapons/axe/worn_iron_axe-2.ron | 4 +- .../items/weapons/axe/worn_iron_axe-3.ron | 4 +- .../items/weapons/axe/worn_iron_axe-4.ron | 4 +- .../items/weapons/bow/horn_longbow-0.ron | 4 +- .../items/weapons/bow/iron_longbow-0.ron | 4 +- .../items/weapons/bow/leafy_longbow-0.ron | 4 +- .../items/weapons/bow/leafy_shortbow-0.ron | 4 +- .../weapons/bow/nature_ore_longbow-0.ron | 4 +- .../common/items/weapons/bow/rare_longbow.ron | 4 +- .../common/items/weapons/bow/starter_bow.ron | 4 +- .../items/weapons/bow/wood_longbow-0.ron | 4 +- .../items/weapons/bow/wood_longbow-1.ron | 4 +- .../items/weapons/bow/wood_shortbow-0.ron | 4 +- .../items/weapons/bow/wood_shortbow-1.ron | 4 +- .../common/items/weapons/dagger/basic_0.ron | 4 +- .../common/items/weapons/dagger/cultist_0.ron | 4 +- .../items/weapons/dagger/starter_dagger.ron | 4 +- assets/common/items/weapons/empty/empty.ron | 4 +- .../items/weapons/hammer/bronze_hammer-0.ron | 4 +- .../items/weapons/hammer/bronze_hammer-1.ron | 4 +- .../items/weapons/hammer/cobalt_hammer-0.ron | 4 +- .../items/weapons/hammer/cobalt_hammer-1.ron | 4 +- .../weapons/hammer/cultist_purp_2h-0.ron | 4 +- .../items/weapons/hammer/flimsy_hammer.ron | 4 +- .../common/items/weapons/hammer/hammer_1.ron | 4 +- .../items/weapons/hammer/iron_hammer-0.ron | 4 +- .../items/weapons/hammer/iron_hammer-1.ron | 4 +- .../items/weapons/hammer/iron_hammer-2.ron | 4 +- .../items/weapons/hammer/iron_hammer-3.ron | 4 +- .../items/weapons/hammer/iron_hammer-4.ron | 4 +- .../items/weapons/hammer/iron_hammer-5.ron | 4 +- .../items/weapons/hammer/iron_hammer-6.ron | 4 +- .../items/weapons/hammer/iron_hammer-7.ron | 4 +- .../items/weapons/hammer/iron_hammer-8.ron | 4 +- .../common/items/weapons/hammer/mjolnir.ron | 4 +- .../items/weapons/hammer/ramshead_hammer.ron | 4 +- .../items/weapons/hammer/runic_hammer.ron | 4 +- .../items/weapons/hammer/starter_hammer.ron | 4 +- .../items/weapons/hammer/steel_hammer-0.ron | 4 +- .../items/weapons/hammer/steel_hammer-1.ron | 4 +- .../items/weapons/hammer/steel_hammer-2.ron | 4 +- .../items/weapons/hammer/steel_hammer-3.ron | 4 +- .../items/weapons/hammer/steel_hammer-4.ron | 4 +- .../items/weapons/hammer/steel_hammer-5.ron | 4 +- .../items/weapons/hammer/stone_hammer-0.ron | 4 +- .../items/weapons/hammer/stone_hammer-1.ron | 4 +- .../items/weapons/hammer/stone_hammer-2.ron | 4 +- .../items/weapons/hammer/stone_hammer-3.ron | 4 +- .../items/weapons/hammer/wood_hammer-0.ron | 4 +- .../weapons/hammer/worn_iron_hammer-0.ron | 4 +- .../weapons/hammer/worn_iron_hammer-1.ron | 4 +- .../weapons/hammer/worn_iron_hammer-2.ron | 4 +- .../weapons/hammer/worn_iron_hammer-3.ron | 4 +- assets/common/items/weapons/sceptre/fork0.ron | 4 +- .../common/items/weapons/sceptre/loops0.ron | 4 +- assets/common/items/weapons/sceptre/moon0.ron | 4 +- .../items/weapons/sceptre/root_evil.ron | 4 +- .../items/weapons/sceptre/root_green0.ron | 4 +- .../weapons/sceptre/sceptre_velorite_0.ron | 4 +- .../items/weapons/sceptre/staff_nature.ron | 4 +- .../items/weapons/sceptre/starter_sceptre.ron | 4 +- .../items/weapons/sceptre/totem_green.ron | 4 +- .../common/items/weapons/shield/shield_1.ron | 4 +- .../items/weapons/staff/amethyst_staff.ron | 4 +- .../common/items/weapons/staff/bone_staff.ron | 4 +- .../items/weapons/staff/cultist_staff.ron | 4 +- assets/common/items/weapons/staff/staff_1.ron | 4 +- .../items/weapons/staff/starter_staff.ron | 4 +- .../items/weapons/sword/cultist_purp_2h-0.ron | 4 +- .../weapons/sword/frost_cleaver_2h-0.ron | 4 +- .../weapons/sword/frost_cleaver_2h-1.ron | 4 +- .../weapons/sword/greatsword_2h_dam-0.ron | 4 +- .../weapons/sword/greatsword_2h_dam-1.ron | 4 +- .../weapons/sword/greatsword_2h_dam-2.ron | 4 +- .../weapons/sword/greatsword_2h_fine-0.ron | 4 +- .../weapons/sword/greatsword_2h_fine-1.ron | 4 +- .../weapons/sword/greatsword_2h_fine-2.ron | 4 +- .../weapons/sword/greatsword_2h_orn-0.ron | 4 +- .../weapons/sword/greatsword_2h_orn-1.ron | 4 +- .../weapons/sword/greatsword_2h_orn-2.ron | 4 +- .../weapons/sword/greatsword_2h_simple-0.ron | 4 +- .../weapons/sword/greatsword_2h_simple-1.ron | 4 +- .../weapons/sword/greatsword_2h_simple-2.ron | 4 +- .../items/weapons/sword/long_2h_dam-0.ron | 4 +- .../items/weapons/sword/long_2h_dam-1.ron | 4 +- .../items/weapons/sword/long_2h_dam-2.ron | 4 +- .../items/weapons/sword/long_2h_dam-3.ron | 4 +- .../items/weapons/sword/long_2h_dam-4.ron | 4 +- .../items/weapons/sword/long_2h_dam-5.ron | 4 +- .../items/weapons/sword/long_2h_fine-0.ron | 4 +- .../items/weapons/sword/long_2h_fine-1.ron | 4 +- .../items/weapons/sword/long_2h_fine-2.ron | 4 +- .../items/weapons/sword/long_2h_fine-3.ron | 4 +- .../items/weapons/sword/long_2h_fine-4.ron | 4 +- .../items/weapons/sword/long_2h_fine-5.ron | 4 +- .../items/weapons/sword/long_2h_orn-0.ron | 4 +- .../items/weapons/sword/long_2h_orn-1.ron | 4 +- .../items/weapons/sword/long_2h_orn-2.ron | 4 +- .../items/weapons/sword/long_2h_orn-3.ron | 4 +- .../items/weapons/sword/long_2h_orn-4.ron | 4 +- .../items/weapons/sword/long_2h_orn-5.ron | 4 +- .../items/weapons/sword/long_2h_simple-0.ron | 4 +- .../items/weapons/sword/long_2h_simple-1.ron | 4 +- .../items/weapons/sword/long_2h_simple-2.ron | 4 +- .../items/weapons/sword/long_2h_simple-3.ron | 4 +- .../items/weapons/sword/long_2h_simple-4.ron | 4 +- .../items/weapons/sword/long_2h_simple-5.ron | 4 +- .../items/weapons/sword/short_sword_0.ron | 4 +- .../items/weapons/sword/starter_sword.ron | 4 +- .../common/items/weapons/sword/wood_sword.ron | 4 +- .../weapons/sword/zweihander_sword_0.ron | 4 +- assets/common/items/weapons/tool/broom.ron | 4 +- .../common/items/weapons/tool/fishing_rod.ron | 4 +- assets/common/items/weapons/tool/hoe.ron | 4 +- assets/common/items/weapons/tool/pickaxe.ron | 4 +- .../common/items/weapons/tool/pitchfork.ron | 4 +- assets/common/items/weapons/tool/rake.ron | 4 +- assets/common/items/weapons/tool/shovel-0.ron | 4 +- assets/common/items/weapons/tool/shovel-1.ron | 4 +- common/src/combat.rs | 32 +- common/src/comp/inventory/item/mod.rs | 118 +++++-- common/src/comp/inventory/item/modular.rs | 306 ++++++++++++++++++ common/src/comp/inventory/item/tool.rs | 128 ++++++-- common/src/comp/inventory/test_helpers.rs | 7 +- common/src/recipe.rs | 18 +- common/src/states/utils.rs | 6 +- voxygen/src/hud/crafting.rs | 2 +- voxygen/src/hud/item_imgs.rs | 4 + voxygen/src/hud/skillbar.rs | 28 +- voxygen/src/hud/slots.rs | 33 +- voxygen/src/hud/util.rs | 66 ++-- 187 files changed, 959 insertions(+), 489 deletions(-) create mode 100644 common/src/comp/inventory/item/modular.rs diff --git a/assets/common/items/debug/admin_stick.ron b/assets/common/items/debug/admin_stick.ron index f74a1affb4..dc8f57c976 100644 --- a/assets/common/items/debug/admin_stick.ron +++ b/assets/common/items/debug/admin_stick.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Debug, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 0, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Debug, diff --git a/assets/common/items/debug/admin_sword.ron b/assets/common/items/debug/admin_sword.ron index 4b4c3ce2e9..0d59c59107 100644 --- a/assets/common/items/debug/admin_sword.ron +++ b/assets/common/items/debug/admin_sword.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 0, power: 1000.0, poise_strength: 1000.0, speed: 1.0 - ), + )), ) ), quality: Debug, diff --git a/assets/common/items/debug/possess.ron b/assets/common/items/debug/possess.ron index 8e8c101fb3..2b0427e60c 100644 --- a/assets/common/items/debug/possess.ron +++ b/assets/common/items/debug/possess.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool( ( kind: Debug, - stats: ( + stats: Direct(( equip_time_millis: 0, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Debug, diff --git a/assets/common/items/npc_weapons/bow/saurok_bow.ron b/assets/common/items/npc_weapons/bow/saurok_bow.ron index 9ada115ab9..8b52c2891c 100644 --- a/assets/common/items/npc_weapons/bow/saurok_bow.ron +++ b/assets/common/items/npc_weapons/bow/saurok_bow.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/hammer/cyclops_hammer.ron b/assets/common/items/npc_weapons/hammer/cyclops_hammer.ron index e6b31337a2..b128b795a7 100644 --- a/assets/common/items/npc_weapons/hammer/cyclops_hammer.ron +++ b/assets/common/items/npc_weapons/hammer/cyclops_hammer.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/hammer/ogre_hammer.ron b/assets/common/items/npc_weapons/hammer/ogre_hammer.ron index a21f130741..e6ff3fbc50 100644 --- a/assets/common/items/npc_weapons/hammer/ogre_hammer.ron +++ b/assets/common/items/npc_weapons/hammer/ogre_hammer.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/hammer/troll_hammer.ron b/assets/common/items/npc_weapons/hammer/troll_hammer.ron index 3c02d6ac09..bd0cdc0598 100644 --- a/assets/common/items/npc_weapons/hammer/troll_hammer.ron +++ b/assets/common/items/npc_weapons/hammer/troll_hammer.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/hammer/wendigo_hammer.ron b/assets/common/items/npc_weapons/hammer/wendigo_hammer.ron index 29bcedb2db..4078c0db3d 100644 --- a/assets/common/items/npc_weapons/hammer/wendigo_hammer.ron +++ b/assets/common/items/npc_weapons/hammer/wendigo_hammer.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/staff/mindflayer_staff.ron b/assets/common/items/npc_weapons/staff/mindflayer_staff.ron index b2d6edebde..24c5ff3980 100644 --- a/assets/common/items/npc_weapons/staff/mindflayer_staff.ron +++ b/assets/common/items/npc_weapons/staff/mindflayer_staff.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Staff, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 300, power: 3.0, poise_strength: 1.00, speed: 1.5, - ), + )), ) ), quality: Legendary, diff --git a/assets/common/items/npc_weapons/staff/ogre_staff.ron b/assets/common/items/npc_weapons/staff/ogre_staff.ron index ad1d611cfa..e4fa9b5e55 100644 --- a/assets/common/items/npc_weapons/staff/ogre_staff.ron +++ b/assets/common/items/npc_weapons/staff/ogre_staff.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Staff, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/staff/saurok_staff.ron b/assets/common/items/npc_weapons/staff/saurok_staff.ron index e38a3df78c..be87572e33 100644 --- a/assets/common/items/npc_weapons/staff/saurok_staff.ron +++ b/assets/common/items/npc_weapons/staff/saurok_staff.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Staff, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/sword/dullahan_sword.ron b/assets/common/items/npc_weapons/sword/dullahan_sword.ron index 42183d263b..a879869db7 100644 --- a/assets/common/items/npc_weapons/sword/dullahan_sword.ron +++ b/assets/common/items/npc_weapons/sword/dullahan_sword.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/sword/saurok_sword.ron b/assets/common/items/npc_weapons/sword/saurok_sword.ron index 82fd5efcc7..3d22dd8f9b 100644 --- a/assets/common/items/npc_weapons/sword/saurok_sword.ron +++ b/assets/common/items/npc_weapons/sword/saurok_sword.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/beast_claws.ron b/assets/common/items/npc_weapons/unique/beast_claws.ron index 3ca1a633af..3b2ca645d4 100644 --- a/assets/common/items/npc_weapons/unique/beast_claws.ron +++ b/assets/common/items/npc_weapons/unique/beast_claws.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(BeastClaws), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadlowbasic.ron b/assets/common/items/npc_weapons/unique/quadlowbasic.ron index 9bdfebcbfc..0ab936cb0d 100644 --- a/assets/common/items/npc_weapons/unique/quadlowbasic.ron +++ b/assets/common/items/npc_weapons/unique/quadlowbasic.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadLowBasic), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadlowbreathe.ron b/assets/common/items/npc_weapons/unique/quadlowbreathe.ron index 1c931dab3b..bbaedc1882 100644 --- a/assets/common/items/npc_weapons/unique/quadlowbreathe.ron +++ b/assets/common/items/npc_weapons/unique/quadlowbreathe.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadLowBreathe), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadlowquick.ron b/assets/common/items/npc_weapons/unique/quadlowquick.ron index 7b4adbd6d1..f9b6c922c9 100644 --- a/assets/common/items/npc_weapons/unique/quadlowquick.ron +++ b/assets/common/items/npc_weapons/unique/quadlowquick.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadLowQuick), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadlowranged.ron b/assets/common/items/npc_weapons/unique/quadlowranged.ron index 137bd49ae8..b4a03cf800 100644 --- a/assets/common/items/npc_weapons/unique/quadlowranged.ron +++ b/assets/common/items/npc_weapons/unique/quadlowranged.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadLowRanged), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadlowtail.ron b/assets/common/items/npc_weapons/unique/quadlowtail.ron index cbb22e5ab5..66c3b04260 100644 --- a/assets/common/items/npc_weapons/unique/quadlowtail.ron +++ b/assets/common/items/npc_weapons/unique/quadlowtail.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadLowTail), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadmedbasic.ron b/assets/common/items/npc_weapons/unique/quadmedbasic.ron index fc9de7cbe8..685acf28c7 100644 --- a/assets/common/items/npc_weapons/unique/quadmedbasic.ron +++ b/assets/common/items/npc_weapons/unique/quadmedbasic.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadMedBasic), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadmedcharge.ron b/assets/common/items/npc_weapons/unique/quadmedcharge.ron index 1527fddf63..d5a2cdc78b 100644 --- a/assets/common/items/npc_weapons/unique/quadmedcharge.ron +++ b/assets/common/items/npc_weapons/unique/quadmedcharge.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadMedCharge), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadmedhoof.ron b/assets/common/items/npc_weapons/unique/quadmedhoof.ron index 3a40927bd1..0317efe916 100644 --- a/assets/common/items/npc_weapons/unique/quadmedhoof.ron +++ b/assets/common/items/npc_weapons/unique/quadmedhoof.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadMedHoof), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadmedjump.ron b/assets/common/items/npc_weapons/unique/quadmedjump.ron index 6ebf329afa..e3d4fa0c8f 100644 --- a/assets/common/items/npc_weapons/unique/quadmedjump.ron +++ b/assets/common/items/npc_weapons/unique/quadmedjump.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadMedJump), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.0, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadmedquick.ron b/assets/common/items/npc_weapons/unique/quadmedquick.ron index 083baa1664..22feaa6aa8 100644 --- a/assets/common/items/npc_weapons/unique/quadmedquick.ron +++ b/assets/common/items/npc_weapons/unique/quadmedquick.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadMedQuick), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.0, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/quadsmallbasic.ron b/assets/common/items/npc_weapons/unique/quadsmallbasic.ron index 3a85b22377..336ed47645 100644 --- a/assets/common/items/npc_weapons/unique/quadsmallbasic.ron +++ b/assets/common/items/npc_weapons/unique/quadsmallbasic.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(QuadSmallBasic), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/stone_golems_fist.ron b/assets/common/items/npc_weapons/unique/stone_golems_fist.ron index 7302e61b0b..6b75281246 100644 --- a/assets/common/items/npc_weapons/unique/stone_golems_fist.ron +++ b/assets/common/items/npc_weapons/unique/stone_golems_fist.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(StoneGolemFist), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.00, poise_strength: 1.00, speed: 1.0 - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/theropodbasic.ron b/assets/common/items/npc_weapons/unique/theropodbasic.ron index 352a99734c..fcfaea939c 100644 --- a/assets/common/items/npc_weapons/unique/theropodbasic.ron +++ b/assets/common/items/npc_weapons/unique/theropodbasic.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(TheropodBasic), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/npc_weapons/unique/theropodbird.ron b/assets/common/items/npc_weapons/unique/theropodbird.ron index f2be3234e2..205b916b54 100644 --- a/assets/common/items/npc_weapons/unique/theropodbird.ron +++ b/assets/common/items/npc_weapons/unique/theropodbird.ron @@ -5,12 +5,12 @@ ItemDef( ( kind: Unique(TheropodBird), hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 10, power: 1.00, poise_strength: 1.00, speed: 1.00, - ), + )), ) ), quality: Low, diff --git a/assets/common/items/weapons/axe/bloodsteel_axe-0.ron b/assets/common/items/weapons/axe/bloodsteel_axe-0.ron index 045677ae3f..ae77701cc3 100644 --- a/assets/common/items/weapons/axe/bloodsteel_axe-0.ron +++ b/assets/common/items/weapons/axe/bloodsteel_axe-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.6, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: High, tags: [], diff --git a/assets/common/items/weapons/axe/bloodsteel_axe-1.ron b/assets/common/items/weapons/axe/bloodsteel_axe-1.ron index 7019bbee07..06163034c5 100644 --- a/assets/common/items/weapons/axe/bloodsteel_axe-1.ron +++ b/assets/common/items/weapons/axe/bloodsteel_axe-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.6, poise_strength: 1.8, speed: 1.0, - ), + )), )), quality: High, tags: [], diff --git a/assets/common/items/weapons/axe/bloodsteel_axe-2.ron b/assets/common/items/weapons/axe/bloodsteel_axe-2.ron index dc80a82fd2..563e000679 100644 --- a/assets/common/items/weapons/axe/bloodsteel_axe-2.ron +++ b/assets/common/items/weapons/axe/bloodsteel_axe-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.6, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: High, tags: [], diff --git a/assets/common/items/weapons/axe/bronze_axe-0.ron b/assets/common/items/weapons/axe/bronze_axe-0.ron index f4c85f5776..5a013aa046 100644 --- a/assets/common/items/weapons/axe/bronze_axe-0.ron +++ b/assets/common/items/weapons/axe/bronze_axe-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 0.9, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/bronze_axe-1.ron b/assets/common/items/weapons/axe/bronze_axe-1.ron index 3dc4648c32..551d6ebcc0 100644 --- a/assets/common/items/weapons/axe/bronze_axe-1.ron +++ b/assets/common/items/weapons/axe/bronze_axe-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/cobalt_axe-0.ron b/assets/common/items/weapons/axe/cobalt_axe-0.ron index 170f1e45cb..c50fb8d418 100644 --- a/assets/common/items/weapons/axe/cobalt_axe-0.ron +++ b/assets/common/items/weapons/axe/cobalt_axe-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.8, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: High, tags: [], diff --git a/assets/common/items/weapons/axe/iron_axe-0.ron b/assets/common/items/weapons/axe/iron_axe-0.ron index 73bfd8f1d6..d9911dc030 100644 --- a/assets/common/items/weapons/axe/iron_axe-0.ron +++ b/assets/common/items/weapons/axe/iron_axe-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 1.7, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/iron_axe-1.ron b/assets/common/items/weapons/axe/iron_axe-1.ron index d3cee4dd0a..4aca7f736e 100644 --- a/assets/common/items/weapons/axe/iron_axe-1.ron +++ b/assets/common/items/weapons/axe/iron_axe-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/iron_axe-2.ron b/assets/common/items/weapons/axe/iron_axe-2.ron index 9bdeebaad5..383782454a 100644 --- a/assets/common/items/weapons/axe/iron_axe-2.ron +++ b/assets/common/items/weapons/axe/iron_axe-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/iron_axe-3.ron b/assets/common/items/weapons/axe/iron_axe-3.ron index df2f42319b..1406ad3e9f 100644 --- a/assets/common/items/weapons/axe/iron_axe-3.ron +++ b/assets/common/items/weapons/axe/iron_axe-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 1.6, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/iron_axe-4.ron b/assets/common/items/weapons/axe/iron_axe-4.ron index 64dd21a82a..c46fdae2fa 100644 --- a/assets/common/items/weapons/axe/iron_axe-4.ron +++ b/assets/common/items/weapons/axe/iron_axe-4.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/iron_axe-5.ron b/assets/common/items/weapons/axe/iron_axe-5.ron index 5d666dd2fe..00379b0a61 100644 --- a/assets/common/items/weapons/axe/iron_axe-5.ron +++ b/assets/common/items/weapons/axe/iron_axe-5.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 1.8, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/iron_axe-6.ron b/assets/common/items/weapons/axe/iron_axe-6.ron index 9521085760..219ce1b923 100644 --- a/assets/common/items/weapons/axe/iron_axe-6.ron +++ b/assets/common/items/weapons/axe/iron_axe-6.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 1.3, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/iron_axe-7.ron b/assets/common/items/weapons/axe/iron_axe-7.ron index d580e411aa..31b889c726 100644 --- a/assets/common/items/weapons/axe/iron_axe-7.ron +++ b/assets/common/items/weapons/axe/iron_axe-7.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 1.6, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/iron_axe-8.ron b/assets/common/items/weapons/axe/iron_axe-8.ron index 830608dcc8..cbaad7165b 100644 --- a/assets/common/items/weapons/axe/iron_axe-8.ron +++ b/assets/common/items/weapons/axe/iron_axe-8.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 0.6, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/iron_axe-9.ron b/assets/common/items/weapons/axe/iron_axe-9.ron index a903851ba4..c65a01804c 100644 --- a/assets/common/items/weapons/axe/iron_axe-9.ron +++ b/assets/common/items/weapons/axe/iron_axe-9.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 0.3, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/malachite_axe-0.ron b/assets/common/items/weapons/axe/malachite_axe-0.ron index acd69ae2a6..bc08b5d4c0 100644 --- a/assets/common/items/weapons/axe/malachite_axe-0.ron +++ b/assets/common/items/weapons/axe/malachite_axe-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 2.0, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Epic, tags: [], diff --git a/assets/common/items/weapons/axe/orc_axe-0.ron b/assets/common/items/weapons/axe/orc_axe-0.ron index 279b0ad6da..ebef7c0bb9 100644 --- a/assets/common/items/weapons/axe/orc_axe-0.ron +++ b/assets/common/items/weapons/axe/orc_axe-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.6, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/axe/starter_axe.ron b/assets/common/items/weapons/axe/starter_axe.ron index b38ce04023..7adeb6c8f3 100644 --- a/assets/common/items/weapons/axe/starter_axe.ron +++ b/assets/common/items/weapons/axe/starter_axe.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.5, poise_strength: 2.0, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/axe/steel_axe-0.ron b/assets/common/items/weapons/axe/steel_axe-0.ron index 533acd3779..baa203d0cb 100644 --- a/assets/common/items/weapons/axe/steel_axe-0.ron +++ b/assets/common/items/weapons/axe/steel_axe-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.4, poise_strength: 1.2, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/steel_axe-1.ron b/assets/common/items/weapons/axe/steel_axe-1.ron index 566e655988..d5f009e54f 100644 --- a/assets/common/items/weapons/axe/steel_axe-1.ron +++ b/assets/common/items/weapons/axe/steel_axe-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.4, poise_strength: 1.2, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/steel_axe-2.ron b/assets/common/items/weapons/axe/steel_axe-2.ron index 96886e9a31..3d4ab8a1ad 100644 --- a/assets/common/items/weapons/axe/steel_axe-2.ron +++ b/assets/common/items/weapons/axe/steel_axe-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.4, poise_strength: 1.2, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/steel_axe-3.ron b/assets/common/items/weapons/axe/steel_axe-3.ron index 63624c94c1..6ff278dfbe 100644 --- a/assets/common/items/weapons/axe/steel_axe-3.ron +++ b/assets/common/items/weapons/axe/steel_axe-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.4, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/steel_axe-4.ron b/assets/common/items/weapons/axe/steel_axe-4.ron index 7bc4fc94c3..090cb5e936 100644 --- a/assets/common/items/weapons/axe/steel_axe-4.ron +++ b/assets/common/items/weapons/axe/steel_axe-4.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.4, poise_strength: 1.2, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/steel_axe-5.ron b/assets/common/items/weapons/axe/steel_axe-5.ron index aa61348583..3e6fb5d55e 100644 --- a/assets/common/items/weapons/axe/steel_axe-5.ron +++ b/assets/common/items/weapons/axe/steel_axe-5.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.4, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/steel_axe-6.ron b/assets/common/items/weapons/axe/steel_axe-6.ron index 106ca98b9c..e07fe8da15 100644 --- a/assets/common/items/weapons/axe/steel_axe-6.ron +++ b/assets/common/items/weapons/axe/steel_axe-6.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.4, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/axe/worn_iron_axe-0.ron b/assets/common/items/weapons/axe/worn_iron_axe-0.ron index 5903909611..141a072b26 100644 --- a/assets/common/items/weapons/axe/worn_iron_axe-0.ron +++ b/assets/common/items/weapons/axe/worn_iron_axe-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.8, poise_strength: 0.4, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/axe/worn_iron_axe-1.ron b/assets/common/items/weapons/axe/worn_iron_axe-1.ron index 6272d2ffec..49a1011180 100644 --- a/assets/common/items/weapons/axe/worn_iron_axe-1.ron +++ b/assets/common/items/weapons/axe/worn_iron_axe-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.8, poise_strength: 0.4, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/axe/worn_iron_axe-2.ron b/assets/common/items/weapons/axe/worn_iron_axe-2.ron index de359ef66f..e29a215ce9 100644 --- a/assets/common/items/weapons/axe/worn_iron_axe-2.ron +++ b/assets/common/items/weapons/axe/worn_iron_axe-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.8, poise_strength: 0.7, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/axe/worn_iron_axe-3.ron b/assets/common/items/weapons/axe/worn_iron_axe-3.ron index ff2bc2a145..839a008de9 100644 --- a/assets/common/items/weapons/axe/worn_iron_axe-3.ron +++ b/assets/common/items/weapons/axe/worn_iron_axe-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.8, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/axe/worn_iron_axe-4.ron b/assets/common/items/weapons/axe/worn_iron_axe-4.ron index bce871c0dc..fbc053bc68 100644 --- a/assets/common/items/weapons/axe/worn_iron_axe-4.ron +++ b/assets/common/items/weapons/axe/worn_iron_axe-4.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Axe, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.8, poise_strength: 0.5, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/bow/horn_longbow-0.ron b/assets/common/items/weapons/bow/horn_longbow-0.ron index 8b974b6e43..ee6f75c2f3 100644 --- a/assets/common/items/weapons/bow/horn_longbow-0.ron +++ b/assets/common/items/weapons/bow/horn_longbow-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.5, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/bow/iron_longbow-0.ron b/assets/common/items/weapons/bow/iron_longbow-0.ron index a4f0b43aeb..0930934b58 100644 --- a/assets/common/items/weapons/bow/iron_longbow-0.ron +++ b/assets/common/items/weapons/bow/iron_longbow-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.75, poise_strength: 1.3, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/bow/leafy_longbow-0.ron b/assets/common/items/weapons/bow/leafy_longbow-0.ron index 2641fbd4d9..72ee1b9ed2 100644 --- a/assets/common/items/weapons/bow/leafy_longbow-0.ron +++ b/assets/common/items/weapons/bow/leafy_longbow-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.25, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/bow/leafy_shortbow-0.ron b/assets/common/items/weapons/bow/leafy_shortbow-0.ron index c689a17293..36fb4c21e8 100644 --- a/assets/common/items/weapons/bow/leafy_shortbow-0.ron +++ b/assets/common/items/weapons/bow/leafy_shortbow-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 0.4, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/bow/nature_ore_longbow-0.ron b/assets/common/items/weapons/bow/nature_ore_longbow-0.ron index bc5ba875cc..da913eeb5a 100644 --- a/assets/common/items/weapons/bow/nature_ore_longbow-0.ron +++ b/assets/common/items/weapons/bow/nature_ore_longbow-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 2.0, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Epic, tags: [], diff --git a/assets/common/items/weapons/bow/rare_longbow.ron b/assets/common/items/weapons/bow/rare_longbow.ron index 3e4acc826c..3e6f048e74 100644 --- a/assets/common/items/weapons/bow/rare_longbow.ron +++ b/assets/common/items/weapons/bow/rare_longbow.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 2.0, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Epic, tags: [], diff --git a/assets/common/items/weapons/bow/starter_bow.ron b/assets/common/items/weapons/bow/starter_bow.ron index 66d311c0f6..cea23874db 100644 --- a/assets/common/items/weapons/bow/starter_bow.ron +++ b/assets/common/items/weapons/bow/starter_bow.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.5, poise_strength: 0.3, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/bow/wood_longbow-0.ron b/assets/common/items/weapons/bow/wood_longbow-0.ron index 9ffffd93ab..a548fa71c7 100644 --- a/assets/common/items/weapons/bow/wood_longbow-0.ron +++ b/assets/common/items/weapons/bow/wood_longbow-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 0.9, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/bow/wood_longbow-1.ron b/assets/common/items/weapons/bow/wood_longbow-1.ron index a86ea56d15..d70d956963 100644 --- a/assets/common/items/weapons/bow/wood_longbow-1.ron +++ b/assets/common/items/weapons/bow/wood_longbow-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 1.2, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/bow/wood_shortbow-0.ron b/assets/common/items/weapons/bow/wood_shortbow-0.ron index 5df7538387..9711d3f714 100644 --- a/assets/common/items/weapons/bow/wood_shortbow-0.ron +++ b/assets/common/items/weapons/bow/wood_shortbow-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.8, poise_strength: 0.7, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/bow/wood_shortbow-1.ron b/assets/common/items/weapons/bow/wood_shortbow-1.ron index df1497b478..e5f1c33e58 100644 --- a/assets/common/items/weapons/bow/wood_shortbow-1.ron +++ b/assets/common/items/weapons/bow/wood_shortbow-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Bow, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.75, poise_strength: 0.4, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/dagger/basic_0.ron b/assets/common/items/weapons/dagger/basic_0.ron index 3b2490852a..2798ee2162 100644 --- a/assets/common/items/weapons/dagger/basic_0.ron +++ b/assets/common/items/weapons/dagger/basic_0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Dagger, hands: One, - stats: ( + stats: Direct(( equip_time_millis: 0, power: 1.8, poise_strength: 2.0, speed: 1.0, - ), + )), )), quality: High, tags: [], diff --git a/assets/common/items/weapons/dagger/cultist_0.ron b/assets/common/items/weapons/dagger/cultist_0.ron index c364188ee9..62ae319739 100644 --- a/assets/common/items/weapons/dagger/cultist_0.ron +++ b/assets/common/items/weapons/dagger/cultist_0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Dagger, hands: One, - stats: ( + stats: Direct(( equip_time_millis: 0, power: 2.0, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Epic, tags: [], diff --git a/assets/common/items/weapons/dagger/starter_dagger.ron b/assets/common/items/weapons/dagger/starter_dagger.ron index 87be7764cf..ea66b26fe3 100644 --- a/assets/common/items/weapons/dagger/starter_dagger.ron +++ b/assets/common/items/weapons/dagger/starter_dagger.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Dagger, hands: One, - stats: ( + stats: Direct(( equip_time_millis: 300, power: 1.0, poise_strength: 0.5, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/empty/empty.ron b/assets/common/items/weapons/empty/empty.ron index c199f96117..2788925af7 100644 --- a/assets/common/items/weapons/empty/empty.ron +++ b/assets/common/items/weapons/empty/empty.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Empty, hands: One, - stats: ( + stats: Direct(( equip_time_millis: 200, power: 1.0, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/hammer/bronze_hammer-0.ron b/assets/common/items/weapons/hammer/bronze_hammer-0.ron index 2eb3812ed1..4ecd533128 100644 --- a/assets/common/items/weapons/hammer/bronze_hammer-0.ron +++ b/assets/common/items/weapons/hammer/bronze_hammer-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.0, poise_strength: 0.9, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/bronze_hammer-1.ron b/assets/common/items/weapons/hammer/bronze_hammer-1.ron index 369391eaaa..5035e5d154 100644 --- a/assets/common/items/weapons/hammer/bronze_hammer-1.ron +++ b/assets/common/items/weapons/hammer/bronze_hammer-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.0, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/cobalt_hammer-0.ron b/assets/common/items/weapons/hammer/cobalt_hammer-0.ron index 49e6dab061..e60c583534 100644 --- a/assets/common/items/weapons/hammer/cobalt_hammer-0.ron +++ b/assets/common/items/weapons/hammer/cobalt_hammer-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.6, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/hammer/cobalt_hammer-1.ron b/assets/common/items/weapons/hammer/cobalt_hammer-1.ron index 8433b21268..7c4a7162f0 100644 --- a/assets/common/items/weapons/hammer/cobalt_hammer-1.ron +++ b/assets/common/items/weapons/hammer/cobalt_hammer-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.6, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/hammer/cultist_purp_2h-0.ron b/assets/common/items/weapons/hammer/cultist_purp_2h-0.ron index bdbbc3d7ed..f3538a28a8 100644 --- a/assets/common/items/weapons/hammer/cultist_purp_2h-0.ron +++ b/assets/common/items/weapons/hammer/cultist_purp_2h-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 2.0, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Epic, tags: [], diff --git a/assets/common/items/weapons/hammer/flimsy_hammer.ron b/assets/common/items/weapons/hammer/flimsy_hammer.ron index fd417558e1..c28ac25674 100644 --- a/assets/common/items/weapons/hammer/flimsy_hammer.ron +++ b/assets/common/items/weapons/hammer/flimsy_hammer.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.5, poise_strength: 0.4, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/hammer/hammer_1.ron b/assets/common/items/weapons/hammer/hammer_1.ron index d11cf784e8..36c761e3cc 100644 --- a/assets/common/items/weapons/hammer/hammer_1.ron +++ b/assets/common/items/weapons/hammer/hammer_1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.5, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/hammer/iron_hammer-0.ron b/assets/common/items/weapons/hammer/iron_hammer-0.ron index 44acc9e3da..2f4e6e19e6 100644 --- a/assets/common/items/weapons/hammer/iron_hammer-0.ron +++ b/assets/common/items/weapons/hammer/iron_hammer-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/iron_hammer-1.ron b/assets/common/items/weapons/hammer/iron_hammer-1.ron index 66ea001a67..efb1b9e40c 100644 --- a/assets/common/items/weapons/hammer/iron_hammer-1.ron +++ b/assets/common/items/weapons/hammer/iron_hammer-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 0.9, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/iron_hammer-2.ron b/assets/common/items/weapons/hammer/iron_hammer-2.ron index d95175c65f..0e2358dfd0 100644 --- a/assets/common/items/weapons/hammer/iron_hammer-2.ron +++ b/assets/common/items/weapons/hammer/iron_hammer-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/iron_hammer-3.ron b/assets/common/items/weapons/hammer/iron_hammer-3.ron index 57b0dee283..fc524992ce 100644 --- a/assets/common/items/weapons/hammer/iron_hammer-3.ron +++ b/assets/common/items/weapons/hammer/iron_hammer-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/iron_hammer-4.ron b/assets/common/items/weapons/hammer/iron_hammer-4.ron index bd9e83e434..ffc556a078 100644 --- a/assets/common/items/weapons/hammer/iron_hammer-4.ron +++ b/assets/common/items/weapons/hammer/iron_hammer-4.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/iron_hammer-5.ron b/assets/common/items/weapons/hammer/iron_hammer-5.ron index f0d479b2f7..14b02b048b 100644 --- a/assets/common/items/weapons/hammer/iron_hammer-5.ron +++ b/assets/common/items/weapons/hammer/iron_hammer-5.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/iron_hammer-6.ron b/assets/common/items/weapons/hammer/iron_hammer-6.ron index d960437e92..0f4c85beeb 100644 --- a/assets/common/items/weapons/hammer/iron_hammer-6.ron +++ b/assets/common/items/weapons/hammer/iron_hammer-6.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/iron_hammer-7.ron b/assets/common/items/weapons/hammer/iron_hammer-7.ron index 90bd20a9bd..4ff94bd769 100644 --- a/assets/common/items/weapons/hammer/iron_hammer-7.ron +++ b/assets/common/items/weapons/hammer/iron_hammer-7.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/iron_hammer-8.ron b/assets/common/items/weapons/hammer/iron_hammer-8.ron index 0d540e8535..14bc9cd770 100644 --- a/assets/common/items/weapons/hammer/iron_hammer-8.ron +++ b/assets/common/items/weapons/hammer/iron_hammer-8.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/mjolnir.ron b/assets/common/items/weapons/hammer/mjolnir.ron index 9c6ef685e5..534be5da25 100644 --- a/assets/common/items/weapons/hammer/mjolnir.ron +++ b/assets/common/items/weapons/hammer/mjolnir.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 4.0, poise_strength: 2.0, speed: 0.5, - ), + )), )), quality: Legendary, tags: [], diff --git a/assets/common/items/weapons/hammer/ramshead_hammer.ron b/assets/common/items/weapons/hammer/ramshead_hammer.ron index 48cd876d09..e58b18f747 100644 --- a/assets/common/items/weapons/hammer/ramshead_hammer.ron +++ b/assets/common/items/weapons/hammer/ramshead_hammer.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.8, poise_strength: 1.7, speed: 1.0, - ), + )), )), quality: High, tags: [], diff --git a/assets/common/items/weapons/hammer/runic_hammer.ron b/assets/common/items/weapons/hammer/runic_hammer.ron index 4f8cb9aa4f..fdd2b0b04b 100644 --- a/assets/common/items/weapons/hammer/runic_hammer.ron +++ b/assets/common/items/weapons/hammer/runic_hammer.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.8, poise_strength: 1.8, speed: 1.0, - ), + )), )), quality: High, tags: [], diff --git a/assets/common/items/weapons/hammer/starter_hammer.ron b/assets/common/items/weapons/hammer/starter_hammer.ron index 3e7bdd0c07..832af40a99 100644 --- a/assets/common/items/weapons/hammer/starter_hammer.ron +++ b/assets/common/items/weapons/hammer/starter_hammer.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.5, poise_strength: 0.9, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/hammer/steel_hammer-0.ron b/assets/common/items/weapons/hammer/steel_hammer-0.ron index 5766a3e76d..cf2a27e242 100644 --- a/assets/common/items/weapons/hammer/steel_hammer-0.ron +++ b/assets/common/items/weapons/hammer/steel_hammer-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.4, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/hammer/steel_hammer-1.ron b/assets/common/items/weapons/hammer/steel_hammer-1.ron index 24208d8ac2..df94e11f3d 100644 --- a/assets/common/items/weapons/hammer/steel_hammer-1.ron +++ b/assets/common/items/weapons/hammer/steel_hammer-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.4, poise_strength: 1.3, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/hammer/steel_hammer-2.ron b/assets/common/items/weapons/hammer/steel_hammer-2.ron index 705b58d630..96b6da84d9 100644 --- a/assets/common/items/weapons/hammer/steel_hammer-2.ron +++ b/assets/common/items/weapons/hammer/steel_hammer-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.4, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/hammer/steel_hammer-3.ron b/assets/common/items/weapons/hammer/steel_hammer-3.ron index 040fe85c7b..dd1abc559d 100644 --- a/assets/common/items/weapons/hammer/steel_hammer-3.ron +++ b/assets/common/items/weapons/hammer/steel_hammer-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.4, poise_strength: 1.7, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/hammer/steel_hammer-4.ron b/assets/common/items/weapons/hammer/steel_hammer-4.ron index ff82a2d7f7..819ec8c602 100644 --- a/assets/common/items/weapons/hammer/steel_hammer-4.ron +++ b/assets/common/items/weapons/hammer/steel_hammer-4.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.4, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/hammer/steel_hammer-5.ron b/assets/common/items/weapons/hammer/steel_hammer-5.ron index f4c9b22c45..698ccd3a68 100644 --- a/assets/common/items/weapons/hammer/steel_hammer-5.ron +++ b/assets/common/items/weapons/hammer/steel_hammer-5.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.4, poise_strength: 1.3, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/hammer/stone_hammer-0.ron b/assets/common/items/weapons/hammer/stone_hammer-0.ron index c6bcef5b88..96fb10c470 100644 --- a/assets/common/items/weapons/hammer/stone_hammer-0.ron +++ b/assets/common/items/weapons/hammer/stone_hammer-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.7, poise_strength: 1.7, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/hammer/stone_hammer-1.ron b/assets/common/items/weapons/hammer/stone_hammer-1.ron index c96aa3bffb..a481c4a072 100644 --- a/assets/common/items/weapons/hammer/stone_hammer-1.ron +++ b/assets/common/items/weapons/hammer/stone_hammer-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.7, poise_strength: 1.8, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/hammer/stone_hammer-2.ron b/assets/common/items/weapons/hammer/stone_hammer-2.ron index 9e1e952a13..d458b1043f 100644 --- a/assets/common/items/weapons/hammer/stone_hammer-2.ron +++ b/assets/common/items/weapons/hammer/stone_hammer-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.7, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/hammer/stone_hammer-3.ron b/assets/common/items/weapons/hammer/stone_hammer-3.ron index 1ef0425581..fc84849c95 100644 --- a/assets/common/items/weapons/hammer/stone_hammer-3.ron +++ b/assets/common/items/weapons/hammer/stone_hammer-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.7, poise_strength: 1.8, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/hammer/wood_hammer-0.ron b/assets/common/items/weapons/hammer/wood_hammer-0.ron index 9f5f3a68f1..8cfdc8b40e 100644 --- a/assets/common/items/weapons/hammer/wood_hammer-0.ron +++ b/assets/common/items/weapons/hammer/wood_hammer-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.6, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/hammer/worn_iron_hammer-0.ron b/assets/common/items/weapons/hammer/worn_iron_hammer-0.ron index 14dfcf1345..dd1ef660a4 100644 --- a/assets/common/items/weapons/hammer/worn_iron_hammer-0.ron +++ b/assets/common/items/weapons/hammer/worn_iron_hammer-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.85, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/worn_iron_hammer-1.ron b/assets/common/items/weapons/hammer/worn_iron_hammer-1.ron index 39961d8ba2..39df706cfe 100644 --- a/assets/common/items/weapons/hammer/worn_iron_hammer-1.ron +++ b/assets/common/items/weapons/hammer/worn_iron_hammer-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.85, poise_strength: 0.6, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/worn_iron_hammer-2.ron b/assets/common/items/weapons/hammer/worn_iron_hammer-2.ron index 756d018c62..af15f236ca 100644 --- a/assets/common/items/weapons/hammer/worn_iron_hammer-2.ron +++ b/assets/common/items/weapons/hammer/worn_iron_hammer-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.85, poise_strength: 0.7, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/hammer/worn_iron_hammer-3.ron b/assets/common/items/weapons/hammer/worn_iron_hammer-3.ron index ed2fc859f1..f28e076dc5 100644 --- a/assets/common/items/weapons/hammer/worn_iron_hammer-3.ron +++ b/assets/common/items/weapons/hammer/worn_iron_hammer-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Hammer, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.85, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sceptre/fork0.ron b/assets/common/items/weapons/sceptre/fork0.ron index d30f79301b..febd87ee8f 100644 --- a/assets/common/items/weapons/sceptre/fork0.ron +++ b/assets/common/items/weapons/sceptre/fork0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sceptre, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 2.0, poise_strength: 1.5, speed: 0.8, - ), + )), )), quality: High, tags: [], diff --git a/assets/common/items/weapons/sceptre/loops0.ron b/assets/common/items/weapons/sceptre/loops0.ron index 2cd8527a5e..e384f280d3 100644 --- a/assets/common/items/weapons/sceptre/loops0.ron +++ b/assets/common/items/weapons/sceptre/loops0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sceptre, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 1.5, speed: 1.5, - ), + )), )), quality: High, tags: [], diff --git a/assets/common/items/weapons/sceptre/moon0.ron b/assets/common/items/weapons/sceptre/moon0.ron index 2daab8c053..f6dfd2db6c 100644 --- a/assets/common/items/weapons/sceptre/moon0.ron +++ b/assets/common/items/weapons/sceptre/moon0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sceptre, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.6, poise_strength: 1.5, speed: 0.5, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sceptre/root_evil.ron b/assets/common/items/weapons/sceptre/root_evil.ron index 496aef8c61..f254db2e85 100644 --- a/assets/common/items/weapons/sceptre/root_evil.ron +++ b/assets/common/items/weapons/sceptre/root_evil.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sceptre, hands: Two, - stats: ( + stats: (( equip_time_millis: 400, power: 4.0, poise_strength: 1.5, speed: 0.5, - ), + )), )), quality: Legendary, tags: [], diff --git a/assets/common/items/weapons/sceptre/root_green0.ron b/assets/common/items/weapons/sceptre/root_green0.ron index 655380b9a2..c8bfbec7d7 100644 --- a/assets/common/items/weapons/sceptre/root_green0.ron +++ b/assets/common/items/weapons/sceptre/root_green0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sceptre, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 3.5, poise_strength: 1.5, speed: 0.4, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sceptre/sceptre_velorite_0.ron b/assets/common/items/weapons/sceptre/sceptre_velorite_0.ron index 83ff7db798..48ed1e72d4 100644 --- a/assets/common/items/weapons/sceptre/sceptre_velorite_0.ron +++ b/assets/common/items/weapons/sceptre/sceptre_velorite_0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sceptre, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.2, poise_strength: 1.5, speed: 1.6, - ), + )), )), quality: Epic, tags: [], diff --git a/assets/common/items/weapons/sceptre/staff_nature.ron b/assets/common/items/weapons/sceptre/staff_nature.ron index 459b49280a..8594ea00d0 100644 --- a/assets/common/items/weapons/sceptre/staff_nature.ron +++ b/assets/common/items/weapons/sceptre/staff_nature.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sceptre, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.91, poise_strength: 0.5, speed: 1.1, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sceptre/starter_sceptre.ron b/assets/common/items/weapons/sceptre/starter_sceptre.ron index 7f8adc23a3..787b186f79 100644 --- a/assets/common/items/weapons/sceptre/starter_sceptre.ron +++ b/assets/common/items/weapons/sceptre/starter_sceptre.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sceptre, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.5, poise_strength: 0.1, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/sceptre/totem_green.ron b/assets/common/items/weapons/sceptre/totem_green.ron index cbe3fa2f88..8df58e4a30 100644 --- a/assets/common/items/weapons/sceptre/totem_green.ron +++ b/assets/common/items/weapons/sceptre/totem_green.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sceptre, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 1.5, speed: 1.2, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/shield/shield_1.ron b/assets/common/items/weapons/shield/shield_1.ron index dfecf944ee..a66f321e58 100644 --- a/assets/common/items/weapons/shield/shield_1.ron +++ b/assets/common/items/weapons/shield/shield_1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Shield, hands: One, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/staff/amethyst_staff.ron b/assets/common/items/weapons/staff/amethyst_staff.ron index ac176501f4..e6e2a39be6 100644 --- a/assets/common/items/weapons/staff/amethyst_staff.ron +++ b/assets/common/items/weapons/staff/amethyst_staff.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Staff, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 300, power: 1.5, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/staff/bone_staff.ron b/assets/common/items/weapons/staff/bone_staff.ron index 2009e3b7c3..041ff07276 100644 --- a/assets/common/items/weapons/staff/bone_staff.ron +++ b/assets/common/items/weapons/staff/bone_staff.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Staff, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 300, power: 1.0, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/staff/cultist_staff.ron b/assets/common/items/weapons/staff/cultist_staff.ron index e3976b61c4..df99316d5c 100644 --- a/assets/common/items/weapons/staff/cultist_staff.ron +++ b/assets/common/items/weapons/staff/cultist_staff.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Staff, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 300, power: 2.0, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Epic, tags: [], diff --git a/assets/common/items/weapons/staff/staff_1.ron b/assets/common/items/weapons/staff/staff_1.ron index b720135ef0..ab4db158f4 100644 --- a/assets/common/items/weapons/staff/staff_1.ron +++ b/assets/common/items/weapons/staff/staff_1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Staff, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 200, power: 0.5, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/staff/starter_staff.ron b/assets/common/items/weapons/staff/starter_staff.ron index 1190c9fbcf..f793ba581b 100644 --- a/assets/common/items/weapons/staff/starter_staff.ron +++ b/assets/common/items/weapons/staff/starter_staff.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Staff, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 300, power: 0.5, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/sword/cultist_purp_2h-0.ron b/assets/common/items/weapons/sword/cultist_purp_2h-0.ron index b3175b6c2a..391573e0d4 100644 --- a/assets/common/items/weapons/sword/cultist_purp_2h-0.ron +++ b/assets/common/items/weapons/sword/cultist_purp_2h-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 2.0, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Epic, tags: [], diff --git a/assets/common/items/weapons/sword/frost_cleaver_2h-0.ron b/assets/common/items/weapons/sword/frost_cleaver_2h-0.ron index 50ae1251dd..cd8b2b0ea6 100644 --- a/assets/common/items/weapons/sword/frost_cleaver_2h-0.ron +++ b/assets/common/items/weapons/sword/frost_cleaver_2h-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.7, poise_strength: 2.0, speed: 1.0, - ), + )), )), quality: High, tags: [], diff --git a/assets/common/items/weapons/sword/frost_cleaver_2h-1.ron b/assets/common/items/weapons/sword/frost_cleaver_2h-1.ron index d2bc2105ab..dbf1d464e3 100644 --- a/assets/common/items/weapons/sword/frost_cleaver_2h-1.ron +++ b/assets/common/items/weapons/sword/frost_cleaver_2h-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.95, poise_strength: 1.7, speed: 1.0, - ), + )), )), quality: Epic, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_dam-0.ron b/assets/common/items/weapons/sword/greatsword_2h_dam-0.ron index 7476dc759b..cec3a97ad6 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_dam-0.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_dam-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.8, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_dam-1.ron b/assets/common/items/weapons/sword/greatsword_2h_dam-1.ron index 129bda61f0..47f454b417 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_dam-1.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_dam-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.8, poise_strength: 0.5, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_dam-2.ron b/assets/common/items/weapons/sword/greatsword_2h_dam-2.ron index eb69c646d3..a4b00f52eb 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_dam-2.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_dam-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.8, poise_strength: 0.9, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_fine-0.ron b/assets/common/items/weapons/sword/greatsword_2h_fine-0.ron index a9b5f746c9..0bf3dea87b 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_fine-0.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_fine-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.4, poise_strength: 1.6, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_fine-1.ron b/assets/common/items/weapons/sword/greatsword_2h_fine-1.ron index 532c23a82f..560fde56e6 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_fine-1.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_fine-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.4, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_fine-2.ron b/assets/common/items/weapons/sword/greatsword_2h_fine-2.ron index 2ce295e216..beb4200568 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_fine-2.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_fine-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.4, poise_strength: 1.7, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_orn-0.ron b/assets/common/items/weapons/sword/greatsword_2h_orn-0.ron index 083b0c2813..70ee016351 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_orn-0.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_orn-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.7, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_orn-1.ron b/assets/common/items/weapons/sword/greatsword_2h_orn-1.ron index 083b0c2813..70ee016351 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_orn-1.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_orn-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.7, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_orn-2.ron b/assets/common/items/weapons/sword/greatsword_2h_orn-2.ron index 015e267374..a150fbe41c 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_orn-2.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_orn-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.7, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_simple-0.ron b/assets/common/items/weapons/sword/greatsword_2h_simple-0.ron index 7d074c0aad..a2d14a9373 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_simple-0.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_simple-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.1, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_simple-1.ron b/assets/common/items/weapons/sword/greatsword_2h_simple-1.ron index 7d074c0aad..a2d14a9373 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_simple-1.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_simple-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.1, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/greatsword_2h_simple-2.ron b/assets/common/items/weapons/sword/greatsword_2h_simple-2.ron index a94d87d5ae..dc1b9c8d92 100644 --- a/assets/common/items/weapons/sword/greatsword_2h_simple-2.ron +++ b/assets/common/items/weapons/sword/greatsword_2h_simple-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.1, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_dam-0.ron b/assets/common/items/weapons/sword/long_2h_dam-0.ron index e311f47e44..178263d311 100644 --- a/assets/common/items/weapons/sword/long_2h_dam-0.ron +++ b/assets/common/items/weapons/sword/long_2h_dam-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.6, poise_strength: 0.5, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_dam-1.ron b/assets/common/items/weapons/sword/long_2h_dam-1.ron index e311f47e44..178263d311 100644 --- a/assets/common/items/weapons/sword/long_2h_dam-1.ron +++ b/assets/common/items/weapons/sword/long_2h_dam-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.6, poise_strength: 0.5, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_dam-2.ron b/assets/common/items/weapons/sword/long_2h_dam-2.ron index e311f47e44..178263d311 100644 --- a/assets/common/items/weapons/sword/long_2h_dam-2.ron +++ b/assets/common/items/weapons/sword/long_2h_dam-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.6, poise_strength: 0.5, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_dam-3.ron b/assets/common/items/weapons/sword/long_2h_dam-3.ron index e311f47e44..178263d311 100644 --- a/assets/common/items/weapons/sword/long_2h_dam-3.ron +++ b/assets/common/items/weapons/sword/long_2h_dam-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.6, poise_strength: 0.5, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_dam-4.ron b/assets/common/items/weapons/sword/long_2h_dam-4.ron index e311f47e44..178263d311 100644 --- a/assets/common/items/weapons/sword/long_2h_dam-4.ron +++ b/assets/common/items/weapons/sword/long_2h_dam-4.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.6, poise_strength: 0.5, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_dam-5.ron b/assets/common/items/weapons/sword/long_2h_dam-5.ron index e311f47e44..178263d311 100644 --- a/assets/common/items/weapons/sword/long_2h_dam-5.ron +++ b/assets/common/items/weapons/sword/long_2h_dam-5.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.6, poise_strength: 0.5, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_fine-0.ron b/assets/common/items/weapons/sword/long_2h_fine-0.ron index 52ee1dc773..87e666fa4e 100644 --- a/assets/common/items/weapons/sword/long_2h_fine-0.ron +++ b/assets/common/items/weapons/sword/long_2h_fine-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.3, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_fine-1.ron b/assets/common/items/weapons/sword/long_2h_fine-1.ron index 52ee1dc773..87e666fa4e 100644 --- a/assets/common/items/weapons/sword/long_2h_fine-1.ron +++ b/assets/common/items/weapons/sword/long_2h_fine-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.3, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_fine-2.ron b/assets/common/items/weapons/sword/long_2h_fine-2.ron index 52ee1dc773..87e666fa4e 100644 --- a/assets/common/items/weapons/sword/long_2h_fine-2.ron +++ b/assets/common/items/weapons/sword/long_2h_fine-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.3, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_fine-3.ron b/assets/common/items/weapons/sword/long_2h_fine-3.ron index 866a443fc7..ee077f7f7f 100644 --- a/assets/common/items/weapons/sword/long_2h_fine-3.ron +++ b/assets/common/items/weapons/sword/long_2h_fine-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_fine-4.ron b/assets/common/items/weapons/sword/long_2h_fine-4.ron index 52ee1dc773..87e666fa4e 100644 --- a/assets/common/items/weapons/sword/long_2h_fine-4.ron +++ b/assets/common/items/weapons/sword/long_2h_fine-4.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.3, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_fine-5.ron b/assets/common/items/weapons/sword/long_2h_fine-5.ron index 2858c3e710..d2a110603f 100644 --- a/assets/common/items/weapons/sword/long_2h_fine-5.ron +++ b/assets/common/items/weapons/sword/long_2h_fine-5.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.2, poise_strength: 1.4, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_orn-0.ron b/assets/common/items/weapons/sword/long_2h_orn-0.ron index 0404b5302e..7e29776c36 100644 --- a/assets/common/items/weapons/sword/long_2h_orn-0.ron +++ b/assets/common/items/weapons/sword/long_2h_orn-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.5, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_orn-1.ron b/assets/common/items/weapons/sword/long_2h_orn-1.ron index 99cc5766ad..2504d7cc97 100644 --- a/assets/common/items/weapons/sword/long_2h_orn-1.ron +++ b/assets/common/items/weapons/sword/long_2h_orn-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.5, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_orn-2.ron b/assets/common/items/weapons/sword/long_2h_orn-2.ron index 0404b5302e..7e29776c36 100644 --- a/assets/common/items/weapons/sword/long_2h_orn-2.ron +++ b/assets/common/items/weapons/sword/long_2h_orn-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.5, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_orn-3.ron b/assets/common/items/weapons/sword/long_2h_orn-3.ron index 0404b5302e..7e29776c36 100644 --- a/assets/common/items/weapons/sword/long_2h_orn-3.ron +++ b/assets/common/items/weapons/sword/long_2h_orn-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.5, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_orn-4.ron b/assets/common/items/weapons/sword/long_2h_orn-4.ron index 99cc5766ad..2504d7cc97 100644 --- a/assets/common/items/weapons/sword/long_2h_orn-4.ron +++ b/assets/common/items/weapons/sword/long_2h_orn-4.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.5, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_orn-5.ron b/assets/common/items/weapons/sword/long_2h_orn-5.ron index 99cc5766ad..2504d7cc97 100644 --- a/assets/common/items/weapons/sword/long_2h_orn-5.ron +++ b/assets/common/items/weapons/sword/long_2h_orn-5.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.5, poise_strength: 1.1, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_simple-0.ron b/assets/common/items/weapons/sword/long_2h_simple-0.ron index d8ca455f9a..ebec54d098 100644 --- a/assets/common/items/weapons/sword/long_2h_simple-0.ron +++ b/assets/common/items/weapons/sword/long_2h_simple-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.9, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_simple-1.ron b/assets/common/items/weapons/sword/long_2h_simple-1.ron index d8ca455f9a..ebec54d098 100644 --- a/assets/common/items/weapons/sword/long_2h_simple-1.ron +++ b/assets/common/items/weapons/sword/long_2h_simple-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.9, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_simple-2.ron b/assets/common/items/weapons/sword/long_2h_simple-2.ron index 5f41e99460..85dc373e74 100644 --- a/assets/common/items/weapons/sword/long_2h_simple-2.ron +++ b/assets/common/items/weapons/sword/long_2h_simple-2.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.9, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_simple-3.ron b/assets/common/items/weapons/sword/long_2h_simple-3.ron index d8ca455f9a..ebec54d098 100644 --- a/assets/common/items/weapons/sword/long_2h_simple-3.ron +++ b/assets/common/items/weapons/sword/long_2h_simple-3.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.9, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_simple-4.ron b/assets/common/items/weapons/sword/long_2h_simple-4.ron index d8ca455f9a..ebec54d098 100644 --- a/assets/common/items/weapons/sword/long_2h_simple-4.ron +++ b/assets/common/items/weapons/sword/long_2h_simple-4.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.9, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/long_2h_simple-5.ron b/assets/common/items/weapons/sword/long_2h_simple-5.ron index d8ca455f9a..ebec54d098 100644 --- a/assets/common/items/weapons/sword/long_2h_simple-5.ron +++ b/assets/common/items/weapons/sword/long_2h_simple-5.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 0.9, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/short_sword_0.ron b/assets/common/items/weapons/sword/short_sword_0.ron index ad78e5affc..2e63e32189 100644 --- a/assets/common/items/weapons/sword/short_sword_0.ron +++ b/assets/common/items/weapons/sword/short_sword_0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.75, poise_strength: 0.8, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/sword/starter_sword.ron b/assets/common/items/weapons/sword/starter_sword.ron index faaeaea880..53f1048edc 100644 --- a/assets/common/items/weapons/sword/starter_sword.ron +++ b/assets/common/items/weapons/sword/starter_sword.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 300, power: 0.5, poise_strength: 0.4, speed: 1.0, - ), + )), )), quality: Low, tags: [], diff --git a/assets/common/items/weapons/sword/wood_sword.ron b/assets/common/items/weapons/sword/wood_sword.ron index 3ad9b2ab9e..f94591932e 100644 --- a/assets/common/items/weapons/sword/wood_sword.ron +++ b/assets/common/items/weapons/sword/wood_sword.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 0.8, poise_strength: 0.5, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/sword/zweihander_sword_0.ron b/assets/common/items/weapons/sword/zweihander_sword_0.ron index c4dade8430..c15a257ef4 100644 --- a/assets/common/items/weapons/sword/zweihander_sword_0.ron +++ b/assets/common/items/weapons/sword/zweihander_sword_0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Sword, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 500, power: 1.5, poise_strength: 1.9, speed: 1.0, - ), + )), )), quality: Moderate, tags: [], diff --git a/assets/common/items/weapons/tool/broom.ron b/assets/common/items/weapons/tool/broom.ron index 1e7f2feda0..ea4722b958 100644 --- a/assets/common/items/weapons/tool/broom.ron +++ b/assets/common/items/weapons/tool/broom.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Farming, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/tool/fishing_rod.ron b/assets/common/items/weapons/tool/fishing_rod.ron index e672813a66..0ca7992bc3 100644 --- a/assets/common/items/weapons/tool/fishing_rod.ron +++ b/assets/common/items/weapons/tool/fishing_rod.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Farming, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/tool/hoe.ron b/assets/common/items/weapons/tool/hoe.ron index cc7c631abc..e311f62538 100644 --- a/assets/common/items/weapons/tool/hoe.ron +++ b/assets/common/items/weapons/tool/hoe.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Farming, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 1.5, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/tool/pickaxe.ron b/assets/common/items/weapons/tool/pickaxe.ron index 0c1e14d01b..ce47e34a75 100644 --- a/assets/common/items/weapons/tool/pickaxe.ron +++ b/assets/common/items/weapons/tool/pickaxe.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Farming, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/tool/pitchfork.ron b/assets/common/items/weapons/tool/pitchfork.ron index 53ea6a471c..fa46363371 100644 --- a/assets/common/items/weapons/tool/pitchfork.ron +++ b/assets/common/items/weapons/tool/pitchfork.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Farming, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 4.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/tool/rake.ron b/assets/common/items/weapons/tool/rake.ron index cd582b1a3e..7164f20a0b 100644 --- a/assets/common/items/weapons/tool/rake.ron +++ b/assets/common/items/weapons/tool/rake.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Farming, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 1.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/tool/shovel-0.ron b/assets/common/items/weapons/tool/shovel-0.ron index 1da67f9e4b..48fb8a81aa 100644 --- a/assets/common/items/weapons/tool/shovel-0.ron +++ b/assets/common/items/weapons/tool/shovel-0.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Farming, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 2.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/assets/common/items/weapons/tool/shovel-1.ron b/assets/common/items/weapons/tool/shovel-1.ron index bf58d91c20..6c647c97df 100644 --- a/assets/common/items/weapons/tool/shovel-1.ron +++ b/assets/common/items/weapons/tool/shovel-1.ron @@ -4,12 +4,12 @@ ItemDef( kind: Tool(( kind: Farming, hands: Two, - stats: ( + stats: Direct(( equip_time_millis: 400, power: 1.0, poise_strength: 2.0, speed: 1.0, - ), + )), )), quality: Common, tags: [], diff --git a/common/src/combat.rs b/common/src/combat.rs index bab35f2183..958e3436c3 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -5,7 +5,7 @@ use crate::{ item::{ armor::Protection, tool::{Tool, ToolKind}, - ItemKind, + Item, ItemKind, }, slot::EquipSlot, }, @@ -606,10 +606,10 @@ impl CombatBuff { } } -fn equipped_tool(inv: &Inventory, slot: EquipSlot) -> Option<&Tool> { +fn equipped_item_and_tool(inv: &Inventory, slot: EquipSlot) -> Option<(&Item, &Tool)> { inv.equipped(slot).and_then(|i| { if let ItemKind::Tool(tool) = &i.kind() { - Some(tool) + Some((i, tool)) } else { None } @@ -618,22 +618,24 @@ fn equipped_tool(inv: &Inventory, slot: EquipSlot) -> Option<&Tool> { pub fn get_weapons(inv: &Inventory) -> (Option, Option) { ( - equipped_tool(inv, EquipSlot::Mainhand).map(|tool| tool.kind), - equipped_tool(inv, EquipSlot::Offhand).map(|tool| tool.kind), + equipped_item_and_tool(inv, EquipSlot::Mainhand).map(|(_, tool)| tool.kind), + equipped_item_and_tool(inv, EquipSlot::Offhand).map(|(_, tool)| tool.kind), ) } fn offensive_rating(inv: &Inventory, skillset: &SkillSet) -> f32 { - let active_damage = equipped_tool(inv, EquipSlot::Mainhand).map_or(0.0, |tool| { - tool.base_power() - * tool.base_speed() - * (1.0 + 0.05 * skillset.earned_sp(SkillGroupKind::Weapon(tool.kind)) as f32) - }); - let second_damage = equipped_tool(inv, EquipSlot::Offhand).map_or(0.0, |tool| { - tool.base_power() - * tool.base_speed() - * (1.0 + 0.05 * skillset.earned_sp(SkillGroupKind::Weapon(tool.kind)) as f32) - }); + let active_damage = + equipped_item_and_tool(inv, EquipSlot::Mainhand).map_or(0.0, |(item, tool)| { + tool.base_power(item.components()) + * tool.base_speed(item.components()) + * (1.0 + 0.05 * skillset.earned_sp(SkillGroupKind::Weapon(tool.kind)) as f32) + }); + let second_damage = + equipped_item_and_tool(inv, EquipSlot::Offhand).map_or(0.0, |(item, tool)| { + tool.base_power(item.components()) + * tool.base_speed(item.components()) + * (1.0 + 0.05 * skillset.earned_sp(SkillGroupKind::Weapon(tool.kind)) as f32) + }); active_damage.max(second_damage) } diff --git a/common/src/comp/inventory/item/mod.rs b/common/src/comp/inventory/item/mod.rs index ae1adbcef1..700b56767a 100644 --- a/common/src/comp/inventory/item/mod.rs +++ b/common/src/comp/inventory/item/mod.rs @@ -1,7 +1,9 @@ pub mod armor; +pub mod modular; pub mod tool; // Reexports +pub use modular::{ModularComponent, ModularComponentKind, ModularComponentTag}; pub use tool::{AbilitySet, Hands, Tool, ToolKind, UniqueKind}; use crate::{ @@ -78,23 +80,31 @@ pub enum Quality { Debug, // Red } +pub trait TagExampleInfo { + fn name(&self) -> &'static str; + /// What item to show in the crafting hud if the player has nothing with the + /// tag + fn exemplar_identifier(&self) -> &'static str; +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ItemTag { ClothItem, + ModularComponent(ModularComponentTag), } -impl ItemTag { - pub fn name(&self) -> &'static str { +impl TagExampleInfo for ItemTag { + fn name(&self) -> &'static str { match self { ItemTag::ClothItem => "cloth item", + ItemTag::ModularComponent(kind) => kind.name(), } } - /// What item to show in the crafting hud if the player has nothing with the - /// tag - pub fn exemplar_identifier(&self) -> &'static str { + fn exemplar_identifier(&self) -> &'static str { match self { ItemTag::ClothItem => "common.items.tag_examples.cloth_item", + ItemTag::ModularComponent(tag) => tag.exemplar_identifier(), } } } @@ -103,6 +113,7 @@ impl ItemTag { pub enum ItemKind { /// Something wieldable Tool(tool::Tool), + ModularComponent(modular::ModularComponent), Lantern(Lantern), Armor(armor::Armor), Glider(Glider), @@ -158,18 +169,28 @@ pub struct Item { /// could change invariants like whether it was stackable (invalidating /// the amount). item_def: Arc, + /// components is hidden to maintain the following invariants: + /// - It should only contain modular components (and enhancements, once they + /// exist) + /// - Enhancements (once they exist) should be compatible with the available + /// slot shapes + /// - Modular components should agree with the tool kind + /// - There should be exactly one damage component and exactly one held + /// component for modular + /// weapons + components: Vec, /// amount is hidden because it needs to maintain the invariant that only /// stackable items can have > 1 amounts. amount: NonZeroU32, /// The slots for items that this item has slots: Vec, + item_config: Option>, } #[derive(Debug, Serialize, Deserialize)] pub struct ItemDef { #[serde(default)] item_definition_id: String, - pub item_config: Option, pub name: String, pub description: String, pub kind: ItemKind, @@ -177,6 +198,7 @@ pub struct ItemDef { pub tags: Vec, #[serde(default)] pub slots: u16, + ability_map: AbilityMap, } impl PartialEq for ItemDef { @@ -190,10 +212,10 @@ pub struct ItemConfig { pub dodge_ability: Option, } -impl From<(&ItemKind, &AbilityMap)> for ItemConfig { - fn from((item_kind, map): (&ItemKind, &AbilityMap)) -> Self { +impl From<(&ItemKind, &[Item], &AbilityMap)> for ItemConfig { + fn from((item_kind, components, map): (&ItemKind, &[Item], &AbilityMap)) -> Self { if let ItemKind::Tool(tool) = item_kind { - let abilities = tool.get_abilities(map); + let abilities = tool.get_abilities(components, map); return ItemConfig { abilities, @@ -217,24 +239,34 @@ impl ItemDef { ) } + pub fn is_modular(&self) -> bool { + match &self.kind { + ItemKind::Tool(tool) => match tool.stats { + tool::StatKind::Direct { .. } => false, + tool::StatKind::Modular => true, + }, + _ => false, + } + } + #[cfg(test)] pub fn new_test( item_definition_id: String, - item_config: Option, kind: ItemKind, quality: Quality, tags: Vec, slots: u16, + ability_map: AbilityMap, ) -> Self { Self { item_definition_id, - item_config, name: "test item name".to_owned(), description: "test item description".to_owned(), kind, quality, tags, slots, + ability_map, } } } @@ -250,7 +282,15 @@ impl assets::Compound for ItemDef { cache: &assets_manager::AssetCache, specifier: &str, ) -> Result { - let raw = cache.load_owned::(specifier)?; + // load from the filesystem first, but if the file doesn't exist, see if it's a + // programmaticly-generated asset + let raw = cache + .load_owned::(specifier) + .or_else(|e| modular::synthesize_modular_asset(specifier).ok_or(e))?; + + let ability_map_handle = + cache.load::("common.abilities.weapon_ability_manifest")?; + let ability_map = ability_map_handle.read().clone(); let RawItemDef { name, @@ -261,16 +301,6 @@ impl assets::Compound for ItemDef { slots, } = raw; - let item_config = if let ItemKind::Tool(_) = kind { - let ability_map_handle = - cache.load::("common.abilities.weapon_ability_manifest")?; - let ability_map = &*ability_map_handle.read(); - - Some(ItemConfig::from((&kind, ability_map))) - } else { - None - }; - // Some commands like /give_item provide the asset specifier separated with \ // instead of . // @@ -279,18 +309,18 @@ impl assets::Compound for ItemDef { Ok(ItemDef { item_definition_id, - item_config, name, description, kind, quality, tags, slots, + ability_map, }) } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename = "ItemDef")] struct RawItemDef { name: String, @@ -334,12 +364,32 @@ impl Item { // loadout when no weapon is present pub fn empty() -> Self { Item::new_from_asset_expect("common.items.weapons.empty.empty") } - pub fn new_from_item_def(inner_item: Arc) -> Self { + pub fn new_from_item_def(inner_item: Arc, input_components: &[Item]) -> 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())); + } + + let kind = inner_item.kind(); + let item_config = if let ItemKind::Tool(_) = kind { + Some(Box::new(ItemConfig::from(( + kind, + &*components, + &inner_item.ability_map, + )))) + } else { + None + }; + Item { item_id: Arc::new(AtomicCell::new(None)), amount: NonZeroU32::new(1).unwrap(), + components, slots: vec![None; inner_item.slots as usize], item_def: inner_item, + item_config, } } @@ -347,7 +397,7 @@ impl Item { /// Panics if the asset does not exist. pub fn new_from_asset_expect(asset_specifier: &str) -> Self { let inner_item = Arc::::load_expect_cloned(asset_specifier); - Item::new_from_item_def(inner_item) + Item::new_from_item_def(inner_item, &[]) } /// Creates a Vec containing one of each item that matches the provided @@ -360,11 +410,13 @@ impl Item { /// it exists pub fn new_from_asset(asset: &str) -> Result { let inner_item = Arc::::load_cloned(asset)?; - Ok(Item::new_from_item_def(inner_item)) + Ok(Item::new_from_item_def(inner_item, &[])) } /// Duplicates an item, creating an exact copy but with a new item ID - pub fn duplicate(&self) -> Self { Item::new_from_item_def(Arc::clone(&self.item_def)) } + pub fn duplicate(&self) -> Self { + Item::new_from_item_def(Arc::clone(&self.item_def), &self.components) + } /// FIXME: HACK: In order to set the entity ID asynchronously, we currently /// start it at None, and then atomically set it when it's saved for the @@ -446,6 +498,8 @@ impl Item { pub fn is_stackable(&self) -> bool { self.item_def.is_stackable() } + pub fn is_modular(&self) -> bool { self.item_def.is_modular() } + pub fn name(&self) -> &str { &self.item_def.name } pub fn description(&self) -> &str { &self.item_def.description } @@ -456,13 +510,14 @@ impl Item { pub fn quality(&self) -> Quality { self.item_def.quality } + pub fn components(&self) -> &[Item] { &self.components } + pub fn slots(&self) -> &[InvSlot] { &self.slots } pub fn slots_mut(&mut self) -> &mut [InvSlot] { &mut self.slots } pub fn item_config_expect(&self) -> &ItemConfig { &self - .item_def .item_config .as_ref() .expect("Item was expected to have an ItemConfig") @@ -568,6 +623,7 @@ pub trait ItemDesc { fn quality(&self) -> &Quality; fn num_slots(&self) -> u16; fn item_definition_id(&self) -> &str; + fn components(&self) -> &[Item]; } impl ItemDesc for Item { @@ -582,6 +638,8 @@ impl ItemDesc for Item { fn num_slots(&self) -> u16 { self.item_def.slots } fn item_definition_id(&self) -> &str { &self.item_def.item_definition_id } + + fn components(&self) -> &[Item] { &self.components } } impl ItemDesc for ItemDef { @@ -596,6 +654,8 @@ impl ItemDesc for ItemDef { fn num_slots(&self) -> u16 { self.slots } fn item_definition_id(&self) -> &str { &self.item_definition_id } + + fn components(&self) -> &[Item] { &[] } } impl Component for Item { diff --git a/common/src/comp/inventory/item/modular.rs b/common/src/comp/inventory/item/modular.rs new file mode 100644 index 0000000000..b7239145b9 --- /dev/null +++ b/common/src/comp/inventory/item/modular.rs @@ -0,0 +1,306 @@ +use super::{tool, ItemKind, ItemTag, Quality, RawItemDef, TagExampleInfo, ToolKind}; +use crate::recipe::{RawRecipeBook, RawRecipeInput}; +use hashbrown::HashMap; +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum ModularComponentKind { + Damage, + Held, +} + +impl ModularComponentKind { + fn identifier_name(&self) -> &'static str { + match self { + ModularComponentKind::Damage => "damage", + ModularComponentKind::Held => "held", + } + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ModularComponent { + pub toolkind: ToolKind, + pub modkind: ModularComponentKind, + pub stats: tool::Stats, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct ModularComponentTag { + toolkind: ToolKind, + modkind: ModularComponentKind, +} + +impl TagExampleInfo for ModularComponentTag { + fn name(&self) -> &'static str { + match self.modkind { + ModularComponentKind::Damage => match self.toolkind { + ToolKind::Sword => "sword blade", + ToolKind::Axe => "axe head", + ToolKind::Hammer => "hammer head", + ToolKind::Bow => "bow limbs", + ToolKind::Dagger => "dagger blade", + ToolKind::Staff => "staff head", + ToolKind::Sceptre => "sceptre head", + // TODO: naming + ToolKind::Shield => "shield damage component", + ToolKind::Unique(_) => "unique damage component", + ToolKind::Debug => "debug damage component", + ToolKind::Farming => "farming damage component", + ToolKind::Empty => "empty damage component", + }, + ModularComponentKind::Held => match self.toolkind { + ToolKind::Sword => "sword hilt", + ToolKind::Axe => "axe shaft", + ToolKind::Hammer => "hammer shaft", + ToolKind::Bow => "bow riser", + ToolKind::Dagger => "dagger grip", + ToolKind::Staff => "staff shaft", + ToolKind::Sceptre => "sceptre shaft", + // TODO: naming + ToolKind::Shield => "shield held component", + ToolKind::Unique(_) => "unique held component", + ToolKind::Debug => "debug held component", + ToolKind::Farming => "farming held component", + ToolKind::Empty => "empty held component", + }, + } + } + + fn exemplar_identifier(&self) -> &'static str { + match self.modkind { + ModularComponentKind::Damage => match self.toolkind { + ToolKind::Sword => "common.items.tag_examples.modular.damage.sword", + ToolKind::Axe => "common.items.tag_examples.modular.damage.axe", + ToolKind::Hammer => "common.items.tag_examples.modular.damage.hammer", + ToolKind::Bow => "common.items.tag_examples.modular.damage.bow", + ToolKind::Dagger => "common.items.tag_examples.modular.damage.dagger", + ToolKind::Staff => "common.items.tag_examples.modular.damage.staff", + ToolKind::Sceptre => "common.items.tag_examples.modular.damage.sceptre", + ToolKind::Shield => "common.items.tag_examples.modular.damage.shield", + ToolKind::Unique(_) => "common.items.tag_examples.modular.damage.unique", + ToolKind::Debug => "common.items.tag_examples.modular.damage.debug", + ToolKind::Farming => "common.items.tag_examples.modular.damage.farming", + ToolKind::Empty => "common.items.tag_examples.modular.damage.empty", + }, + ModularComponentKind::Held => match self.toolkind { + ToolKind::Sword => "common.items.tag_examples.modular.held.sword", + ToolKind::Axe => "common.items.tag_examples.modular.held.axe", + ToolKind::Hammer => "common.items.tag_examples.modular.held.hammer", + ToolKind::Bow => "common.items.tag_examples.modular.held.bow", + ToolKind::Dagger => "common.items.tag_examples.modular.held.dagger", + ToolKind::Staff => "common.items.tag_examples.modular.held.staff", + ToolKind::Sceptre => "common.items.tag_examples.modular.held.sceptre", + ToolKind::Shield => "common.items.tag_examples.modular.held.shield", + ToolKind::Unique(_) => "common.items.tag_examples.modular.held.unique", + ToolKind::Debug => "common.items.tag_examples.modular.held.debug", + ToolKind::Farming => "common.items.tag_examples.modular.held.farming", + ToolKind::Empty => "common.items.tag_examples.modular.held.empty", + }, + } + } +} + +const SUPPORTED_TOOLKINDS: [ToolKind; 7] = [ + ToolKind::Sword, + ToolKind::Axe, + ToolKind::Hammer, + ToolKind::Bow, + ToolKind::Dagger, + ToolKind::Staff, + ToolKind::Sceptre, +]; +const MODKINDS: [ModularComponentKind; 2] = + [ModularComponentKind::Damage, ModularComponentKind::Held]; + +const COMPONENT_PREFIX: &str = "common.items.crafting_ing.modular"; +const WEAPON_PREFIX: &str = "common.items.weapons.modular"; +const TAG_EXAMPLES_PREFIX: &str = "common.items.tag_examples.modular"; + +// AVERAGE_STAT_VALUE from the "Progression" google sheet +// TODO: also get materials from there +const AVERAGE_STAT_VALUE: [f32; 6] = [0.75, 1.0, 1.25, 1.5, 1.75, 2.0]; + +fn make_component_def( + toolkind: ToolKind, + modkind: ModularComponentKind, + tier: usize, +) -> (String, RawItemDef) { + let tag = ModularComponentTag { toolkind, modkind }; + let identifier = format!( + "{}.{}.{}.tier{}", + COMPONENT_PREFIX, + modkind.identifier_name(), + toolkind.identifier_name(), + tier + ); + let name = format!("Tier-{} {}", tier, tag.name()); + let description = format!( + "A {} used to make {}s", + tag.name(), + toolkind.identifier_name() + ); + let mc = ModularComponent { + toolkind, + modkind, + stats: tool::Stats { + equip_time_millis: 250, + power: if matches!(modkind, ModularComponentKind::Damage) { + AVERAGE_STAT_VALUE[tier] + } else { + 0.0 + }, + poise_strength: if matches!(modkind, ModularComponentKind::Damage) { + AVERAGE_STAT_VALUE[tier] * 0.75 + } else { + 0.0 + }, + speed: if matches!(modkind, ModularComponentKind::Held) { + //AVERAGE_STAT_VALUE[tier] * 0.5 + 1.0 + } else { + 0.0 + }, + }, + }; + let kind = ItemKind::ModularComponent(mc); + // TODO: tier -> quality? + let quality = Quality::Common; + let item = RawItemDef { + name, + description, + kind, + quality, + tags: vec![ItemTag::ModularComponent(tag)], + slots: 0, + }; + (identifier, item) +} + +fn make_weapon_def(toolkind: ToolKind) -> (String, RawItemDef) { + let identifier = format!("{}.{}", WEAPON_PREFIX, toolkind.identifier_name(),); + let name = format!("Modular {}", toolkind.identifier_name()); + let description = format!("A {} made of components", toolkind.identifier_name()); + let tool = tool::Tool { + kind: toolkind, + hands: tool::Hands::Two, + stats: tool::StatKind::Modular, + }; + let kind = ItemKind::Tool(tool); + let quality = Quality::Common; + let item = RawItemDef { + name, + description, + kind, + quality, + tags: Vec::new(), + slots: 0, + }; + (identifier, item) +} + +fn make_recipe_def( + identifier: String, + toolkind: ToolKind, +) -> ((String, u32), Vec<(RawRecipeInput, u32)>) { + let outputs = (identifier, 1); + let mut inputs = Vec::new(); + for &modkind in &MODKINDS { + let input = RawRecipeInput::Tag(ItemTag::ModularComponent(ModularComponentTag { + toolkind, + modkind, + })); + inputs.push((input, 1)); + } + (outputs, inputs) +} + +fn make_tagexample_def( + toolkind: ToolKind, + modkind: ModularComponentKind, + exemplars: &HashMap>, +) -> (String, RawItemDef) { + let identifier = format!( + "{}.{}.{}", + TAG_EXAMPLES_PREFIX, + modkind.identifier_name(), + toolkind.identifier_name(), + ); + let tag = ModularComponentTag { modkind, toolkind }; + // TODO: i18n + let name = format!("Any {}", tag.name()); + let description = format!( + "{}s used to make {}s", + tag.name(), + toolkind.identifier_name() + ); + let kind = ItemKind::TagExamples { + item_ids: exemplars.get(&tag).cloned().unwrap_or_else(Vec::new), + }; + let quality = Quality::Common; + + let item = RawItemDef { + name, + description, + kind, + quality, + tags: vec![ItemTag::ModularComponent(tag)], + slots: 0, + }; + (identifier, item) +} + +fn initialize_modular_assets() -> (HashMap, RawRecipeBook) { + let mut itemdefs = HashMap::new(); + let mut exemplars = HashMap::new(); + let mut recipes = HashMap::new(); + for &toolkind in &SUPPORTED_TOOLKINDS { + for &modkind in &MODKINDS { + for tier in 0..=5 { + let (identifier, item) = make_component_def(toolkind, modkind, tier); + let tag = ModularComponentTag { modkind, toolkind }; + exemplars + .entry(tag) + .or_insert_with(Vec::new) + .push(identifier.clone()); + itemdefs.insert(identifier, item); + } + } + let (identifier, item) = make_weapon_def(toolkind); + itemdefs.insert(identifier.clone(), item); + let recipe = make_recipe_def(identifier.clone(), toolkind); + recipes.insert(identifier, recipe); + } + for &toolkind in &SUPPORTED_TOOLKINDS { + for &modkind in &MODKINDS { + let (identifier, item) = make_tagexample_def(toolkind, modkind, &exemplars); + itemdefs.insert(identifier, item); + } + } + (itemdefs, RawRecipeBook(recipes)) +} + +lazy_static! { + static ref ITEM_DEFS_AND_RECIPES: (HashMap, RawRecipeBook) = + initialize_modular_assets(); +} + +pub(crate) fn append_modular_recipes(recipes: &mut RawRecipeBook) { + for (name, recipe) in ITEM_DEFS_AND_RECIPES.1.0.iter() { + // avoid clobbering recipes from the filesystem, to allow overrides + if !recipes.0.contains_key(name) { + recipes.0.insert(name.clone(), recipe.clone()); + } + } +} + +/// Synthesize modular assets programmatically, to allow for the following: +/// - Tweaking stats as a function of tier automatically +/// - Allow the modular tag_examples to auto-update with the list of applicable +/// components +pub(super) fn synthesize_modular_asset(specifier: &str) -> Option { + let ret = ITEM_DEFS_AND_RECIPES.0.get(specifier).cloned(); + tracing::trace!("synthesize_modular_asset({:?}) -> {:?}", specifier, ret); + ret +} diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 9e45a89134..9aaf87b78f 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -3,7 +3,7 @@ use crate::{ assets::{self, Asset}, - comp::{skills::Skill, CharacterAbility}, + comp::{item::ItemKind, skills::Skill, CharacterAbility, Item}, }; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; @@ -27,23 +27,81 @@ pub enum ToolKind { Empty, } +impl ToolKind { + pub fn identifier_name(&self) -> &'static str { + match self { + ToolKind::Sword => "sword", + ToolKind::Axe => "axe", + ToolKind::Hammer => "hammer", + ToolKind::Bow => "bow", + ToolKind::Dagger => "dagger", + ToolKind::Staff => "staff", + ToolKind::Sceptre => "sceptre", + ToolKind::Shield => "shield", + ToolKind::Unique(_) => "unique", + ToolKind::Debug => "debug", + ToolKind::Farming => "farming", + ToolKind::Empty => "empty", + } + } +} + #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub enum Hands { One, Two, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub struct Stats { - equip_time_millis: u32, - power: f32, - poise_strength: f32, - speed: f32, + pub equip_time_millis: u32, + pub power: f32, + pub poise_strength: f32, + pub speed: f32, } -impl From<&Tool> for Stats { - fn from(tool: &Tool) -> Self { - let raw_stats = tool.stats; +impl Stats { + pub fn zeroed() -> Stats { + Stats { + equip_time_millis: 0, + power: 0.0, + poise_strength: 0.0, + speed: 0.0, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +pub enum StatKind { + Direct(Stats), + Modular, +} + +impl StatKind { + pub fn resolve_stats(&self, components: &[Item]) -> Stats { + let mut stats = match self { + StatKind::Direct(stats) => *stats, + StatKind::Modular => Stats::zeroed(), + }; + for item in components.iter() { + if let ItemKind::ModularComponent(mc) = item.kind() { + stats.equip_time_millis += mc.stats.equip_time_millis; + stats.power += mc.stats.power; + stats.poise_strength += mc.stats.poise_strength; + stats.speed += mc.stats.speed; + } + // TODO: add stats from enhancement slots + } + // if an item has 0.0 speed, that panics due to being infinite duration, so + // enforce speed >= 0.5 + stats.speed = stats.speed.max(0.5); + stats + } +} + +impl From<(&[Item], &Tool)> for Stats { + fn from((components, tool): (&[Item], &Tool)) -> Self { + let raw_stats = tool.stats.resolve_stats(components); let (power, speed) = match tool.hands { Hands::One => (0.67, 1.33), // TODO: Restore this when one-handed weapons are made accessible @@ -63,7 +121,7 @@ impl From<&Tool> for Stats { pub struct Tool { pub kind: ToolKind, pub hands: Hands, - pub stats: Stats, + pub stats: StatKind, // TODO: item specific abilities } @@ -81,12 +139,12 @@ impl Tool { Self { kind, hands, - stats: Stats { + stats: StatKind::Direct(Stats { equip_time_millis, power, poise_strength, speed, - }, + }), } } @@ -94,29 +152,39 @@ impl Tool { Self { kind: ToolKind::Empty, hands: Hands::One, - stats: Stats { + stats: StatKind::Direct(Stats { equip_time_millis: 0, power: 1.00, poise_strength: 1.00, speed: 1.00, - }, + }), } } // Keep power between 0.5 and 2.00 - pub fn base_power(&self) -> f32 { self.stats.power } - - pub fn base_poise_strength(&self) -> f32 { self.stats.poise_strength } - - pub fn base_speed(&self) -> f32 { self.stats.speed } - - pub fn equip_time(&self) -> Duration { - Duration::from_millis(self.stats.equip_time_millis as u64) + pub fn base_power(&self, components: &[Item]) -> f32 { + self.stats.resolve_stats(components).power } - pub fn get_abilities(&self, map: &AbilityMap) -> AbilitySet { + pub fn base_poise_strength(&self, components: &[Item]) -> f32 { + self.stats.resolve_stats(components).poise_strength + } + + pub fn base_speed(&self, components: &[Item]) -> f32 { + self.stats.resolve_stats(components).speed + } + + pub fn equip_time(&self, components: &[Item]) -> Duration { + Duration::from_millis(self.stats.resolve_stats(components).equip_time_millis as u64) + } + + pub fn get_abilities( + &self, + components: &[Item], + map: &AbilityMap, + ) -> AbilitySet { if let Some(set) = map.0.get(&self.kind).cloned() { - set.modified_by_tool(&self) + set.modified_by_tool(&self, components) } else { error!( "ToolKind: {:?} has no AbilitySet in the ability map falling back to default", @@ -135,8 +203,8 @@ pub struct AbilitySet { } impl AbilitySet { - pub fn modified_by_tool(self, tool: &Tool) -> Self { - let stats = Stats::from(tool); + pub fn modified_by_tool(self, tool: &Tool, components: &[Item]) -> Self { + let stats = Stats::from((components, tool)); self.map(|a| a.adjusted_by_stats(stats.power, stats.poise_strength, stats.speed)) } } @@ -172,6 +240,14 @@ impl Default for AbilitySet { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AbilityMap(HashMap>); +impl Default for AbilityMap { + fn default() -> Self { + let mut map = HashMap::new(); + map.insert(ToolKind::Empty, AbilitySet::default()); + AbilityMap(map) + } +} + impl Asset for AbilityMap { type Loader = assets::RonLoader; diff --git a/common/src/comp/inventory/test_helpers.rs b/common/src/comp/inventory/test_helpers.rs index ac050ffecd..a3f07cf78b 100644 --- a/common/src/comp/inventory/test_helpers.rs +++ b/common/src/comp/inventory/test_helpers.rs @@ -2,16 +2,16 @@ use crate::comp::{ inventory::item::{ armor, armor::{ArmorKind, Protection}, + tool::AbilityMap, ItemDef, ItemKind, Quality, }, Item, }; -use std::sync::Arc; +use std::{default::Default, sync::Arc}; pub(super) fn get_test_bag(slots: u16) -> Item { let item_def = ItemDef::new_test( "common.items.testing.test_bag".to_string(), - None, ItemKind::Armor(armor::Armor::test_armor( ArmorKind::Bag("Test Bag".to_string()), Protection::Normal(0.0), @@ -20,7 +20,8 @@ pub(super) fn get_test_bag(slots: u16) -> Item { Quality::Common, Vec::new(), slots, + AbilityMap::default(), ); - Item::new_from_item_def(Arc::new(item_def)) + Item::new_from_item_def(Arc::new(item_def), &[]) } diff --git a/common/src/recipe.rs b/common/src/recipe.rs index 1cbd7b6745..b998b443fd 100644 --- a/common/src/recipe.rs +++ b/common/src/recipe.rs @@ -1,7 +1,7 @@ use crate::{ assets::{self, AssetExt, AssetHandle}, comp::{ - item::{ItemDef, ItemTag}, + item::{modular, ItemDef, ItemTag}, Inventory, Item, }, }; @@ -29,16 +29,19 @@ impl Recipe { inv: &mut Inventory, ) -> Result, Vec<(&RecipeInput, u32)>> { // Get ingredient cells from inventory, + let mut components = Vec::new(); + inv.contains_ingredients(self)? .into_iter() .for_each(|(pos, n)| { (0..n).for_each(|_| { - inv.take(pos).expect("Expected item to exist in inventory"); + let component = inv.take(pos).expect("Expected item to exist in inventory"); + components.push(component); }) }); for i in 0..self.output.1 { - let crafted_item = Item::new_from_item_def(Arc::clone(&self.output.0)); + let crafted_item = Item::new_from_item_def(Arc::clone(&self.output.0), &components); if let Some(item) = inv.push(crafted_item) { return Ok(Some((item, self.output.1 - i))); } @@ -79,10 +82,12 @@ pub enum RawRecipeInput { Tag(ItemTag), } -#[derive(Deserialize)] +#[derive(Clone, Deserialize)] #[serde(transparent)] #[allow(clippy::type_complexity)] -struct RawRecipeBook(HashMap)>); +pub(crate) struct RawRecipeBook( + pub(crate) HashMap)>, +); impl assets::Asset for RawRecipeBook { type Loader = assets::RonLoader; @@ -113,7 +118,8 @@ impl assets::Compound for RecipeBook { Ok((def, spec.1)) } - let raw = cache.load::(specifier)?.read(); + let mut raw = cache.load::(specifier)?.read().clone(); + modular::append_modular_recipes(&mut raw); let recipes = raw .0 diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index fd6bba8b15..9abcfb8184 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -294,14 +294,14 @@ pub fn handle_wield(data: &JoinData, update: &mut StateUpdate) { /// If a tool is equipped, goes into Equipping state, otherwise goes to Idle pub fn attempt_wield(data: &JoinData, update: &mut StateUpdate) { - if let Some(ItemKind::Tool(tool)) = data + if let Some((item, ItemKind::Tool(tool))) = data .inventory .equipped(EquipSlot::Mainhand) - .map(|i| i.kind()) + .map(|i| (i, i.kind())) { update.character = CharacterState::Equipping(equipping::Data { static_data: equipping::StaticData { - buildup_duration: tool.equip_time(), + buildup_duration: tool.equip_time(item.components()), }, timer: Duration::default(), }); diff --git a/voxygen/src/hud/crafting.rs b/voxygen/src/hud/crafting.rs index c47b64fa02..f071951e58 100644 --- a/voxygen/src/hud/crafting.rs +++ b/voxygen/src/hud/crafting.rs @@ -12,7 +12,7 @@ use client::{self, Client}; use common::{ assets::AssetExt, comp::{ - item::{ItemDef, ItemDesc, Quality}, + item::{ItemDef, ItemDesc, Quality, TagExampleInfo}, Inventory, }, recipe::RecipeInput, diff --git a/voxygen/src/hud/item_imgs.rs b/voxygen/src/hud/item_imgs.rs index 73648e4604..50ceaac0cf 100644 --- a/voxygen/src/hud/item_imgs.rs +++ b/voxygen/src/hud/item_imgs.rs @@ -23,6 +23,7 @@ pub fn animate_by_pulse(ids: &[Id], pulse: f32) -> Id { #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ItemKey { Tool(String), + ModularComponent(String), Lantern(String), Glider(String), Armor(ArmorKind), @@ -41,6 +42,9 @@ impl From<&T> for ItemKey { match item_kind { ItemKind::Tool(_) => ItemKey::Tool(item_definition_id.to_owned()), + ItemKind::ModularComponent(_) => { + ItemKey::ModularComponent(item_definition_id.to_owned()) + }, ItemKind::Lantern(Lantern { kind, .. }) => ItemKey::Lantern(kind.clone()), ItemKind::Glider(Glider { kind, .. }) => ItemKey::Glider(kind.clone()), ItemKind::Armor(Armor { kind, .. }) => ItemKey::Armor(kind.clone()), diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index bdfd3ee807..3940b9012a 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -19,7 +19,7 @@ use common::comp::{ inventory::slot::EquipSlot, item::{ tool::{AbilityMap, Tool, ToolKind}, - Hands, ItemKind, + Hands, Item, ItemKind, }, Energy, Health, Inventory, }; @@ -583,24 +583,30 @@ impl<'a> Widget for Skillbar<'a> { .right_from(state.ids.m1_slot_bg, slot_offset) .set(state.ids.m2_slot_bg, ui); - fn get_tool(inventory: &Inventory, equip_slot: EquipSlot) -> Option<&Tool> { - match inventory.equipped(equip_slot).map(|i| i.kind()) { - Some(ItemKind::Tool(tool)) => Some(tool), + fn get_item_and_tool( + inventory: &Inventory, + equip_slot: EquipSlot, + ) -> Option<(&Item, &Tool)> { + match inventory.equipped(equip_slot).map(|i| (i, i.kind())) { + Some((i, ItemKind::Tool(tool))) => Some((i, tool)), _ => None, } } - let active_tool = get_tool(self.inventory, EquipSlot::Mainhand); - let second_tool = get_tool(self.inventory, EquipSlot::Offhand); + let active_tool = get_item_and_tool(self.inventory, EquipSlot::Mainhand); + let second_tool = get_item_and_tool(self.inventory, EquipSlot::Offhand); - let tool = match (active_tool.map(|x| x.hands), second_tool.map(|x| x.hands)) { + let tool = match ( + active_tool.map(|(_, x)| x.hands), + second_tool.map(|(_, x)| x.hands), + ) { (Some(Hands::Two), _) => active_tool, (_, Some(Hands::One)) => second_tool, (Some(Hands::One), _) => active_tool, (_, _) => None, }; - Button::image(match tool.map(|t| t.kind) { + Button::image(match tool.map(|(_, t)| t.kind) { Some(ToolKind::Sword) => self.imgs.twohsword_m2, Some(ToolKind::Dagger) => self.imgs.onehdagger_m2, Some(ToolKind::Shield) => self.imgs.onehshield_m2, @@ -614,10 +620,10 @@ impl<'a> Widget for Skillbar<'a> { }) .w_h(36.0, 36.0) .middle_of(state.ids.m2_slot_bg) - .image_color(if let Some(tool) = tool { + .image_color(if let Some((item, tool)) = tool { if self.energy.current() >= tool - .get_abilities(self.ability_map) + .get_abilities(item.components(), self.ability_map) .secondary .get_energy_cost() { @@ -626,7 +632,7 @@ impl<'a> Widget for Skillbar<'a> { Color::Rgba(0.3, 0.3, 0.3, 0.8) } } else { - match tool.map(|t| t.kind) { + match tool.map(|(_, t)| t.kind) { None => Color::Rgba(1.0, 1.0, 1.0, 0.0), _ => Color::Rgba(1.0, 1.0, 1.0, 1.0), } diff --git a/voxygen/src/hud/slots.rs b/voxygen/src/hud/slots.rs index 338555b6d4..95a4146c88 100644 --- a/voxygen/src/hud/slots.rs +++ b/voxygen/src/hud/slots.rs @@ -117,16 +117,23 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { .map(|item| HotbarImage::Item(item.into())) .map(|i| (i, None)), hotbar::SlotContents::Ability3 => { - let tool = match inventory.equipped(EquipSlot::Mainhand).map(|i| i.kind()) { - Some(ItemKind::Tool(tool)) => Some(tool), + let tool = match inventory + .equipped(EquipSlot::Mainhand) + .map(|i| (i, i.kind())) + { + Some((item, ItemKind::Tool(tool))) => Some((item, tool)), _ => None, }; - tool.and_then(|tool| { + tool.and_then(|(item, tool)| { hotbar_image(tool.kind).map(|i| { ( i, - if let Some(skill) = tool.get_abilities(ability_map).abilities.get(0) { + if let Some(skill) = tool + .get_abilities(item.components(), ability_map) + .abilities + .get(0) + { if energy.current() >= skill.1.get_energy_cost() { Some(Color::Rgba(1.0, 1.0, 1.0, 1.0)) } else { @@ -155,18 +162,20 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { (_, _) => (None, 0), }; - let tool = match equip_slot.and_then(|es| inventory.equipped(es).map(|i| i.kind())) - { - Some(ItemKind::Tool(tool)) => Some(tool), - _ => None, - }; + let tool = + match equip_slot.and_then(|es| inventory.equipped(es).map(|i| (i, i.kind()))) { + Some((item, ItemKind::Tool(tool))) => Some((item, tool)), + _ => None, + }; - tool.and_then(|tool| { + tool.and_then(|(item, tool)| { hotbar_image(tool.kind).map(|i| { ( i, - if let Some(skill) = - tool.get_abilities(ability_map).abilities.get(skill_index) + if let Some(skill) = tool + .get_abilities(item.components(), ability_map) + .abilities + .get(skill_index) { if energy.current() >= skill.1.get_energy_cost() { Some(Color::Rgba(1.0, 1.0, 1.0, 1.0)) diff --git a/voxygen/src/hud/util.rs b/voxygen/src/hud/util.rs index 7f66264869..028250bf49 100644 --- a/voxygen/src/hud/util.rs +++ b/voxygen/src/hud/util.rs @@ -1,7 +1,7 @@ use common::comp::item::{ armor::{Armor, ArmorKind, Protection}, tool::{Hands, Tool, ToolKind}, - ItemDesc, ItemKind, + Item, ItemDesc, ItemKind, ModularComponent, }; use std::{borrow::Cow, fmt::Write}; @@ -23,7 +23,8 @@ pub fn item_text<'a>(item: &'a impl ItemDesc) -> (&'_ str, Cow<'a, str>) { ItemKind::Armor(armor) => { Cow::Owned(armor_desc(armor, item.description(), item.num_slots())) }, - ItemKind::Tool(tool) => Cow::Owned(tool_desc(&tool, item.description())), + ItemKind::Tool(tool) => Cow::Owned(tool_desc(&tool, item.components(), item.description())), + ItemKind::ModularComponent(mc) => Cow::Owned(modular_component_desc(mc)), ItemKind::Glider(_glider) => Cow::Owned(glider_desc(item.description())), ItemKind::Consumable { .. } => Cow::Owned(consumable_desc(item.description())), ItemKind::Throwable { .. } => Cow::Owned(throwable_desc(item.description())), @@ -38,6 +39,9 @@ pub fn item_text<'a>(item: &'a impl ItemDesc) -> (&'_ str, Cow<'a, str>) { } // TODO: localization +fn modular_component_desc(mc: &ModularComponent) -> String { + format!("Modular Component\n\n{:?}", mc) +} fn glider_desc(desc: &str) -> String { format!("Glider\n\n{}\n\n", desc) } fn consumable_desc(desc: &str) -> String { @@ -98,7 +102,7 @@ fn armor_desc(armor: &Armor, desc: &str, slots: u16) -> String { description } -fn tool_desc(tool: &Tool, desc: &str) -> String { +fn tool_desc(tool: &Tool, components: &[Item], desc: &str) -> String { let kind = match tool.kind { ToolKind::Sword => "Sword", ToolKind::Axe => "Axe", @@ -115,43 +119,39 @@ fn tool_desc(tool: &Tool, desc: &str) -> String { }; // Get tool stats - let power = tool.base_power(); + let power = tool.base_power(components); //let poise_strength = tool.base_poise_strength(); - let speed = tool.base_speed(); let hands = match tool.hands { Hands::One => "One", Hands::Two => "Two", }; + let speed = tool.base_speed(components); - if !desc.is_empty() { - format!( - "{}-Handed {}\n\nDPS: {:0.1}\n\nPower: {:0.1}\n\nSpeed: {:0.1}\n\n{}\n\n", - // add back when ready for poise - //"{}\n\nDPS: {:0.1}\n\nPower: {:0.1}\n\nPoise Strength: {:0.1}\n\nSpeed: \ - // {:0.1}\n\n{}\n\n", - hands, - kind, - speed * power * 10.0, // Damage per second - power * 10.0, - //poise_strength * 10.0, - speed, - desc - ) - } else { - format!( - "{}-Handed {}\n\nDPS: {:0.1}\n\nPower: {:0.1}\n\nSpeed: {:0.1}\n\n", - // add back when ready for poise - //"{}\n\nDPS: {:0.1}\n\nPower: {:0.1}\n\nPoise Strength: {:0.1}\n\nSpeed: \ - // {:0.1}\n\n", - hands, - kind, - speed * power * 10.0, // Damage per second - power * 10.0, - //poise_strength * 10.0, - speed - ) + let mut result = format!( + "{}-Handed {}\n\nDPS: {:0.1}\n\nPower: {:0.1}\n\nSpeed: {:0.1}\n\n", + // add back when ready for poise + //"{}\n\nDPS: {:0.1}\n\nPower: {:0.1}\n\nPoise Strength: {:0.1}\n\nSpeed: \ + // {:0.1}\n\n{}\n\n", + hands, + kind, + speed * power * 10.0, // Damage per second + power * 10.0, + //poise_strength * 10.0, + speed + ); + if !components.is_empty() { + result += "Made from:\n"; + for component in components { + result += component.name(); + result += "\n" + } + result += "\n"; } + if !desc.is_empty() { + result += &format!("{}\n\n", desc); + } + result += ""; + result } #[cfg(test)] From c489d095dfb712bcc9071b7a48779cac44c69061 Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Thu, 18 Feb 2021 17:22:15 -0500 Subject: [PATCH 2/2] Implement persistence for modular weapons. This stores the components as children of the item that contains them via the DB's `parent_container_item_id` feature, and ensures that things are loaded in a good order with breadth-first search. Squahed fixes: - Fix some constraint violations that occurred when swapping inventory items. - Comment out recipes for modular weapons. - Make update_item_at_slot_using_persistence_key and is_modular more idiomatic. - Add changelog entry. - Document `defer_foreign_keys` usage. --- CHANGELOG.md | 1 + common/src/comp/inventory/item/mod.rs | 54 +-- common/src/comp/inventory/loadout.rs | 20 + common/src/comp/inventory/mod.rs | 2 +- common/src/recipe.rs | 8 +- server/src/persistence/character.rs | 87 +++-- .../src/persistence/character/conversions.rs | 348 +++++++++++------- 7 files changed, 335 insertions(+), 185 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 019789c0c2..b5ab250558 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Basic NPC interaction - Lights in dungeons - Trading system (bound to the `R` key by default, currently only works with players) +- Support for modular weapons. ### Changed diff --git a/common/src/comp/inventory/item/mod.rs b/common/src/comp/inventory/item/mod.rs index 700b56767a..bc045dae59 100644 --- a/common/src/comp/inventory/item/mod.rs +++ b/common/src/comp/inventory/item/mod.rs @@ -240,13 +240,13 @@ impl ItemDef { } pub fn is_modular(&self) -> bool { - match &self.kind { - ItemKind::Tool(tool) => match tool.stats { - tool::StatKind::Direct { .. } => false, - tool::StatKind::Modular => true, - }, - _ => false, - } + matches!( + &self.kind, + ItemKind::Tool(tool::Tool { + stats: tool::StatKind::Modular, + .. + }) + ) } #[cfg(test)] @@ -372,25 +372,16 @@ impl Item { components.extend(input_components.iter().map(|comp| comp.duplicate())); } - let kind = inner_item.kind(); - let item_config = if let ItemKind::Tool(_) = kind { - Some(Box::new(ItemConfig::from(( - kind, - &*components, - &inner_item.ability_map, - )))) - } else { - None - }; - - Item { + let mut item = Item { item_id: Arc::new(AtomicCell::new(None)), amount: NonZeroU32::new(1).unwrap(), components, slots: vec![None; inner_item.slots as usize], item_def: inner_item, - item_config, - } + item_config: None, + }; + item.update_item_config(); + item } /// Creates a new instance of an `Item` from the provided asset identifier @@ -478,6 +469,27 @@ impl Item { } } + pub fn add_component(&mut self, component: Item) { + // 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(); + } + + fn update_item_config(&mut self) { + self.item_config = if let ItemKind::Tool(_) = self.kind() { + Some(Box::new(ItemConfig::from(( + self.kind(), + self.components(), + &self.item_def.ability_map, + )))) + } else { + None + }; + } + /// Returns an iterator that drains items contained within the item's slots pub fn drain(&mut self) -> impl Iterator + '_ { self.slots.iter_mut().filter_map(|x| mem::take(x)) diff --git a/common/src/comp/inventory/loadout.rs b/common/src/comp/inventory/loadout.rs index c79f8c4d21..aaf8581e78 100644 --- a/common/src/comp/inventory/loadout.rs +++ b/common/src/comp/inventory/loadout.rs @@ -46,6 +46,7 @@ pub(super) struct LoadoutSlotId { pub enum LoadoutError { InvalidPersistenceKey, + NoParentAtSlot, } impl Loadout { @@ -134,6 +135,25 @@ impl Loadout { } } + pub fn update_item_at_slot_using_persistence_key( + &mut self, + persistence_key: &str, + f: F, + ) -> Result<(), LoadoutError> { + self.slots + .iter_mut() + .find(|loadout_slot| loadout_slot.persistence_key == persistence_key) + .map_or(Err(LoadoutError::InvalidPersistenceKey), |loadout_slot| { + loadout_slot + .slot + .as_mut() + .map_or(Err(LoadoutError::NoParentAtSlot), |item| { + f(item); + Ok(()) + }) + }) + } + /// Swaps the contents of two loadout slots pub(super) fn swap_slots(&mut self, equip_slot_a: EquipSlot, equip_slot_b: EquipSlot) { if self.slot(equip_slot_b).is_none() || self.slot(equip_slot_b).is_none() { diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs index fd9f8af8be..2a7cf3713f 100644 --- a/common/src/comp/inventory/mod.rs +++ b/common/src/comp/inventory/mod.rs @@ -350,7 +350,7 @@ impl Inventory { } } - fn slot_mut(&mut self, inv_slot_id: InvSlotId) -> Option<&mut InvSlot> { + pub fn slot_mut(&mut self, inv_slot_id: InvSlotId) -> Option<&mut InvSlot> { match SlotId::from(inv_slot_id) { SlotId::Inventory(slot_idx) => self.slots.get_mut(slot_idx), SlotId::Loadout(loadout_slot_id) => self.loadout.inv_slot_mut(loadout_slot_id), diff --git a/common/src/recipe.rs b/common/src/recipe.rs index b998b443fd..f11b464d79 100644 --- a/common/src/recipe.rs +++ b/common/src/recipe.rs @@ -119,7 +119,13 @@ impl assets::Compound for RecipeBook { } let mut raw = cache.load::(specifier)?.read().clone(); - modular::append_modular_recipes(&mut raw); + + // Avoid showing purple-question-box recipes until the assets are added + // (the `if false` is needed because commenting out the call will add a warning + // that there are no other uses of append_modular_recipes) + if false { + modular::append_modular_recipes(&mut raw); + } let recipes = raw .0 diff --git a/server/src/persistence/character.rs b/server/src/persistence/character.rs index be5b993dd3..24cc6c85de 100644 --- a/server/src/persistence/character.rs +++ b/server/src/persistence/character.rs @@ -27,7 +27,7 @@ use crate::{ use common::character::{CharacterId, CharacterItem, MAX_CHARACTERS_PER_PLAYER}; use core::ops::Range; use diesel::{prelude::*, sql_query, sql_types::BigInt}; -use std::sync::Arc; +use std::{collections::VecDeque, sync::Arc}; use tracing::{error, trace, warn}; /// Private module for very tightly coupled database conversion methods. In @@ -50,6 +50,26 @@ struct CharacterContainers { loadout_container_id: EntityId, } +/// BFS the inventory/loadout to ensure that each is topologically sorted in the +/// sense required by convert_inventory_from_database_items to support recursive +/// items +pub fn load_items_bfs(connection: VelorenTransaction, root: i64) -> Result, Error> { + use schema::item::dsl::*; + let mut items = Vec::new(); + let mut queue = VecDeque::new(); + queue.push_front(root); + while let Some(id) = queue.pop_front() { + let frontier = item + .filter(parent_container_item_id.eq(id)) + .load::(&*connection)?; + for i in frontier.iter() { + queue.push_back(i.item_id); + } + items.extend(frontier); + } + Ok(items) +} + /// Load stored data for a character. /// /// After first logging in, and after a character is selected, we fetch this @@ -59,19 +79,12 @@ pub fn load_character_data( char_id: CharacterId, connection: VelorenTransaction, ) -> CharacterDataResult { - use schema::{body::dsl::*, character::dsl::*, item::dsl::*, skill_group::dsl::*}; + use schema::{body::dsl::*, character::dsl::*, skill_group::dsl::*}; let character_containers = get_pseudo_containers(connection, char_id)?; - // TODO: Make inventory and loadout item loading work with recursive items when - // container items are supported - let inventory_items = item - .filter(parent_container_item_id.eq(character_containers.inventory_container_id)) - .load::(&*connection)?; - - let loadout_items = item - .filter(parent_container_item_id.eq(character_containers.loadout_container_id)) - .load::(&*connection)?; + let inventory_items = load_items_bfs(connection, character_containers.inventory_container_id)?; + let loadout_items = load_items_bfs(connection, character_containers.loadout_container_id)?; let character_data = character .filter( @@ -109,7 +122,12 @@ pub fn load_character_data( Ok(( convert_body_from_database(&char_body)?, convert_stats_from_database(character_data.alias, &skill_data, &skill_group_data), - convert_inventory_from_database_items(&inventory_items, &loadout_items)?, + convert_inventory_from_database_items( + character_containers.inventory_container_id, + &inventory_items, + character_containers.loadout_container_id, + &loadout_items, + )?, char_waypoint, )) } @@ -125,7 +143,7 @@ pub fn load_character_list( player_uuid_: &str, connection: VelorenTransaction, ) -> CharacterListResult { - use schema::{body::dsl::*, character::dsl::*, item::dsl::*}; + use schema::{body::dsl::*, character::dsl::*}; let result = character .filter(player_uuid.eq(player_uuid_)) @@ -149,13 +167,10 @@ pub fn load_character_list( LOADOUT_PSEUDO_CONTAINER_POSITION, )?; - // TODO: Make work with recursive items if containers are ever supported as part - // of a loadout - let loadout_items = item - .filter(parent_container_item_id.eq(loadout_container_id)) - .load::(&*connection)?; + let loadout_items = load_items_bfs(connection, loadout_container_id)?; - let loadout = convert_loadout_from_database_items(&loadout_items)?; + let loadout = + convert_loadout_from_database_items(loadout_container_id, &loadout_items)?; Ok(CharacterItem { character: char, @@ -276,7 +291,7 @@ pub fn create_character( let mut inserts = Vec::new(); get_new_entity_ids(connection, |mut next_id| { - let (inserts_, _deletes) = convert_items_to_database_items( + let inserts_ = convert_items_to_database_items( loadout_container_id, &inventory, inventory_container_id, @@ -541,7 +556,7 @@ pub fn update( // First, get all the entity IDs for any new items, and identify which slots to // upsert and which ones to delete. get_new_entity_ids(connection, |mut next_id| { - let (upserts_, _deletes) = convert_items_to_database_items( + let upserts_ = convert_items_to_database_items( pseudo_containers.loadout_container_id, &inventory, pseudo_containers.inventory_container_id, @@ -553,9 +568,17 @@ pub fn update( // Next, delete any slots we aren't upserting. trace!("Deleting items for character_id {}", char_id); - let existing_items = parent_container_item_id - .eq(pseudo_containers.inventory_container_id) - .or(parent_container_item_id.eq(pseudo_containers.loadout_container_id)); + let mut existing_item_ids: Vec = vec![ + pseudo_containers.inventory_container_id, + pseudo_containers.loadout_container_id, + ]; + for it in load_items_bfs(connection, pseudo_containers.inventory_container_id)? { + existing_item_ids.push(it.item_id); + } + for it in load_items_bfs(connection, pseudo_containers.loadout_container_id)? { + existing_item_ids.push(it.item_id); + } + let existing_items = parent_container_item_id.eq_any(existing_item_ids); let non_upserted_items = item_id.ne_all( upserts .iter() @@ -573,7 +596,13 @@ pub fn update( if expected_upsert_count > 0 { let (upserted_items, upserted_comps_): (Vec<_>, Vec<_>) = upserts .into_iter() - .map(|model_pair| (model_pair.model, model_pair.comp)) + .map(|model_pair| { + debug_assert_eq!( + model_pair.model.item_id, + model_pair.comp.load().unwrap().get() as i64 + ); + (model_pair.model, model_pair.comp) + }) .unzip(); upserted_comps = upserted_comps_; trace!( @@ -582,9 +611,17 @@ pub fn update( char_id ); + // When moving inventory items around, foreign key constraints on + // `parent_container_item_id` can be temporarily violated by one upsert, but + // restored by another upsert. Deferred constraints allow SQLite to check this + // when committing the transaction. The `defer_foreign_keys` pragma treats the + // foreign key constraints as deferred for the next transaction (it turns itself + // off at the commit boundary). https://sqlite.org/foreignkeys.html#fk_deferred + connection.execute("PRAGMA defer_foreign_keys = ON;")?; let upsert_count = diesel::replace_into(item) .values(&upserted_items) .execute(&*connection)?; + trace!("upsert_count: {}", upsert_count); if upsert_count != expected_upsert_count { return Err(Error::OtherError(format!( "Expected upsertions={}, actual={}, for char_id {}--unsafe to continue \ diff --git a/server/src/persistence/character/conversions.rs b/server/src/persistence/character/conversions.rs index 77f8b67007..2cf8fa8932 100644 --- a/server/src/persistence/character/conversions.rs +++ b/server/src/persistence/character/conversions.rs @@ -21,16 +21,17 @@ use common::{ }; use core::{convert::TryFrom, num::NonZeroU64}; use hashbrown::HashMap; -use itertools::{Either, Itertools}; -use std::sync::Arc; +use std::{collections::VecDeque, sync::Arc}; +#[derive(Debug)] pub struct ItemModelPair { pub comp: Arc, pub model: Item, } -/// The left vector contains all item rows to upsert; the right-hand vector -/// contains all item rows to delete (by parent ID and position). +/// Returns a vector that contains all item rows to upsert; parent is +/// responsible for deleting items from the same owner that aren't affirmatively +/// kept by this. /// /// NOTE: This method does not yet handle persisting nested items within /// inventories. Although loadout items do store items inside them this does @@ -41,7 +42,7 @@ pub fn convert_items_to_database_items( inventory: &Inventory, inventory_container_id: EntityId, next_id: &mut i64, -) -> (Vec, Vec<(EntityId, String)>) { +) -> Vec { let loadout = inventory .loadout_items_with_persistence_key() .map(|(slot, item)| (slot.to_string(), item, loadout_container_id)); @@ -55,103 +56,125 @@ pub fn convert_items_to_database_items( ) }); - // Construct new items. - inventory.chain(loadout) - .partition_map(|(position, item, parent_container_item_id)| { - if let Some(item) = item { - // Try using the next available id in the sequence as the default for new items. - let new_item_id = NonZeroU64::new(u64::try_from(*next_id) - .expect("We are willing to crash if the next entity id overflows \ - (or is otherwise negative).")).expect("next_id should not be zero, either"); + // Use Breadth-first search to recurse into containers/modular weapons to store + // their parts + let mut bfs_queue: VecDeque<_> = inventory.chain(loadout).collect(); + let mut upserts = Vec::new(); + let mut depth = HashMap::new(); + depth.insert(inventory_container_id, 0); + depth.insert(loadout_container_id, 0); + while let Some((position, item, parent_container_item_id)) = bfs_queue.pop_front() { + // Construct new items. + if let Some(item) = item { + // Try using the next available id in the sequence as the default for new items. + let new_item_id = NonZeroU64::new(u64::try_from(*next_id).expect( + "We are willing to crash if the next entity id overflows (or is otherwise \ + negative).", + )) + .expect("next_id should not be zero, either"); - let comp = item.get_item_id_for_database(); - Either::Left(ItemModelPair { - model: Item { - item_definition_id: item.item_definition_id().to_owned(), - position, - parent_container_item_id, - // Fast (kinda) path: acquire read for the common case where an id has - // already been assigned. - item_id: comp.load() - // First, we filter out "impossible" entity IDs--IDs that are larger - // than the maximum sequence value (next_id). This is important - // because we update the item ID atomically, *before* we know whether - // this transaction has completed successfully, and we don't abort the - // process on a failed transaction. In such cases, new IDs from - // aborted transactions will show up as having a higher value than the - // current max sequence number. Because the only place that modifies - // the item_id through a shared reference is (supposed to be) this - // function, which is part of the batch update transaction, we can - // assume that any rollback during the update would fail to insert - // *any* new items for the current character; this means that any items - // inserted between the failure and now (i.e. values less than next_id) - // would either not be items at all, or items belonging to other - // characters, leading to an easily detectable SQLite failure that we - // can use to atomically set the id back to None (if it was still the - // same bad value). - // - // Note that this logic only requires that all the character's items be - // updated within the same serializable transaction; the argument does - // not depend on SQLite-specific details (like locking) or on the fact - // that a user's transactions are always serialized on their own - // session. Also note that since these IDs are in-memory, we don't - // have to worry about their values during, e.g., a process crash; - // serializability will take care of us in those cases. Finally, note - // that while we have not yet implemented the "liveness" part of the - // algorithm (resetting ids back to None if we detect errors), this is - // not needed for soundness, and this part can be deferred until we - // switch to an execution model where such races are actually possible - // during normal gameplay. - .and_then(|item_id| Some(if item_id >= new_item_id { - // Try to atomically exchange with our own, "correct" next id. - match comp.compare_exchange(Some(item_id), Some(new_item_id)) { - Ok(_) => { - let item_id = *next_id; - // We won the race, use next_id and increment it. - *next_id += 1; - item_id - }, - Err(item_id) => { - // We raced with someone, and they won the race, so we know - // this transaction must abort unless they finish first. So, - // just assume they will finish first, and use their assigned - // item_id. - EntityId::try_from(item_id?.get()) - .expect("We always choose legal EntityIds as item ids") - }, - } - } else { EntityId::try_from(item_id.get()).expect("We always choose legal EntityIds as item ids") })) - // Finally, we're in the case where no entity was assigned yet (either - // ever, or due to corrections after a rollback). This proceeds - // identically to the "impossible ID" case. - .unwrap_or_else(|| { - // Try to atomically compare with the empty id. - match comp.compare_exchange(None, Some(new_item_id)) { - Ok(_) => { - let item_id = *next_id; - *next_id += 1; - item_id - }, - Err(item_id) => { - EntityId::try_from(item_id.expect("TODO: Fix handling of reset to None when we have concurrent writers.").get()) - .expect("We always choose legal EntityIds as item ids") - }, - } - }), - stack_size: if item.is_stackable() { - item.amount() as i32 - } else { - 1 + // Fast (kinda) path: acquire read for the common case where an id has + // already been assigned. + let comp = item.get_item_id_for_database(); + let item_id = comp.load() + // First, we filter out "impossible" entity IDs--IDs that are larger + // than the maximum sequence value (next_id). This is important + // because we update the item ID atomically, *before* we know whether + // this transaction has completed successfully, and we don't abort the + // process on a failed transaction. In such cases, new IDs from + // aborted transactions will show up as having a higher value than the + // current max sequence number. Because the only place that modifies + // the item_id through a shared reference is (supposed to be) this + // function, which is part of the batch update transaction, we can + // assume that any rollback during the update would fail to insert + // *any* new items for the current character; this means that any items + // inserted between the failure and now (i.e. values less than next_id) + // would either not be items at all, or items belonging to other + // characters, leading to an easily detectable SQLite failure that we + // can use to atomically set the id back to None (if it was still the + // same bad value). + // + // Note that this logic only requires that all the character's items be + // updated within the same serializable transaction; the argument does + // not depend on SQLite-specific details (like locking) or on the fact + // that a user's transactions are always serialized on their own + // session. Also note that since these IDs are in-memory, we don't + // have to worry about their values during, e.g., a process crash; + // serializability will take care of us in those cases. Finally, note + // that while we have not yet implemented the "liveness" part of the + // algorithm (resetting ids back to None if we detect errors), this is + // not needed for soundness, and this part can be deferred until we + // switch to an execution model where such races are actually possible + // during normal gameplay. + .and_then(|item_id| Some(if item_id >= new_item_id { + // Try to atomically exchange with our own, "correct" next id. + match comp.compare_exchange(Some(item_id), Some(new_item_id)) { + Ok(_) => { + let item_id = *next_id; + // We won the race, use next_id and increment it. + *next_id += 1; + item_id }, - }, - // Continue to remember the atomic, in case we detect an error later and want - // to roll back to preserve liveness. - comp, - }) - } else { - Either::Right((parent_container_item_id, position)) + Err(item_id) => { + // We raced with someone, and they won the race, so we know + // this transaction must abort unless they finish first. So, + // just assume they will finish first, and use their assigned + // item_id. + EntityId::try_from(item_id?.get()) + .expect("We always choose legal EntityIds as item ids") + }, + } + } else { EntityId::try_from(item_id.get()).expect("We always choose legal EntityIds as item ids") })) + // Finally, we're in the case where no entity was assigned yet (either + // ever, or due to corrections after a rollback). This proceeds + // identically to the "impossible ID" case. + .unwrap_or_else(|| { + // Try to atomically compare with the empty id. + match comp.compare_exchange(None, Some(new_item_id)) { + Ok(_) => { + let item_id = *next_id; + *next_id += 1; + item_id + }, + Err(item_id) => { + EntityId::try_from(item_id.expect("TODO: Fix handling of reset to None when we have concurrent writers.").get()) + .expect("We always choose legal EntityIds as item ids") + }, + } + }); + + depth.insert(item_id, depth[&parent_container_item_id] + 1); + + for (i, component) in item.components().iter().enumerate() { + // recursive items' children have the same position as their parents, and since + // they occur afterwards in the topological sort of the parent graph (which + // should still always be a tree, even with recursive items), we + // have enough information to put them back into their parents on load + bfs_queue.push_back((format!("component_{}", i), Some(component), item_id)); } - }) + + let upsert = ItemModelPair { + model: Item { + item_definition_id: item.item_definition_id().to_owned(), + position, + parent_container_item_id, + item_id, + stack_size: if item.is_stackable() { + item.amount() as i32 + } else { + 1 + }, + }, + // Continue to remember the atomic, in case we detect an error later and want + // to roll back to preserve liveness. + comp, + }; + upserts.push(upsert); + } + } + upserts.sort_by_key(|pair| (depth[&pair.model.item_id], pair.model.item_id)); + tracing::debug!("upserts: {:#?}", upserts); + upserts } pub fn convert_body_to_database_json(body: &CompBody) -> Result { @@ -192,23 +215,30 @@ pub fn convert_waypoint_from_database_json(position: &str) -> Result Result { // Loadout items must be loaded before inventory items since loadout items // provide inventory slots. Since items stored inside loadout items actually // have their parent_container_item_id as the loadout pseudo-container we rely // on populating the loadout items first, and then inserting the items into the - // inventory at the correct position. When we want to support items inside the - // player's inventory containing other items (such as "right click to - // unwrap" gifts perhaps) then we will need to refactor inventory/loadout - // persistence to traverse the tree of items and load them from the root - // down. - let loadout = convert_loadout_from_database_items(loadout_items)?; + // inventory at the correct position. + // + let loadout = convert_loadout_from_database_items(loadout_container_id, loadout_items)?; let mut inventory = Inventory::new_with_loadout(loadout); + let mut item_indices = HashMap::new(); + + for (i, db_item) in inventory_items.iter().enumerate() { + item_indices.insert(db_item.item_id, i); - for db_item in inventory_items.iter() { let mut item = get_item_from_asset(db_item.item_definition_id.as_str())?; // NOTE: Since this is freshly loaded, the atomic is *unique.* @@ -234,55 +264,99 @@ pub fn convert_inventory_from_database_items( // Insert item into inventory // Slot position - let slot: InvSlotId = serde_json::from_str(&db_item.position).map_err(|_| { - Error::ConversionError(format!( - "Failed to parse item position: {:?}", - &db_item.position - )) - })?; + let slot = |s: &str| { + serde_json::from_str::(s).map_err(|_| { + Error::ConversionError(format!( + "Failed to parse item position: {:?}", + &db_item.position + )) + }) + }; - let insert_res = inventory.insert_at(slot, item).map_err(|_| { - // If this happens there were too many items in the database for the current - // inventory size - Error::ConversionError(format!( - "Error inserting item into inventory, position: {:?}", - slot - )) - })?; + if db_item.parent_container_item_id == inventory_container_id { + let slot = slot(&db_item.position)?; + let insert_res = inventory.insert_at(slot, item).map_err(|_| { + // If this happens there were too many items in the database for the current + // inventory size + Error::ConversionError(format!( + "Error inserting item into inventory, position: {:?}", + slot + )) + })?; - if insert_res.is_some() { - // If inventory.insert returns an item, it means it was swapped for an item that - // already occupied the slot. Multiple items being stored in the database for - // the same slot is an error. - return Err(Error::ConversionError( - "Inserted an item into the same slot twice".to_string(), - )); + if insert_res.is_some() { + // If inventory.insert returns an item, it means it was swapped for an item that + // already occupied the slot. Multiple items being stored in the database for + // the same slot is an error. + return Err(Error::ConversionError( + "Inserted an item into the same slot twice".to_string(), + )); + } + } 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); + } else { + return Err(Error::ConversionError(format!( + "Parent slot {} for component {} was empty even though it occurred earlier in \ + the loop?", + db_item.parent_container_item_id, db_item.item_id + ))); + } + } else { + return Err(Error::ConversionError(format!( + "Couldn't find parent item {} before item {} in inventory", + db_item.parent_container_item_id, db_item.item_id + ))); } } Ok(inventory) } -pub fn convert_loadout_from_database_items(database_items: &[Item]) -> Result { +pub fn convert_loadout_from_database_items( + loadout_container_id: i64, + database_items: &[Item], +) -> Result { let loadout_builder = LoadoutBuilder::new(); let mut loadout = loadout_builder.build(); + let mut item_indices = HashMap::new(); + + for (i, db_item) in database_items.iter().enumerate() { + item_indices.insert(db_item.item_id, i); - for db_item in database_items.iter() { let item = get_item_from_asset(db_item.item_definition_id.as_str())?; + // NOTE: item id is currently *unique*, so we can store the ID safely. let comp = item.get_item_id_for_database(); comp.store(Some(NonZeroU64::try_from(db_item.item_id as u64).map_err( |_| Error::ConversionError("Item with zero item_id".to_owned()), )?)); - loadout - .set_item_at_slot_using_persistence_key(&db_item.position, item) - .map_err(|err| match err { - LoadoutError::InvalidPersistenceKey => Error::ConversionError(format!( - "Invalid persistence key: {}", - &db_item.position - )), - })?; + let convert_error = |err| match err { + LoadoutError::InvalidPersistenceKey => { + Error::ConversionError(format!("Invalid persistence key: {}", &db_item.position)) + }, + LoadoutError::NoParentAtSlot => { + Error::ConversionError(format!("No parent item at slot: {}", &db_item.position)) + }, + }; + + if db_item.parent_container_item_id == loadout_container_id { + loadout + .set_item_at_slot_using_persistence_key(&db_item.position, item) + .map_err(convert_error)?; + } 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); + }) + .map_err(convert_error)?; + } else { + return Err(Error::ConversionError(format!( + "Couldn't find parent item {} before item {} in loadout", + db_item.parent_container_item_id, db_item.item_id + ))); + } } Ok(loadout)