use crate::{ client::Client, comp::{ ability, agent::{Agent, AgentEvent, Sound, SoundKind}, loot_owner::LootOwner, skillset::SkillGroupKind, BuffKind, BuffSource, PhysicsState, }, rtsim::RtSim, sys::terrain::SAFE_ZONE_RADIUS, Server, SpawnPoint, StateExt, }; use common::{ combat, combat::DamageContributor, comp::{ self, aura, buff, chat::{KillSource, KillType}, inventory::item::MaterialStatManifest, Alignment, Auras, Body, CharacterState, Energy, Group, Health, HealthChange, Inventory, Player, Poise, Pos, SkillSet, Stats, }, event::{EventBus, ServerEvent}, outcome::Outcome, resources::Time, rtsim::RtSimEntity, terrain::{Block, BlockKind, TerrainGrid}, uid::{Uid, UidAllocator}, util::Dir, vol::ReadVol, Damage, DamageKind, DamageSource, Explosion, GroupTarget, RadiusEffect, }; use common_net::{msg::ServerGeneral, sync::WorldSyncExt}; use common_state::BlockChange; use comp::chat::GenericChatMsg; use hashbrown::HashSet; use rand::{distributions::WeightedIndex, Rng}; use rand_distr::Distribution; use specs::{ join::Join, saveload::MarkerAllocator, Builder, Entity as EcsEntity, Entity, WorldExt, }; use std::{collections::HashMap, iter}; use tracing::{debug, error}; use vek::{Vec2, Vec3}; #[derive(Hash, Eq, PartialEq)] enum DamageContrib { Solo(EcsEntity), Group(Group), NotFound, } pub fn handle_poise(server: &Server, entity: EcsEntity, change: comp::PoiseChange) { let ecs = &server.state.ecs(); if let Some(character_state) = ecs.read_storage::().get(entity) { // Entity is invincible to poise change during stunned/staggered character // state, but the mitigated poise damage is converted to health damage instead if let CharacterState::Stunned(data) = character_state { let health_change = change.amount * data.static_data.poise_state.damage_multiplier(); let time = ecs.read_resource::