Merge branch 'juliancoffee/explode_vines' into 'master'

Make Fireballs explode EnsnaringVines

See merge request veloren/veloren!2758
This commit is contained in:
Imbris 2021-08-14 19:09:05 +00:00
commit 1fd25c22dd
5 changed files with 83 additions and 35 deletions

View File

@ -13,7 +13,12 @@ pub struct Ray<'a, V: ReadVol, F: FnMut(&V::Vox) -> bool, G: RayForEach<V::Vox>>
ignore_error: bool,
}
impl<'a, V: ReadVol, F: FnMut(&V::Vox) -> bool, G: RayForEach<V::Vox>> Ray<'a, V, F, G> {
impl<'a, V, F, G> Ray<'a, V, F, G>
where
V: ReadVol,
F: FnMut(&V::Vox) -> bool,
G: RayForEach<V::Vox>,
{
pub fn new(vol: &'a V, from: Vec3<f32>, to: Vec3<f32>, until: F) -> Self {
Self {
vol,

View File

@ -243,6 +243,7 @@ impl Block {
| SpriteKind::Loom
| SpriteKind::SpinningWheel
| SpriteKind::TanningRack => None,
SpriteKind::EnsnaringVines => Some(0.1),
_ => Some(0.25),
}),
}

View File

@ -318,8 +318,7 @@ impl<'a> PhysicsData<'a> {
char_state_maybe,
)| {
let is_sticky = sticky.is_some();
// Code reviewers: remind me to check why on_ground was true instead of false here?
let is_mid_air = physics.on_wall.is_none() && physics.on_ground.is_some();
let is_mid_air = physics.on_surface().is_none();
let mut entity_entity_collision_checks = 0;
let mut entity_entity_collisions = 0;
@ -425,25 +424,43 @@ impl<'a> PhysicsData<'a> {
entity_entity_collisions += 1;
}
// Don't apply e2e pushback to entities that are in a forced movement state
// (e.g. roll, leapmelee). This allows leaps to work properly (since you won't
// get pushed away before delivering the hit), and allows rolling through an
// enemy when trapped (e.g. with minotaur). This allows using e2e pushback to
// gain speed by jumping out of a roll while in the middle of a collider, this
// is an intentional combat mechanic.
let forced_movement = matches!(char_state_maybe, Some(cs) if cs.is_forced_movement());
// Don't apply repulsive force to projectiles or if we're colliding with a
// terrain-like entity, or if we are a terrain-like entity
// Don't apply e2e pushback to entities
// that are in a forced movement state
// (e.g. roll, leapmelee).
//
// Don't apply force when entity is a sticky which is on the
// This allows leaps to work properly
// (since you won't get pushed away before
// delivering the hit), and allows
// rolling through an enemy when trapped
// (e.g. with minotaur).
//
// This allows using e2e pushback to
// gain speed by jumping out of a roll
// while in the middle of a collider, this
// is an intentional combat mechanic.
let forced_movement = matches!(
char_state_maybe,
Some(cs) if cs.is_forced_movement());
// Don't apply repulsive force
// to projectiles
//
// or if we're colliding with a
// terrain-like entity,
//
// or if we are a terrain-like entity
//
// Don't apply force when entity
// is a sticky which is on the
// ground (or on the wall)
if !forced_movement
&& (!is_sticky
|| is_mid_air)
&& (!is_sticky || is_mid_air)
&& diff.magnitude_squared() > 0.0
&& !is_projectile
&& !matches!(collider_other,Some(Collider::Voxel { .. }))
&& !matches!(
collider_other,
Some(Collider::Voxel { .. })
)
&& !matches!(collider, Some(Collider::Voxel { .. }))
{
let force = 400.0
@ -892,7 +909,8 @@ impl<'a> PhysicsData<'a> {
.try_normalized()
.unwrap_or_else(Vec3::zero);
// See whether we're on the top/bottom of a block, or the side
// See whether we're on the top/bottom of a block,
// or the side
if block_rpos.z.abs()
> block_rpos.xy().map(|e| e.abs()).reduce_partial_max()
{
@ -942,11 +960,12 @@ impl<'a> PhysicsData<'a> {
},
}
// Compute center and radius of tick path bounding sphere for the entity
// for broad checks of whether it will collide with a voxel collider
// Compute center and radius of tick path bounding sphere
// for the entity for broad checks of whether it will
// collide with a voxel collider
let path_sphere = {
// TODO: duplicated with maintain_pushback_cache, make a common function
// to call to compute all this info?
// TODO: duplicated with maintain_pushback_cache,
// make a common function to call to compute all this info?
let z_limits = calc_z_limit(character_state, Some(collider));
let z_limits = (z_limits.0 * scale, z_limits.1 * scale);
let half_height = (z_limits.1 - z_limits.0) / 2.0;

View File

@ -157,8 +157,19 @@ impl<'a> System<'a> for Sys {
for effect in projectile.hit_solid.drain(..) {
match effect {
projectile::Effect::Explode(e) => {
// We offset position a little back on the way,
// so if we hit non-exploadable block
// we still can affect blocks around it.
//
// TODO: orientation of fallen projectile is
// fragile heuristic for direction, find more
// robust method.
let projectile_direction = orientations
.get(entity)
.map_or_else(Vec3::zero, |ori| ori.look_vec());
let offset = -0.2 * projectile_direction;
server_emitter.emit(ServerEvent::Explosion {
pos: pos.0,
pos: pos.0 + offset,
explosion: e,
owner: projectile.owner,
});

View File

@ -34,6 +34,7 @@ use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
use common_state::BlockChange;
use comp::chat::GenericChatMsg;
use hashbrown::HashSet;
use rand::Rng;
use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt};
use tracing::error;
use vek::{Vec2, Vec3};
@ -738,6 +739,8 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
((horiz_dist.max(vert_distance).max(0.0) / radius).min(1.0) - 1.0).abs()
}
// TODO: Faster RNG?
let mut rng = rand::thread_rng();
for effect in explosion.effects {
match effect {
RadiusEffect::TerrainDestruction(power) => {
@ -748,17 +751,16 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
let color_range = power * 2.7;
for _ in 0..RAYS {
let dir = Vec3::new(
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
rng.gen::<f32>() - 0.5,
rng.gen::<f32>() - 0.5,
rng.gen::<f32>() - 0.5,
)
.normalized();
let _ = ecs
.read_resource::<TerrainGrid>()
.ray(pos, pos + dir * color_range)
// TODO: Faster RNG
.until(|_| rand::random::<f32>() < 0.05)
.until(|_| rng.gen::<f32>() < 0.05)
.for_each(|_: &Block, pos| touched_blocks.push(pos))
.cast();
}
@ -790,21 +792,31 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
// Destroy terrain
for _ in 0..RAYS {
let dir = Vec3::new(
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.15,
rng.gen::<f32>() - 0.5,
rng.gen::<f32>() - 0.5,
rng.gen::<f32>() - 0.15,
)
.normalized();
let mut ray_energy = power;
let terrain = ecs.read_resource::<TerrainGrid>();
let from = pos;
let to = pos + dir * power;
let _ = terrain
.ray(pos, pos + dir * power)
// TODO: Faster RNG
.ray(from, to)
.until(|block: &Block| {
let stop = block.is_liquid() || block.explode_power().is_none() || ray_energy <= 0.0;
ray_energy -= block.explode_power().unwrap_or(0.0) + rand::random::<f32>() * 0.1;
// Stop if:
// 1) Block is liquid
// 2) Consumed all energy
// 3) Can't explode block (for example we hit stone wall)
let stop = block.is_liquid()
|| block.explode_power().is_none()
|| ray_energy <= 0.0;
ray_energy -=
block.explode_power().unwrap_or(0.0) + rng.gen::<f32>() * 0.1;
stop
})
.for_each(|block: &Block, pos| {