Pumpkin/pumpkin/src/client/combat.rs
Snowiiii 796341be05 Extractor: minimize everything
- blocks.json 8.3MB -> 4.1MB
- items.json 988KB -> 548KB
- packets.json 6.9kb -> 4.2kb
- particles.json 3.5kb -> 1.6kb
- recipies.json 376kb -> 264kb
- screens.json 731b -> 315b
- sounds.json 72.2kb -> 42.2kb
- synced_registeries.json 143.3kb -> 87.6kb
- tags.json 335.4kb -> 165.8kb
2024-11-27 00:12:11 +01:00

171 lines
4.4 KiB
Rust

use std::f32::consts::PI;
use pumpkin_core::math::vector3::Vector3;
use pumpkin_macros::{particle, sound};
use pumpkin_protocol::{
client::play::{CEntityVelocity, CParticle},
SoundCategory, VarInt,
};
use pumpkin_world::item::ItemStack;
use crate::{
entity::{player::Player, Entity},
world::World,
};
#[derive(Debug, Clone, Copy)]
pub enum AttackType {
Knockback,
Critical,
Sweeping,
Strong,
Weak,
}
impl AttackType {
pub async fn new(player: &Player, attack_cooldown_progress: f32) -> Self {
let entity = &player.living_entity.entity;
let sprinting = entity.sprinting.load(std::sync::atomic::Ordering::Relaxed);
let on_ground = entity.on_ground.load(std::sync::atomic::Ordering::Relaxed);
let sword = player
.inventory
.lock()
.await
.held_item()
.is_some_and(ItemStack::is_sword);
let is_strong = attack_cooldown_progress > 0.9;
if sprinting && is_strong {
return Self::Knockback;
}
// TODO: even more checks
if is_strong && !on_ground {
// !sprinting omitted
return Self::Critical;
}
// TODO: movement speed check
if sword && is_strong {
// !is_crit, !is_knockback_hit, on_ground omitted
return Self::Sweeping;
}
if is_strong {
Self::Strong
} else {
Self::Weak
}
}
}
pub async fn handle_knockback(
attacker_entity: &Entity,
victim: &Player,
victim_entity: &Entity,
strength: f64,
) {
let yaw = attacker_entity.yaw.load();
let saved_velo = victim_entity.velocity.load();
victim_entity.knockback(
strength * 0.5,
f64::from((yaw * (PI / 180.0)).sin()),
f64::from(-(yaw * (PI / 180.0)).cos()),
);
let entity_id = VarInt(victim_entity.entity_id);
let victim_velocity = victim_entity.velocity.load();
let packet = &CEntityVelocity::new(
&entity_id,
victim_velocity.x as f32,
victim_velocity.y as f32,
victim_velocity.z as f32,
);
let velocity = attacker_entity.velocity.load();
attacker_entity
.velocity
.store(velocity.multiply(0.6, 1.0, 0.6));
victim_entity.velocity.store(saved_velo);
victim.client.send_packet(packet).await;
}
pub async fn spawn_sweep_particle(attacker_entity: &Entity, world: &World, pos: &Vector3<f64>) {
let yaw = attacker_entity.yaw.load();
let d = -f64::from((yaw * (PI / 180.0)).sin());
let e = f64::from((yaw * (PI / 180.0)).cos());
let scale = 0.5;
// TODO: use entity height
let body_y = pos.y * 2.0 * scale;
world
.broadcast_packet_all(&CParticle::new(
false,
pos.x + d,
body_y,
pos.z + e,
0.0,
0.0,
0.0,
0.0,
0,
VarInt(i32::from(particle!("sweep_attack"))), // sweep
&[],
))
.await;
}
pub async fn player_attack_sound(pos: &Vector3<f64>, world: &World, attack_type: AttackType) {
match attack_type {
AttackType::Knockback => {
world
.play_sound(
sound!("entity.player.attack.knockback"),
SoundCategory::Players,
pos,
)
.await;
}
AttackType::Critical => {
world
.play_sound(
sound!("entity.player.attack.crit"),
SoundCategory::Players,
pos,
)
.await;
}
AttackType::Sweeping => {
world
.play_sound(
sound!("entity.player.attack.sweep"),
SoundCategory::Players,
pos,
)
.await;
}
AttackType::Strong => {
world
.play_sound(
sound!("entity.player.attack.strong"),
SoundCategory::Players,
pos,
)
.await;
}
AttackType::Weak => {
world
.play_sound(
sound!("entity.player.attack.weak"),
SoundCategory::Players,
pos,
)
.await;
}
};
}