Merge branch 'zesterer/small-fixes' into 'master'

Actually small fixes this time

See merge request veloren/veloren!1175
This commit is contained in:
Joshua Barretto 2020-07-07 02:21:17 +00:00
commit 1df9fd6600
21 changed files with 253 additions and 147 deletions

View File

@ -60,6 +60,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Connection screen fails after 4 minutes if it can't connect to the server instead of 80 minutes
- Rebuilt quadruped_medium animation and assets
- Disabled destruction of most blocks by explosions
- Disable damage to pets
- Made pets healable
- Rebalanced fire staff
- Animals are more effective in combat
- Pathfinding is much smoother and pets are cleverer
- Animals run/turn at different speeds
### Removed

View File

@ -5,4 +5,12 @@ vec3 srgb_to_linear(vec3 srgb) {
vec3 lower = srgb/vec3(12.92);
return mix(higher, lower, cutoff);
}
}
vec3 linear_to_srgb(vec3 linear) {
bvec3 cutoff = lessThan(linear, vec3(0.0031308));
vec3 higher = vec3(1.055) * pow(linear, vec3(1.0 / 2.4)) - vec3(0.055);
vec3 lower = linear * vec3(12.92);
return mix(higher, lower, cutoff);
}

View File

@ -50,7 +50,7 @@ void main() {
// Select glowing
if (select_pos.w > 0 && select_pos.xyz == floor(sprite_pos)) {
f_col *= 4.0;
f_col *= 8.0;
}
f_light = 1.0;

View File

@ -21,6 +21,10 @@ out vec4 tgt_color;
#include <sky.glsl>
#include <light.glsl>
float vmax(vec3 v) {
return max(v.x, max(v.y, v.z));
}
void main() {
// First 3 normals are negative, next 3 are positive
vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
@ -46,6 +50,14 @@ void main() {
diffuse_light += point_light * ao;
vec3 col = f_col + hash(vec4(floor(f_chunk_pos * 3.0 - f_norm * 0.5), 0)) * 0.02; // Small-scale noise
// Select glowing
if (select_pos.w > 0 && select_pos.xyz == floor(f_pos - f_norm * 0.01)) {
if (vmax(abs(mod(f_pos - f_norm * 0.5, 1.0) - 0.5)) > 0.45) {
col *= 0.5;
}
}
vec3 surf_color = illuminate(srgb_to_linear(col), light, diffuse_light, ambient_light);
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);

View File

@ -1,9 +1,9 @@
use crate::path::Chaser;
use specs::{Component, Entity as EcsEntity};
use crate::{path::Chaser, sync::Uid};
use specs::{Component, Entity as EcsEntity, FlaggedStorage};
use specs_idvs::IdvStorage;
use vek::*;
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Alignment {
/// Wild animals and gentle giants
Wild,
@ -14,7 +14,7 @@ pub enum Alignment {
/// Farm animals and pets of villagers
Tame,
/// Pets you've tamed with a collar
Owned(EcsEntity),
Owned(Uid),
}
impl Alignment {
@ -40,10 +40,18 @@ impl Alignment {
_ => false,
}
}
// TODO: Remove this hack
pub fn is_friendly_to_players(&self) -> bool {
match self {
Alignment::Npc | Alignment::Tame | Alignment::Owned(_) => true,
_ => false,
}
}
}
impl Component for Alignment {
type Storage = IdvStorage<Self>;
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
}
#[derive(Clone, Debug, Default)]

View File

@ -331,18 +331,18 @@ impl Tool {
},
BasicRanged {
energy_cost: 0,
holdable: true,
holdable: false,
prepare_duration: Duration::from_millis(250),
recover_duration: Duration::from_millis(200),
recover_duration: Duration::from_millis(600),
projectile: Projectile {
hit_solid: vec![projectile::Effect::Vanish],
hit_entity: vec![
projectile::Effect::Damage(HealthChange {
// TODO: This should not be fixed (?)
amount: -2,
amount: -3,
cause: HealthSource::Projectile { owner: None },
}),
projectile::Effect::RewardEnergy(100),
projectile::Effect::RewardEnergy(150),
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(20),
@ -350,7 +350,7 @@ impl Tool {
},
projectile_body: Body::Object(object::Body::BoltFire),
projectile_light: Some(LightEmitter {
col: (0.72, 0.11, 0.11).into(),
col: (0.85, 0.5, 0.11).into(),
..Default::default()
}),
@ -375,7 +375,7 @@ impl Tool {
},
projectile_body: Body::Object(object::Body::BoltFireBig),
projectile_light: Some(LightEmitter {
col: (0.72, 0.11, 0.11).into(),
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),
@ -449,8 +449,8 @@ impl Tool {
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(1000),
base_healthchange: -2,
range: 3.5,
max_angle: 45.0,
range: 5.0,
max_angle: 60.0,
}],
}
}

View File

@ -7,7 +7,8 @@
bool_to_option,
label_break_value,
trait_alias,
type_alias_impl_trait
type_alias_impl_trait,
option_zip
)]
#[macro_use] extern crate serde_derive;

View File

@ -5,6 +5,7 @@ use crate::{
CharacterAbility, ItemConfig, Loadout,
},
};
use std::time::Duration;
/// Builder for character Loadouts, containing weapon and armour items belonging
/// to a character, along with some helper methods for loading Items and
@ -61,6 +62,40 @@ impl LoadoutBuilder {
)))
}
/// Default animal configuration
pub fn animal() -> Self {
Self(Loadout {
active_item: Some(ItemConfig {
item: assets::load_expect_cloned("common.items.weapons.empty"),
ability1: Some(CharacterAbility::BasicMelee {
energy_cost: 10,
buildup_duration: Duration::from_millis(600),
recover_duration: Duration::from_millis(100),
base_healthchange: -6,
range: 5.0,
max_angle: 80.0,
}),
ability2: None,
ability3: None,
block_ability: None,
dodge_ability: None,
}),
second_item: None,
shoulder: None,
chest: None,
belt: None,
hand: None,
pants: None,
foot: None,
back: None,
ring: None,
neck: None,
lantern: None,
head: None,
tabard: None,
})
}
/// Get the default [ItemConfig](../comp/struct.ItemConfig.html) for a tool
/// (weapon). This information is required for the `active` and `second`
/// weapon items in a loadout. If some customisation to the item's

