Explosions now use attacks.

This commit is contained in:
Sam 2021-01-30 17:35:00 -05:00
parent 7675e53740
commit 5c16b0b532
7 changed files with 147 additions and 200 deletions

View File

@ -173,7 +173,7 @@ impl Attack {
.filter(|e| !(matches!(e.target, Some(GroupTarget::OutOfGroup)) && target_dodging))
{
if match &effect.requirement {
Some(CombatRequirement::AnyDamage) => accumulated_damage != 0.0,
Some(CombatRequirement::AnyDamage) => accumulated_damage > 0.0,
Some(CombatRequirement::SufficientEnergy(r)) => {
if attacker_energy.map_or(true, |e| e.current() >= *r) {
server_events.push(ServerEvent::EnergyChange {
@ -322,7 +322,6 @@ pub enum CombatRequirement {
pub enum DamageSource {
Buff(BuffKind),
Melee,
Healing,
Projectile,
Explosion,
Falling,
@ -444,10 +443,6 @@ impl Damage {
},
}
},
DamageSource::Healing => HealthChange {
amount: damage as i32,
cause: HealthSource::Heal { by: uid },
},
DamageSource::Falling => {
// Armor
if (damage_reduction - 1.0).abs() < f32::EPSILON {

View File

@ -3,7 +3,6 @@ use crate::{
Attack, AttackEffect, CombatBuff, CombatRequirement, Damage, DamageComponent, DamageSource,
EffectComponent, GroupTarget, Knockback, KnockbackDir,
},
effect,
uid::Uid,
Explosion, RadiusEffect,
};
@ -109,41 +108,30 @@ impl ProjectileConstructor {
damage,
radius,
energy_regen,
} => Projectile {
hit_solid: vec![
Effect::Explode(Explosion {
effects: vec![
RadiusEffect::Entity(
Some(GroupTarget::OutOfGroup),
effect::Effect::Damage(Damage {
source: DamageSource::Explosion,
value: damage,
}),
),
RadiusEffect::TerrainDestruction(2.0),
],
radius,
energy_regen,
}),
Effect::Vanish,
],
hit_entity: vec![
Effect::Explode(Explosion {
effects: vec![RadiusEffect::Entity(
Some(GroupTarget::OutOfGroup),
effect::Effect::Damage(Damage {
source: DamageSource::Explosion,
value: damage,
}),
)],
radius,
energy_regen,
}),
Effect::Vanish,
],
time_left: Duration::from_secs(10),
owner,
ignore_group: true,
} => {
let damage = Damage {
source: DamageSource::Explosion,
value: damage,
};
let energy = AttackEffect::EnergyReward(energy_regen);
let energy = EffectComponent::new(None, energy)
.with_requirement(CombatRequirement::AnyDamage);
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup));
let attack = Attack::default().with_damage(damage).with_effect(energy);
let explosion = Explosion {
effects: vec![
RadiusEffect::Attack(attack),
RadiusEffect::TerrainDestruction(2.0),
],
radius,
};
Projectile {
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
hit_entity: vec![Effect::Explode(explosion), Effect::Vanish],
time_left: Duration::from_secs(10),
owner,
ignore_group: true,
}
},
Firebolt {
damage,
@ -171,56 +159,26 @@ impl ProjectileConstructor {
heal,
damage,
radius,
} => Projectile {
hit_solid: vec![
Effect::Explode(Explosion {
effects: vec![
RadiusEffect::Entity(
Some(GroupTarget::OutOfGroup),
effect::Effect::Damage(Damage {
source: DamageSource::Explosion,
value: damage,
}),
),
RadiusEffect::Entity(
Some(GroupTarget::InGroup),
effect::Effect::Damage(Damage {
source: DamageSource::Healing,
value: heal,
}),
),
],
radius,
energy_regen: 0,
}),
Effect::Vanish,
],
hit_entity: vec![
Effect::Explode(Explosion {
effects: vec![
RadiusEffect::Entity(
Some(GroupTarget::OutOfGroup),
effect::Effect::Damage(Damage {
source: DamageSource::Explosion,
value: damage,
}),
),
RadiusEffect::Entity(
Some(GroupTarget::InGroup),
effect::Effect::Damage(Damage {
source: DamageSource::Healing,
value: heal,
}),
),
],
radius,
energy_regen: 0,
}),
Effect::Vanish,
],
time_left: Duration::from_secs(10),
owner,
ignore_group: true,
} => {
let damage = Damage {
source: DamageSource::Explosion,
value: damage,
};
let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup));
let heal = AttackEffect::Heal(heal);
let heal = EffectComponent::new(Some(GroupTarget::InGroup), heal);
let attack = Attack::default().with_damage(damage).with_effect(heal);
let explosion = Explosion {
effects: vec![RadiusEffect::Attack(attack)],
radius,
};
Projectile {
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
hit_entity: vec![Effect::Explode(explosion), Effect::Vanish],
time_left: Duration::from_secs(10),
owner,
ignore_group: false,
}
},
Possess => Projectile {
hit_solid: vec![Effect::Stick],

View File

@ -1,15 +1,15 @@
use crate::{combat::GroupTarget, effect::Effect};
use crate::{combat::Attack, effect::Effect};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Explosion {
pub effects: Vec<RadiusEffect>,
pub radius: f32,
pub energy_regen: u32,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum RadiusEffect {
TerrainDestruction(f32),
Entity(Option<GroupTarget>, Effect),
Entity(Effect),
Attack(Attack),
}

View File

@ -122,8 +122,7 @@ impl<'a> System<'a> for Sys {
// Group to ignore collisions with
// Might make this more nuanced if shockwaves are used for non damage effects
let group = shockwave_owner
.and_then(|e| groups.get(e));
let group = shockwave_owner.and_then(|e| groups.get(e));
// Go through all other effectable entities
for (

View File

@ -1360,17 +1360,13 @@ fn handle_explosion(
pos: pos.0,
explosion: Explosion {
effects: vec![
RadiusEffect::Entity(
None,
Effect::Damage(Damage {
source: DamageSource::Explosion,
value: 100.0 * power,
}),
),
RadiusEffect::Entity(Effect::Damage(Damage {
source: DamageSource::Explosion,
value: 100.0 * power,
})),
RadiusEffect::TerrainDestruction(power),
],
radius: 3.0 * power,
energy_regen: 0,
},
owner: ecs.read_storage::<Uid>().get(target).copied(),
reagent: None,

View File

@ -16,12 +16,13 @@ use common::{
object, Alignment, Body, CharacterState, Energy, EnergyChange, Group, Health, HealthChange,
HealthSource, Inventory, Item, Player, Poise, PoiseChange, PoiseSource, Pos, Stats,
},
effect::Effect,
event::{EventBus, ServerEvent},
lottery::Lottery,
outcome::Outcome,
rtsim::RtSimEntity,
terrain::{Block, TerrainGrid},
uid::{Uid, UidAllocator},
util::Dir,
vol::ReadVol,
Damage, DamageSource, Explosion, GroupTarget, RadiusEffect,
};
@ -576,32 +577,24 @@ pub fn handle_explosion(
// Add an outcome
// Uses radius as outcome power, makes negative if explosion has healing effect
let outcome_power = explosion.radius
* if explosion.effects.iter().any(|e| {
matches!(
e,
RadiusEffect::Entity(
_,
Effect::Damage(Damage {
source: DamageSource::Healing,
..
})
)
)
}) {
-1.0
} else {
1.0
};
let outcome_power = explosion.radius;
//
// * if explosion.effects.iter().any(|e| { matches!( e, RadiusEffect::Entity( _,
// Effect::Damage(Damage { source: DamageSource::Healing, .. }) ) )
// }) {
// -1.0
// } else {
// 1.0
// };
ecs.write_resource::<Vec<Outcome>>()
.push(Outcome::Explosion {
pos,
power: outcome_power,
radius: explosion.radius,
is_attack: explosion
.effects
.iter()
.any(|e| matches!(e, RadiusEffect::Entity(_, Effect::Damage(_)))),
is_attack: false, /*explosion
.effects
.iter()
.any(|e| matches!(e, RadiusEffect::Entity(_, Effect::Damage(_))))*/
reagent,
});
let owner_entity = owner.and_then(|uid| {
@ -685,54 +678,74 @@ pub fn handle_explosion(
.cast();
}
},
RadiusEffect::Entity(target, mut effect) => {
for (entity_b, pos_b) in (&ecs.entities(), &ecs.read_storage::<comp::Pos>()).join()
RadiusEffect::Attack(attack) => {
// TODO: Before merging handle falloff
let energies = &ecs.read_storage::<comp::Energy>();
for (entity_b, pos_b, _health_b, inventory_b_maybe) in (
&ecs.entities(),
&ecs.read_storage::<comp::Pos>(),
&ecs.read_storage::<comp::Health>(),
ecs.read_storage::<comp::Inventory>().maybe(),
)
.join()
.filter(|(_, _, h, _)| !h.is_dead)
{
// See if entities are in the same group
let mut same_group = owner_entity
.and_then(|e| groups.get(e))
.map_or(false, |group_a| Some(group_a) == groups.get(entity_b));
if let Some(entity) = owner_entity {
if entity == entity_b {
same_group = true;
// Check if it is a hit
let distance_squared = pos.distance_squared(pos_b.0);
let strength = 1.0 - distance_squared / explosion.radius.powi(2);
if strength > 0.0 {
// See if entities are in the same group
let same_group = owner_entity
.and_then(|e| groups.get(e))
.map(|group_a| Some(group_a) == groups.get(entity_b))
.unwrap_or(Some(entity_b) == owner_entity);
let target_group = if same_group {
GroupTarget::InGroup
} else {
GroupTarget::OutOfGroup
};
let dir = Dir::new(
(pos_b.0 - pos)
.try_normalized()
.unwrap_or_else(Vec3::unit_z),
);
let server_events = attack.apply_attack(
target_group,
owner_entity.unwrap(),
entity_b,
inventory_b_maybe,
owner.unwrap(),
owner_entity.and_then(|e| energies.get(e)),
dir,
false,
);
let server_eventbus = ecs.read_resource::<EventBus<ServerEvent>>();
for event in server_events {
server_eventbus.emit_now(event);
}
}
let target_group = if same_group {
GroupTarget::InGroup
} else {
GroupTarget::OutOfGroup
};
if let Some(target) = target {
if target != target_group {
continue;
}
}
}
},
RadiusEffect::Entity(mut effect) => {
for (entity_b, pos_b, _health_b) in (
&ecs.entities(),
&ecs.read_storage::<comp::Pos>(),
&ecs.read_storage::<comp::Health>(),
)
.join()
.filter(|(_, _, h)| !h.is_dead)
{
let distance_squared = pos.distance_squared(pos_b.0);
let strength = 1.0 - distance_squared / explosion.radius.powi(2);
if strength > 0.0 {
let is_alive = ecs
.read_storage::<comp::Health>()
.get(entity_b)
.map_or(false, |h| !h.is_dead);
if is_alive {
effect.modify_strength(strength);
server.state().apply_effect(entity_b, effect.clone(), owner);
// Apply energy change
if let Some(owner) = owner_entity {
if let Some(mut energy) =
ecs.write_storage::<comp::Energy>().get_mut(owner)
{
energy.change_by(EnergyChange {
amount: explosion.energy_regen as i32,
source: comp::EnergySource::HitEnemy,
});
}
}
}
effect.modify_strength(strength);
server.state().apply_effect(entity_b, effect.clone(), owner);
}
}
},

View File

@ -49,24 +49,17 @@ impl<'a> System<'a> for Sys {
pos: pos.0,
explosion: Explosion {
effects: vec![
RadiusEffect::Entity(
None,
Effect::Damage(Damage {
source: DamageSource::Explosion,
value: 500.0,
}),
),
RadiusEffect::Entity(
None,
Effect::PoiseChange(PoiseChange {
source: PoiseSource::Explosion,
amount: -100,
}),
),
RadiusEffect::Entity(Effect::Damage(Damage {
source: DamageSource::Explosion,
value: 500.0,
})),
RadiusEffect::Entity(Effect::PoiseChange(PoiseChange {
source: PoiseSource::Explosion,
amount: -100,
})),
RadiusEffect::TerrainDestruction(4.0),
],
radius: 12.0,
energy_regen: 0,
},
owner: *owner,
reagent: None,
@ -83,24 +76,17 @@ impl<'a> System<'a> for Sys {
pos: pos.0,
explosion: Explosion {
effects: vec![
RadiusEffect::Entity(
None,
Effect::Damage(Damage {
source: DamageSource::Explosion,
value: 50.0,
}),
),
RadiusEffect::Entity(
None,
Effect::PoiseChange(PoiseChange {
source: PoiseSource::Explosion,
amount: -40,
}),
),
RadiusEffect::Entity(Effect::Damage(Damage {
source: DamageSource::Explosion,
value: 50.0,
})),
RadiusEffect::Entity(Effect::PoiseChange(PoiseChange {
source: PoiseSource::Explosion,
amount: -40,
})),
RadiusEffect::TerrainDestruction(4.0),
],
radius: 12.0,
energy_regen: 0,
},
owner: *owner,
reagent: Some(*reagent),