diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index f9b6903e87..d7508f36f7 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -1,5 +1,5 @@ use crate::{ - comp::{CharacterState, ToolData}, + comp::{CharacterState, Item, ToolData}, states::*, }; use specs::{Component, DenseVecStorage, FlaggedStorage, HashMapStorage}; @@ -25,12 +25,20 @@ impl Component for CharacterAbility { type Storage = DenseVecStorage; } -#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)] -pub struct AbilityPool { - pub primary: Option, - pub secondary: Option, - pub block: Option, - pub dodge: Option, +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ItemConfig { + pub item: Item, + pub primary_ability: Option, + pub secondary_ability: Option, + pub block_ability: Option, + pub dodge_ability: Option, +} + +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +pub struct Loadout { + pub active_item: Option, + pub second_item: Option, + // armor } impl From for CharacterState { @@ -69,6 +77,6 @@ impl From for CharacterState { } } -impl Component for AbilityPool { +impl Component for Loadout { type Storage = FlaggedStorage>; } diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index 3c92f65890..bbc3242743 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -95,7 +95,7 @@ impl Component for CharacterState { #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] pub struct Attacking { - pub weapon: Option, + pub base_damage: u32, pub applied: bool, pub hit_count: u32, } diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs index 2835d480d0..9f07d6a3b3 100644 --- a/common/src/comp/inventory/item.rs +++ b/common/src/comp/inventory/item.rs @@ -127,8 +127,8 @@ pub struct ToolData { equip_time_millis: u64, attack_buildup_millis: u64, attack_recover_millis: u64, - range: u64, - pub base_damage: u64, + range: u32, + pub base_damage: u32, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 8a6fe50631..34ee837944 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -16,7 +16,7 @@ mod stats; mod visual; // Reexports -pub use ability::{AbilityPool, CharacterAbility}; +pub use ability::{CharacterAbility, ItemConfig, Loadout}; pub use admin::Admin; pub use agent::{Agent, Alignment}; pub use body::{ @@ -39,5 +39,5 @@ pub use location::{Waypoint, WaypointArea}; pub use phys::{ForceUpdate, Gravity, Mass, Ori, PhysicsState, Pos, Scale, Sticky, Vel}; pub use player::Player; pub use projectile::Projectile; -pub use stats::{Equipment, Exp, HealthChange, HealthSource, Level, Stats}; +pub use stats::{Exp, HealthChange, HealthSource, Level, Stats}; pub use visual::LightEmitter; diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index aaa768fee3..d60e2d45dd 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -42,13 +42,6 @@ pub struct Level { amount: u32, } -#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -pub struct Equipment { - pub main: Option, - pub alt: Option, - // TODO: Armor -} - impl Health { pub fn current(&self) -> u32 { self.current } @@ -125,7 +118,6 @@ pub struct Stats { pub health: Health, pub level: Level, pub exp: Exp, - pub equipment: Equipment, pub endurance: u32, pub fitness: u32, pub willpower: u32, @@ -178,7 +170,6 @@ impl Stats { current: 0, maximum: 50, }, - equipment: Equipment { main, alt: None }, endurance, fitness, willpower, diff --git a/common/src/msg/ecs_packet.rs b/common/src/msg/ecs_packet.rs index f0135dd3c4..4034c6b953 100644 --- a/common/src/msg/ecs_packet.rs +++ b/common/src/msg/ecs_packet.rs @@ -22,7 +22,7 @@ sum_type! { Gravity(comp::Gravity), Sticky(comp::Sticky), CharacterAbility(comp::CharacterAbility), - AbilityPool(comp::AbilityPool), + Loadout(comp::Loadout), Attacking(comp::Attacking), CharacterState(comp::CharacterState), } @@ -46,7 +46,7 @@ sum_type! { Gravity(PhantomData), Sticky(PhantomData), CharacterAbility(PhantomData), - AbilityPool(PhantomData), + Loadout(PhantomData), Attacking(PhantomData), CharacterState(PhantomData), } @@ -70,7 +70,7 @@ impl sync::CompPacket for EcsCompPacket { EcsCompPacket::Gravity(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Sticky(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::CharacterAbility(comp) => sync::handle_insert(comp, entity, world), - EcsCompPacket::AbilityPool(comp) => sync::handle_insert(comp, entity, world), + EcsCompPacket::Loadout(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::Attacking(comp) => sync::handle_insert(comp, entity, world), EcsCompPacket::CharacterState(comp) => sync::handle_insert(comp, entity, world), } @@ -92,7 +92,7 @@ impl sync::CompPacket for EcsCompPacket { EcsCompPacket::Gravity(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Sticky(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::CharacterAbility(comp) => sync::handle_modify(comp, entity, world), - EcsCompPacket::AbilityPool(comp) => sync::handle_modify(comp, entity, world), + EcsCompPacket::Loadout(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::Attacking(comp) => sync::handle_modify(comp, entity, world), EcsCompPacket::CharacterState(comp) => sync::handle_modify(comp, entity, world), } @@ -118,9 +118,7 @@ impl sync::CompPacket for EcsCompPacket { EcsCompPhantom::CharacterAbility(_) => { sync::handle_remove::(entity, world) }, - EcsCompPhantom::AbilityPool(_) => { - sync::handle_remove::(entity, world) - }, + EcsCompPhantom::Loadout(_) => sync::handle_remove::(entity, world), EcsCompPhantom::Attacking(_) => sync::handle_remove::(entity, world), EcsCompPhantom::CharacterState(_) => { sync::handle_remove::(entity, world) diff --git a/common/src/state.rs b/common/src/state.rs index 5fdbc211f6..d2b8386304 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -106,7 +106,7 @@ impl State { // Uids for sync ecs.register_sync_marker(); // Register server -> all clients synced components. - ecs.register::(); + ecs.register::(); ecs.register::(); ecs.register::(); ecs.register::(); diff --git a/common/src/states/basic_attack.rs b/common/src/states/basic_attack.rs index f8d2ba5230..64846659ba 100644 --- a/common/src/states/basic_attack.rs +++ b/common/src/states/basic_attack.rs @@ -29,9 +29,8 @@ impl CharacterBehavior for Data { handle_move(data, &mut update); - // Build up window + // Build up if self.buildup_duration != Duration::default() { - // Start to swing update.character = CharacterState::BasicAttack(Data { buildup_duration: self .buildup_duration @@ -41,12 +40,11 @@ impl CharacterBehavior for Data { exhausted: false, }); } - // Hit attempt window + // Hit attempt else if !self.exhausted { - // Swing hits if let Some(tool) = unwrap_tool_data(data) { data.updater.insert(data.entity, Attacking { - weapon: Some(tool), + base_damage: tool.base_damage, applied: false, hit_count: 0, }); @@ -58,7 +56,7 @@ impl CharacterBehavior for Data { exhausted: true, }); } - // Swing recovery window + // Recovery else if self.recover_duration != Duration::default() { update.character = CharacterState::BasicAttack(Data { buildup_duration: self.buildup_duration, @@ -79,7 +77,8 @@ impl CharacterBehavior for Data { update.character = CharacterState::Idle; } } - // Subtract energy on successful hit + + // Grant energy on successful hit if let Some(attack) = data.attacking { if attack.applied && attack.hit_count > 0 { data.updater.remove::(data.entity); diff --git a/common/src/states/timed_combo.rs b/common/src/states/timed_combo.rs index 6c8ad42e6c..4467ce7173 100644 --- a/common/src/states/timed_combo.rs +++ b/common/src/states/timed_combo.rs @@ -62,7 +62,7 @@ impl CharacterBehavior for Data { else if !self.stage_exhausted { // Swing hits data.updater.insert(data.entity, Attacking { - weapon: Some(self.tool), + base_damage: self.tool.base_damage, applied: false, hit_count: 0, }); diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index a0f83674a3..169611a8cc 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -119,7 +119,7 @@ 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(Tool(tool)) = data.stats.equipment.main.as_ref().map(|i| i.kind) { + if let Some(Tool(tool)) = data.loadout.active_item.as_ref().map(|i| i.item.kind) { update.character = CharacterState::Equipping(equipping::Data { tool, time_left: tool.equip_time(), @@ -192,7 +192,12 @@ pub fn handle_primary_input(data: &JoinData, update: &mut StateUpdate) { /// Attempts to go into `ability_pool.primary` if is `Some()` on `AbilityPool` pub fn attempt_primary_ability(data: &JoinData, update: &mut StateUpdate) { - if let Some(ability) = data.ability_pool.primary { + if let Some(ability) = data + .loadout + .active_item + .as_ref() + .and_then(|i| i.primary_ability) + { update.character = ability.into(); } } @@ -209,7 +214,12 @@ pub fn handle_secondary_input(data: &JoinData, update: &mut StateUpdate) { /// Attempts to go into `ability_pool.secondary` if is `Some()` on `AbilityPool` pub fn attempt_secondary_ability(data: &JoinData, update: &mut StateUpdate) { - if let Some(ability) = data.ability_pool.secondary { + if let Some(ability) = data + .loadout + .active_item + .as_ref() + .and_then(|i| i.secondary_ability) + { update.character = ability.into(); } } @@ -233,13 +243,18 @@ pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) { } pub fn attempt_dodge_ability(data: &JoinData, update: &mut StateUpdate) { - if let Some(ability) = data.ability_pool.dodge { + if let Some(ability) = data + .loadout + .active_item + .as_ref() + .and_then(|i| i.dodge_ability) + { update.character = ability.into(); } } pub fn unwrap_tool_data(data: &JoinData) -> Option { - if let Some(Tool(tool)) = data.stats.equipment.main.as_ref().map(|i| i.kind) { + if let Some(Tool(tool)) = data.loadout.active_item.as_ref().map(|i| i.item.kind) { Some(tool) } else { None diff --git a/common/src/sys/character_behavior.rs b/common/src/sys/character_behavior.rs index e35bfbbb10..2309e7a579 100644 --- a/common/src/sys/character_behavior.rs +++ b/common/src/sys/character_behavior.rs @@ -1,7 +1,7 @@ use crate::{ comp::{ - AbilityPool, Attacking, Body, CharacterState, Controller, ControllerInputs, Energy, - Mounting, Ori, PhysicsState, Pos, StateUpdate, Stats, Vel, + Attacking, Body, CharacterState, Controller, ControllerInputs, Energy, Loadout, Mounting, + Ori, PhysicsState, Pos, StateUpdate, Stats, Vel, }, event::{EventBus, LocalEvent, ServerEvent}, state::DeltaTime, @@ -33,7 +33,7 @@ pub struct JoinData<'a> { pub energy: &'a Energy, pub body: &'a Body, pub physics: &'a PhysicsState, - pub ability_pool: &'a AbilityPool, + pub loadout: &'a Loadout, pub attacking: Option<&'a Attacking>, pub updater: &'a LazyUpdate, } @@ -50,7 +50,7 @@ pub type JoinTuple<'a> = ( &'a Stats, &'a Body, &'a PhysicsState, - &'a AbilityPool, + &'a Loadout, Option<&'a Attacking>, ); @@ -69,7 +69,7 @@ impl<'a> JoinData<'a> { stats: j.8, body: j.9, physics: j.10, - ability_pool: j.11, + loadout: j.11, attacking: j.12, updater, dt, @@ -102,7 +102,7 @@ impl<'a> System<'a> for Sys { ReadStorage<'a, Stats>, ReadStorage<'a, Body>, ReadStorage<'a, PhysicsState>, - ReadStorage<'a, AbilityPool>, + ReadStorage<'a, Loadout>, ReadStorage<'a, Attacking>, ReadStorage<'a, Uid>, ReadStorage<'a, Mounting>, @@ -126,7 +126,7 @@ impl<'a> System<'a> for Sys { stats, bodies, physics_states, - ability_pools, + loadouts, attacking_storage, uids, mountings, @@ -144,7 +144,7 @@ impl<'a> System<'a> for Sys { &stats, &bodies, &physics_states, - &ability_pools, + &loadouts, attacking_storage.maybe(), ) .join(); diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index b811beb991..0ee15f7211 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -104,19 +104,19 @@ impl<'a> System<'a> for Sys { && ori2.angle_between(pos_b2 - pos2) < ATTACK_ANGLE.to_radians() / 2.0 + (rad_b / pos2.distance(pos_b2)).atan() { // Weapon gives base damage - let mut dmg = attack.weapon.map(|w| w.base_damage as i32).unwrap_or(3); + let mut dmg = attack.base_damage; // Block if character_b.is_block() && ori_b.0.angle_between(pos.0 - pos_b.0) < BLOCK_ANGLE.to_radians() / 2.0 { - dmg = (dmg as f32 * (1.0 - BLOCK_EFFICIENCY)) as i32 + dmg = (dmg as f32 * (1.0 - BLOCK_EFFICIENCY)) as u32 } server_bus.emitter().emit(ServerEvent::Damage { uid: *uid_b, change: HealthChange { - amount: -dmg, + amount: -(dmg as i32), cause: HealthSource::Attack { by: *uid }, }, }); diff --git a/server/src/events/inventory_manip.rs b/server/src/events/inventory_manip.rs index 09998ca6aa..2023bec217 100644 --- a/server/src/events/inventory_manip.rs +++ b/server/src/events/inventory_manip.rs @@ -83,22 +83,6 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv if let Some(item) = item_opt { match item.kind { - comp::ItemKind::Tool { .. } => { - if let Some(stats) = - state.ecs().write_storage::().get_mut(entity) - { - // Insert old item into inventory - if let Some(old_item) = stats.equipment.main.take() { - state - .ecs() - .write_storage::() - .get_mut(entity) - .map(|inv| inv.insert(slot, old_item)); - } - - stats.equipment.main = Some(item); - } - }, comp::ItemKind::Consumable { kind, effect } => { event = comp::InventoryUpdateEvent::Consumed(kind); state.apply_effect(entity, effect); diff --git a/server/src/lib.rs b/server/src/lib.rs index ebe6dd8d84..213f837831 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -289,21 +289,21 @@ impl Server { state.write_component( entity, - if let Some(comp::Item { - kind: comp::ItemKind::Tool(tool), - .. - }) = main - { + if let Some(comp::ItemKind::Tool(tool)) = main.as_ref().map(|i| i.kind) { let mut abilities = tool.get_abilities(); let mut ability_drain = abilities.drain(..); - comp::AbilityPool { - primary: ability_drain.next(), - secondary: ability_drain.next(), - block: Some(comp::CharacterAbility::BasicBlock), - dodge: Some(comp::CharacterAbility::Roll), + comp::Loadout { + active_item: main.map(|item| comp::ItemConfig { + item, + primary_ability: ability_drain.next(), + secondary_ability: ability_drain.next(), + block_ability: Some(comp::CharacterAbility::BasicBlock), + dodge_ability: Some(comp::CharacterAbility::Roll), + }), + second_item: None, } } else { - comp::AbilityPool::default() + comp::Loadout::default() }, ); @@ -676,7 +676,7 @@ impl StateExt for State { .with(comp::Energy::new(500)) .with(comp::Gravity(1.0)) .with(comp::CharacterState::default()) - .with(comp::AbilityPool::default()) + .with(comp::Loadout::default()) // TODO Give the poor npc something to do } fn notify_registered_clients(&self, msg: ServerMsg) { diff --git a/server/src/sys/sentinel.rs b/server/src/sys/sentinel.rs index f48f8a9f59..382e1aa27c 100644 --- a/server/src/sys/sentinel.rs +++ b/server/src/sys/sentinel.rs @@ -1,7 +1,7 @@ use super::SysTimer; use common::{ comp::{ - AbilityPool, Body, CanBuild, CharacterState, Energy, Gravity, Item, LightEmitter, Mass, + Body, CanBuild, CharacterState, Energy, Gravity, Item, LightEmitter, Loadout, Mass, MountState, Mounting, Player, Scale, Stats, Sticky, }, msg::EcsCompPacket, @@ -51,7 +51,7 @@ pub struct TrackedComps<'a> { pub mass: ReadStorage<'a, Mass>, pub sticky: ReadStorage<'a, Sticky>, pub gravity: ReadStorage<'a, Gravity>, - pub ability_pool: ReadStorage<'a, AbilityPool>, + pub loadout: ReadStorage<'a, Loadout>, pub character_state: ReadStorage<'a, CharacterState>, } impl<'a> TrackedComps<'a> { @@ -106,9 +106,9 @@ impl<'a> TrackedComps<'a> { .get(entity) .copied() .map(|c| comps.push(c.into())); - self.ability_pool + self.loadout .get(entity) - .copied() + .cloned() .map(|c| comps.push(c.into())); self.character_state .get(entity) @@ -134,7 +134,7 @@ pub struct ReadTrackers<'a> { pub mass: ReadExpect<'a, UpdateTracker>, pub sticky: ReadExpect<'a, UpdateTracker>, pub gravity: ReadExpect<'a, UpdateTracker>, - pub ability_pool: ReadExpect<'a, UpdateTracker>, + pub loadout: ReadExpect<'a, UpdateTracker>, pub character_state: ReadExpect<'a, UpdateTracker>, } impl<'a> ReadTrackers<'a> { @@ -163,7 +163,7 @@ impl<'a> ReadTrackers<'a> { .with_component(&comps.uid, &*self.mass, &comps.mass, filter) .with_component(&comps.uid, &*self.sticky, &comps.sticky, filter) .with_component(&comps.uid, &*self.gravity, &comps.gravity, filter) - .with_component(&comps.uid, &*self.ability_pool, &comps.ability_pool, filter) + .with_component(&comps.uid, &*self.loadout, &comps.loadout, filter) .with_component( &comps.uid, &*self.character_state, @@ -189,7 +189,7 @@ pub struct WriteTrackers<'a> { mass: WriteExpect<'a, UpdateTracker>, sticky: WriteExpect<'a, UpdateTracker>, gravity: WriteExpect<'a, UpdateTracker>, - ability_pool: WriteExpect<'a, UpdateTracker>, + loadout: WriteExpect<'a, UpdateTracker>, character_state: WriteExpect<'a, UpdateTracker>, } @@ -209,7 +209,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) { trackers.mass.record_changes(&comps.mass); trackers.sticky.record_changes(&comps.sticky); trackers.gravity.record_changes(&comps.gravity); - trackers.ability_pool.record_changes(&comps.ability_pool); + trackers.loadout.record_changes(&comps.loadout); trackers .character_state .record_changes(&comps.character_state); @@ -230,7 +230,7 @@ pub fn register_trackers(world: &mut World) { world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); - world.register_tracker::(); + world.register_tracker::(); world.register_tracker::(); } diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index 2ca9c72912..f646795e9a 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -180,7 +180,17 @@ impl<'a> System<'a> for Sys { .choose(&mut rand::thread_rng()) .expect("SPAWN_NPCS is nonempty")( ); - let mut stats = comp::Stats::new(name, body, main); + let mut stats = comp::Stats::new(name, body, main.clone()); + let mut loadout = comp::Loadout { + active_item: main.map(|item| comp::ItemConfig { + item, + primary_ability: None, + secondary_ability: None, + block_ability: None, + dodge_ability: None, + }), + second_item: None, + }; let mut scale = 1.0; @@ -202,6 +212,17 @@ impl<'a> System<'a> for Sys { Some(assets::load_expect_cloned("common.items.weapons.hammer_1")), ); } + loadout = comp::Loadout { + active_item: Some(comp::ItemConfig { + item: assets::load_expect_cloned("common.items.weapons.hammer_1"), + primary_ability: None, + secondary_ability: None, + block_ability: None, + dodge_ability: None, + }), + second_item: None, + }; + stats.level.set_level(rand::thread_rng().gen_range(8, 15)); scale = 2.0 + rand::random::(); } @@ -210,12 +231,10 @@ impl<'a> System<'a> for Sys { stats .health .set_to(stats.health.maximum(), comp::HealthSource::Revive); - if let Some(item::Item { - kind: item::ItemKind::Tool(item::ToolData { base_damage, .. }), - .. - }) = &mut stats.equipment.main + if let Some(item::ItemKind::Tool(item::ToolData { base_damage, .. })) = + &mut loadout.active_item.map(|i| i.item.kind) { - *base_damage = stats.level.level() as u64 * 3; + *base_damage = stats.level.level() as u32 * 3; } server_emitter.emit(ServerEvent::CreateNpc { pos: Pos(entity.pos), diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index f5a0a89ad8..0cf8986a7f 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -1659,22 +1659,25 @@ impl Hud { // Skillbar // Get player stats let ecs = client.state().ecs(); - let stats = ecs.read_storage::(); - let energy = ecs.read_storage::(); - let character_state = ecs.read_storage::(); let entity = client.entity(); - let controller = ecs.read_storage::(); - if let (Some(stats), Some(energy), Some(character_state), Some(controller)) = ( + let stats = ecs.read_storage::(); + let loadouts = ecs.read_storage::(); + let energies = ecs.read_storage::(); + let character_states = ecs.read_storage::(); + let controllers = ecs.read_storage::(); + if let (Some(stats), Some(loadout), Some(energy), Some(character_state), Some(controller)) = ( stats.get(entity), - energy.get(entity), - character_state.get(entity), - controller.get(entity).map(|c| &c.inputs), + loadouts.get(entity), + energies.get(entity), + character_states.get(entity), + controllers.get(entity).map(|c| &c.inputs), ) { Skillbar::new( global_state, &self.imgs, &self.fonts, &stats, + &loadout, &energy, &character_state, self.pulse, diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 8df29bac07..98414df9a6 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -11,7 +11,7 @@ use common::{ assets::load_expect, comp::{ item::{DebugKind, ToolData, ToolKind}, - CharacterState, ControllerInputs, Energy, ItemKind, Stats, + CharacterState, ControllerInputs, Energy, ItemKind, Loadout, Stats, }, }; use conrod_core::{ @@ -111,6 +111,7 @@ pub struct Skillbar<'a> { imgs: &'a Imgs, fonts: &'a ConrodVoxygenFonts, stats: &'a Stats, + loadout: &'a Loadout, energy: &'a Energy, character_state: &'a CharacterState, controller: &'a ControllerInputs, @@ -126,6 +127,7 @@ impl<'a> Skillbar<'a> { imgs: &'a Imgs, fonts: &'a ConrodVoxygenFonts, stats: &'a Stats, + loadout: &'a Loadout, energy: &'a Energy, character_state: &'a CharacterState, pulse: f32, @@ -136,6 +138,7 @@ impl<'a> Skillbar<'a> { imgs, fonts, stats, + loadout, energy, current_resource: ResourceType::Mana, common: widget::CommonBuilder::default(), @@ -580,44 +583,52 @@ impl<'a> Widget for Skillbar<'a> { // M1 Slot Image::new(self.imgs.skillbar_slot_big_bg) .w_h(38.0 * scale, 38.0 * scale) - .color(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { - Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { - ToolKind::Bow => Some(BG_COLOR_2), - ToolKind::Staff => Some(BG_COLOR_2), + .color( + match self.loadout.active_item.as_ref().map(|i| &i.item.kind) { + Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { + ToolKind::Bow => Some(BG_COLOR_2), + ToolKind::Staff => Some(BG_COLOR_2), + _ => Some(BG_COLOR_2), + }, _ => Some(BG_COLOR_2), }, - _ => Some(BG_COLOR_2), - }) + ) .middle_of(state.ids.m1_slot) .set(state.ids.m1_slot_bg, ui); - Button::image(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { - Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { - ToolKind::Sword(_) => self.imgs.twohsword_m1, - ToolKind::Hammer => self.imgs.twohhammer_m1, - ToolKind::Axe => self.imgs.twohaxe_m1, - ToolKind::Bow => self.imgs.bow_m1, - ToolKind::Staff => self.imgs.staff_m1, - ToolKind::Debug(DebugKind::Boost) => self.imgs.flyingrod_m1, + Button::image( + match self.loadout.active_item.as_ref().map(|i| &i.item.kind) { + Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { + ToolKind::Sword(_) => self.imgs.twohsword_m1, + ToolKind::Hammer => self.imgs.twohhammer_m1, + ToolKind::Axe => self.imgs.twohaxe_m1, + ToolKind::Bow => self.imgs.bow_m1, + ToolKind::Staff => self.imgs.staff_m1, + ToolKind::Debug(DebugKind::Boost) => self.imgs.flyingrod_m1, + _ => self.imgs.twohaxe_m1, + }, _ => self.imgs.twohaxe_m1, }, - _ => self.imgs.twohaxe_m1, - }) // Insert Icon here - .w(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { - Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { - ToolKind::Bow => 30.0 * scale, - ToolKind::Staff => 32.0 * scale, + ) // Insert Icon here + .w( + match self.loadout.active_item.as_ref().map(|i| &i.item.kind) { + Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { + ToolKind::Bow => 30.0 * scale, + ToolKind::Staff => 32.0 * scale, + _ => 38.0 * scale, + }, _ => 38.0 * scale, }, - _ => 38.0 * scale, - }) - .h(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { - Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { - ToolKind::Bow => 30.0 * scale, - ToolKind::Staff => 32.0 * scale, + ) + .h( + match self.loadout.active_item.as_ref().map(|i| &i.item.kind) { + Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { + ToolKind::Bow => 30.0 * scale, + ToolKind::Staff => 32.0 * scale, + _ => 38.0 * scale, + }, _ => 38.0 * scale, }, - _ => 38.0 * scale, - }) + ) .middle_of(state.ids.m1_slot_bg) .set(state.ids.m1_content, ui); // M2 Slot @@ -673,44 +684,52 @@ impl<'a> Widget for Skillbar<'a> { Image::new(self.imgs.skillbar_slot_big_bg) .w_h(38.0 * scale, 38.0 * scale) - .color(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { - Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { - ToolKind::Bow => Some(BG_COLOR_2), - ToolKind::Staff => Some(BG_COLOR_2), + .color( + match self.loadout.active_item.as_ref().map(|i| &i.item.kind) { + Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { + ToolKind::Bow => Some(BG_COLOR_2), + ToolKind::Staff => Some(BG_COLOR_2), + _ => Some(BG_COLOR_2), + }, _ => Some(BG_COLOR_2), }, - _ => Some(BG_COLOR_2), - }) + ) .middle_of(state.ids.m2_slot) .set(state.ids.m2_slot_bg, ui); - Button::image(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { - Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { - ToolKind::Sword(_) => self.imgs.twohsword_m2, - ToolKind::Hammer => self.imgs.twohhammer_m2, - ToolKind::Axe => self.imgs.twohaxe_m2, - ToolKind::Bow => self.imgs.bow_m2, - ToolKind::Staff => self.imgs.staff_m2, - ToolKind::Debug(DebugKind::Boost) => self.imgs.flyingrod_m2, + Button::image( + match self.loadout.active_item.as_ref().map(|i| &i.item.kind) { + Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { + ToolKind::Sword(_) => self.imgs.twohsword_m2, + ToolKind::Hammer => self.imgs.twohhammer_m2, + ToolKind::Axe => self.imgs.twohaxe_m2, + ToolKind::Bow => self.imgs.bow_m2, + ToolKind::Staff => self.imgs.staff_m2, + ToolKind::Debug(DebugKind::Boost) => self.imgs.flyingrod_m2, + _ => self.imgs.twohaxe_m2, + }, _ => self.imgs.twohaxe_m2, }, - _ => self.imgs.twohaxe_m2, - }) // Insert Icon here - .w(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { - Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { - ToolKind::Bow => 30.0 * scale, - ToolKind::Staff => 30.0 * scale, + ) // Insert Icon here + .w( + match self.loadout.active_item.as_ref().map(|i| &i.item.kind) { + Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { + ToolKind::Bow => 30.0 * scale, + ToolKind::Staff => 30.0 * scale, + _ => 38.0 * scale, + }, _ => 38.0 * scale, }, - _ => 38.0 * scale, - }) - .h(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { - Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { - ToolKind::Bow => 30.0 * scale, - ToolKind::Staff => 30.0 * scale, + ) + .h( + match self.loadout.active_item.as_ref().map(|i| &i.item.kind) { + Some(ItemKind::Tool(ToolData { kind, .. })) => match kind { + ToolKind::Bow => 30.0 * scale, + ToolKind::Staff => 30.0 * scale, + _ => 38.0 * scale, + }, _ => 38.0 * scale, }, - _ => 38.0 * scale, - }) + ) .middle_of(state.ids.m2_slot_bg) .set(state.ids.m2_content, ui); //Slot 5 diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index f7eaae27c2..cff2d9f925 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -116,14 +116,11 @@ impl PlayState for CharSelectionState { global_state.window.renderer_mut(), self.client.borrow().get_tick(), humanoid_body.clone(), - &comp::Equipment { - main: self - .char_selection_ui - .get_character_data() - .and_then(|data| data.tool) - .and_then(|tool| assets::load_cloned(&tool).ok()), - alt: None, - }, + self.char_selection_ui + .get_character_data() + .and_then(|data| data.tool) + .and_then(|tool| assets::load_cloned::(&tool).ok()) + .map(|i| i.kind), ); // Draw the UI to the screen. diff --git a/voxygen/src/scene/figure/cache.rs b/voxygen/src/scene/figure/cache.rs index 3cd35ebb13..8d576bb418 100644 --- a/voxygen/src/scene/figure/cache.rs +++ b/voxygen/src/scene/figure/cache.rs @@ -6,7 +6,7 @@ use crate::{ }; use common::{ assets::watch::ReloadIndicator, - comp::{Body, CharacterState, Equipment}, + comp::{Body, CharacterState, ItemKind}, }; use hashbrown::{hash_map::Entry, HashMap}; use std::{ @@ -19,7 +19,7 @@ enum FigureKey { Simple(Body), Complex( Body, - Option, + Option, CameraMode, Option, ), @@ -58,7 +58,7 @@ impl FigureModelCache { &mut self, renderer: &mut Renderer, body: Body, - equipment: Option<&Equipment>, + item_kind: Option, tick: u64, camera_mode: CameraMode, character_state: Option<&CharacterState>, @@ -67,10 +67,10 @@ impl FigureModelCache { for<'a> &'a common::comp::Body: std::convert::TryInto, Skel::Attr: Default, { - let key = if equipment.is_some() { + let key = if item_kind.is_some() { FigureKey::Complex( body, - equipment.cloned(), + item_kind, camera_mode, character_state.map(|cs| CharacterStateCacheKey::from(cs)), ) @@ -187,7 +187,7 @@ impl FigureModelCache { }) .unwrap_or_default() { - Some(mesh_main(equipment.and_then(|e| e.main.as_ref()))) + Some(mesh_main(item_kind)) } else { None }, diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 5924e323c8..44821d5ef5 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -534,9 +534,9 @@ impl HumArmorFootSpec { } } -pub fn mesh_main(item: Option<&Item>) -> Mesh { - if let Some(item) = item { - let (name, offset) = match item.kind { +pub fn mesh_main(item_kind: Option) -> Mesh { + if let Some(item_kind) = item_kind { + let (name, offset) = match item_kind { ItemKind::Tool(ToolData { kind, .. }) => match kind { ToolKind::Sword(_) => ("weapon.sword.rusty_2h", Vec3::new(-1.5, -6.5, -4.0)), ToolKind::Axe => ("weapon.axe.rusty_2h", Vec3::new(-1.5, -5.0, -4.0)), diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 718339c632..9d97b697e9 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -20,7 +20,8 @@ use crate::{ }; use common::{ comp::{ - Body, CharacterState, ItemKind, Last, Ori, PhysicsState, Pos, Scale, Stats, ToolData, Vel, + Body, CharacterState, ItemKind, Last, Loadout, Ori, PhysicsState, Pos, Scale, Stats, + ToolData, Vel, }, state::State, terrain::TerrainChunk, @@ -112,7 +113,19 @@ impl FigureMgr { .get(scene_data.player_entity) .map_or(Vec3::zero(), |pos| pos.0); - for (entity, pos, vel, ori, scale, body, character, last_character, physics, stats) in ( + for ( + entity, + pos, + vel, + ori, + scale, + body, + character, + last_character, + physics, + stats, + loadout, + ) in ( &ecs.entities(), &ecs.read_storage::(), &ecs.read_storage::(), @@ -123,6 +136,7 @@ impl FigureMgr { ecs.read_storage::>().maybe(), &ecs.read_storage::(), ecs.read_storage::().maybe(), + ecs.read_storage::().maybe(), ) .join() { @@ -370,11 +384,11 @@ impl FigureMgr { let mut state_animation_rate = 1.0; - let active_tool_kind = if let Some(ItemKind::Tool(ToolData { kind, .. })) = stats - .and_then(|s| s.equipment.main.as_ref()) - .map(|i| &i.kind) - { - Some(*kind) + let active_item_kind = loadout + .and_then(|l| l.active_item.as_ref()) + .map(|i| i.item.kind); + let active_tool_kind = if let Some(ItemKind::Tool(tool)) = active_item_kind { + Some(tool.kind) } else { None }; @@ -386,7 +400,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats.map(|s| &s.equipment), + active_item_kind, tick, CameraMode::default(), None, @@ -566,7 +580,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats.map(|s| &s.equipment), + active_item_kind, tick, CameraMode::default(), None, @@ -647,7 +661,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats.map(|s| &s.equipment), + active_item_kind, tick, CameraMode::default(), None, @@ -730,7 +744,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats.map(|s| &s.equipment), + active_item_kind, tick, CameraMode::default(), None, @@ -805,7 +819,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats.map(|s| &s.equipment), + active_item_kind, tick, CameraMode::default(), None, @@ -880,7 +894,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats.map(|s| &s.equipment), + active_item_kind, tick, CameraMode::default(), None, @@ -955,7 +969,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats.map(|s| &s.equipment), + active_item_kind, tick, CameraMode::default(), None, @@ -1030,7 +1044,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats.map(|s| &s.equipment), + active_item_kind, tick, CameraMode::default(), None, @@ -1105,7 +1119,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats.map(|s| &s.equipment), + active_item_kind, tick, CameraMode::default(), None, @@ -1180,7 +1194,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats.map(|s| &s.equipment), + active_item_kind, tick, CameraMode::default(), None, @@ -1313,17 +1327,18 @@ impl FigureMgr { let character_state_storage = state.read_storage::(); let character_state = character_state_storage.get(player_entity); - for (entity, _, _, body, stats, _) in ( + for (entity, _, _, body, stats, loadout, _) in ( &ecs.entities(), &ecs.read_storage::(), ecs.read_storage::().maybe(), &ecs.read_storage::(), ecs.read_storage::().maybe(), + ecs.read_storage::().maybe(), ecs.read_storage::().maybe(), ) .join() // Don't render dead entities - .filter(|(_, _, _, _, stats, _)| stats.map_or(true, |s| !s.is_dead)) + .filter(|(_, _, _, _, stats, loadout, _)| stats.map_or(true, |s| !s.is_dead)) { let is_player = entity == player_entity; let player_camera_mode = if is_player { @@ -1331,7 +1346,9 @@ impl FigureMgr { } else { CameraMode::default() }; - let stats = stats.map(|s| &s.equipment); + let active_item_kind = loadout + .and_then(|l| l.active_item.as_ref()) + .map(|i| i.item.kind); let character_state = if is_player { character_state } else { None }; let FigureMgr { @@ -1369,7 +1386,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, @@ -1385,7 +1402,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, @@ -1401,7 +1418,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, @@ -1417,7 +1434,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, @@ -1433,7 +1450,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, @@ -1449,7 +1466,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, @@ -1465,7 +1482,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, @@ -1481,7 +1498,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, @@ -1497,7 +1514,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, @@ -1513,7 +1530,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, @@ -1529,7 +1546,7 @@ impl FigureMgr { .get_or_create_model( renderer, *body, - stats, + active_item_kind, tick, player_camera_mode, character_state, diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index a0f6d159e7..9547b82fb3 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -15,7 +15,7 @@ use crate::{ window::{Event, PressState}, }; use common::{ - comp::{humanoid, Body, Equipment}, + comp::{humanoid, Body, ItemKind}, terrain::BlockKind, vol::{BaseVol, ReadVol, Vox}, }; @@ -208,7 +208,7 @@ impl Scene { renderer: &mut Renderer, tick: u64, body: Option, - equipment: &Equipment, + active_item_kind: Option, ) { renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals); @@ -218,7 +218,7 @@ impl Scene { .get_or_create_model( renderer, Body::Humanoid(body), - Some(equipment), + active_item_kind, tick, CameraMode::default(), None,