View File

@ -17,6 +17,7 @@ sum_type! {
LightEmitter(comp::LightEmitter),
Item(comp::Item),
Scale(comp::Scale),
Alignment(comp::Alignment),
MountState(comp::MountState),
Mounting(comp::Mounting),
Mass(comp::Mass),
@ -43,6 +44,7 @@ sum_type! {
LightEmitter(PhantomData<comp::LightEmitter>),
Item(PhantomData<comp::Item>),
Scale(PhantomData<comp::Scale>),
Alignment(PhantomData<comp::Alignment>),
MountState(PhantomData<comp::MountState>),
Mounting(PhantomData<comp::Mounting>),
Mass(PhantomData<comp::Mass>),
@ -69,6 +71,7 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::LightEmitter(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Item(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Scale(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Alignment(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::MountState(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Mounting(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Mass(comp) => sync::handle_insert(comp, entity, world),
@ -93,6 +96,7 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::LightEmitter(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Item(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Scale(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Alignment(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::MountState(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Mounting(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Mass(comp) => sync::handle_modify(comp, entity, world),
@ -119,6 +123,7 @@ impl sync::CompPacket for EcsCompPacket {
},
EcsCompPhantom::Item(_) => sync::handle_remove::<comp::Item>(entity, world),
EcsCompPhantom::Scale(_) => sync::handle_remove::<comp::Scale>(entity, world),
EcsCompPhantom::Alignment(_) => sync::handle_remove::<comp::Alignment>(entity, world),
EcsCompPhantom::MountState(_) => sync::handle_remove::<comp::MountState>(entity, world),
EcsCompPhantom::Mounting(_) => sync::handle_remove::<comp::Mounting>(entity, world),
EcsCompPhantom::Mass(_) => sync::handle_remove::<comp::Mass>(entity, world),

View File

@ -123,6 +123,7 @@ impl State {
ecs.register::<comp::Gravity>();
ecs.register::<comp::CharacterState>();
ecs.register::<comp::Object>();
ecs.register::<comp::Alignment>();
// Register components send from clients -> server
ecs.register::<comp::Controller>();
@ -146,7 +147,6 @@ impl State {
ecs.register::<comp::Last<comp::Vel>>();
ecs.register::<comp::Last<comp::Ori>>();
ecs.register::<comp::Agent>();
ecs.register::<comp::Alignment>();
ecs.register::<comp::WaypointArea>();
ecs.register::<comp::ForceUpdate>();
ecs.register::<comp::InventoryUpdate>();

View File

@ -31,8 +31,12 @@ impl CharacterBehavior for Data {
handle_move(data, &mut update, 0.3);
handle_jump(data, &mut update);
if self.prepare_timer < self.prepare_duration
|| self.holdable && !self.exhausted && data.inputs.holding_ability_key()
if !self.exhausted
&& if self.holdable {
data.inputs.holding_ability_key() || self.prepare_timer < self.prepare_duration
} else {
self.prepare_timer < self.prepare_duration
}
{
// Prepare (draw the bow)
update.character = CharacterState::BasicRanged(Data {

View File

@ -11,7 +11,7 @@ use crate::{
use vek::vec::Vec2;
pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
const BASE_HUMANOID_AIR_ACCEL: f32 = 15.0;
const BASE_HUMANOID_AIR_ACCEL: f32 = 8.0;
const BASE_HUMANOID_WATER_ACCEL: f32 = 150.0;
const BASE_HUMANOID_WATER_SPEED: f32 = 180.0;
// const BASE_HUMANOID_CLIMB_ACCEL: f32 = 10.0;
@ -45,6 +45,24 @@ impl Body {
Body::QuadrupedLow(_) => 120.0,
}
}
pub fn base_ori_rate(&self) -> f32 {
match self {
Body::Humanoid(_) => 20.0,
Body::QuadrupedSmall(_) => 15.0,
Body::QuadrupedMedium(_) => 10.0,
Body::BirdMedium(_) => 30.0,
Body::FishMedium(_) => 5.0,
Body::Dragon(_) => 5.0,
Body::BirdSmall(_) => 35.0,
Body::FishSmall(_) => 10.0,
Body::BipedLarge(_) => 12.0,
Body::Object(_) => 5.0,
Body::Golem(_) => 8.0,
Body::Critter(_) => 35.0,
Body::QuadrupedLow(_) => 12.0,
}
}
}
/// Handles updating `Components` to move player based on state of `JoinData`
@ -68,10 +86,10 @@ fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
update.vel.0 =
update.vel.0 + Vec2::broadcast(data.dt.0) * data.inputs.move_dir * accel * efficiency;
handle_orientation(data, update, 20.0);
handle_orientation(data, update, data.body.base_ori_rate());
}
pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, strength: f32) {
pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, rate: f32) {
// Set direction based on move direction
let ori_dir = if update.character.is_attack() || update.character.is_block() {
data.inputs.look_dir.xy()
@ -82,7 +100,7 @@ pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, strength: f
};
// Smooth orientation
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, ori_dir.into(), strength * data.dt.0);
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, ori_dir.into(), rate * data.dt.0);
}
/// Updates components to move player as if theyre swimming

View File

@ -118,7 +118,7 @@ impl<'a> System<'a> for Sys {
const LISTEN_DIST: f32 = 16.0;
const SEARCH_DIST: f32 = 48.0;
const SIGHT_DIST: f32 = 128.0;
const MIN_ATTACK_DIST: f32 = 3.25;
const MIN_ATTACK_DIST: f32 = 3.5;
let scale = scales.get(entity).map(|s| s.0).unwrap_or(1.0);
@ -191,9 +191,9 @@ impl<'a> System<'a> for Sys {
if let (Some(tgt_pos), _tgt_stats) =
(positions.get(*target), stats.get(*target))
{
let dist_sqrd = pos.0.distance_squared(tgt_pos.0);
let dist = pos.0.distance(tgt_pos.0);
// Follow, or return to idle
if dist_sqrd > AVG_FOLLOW_DIST.powf(2.0) {
if dist > AVG_FOLLOW_DIST {
if let Some((bearing, speed)) = chaser.chase(
&*terrain,
pos.0,
@ -204,7 +204,7 @@ impl<'a> System<'a> for Sys {
) {
inputs.move_dir =
bearing.xy().try_normalized().unwrap_or(Vec2::zero())
* speed;
* speed.min(0.2 + (dist - AVG_FOLLOW_DIST) / 8.0);
inputs.jump.set_state(bearing.z > 1.5);
}
} else {
@ -242,10 +242,12 @@ impl<'a> System<'a> for Sys {
if let (Some(tgt_pos), Some(tgt_stats), tgt_alignment) = (
positions.get(*target),
stats.get(*target),
alignments
.get(*target)
.copied()
.unwrap_or(Alignment::Owned(*target)),
alignments.get(*target).copied().unwrap_or(
uids.get(*target)
.copied()
.map(Alignment::Owned)
.unwrap_or(Alignment::Wild),
),
) {
if let Some(dir) = Dir::from_unnormalized(tgt_pos.0 - pos.0) {
inputs.look_dir = dir;
@ -264,10 +266,10 @@ impl<'a> System<'a> for Sys {
let dist_sqrd = pos.0.distance_squared(tgt_pos.0);
if dist_sqrd < (MIN_ATTACK_DIST * scale).powf(2.0) {
// Close-range attack
/*inputs.move_dir = Vec2::from(tgt_pos.0 - pos.0)
.try_normalized()
.unwrap_or(Vec2::unit_y())
* 0.7;*/
inputs.move_dir = Vec2::from(tgt_pos.0 - pos.0)
.try_normalized()
.unwrap_or(Vec2::unit_y())
* 0.1;
match tactic {
Tactic::Melee | Tactic::Staff => inputs.primary.set_state(true),
@ -419,7 +421,10 @@ impl<'a> System<'a> for Sys {
// Follow owner if we're too far, or if they're under attack
if let Some(Alignment::Owned(owner)) = alignment.copied() {
if let Some(owner_pos) = positions.get(owner) {
(|| {
let owner = uid_allocator.retrieve_entity_internal(owner.id())?;
let owner_pos = positions.get(owner)?;
let dist_sqrd = pos.0.distance_squared(owner_pos.0);
if dist_sqrd > MAX_FOLLOW_DIST.powf(2.0) && !agent.activity.is_follow() {
agent.activity = Activity::Follow {
@ -429,28 +434,27 @@ impl<'a> System<'a> for Sys {
}
// Attack owner's attacker
if let Some(owner_stats) = stats.get(owner) {
if owner_stats.health.last_change.0 < 5.0 {
if let comp::HealthSource::Attack { by } =
owner_stats.health.last_change.1.cause
{
if !agent.activity.is_attack() {
if let Some(attacker) =
uid_allocator.retrieve_entity_internal(by.id())
{
agent.activity = Activity::Attack {
target: attacker,
chaser: Chaser::default(),
time: time.0,
been_close: false,
powerup: 0.0,
};
}
}
let owner_stats = stats.get(owner)?;
if owner_stats.health.last_change.0 < 5.0 {
if let comp::HealthSource::Attack { by } =
owner_stats.health.last_change.1.cause
{
if !agent.activity.is_attack() {
let attacker = uid_allocator.retrieve_entity_internal(by.id())?;
agent.activity = Activity::Attack {
target: attacker,
chaser: Chaser::default(),
time: time.0,
been_close: false,
powerup: 0.0,
};
}
}
}
}
Some(())
})();
}
debug_assert!(inputs.move_dir.map(|e| !e.is_nan()).reduce_and());

View File

@ -1,6 +1,7 @@
use crate::{
comp::{
Agent, Attacking, Body, CharacterState, HealthChange, HealthSource, Ori, Pos, Scale, Stats,
Alignment, Attacking, Body, CharacterState, HealthChange, HealthSource, Ori, Pos, Scale,
Stats,
},
event::{EventBus, LocalEvent, ServerEvent},
sync::Uid,
@ -25,7 +26,7 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Pos>,
ReadStorage<'a, Ori>,
ReadStorage<'a, Scale>,
ReadStorage<'a, Agent>,
ReadStorage<'a, Alignment>,
ReadStorage<'a, Body>,
ReadStorage<'a, Stats>,
WriteStorage<'a, Attacking>,
@ -42,7 +43,7 @@ impl<'a> System<'a> for Sys {
positions,
orientations,
scales,
agents,
alignments,
bodies,
stats,
mut attacking_storage,
@ -74,7 +75,7 @@ impl<'a> System<'a> for Sys {
pos_b,
ori_b,
scale_b_maybe,
agent_b_maybe,
alignment_b_maybe,
character_b,
stats_b,
body_b,
@ -84,7 +85,7 @@ impl<'a> System<'a> for Sys {
&positions,
&orientations,
scales.maybe(),
agents.maybe(),
alignments.maybe(),
character_states.maybe(),
&stats,
&bodies,
@ -110,6 +111,7 @@ impl<'a> System<'a> for Sys {
{
// Weapon gives base damage
let mut healthchange = attack.base_healthchange as f32;
let mut knockback = attack.knockback;
// TODO: remove this, either it will remain unused or be used as a temporary
// gameplay balance
@ -118,10 +120,18 @@ impl<'a> System<'a> for Sys {
// healthchange = (healthchange / 1.5).min(-1.0);
//}
// TODO: remove this when there is a better way to target healing
// Don't heal npc's hp
if agent_b_maybe.is_some() && healthchange > 0.0 {
// TODO: remove this when there is a better way to deal with alignment
// Don't heal NPCs
if (healthchange > 0.0 && alignment_b_maybe
.map(|a| !a.is_friendly_to_players())
.unwrap_or(true))
// Don't hurt pets
|| (healthchange < 0.0 && alignment_b_maybe
.map(|b| Alignment::Owned(*uid).passive_towards(*b))
.unwrap_or(false))
{
healthchange = 0.0;
knockback = 0.0;
}
if rand::random() {
@ -135,14 +145,16 @@ impl<'a> System<'a> for Sys {
healthchange *= 1.0 - BLOCK_EFFICIENCY
}
server_emitter.emit(ServerEvent::Damage {
uid: *uid_b,
change: HealthChange {
amount: healthchange as i32,
cause: HealthSource::Attack { by: *uid },
},
});
if attack.knockback != 0.0 {
if healthchange != 0.0 {
server_emitter.emit(ServerEvent::Damage {
uid: *uid_b,
change: HealthChange {
amount: healthchange as i32,
cause: HealthSource::Attack { by: *uid },
},
});
}
if knockback != 0.0 {
local_emitter.emit(LocalEvent::ApplyForce {
entity: b,
force: attack.knockback

View File

@ -1,6 +1,7 @@
use crate::{
comp::{
projectile, Energy, EnergySource, HealthSource, Ori, PhysicsState, Pos, Projectile, Vel,
projectile, Alignment, Energy, EnergySource, HealthSource, Ori, PhysicsState, Pos,
Projectile, Vel,
},
event::{EventBus, LocalEvent, ServerEvent},
state::DeltaTime,
@ -27,6 +28,7 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Ori>,
WriteStorage<'a, Projectile>,
WriteStorage<'a, Energy>,
ReadStorage<'a, Alignment>,
);
fn run(
@ -43,6 +45,7 @@ impl<'a> System<'a> for Sys {
mut orientations,
mut projectiles,
mut energies,
alignments,
): Self::SystemData,
) {
let mut local_emitter = local_bus.emitter();
@ -82,7 +85,17 @@ impl<'a> System<'a> for Sys {
for effect in projectile.hit_entity.drain(..) {
match effect {
projectile::Effect::Damage(change) => {
if other != projectile.owner.unwrap() {
let owner_uid = projectile.owner.unwrap();
// Hacky: remove this when groups get implemented
let passive = uid_allocator
.retrieve_entity_internal(other.into())
.and_then(|other| {
alignments
.get(other)
.map(|a| Alignment::Owned(owner_uid).passive_towards(*a))
})
.unwrap_or(false);
if other != projectile.owner.unwrap() && !passive {
server_emitter.emit(ServerEvent::Damage { uid: other, change });
}
},

View File

@ -16,6 +16,7 @@ use common::{
terrain::TerrainChunkSize,
util::Dir,
vol::RectVolSize,
LoadoutBuilder,
};
use rand::Rng;
use specs::{Builder, Entity as EcsEntity, Join, WorldExt};
@ -507,7 +508,11 @@ fn handle_spawn(
String
) {
(Some(opt_align), Some(npc::NpcBody(id, mut body)), opt_amount, opt_ai) => {
if let Some(alignment) = parse_alignment(target, &opt_align) {
let uid = server
.state
.read_component_cloned(target)
.expect("Expected player to have a UID");
if let Some(alignment) = parse_alignment(uid, &opt_align) {
let amount = opt_amount
.and_then(|a| a.parse().ok())
.filter(|x| *x > 0)
@ -539,7 +544,7 @@ fn handle_spawn(
.create_npc(
pos,
comp::Stats::new(get_npc_name(id).into(), body),
comp::Loadout::default(),
LoadoutBuilder::animal().build(),
body,
)
.with(comp::Vel(vel))
@ -715,7 +720,7 @@ fn handle_help(
}
}
fn parse_alignment(owner: EcsEntity, alignment: &str) -> Option<comp::Alignment> {
fn parse_alignment(owner: Uid, alignment: &str) -> Option<comp::Alignment> {
match alignment {
"wild" => Some(comp::Alignment::Wild),
"enemy" => Some(comp::Alignment::Enemy),

View File

@ -188,13 +188,16 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
let reinsert = if let Some(pos) =
state.read_storage::<comp::Pos>().get(entity)
{
let uid = state
.read_component_cloned(entity)
.expect("Expected player to have a UID");
if (
&state.read_storage::<comp::Alignment>(),
&state.read_storage::<comp::Agent>(),
)
.join()
.filter(|(alignment, _)| {
alignment == &&comp::Alignment::Owned(entity)
alignment == &&comp::Alignment::Owned(uid)
})
.count()
>= 3
@ -220,10 +223,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.map(|(entity, _, _)| entity);
nearest_tameable
} {
let _ = state.ecs().write_storage().insert(
tameable_entity,
comp::Alignment::Owned(entity),
);
let _ = state
.ecs()
.write_storage()
.insert(tameable_entity, comp::Alignment::Owned(uid));
let _ = state
.ecs()
.write_storage()

View File

@ -171,7 +171,10 @@ impl StateExt for State {
});
self.write_component(entity, comp::Gravity(1.0));
self.write_component(entity, comp::CharacterState::default());
self.write_component(entity, comp::Alignment::Owned(entity));
self.write_component(
entity,
comp::Alignment::Owned(self.read_component_cloned(entity).unwrap()),
);
// Set the character id for the player
// TODO this results in a warning in the console: "Error modifying synced

View File

@ -1,8 +1,8 @@
use super::SysTimer;
use common::{
comp::{
Body, CanBuild, CharacterState, Collider, Energy, Gravity, Item, LightEmitter, Loadout,
Mass, MountState, Mounting, Ori, Player, Pos, Scale, Stats, Sticky, Vel,
Alignment, Body, CanBuild, CharacterState, Collider, Energy, Gravity, Item, LightEmitter,
Loadout, Mass, MountState, Mounting, Ori, Player, Pos, Scale, Stats, Sticky, Vel,
},
msg::EcsCompPacket,
sync::{CompSyncPackage, EntityPackage, EntitySyncPackage, Uid, UpdateTracker, WorldSyncExt},
@ -48,6 +48,7 @@ pub struct TrackedComps<'a> {
pub scale: ReadStorage<'a, Scale>,
pub mounting: ReadStorage<'a, Mounting>,
pub mount_state: ReadStorage<'a, MountState>,
pub alignment: ReadStorage<'a, Alignment>,
pub mass: ReadStorage<'a, Mass>,
pub collider: ReadStorage<'a, Collider>,
pub sticky: ReadStorage<'a, Sticky>,
@ -104,6 +105,10 @@ impl<'a> TrackedComps<'a> {
.get(entity)
.cloned()
.map(|c| comps.push(c.into()));
self.alignment
.get(entity)
.cloned()
.map(|c| comps.push(c.into()));
self.mass.get(entity).copied().map(|c| comps.push(c.into()));
self.collider
.get(entity)
@ -146,6 +151,7 @@ pub struct ReadTrackers<'a> {
pub scale: ReadExpect<'a, UpdateTracker<Scale>>,
pub mounting: ReadExpect<'a, UpdateTracker<Mounting>>,
pub mount_state: ReadExpect<'a, UpdateTracker<MountState>>,
pub alignment: ReadExpect<'a, UpdateTracker<Alignment>>,
pub mass: ReadExpect<'a, UpdateTracker<Mass>>,
pub collider: ReadExpect<'a, UpdateTracker<Collider>>,
pub sticky: ReadExpect<'a, UpdateTracker<Sticky>>,
@ -178,6 +184,7 @@ impl<'a> ReadTrackers<'a> {
.with_component(&comps.uid, &*self.scale, &comps.scale, filter)
.with_component(&comps.uid, &*self.mounting, &comps.mounting, filter)
.with_component(&comps.uid, &*self.mount_state, &comps.mount_state, filter)
.with_component(&comps.uid, &*self.alignment, &comps.alignment, filter)
.with_component(&comps.uid, &*self.mass, &comps.mass, filter)
.with_component(&comps.uid, &*self.collider, &comps.collider, filter)
.with_component(&comps.uid, &*self.sticky, &comps.sticky, filter)
@ -207,6 +214,7 @@ pub struct WriteTrackers<'a> {
scale: WriteExpect<'a, UpdateTracker<Scale>>,
mounting: WriteExpect<'a, UpdateTracker<Mounting>>,
mount_state: WriteExpect<'a, UpdateTracker<MountState>>,
alignment: WriteExpect<'a, UpdateTracker<Alignment>>,
mass: WriteExpect<'a, UpdateTracker<Mass>>,
collider: WriteExpect<'a, UpdateTracker<Collider>>,
sticky: WriteExpect<'a, UpdateTracker<Sticky>>,
@ -228,6 +236,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
trackers.scale.record_changes(&comps.scale);
trackers.mounting.record_changes(&comps.mounting);
trackers.mount_state.record_changes(&comps.mount_state);
trackers.alignment.record_changes(&comps.alignment);
trackers.mass.record_changes(&comps.mass);
trackers.collider.record_changes(&comps.collider);
trackers.sticky.record_changes(&comps.sticky);
@ -282,6 +291,7 @@ pub fn register_trackers(world: &mut World) {
world.register_tracker::<Scale>();
world.register_tracker::<Mounting>();
world.register_tracker::<MountState>();
world.register_tracker::<Alignment>();
world.register_tracker::<Mass>();
world.register_tracker::<Collider>();
world.register_tracker::<Sticky>();

View File

@ -9,6 +9,7 @@ use common::{
npc::NPC_NAMES,
state::TerrainChanges,
terrain::TerrainGrid,
LoadoutBuilder,
};
use rand::Rng;
use specs::{Join, Read, ReadStorage, System, Write, WriteExpect, WriteStorage};
@ -136,9 +137,9 @@ impl<'a> System<'a> for Sys {
energy_cost: 0,
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(400),
base_healthchange: -2,
range: 3.5,
max_angle: 60.0,
base_healthchange: -6,
range: 5.0,
max_angle: 80.0,
}),
ability2: None,
ability3: None,
@ -214,36 +215,7 @@ impl<'a> System<'a> for Sys {
head: None,
tabard: None,
},
_ => comp::Loadout {
active_item: Some(comp::ItemConfig {
item: assets::load_expect_cloned("common.items.weapons.empty"),
ability1: Some(CharacterAbility::BasicMelee {
energy_cost: 10,
buildup_duration: Duration::from_millis(800),
recover_duration: Duration::from_millis(200),
base_healthchange: -2,
range: 3.5,
max_angle: 60.0,
}),
ability2: None,
ability3: None,
block_ability: None,
dodge_ability: None,
}),
second_item: None,
shoulder: None,
chest: None,
belt: None,
hand: None,
pants: None,
foot: None,
back: None,
ring: None,
neck: None,
lantern: None,
head: None,
tabard: None,
},
_ => LoadoutBuilder::animal().build(),
};
let mut scale = entity.scale;

View File

@ -57,12 +57,9 @@ impl SessionState {
.set_fov_deg(global_state.settings.graphics.fov);
let hud = Hud::new(global_state, &client.borrow());
{
let my_entity = client.borrow().entity();
client
.borrow_mut()
.state_mut()
.ecs_mut()
.insert(MyEntity(my_entity));
let mut client = client.borrow_mut();
let my_entity = client.entity();
client.state_mut().ecs_mut().insert(MyEntity(my_entity));
}
let voxygen_i18n = load_expect::<VoxygenLocalization>(&i18n_asset_key(
&global_state.settings.language.selected_language,
@ -249,13 +246,21 @@ impl PlayState for SessionState {
{
(
Some((cam_pos + cam_dir * (cam_dist - 0.01)).map(|e| e.floor() as i32)),
Some((cam_pos + cam_dir * cam_dist).map(|e| e.floor() as i32)),
Some((cam_pos + cam_dir * (cam_dist + 0.01)).map(|e| e.floor() as i32)),
)
},
_ => (None, None),
}
};
let can_build = self
.client
.borrow()
.state()
.read_storage::<comp::CanBuild>()
.get(self.client.borrow().entity())
.is_some();
// Only highlight collectables
self.scene.set_select_pos(select_pos.filter(|sp| {
self.client
@ -263,7 +268,7 @@ impl PlayState for SessionState {
.state()
.terrain()
.get(*sp)
.map(|b| b.is_collectible())
.map(|b| b.is_collectible() || can_build)
.unwrap_or(false)
}));
@ -279,16 +284,9 @@ impl PlayState for SessionState {
return PlayStateResult::Shutdown;
},
Event::InputUpdate(GameInput::Primary, state) => {
// Check the existence of CanBuild component. If it's here, use LMB to
// break blocks, if not, use it to attack
// If we can build, use LMB to break blocks, if not, use it to attack
let mut client = self.client.borrow_mut();
if state
&& client
.state()
.read_storage::<comp::CanBuild>()
.get(client.entity())
.is_some()
{
if state && can_build {
if let Some(select_pos) = select_pos {
client.remove_block(select_pos);
}
@ -302,13 +300,7 @@ impl PlayState for SessionState {
let mut client = self.client.borrow_mut();
if state
&& client
.state()
.read_storage::<comp::CanBuild>()
.get(client.entity())
.is_some()
{
if state && can_build {
if let Some(build_pos) = build_pos {
client.place_block(build_pos, self.selected_block);
}
@ -319,12 +311,7 @@ impl PlayState for SessionState {
Event::InputUpdate(GameInput::Roll, state) => {
let client = self.client.borrow();
if client
.state()
.read_storage::<comp::CanBuild>()
.get(client.entity())
.is_some()
{
if can_build {
if state {
if let Some(block) = select_pos
.and_then(|sp| client.state().terrain().get(sp).ok().copied())