Make arrows 'bonk' hanging sprites

This commit is contained in:
Joshua Barretto 2021-08-30 16:02:13 +01:00
parent 913c23e1ad
commit 0b1a820762
8 changed files with 71 additions and 10 deletions

View File

@ -19,6 +19,7 @@ pub enum Effect {
Vanish,
Stick,
Possess,
Bonk, // Knock/dislodge/change objects on hit
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -127,7 +128,7 @@ impl ProjectileConstructor {
.with_combo_increment();
Projectile {
hit_solid: vec![Effect::Stick],
hit_solid: vec![Effect::Stick, Effect::Bonk],
hit_entity: vec![Effect::Attack(attack), Effect::Vanish],
time_left: Duration::from_secs(15),
owner,

View File

@ -42,6 +42,11 @@ pub enum ServerEvent {
explosion: Explosion,
owner: Option<Uid>,
},
Bonk {
pos: Vec3<f32>,
owner: Option<Uid>,
target: Option<Uid>,
},
Damage {
entity: EcsEntity,
change: comp::HealthChange,

View File

@ -259,6 +259,14 @@ impl Block {
.unwrap_or(false)
}
#[inline]
pub fn is_bonkable(&self) -> bool {
match self.get_sprite() {
Some(SpriteKind::Apple | SpriteKind::Beehive | SpriteKind::Coconut) => self.is_solid(),
_ => false,
}
}
/// The tool required to mine this block. For blocks that cannot be mined,
/// `None` is returned.
#[inline]

View File

@ -238,6 +238,7 @@ impl SpriteKind {
| SpriteKind::MedFlatCactus
| SpriteKind::ShortFlatCactus
| SpriteKind::Apple
| SpriteKind::Beehive
| SpriteKind::Velorite
| SpriteKind::VeloriteFrag
| SpriteKind::Coconut

View File

@ -872,15 +872,14 @@ impl<'a> PhysicsData<'a> {
.terrain
.get(pos.0.map(|e| e.floor() as i32))
.ok()
.filter(|b| b.is_filled())
// TODO: `is_solid`, when arrows are special-cased
.filter(|b| b.is_solid())
{
(0.0, Some(block))
} else {
let (dist, block) = read
.terrain
.ray(pos.0, pos.0 + pos_delta)
.until(|block: &Block| block.is_filled())
.until(|block: &Block| block.is_solid())
.ignore_error()
.cast();
(dist, block.unwrap()) // Can't fail since we do ignore_error above
@ -897,7 +896,7 @@ impl<'a> PhysicsData<'a> {
.zip(read.bodies.get(entity).copied())
{
outcomes.push(Outcome::ProjectileHit {
pos: pos.0,
pos: pos.0 + pos_delta * dist,
body,
vel: vel.0,
source: projectile.owner,

View File

@ -181,6 +181,13 @@ impl<'a> System<'a> for Sys {
});
projectile_vanished = true;
},
projectile::Effect::Bonk => {
server_emitter.emit(ServerEvent::Bonk {
pos: pos.0,
owner: projectile.owner,
target: None,
});
},
_ => {},
}
}
@ -325,6 +332,15 @@ fn dispatch_hit(
owner: owner_uid,
});
},
projectile::Effect::Bonk => {
let Pos(pos) = *projectile_info.pos;
let owner_uid = projectile_info.owner_uid;
server_emitter.emit(ServerEvent::Bonk {
pos,
owner: owner_uid,
target: Some(projectile_target_info.uid),
});
},
projectile::Effect::Vanish => {
let entity = projectile_info.entity;
server_emitter.emit(ServerEvent::Destroy {

View File

@ -37,7 +37,7 @@ 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 specs::{join::Join, saveload::MarkerAllocator, Builder, Entity as EcsEntity, WorldExt};
use tracing::error;
use vek::{Vec2, Vec3};
@ -378,7 +378,6 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
{
// Only drop loot if entity has agency (not a player), and if it is not owned by
// another entity (not a pet)
use specs::Builder;
// Decide for a loot drop before turning into a lootbag
let old_body = state.ecs().write_storage::<Body>().remove(entity);
@ -1021,6 +1020,37 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
}
}
pub fn handle_bonk(server: &mut Server, pos: Vec3<f32>, owner: Option<Uid>, target: Option<Uid>) {
let ecs = &server.state.ecs();
let terrain = ecs.read_resource::<TerrainGrid>();
let mut block_change = ecs.write_resource::<BlockChange>();
if let Some(_target) = target {
// TODO: bonk entities but do no damage?
drop(owner);
} else {
use common::terrain::SpriteKind;
let pos = pos.map(|e| e.floor() as i32);
if let Some(block) = terrain.get(pos).ok().copied().filter(|b| b.is_bonkable()) {
if let Some(item) = comp::Item::try_reclaim_from_block(block) {
if block_change
.try_set(pos, block.with_sprite(SpriteKind::Empty))
.is_some()
{
drop(terrain);
drop(block_change);
server
.state
.create_object(Default::default(), comp::object::Body::Pouch)
.with(comp::Pos(pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)))
.with(item)
.build();
}
}
}
}
}
pub fn handle_aura(server: &mut Server, entity: EcsEntity, aura_change: aura::AuraChange) {
let ecs = &server.state.ecs();
let mut auras_all = ecs.write_storage::<comp::Auras>();

View File

@ -6,9 +6,9 @@ use entity_creation::{
handle_initialize_character, handle_loaded_character_data, handle_shockwave, handle_shoot,
};
use entity_manipulation::{
handle_aura, handle_buff, handle_combo_change, handle_damage, handle_delete, handle_destroy,
handle_energy_change, handle_explosion, handle_knockback, handle_land_on_ground, handle_poise,
handle_respawn, handle_teleport_to,
handle_aura, handle_bonk, handle_buff, handle_combo_change, handle_damage, handle_delete,
handle_destroy, handle_energy_change, handle_explosion, handle_knockback,
handle_land_on_ground, handle_poise, handle_respawn, handle_teleport_to,
};
use group_manip::handle_group;
use information::handle_site_info;
@ -67,6 +67,7 @@ impl Server {
explosion,
owner,
} => handle_explosion(self, pos, explosion, owner),
ServerEvent::Bonk { pos, owner, target } => handle_bonk(self, pos, owner, target),
ServerEvent::Shoot {
entity,
dir,