mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sam/explosions' into 'master'
Staff Rebalancing See merge request veloren/veloren!2970
This commit is contained in:
@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Nerfed some skill values
|
- Nerfed some skill values
|
||||||
- Tweaked critical chance of legendary weapons
|
- Tweaked critical chance of legendary weapons
|
||||||
- Agents using fireball projectiles aim at the feet instead of the eyes
|
- Agents using fireball projectiles aim at the feet instead of the eyes
|
||||||
|
- Explosions can now have a nonzero minimum falloff
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ BasicRanged(
|
|||||||
damage: 13.0,
|
damage: 13.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
energy_regen: 0,
|
energy_regen: 0,
|
||||||
|
min_falloff: 0.5,
|
||||||
),
|
),
|
||||||
projectile_body: Object(BoltFire),
|
projectile_body: Object(BoltFire),
|
||||||
/*projectile_light: Some(LightEmitter {
|
/*projectile_light: Some(LightEmitter {
|
||||||
|
@ -6,6 +6,7 @@ BasicRanged(
|
|||||||
damage: 10.0,
|
damage: 10.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
energy_regen: 5.0,
|
energy_regen: 5.0,
|
||||||
|
min_falloff: 0.5,
|
||||||
),
|
),
|
||||||
projectile_body: Object(BoltFire),
|
projectile_body: Object(BoltFire),
|
||||||
/*projectile_light: Some(LightEmitter {
|
/*projectile_light: Some(LightEmitter {
|
||||||
|
@ -6,6 +6,7 @@ BasicRanged(
|
|||||||
damage: 10.0,
|
damage: 10.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
energy_regen: 5.0,
|
energy_regen: 5.0,
|
||||||
|
min_falloff: 0.5,
|
||||||
),
|
),
|
||||||
projectile_body: Object(BoltFire),
|
projectile_body: Object(BoltFire),
|
||||||
/*projectile_light: Some(LightEmitter {
|
/*projectile_light: Some(LightEmitter {
|
||||||
|
@ -6,6 +6,7 @@ BasicRanged(
|
|||||||
damage: 50.0,
|
damage: 50.0,
|
||||||
knockback: 18.0,
|
knockback: 18.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
|
min_falloff: 0.75,
|
||||||
),
|
),
|
||||||
projectile_body: Object(ClayRocket),
|
projectile_body: Object(ClayRocket),
|
||||||
projectile_light: None,
|
projectile_light: None,
|
||||||
|
@ -6,6 +6,7 @@ BasicRanged(
|
|||||||
damage: 20.0,
|
damage: 20.0,
|
||||||
knockback: 25.0,
|
knockback: 25.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
|
min_falloff: 0.6,
|
||||||
),
|
),
|
||||||
projectile_body: Object(Pumpkin),
|
projectile_body: Object(Pumpkin),
|
||||||
projectile_light: None,
|
projectile_light: None,
|
||||||
|
@ -6,6 +6,7 @@ BasicRanged(
|
|||||||
damage: 26.0,
|
damage: 26.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
energy_regen: 0,
|
energy_regen: 0,
|
||||||
|
min_falloff: 0.5,
|
||||||
),
|
),
|
||||||
projectile_body: Object(FireworkPurple),
|
projectile_body: Object(FireworkPurple),
|
||||||
/*projectile_light: Some(LightEmitter {
|
/*projectile_light: Some(LightEmitter {
|
||||||
|
@ -5,6 +5,7 @@ BasicRanged(
|
|||||||
projectile: NecroticSphere(
|
projectile: NecroticSphere(
|
||||||
damage: 45.0,
|
damage: 45.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
|
min_falloff: 0.9,
|
||||||
),
|
),
|
||||||
projectile_body: Object(FireworkPurple),
|
projectile_body: Object(FireworkPurple),
|
||||||
projectile_speed: 100.0,
|
projectile_speed: 100.0,
|
||||||
|
@ -6,6 +6,7 @@ BasicRanged(
|
|||||||
damage: 13.0,
|
damage: 13.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
energy_regen: 0,
|
energy_regen: 0,
|
||||||
|
min_falloff: 0.5,
|
||||||
),
|
),
|
||||||
projectile_body: Object(FireworkPurple),
|
projectile_body: Object(FireworkPurple),
|
||||||
/*projectile_light: Some(LightEmitter {
|
/*projectile_light: Some(LightEmitter {
|
||||||
|
@ -5,6 +5,7 @@ BasicRanged(
|
|||||||
projectile: Frostball(
|
projectile: Frostball(
|
||||||
damage: 12.0,
|
damage: 12.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
|
min_falloff: 0.5,
|
||||||
),
|
),
|
||||||
projectile_body: Object(BoltFire), // TODO: Get ice projectile model
|
projectile_body: Object(BoltFire), // TODO: Get ice projectile model
|
||||||
/*projectile_light: Some(LightEmitter {
|
/*projectile_light: Some(LightEmitter {
|
||||||
|
@ -5,6 +5,7 @@ BasicRanged(
|
|||||||
projectile: Snowball(
|
projectile: Snowball(
|
||||||
damage: 20.0,
|
damage: 20.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
|
min_falloff: 0.7,
|
||||||
),
|
),
|
||||||
projectile_body: Object(Snowball),
|
projectile_body: Object(Snowball),
|
||||||
projectile_speed: 60.0,
|
projectile_speed: 60.0,
|
||||||
|
@ -5,7 +5,8 @@ BasicRanged(
|
|||||||
projectile: Fireball(
|
projectile: Fireball(
|
||||||
damage: 9.0,
|
damage: 9.0,
|
||||||
radius: 4.0,
|
radius: 4.0,
|
||||||
energy_regen: 6.0,
|
energy_regen: 10.0,
|
||||||
|
min_falloff: 0.5,
|
||||||
),
|
),
|
||||||
projectile_body: Object(BoltFire),
|
projectile_body: Object(BoltFire),
|
||||||
projectile_speed: 60.0,
|
projectile_speed: 60.0,
|
||||||
|
@ -6,6 +6,7 @@ BasicRanged(
|
|||||||
damage: 6.0,
|
damage: 6.0,
|
||||||
radius: 5.0,
|
radius: 5.0,
|
||||||
energy_regen: 5.0,
|
energy_regen: 5.0,
|
||||||
|
min_falloff: 0.5,
|
||||||
),
|
),
|
||||||
projectile_body: Object(BoltFire),
|
projectile_body: Object(BoltFire),
|
||||||
/*projectile_light: Some(LightEmitter {
|
/*projectile_light: Some(LightEmitter {
|
||||||
|
@ -227,7 +227,7 @@ impl Attack {
|
|||||||
self.crit_multiplier,
|
self.crit_multiplier,
|
||||||
strength_modifier,
|
strength_modifier,
|
||||||
);
|
);
|
||||||
let applied_damage = -change.amount as f32;
|
let applied_damage = -change.amount;
|
||||||
accumulated_damage += applied_damage;
|
accumulated_damage += applied_damage;
|
||||||
emit_outcome(Outcome::Damage { pos: target.pos });
|
emit_outcome(Outcome::Damage { pos: target.pos });
|
||||||
if change.amount.abs() > Health::HEALTH_EPSILON {
|
if change.amount.abs() > Health::HEALTH_EPSILON {
|
||||||
@ -238,7 +238,7 @@ impl Attack {
|
|||||||
for effect in damage.effects.iter() {
|
for effect in damage.effects.iter() {
|
||||||
match effect {
|
match effect {
|
||||||
CombatEffect::Knockback(kb) => {
|
CombatEffect::Knockback(kb) => {
|
||||||
let impulse = kb.calculate_impulse(dir);
|
let impulse = kb.calculate_impulse(dir) * strength_modifier;
|
||||||
if !impulse.is_approx_zero() {
|
if !impulse.is_approx_zero() {
|
||||||
emit(ServerEvent::Knockback {
|
emit(ServerEvent::Knockback {
|
||||||
entity: target.entity,
|
entity: target.entity,
|
||||||
@ -250,7 +250,9 @@ impl Attack {
|
|||||||
if let Some(attacker) = attacker {
|
if let Some(attacker) = attacker {
|
||||||
emit(ServerEvent::EnergyChange {
|
emit(ServerEvent::EnergyChange {
|
||||||
entity: attacker.entity,
|
entity: attacker.entity,
|
||||||
change: *ec * compute_energy_reward_mod(attacker.inventory),
|
change: *ec
|
||||||
|
* compute_energy_reward_mod(attacker.inventory)
|
||||||
|
* strength_modifier,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -258,13 +260,16 @@ impl Attack {
|
|||||||
if thread_rng().gen::<f32>() < b.chance {
|
if thread_rng().gen::<f32>() < b.chance {
|
||||||
emit(ServerEvent::Buff {
|
emit(ServerEvent::Buff {
|
||||||
entity: target.entity,
|
entity: target.entity,
|
||||||
buff_change: BuffChange::Add(
|
buff_change: BuffChange::Add(b.to_buff(
|
||||||
b.to_buff(attacker.map(|a| a.uid), applied_damage),
|
attacker.map(|a| a.uid),
|
||||||
),
|
applied_damage,
|
||||||
|
strength_modifier,
|
||||||
|
)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
CombatEffect::Lifesteal(l) => {
|
CombatEffect::Lifesteal(l) => {
|
||||||
|
// Not modified by strength_modifer as damage already is
|
||||||
if let Some(attacker_entity) = attacker.map(|a| a.entity) {
|
if let Some(attacker_entity) = attacker.map(|a| a.entity) {
|
||||||
let change = HealthChange {
|
let change = HealthChange {
|
||||||
amount: applied_damage * l,
|
amount: applied_damage * l,
|
||||||
@ -280,7 +285,8 @@ impl Attack {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
CombatEffect::Poise(p) => {
|
CombatEffect::Poise(p) => {
|
||||||
let change = -Poise::apply_poise_reduction(*p, target.inventory);
|
let change = -Poise::apply_poise_reduction(*p, target.inventory)
|
||||||
|
* strength_modifier;
|
||||||
if change.abs() > Poise::POISE_EPSILON {
|
if change.abs() > Poise::POISE_EPSILON {
|
||||||
emit(ServerEvent::PoiseChange {
|
emit(ServerEvent::PoiseChange {
|
||||||
entity: target.entity,
|
entity: target.entity,
|
||||||
@ -291,7 +297,7 @@ impl Attack {
|
|||||||
},
|
},
|
||||||
CombatEffect::Heal(h) => {
|
CombatEffect::Heal(h) => {
|
||||||
let change = HealthChange {
|
let change = HealthChange {
|
||||||
amount: *h,
|
amount: *h * strength_modifier,
|
||||||
by: attacker.map(|a| a.uid),
|
by: attacker.map(|a| a.uid),
|
||||||
cause: None,
|
cause: None,
|
||||||
};
|
};
|
||||||
@ -303,6 +309,7 @@ impl Attack {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
CombatEffect::Combo(c) => {
|
CombatEffect::Combo(c) => {
|
||||||
|
// Not affected by strength modifier as integer
|
||||||
if let Some(attacker_entity) = attacker.map(|a| a.entity) {
|
if let Some(attacker_entity) = attacker.map(|a| a.entity) {
|
||||||
emit(ServerEvent::ComboChange {
|
emit(ServerEvent::ComboChange {
|
||||||
entity: attacker_entity,
|
entity: attacker_entity,
|
||||||
@ -366,7 +373,7 @@ impl Attack {
|
|||||||
is_applied = true;
|
is_applied = true;
|
||||||
match effect.effect {
|
match effect.effect {
|
||||||
CombatEffect::Knockback(kb) => {
|
CombatEffect::Knockback(kb) => {
|
||||||
let impulse = kb.calculate_impulse(dir);
|
let impulse = kb.calculate_impulse(dir) * strength_modifier;
|
||||||
if !impulse.is_approx_zero() {
|
if !impulse.is_approx_zero() {
|
||||||
emit(ServerEvent::Knockback {
|
emit(ServerEvent::Knockback {
|
||||||
entity: target.entity,
|
entity: target.entity,
|
||||||
@ -378,7 +385,9 @@ impl Attack {
|
|||||||
if let Some(attacker) = attacker {
|
if let Some(attacker) = attacker {
|
||||||
emit(ServerEvent::EnergyChange {
|
emit(ServerEvent::EnergyChange {
|
||||||
entity: attacker.entity,
|
entity: attacker.entity,
|
||||||
change: ec * compute_energy_reward_mod(attacker.inventory),
|
change: ec
|
||||||
|
* compute_energy_reward_mod(attacker.inventory)
|
||||||
|
* strength_modifier,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -386,13 +395,16 @@ impl Attack {
|
|||||||
if thread_rng().gen::<f32>() < b.chance {
|
if thread_rng().gen::<f32>() < b.chance {
|
||||||
emit(ServerEvent::Buff {
|
emit(ServerEvent::Buff {
|
||||||
entity: target.entity,
|
entity: target.entity,
|
||||||
buff_change: BuffChange::Add(
|
buff_change: BuffChange::Add(b.to_buff(
|
||||||
b.to_buff(attacker.map(|a| a.uid), accumulated_damage),
|
attacker.map(|a| a.uid),
|
||||||
),
|
accumulated_damage,
|
||||||
|
strength_modifier,
|
||||||
|
)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
CombatEffect::Lifesteal(l) => {
|
CombatEffect::Lifesteal(l) => {
|
||||||
|
// Not modified by strength_modifer as damage already is
|
||||||
if let Some(attacker_entity) = attacker.map(|a| a.entity) {
|
if let Some(attacker_entity) = attacker.map(|a| a.entity) {
|
||||||
let change = HealthChange {
|
let change = HealthChange {
|
||||||
amount: accumulated_damage * l,
|
amount: accumulated_damage * l,
|
||||||
@ -408,7 +420,8 @@ impl Attack {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
CombatEffect::Poise(p) => {
|
CombatEffect::Poise(p) => {
|
||||||
let change = -Poise::apply_poise_reduction(p, target.inventory);
|
let change =
|
||||||
|
-Poise::apply_poise_reduction(p, target.inventory) * strength_modifier;
|
||||||
if change.abs() > Poise::POISE_EPSILON {
|
if change.abs() > Poise::POISE_EPSILON {
|
||||||
emit(ServerEvent::PoiseChange {
|
emit(ServerEvent::PoiseChange {
|
||||||
entity: target.entity,
|
entity: target.entity,
|
||||||
@ -419,7 +432,7 @@ impl Attack {
|
|||||||
},
|
},
|
||||||
CombatEffect::Heal(h) => {
|
CombatEffect::Heal(h) => {
|
||||||
let change = HealthChange {
|
let change = HealthChange {
|
||||||
amount: h,
|
amount: h * strength_modifier,
|
||||||
by: attacker.map(|a| a.uid),
|
by: attacker.map(|a| a.uid),
|
||||||
cause: None,
|
cause: None,
|
||||||
};
|
};
|
||||||
@ -431,6 +444,7 @@ impl Attack {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
CombatEffect::Combo(c) => {
|
CombatEffect::Combo(c) => {
|
||||||
|
// Not affected by strength modifier as integer
|
||||||
if let Some(attacker_entity) = attacker.map(|a| a.entity) {
|
if let Some(attacker_entity) = attacker.map(|a| a.entity) {
|
||||||
emit(ServerEvent::ComboChange {
|
emit(ServerEvent::ComboChange {
|
||||||
entity: attacker_entity,
|
entity: attacker_entity,
|
||||||
@ -768,10 +782,11 @@ pub enum CombatBuffStrength {
|
|||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
impl CombatBuffStrength {
|
impl CombatBuffStrength {
|
||||||
fn to_strength(self, damage: f32) -> f32 {
|
fn to_strength(self, damage: f32, strength_modifier: f32) -> f32 {
|
||||||
match self {
|
match self {
|
||||||
|
// Not affected by strength modifier as damage already is
|
||||||
CombatBuffStrength::DamageFraction(f) => damage * f,
|
CombatBuffStrength::DamageFraction(f) => damage * f,
|
||||||
CombatBuffStrength::Value(v) => v,
|
CombatBuffStrength::Value(v) => v * strength_modifier,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -788,7 +803,7 @@ impl MulAssign<f32> for CombatBuffStrength {
|
|||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
impl CombatBuff {
|
impl CombatBuff {
|
||||||
fn to_buff(self, uid: Option<Uid>, damage: f32) -> Buff {
|
fn to_buff(self, uid: Option<Uid>, damage: f32, strength_modifier: f32) -> Buff {
|
||||||
// TODO: Generate BufCategoryId vec (probably requires damage overhaul?)
|
// TODO: Generate BufCategoryId vec (probably requires damage overhaul?)
|
||||||
let source = if let Some(uid) = uid {
|
let source = if let Some(uid) = uid {
|
||||||
BuffSource::Character { by: uid }
|
BuffSource::Character { by: uid }
|
||||||
@ -798,7 +813,7 @@ impl CombatBuff {
|
|||||||
Buff::new(
|
Buff::new(
|
||||||
self.kind,
|
self.kind,
|
||||||
BuffData::new(
|
BuffData::new(
|
||||||
self.strength.to_strength(damage),
|
self.strength.to_strength(damage, strength_modifier),
|
||||||
Some(Duration::from_secs_f32(self.dur_secs)),
|
Some(Duration::from_secs_f32(self.dur_secs)),
|
||||||
),
|
),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
|
@ -54,29 +54,35 @@ pub enum ProjectileConstructor {
|
|||||||
damage: f32,
|
damage: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
energy_regen: f32,
|
energy_regen: f32,
|
||||||
|
min_falloff: f32,
|
||||||
},
|
},
|
||||||
Frostball {
|
Frostball {
|
||||||
damage: f32,
|
damage: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
|
min_falloff: f32,
|
||||||
},
|
},
|
||||||
NecroticSphere {
|
NecroticSphere {
|
||||||
damage: f32,
|
damage: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
|
min_falloff: f32,
|
||||||
},
|
},
|
||||||
Possess,
|
Possess,
|
||||||
ClayRocket {
|
ClayRocket {
|
||||||
damage: f32,
|
damage: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
knockback: f32,
|
knockback: f32,
|
||||||
|
min_falloff: f32,
|
||||||
},
|
},
|
||||||
Snowball {
|
Snowball {
|
||||||
damage: f32,
|
damage: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
|
min_falloff: f32,
|
||||||
},
|
},
|
||||||
ExplodingPumpkin {
|
ExplodingPumpkin {
|
||||||
damage: f32,
|
damage: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
knockback: f32,
|
knockback: f32,
|
||||||
|
min_falloff: f32,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,9 +147,16 @@ impl ProjectileConstructor {
|
|||||||
damage,
|
damage,
|
||||||
radius,
|
radius,
|
||||||
energy_regen,
|
energy_regen,
|
||||||
|
min_falloff,
|
||||||
} => {
|
} => {
|
||||||
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(energy_regen))
|
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(energy_regen))
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
|
let buff = CombatEffect::Buff(CombatBuff {
|
||||||
|
kind: BuffKind::Burning,
|
||||||
|
dur_secs: 5.0,
|
||||||
|
strength: CombatBuffStrength::DamageFraction(0.1 * buff_strength),
|
||||||
|
chance: 0.1,
|
||||||
|
});
|
||||||
let damage = AttackDamage::new(
|
let damage = AttackDamage::new(
|
||||||
Damage {
|
Damage {
|
||||||
source: DamageSource::Explosion,
|
source: DamageSource::Explosion,
|
||||||
@ -151,7 +164,8 @@ impl ProjectileConstructor {
|
|||||||
value: damage,
|
value: damage,
|
||||||
},
|
},
|
||||||
Some(GroupTarget::OutOfGroup),
|
Some(GroupTarget::OutOfGroup),
|
||||||
);
|
)
|
||||||
|
.with_effect(buff);
|
||||||
let attack = Attack::default()
|
let attack = Attack::default()
|
||||||
.with_damage(damage)
|
.with_damage(damage)
|
||||||
.with_crit(crit_chance, crit_mult)
|
.with_crit(crit_chance, crit_mult)
|
||||||
@ -164,6 +178,7 @@ impl ProjectileConstructor {
|
|||||||
],
|
],
|
||||||
radius,
|
radius,
|
||||||
reagent: Some(Reagent::Red),
|
reagent: Some(Reagent::Red),
|
||||||
|
min_falloff,
|
||||||
};
|
};
|
||||||
Projectile {
|
Projectile {
|
||||||
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
||||||
@ -175,7 +190,11 @@ impl ProjectileConstructor {
|
|||||||
is_point: true,
|
is_point: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Frostball { damage, radius } => {
|
Frostball {
|
||||||
|
damage,
|
||||||
|
radius,
|
||||||
|
min_falloff,
|
||||||
|
} => {
|
||||||
let damage = AttackDamage::new(
|
let damage = AttackDamage::new(
|
||||||
Damage {
|
Damage {
|
||||||
source: DamageSource::Explosion,
|
source: DamageSource::Explosion,
|
||||||
@ -192,6 +211,7 @@ impl ProjectileConstructor {
|
|||||||
effects: vec![RadiusEffect::Attack(attack)],
|
effects: vec![RadiusEffect::Attack(attack)],
|
||||||
radius,
|
radius,
|
||||||
reagent: Some(Reagent::White),
|
reagent: Some(Reagent::White),
|
||||||
|
min_falloff,
|
||||||
};
|
};
|
||||||
Projectile {
|
Projectile {
|
||||||
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
||||||
@ -203,7 +223,11 @@ impl ProjectileConstructor {
|
|||||||
is_point: true,
|
is_point: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
NecroticSphere { damage, radius } => {
|
NecroticSphere {
|
||||||
|
damage,
|
||||||
|
radius,
|
||||||
|
min_falloff,
|
||||||
|
} => {
|
||||||
let damage = AttackDamage::new(
|
let damage = AttackDamage::new(
|
||||||
Damage {
|
Damage {
|
||||||
source: DamageSource::Explosion,
|
source: DamageSource::Explosion,
|
||||||
@ -220,6 +244,7 @@ impl ProjectileConstructor {
|
|||||||
effects: vec![RadiusEffect::Attack(attack)],
|
effects: vec![RadiusEffect::Attack(attack)],
|
||||||
radius,
|
radius,
|
||||||
reagent: Some(Reagent::Purple),
|
reagent: Some(Reagent::Purple),
|
||||||
|
min_falloff,
|
||||||
};
|
};
|
||||||
Projectile {
|
Projectile {
|
||||||
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
||||||
@ -244,6 +269,7 @@ impl ProjectileConstructor {
|
|||||||
damage,
|
damage,
|
||||||
radius,
|
radius,
|
||||||
knockback,
|
knockback,
|
||||||
|
min_falloff,
|
||||||
} => {
|
} => {
|
||||||
let knockback = AttackEffect::new(
|
let knockback = AttackEffect::new(
|
||||||
Some(GroupTarget::OutOfGroup),
|
Some(GroupTarget::OutOfGroup),
|
||||||
@ -272,6 +298,7 @@ impl ProjectileConstructor {
|
|||||||
],
|
],
|
||||||
radius,
|
radius,
|
||||||
reagent: Some(Reagent::Red),
|
reagent: Some(Reagent::Red),
|
||||||
|
min_falloff,
|
||||||
};
|
};
|
||||||
Projectile {
|
Projectile {
|
||||||
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
||||||
@ -283,7 +310,11 @@ impl ProjectileConstructor {
|
|||||||
is_point: true,
|
is_point: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Snowball { damage, radius } => {
|
Snowball {
|
||||||
|
damage,
|
||||||
|
radius,
|
||||||
|
min_falloff,
|
||||||
|
} => {
|
||||||
let damage = AttackDamage::new(
|
let damage = AttackDamage::new(
|
||||||
Damage {
|
Damage {
|
||||||
source: DamageSource::Explosion,
|
source: DamageSource::Explosion,
|
||||||
@ -299,6 +330,7 @@ impl ProjectileConstructor {
|
|||||||
effects: vec![RadiusEffect::Attack(attack)],
|
effects: vec![RadiusEffect::Attack(attack)],
|
||||||
radius,
|
radius,
|
||||||
reagent: Some(Reagent::White),
|
reagent: Some(Reagent::White),
|
||||||
|
min_falloff,
|
||||||
};
|
};
|
||||||
Projectile {
|
Projectile {
|
||||||
hit_solid: vec![],
|
hit_solid: vec![],
|
||||||
@ -314,6 +346,7 @@ impl ProjectileConstructor {
|
|||||||
damage,
|
damage,
|
||||||
radius,
|
radius,
|
||||||
knockback,
|
knockback,
|
||||||
|
min_falloff,
|
||||||
} => {
|
} => {
|
||||||
let knockback = AttackEffect::new(
|
let knockback = AttackEffect::new(
|
||||||
Some(GroupTarget::OutOfGroup),
|
Some(GroupTarget::OutOfGroup),
|
||||||
@ -353,6 +386,7 @@ impl ProjectileConstructor {
|
|||||||
],
|
],
|
||||||
radius,
|
radius,
|
||||||
reagent: Some(Reagent::Red),
|
reagent: Some(Reagent::Red),
|
||||||
|
min_falloff,
|
||||||
};
|
};
|
||||||
Projectile {
|
Projectile {
|
||||||
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
||||||
@ -417,6 +451,7 @@ impl ProjectileConstructor {
|
|||||||
Snowball {
|
Snowball {
|
||||||
ref mut damage,
|
ref mut damage,
|
||||||
ref mut radius,
|
ref mut radius,
|
||||||
|
..
|
||||||
} => {
|
} => {
|
||||||
*damage *= power;
|
*damage *= power;
|
||||||
*radius *= range;
|
*radius *= range;
|
||||||
|
@ -6,6 +6,7 @@ pub struct Explosion {
|
|||||||
pub effects: Vec<RadiusEffect>,
|
pub effects: Vec<RadiusEffect>,
|
||||||
pub radius: f32,
|
pub radius: f32,
|
||||||
pub reagent: Option<Reagent>,
|
pub reagent: Option<Reagent>,
|
||||||
|
pub min_falloff: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
@ -2033,6 +2033,7 @@ fn handle_explosion(
|
|||||||
],
|
],
|
||||||
radius: 3.0 * power,
|
radius: 3.0 * power,
|
||||||
reagent: None,
|
reagent: None,
|
||||||
|
min_falloff: 0.0,
|
||||||
},
|
},
|
||||||
owner,
|
owner,
|
||||||
});
|
});
|
||||||
|
@ -546,6 +546,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
|||||||
fn cylinder_sphere_strength(
|
fn cylinder_sphere_strength(
|
||||||
sphere_pos: Vec3<f32>,
|
sphere_pos: Vec3<f32>,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
|
min_falloff: f32,
|
||||||
cyl_pos: Vec3<f32>,
|
cyl_pos: Vec3<f32>,
|
||||||
cyl_body: Body,
|
cyl_body: Body,
|
||||||
) -> f32 {
|
) -> f32 {
|
||||||
@ -557,9 +558,19 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
|||||||
let vert_distance =
|
let vert_distance =
|
||||||
(sphere_pos.z - (cyl_pos.z + half_body_height)).abs() - half_body_height;
|
(sphere_pos.z - (cyl_pos.z + half_body_height)).abs() - half_body_height;
|
||||||
|
|
||||||
// Compare both checks, take whichever gives weaker effect, sets minimum of 0 so
|
// Use whichever gives maximum distance as that closer to real value. Sets
|
||||||
// that explosions reach a max strength on edge of entity
|
// minimum to 0 as negative values would indicate inside entity.
|
||||||
((horiz_dist.max(vert_distance).max(0.0) / radius).min(1.0) - 1.0).abs()
|
let distance = horiz_dist.max(vert_distance).max(0.0);
|
||||||
|
|
||||||
|
if distance > radius {
|
||||||
|
// If further than exploion radius, no strength
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
// Falloff inversely proportional to radius
|
||||||
|
let fall_off = ((distance / radius).min(1.0) - 1.0).abs();
|
||||||
|
let min_falloff = min_falloff.clamp(0.0, 1.0);
|
||||||
|
min_falloff + fall_off * (1.0 - min_falloff)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Faster RNG?
|
// TODO: Faster RNG?
|
||||||
@ -714,7 +725,13 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
|||||||
{
|
{
|
||||||
// Check if it is a hit
|
// Check if it is a hit
|
||||||
let strength = if let Some(body) = body_b_maybe {
|
let strength = if let Some(body) = body_b_maybe {
|
||||||
cylinder_sphere_strength(pos, explosion.radius, pos_b.0, *body)
|
cylinder_sphere_strength(
|
||||||
|
pos,
|
||||||
|
explosion.radius,
|
||||||
|
explosion.min_falloff,
|
||||||
|
pos_b.0,
|
||||||
|
*body,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let distance_squared = pos.distance_squared(pos_b.0);
|
let distance_squared = pos.distance_squared(pos_b.0);
|
||||||
1.0 - distance_squared / explosion.radius.powi(2)
|
1.0 - distance_squared / explosion.radius.powi(2)
|
||||||
@ -801,7 +818,13 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
|||||||
.join()
|
.join()
|
||||||
{
|
{
|
||||||
let strength = if let Some(body) = body_b_maybe {
|
let strength = if let Some(body) = body_b_maybe {
|
||||||
cylinder_sphere_strength(pos, explosion.radius, pos_b.0, *body)
|
cylinder_sphere_strength(
|
||||||
|
pos,
|
||||||
|
explosion.radius,
|
||||||
|
explosion.min_falloff,
|
||||||
|
pos_b.0,
|
||||||
|
*body,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let distance_squared = pos.distance_squared(pos_b.0);
|
let distance_squared = pos.distance_squared(pos_b.0);
|
||||||
1.0 - distance_squared / explosion.radius.powi(2)
|
1.0 - distance_squared / explosion.radius.powi(2)
|
||||||
|
@ -1862,6 +1862,7 @@ impl<'a> AgentData<'a> {
|
|||||||
damage: _,
|
damage: _,
|
||||||
radius: _,
|
radius: _,
|
||||||
energy_regen: _,
|
energy_regen: _,
|
||||||
|
min_falloff: _,
|
||||||
} => 0.0,
|
} => 0.0,
|
||||||
_ => tgt_eye_offset,
|
_ => tgt_eye_offset,
|
||||||
};
|
};
|
||||||
|
@ -61,6 +61,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
],
|
],
|
||||||
radius: 12.0,
|
radius: 12.0,
|
||||||
reagent: None,
|
reagent: None,
|
||||||
|
min_falloff: 0.75,
|
||||||
},
|
},
|
||||||
owner: *owner,
|
owner: *owner,
|
||||||
});
|
});
|
||||||
@ -153,6 +154,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
],
|
],
|
||||||
radius: 12.0,
|
radius: 12.0,
|
||||||
reagent: Some(*reagent),
|
reagent: Some(*reagent),
|
||||||
|
min_falloff: 0.0,
|
||||||
},
|
},
|
||||||
owner: *owner,
|
owner: *owner,
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user