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

View File

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

View File

@ -259,6 +259,14 @@ impl Block {
.unwrap_or(false) .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, /// The tool required to mine this block. For blocks that cannot be mined,
/// `None` is returned. /// `None` is returned.
#[inline] #[inline]

View File

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

View File

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

View File

@ -181,6 +181,13 @@ impl<'a> System<'a> for Sys {
}); });
projectile_vanished = true; 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, 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 => { projectile::Effect::Vanish => {
let entity = projectile_info.entity; let entity = projectile_info.entity;
server_emitter.emit(ServerEvent::Destroy { server_emitter.emit(ServerEvent::Destroy {

View File

@ -37,7 +37,7 @@ use common_state::BlockChange;
use comp::chat::GenericChatMsg; use comp::chat::GenericChatMsg;
use hashbrown::HashSet; use hashbrown::HashSet;
use rand::Rng; 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 tracing::error;
use vek::{Vec2, Vec3}; 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 // Only drop loot if entity has agency (not a player), and if it is not owned by
// another entity (not a pet) // another entity (not a pet)
use specs::Builder;
// Decide for a loot drop before turning into a lootbag // Decide for a loot drop before turning into a lootbag
let old_body = state.ecs().write_storage::<Body>().remove(entity); 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) { pub fn handle_aura(server: &mut Server, entity: EcsEntity, aura_change: aura::AuraChange) {
let ecs = &server.state.ecs(); let ecs = &server.state.ecs();
let mut auras_all = ecs.write_storage::<comp::Auras>(); 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, handle_initialize_character, handle_loaded_character_data, handle_shockwave, handle_shoot,
}; };
use entity_manipulation::{ use entity_manipulation::{
handle_aura, handle_buff, handle_combo_change, handle_damage, handle_delete, handle_destroy, handle_aura, handle_bonk, handle_buff, handle_combo_change, handle_damage, handle_delete,
handle_energy_change, handle_explosion, handle_knockback, handle_land_on_ground, handle_poise, handle_destroy, handle_energy_change, handle_explosion, handle_knockback,
handle_respawn, handle_teleport_to, handle_land_on_ground, handle_poise, handle_respawn, handle_teleport_to,
}; };
use group_manip::handle_group; use group_manip::handle_group;
use information::handle_site_info; use information::handle_site_info;
@ -67,6 +67,7 @@ impl Server {
explosion, explosion,
owner, owner,
} => handle_explosion(self, pos, explosion, owner), } => handle_explosion(self, pos, explosion, owner),
ServerEvent::Bonk { pos, owner, target } => handle_bonk(self, pos, owner, target),
ServerEvent::Shoot { ServerEvent::Shoot {
entity, entity,
dir, dir,