mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added armour items and equipping of armour
This commit is contained in:
parent
e80750bc53
commit
e20feeeb0c
8
assets/common/items/armor/chest_plate.ron
Normal file
8
assets/common/items/armor/chest_plate.ron
Normal file
@ -0,0 +1,8 @@
|
||||
Item(
|
||||
name: "Iron Chestplate",
|
||||
description: "Arrows to the stomach are soooo last update.",
|
||||
kind: Armor(
|
||||
kind: Chest(Plate),
|
||||
stats: 20,
|
||||
),
|
||||
)
|
8
assets/common/items/armor/pants_assassin.ron
Normal file
8
assets/common/items/armor/pants_assassin.ron
Normal file
@ -0,0 +1,8 @@
|
||||
Item(
|
||||
name: "Assassin Pants",
|
||||
description: "Only the best for a member of the creed.",
|
||||
kind: Armor(
|
||||
kind: Pants(Assassin),
|
||||
stats: 20,
|
||||
),
|
||||
)
|
8
assets/common/items/armor/pants_green.ron
Normal file
8
assets/common/items/armor/pants_green.ron
Normal file
@ -0,0 +1,8 @@
|
||||
Item(
|
||||
name: "Green Camo Pants",
|
||||
description: "Perfect for hunting.",
|
||||
kind: Armor(
|
||||
kind: Pants(Green),
|
||||
stats: 20,
|
||||
),
|
||||
)
|
@ -39,7 +39,13 @@ pub struct ItemConfig {
|
||||
pub struct Loadout {
|
||||
pub active_item: Option<ItemConfig>,
|
||||
pub second_item: Option<ItemConfig>,
|
||||
// armor
|
||||
|
||||
pub shoulder: Option<Item>,
|
||||
pub chest: Option<Item>,
|
||||
pub belt: Option<Item>,
|
||||
pub hand: Option<Item>,
|
||||
pub pants: Option<Item>,
|
||||
pub foot: Option<Item>,
|
||||
}
|
||||
|
||||
impl From<CharacterAbility> for CharacterState {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
assets::{self, Asset},
|
||||
comp::CharacterAbility,
|
||||
comp::{body::humanoid, CharacterAbility},
|
||||
effect::Effect,
|
||||
terrain::{Block, BlockKind},
|
||||
};
|
||||
@ -80,22 +80,17 @@ pub enum DebugKind {
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Armor {
|
||||
// TODO: Don't make armor be a body part. Wearing enemy's head is funny but also a creepy
|
||||
// thing to do.
|
||||
Helmet,
|
||||
Shoulders,
|
||||
Chestplate,
|
||||
Belt,
|
||||
Gloves,
|
||||
Pants,
|
||||
Boots,
|
||||
Back,
|
||||
Tabard,
|
||||
Gem,
|
||||
Necklace,
|
||||
Shoulder(humanoid::Shoulder),
|
||||
Chest(humanoid::Chest),
|
||||
Belt(humanoid::Belt),
|
||||
Hand(humanoid::Hand),
|
||||
Pants(humanoid::Pants),
|
||||
Foot(humanoid::Foot),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub type ArmorStats = u32;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Consumable {
|
||||
Apple,
|
||||
Cheese,
|
||||
@ -124,13 +119,13 @@ pub struct ToolData {
|
||||
// TODO: item specific abilities
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum ItemKind {
|
||||
/// Something wieldable
|
||||
Tool(ToolData),
|
||||
Armor {
|
||||
kind: Armor,
|
||||
power: u32,
|
||||
stats: ArmorStats,
|
||||
},
|
||||
Consumable {
|
||||
kind: Consumable,
|
||||
|
@ -100,6 +100,7 @@ pub enum ServerEvent {
|
||||
CreateNpc {
|
||||
pos: comp::Pos,
|
||||
stats: comp::Stats,
|
||||
loadout: comp::Loadout,
|
||||
body: comp::Body,
|
||||
agent: comp::Agent,
|
||||
alignment: comp::Alignment,
|
||||
|
@ -1,15 +1,12 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{CharacterState, StateUpdate, ToolData},
|
||||
states::wielding,
|
||||
comp::{CharacterState, StateUpdate},
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct Data {
|
||||
/// The weapon being equipped
|
||||
pub tool: ToolData,
|
||||
/// Time left before next state
|
||||
pub time_left: Duration,
|
||||
}
|
||||
@ -40,7 +37,6 @@ impl CharacterBehavior for Data {
|
||||
.time_left
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
tool: self.tool,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -119,9 +119,8 @@ 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.loadout.active_item.as_ref().map(|i| i.item.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(),
|
||||
});
|
||||
} else {
|
||||
@ -253,8 +252,8 @@ pub fn attempt_dodge_ability(data: &JoinData, update: &mut StateUpdate) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_tool_data(data: &JoinData) -> Option<ToolData> {
|
||||
if let Some(Tool(tool)) = data.loadout.active_item.as_ref().map(|i| i.item.kind) {
|
||||
pub fn unwrap_tool_data<'a>(data: &'a JoinData) -> Option<&'a ToolData> {
|
||||
if let Some(Tool(tool)) = data.loadout.active_item.as_ref().map(|i| &i.item.kind) {
|
||||
Some(tool)
|
||||
} else {
|
||||
None
|
||||
|
@ -505,6 +505,7 @@ fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &C
|
||||
.create_npc(
|
||||
pos,
|
||||
comp::Stats::new(get_npc_name(id).into(), body),
|
||||
comp::Loadout::default(),
|
||||
body,
|
||||
)
|
||||
.with(comp::Vel(vel))
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{sys, Server, StateExt};
|
||||
use common::comp::{
|
||||
self, Agent, Alignment, Body, Gravity, LightEmitter, Pos, Projectile, Scale, Stats, Vel,
|
||||
WaypointArea,
|
||||
self, Agent, Alignment, Body, Gravity, LightEmitter, Loadout, Pos, Projectile, Scale, Stats,
|
||||
Vel, WaypointArea,
|
||||
};
|
||||
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||
use vek::{Rgb, Vec3};
|
||||
@ -24,6 +24,7 @@ pub fn handle_create_npc(
|
||||
server: &mut Server,
|
||||
pos: Pos,
|
||||
stats: Stats,
|
||||
loadout: Loadout,
|
||||
body: Body,
|
||||
agent: Agent,
|
||||
alignment: Alignment,
|
||||
@ -31,7 +32,7 @@ pub fn handle_create_npc(
|
||||
) {
|
||||
server
|
||||
.state
|
||||
.create_npc(pos, stats, body)
|
||||
.create_npc(pos, stats, loadout, body)
|
||||
.with(agent)
|
||||
.with(scale)
|
||||
.with(alignment)
|
||||
|
@ -83,21 +83,97 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
}
|
||||
},
|
||||
|
||||
comp::InventoryManip::Use(slot) => {
|
||||
comp::InventoryManip::Use(slot_idx) => {
|
||||
let item_opt = state
|
||||
.ecs()
|
||||
.write_storage::<comp::Inventory>()
|
||||
.get_mut(entity)
|
||||
.and_then(|inv| inv.remove(slot));
|
||||
.and_then(|inv| inv.remove(slot_idx));
|
||||
|
||||
let mut event = comp::InventoryUpdateEvent::Used;
|
||||
|
||||
if let Some(item) = item_opt {
|
||||
match item.kind {
|
||||
comp::ItemKind::Consumable { kind, effect } => {
|
||||
event = comp::InventoryUpdateEvent::Consumed(kind);
|
||||
state.apply_effect(entity, effect);
|
||||
match &item.kind {
|
||||
comp::ItemKind::Tool(tool) => {
|
||||
if let Some(loadout) =
|
||||
state.ecs().write_storage::<comp::Loadout>().get_mut(entity)
|
||||
{
|
||||
// Insert old item into inventory
|
||||
if let Some(old_item) = loadout.active_item.take() {
|
||||
state
|
||||
.ecs()
|
||||
.write_storage::<comp::Inventory>()
|
||||
.get_mut(entity)
|
||||
.map(|inv| inv.insert(slot_idx, old_item.item));
|
||||
}
|
||||
|
||||
let mut abilities = tool.get_abilities();
|
||||
let mut ability_drain = abilities.drain(..);
|
||||
let active_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),
|
||||
};
|
||||
loadout.active_item = Some(active_item);
|
||||
}
|
||||
},
|
||||
|
||||
comp::ItemKind::Consumable { kind, effect } => {
|
||||
event = comp::InventoryUpdateEvent::Consumed(*kind);
|
||||
state.apply_effect(entity, *effect);
|
||||
},
|
||||
|
||||
comp::ItemKind::Armor { kind, .. } => {
|
||||
if let Some(loadout) =
|
||||
state.ecs().write_storage::<comp::Loadout>().get_mut(entity)
|
||||
{
|
||||
if let Some(comp::Body::Humanoid(body)) =
|
||||
state.ecs().write_storage::<comp::Body>().get_mut(entity)
|
||||
{
|
||||
use comp::item::Armor::*;
|
||||
let slot = match kind.clone() {
|
||||
Shoulder(shoulder) => {
|
||||
body.shoulder = shoulder;
|
||||
&mut loadout.shoulder
|
||||
},
|
||||
Chest(chest) => {
|
||||
body.chest = chest;
|
||||
&mut loadout.chest
|
||||
},
|
||||
Belt(belt) => {
|
||||
body.belt = belt;
|
||||
&mut loadout.belt
|
||||
},
|
||||
Hand(hand) => {
|
||||
body.hand = hand;
|
||||
&mut loadout.hand
|
||||
},
|
||||
Pants(pants) => {
|
||||
body.pants = pants;
|
||||
&mut loadout.pants
|
||||
},
|
||||
Foot(foot) => {
|
||||
body.foot = foot;
|
||||
&mut loadout.foot
|
||||
},
|
||||
};
|
||||
|
||||
// Insert old item into inventory
|
||||
if let Some(old_item) = slot.take() {
|
||||
state
|
||||
.ecs()
|
||||
.write_storage::<comp::Inventory>()
|
||||
.get_mut(entity)
|
||||
.map(|inv| inv.insert(slot_idx, old_item));
|
||||
}
|
||||
|
||||
*slot = Some(item);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
comp::ItemKind::Utility { kind } => match kind {
|
||||
comp::item::Utility::Collar => {
|
||||
let reinsert = if let Some(pos) =
|
||||
@ -155,7 +231,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
.ecs()
|
||||
.write_storage::<comp::Inventory>()
|
||||
.get_mut(entity)
|
||||
.map(|inv| inv.insert(slot, item));
|
||||
.map(|inv| inv.insert(slot_idx, item));
|
||||
}
|
||||
},
|
||||
},
|
||||
@ -164,7 +240,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
.ecs()
|
||||
.write_storage::<comp::Inventory>()
|
||||
.get_mut(entity)
|
||||
.map(|inv| inv.insert(slot, item));
|
||||
.map(|inv| inv.insert(slot_idx, item));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -76,11 +76,12 @@ impl Server {
|
||||
ServerEvent::CreateNpc {
|
||||
pos,
|
||||
stats,
|
||||
loadout,
|
||||
body,
|
||||
agent,
|
||||
alignment,
|
||||
scale,
|
||||
} => handle_create_npc(self, pos, stats, body, agent, alignment, scale),
|
||||
} => handle_create_npc(self, pos, stats, loadout, body, agent, alignment, scale),
|
||||
ServerEvent::CreateWaypoint(pos) => handle_create_waypoint(self, pos),
|
||||
ServerEvent::ClientDisconnect(entity) => {
|
||||
frontend_events.push(handle_client_disconnect(self, entity))
|
||||
|
@ -17,6 +17,7 @@ pub trait StateExt {
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
stats: comp::Stats,
|
||||
loadout: comp::Loadout,
|
||||
body: comp::Body,
|
||||
) -> EcsEntityBuilder;
|
||||
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder;
|
||||
@ -81,6 +82,7 @@ impl StateExt for State {
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
stats: comp::Stats,
|
||||
loadout: comp::Loadout,
|
||||
body: comp::Body,
|
||||
) -> EcsEntityBuilder {
|
||||
self.ecs_mut()
|
||||
@ -95,7 +97,7 @@ impl StateExt for State {
|
||||
.with(comp::Energy::new(500))
|
||||
.with(comp::Gravity(1.0))
|
||||
.with(comp::CharacterState::default())
|
||||
.with(comp::Loadout::default()) // TODO Give the poor npc something to do
|
||||
.with(loadout)
|
||||
}
|
||||
|
||||
/// Build a static object entity
|
||||
@ -161,7 +163,7 @@ impl StateExt for State {
|
||||
|
||||
self.write_component(
|
||||
entity,
|
||||
if let Some(comp::ItemKind::Tool(tool)) = main.as_ref().map(|i| i.kind) {
|
||||
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::Loadout {
|
||||
@ -173,6 +175,12 @@ impl StateExt for State {
|
||||
dodge_ability: Some(comp::CharacterAbility::Roll),
|
||||
}),
|
||||
second_item: None,
|
||||
shoulder: None,
|
||||
chest: None,
|
||||
belt: None,
|
||||
hand: None,
|
||||
pants: None,
|
||||
foot: None,
|
||||
}
|
||||
} else {
|
||||
comp::Loadout::default()
|
||||
|
@ -190,6 +190,12 @@ impl<'a> System<'a> for Sys {
|
||||
dodge_ability: None,
|
||||
}),
|
||||
second_item: None,
|
||||
shoulder: None,
|
||||
chest: None,
|
||||
belt: None,
|
||||
hand: None,
|
||||
pants: None,
|
||||
foot: None,
|
||||
};
|
||||
|
||||
let mut scale = 1.0;
|
||||
@ -222,6 +228,12 @@ impl<'a> System<'a> for Sys {
|
||||
dodge_ability: None,
|
||||
}),
|
||||
second_item: None,
|
||||
shoulder: None,
|
||||
chest: None,
|
||||
belt: None,
|
||||
hand: None,
|
||||
pants: None,
|
||||
foot: None,
|
||||
};
|
||||
|
||||
stats.level.set_level(rand::thread_rng().gen_range(8, 15));
|
||||
@ -246,6 +258,7 @@ impl<'a> System<'a> for Sys {
|
||||
server_emitter.emit(ServerEvent::CreateNpc {
|
||||
pos: Pos(entity.pos),
|
||||
stats,
|
||||
loadout,
|
||||
body,
|
||||
alignment,
|
||||
agent: comp::Agent::default().with_patrol_origin(entity.pos),
|
||||
|
@ -112,15 +112,18 @@ impl PlayState for CharSelectionState {
|
||||
}
|
||||
|
||||
// Render the scene.
|
||||
let item = self
|
||||
.char_selection_ui
|
||||
.get_character_data()
|
||||
.and_then(|data| data.tool)
|
||||
.and_then(|tool| assets::load_cloned::<comp::Item>(&tool).ok());
|
||||
let item_kind = item.map(|i| i.kind);
|
||||
|
||||
self.scene.render(
|
||||
global_state.window.renderer_mut(),
|
||||
self.client.borrow().get_tick(),
|
||||
humanoid_body.clone(),
|
||||
self.char_selection_ui
|
||||
.get_character_data()
|
||||
.and_then(|data| data.tool)
|
||||
.and_then(|tool| assets::load_cloned::<comp::Item>(&tool).ok())
|
||||
.map(|i| i.kind),
|
||||
item_kind.as_ref(),
|
||||
);
|
||||
|
||||
// Draw the UI to the screen.
|
||||
|
@ -58,7 +58,7 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
||||
&mut self,
|
||||
renderer: &mut Renderer,
|
||||
body: Body,
|
||||
item_kind: Option<ItemKind>,
|
||||
item_kind: Option<&ItemKind>,
|
||||
tick: u64,
|
||||
camera_mode: CameraMode,
|
||||
character_state: Option<&CharacterState>,
|
||||
@ -70,7 +70,7 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
||||
let key = if item_kind.is_some() {
|
||||
FigureKey::Complex(
|
||||
body,
|
||||
item_kind,
|
||||
item_kind.cloned(),
|
||||
camera_mode,
|
||||
character_state.map(|cs| CharacterStateCacheKey::from(cs)),
|
||||
)
|
||||
|
@ -534,7 +534,7 @@ impl HumArmorFootSpec {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mesh_main(item_kind: Option<ItemKind>) -> Mesh<FigurePipeline> {
|
||||
pub fn mesh_main(item_kind: Option<&ItemKind>) -> Mesh<FigurePipeline> {
|
||||
if let Some(item_kind) = item_kind {
|
||||
let (name, offset) = match item_kind {
|
||||
ItemKind::Tool(ToolData { kind, .. }) => match kind {
|
||||
|
@ -386,7 +386,7 @@ impl FigureMgr {
|
||||
|
||||
let active_item_kind = loadout
|
||||
.and_then(|l| l.active_item.as_ref())
|
||||
.map(|i| i.item.kind);
|
||||
.map(|i| &i.item.kind);
|
||||
let active_tool_kind = if let Some(ItemKind::Tool(tool)) = active_item_kind {
|
||||
Some(tool.kind)
|
||||
} else {
|
||||
@ -1348,7 +1348,7 @@ impl FigureMgr {
|
||||
};
|
||||
let active_item_kind = loadout
|
||||
.and_then(|l| l.active_item.as_ref())
|
||||
.map(|i| i.item.kind);
|
||||
.map(|i| &i.item.kind);
|
||||
let character_state = if is_player { character_state } else { None };
|
||||
|
||||
let FigureMgr {
|
||||
|
@ -208,7 +208,7 @@ impl Scene {
|
||||
renderer: &mut Renderer,
|
||||
tick: u64,
|
||||
body: Option<humanoid::Body>,
|
||||
active_item_kind: Option<ItemKind>,
|
||||
active_item_kind: Option<&ItemKind>,
|
||||
) {
|
||||
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user