mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/inventories' into 'master'
Inventories Closes #167 and #166 See merge request veloren/veloren!371
This commit is contained in:
commit
6f73d27431
BIN
assets/voxygen/voxel/object/pouch.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/pouch.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -4,14 +4,13 @@ pub mod error;
|
||||
|
||||
// Reexports
|
||||
pub use crate::error::Error;
|
||||
pub use specs::join::Join;
|
||||
pub use specs::Entity as EcsEntity;
|
||||
pub use specs::{join::Join, saveload::Marker, Entity as EcsEntity, ReadStorage};
|
||||
|
||||
use common::{
|
||||
comp,
|
||||
msg::{ClientMsg, ClientState, ServerError, ServerInfo, ServerMsg},
|
||||
net::PostBox,
|
||||
state::State,
|
||||
state::{State, Uid},
|
||||
terrain::{block::Block, chonk::ChonkMetrics, TerrainChunk, TerrainChunkSize},
|
||||
vol::VolSize,
|
||||
ChatType,
|
||||
@ -165,6 +164,21 @@ impl Client {
|
||||
.send_message(ClientMsg::SetViewDistance(self.view_distance.unwrap())); // Can't fail
|
||||
}
|
||||
|
||||
pub fn swap_inventory_slots(&mut self, a: usize, b: usize) {
|
||||
self.postbox
|
||||
.send_message(ClientMsg::SwapInventorySlots(a, b))
|
||||
}
|
||||
|
||||
pub fn drop_inventory_slot(&mut self, x: usize) {
|
||||
self.postbox.send_message(ClientMsg::DropInventorySlot(x))
|
||||
}
|
||||
|
||||
pub fn pick_up(&mut self, entity: EcsEntity) {
|
||||
if let Some(uid) = self.state.ecs().read_storage::<Uid>().get(entity).copied() {
|
||||
self.postbox.send_message(ClientMsg::PickUp(uid.id()));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view_distance(&self) -> Option<u32> {
|
||||
self.view_distance
|
||||
}
|
||||
@ -188,6 +202,10 @@ impl Client {
|
||||
self.state.terrain().get_key_arc(chunk_pos).cloned()
|
||||
}
|
||||
|
||||
pub fn inventories(&self) -> ReadStorage<comp::Inventory> {
|
||||
self.state.read_storage()
|
||||
}
|
||||
|
||||
/// Send a chat message to the server.
|
||||
#[allow(dead_code)]
|
||||
pub fn send_chat(&mut self, msg: String) {
|
||||
@ -421,6 +439,9 @@ impl Client {
|
||||
self.state.write_component(entity, action_state);
|
||||
}
|
||||
}
|
||||
ServerMsg::InventoryUpdate(inventory) => {
|
||||
self.state.write_component(self.entity, inventory)
|
||||
}
|
||||
ServerMsg::TerrainChunkUpdate { key, chunk } => {
|
||||
self.state.insert_chunk(key, *chunk);
|
||||
self.pending_chunks.remove(&key);
|
||||
|
@ -48,6 +48,7 @@ pub enum Body {
|
||||
CarpetHumanSquare,
|
||||
CarpetHumanSquare2,
|
||||
CarpetHumanSquircle,
|
||||
Pouch,
|
||||
}
|
||||
|
||||
impl Body {
|
||||
|
@ -1,8 +1,8 @@
|
||||
use specs::Component;
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Weapon {
|
||||
pub enum Tool {
|
||||
Daggers,
|
||||
SwordShield,
|
||||
Sword,
|
||||
@ -11,14 +11,29 @@ pub enum Weapon {
|
||||
Bow,
|
||||
Staff,
|
||||
}
|
||||
pub const ALL_WEAPONS: [Weapon; 7] = [
|
||||
Weapon::Daggers,
|
||||
Weapon::SwordShield,
|
||||
Weapon::Sword,
|
||||
Weapon::Axe,
|
||||
Weapon::Hammer,
|
||||
Weapon::Bow,
|
||||
Weapon::Staff,
|
||||
|
||||
impl Tool {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
Tool::Daggers => "daggers",
|
||||
Tool::SwordShield => "sword and shield",
|
||||
Tool::Sword => "sword",
|
||||
Tool::Axe => "axe",
|
||||
Tool::Hammer => "hammer",
|
||||
Tool::Bow => "bow",
|
||||
Tool::Staff => "staff",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const ALL_TOOLS: [Tool; 7] = [
|
||||
Tool::Daggers,
|
||||
Tool::SwordShield,
|
||||
Tool::Sword,
|
||||
Tool::Axe,
|
||||
Tool::Hammer,
|
||||
Tool::Bow,
|
||||
Tool::Staff,
|
||||
];
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
@ -37,29 +52,82 @@ pub enum Armor {
|
||||
Necklace,
|
||||
}
|
||||
|
||||
impl Armor {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
Armor::Helmet => "helmet",
|
||||
Armor::Shoulders => "shoulder pads",
|
||||
Armor::Chestplate => "chestplate",
|
||||
Armor::Belt => "belt",
|
||||
Armor::Gloves => "gloves",
|
||||
Armor::Pants => "pants",
|
||||
Armor::Boots => "boots",
|
||||
Armor::Back => "back",
|
||||
Armor::Tabard => "tabard",
|
||||
Armor::Gem => "gem",
|
||||
Armor::Necklace => "necklace",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Rarity {
|
||||
Common,
|
||||
Uncommon,
|
||||
Rare,
|
||||
Legendary,
|
||||
pub enum ConsumptionEffect {
|
||||
Health(i32),
|
||||
Xp(i32),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Item {
|
||||
Weapon {
|
||||
Tool {
|
||||
kind: Tool,
|
||||
damage: i32,
|
||||
strength: i32,
|
||||
rarity: Rarity,
|
||||
},
|
||||
Armor {
|
||||
kind: Armor,
|
||||
defense: i32,
|
||||
health_bonus: i32,
|
||||
rarity: Rarity,
|
||||
variant: Armor,
|
||||
},
|
||||
Consumable {
|
||||
effect: ConsumptionEffect,
|
||||
},
|
||||
Ingredient,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
Item::Tool { kind, .. } => kind.name(),
|
||||
Item::Armor { kind, .. } => kind.name(),
|
||||
Item::Consumable { .. } => "<consumable>",
|
||||
Item::Ingredient => "<ingredient>",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn category(&self) -> &'static str {
|
||||
match self {
|
||||
Item::Tool { .. } => "tool",
|
||||
Item::Armor { .. } => "armour",
|
||||
Item::Consumable { .. } => "consumable",
|
||||
Item::Ingredient => "ingredient",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn description(&self) -> String {
|
||||
format!("{} ({})", self.name(), self.category())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Item {
|
||||
fn default() -> Self {
|
||||
Item::Tool {
|
||||
kind: Tool::Hammer,
|
||||
damage: 0,
|
||||
strength: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Item {
|
||||
type Storage = IDVStorage<Self>;
|
||||
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
use specs::{Component, HashMapStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
|
||||
//Re-Exports
|
||||
pub mod item;
|
||||
|
||||
use item::Item;
|
||||
use std::mem::swap;
|
||||
// Reexports
|
||||
pub use self::item::Item;
|
||||
|
||||
use specs::{Component, HashMapStorage, NullStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Inventory {
|
||||
@ -13,9 +13,21 @@ pub struct Inventory {
|
||||
}
|
||||
|
||||
impl Inventory {
|
||||
pub fn new() -> Inventory {
|
||||
Inventory {
|
||||
slots: vec![None; 24],
|
||||
pub fn slots(&self) -> &[Option<Item>] {
|
||||
&self.slots
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.slots.len()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, item: Item) -> Option<Item> {
|
||||
match self.slots.iter_mut().find(|slot| slot.is_none()) {
|
||||
Some(slot) => {
|
||||
*slot = Some(item);
|
||||
None
|
||||
}
|
||||
None => Some(item),
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,18 +42,40 @@ impl Inventory {
|
||||
self.slots.get_mut(cell).and_then(|cell| cell.replace(item))
|
||||
}
|
||||
|
||||
// Remove an item from the slot
|
||||
pub fn remove(&mut self, cell: usize, item: Item) -> Option<Item> {
|
||||
let mut tmp_item = Some(item);
|
||||
pub fn swap_slots(&mut self, a: usize, b: usize) {
|
||||
if a.max(b) < self.slots.len() {
|
||||
self.slots.swap(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(old_item) = self.slots.get_mut(cell) {
|
||||
swap(old_item, &mut tmp_item);
|
||||
// Remove an item from the slot
|
||||
pub fn remove(&mut self, cell: usize) -> Option<Item> {
|
||||
self.slots.get_mut(cell).and_then(|item| item.take())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Inventory {
|
||||
fn default() -> Inventory {
|
||||
let mut this = Inventory {
|
||||
slots: vec![None; 24],
|
||||
};
|
||||
|
||||
for _ in 0..18 {
|
||||
this.insert(Item::default());
|
||||
}
|
||||
|
||||
tmp_item
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Inventory {
|
||||
type Storage = HashMapStorage<Self>;
|
||||
}
|
||||
|
||||
// ForceUpdate
|
||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct InventoryUpdate;
|
||||
|
||||
impl Component for InventoryUpdate {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ pub use controller::Controller;
|
||||
pub use inputs::{
|
||||
Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding,
|
||||
};
|
||||
pub use inventory::{item, Inventory};
|
||||
pub use inventory::{item, Inventory, InventoryUpdate, Item};
|
||||
pub use last::Last;
|
||||
pub use phys::{ForceUpdate, Ori, Pos, Vel};
|
||||
pub use player::Player;
|
||||
|
@ -3,7 +3,7 @@ use specs_idvs::IDVStorage;
|
||||
use vek::*;
|
||||
|
||||
// Position
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Pos(pub Vec3<f32>);
|
||||
|
||||
impl Component for Pos {
|
||||
@ -11,7 +11,7 @@ impl Component for Pos {
|
||||
}
|
||||
|
||||
// Velocity
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Vel(pub Vec3<f32>);
|
||||
|
||||
impl Component for Vel {
|
||||
@ -19,7 +19,7 @@ impl Component for Vel {
|
||||
}
|
||||
|
||||
// Orientation
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Ori(pub Vec3<f32>);
|
||||
|
||||
impl Component for Ori {
|
||||
|
@ -28,6 +28,9 @@ pub enum ClientMsg {
|
||||
vel: comp::Vel,
|
||||
ori: comp::Ori,
|
||||
},
|
||||
SwapInventorySlots(usize, usize),
|
||||
DropInventorySlot(usize),
|
||||
PickUp(u64),
|
||||
TerrainChunkRequest {
|
||||
key: Vec2<i32>,
|
||||
},
|
||||
|
@ -25,6 +25,7 @@ sphynx::sum_type! {
|
||||
CanBuild(comp::CanBuild),
|
||||
Stats(comp::Stats),
|
||||
LightEmitter(comp::LightEmitter),
|
||||
Item(comp::Item),
|
||||
}
|
||||
}
|
||||
// Automatically derive From<T> for EcsCompPhantom
|
||||
@ -40,6 +41,7 @@ sphynx::sum_type! {
|
||||
CanBuild(PhantomData<comp::CanBuild>),
|
||||
Stats(PhantomData<comp::Stats>),
|
||||
LightEmitter(PhantomData<comp::LightEmitter>),
|
||||
Item(PhantomData<comp::Item>),
|
||||
}
|
||||
}
|
||||
impl sphynx::CompPacket for EcsCompPacket {
|
||||
|
@ -55,6 +55,7 @@ pub enum ServerMsg {
|
||||
entity: u64,
|
||||
action_state: comp::ActionState,
|
||||
},
|
||||
InventoryUpdate(comp::Inventory),
|
||||
TerrainChunkUpdate {
|
||||
key: Vec2<i32>,
|
||||
chunk: Box<TerrainChunk>,
|
||||
|
@ -131,6 +131,7 @@ impl State {
|
||||
ecs.register_synced::<comp::Stats>();
|
||||
ecs.register_synced::<comp::CanBuild>();
|
||||
ecs.register_synced::<comp::LightEmitter>();
|
||||
ecs.register_synced::<comp::Item>();
|
||||
|
||||
// Register components send from clients -> server
|
||||
ecs.register::<comp::Controller>();
|
||||
@ -142,6 +143,7 @@ impl State {
|
||||
ecs.register::<comp::Pos>();
|
||||
ecs.register::<comp::Vel>();
|
||||
ecs.register::<comp::Ori>();
|
||||
ecs.register::<comp::Inventory>();
|
||||
|
||||
// Register client-local components
|
||||
ecs.register::<comp::AnimationInfo>();
|
||||
@ -156,6 +158,7 @@ impl State {
|
||||
ecs.register::<comp::Respawning>();
|
||||
ecs.register::<comp::Dying>();
|
||||
ecs.register::<comp::ForceUpdate>();
|
||||
ecs.register::<comp::InventoryUpdate>();
|
||||
ecs.register::<comp::Inventory>();
|
||||
// Controller effects
|
||||
ecs.register::<comp::MoveDir>();
|
||||
|
@ -11,7 +11,7 @@ const HUMANOID_ACCEL: f32 = 70.0;
|
||||
const HUMANOID_SPEED: f32 = 120.0;
|
||||
const HUMANOID_AIR_ACCEL: f32 = 10.0;
|
||||
const HUMANOID_AIR_SPEED: f32 = 100.0;
|
||||
const HUMANOID_JUMP_ACCEL: f32 = 16.5;
|
||||
const HUMANOID_JUMP_ACCEL: f32 = 18.0;
|
||||
const ROLL_ACCEL: f32 = 120.0;
|
||||
const ROLL_SPEED: f32 = 550.0;
|
||||
const GLIDE_ACCEL: f32 = 15.0;
|
||||
|
@ -16,8 +16,8 @@ const FRIC_AIR: f32 = 0.015;
|
||||
// lv = linear velocity
|
||||
// damp = linear damping
|
||||
// Friction is a type of damping.
|
||||
fn integrate_forces(dt: f32, mut lv: Vec3<f32>, damp: f32) -> Vec3<f32> {
|
||||
lv.z = (lv.z - GRAVITY * dt).max(-50.0);
|
||||
fn integrate_forces(dt: f32, mut lv: Vec3<f32>, grav: f32, damp: f32) -> Vec3<f32> {
|
||||
lv.z = (lv.z - grav * dt).max(-50.0);
|
||||
|
||||
let linear_damp = (1.0 - dt * damp).max(0.0);
|
||||
|
||||
@ -63,8 +63,13 @@ impl<'a> System<'a> for Sys {
|
||||
{
|
||||
// Integrate forces
|
||||
// Friction is assumed to be a constant dependent on location
|
||||
let friction = 50.0 * if a.on_ground { FRIC_GROUND } else { FRIC_AIR };
|
||||
vel.0 = integrate_forces(dt.0, vel.0, friction);
|
||||
let friction = 50.0
|
||||
* if on_grounds.get(entity).is_some() {
|
||||
FRIC_GROUND
|
||||
} else {
|
||||
FRIC_AIR
|
||||
};
|
||||
vel.0 = integrate_forces(dt.0, vel.0, GRAVITY, friction);
|
||||
|
||||
// Basic collision with terrain
|
||||
let player_rad = 0.3f32; // half-width of the player's AABB
|
||||
@ -126,6 +131,7 @@ impl<'a> System<'a> for Sys {
|
||||
let increments = (pos_delta.map(|e| e.abs()).reduce_partial_max() / 0.3)
|
||||
.ceil()
|
||||
.max(1.0);
|
||||
let old_pos = pos.0;
|
||||
for _ in 0..increments as usize {
|
||||
pos.0 += pos_delta / increments;
|
||||
|
||||
@ -197,12 +203,12 @@ impl<'a> System<'a> for Sys {
|
||||
&& -dir.z > 0.1
|
||||
// ...and we're falling/standing OR there is a block *directly* beneath our current origin (note: not hitbox)...
|
||||
&& (vel.0.z <= 0.0 || terrain
|
||||
.get((pos.0 - Vec3::unit_z()).map(|e| e.floor() as i32))
|
||||
.get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32))
|
||||
.map(|vox| !vox.is_empty())
|
||||
.unwrap_or(false))
|
||||
// ...and there is a collision with a block beneath our current hitbox...
|
||||
&& collision_with(
|
||||
pos.0 + resolve_dir - Vec3::unit_z() * 1.05,
|
||||
old_pos + resolve_dir - Vec3::unit_z() * 1.05,
|
||||
near_iter.clone(),
|
||||
)
|
||||
{
|
||||
|
@ -547,7 +547,7 @@ fn handle_object(server: &mut Server, entity: EcsEntity, args: String, _action:
|
||||
}
|
||||
};
|
||||
server
|
||||
.create_object(pos, ori, obj_type)
|
||||
.create_object(pos, obj_type)
|
||||
.with(comp::Ori(
|
||||
// converts player orientation into a 90° rotation for the object by using the axis with the highest value
|
||||
ori.0
|
||||
|
@ -23,6 +23,7 @@ use common::{
|
||||
vol::Vox,
|
||||
};
|
||||
use log::debug;
|
||||
use rand::Rng;
|
||||
use specs::{join::Join, world::EntityBuilder as EcsEntityBuilder, Builder, Entity as EcsEntity};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
@ -155,14 +156,12 @@ impl Server {
|
||||
pub fn create_object(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
ori: comp::Ori,
|
||||
object: comp::object::Body,
|
||||
) -> EcsEntityBuilder {
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(ori)
|
||||
.with(comp::Vel(Vec3::zero()))
|
||||
.with(comp::Ori(Vec3::unit_y()))
|
||||
.with(comp::Body::Object(object))
|
||||
@ -191,6 +190,8 @@ impl Server {
|
||||
state.write_component(entity, comp::Vel(Vec3::zero()));
|
||||
state.write_component(entity, comp::Ori(Vec3::unit_y()));
|
||||
state.write_component(entity, comp::ActionState::default());
|
||||
state.write_component(entity, comp::Inventory::default());
|
||||
state.write_component(entity, comp::InventoryUpdate);
|
||||
// Make sure physics are accepted.
|
||||
state.write_component(entity, comp::ForceUpdate);
|
||||
|
||||
@ -417,6 +418,7 @@ impl Server {
|
||||
let mut disconnected_clients = Vec::new();
|
||||
let mut requested_chunks = Vec::new();
|
||||
let mut modified_blocks = Vec::new();
|
||||
let mut dropped_items = Vec::new();
|
||||
|
||||
self.clients.remove_if(|entity, client| {
|
||||
let mut disconnect = false;
|
||||
@ -488,6 +490,66 @@ impl Server {
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
ClientMsg::SwapInventorySlots(a, b) => {
|
||||
state
|
||||
.ecs()
|
||||
.write_storage::<comp::Inventory>()
|
||||
.get_mut(entity)
|
||||
.map(|inv| inv.swap_slots(a, b));
|
||||
state.write_component(entity, comp::InventoryUpdate);
|
||||
}
|
||||
ClientMsg::DropInventorySlot(x) => {
|
||||
let item = state
|
||||
.ecs()
|
||||
.write_storage::<comp::Inventory>()
|
||||
.get_mut(entity)
|
||||
.and_then(|inv| inv.remove(x));
|
||||
|
||||
state.write_component(entity, comp::InventoryUpdate);
|
||||
|
||||
if let (Some(item), Some(pos)) =
|
||||
(item, state.ecs().read_storage::<comp::Pos>().get(entity))
|
||||
{
|
||||
dropped_items.push((
|
||||
*pos,
|
||||
state
|
||||
.ecs()
|
||||
.read_storage::<comp::Ori>()
|
||||
.get(entity)
|
||||
.copied()
|
||||
.unwrap_or(comp::Ori(Vec3::unit_y())),
|
||||
item,
|
||||
));
|
||||
}
|
||||
}
|
||||
ClientMsg::PickUp(uid) => {
|
||||
let item_entity = state.ecs_mut().entity_from_uid(uid);
|
||||
|
||||
let ecs = state.ecs_mut();
|
||||
|
||||
let item_entity = if let (Some((item, item_entity)), Some(inv)) = (
|
||||
item_entity.and_then(|item_entity| {
|
||||
ecs.write_storage::<comp::Item>()
|
||||
.get_mut(item_entity)
|
||||
.map(|item| (*item, item_entity))
|
||||
}),
|
||||
ecs.write_storage::<comp::Inventory>().get_mut(entity),
|
||||
) {
|
||||
if inv.insert(item).is_none() {
|
||||
Some(item_entity)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(item_entity) = item_entity {
|
||||
let _ = ecs.delete_entity_synced(item_entity);
|
||||
}
|
||||
|
||||
state.write_component(entity, comp::InventoryUpdate);
|
||||
}
|
||||
ClientMsg::Character { name, body } => match client.client_state {
|
||||
// Become Registered first.
|
||||
ClientState::Connected => {
|
||||
@ -664,6 +726,17 @@ impl Server {
|
||||
self.state.set_block(pos, block);
|
||||
}
|
||||
|
||||
for (pos, ori, item) in dropped_items {
|
||||
let vel = ori.0.normalized() * 5.0
|
||||
+ Vec3::unit_z() * 10.0
|
||||
+ Vec3::<f32>::zero().map(|_| rand::thread_rng().gen::<f32>() - 0.5) * 4.0;
|
||||
self.create_object(Default::default(), comp::object::Body::Pouch)
|
||||
.with(comp::Pos(pos.0 + Vec3::unit_z() * 0.25))
|
||||
.with(item)
|
||||
.with(comp::Vel(vel))
|
||||
.build();
|
||||
}
|
||||
|
||||
Ok(frontend_events)
|
||||
}
|
||||
|
||||
@ -919,11 +992,27 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
// Sync inventories
|
||||
for (entity, inventory, _) in (
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<comp::Inventory>(),
|
||||
&self.state.ecs().read_storage::<comp::InventoryUpdate>(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
self.clients
|
||||
.notify(entity, ServerMsg::InventoryUpdate(inventory.clone()));
|
||||
}
|
||||
|
||||
// Remove all force flags.
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::ForceUpdate>()
|
||||
.clear();
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::InventoryUpdate>()
|
||||
.clear();
|
||||
}
|
||||
|
||||
pub fn generate_chunk(&mut self, key: Vec2<i32>) {
|
||||
|
@ -30,7 +30,7 @@ void main() {
|
||||
f_norm = vec3(0.0, 0.0, 1.0) * norm_dir;
|
||||
}
|
||||
|
||||
vec3 light = (get_sun_diffuse(f_norm, time_of_day.x) + light_at(f_pos, f_norm)) * f_light;
|
||||
vec3 light = get_sun_diffuse(f_norm, time_of_day.x) * f_light + light_at(f_pos, f_norm);
|
||||
vec3 surf_color = f_col * light;
|
||||
|
||||
float fog_level = fog(f_pos.xy, focus_pos.xy);
|
||||
|
@ -2,7 +2,7 @@ use super::{
|
||||
super::{Animation, SkeletonAttr},
|
||||
CharacterSkeleton,
|
||||
};
|
||||
use common::comp::item::Weapon;
|
||||
use common::comp::item::Tool;
|
||||
use std::{f32::consts::PI, ops::Mul};
|
||||
use vek::*;
|
||||
|
||||
@ -61,9 +61,9 @@ impl Animation for CidleAnimation {
|
||||
next.shorts.ori = Quaternion::rotation_x(0.0);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
match Weapon::Hammer {
|
||||
match Tool::Hammer {
|
||||
//TODO: Inventory
|
||||
Weapon::Sword => {
|
||||
Tool::Sword => {
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-6.0 + wave_ultra_slow_cos * 1.0,
|
||||
3.5 + wave_ultra_slow_cos * 0.5,
|
||||
@ -88,7 +88,7 @@ impl Animation for CidleAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Axe => {
|
||||
Tool::Axe => {
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-6.0 + wave_ultra_slow_cos * 1.0,
|
||||
3.5 + wave_ultra_slow_cos * 0.5,
|
||||
@ -113,7 +113,7 @@ impl Animation for CidleAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Hammer => {
|
||||
Tool::Hammer => {
|
||||
next.l_hand.offset = Vec3::new(-7.0, 8.25, 2.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3)
|
||||
* Quaternion::rotation_y(-1.2)
|
||||
@ -134,7 +134,7 @@ impl Animation for CidleAnimation {
|
||||
* Quaternion::rotation_z(wave_ultra_slow * 0.2);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Staff => {
|
||||
Tool::Staff => {
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-6.0 + wave_ultra_slow_cos * 1.0,
|
||||
3.5 + wave_ultra_slow_cos * 0.5,
|
||||
@ -159,7 +159,7 @@ impl Animation for CidleAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::SwordShield => {
|
||||
Tool::SwordShield => {
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-6.0 + wave_ultra_slow_cos * 1.0,
|
||||
3.5 + wave_ultra_slow_cos * 0.5,
|
||||
@ -184,7 +184,7 @@ impl Animation for CidleAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Bow => {
|
||||
Tool::Bow => {
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-6.0 + wave_ultra_slow_cos * 1.0,
|
||||
3.5 + wave_ultra_slow_cos * 0.5,
|
||||
@ -209,7 +209,7 @@ impl Animation for CidleAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Daggers => {
|
||||
Tool::Daggers => {
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-6.0 + wave_ultra_slow_cos * 1.0,
|
||||
3.5 + wave_ultra_slow_cos * 0.5,
|
||||
|
@ -2,7 +2,7 @@ use super::{
|
||||
super::{Animation, SkeletonAttr},
|
||||
CharacterSkeleton,
|
||||
};
|
||||
use common::comp::item::Weapon;
|
||||
use common::comp::item::Tool;
|
||||
use std::f32::consts::PI;
|
||||
use vek::*;
|
||||
|
||||
@ -43,9 +43,9 @@ impl Animation for CjumpAnimation {
|
||||
next.shorts.ori = Quaternion::rotation_z(0.0);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
match Weapon::Hammer {
|
||||
match Tool::Hammer {
|
||||
//TODO: Inventory
|
||||
Weapon::Sword => {
|
||||
Tool::Sword => {
|
||||
next.l_hand.offset = Vec3::new(-7.0, 3.25, 0.25 + wave_stop * 2.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
@ -62,7 +62,7 @@ impl Animation for CjumpAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Axe => {
|
||||
Tool::Axe => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
@ -79,7 +79,7 @@ impl Animation for CjumpAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Hammer => {
|
||||
Tool::Hammer => {
|
||||
next.l_hand.offset = Vec3::new(-7.0, 8.25, 2.0 + wave_stop * 2.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3)
|
||||
* Quaternion::rotation_y(-1.2)
|
||||
@ -100,7 +100,7 @@ impl Animation for CjumpAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Staff => {
|
||||
Tool::Staff => {
|
||||
next.l_hand.offset = Vec3::new(-7.0, 7.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3)
|
||||
* Quaternion::rotation_y(-1.7)
|
||||
@ -121,7 +121,7 @@ impl Animation for CjumpAnimation {
|
||||
* Quaternion::rotation_z(1.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::SwordShield => {
|
||||
Tool::SwordShield => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
@ -138,7 +138,7 @@ impl Animation for CjumpAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Bow => {
|
||||
Tool::Bow => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
@ -155,7 +155,7 @@ impl Animation for CjumpAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Daggers => {
|
||||
Tool::Daggers => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
|
@ -2,7 +2,7 @@ use super::{
|
||||
super::{Animation, SkeletonAttr},
|
||||
CharacterSkeleton,
|
||||
};
|
||||
use common::comp::item::Weapon;
|
||||
use common::comp::item::Tool;
|
||||
use std::f32::consts::PI;
|
||||
use std::ops::Mul;
|
||||
use vek::*;
|
||||
@ -61,9 +61,9 @@ impl Animation for CrunAnimation {
|
||||
next.shorts.ori = Quaternion::rotation_z(wave * 0.6);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
match Weapon::Hammer {
|
||||
match Tool::Hammer {
|
||||
//TODO: Inventory
|
||||
Weapon::Sword => {
|
||||
Tool::Sword => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.75, 0.25);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
@ -80,7 +80,7 @@ impl Animation for CrunAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Axe => {
|
||||
Tool::Axe => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
@ -97,7 +97,7 @@ impl Animation for CrunAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Hammer => {
|
||||
Tool::Hammer => {
|
||||
next.l_hand.offset = Vec3::new(-7.0, 8.25, 3.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3)
|
||||
* Quaternion::rotation_y(-1.2)
|
||||
@ -118,7 +118,7 @@ impl Animation for CrunAnimation {
|
||||
* Quaternion::rotation_z(wave * -0.25);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Staff => {
|
||||
Tool::Staff => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
@ -135,7 +135,7 @@ impl Animation for CrunAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::SwordShield => {
|
||||
Tool::SwordShield => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
@ -152,7 +152,7 @@ impl Animation for CrunAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Bow => {
|
||||
Tool::Bow => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
@ -169,7 +169,7 @@ impl Animation for CrunAnimation {
|
||||
* Quaternion::rotation_z(0.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
}
|
||||
Weapon::Daggers => {
|
||||
Tool::Daggers => {
|
||||
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
|
||||
next.l_hand.ori = Quaternion::rotation_x(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.01;
|
||||
|
@ -5,7 +5,7 @@ pub mod quadruped;
|
||||
pub mod quadrupedmedium;
|
||||
|
||||
use crate::render::FigureBoneData;
|
||||
use common::comp::{self, item::Weapon};
|
||||
use common::comp::{self, item::Tool};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@ -145,25 +145,25 @@ impl<'a> From<&'a comp::humanoid::Body> for SkeletonAttr {
|
||||
(Danari, Male) => 0.0,
|
||||
(Danari, Female) => 0.0,
|
||||
},
|
||||
weapon_x: match Weapon::Hammer {
|
||||
weapon_x: match Tool::Hammer {
|
||||
// TODO: Inventory
|
||||
Weapon::Sword => 0.0,
|
||||
Weapon::Axe => 3.0,
|
||||
Weapon::Hammer => 0.0,
|
||||
Weapon::SwordShield => 3.0,
|
||||
Weapon::Staff => 3.0,
|
||||
Weapon::Bow => 0.0,
|
||||
Weapon::Daggers => 0.0,
|
||||
Tool::Sword => 0.0,
|
||||
Tool::Axe => 3.0,
|
||||
Tool::Hammer => 0.0,
|
||||
Tool::SwordShield => 3.0,
|
||||
Tool::Staff => 3.0,
|
||||
Tool::Bow => 0.0,
|
||||
Tool::Daggers => 0.0,
|
||||
},
|
||||
weapon_y: match Weapon::Hammer {
|
||||
weapon_y: match Tool::Hammer {
|
||||
// TODO: Inventory
|
||||
Weapon::Sword => -1.25,
|
||||
Weapon::Axe => 0.0,
|
||||
Weapon::Hammer => -2.0,
|
||||
Weapon::SwordShield => 0.0,
|
||||
Weapon::Staff => 0.0,
|
||||
Weapon::Bow => -2.0,
|
||||
Weapon::Daggers => -2.0,
|
||||
Tool::Sword => -1.25,
|
||||
Tool::Axe => 0.0,
|
||||
Tool::Hammer => -2.0,
|
||||
Tool::SwordShield => 0.0,
|
||||
Tool::Staff => 0.0,
|
||||
Tool::Bow => -2.0,
|
||||
Tool::Daggers => -2.0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::{img_ids::Imgs, Fonts, TEXT_COLOR};
|
||||
use super::{img_ids::Imgs, Event as HudEvent, Fonts, TEXT_COLOR};
|
||||
use client::Client;
|
||||
use conrod_core::{
|
||||
color,
|
||||
position::Relative,
|
||||
@ -16,17 +17,16 @@ widget_ids! {
|
||||
inv_grid_1,
|
||||
inv_grid_2,
|
||||
inv_scrollbar,
|
||||
inv_slot_0,
|
||||
inv_slots_0,
|
||||
map_title,
|
||||
inv_slot[],
|
||||
item1,
|
||||
inv_slots[],
|
||||
items[],
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct Bag<'a> {
|
||||
inventory_space: usize,
|
||||
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a Fonts,
|
||||
#[conrod(common_builder)]
|
||||
@ -34,9 +34,9 @@ pub struct Bag<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Bag<'a> {
|
||||
pub fn new(inventory_space: usize, imgs: &'a Imgs, fonts: &'a Fonts) -> Self {
|
||||
pub fn new(client: &'a Client, imgs: &'a Imgs, fonts: &'a Fonts) -> Self {
|
||||
Self {
|
||||
inventory_space,
|
||||
client,
|
||||
imgs,
|
||||
fonts,
|
||||
common: widget::CommonBuilder::default(),
|
||||
@ -46,11 +46,13 @@ impl<'a> Bag<'a> {
|
||||
|
||||
pub struct State {
|
||||
ids: Ids,
|
||||
selected_slot: Option<usize>,
|
||||
}
|
||||
|
||||
const BAG_SCALE: f64 = 4.0;
|
||||
|
||||
pub enum Event {
|
||||
HudEvent(HudEvent),
|
||||
Close,
|
||||
}
|
||||
|
||||
@ -62,6 +64,7 @@ impl<'a> Widget for Bag<'a> {
|
||||
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
|
||||
State {
|
||||
ids: Ids::new(id_gen),
|
||||
selected_slot: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,87 +75,115 @@ impl<'a> Widget for Bag<'a> {
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs { state, ui, .. } = args;
|
||||
|
||||
let mut event = None;
|
||||
|
||||
let invs = self.client.inventories();
|
||||
let inventory = match invs.get(self.client.entity()) {
|
||||
Some(inv) => inv,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
// Bag parts
|
||||
Image::new(self.imgs.bag_bot)
|
||||
.w_h(61.0 * BAG_SCALE, 9.0 * BAG_SCALE)
|
||||
.bottom_right_with_margins_on(ui.window, 60.0, 5.0)
|
||||
.set(state.ids.bag_bot, ui);
|
||||
Image::new(self.imgs.bag_mid)
|
||||
.w_h(
|
||||
61.0 * BAG_SCALE,
|
||||
((self.inventory_space + 4) / 5) as f64 * 44.0,
|
||||
)
|
||||
.up_from(state.ids.bag_bot, 0.0)
|
||||
.set(state.ids.bag_mid, ui);
|
||||
Image::new(self.imgs.bag_top)
|
||||
.w_h(61.0 * BAG_SCALE, 9.0 * BAG_SCALE)
|
||||
.up_from(state.ids.bag_mid, 0.0)
|
||||
.set(state.ids.bag_top, ui);
|
||||
Image::new(self.imgs.bag_mid)
|
||||
.w_h(61.0 * BAG_SCALE, ((inventory.len() + 4) / 5) as f64 * 44.0)
|
||||
.up_from(state.ids.bag_bot, 0.0)
|
||||
.set(state.ids.bag_mid, ui);
|
||||
|
||||
// Alignment for Grid
|
||||
Rectangle::fill_with(
|
||||
[
|
||||
54.0 * BAG_SCALE,
|
||||
((self.inventory_space + 4) / 5) as f64 * 44.0,
|
||||
],
|
||||
[54.0 * BAG_SCALE, ((inventory.len() + 4) / 5) as f64 * 44.0],
|
||||
color::TRANSPARENT,
|
||||
)
|
||||
.top_left_with_margins_on(state.ids.bag_top, 9.0 * BAG_SCALE, 3.0 * BAG_SCALE)
|
||||
.scroll_kids()
|
||||
.scroll_kids_vertically()
|
||||
.set(state.ids.inv_alignment, ui);
|
||||
|
||||
// Grid
|
||||
/*Image::new(self.imgs.inv_grid)
|
||||
.w_h(61.0 * BAG_SCALE, 111.0 * BAG_SCALE)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.5)))
|
||||
.mid_top_with_margin_on(state.ids.inv_alignment, 0.0)
|
||||
.set(state.ids.inv_grid_1, ui);
|
||||
Image::new(self.imgs.inv_grid)
|
||||
.w_h(61.0 * BAG_SCALE, 111.0 * BAG_SCALE)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.5)))
|
||||
.mid_top_with_margin_on(state.ids.inv_alignment, 110.0 * BAG_SCALE)
|
||||
.set(state.ids.inv_grid_2, ui);
|
||||
Scrollbar::y_axis(state.ids.inv_alignment)
|
||||
.thickness(5.0)
|
||||
.rgba(0.33, 0.33, 0.33, 1.0)
|
||||
.set(state.ids.inv_scrollbar, ui);*/
|
||||
// Create available inventory slot widgets
|
||||
if state.ids.inv_slot.len() < self.inventory_space {
|
||||
|
||||
if state.ids.inv_slots.len() < inventory.len() {
|
||||
state.update(|s| {
|
||||
s.ids
|
||||
.inv_slot
|
||||
.resize(self.inventory_space, &mut ui.widget_id_generator());
|
||||
.inv_slots
|
||||
.resize(inventory.len(), &mut ui.widget_id_generator());
|
||||
});
|
||||
}
|
||||
// "Allowed" max. inventory space should be handled serverside and thus isn't limited in the UI
|
||||
for i in 0..self.inventory_space {
|
||||
|
||||
if state.ids.items.len() < inventory.len() {
|
||||
state.update(|s| {
|
||||
s.ids
|
||||
.items
|
||||
.resize(inventory.len(), &mut ui.widget_id_generator());
|
||||
});
|
||||
}
|
||||
|
||||
// Display inventory contents
|
||||
|
||||
for (i, item) in inventory.slots().iter().enumerate() {
|
||||
let x = i % 5;
|
||||
let y = i / 5;
|
||||
Button::image(self.imgs.inv_slot)
|
||||
|
||||
let is_selected = Some(i) == state.selected_slot;
|
||||
|
||||
// Slot
|
||||
if Button::image(self.imgs.inv_slot)
|
||||
.top_left_with_margins_on(
|
||||
state.ids.inv_alignment,
|
||||
4.0 + y as f64 * (40.0 + 4.0),
|
||||
4.0 + x as f64 * (40.0 + 4.0),
|
||||
) // conrod uses a (y,x) format for placing...
|
||||
.parent(state.ids.bag_mid) // Avoids the background overlapping available slots
|
||||
.parent(state.ids.inv_alignment) // Avoids the background overlapping available slots
|
||||
.w_h(40.0, 40.0)
|
||||
.set(state.ids.inv_slot[i], ui);
|
||||
.image_color(if is_selected {
|
||||
color::WHITE
|
||||
} else {
|
||||
color::DARK_YELLOW
|
||||
})
|
||||
.floating(true)
|
||||
.set(state.ids.inv_slots[i], ui)
|
||||
.was_clicked()
|
||||
{
|
||||
let selected_slot = match state.selected_slot {
|
||||
Some(a) => {
|
||||
if a == i {
|
||||
event = Some(Event::HudEvent(HudEvent::DropInventorySlot(i)));
|
||||
} else {
|
||||
event = Some(Event::HudEvent(HudEvent::SwapInventorySlots(a, i)));
|
||||
}
|
||||
None
|
||||
}
|
||||
None if item.is_some() => Some(i),
|
||||
None => None,
|
||||
};
|
||||
state.update(|s| s.selected_slot = selected_slot);
|
||||
}
|
||||
|
||||
// Item
|
||||
if item.is_some() {
|
||||
Button::image(self.imgs.potion_red) // TODO: Insert variable image depending on the item displayed in that slot
|
||||
.w_h(4.0 * 4.4, 7.0 * 4.4) // TODO: Fix height and scale width correctly to that to avoid a stretched item image
|
||||
.middle_of(state.ids.inv_slots[i]) // TODO: Items need to be assigned to a certain slot and then placed like in this example
|
||||
.label("5x") // TODO: Quantity goes here...
|
||||
.label_font_id(self.fonts.opensans)
|
||||
.label_font_size(12)
|
||||
.label_x(Relative::Scalar(10.0))
|
||||
.label_y(Relative::Scalar(-10.0))
|
||||
.label_color(TEXT_COLOR)
|
||||
.parent(state.ids.inv_slots[i])
|
||||
.graphics_for(state.ids.inv_slots[i])
|
||||
.set(state.ids.items[i], ui);
|
||||
}
|
||||
}
|
||||
// Test Item
|
||||
if self.inventory_space > 0 {
|
||||
Button::image(self.imgs.potion_red) // TODO: Insert variable image depending on the item displayed in that slot
|
||||
.w_h(4.0 * 4.4, 7.0 * 4.4) // TODO: Fix height and scale width correctly to that to avoid a stretched item image
|
||||
.middle_of(state.ids.inv_slot[0]) // TODO: Items need to be assigned to a certain slot and then placed like in this example
|
||||
.label("5x") // TODO: Quantity goes here...
|
||||
.label_font_id(self.fonts.opensans)
|
||||
.label_font_size(12)
|
||||
.label_x(Relative::Scalar(10.0))
|
||||
.label_y(Relative::Scalar(-10.0))
|
||||
.label_color(TEXT_COLOR)
|
||||
.set(state.ids.item1, ui); // TODO: Add widget_id generator for displayed items
|
||||
}
|
||||
// X-button
|
||||
|
||||
// Close button
|
||||
|
||||
if Button::image(self.imgs.close_button)
|
||||
.w_h(28.0, 28.0)
|
||||
.hover_image(self.imgs.close_button_hover)
|
||||
@ -161,9 +192,9 @@ impl<'a> Widget for Bag<'a> {
|
||||
.set(state.ids.bag_close, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
Some(Event::Close)
|
||||
} else {
|
||||
None
|
||||
event = Some(Event::Close);
|
||||
}
|
||||
|
||||
event
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +141,8 @@ pub enum Event {
|
||||
CrosshairType(CrosshairType),
|
||||
UiScale(ScaleChange),
|
||||
CharacterSelection,
|
||||
SwapInventorySlots(usize, usize),
|
||||
DropInventorySlot(usize),
|
||||
Logout,
|
||||
Quit,
|
||||
}
|
||||
@ -588,9 +590,8 @@ impl Hud {
|
||||
|
||||
// Bag contents
|
||||
if self.show.bag {
|
||||
match Bag::new(self.inventory_space, &self.imgs, &self.fonts)
|
||||
.set(self.ids.bag, ui_widgets)
|
||||
{
|
||||
match Bag::new(client, &self.imgs, &self.fonts).set(self.ids.bag, ui_widgets) {
|
||||
Some(bag::Event::HudEvent(event)) => events.push(event),
|
||||
Some(bag::Event::Close) => {
|
||||
self.show.bag(false);
|
||||
self.force_ungrab = true;
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
GlobalState,
|
||||
};
|
||||
use client::Client;
|
||||
use common::comp::{humanoid, item::Weapon};
|
||||
use common::comp::{humanoid, item::Tool};
|
||||
use conrod_core::{
|
||||
color,
|
||||
color::TRANSPARENT,
|
||||
@ -109,7 +109,7 @@ widget_ids! {
|
||||
body_type_1,
|
||||
body_type_2,
|
||||
|
||||
// Weapons
|
||||
// Tools
|
||||
sword,
|
||||
sword_button,
|
||||
daggers,
|
||||
@ -152,7 +152,7 @@ image_ids! {
|
||||
slider_range: "voxygen/element/slider/track.png",
|
||||
slider_indicator: "voxygen/element/slider/indicator.png",
|
||||
|
||||
// Weapon Icons
|
||||
// Tool Icons
|
||||
daggers: "voxygen/element/icons/daggers.png",
|
||||
sword: "voxygen/element/icons/sword.png",
|
||||
axe: "voxygen/element/icons/axe.png",
|
||||
@ -209,7 +209,7 @@ pub struct CharSelectionUi {
|
||||
character_creation: bool,
|
||||
pub character_name: String,
|
||||
pub character_body: humanoid::Body,
|
||||
pub character_weapon: Weapon, // TODO: Move into ecs inventory struct?
|
||||
pub character_weapon: Tool, // TODO: Move into ecs inventory struct?
|
||||
}
|
||||
|
||||
impl CharSelectionUi {
|
||||
@ -235,7 +235,7 @@ impl CharSelectionUi {
|
||||
character_creation: false,
|
||||
character_name: "Character Name".to_string(),
|
||||
character_body: humanoid::Body::random(),
|
||||
character_weapon: Weapon::Sword,
|
||||
character_weapon: Tool::Sword,
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,7 +344,7 @@ impl CharSelectionUi {
|
||||
.was_clicked()
|
||||
{
|
||||
self.character_creation = true;
|
||||
self.character_weapon = Weapon::Sword;
|
||||
self.character_weapon = Tool::Sword;
|
||||
}
|
||||
|
||||
// Alpha Version
|
||||
@ -553,7 +553,7 @@ impl CharSelectionUi {
|
||||
self.character_body.body_type = humanoid::BodyType::Female;
|
||||
}
|
||||
|
||||
// Alignment for Races and Weapons
|
||||
// Alignment for Races and Tools
|
||||
Rectangle::fill_with([214.0, 304.0], color::TRANSPARENT)
|
||||
.mid_bottom_with_margin_on(self.ids.creation_buttons_alignment_1, -324.0)
|
||||
.set(self.ids.creation_buttons_alignment_2, ui_widgets);
|
||||
@ -710,7 +710,7 @@ impl CharSelectionUi {
|
||||
.w_h(70.0, 70.0)
|
||||
.bottom_left_with_margins_on(self.ids.creation_buttons_alignment_2, 0.0, 0.0)
|
||||
.set(self.ids.hammer, ui_widgets);
|
||||
if Button::image(if let Weapon::Hammer = self.character_weapon {
|
||||
if Button::image(if let Tool::Hammer = self.character_weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -721,7 +721,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.hammer_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character_weapon = Weapon::Hammer;
|
||||
self.character_weapon = Tool::Hammer;
|
||||
}
|
||||
// REMOVE THIS AFTER IMPLEMENTATION
|
||||
/*Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
|
||||
@ -734,7 +734,7 @@ impl CharSelectionUi {
|
||||
.w_h(70.0, 70.0)
|
||||
.right_from(self.ids.hammer, 2.0)
|
||||
.set(self.ids.bow, ui_widgets);
|
||||
if Button::image(if let Weapon::Bow = self.character_weapon {
|
||||
if Button::image(if let Tool::Bow = self.character_weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -745,7 +745,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.bow_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
//self.character_weapon = Weapon::Bow;
|
||||
//self.character_weapon = Tool::Bow;
|
||||
}
|
||||
// REMOVE THIS AFTER IMPLEMENTATION
|
||||
Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
|
||||
@ -756,7 +756,7 @@ impl CharSelectionUi {
|
||||
.w_h(70.0, 70.0)
|
||||
.right_from(self.ids.bow, 2.0)
|
||||
.set(self.ids.staff, ui_widgets);
|
||||
if Button::image(if let Weapon::Staff = self.character_weapon {
|
||||
if Button::image(if let Tool::Staff = self.character_weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -767,7 +767,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.staff_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
//self.character_weapon = Weapon::Staff;
|
||||
//self.character_weapon = Tool::Staff;
|
||||
}
|
||||
// REMOVE THIS AFTER IMPLEMENTATION
|
||||
Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
|
||||
@ -778,7 +778,7 @@ impl CharSelectionUi {
|
||||
.w_h(70.0, 70.0)
|
||||
.up_from(self.ids.hammer, 2.0)
|
||||
.set(self.ids.sword, ui_widgets);
|
||||
if Button::image(if let Weapon::Sword = self.character_weapon {
|
||||
if Button::image(if let Tool::Sword = self.character_weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -789,7 +789,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.sword_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character_weapon = Weapon::Sword;
|
||||
self.character_weapon = Tool::Sword;
|
||||
}
|
||||
|
||||
// Daggers
|
||||
@ -797,7 +797,7 @@ impl CharSelectionUi {
|
||||
.w_h(70.0, 70.0)
|
||||
.right_from(self.ids.sword, 2.0)
|
||||
.set(self.ids.daggers, ui_widgets);
|
||||
if Button::image(if let Weapon::Daggers = self.character_weapon {
|
||||
if Button::image(if let Tool::Daggers = self.character_weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -808,7 +808,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.daggers_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
// self.character_weapon = Weapon::Daggers;
|
||||
// self.character_weapon = Tool::Daggers;
|
||||
} // REMOVE THIS AFTER IMPLEMENTATION
|
||||
Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
|
||||
.middle_of(self.ids.daggers)
|
||||
@ -819,7 +819,7 @@ impl CharSelectionUi {
|
||||
.w_h(70.0, 70.0)
|
||||
.right_from(self.ids.daggers, 2.0)
|
||||
.set(self.ids.axe, ui_widgets);
|
||||
if Button::image(if let Weapon::Axe = self.character_weapon {
|
||||
if Button::image(if let Tool::Axe = self.character_weapon {
|
||||
self.imgs.icon_border_pressed
|
||||
} else {
|
||||
self.imgs.icon_border
|
||||
@ -830,7 +830,7 @@ impl CharSelectionUi {
|
||||
.set(self.ids.axe_button, ui_widgets)
|
||||
.was_clicked()
|
||||
{
|
||||
self.character_weapon = Weapon::Axe;
|
||||
self.character_weapon = Tool::Axe;
|
||||
}
|
||||
// REMOVE THIS AFTER IMPLEMENTATION
|
||||
/*Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8))
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||
use client::Client;
|
||||
use common::{
|
||||
assets,
|
||||
comp::{self, humanoid, item::Weapon, object, quadruped, quadruped_medium, Body},
|
||||
comp::{self, humanoid, item::Tool, object, quadruped, quadruped_medium, Body},
|
||||
figure::Segment,
|
||||
terrain::TerrainChunkSize,
|
||||
vol::VolSize,
|
||||
@ -61,7 +61,7 @@ impl FigureModelCache {
|
||||
Some(Self::load_right_hand(body.hand)),
|
||||
Some(Self::load_left_foot(body.foot)),
|
||||
Some(Self::load_right_foot(body.foot)),
|
||||
Some(Self::load_weapon(Weapon::Hammer)), // TODO: Inventory
|
||||
Some(Self::load_weapon(Tool::Hammer)), // TODO: Inventory
|
||||
Some(Self::load_left_shoulder(body.shoulder)),
|
||||
Some(Self::load_right_shoulder(body.shoulder)),
|
||||
Some(Self::load_draw()),
|
||||
@ -312,15 +312,15 @@ impl FigureModelCache {
|
||||
)
|
||||
}
|
||||
|
||||
fn load_weapon(weapon: Weapon) -> Mesh<FigurePipeline> {
|
||||
fn load_weapon(weapon: Tool) -> Mesh<FigurePipeline> {
|
||||
let (name, offset) = match weapon {
|
||||
Weapon::Sword => ("weapon/sword/rusty_2h.vox", Vec3::new(-1.5, -6.5, -4.0)),
|
||||
Weapon::Axe => ("weapon/axe/rusty_2h.vox", Vec3::new(-1.5, -6.5, -4.0)),
|
||||
Weapon::Hammer => ("weapon/hammer/rusty_2h.vox", Vec3::new(-2.5, -5.5, -4.0)),
|
||||
Weapon::Daggers => ("weapon/hammer/rusty_2h.vox", Vec3::new(-2.5, -5.5, -4.0)),
|
||||
Weapon::SwordShield => ("weapon/axe/rusty_2h.vox", Vec3::new(-2.5, -6.5, -2.0)),
|
||||
Weapon::Bow => ("weapon/hammer/rusty_2h.vox", Vec3::new(-2.5, -5.5, -4.0)),
|
||||
Weapon::Staff => ("weapon/axe/rusty_2h.vox", Vec3::new(-2.5, -6.5, -2.0)),
|
||||
Tool::Sword => ("weapon/sword/rusty_2h.vox", Vec3::new(-1.5, -6.5, -4.0)),
|
||||
Tool::Axe => ("weapon/axe/rusty_2h.vox", Vec3::new(-1.5, -6.5, -4.0)),
|
||||
Tool::Hammer => ("weapon/hammer/rusty_2h.vox", Vec3::new(-2.5, -5.5, -4.0)),
|
||||
Tool::Daggers => ("weapon/hammer/rusty_2h.vox", Vec3::new(-2.5, -5.5, -4.0)),
|
||||
Tool::SwordShield => ("weapon/axe/rusty_2h.vox", Vec3::new(-2.5, -6.5, -2.0)),
|
||||
Tool::Bow => ("weapon/hammer/rusty_2h.vox", Vec3::new(-2.5, -5.5, -4.0)),
|
||||
Tool::Staff => ("weapon/axe/rusty_2h.vox", Vec3::new(-2.5, -6.5, -2.0)),
|
||||
};
|
||||
Self::load_mesh(name, offset)
|
||||
}
|
||||
@ -583,6 +583,7 @@ impl FigureModelCache {
|
||||
"object/carpet_human_squircle.vox",
|
||||
Vec3::new(-21.0, -21.0, -0.5),
|
||||
),
|
||||
object::Body::Pouch => ("object/pouch.vox", Vec3::new(-5.5, -4.5, 0.0)),
|
||||
};
|
||||
Self::load_mesh(name, offset)
|
||||
}
|
||||
@ -970,8 +971,13 @@ impl<S: Skeleton> FigureState<S> {
|
||||
dt: f32,
|
||||
) {
|
||||
// Update interpolation values
|
||||
self.pos = Lerp::lerp(self.pos, pos, 15.0 * dt);
|
||||
self.ori = Slerp::slerp(self.ori, ori, 7.5 * dt);
|
||||
if self.pos.distance_squared(pos) < 64.0 * 64.0 {
|
||||
self.pos = Lerp::lerp(self.pos, pos, 15.0 * dt);
|
||||
self.ori = Slerp::slerp(self.ori, ori, 7.5 * dt);
|
||||
} else {
|
||||
self.pos = pos;
|
||||
self.ori = ori;
|
||||
}
|
||||
|
||||
let mat = Mat4::<f32>::identity()
|
||||
* Mat4::translation_3d(self.pos)
|
||||
|
@ -9,6 +9,7 @@ use crate::{
|
||||
use client::{self, Client};
|
||||
use common::{clock::Clock, comp, comp::Pos, msg::ClientState, terrain::Block, vol::ReadVol};
|
||||
use log::error;
|
||||
use specs::Join;
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
use vek::*;
|
||||
|
||||
@ -212,6 +213,35 @@ impl PlayState for SessionState {
|
||||
Event::InputUpdate(GameInput::Glide, state) => {
|
||||
self.controller.glide = state;
|
||||
}
|
||||
Event::InputUpdate(GameInput::Interact, state) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
|
||||
let player_pos = client
|
||||
.state()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(client.entity())
|
||||
.copied();
|
||||
|
||||
if let (Some(player_pos), true) = (player_pos, state) {
|
||||
let entity = (
|
||||
&client.state().ecs().entities(),
|
||||
&client.state().ecs().read_storage::<comp::Pos>(),
|
||||
&client.state().ecs().read_storage::<comp::Item>(),
|
||||
)
|
||||
.join()
|
||||
.filter(|(_, pos, _)| {
|
||||
pos.0.distance_squared(player_pos.0) < 3.0 * 3.0
|
||||
})
|
||||
.min_by_key(|(_, pos, _)| {
|
||||
(pos.0.distance_squared(player_pos.0) * 1000.0) as i32
|
||||
})
|
||||
.map(|(entity, _, _)| entity);
|
||||
|
||||
if let Some(entity) = entity {
|
||||
client.pick_up(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass all other events to the scene
|
||||
event => {
|
||||
@ -318,6 +348,12 @@ impl PlayState for SessionState {
|
||||
global_state.settings.graphics.max_fps = fps;
|
||||
global_state.settings.save_to_file_warn();
|
||||
}
|
||||
HudEvent::SwapInventorySlots(a, b) => {
|
||||
self.client.borrow_mut().swap_inventory_slots(a, b)
|
||||
}
|
||||
HudEvent::DropInventorySlot(x) => {
|
||||
self.client.borrow_mut().drop_inventory_slot(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ pub struct ControlSettings {
|
||||
pub attack: KeyMouse,
|
||||
pub second_attack: KeyMouse,
|
||||
pub roll: KeyMouse,
|
||||
pub interact: KeyMouse,
|
||||
}
|
||||
|
||||
impl Default for ControlSettings {
|
||||
@ -66,6 +67,7 @@ impl Default for ControlSettings {
|
||||
attack: KeyMouse::Mouse(MouseButton::Left),
|
||||
second_attack: KeyMouse::Mouse(MouseButton::Right),
|
||||
roll: KeyMouse::Mouse(MouseButton::Middle),
|
||||
interact: KeyMouse::Key(VirtualKeyCode::E),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ pub enum GameInput {
|
||||
SecondAttack,
|
||||
Roll,
|
||||
Respawn,
|
||||
Interact,
|
||||
}
|
||||
|
||||
/// Represents an incoming event from the window.
|
||||
@ -143,6 +144,7 @@ impl Window {
|
||||
key_map.insert(settings.controls.attack, GameInput::Attack);
|
||||
key_map.insert(settings.controls.second_attack, GameInput::SecondAttack);
|
||||
key_map.insert(settings.controls.roll, GameInput::Roll);
|
||||
key_map.insert(settings.controls.interact, GameInput::Interact);
|
||||
|
||||
let keypress_map = HashMap::new();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user