mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Make Fireballs explode EnsnaringVines
This commit is contained in:
parent
92684b31fa
commit
86b9e2d8e6
@ -13,7 +13,12 @@ pub struct Ray<'a, V: ReadVol, F: FnMut(&V::Vox) -> bool, G: RayForEach<V::Vox>>
|
|||||||
ignore_error: bool,
|
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 {
|
pub fn new(vol: &'a V, from: Vec3<f32>, to: Vec3<f32>, until: F) -> Self {
|
||||||
Self {
|
Self {
|
||||||
vol,
|
vol,
|
||||||
|
@ -243,6 +243,7 @@ impl Block {
|
|||||||
| SpriteKind::Loom
|
| SpriteKind::Loom
|
||||||
| SpriteKind::SpinningWheel
|
| SpriteKind::SpinningWheel
|
||||||
| SpriteKind::TanningRack => None,
|
| SpriteKind::TanningRack => None,
|
||||||
|
SpriteKind::EnsnaringVines => Some(0.1),
|
||||||
_ => Some(0.25),
|
_ => Some(0.25),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,8 @@ impl<'a> PhysicsData<'a> {
|
|||||||
char_state_maybe,
|
char_state_maybe,
|
||||||
)| {
|
)| {
|
||||||
let is_sticky = sticky.is_some();
|
let is_sticky = sticky.is_some();
|
||||||
// Code reviewers: remind me to check why on_ground was true instead of false here?
|
// 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_wall.is_none() && physics.on_ground.is_some();
|
||||||
let mut entity_entity_collision_checks = 0;
|
let mut entity_entity_collision_checks = 0;
|
||||||
let mut entity_entity_collisions = 0;
|
let mut entity_entity_collisions = 0;
|
||||||
@ -425,25 +426,43 @@ impl<'a> PhysicsData<'a> {
|
|||||||
entity_entity_collisions += 1;
|
entity_entity_collisions += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't apply e2e pushback to entities that are in a forced movement state
|
// Don't apply e2e pushback to entities
|
||||||
// (e.g. roll, leapmelee). This allows leaps to work properly (since you won't
|
// that are in a forced movement state
|
||||||
// get pushed away before delivering the hit), and allows rolling through an
|
// (e.g. roll, leapmelee).
|
||||||
// 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
|
// 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)
|
// ground (or on the wall)
|
||||||
if !forced_movement
|
if !forced_movement
|
||||||
&& (!is_sticky
|
&& (!is_sticky || is_mid_air)
|
||||||
|| is_mid_air)
|
|
||||||
&& diff.magnitude_squared() > 0.0
|
&& diff.magnitude_squared() > 0.0
|
||||||
&& !is_projectile
|
&& !is_projectile
|
||||||
&& !matches!(collider_other,Some(Collider::Voxel { .. }))
|
&& !matches!(
|
||||||
|
collider_other,
|
||||||
|
Some(Collider::Voxel { .. })
|
||||||
|
)
|
||||||
&& !matches!(collider, Some(Collider::Voxel { .. }))
|
&& !matches!(collider, Some(Collider::Voxel { .. }))
|
||||||
{
|
{
|
||||||
let force = 400.0
|
let force = 400.0
|
||||||
@ -892,7 +911,8 @@ impl<'a> PhysicsData<'a> {
|
|||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec3::zero);
|
.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()
|
if block_rpos.z.abs()
|
||||||
> block_rpos.xy().map(|e| e.abs()).reduce_partial_max()
|
> block_rpos.xy().map(|e| e.abs()).reduce_partial_max()
|
||||||
{
|
{
|
||||||
@ -942,11 +962,12 @@ impl<'a> PhysicsData<'a> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute center and radius of tick path bounding sphere for the entity
|
// Compute center and radius of tick path bounding sphere
|
||||||
// for broad checks of whether it will collide with a voxel collider
|
// for the entity for broad checks of whether it will
|
||||||
|
// collide with a voxel collider
|
||||||
let path_sphere = {
|
let path_sphere = {
|
||||||
// TODO: duplicated with maintain_pushback_cache, make a common function
|
// TODO: duplicated with maintain_pushback_cache,
|
||||||
// to call to compute all this info?
|
// make a common function to call to compute all this info?
|
||||||
let z_limits = calc_z_limit(character_state, Some(collider));
|
let z_limits = calc_z_limit(character_state, Some(collider));
|
||||||
let z_limits = (z_limits.0 * scale, z_limits.1 * scale);
|
let z_limits = (z_limits.0 * scale, z_limits.1 * scale);
|
||||||
let half_height = (z_limits.1 - z_limits.0) / 2.0;
|
let half_height = (z_limits.1 - z_limits.0) / 2.0;
|
||||||
|
@ -157,8 +157,15 @@ impl<'a> System<'a> for Sys {
|
|||||||
for effect in projectile.hit_solid.drain(..) {
|
for effect in projectile.hit_solid.drain(..) {
|
||||||
match effect {
|
match effect {
|
||||||
projectile::Effect::Explode(e) => {
|
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.
|
||||||
|
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 {
|
server_emitter.emit(ServerEvent::Explosion {
|
||||||
pos: pos.0,
|
pos: pos.0 + offset,
|
||||||
explosion: e,
|
explosion: e,
|
||||||
owner: projectile.owner,
|
owner: projectile.owner,
|
||||||
});
|
});
|
||||||
|
@ -34,6 +34,7 @@ use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
|
|||||||
use common_state::BlockChange;
|
use common_state::BlockChange;
|
||||||
use comp::chat::GenericChatMsg;
|
use comp::chat::GenericChatMsg;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
|
use rand::Rng;
|
||||||
use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt};
|
use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use vek::{Vec2, Vec3};
|
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()
|
((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 {
|
for effect in explosion.effects {
|
||||||
match effect {
|
match effect {
|
||||||
RadiusEffect::TerrainDestruction(power) => {
|
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;
|
let color_range = power * 2.7;
|
||||||
for _ in 0..RAYS {
|
for _ in 0..RAYS {
|
||||||
let dir = Vec3::new(
|
let dir = Vec3::new(
|
||||||
rand::random::<f32>() - 0.5,
|
rng.gen::<f32>() - 0.5,
|
||||||
rand::random::<f32>() - 0.5,
|
rng.gen::<f32>() - 0.5,
|
||||||
rand::random::<f32>() - 0.5,
|
rng.gen::<f32>() - 0.5,
|
||||||
)
|
)
|
||||||
.normalized();
|
.normalized();
|
||||||
|
|
||||||
let _ = ecs
|
let _ = ecs
|
||||||
.read_resource::<TerrainGrid>()
|
.read_resource::<TerrainGrid>()
|
||||||
.ray(pos, pos + dir * color_range)
|
.ray(pos, pos + dir * color_range)
|
||||||
// TODO: Faster RNG
|
.until(|_| rng.gen::<f32>() < 0.05)
|
||||||
.until(|_| rand::random::<f32>() < 0.05)
|
|
||||||
.for_each(|_: &Block, pos| touched_blocks.push(pos))
|
.for_each(|_: &Block, pos| touched_blocks.push(pos))
|
||||||
.cast();
|
.cast();
|
||||||
}
|
}
|
||||||
@ -790,21 +792,31 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
|||||||
// Destroy terrain
|
// Destroy terrain
|
||||||
for _ in 0..RAYS {
|
for _ in 0..RAYS {
|
||||||
let dir = Vec3::new(
|
let dir = Vec3::new(
|
||||||
rand::random::<f32>() - 0.5,
|
rng.gen::<f32>() - 0.5,
|
||||||
rand::random::<f32>() - 0.5,
|
rng.gen::<f32>() - 0.5,
|
||||||
rand::random::<f32>() - 0.15,
|
rng.gen::<f32>() - 0.15,
|
||||||
)
|
)
|
||||||
.normalized();
|
.normalized();
|
||||||
|
|
||||||
let mut ray_energy = power;
|
let mut ray_energy = power;
|
||||||
|
|
||||||
let terrain = ecs.read_resource::<TerrainGrid>();
|
let terrain = ecs.read_resource::<TerrainGrid>();
|
||||||
|
let from = pos;
|
||||||
|
let to = pos + dir * power;
|
||||||
let _ = terrain
|
let _ = terrain
|
||||||
.ray(pos, pos + dir * power)
|
.ray(from, to)
|
||||||
// TODO: Faster RNG
|
|
||||||
.until(|block: &Block| {
|
.until(|block: &Block| {
|
||||||
let stop = block.is_liquid() || block.explode_power().is_none() || ray_energy <= 0.0;
|
// Stop if:
|
||||||
ray_energy -= block.explode_power().unwrap_or(0.0) + rand::random::<f32>() * 0.1;
|
// 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
|
stop
|
||||||
})
|
})
|
||||||
.for_each(|block: &Block, pos| {
|
.for_each(|block: &Block, pos| {
|
||||||
|
Loading…
Reference in New Issue
Block a user