mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sam/armor-fixes' into 'master'
Armor fixes See merge request veloren/veloren!1222
This commit is contained in:
commit
9156dbadb8
@ -5,7 +5,7 @@ Item(
|
||||
(
|
||||
kind: Chest(CultistBlue),
|
||||
stats: (
|
||||
protection: Normal(5.0),
|
||||
protection: Normal(30.0),
|
||||
),
|
||||
)
|
||||
),
|
||||
|
@ -5,7 +5,7 @@ Item(
|
||||
(
|
||||
kind: Chest(CultistPurple),
|
||||
stats: (
|
||||
protection: Normal(5.0),
|
||||
protection: Normal(30.0),
|
||||
),
|
||||
)
|
||||
),
|
||||
|
@ -5,7 +5,7 @@ Item(
|
||||
(
|
||||
kind: Foot(Cultist),
|
||||
stats: (
|
||||
protection: Normal(1.0),
|
||||
protection: Normal(6.0),
|
||||
),
|
||||
)
|
||||
),
|
||||
|
@ -5,7 +5,7 @@ Item(
|
||||
(
|
||||
kind: Hand(CultistBlue),
|
||||
stats: (
|
||||
protection: Normal(2.0),
|
||||
protection: Normal(12.0),
|
||||
),
|
||||
)
|
||||
),
|
||||
|
@ -5,7 +5,7 @@ Item(
|
||||
(
|
||||
kind: Hand(CultistPurple),
|
||||
stats: (
|
||||
protection: Normal(2.0),
|
||||
protection: Normal(12.0),
|
||||
),
|
||||
)
|
||||
),
|
||||
|
@ -5,7 +5,7 @@ Item(
|
||||
(
|
||||
kind: Pants(CultistBlue),
|
||||
stats: (
|
||||
protection: Normal(3.0),
|
||||
protection: Normal(24.0),
|
||||
),
|
||||
)
|
||||
),
|
||||
|
@ -5,7 +5,7 @@ Item(
|
||||
(
|
||||
kind: Pants(CultistPurple),
|
||||
stats: (
|
||||
protection: Normal(3.0),
|
||||
protection: Normal(24.0),
|
||||
),
|
||||
)
|
||||
),
|
||||
|
@ -5,7 +5,7 @@ Item(
|
||||
(
|
||||
kind: Shoulder(CultistBlue),
|
||||
stats: (
|
||||
protection: Normal(3.0),
|
||||
protection: Normal(18.0),
|
||||
),
|
||||
)
|
||||
),
|
||||
|
@ -5,7 +5,7 @@ Item(
|
||||
(
|
||||
kind: Shoulder(CultistPurple),
|
||||
stats: (
|
||||
protection: Normal(3.0),
|
||||
protection: Normal(18.0),
|
||||
),
|
||||
)
|
||||
),
|
||||
|
77
common/src/comp/damage.rs
Normal file
77
common/src/comp/damage.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use crate::comp::Loadout;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const BLOCK_EFFICIENCY: f32 = 0.9;
|
||||
|
||||
pub struct Damage {
|
||||
pub healthchange: f32,
|
||||
pub source: DamageSource,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum DamageSource {
|
||||
Melee,
|
||||
Healing,
|
||||
Projectile,
|
||||
Explosion,
|
||||
Falling,
|
||||
}
|
||||
|
||||
impl Damage {
|
||||
pub fn modify_damage(&mut self, block: bool, loadout: &Loadout) {
|
||||
match self.source {
|
||||
DamageSource::Melee => {
|
||||
// Critical hit
|
||||
if rand::random() {
|
||||
self.healthchange *= 1.2;
|
||||
}
|
||||
// Block
|
||||
if block {
|
||||
self.healthchange *= 1.0 - BLOCK_EFFICIENCY
|
||||
}
|
||||
// Armor
|
||||
self.healthchange *= 1.0 - loadout.get_damage_reduction();
|
||||
|
||||
// Min damage
|
||||
if self.healthchange > -1.0 {
|
||||
self.healthchange = -1.0;
|
||||
}
|
||||
},
|
||||
DamageSource::Projectile => {
|
||||
// Critical hit
|
||||
if rand::random() {
|
||||
self.healthchange *= 1.2;
|
||||
}
|
||||
// Block
|
||||
if block {
|
||||
self.healthchange *= 1.0 - BLOCK_EFFICIENCY
|
||||
}
|
||||
// Armor
|
||||
self.healthchange *= 1.0 - loadout.get_damage_reduction();
|
||||
|
||||
// Min damage
|
||||
if self.healthchange > -1.0 {
|
||||
self.healthchange = -1.0;
|
||||
}
|
||||
},
|
||||
DamageSource::Explosion => {
|
||||
// Critical hit
|
||||
if rand::random() {
|
||||
self.healthchange *= 1.2;
|
||||
}
|
||||
// Block
|
||||
if block {
|
||||
self.healthchange *= 1.0 - BLOCK_EFFICIENCY
|
||||
}
|
||||
// Armor
|
||||
self.healthchange *= 1.0 - loadout.get_damage_reduction();
|
||||
|
||||
// Min damage
|
||||
if self.healthchange > -1.0 {
|
||||
self.healthchange = -1.0;
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
@ -2,8 +2,7 @@
|
||||
// version in voxygen\src\meta.rs in order to reset save files to being empty
|
||||
|
||||
use crate::comp::{
|
||||
body::object, projectile, Body, CharacterAbility, Gravity, HealthChange, HealthSource,
|
||||
LightEmitter, Projectile,
|
||||
body::object, projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -262,11 +261,7 @@ impl Tool {
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damage(HealthChange {
|
||||
// TODO: This should not be fixed (?)
|
||||
amount: -3,
|
||||
cause: HealthSource::Projectile { owner: None },
|
||||
}),
|
||||
projectile::Effect::Damage(-3),
|
||||
projectile::Effect::Knockback(10.0),
|
||||
projectile::Effect::RewardEnergy(100),
|
||||
projectile::Effect::Vanish,
|
||||
@ -286,11 +281,7 @@ impl Tool {
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damage(HealthChange {
|
||||
// TODO: This should not be fixed (?)
|
||||
amount: -9,
|
||||
cause: HealthSource::Projectile { owner: None },
|
||||
}),
|
||||
projectile::Effect::Damage(-9),
|
||||
projectile::Effect::Knockback(15.0),
|
||||
projectile::Effect::RewardEnergy(50),
|
||||
projectile::Effect::Vanish,
|
||||
@ -336,11 +327,7 @@ impl Tool {
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![projectile::Effect::Vanish],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damage(HealthChange {
|
||||
// TODO: This should not be fixed (?)
|
||||
amount: -3,
|
||||
cause: HealthSource::Projectile { owner: None },
|
||||
}),
|
||||
projectile::Effect::Damage(-3),
|
||||
projectile::Effect::RewardEnergy(150),
|
||||
projectile::Effect::Vanish,
|
||||
],
|
||||
|
@ -5,6 +5,7 @@ mod body;
|
||||
mod character_state;
|
||||
mod chat;
|
||||
mod controller;
|
||||
mod damage;
|
||||
mod energy;
|
||||
mod inputs;
|
||||
mod inventory;
|
||||
@ -32,6 +33,7 @@ pub use controller::{
|
||||
Climb, ControlAction, ControlEvent, Controller, ControllerInputs, Input, InventoryManip,
|
||||
MountState, Mounting,
|
||||
};
|
||||
pub use damage::{Damage, DamageSource};
|
||||
pub use energy::{Energy, EnergySource};
|
||||
pub use inputs::CanBuild;
|
||||
pub use inventory::{
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{comp, sync::Uid};
|
||||
use crate::sync::Uid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
@ -6,7 +6,7 @@ use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Effect {
|
||||
Damage(comp::HealthChange),
|
||||
Damage(i32),
|
||||
Knockback(f32),
|
||||
RewardEnergy(u32),
|
||||
Explode { power: f32 },
|
||||
@ -25,21 +25,6 @@ pub struct Projectile {
|
||||
pub owner: Option<Uid>,
|
||||
}
|
||||
|
||||
impl Projectile {
|
||||
pub fn set_owner(&mut self, new_owner: Uid) {
|
||||
self.owner = Some(new_owner);
|
||||
for e in self.hit_solid.iter_mut().chain(self.hit_entity.iter_mut()) {
|
||||
if let Effect::Damage(comp::HealthChange {
|
||||
cause: comp::HealthSource::Projectile { owner, .. },
|
||||
..
|
||||
}) = e
|
||||
{
|
||||
*owner = Some(new_owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Projectile {
|
||||
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ impl CharacterBehavior for Data {
|
||||
} else if !self.exhausted {
|
||||
// Fire
|
||||
let mut projectile = self.projectile.clone();
|
||||
projectile.set_owner(*data.uid);
|
||||
projectile.owner = Some(*data.uid);
|
||||
update.server_events.push_front(ServerEvent::Shoot {
|
||||
entity: data.entity,
|
||||
dir: data.inputs.look_dir,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
Alignment, Attacking, Body, CharacterState, HealthChange, HealthSource, Loadout, Ori, Pos,
|
||||
Scale, Stats,
|
||||
Alignment, Attacking, Body, CharacterState, Damage, DamageSource, HealthChange,
|
||||
HealthSource, Loadout, Ori, Pos, Scale, Stats,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
sync::Uid,
|
||||
@ -112,7 +112,15 @@ impl<'a> System<'a> for Sys {
|
||||
&& ori2.angle_between(pos_b2 - pos2) < attack.max_angle + (rad_b / pos2.distance(pos_b2)).atan()
|
||||
{
|
||||
// Weapon gives base damage
|
||||
let mut healthchange = attack.base_healthchange as f32;
|
||||
let source = if attack.base_healthchange > 0 {
|
||||
DamageSource::Healing
|
||||
} else {
|
||||
DamageSource::Melee
|
||||
};
|
||||
let mut damage = Damage {
|
||||
healthchange: attack.base_healthchange as f32,
|
||||
source,
|
||||
};
|
||||
let mut knockback = attack.knockback;
|
||||
|
||||
// TODO: remove this, either it will remain unused or be used as a temporary
|
||||
@ -124,40 +132,30 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// TODO: remove this when there is a better way to deal with alignment
|
||||
// Don't heal NPCs
|
||||
if (healthchange > 0.0 && alignment_b_maybe
|
||||
if (damage.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
|
||||
|| (damage.healthchange < 0.0 && alignment_b_maybe
|
||||
.map(|b| Alignment::Owned(*uid).passive_towards(*b))
|
||||
.unwrap_or(false))
|
||||
{
|
||||
healthchange = 0.0;
|
||||
damage.healthchange = 0.0;
|
||||
knockback = 0.0;
|
||||
}
|
||||
|
||||
if rand::random() {
|
||||
healthchange *= 1.2;
|
||||
}
|
||||
let block = character_b.map(|c_b| c_b.is_block()).unwrap_or(false)
|
||||
&& ori_b.0.angle_between(pos.0 - pos_b.0) < BLOCK_ANGLE.to_radians() / 2.0;
|
||||
|
||||
// Block
|
||||
if character_b.map(|c_b| c_b.is_block()).unwrap_or(false)
|
||||
&& ori_b.0.angle_between(pos.0 - pos_b.0) < BLOCK_ANGLE.to_radians() / 2.0
|
||||
{
|
||||
healthchange *= 1.0 - BLOCK_EFFICIENCY
|
||||
}
|
||||
|
||||
// Armor
|
||||
if let Some(loadout) = loadouts.get(b) {
|
||||
let damage_reduction = loadout.get_damage_reduction();
|
||||
healthchange *= 1.0 - damage_reduction;
|
||||
damage.modify_damage(block, loadout);
|
||||
}
|
||||
|
||||
if healthchange != 0.0 {
|
||||
if damage.healthchange != 0.0 {
|
||||
server_emitter.emit(ServerEvent::Damage {
|
||||
uid: *uid_b,
|
||||
change: HealthChange {
|
||||
amount: healthchange as i32,
|
||||
amount: damage.healthchange as i32,
|
||||
cause: HealthSource::Attack { by: *uid },
|
||||
},
|
||||
});
|
||||
@ -165,7 +163,7 @@ impl<'a> System<'a> for Sys {
|
||||
if knockback != 0.0 {
|
||||
local_emitter.emit(LocalEvent::ApplyForce {
|
||||
entity: b,
|
||||
force: attack.knockback
|
||||
force: knockback
|
||||
* *Dir::slerp(ori.0, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5),
|
||||
});
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
projectile, Alignment, Energy, EnergySource, HealthSource, Ori, PhysicsState, Pos,
|
||||
Projectile, Vel,
|
||||
projectile, Alignment, Damage, DamageSource, Energy, EnergySource, HealthChange,
|
||||
HealthSource, Loadout, Ori, PhysicsState, Pos, Projectile, Vel,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
state::DeltaTime,
|
||||
@ -29,6 +29,7 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Projectile>,
|
||||
WriteStorage<'a, Energy>,
|
||||
ReadStorage<'a, Alignment>,
|
||||
ReadStorage<'a, Loadout>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
@ -46,6 +47,7 @@ impl<'a> System<'a> for Sys {
|
||||
mut projectiles,
|
||||
mut energies,
|
||||
alignments,
|
||||
loadouts,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let mut local_emitter = local_bus.emitter();
|
||||
@ -84,8 +86,19 @@ impl<'a> System<'a> for Sys {
|
||||
else if let Some(other) = physics.touch_entity {
|
||||
for effect in projectile.hit_entity.drain(..) {
|
||||
match effect {
|
||||
projectile::Effect::Damage(change) => {
|
||||
projectile::Effect::Damage(healthchange) => {
|
||||
let owner_uid = projectile.owner.unwrap();
|
||||
let mut damage = Damage {
|
||||
healthchange: healthchange as f32,
|
||||
source: DamageSource::Projectile,
|
||||
};
|
||||
if let Some(entity) =
|
||||
uid_allocator.retrieve_entity_internal(other.into())
|
||||
{
|
||||
if let Some(loadout) = loadouts.get(entity) {
|
||||
damage.modify_damage(false, loadout);
|
||||
}
|
||||
}
|
||||
// Hacky: remove this when groups get implemented
|
||||
let passive = uid_allocator
|
||||
.retrieve_entity_internal(other.into())
|
||||
@ -96,7 +109,13 @@ impl<'a> System<'a> for Sys {
|
||||
})
|
||||
.unwrap_or(false);
|
||||
if other != projectile.owner.unwrap() && !passive {
|
||||
server_emitter.emit(ServerEvent::Damage { uid: other, change });
|
||||
server_emitter.emit(ServerEvent::Damage {
|
||||
uid: other,
|
||||
change: HealthChange {
|
||||
amount: damage.healthchange as i32,
|
||||
cause: HealthSource::Attack { by: owner_uid },
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
projectile::Effect::Knockback(knockback) => {
|
||||
|
@ -1,11 +1,14 @@
|
||||
use crate::{client::Client, Server, SpawnPoint, StateExt};
|
||||
use common::{
|
||||
assets,
|
||||
comp::{self, item::lottery::Lottery, object, Body, HealthChange, HealthSource, Player, Stats},
|
||||
comp::{
|
||||
self, item::lottery::Lottery, object, Body, Damage, DamageSource, HealthChange,
|
||||
HealthSource, Player, Stats,
|
||||
},
|
||||
msg::{PlayerListUpdate, ServerMsg},
|
||||
state::BlockChange,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
sys::combat::{BLOCK_ANGLE, BLOCK_EFFICIENCY},
|
||||
sys::combat::BLOCK_ANGLE,
|
||||
terrain::{Block, TerrainGrid},
|
||||
vol::{ReadVol, Vox},
|
||||
};
|
||||
@ -159,9 +162,16 @@ pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>)
|
||||
let state = &server.state;
|
||||
if vel.z <= -30.0 {
|
||||
if let Some(stats) = state.ecs().write_storage::<comp::Stats>().get_mut(entity) {
|
||||
let falldmg = vel.z.powi(2) as i32 / 20 - 40;
|
||||
let falldmg = vel.z.powi(2) / 20.0 - 40.0;
|
||||
let mut damage = Damage {
|
||||
healthchange: -falldmg,
|
||||
source: DamageSource::Falling,
|
||||
};
|
||||
if let Some(loadout) = state.ecs().read_storage::<comp::Loadout>().get(entity) {
|
||||
damage.modify_damage(false, loadout);
|
||||
}
|
||||
stats.health.change_by(comp::HealthChange {
|
||||
amount: -falldmg,
|
||||
amount: damage.healthchange as i32,
|
||||
cause: comp::HealthSource::World,
|
||||
});
|
||||
}
|
||||
@ -211,11 +221,12 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, power: f32, owner: Opti
|
||||
// Go through all other entities
|
||||
let hit_range = 3.0 * power;
|
||||
let ecs = &server.state.ecs();
|
||||
for (pos_b, ori_b, character_b, stats_b) in (
|
||||
for (pos_b, ori_b, character_b, stats_b, loadout_b) in (
|
||||
&ecs.read_storage::<comp::Pos>(),
|
||||
&ecs.read_storage::<comp::Ori>(),
|
||||
ecs.read_storage::<comp::CharacterState>().maybe(),
|
||||
&mut ecs.write_storage::<comp::Stats>(),
|
||||
ecs.read_storage::<comp::Loadout>().maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -227,21 +238,22 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, power: f32, owner: Opti
|
||||
&& distance_squared < hit_range.powi(2)
|
||||
{
|
||||
// Weapon gives base damage
|
||||
let mut dmg = ((1.0 - distance_squared / hit_range.powi(2)) * power * 10.0) as u32;
|
||||
let dmg = (1.0 - distance_squared / hit_range.powi(2)) * power * 10.0;
|
||||
|
||||
if rand::random() {
|
||||
dmg += 1;
|
||||
}
|
||||
let mut damage = Damage {
|
||||
healthchange: -dmg,
|
||||
source: DamageSource::Explosion,
|
||||
};
|
||||
|
||||
// Block
|
||||
if character_b.map(|c_b| c_b.is_block()).unwrap_or(false)
|
||||
&& ori_b.0.angle_between(pos - pos_b.0) < BLOCK_ANGLE.to_radians() / 2.0
|
||||
{
|
||||
dmg = (dmg as f32 * (1.0 - BLOCK_EFFICIENCY)) as u32
|
||||
let block = character_b.map(|c_b| c_b.is_block()).unwrap_or(false)
|
||||
&& ori_b.0.angle_between(pos - pos_b.0) < BLOCK_ANGLE.to_radians() / 2.0;
|
||||
|
||||
if let Some(loadout) = loadout_b {
|
||||
damage.modify_damage(block, loadout);
|
||||
}
|
||||
|
||||
stats_b.health.change_by(HealthChange {
|
||||
amount: -(dmg as i32),
|
||||
amount: damage.healthchange as i32,
|
||||
cause: HealthSource::Projectile { owner },
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
-- This file should undo anything in `up.sql`
|
@ -0,0 +1,15 @@
|
||||
-- This migration adjusts projectiles in accordance with the changes made in MR 1222
|
||||
UPDATE
|
||||
loadout
|
||||
SET
|
||||
items = json_replace(
|
||||
items,
|
||||
'$.active_item.ability1.BasicRanged.projectile.hit_entity[0]',
|
||||
json('{"Damage": -3}'),
|
||||
'$.active_item.ability2.BasicRanged.projectile.hit_entity[0]',
|
||||
json('{"Damage": -3}'),
|
||||
'$.second_item.ability1.BasicRanged.projectile.hit_entity[0]',
|
||||
json('{"Damage": -3}'),
|
||||
'$.second_item.ability2.BasicRanged.projectile.hit_entity[0]',
|
||||
json('{"Damage": -3}')
|
||||
);
|
Loading…
Reference in New Issue
Block a user