コード例 #1
0
        /// <summary>
        /// Called every ~5 seconds for WorldObject base
        /// </summary>
        public virtual void Heartbeat(double currentUnixTime)
        {
            if (EnchantmentManager.HasEnchantments)
            {
                EnchantmentManager.HeartBeat();
            }

            SetProperty(PropertyFloat.HeartbeatTimestamp, currentUnixTime);
            NextHeartbeatTime = currentUnixTime + CachedHeartbeatInterval;
        }
コード例 #2
0
        public int GetHealingResistRating()
        {
            // debuff?
            var healResistRating = HealingResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.HealingResistRating);

            return(healResistRating + enchantments);
        }
コード例 #3
0
ファイル: Creature_Rating.cs プロジェクト: zhouzu/PcapPlayer
        public int GetDotResistanceRating()
        {
            // get from base properties (monsters)?
            var dotResistRating = DotResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.DotResistRating);

            return(dotResistRating + enchantments);
        }
コード例 #4
0
ファイル: WorldObject_Tick.cs プロジェクト: acriaf/ACE
        /// <summary>
        /// Called every ~5 seconds for WorldObject base
        /// </summary>
        public virtual void HeartBeat(double currentUnixTime)
        {
            Generator_HeartBeat();

            EmoteManager.HeartBeat();

            EnchantmentManager.HeartBeat();

            cachedHeartbeatTimestamp = currentUnixTime;
            SetProperty(PropertyFloat.HeartbeatTimestamp, currentUnixTime);
        }
コード例 #5
0
ファイル: Player.cs プロジェクト: Zegeger/ACE
        /// <summary>
        /// Called every ~5 seconds for Players
        /// </summary>
        public override void HeartBeat()
        {
            NotifyLandblocks();

            EnchantmentManager.HeartBeat();
            VitalTick();
            ManaConsumersTick();
            ItemEnchantmentTick();

            QueueNextHeartBeat();
        }
コード例 #6
0
ファイル: Player_Death.cs プロジェクト: Illbatting/ACE
        /// <summary>
        /// Broadcasts the player death animation, updates vitae, and sends network messages for player death
        /// Queues the action to call TeleportOnDeath and enter portal space soon
        /// </summary>
        protected override void Die(WorldObject lastDamager, WorldObject topDamager)
        {
            UpdateVital(Health, 0);
            NumDeaths++;
            DeathLevel  = Level; // for calculating vitae XP
            VitaeCpPool = 0;     // reset vitae XP earned

            // killer = top damager for looting rights
            if (topDamager != null)
            {
                Killer = topDamager.Guid.Full;
            }

            // broadcast death animation
            var deathAnim = new Motion(MotionStance.NonCombat, MotionCommand.Dead);

            EnqueueBroadcastMotion(deathAnim);

            // killer death message = last damager
            var killerMsg           = lastDamager != null ? " to " + lastDamager.Name : "";
            var currentDeathMessage = $"died{killerMsg}.";

            // create network messages for player death
            var msgHealthUpdate = new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Health, 0);

            // TODO: death sounds? seems to play automatically in client
            // var msgDeathSound = new GameMessageSound(Guid, Sound.Death1, 1.0f);
            var msgNumDeaths         = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.NumDeaths, NumDeaths ?? 0);
            var msgDeathLevel        = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.DeathLevel, DeathLevel ?? 0);
            var msgVitaeCpPool       = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.VitaeCpPool, VitaeCpPool.Value);
            var msgPurgeEnchantments = new GameEventMagicPurgeEnchantments(Session);

            // update vitae
            var vitae = EnchantmentManager.UpdateVitae();

            var spellID             = (uint)SpellId.Vitae;
            var spell               = new Spell(spellID);
            var vitaeEnchantment    = new Enchantment(this, Guid, spellID, spell.Duration, 0, (EnchantmentMask)spell.StatModType, vitae);
            var msgVitaeEnchantment = new GameEventMagicUpdateEnchantment(Session, vitaeEnchantment);

            // send network messages for player death
            Session.Network.EnqueueSend(msgHealthUpdate, msgNumDeaths, msgDeathLevel, msgVitaeCpPool, msgPurgeEnchantments, msgVitaeEnchantment);

            // wait for the death animation to finish
            var dieChain   = new ActionChain();
            var animLength = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId).GetAnimationLength(MotionCommand.Dead);

            dieChain.AddDelaySeconds(animLength + 1.0f);

            // enter portal space
            dieChain.AddAction(this, CreateCorpse);
            dieChain.AddAction(this, TeleportOnDeath);
            dieChain.EnqueueChain();
        }
コード例 #7
0
ファイル: Creature_Rating.cs プロジェクト: tuita520/ACE
        public int GetNetherResistRating()
        {
            // wiki calls this dot resistance, does this affect dirty fighting bleed attack?

            // get from base properties (monsters)?
            var netherResistRating = NetherResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.NetherResistRating);

            return(netherResistRating + enchantments);
        }
コード例 #8
0
ファイル: Creature_Vitals.cs プロジェクト: klp2/ACE
        /// <summary>
        /// Updates a particular vital according to regeneration rate
        /// </summary>
        /// <param name="vital">The vital stat to update (health/stamina/mana)</param>
        public void VitalHeartBeat(CreatureVital vital)
        {
            // Current and MaxValue are properties and include overhead in getting their values. We cache them so we only hit the overhead once.
            var vitalCurrent = vital.Current;
            var vitalMax     = vital.MaxValue;

            if (vitalCurrent == vitalMax)
            {
                return;
            }

            if (vitalCurrent > vitalMax)
            {
                UpdateVital(vital, vitalMax);
                return;
            }

            if (vital.RegenRate == 0.0)
            {
                return;
            }

            // take attributes into consideration (strength, endurance)
            var attributeMod = GetAttributeMod(vital);

            // take stance into consideration (combat, crouch, sitting, sleeping)
            var stanceMod = GetStanceMod(vital);

            // take enchantments into consideration:
            // (regeneration / rejuvenation / mana renewal / etc.)
            var enchantmentMod = EnchantmentManager.GetRegenerationMod(vital);

            // cap rate?
            var currentTick = vital.RegenRate * attributeMod * stanceMod * enchantmentMod;

            // add in partially accumulated / rounded vitals from previous tick(s)
            var totalTick = currentTick + vital.PartialRegen;

            // accumulate partial vital rates between ticks
            var intTick = (int)totalTick;

            vital.PartialRegen = totalTick - intTick;

            if (intTick > 0)
            {
                UpdateVitalDelta(vital, intTick);
                if (vital.Vital == PropertyAttribute2nd.MaxHealth)
                {
                    DamageHistory.OnHeal((uint)intTick);
                }
            }
            //Console.WriteLine($"VitalTick({vital.Vital.ToSentence()}): attributeMod={attributeMod}, stanceMod={stanceMod}, enchantmentMod={enchantmentMod}, regenRate={vital.RegenRate}, currentTick={currentTick}, totalTick={totalTick}, accumulated={vital.PartialRegen}");
        }
コード例 #9
0
        public int GetPKDamageResistRating()
        {
            var pkDamageResistRating = PKDamageResistRating ?? 0;

            // additive enchantments?
            var enchantments = EnchantmentManager.GetRating(PropertyInt.PKDamageResistRating);

            // equipment ratings
            var equipment = GetEquippedItemsRatingSum(PropertyInt.GearPKDamageResistRating);

            return(pkDamageResistRating + equipment + enchantments);
        }
コード例 #10
0
        public void AuditItemSpells()
        {
            // cleans up bugged chars with dangling item set spells
            // from previous bugs

            // get active item enchantments
            var enchantments = Biota.GetEnchantments(BiotaDatabaseLock).Where(i => i.Duration == -1 && i.SpellId != (int)SpellId.Vitae).ToList();

            foreach (var enchantment in enchantments)
            {
                // if this item is not equipped, remove enchantment
                if (!EquippedObjects.TryGetValue(new ObjectGuid(enchantment.CasterObjectId), out var item))
                {
                    var spell = new Spell(enchantment.SpellId, false);
                    log.Error($"{Name}.AuditItemSpells(): removing spell {spell.Name} from non-equipped item");

                    EnchantmentManager.Dispel(enchantment);
                    continue;
                }

                // is this item part of a set?
                if (!item.HasItemSet)
                {
                    continue;
                }

                // get all of the equipped items in this set
                var setItems = EquippedObjects.Values.Where(i => i.HasItemSet && i.EquipmentSetId == item.EquipmentSetId).ToList();

                // get all of the spells currently active from this set
                var currentSpells = GetSpellSet((EquipmentSet)item.EquipmentSetId, setItems);

                // get all of the spells possible for this item set
                var possibleSpells = GetSpellSetAll((EquipmentSet)item.EquipmentSetId);

                // get the difference between them
                var inactiveSpells = possibleSpells.Except(currentSpells).ToList();

                // remove any item set spells that shouldn't be active
                foreach (var inactiveSpell in inactiveSpells)
                {
                    var removeSpells = enchantments.Where(i => i.SpellSetId == (uint)item.EquipmentSetId && i.SpellId == inactiveSpell.Id).ToList();

                    foreach (var removeSpell in removeSpells)
                    {
                        log.Error($"{Name}.AuditItemSpells(): removing spell {inactiveSpell.Name} from {item.EquipmentSetId}");

                        EnchantmentManager.Dispel(removeSpell);
                    }
                }
            }
        }
コード例 #11
0
        public int GetNetherResistRating()
        {
            // there is a property defined for this,
            // but does anything use this?

            // get from base properties (monsters)?
            var netherResistRating = NetherResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.NetherResistRating);

            return(netherResistRating + enchantments);
        }
コード例 #12
0
ファイル: Creature_Rating.cs プロジェクト: tuita520/ACE
        public int GetCritResistRating()
        {
            // crit resist chance

            // get from base properties (monsters)?
            var critResistRating = CritResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.CritResistRating);

            // no augs / lum augs?
            return(critResistRating + enchantments);
        }
コード例 #13
0
        public int GetLifeResistRating()
        {
            // only affects health drain?
            // only cast by Sigil of Perserverance (Aetheria)?

            // get from base properties (monsters)?
            var lifeResistRating = LifeResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.LifeResistRating);

            return(lifeResistRating + enchantments);
        }
コード例 #14
0
ファイル: Creature_Rating.cs プロジェクト: tuita520/ACE
        public int GetLifeResistRating()
        {
            // drain resistance?

            // Drain Resistances - allows one to partially resist drain health/stamina/mana and harm attacks (not including other life transfer spells).

            // get from base properties (monsters)?
            var lifeResistRating = LifeResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.LifeResistRating);

            return(lifeResistRating + enchantments);
        }
コード例 #15
0
ファイル: Creature_Rating.cs プロジェクト: fartwhif/ACE
        public int GetCritResistRating()
        {
            // crit resist chance

            // get from base properties (monsters)?
            var critResistRating = CritResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.CritResistRating);

            // equipment ratings
            var equipment = GetEquippedItemsRatingSum(PropertyInt.GearCritResist);

            // no augs / lum augs?
            return(critResistRating + equipment + enchantments);
        }
コード例 #16
0
ファイル: Player_Xp.cs プロジェクト: dgatewood/ACE
        /// <summary>
        /// Handles updating the vitae penalty through earned XP
        /// </summary>
        /// <param name="amount">The amount of XP to apply to the vitae penalty</param>
        private void UpdateXpVitae(long amount)
        {
            var vitaePenalty = EnchantmentManager.GetVitae().StatModValue;
            var startPenalty = vitaePenalty;

            var maxPool = (int)VitaeCPPoolThreshold(vitaePenalty, DeathLevel.Value);
            var curPool = VitaeCpPool + amount;

            while (curPool >= maxPool)
            {
                curPool     -= maxPool;
                vitaePenalty = EnchantmentManager.ReduceVitae();
                if (vitaePenalty == 1.0f)
                {
                    break;
                }
                maxPool = (int)VitaeCPPoolThreshold(vitaePenalty, DeathLevel.Value);
            }
            VitaeCpPool = (int)curPool;

            Session.Network.EnqueueSend(new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.VitaeCpPool, VitaeCpPool.Value));

            if (vitaePenalty != startPenalty)
            {
                Session.Network.EnqueueSend(new GameMessageSystemChat("Your experience has reduced your Vitae penalty!", ChatMessageType.Magic));
                EnchantmentManager.SendUpdateVitae();
            }

            if (vitaePenalty.EpsilonEquals(1.0f) || vitaePenalty > 1.0f)
            {
                var actionChain = new ActionChain();
                actionChain.AddDelaySeconds(2.0f);
                actionChain.AddAction(this, () =>
                {
                    var vitae = EnchantmentManager.GetVitae();
                    if (vitae != null)
                    {
                        var curPenalty = vitae.StatModValue;
                        if (curPenalty.EpsilonEquals(1.0f) || curPenalty > 1.0f)
                        {
                            EnchantmentManager.RemoveVitae();
                        }
                    }
                });
                actionChain.EnqueueChain();
            }
        }
コード例 #17
0
        public int GetCritResistRating()
        {
            // crit resist chance

            // get from base properties (monsters)?
            var critResistRating = CritResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.CritResistRating);

            // equipment ratings
            // TODO: caching?
            var equipment = EquippedObjects.Values.Sum(i => i.GearCritResist ?? 0);

            // no augs / lum augs?
            return(critResistRating + equipment + enchantments);
        }
コード例 #18
0
        /// <summary>
        /// Returns the multiplier to XP and Luminance from Trinkets and Augmentations
        /// </summary>
        public float GetXPAndLuminanceModifier(XpType xpType)
        {
            var enchantmentBonus = EnchantmentManager.GetXPBonus();

            var augBonus = 0.0f;

            if (xpType == XpType.Kill && AugmentationBonusXp > 0)
            {
                augBonus = AugmentationBonusXp * 0.05f;
            }

            var modifier = 1.0f + enchantmentBonus + augBonus;

            //Console.WriteLine($"XPAndLuminanceModifier: {modifier}");

            return(modifier);
        }
コード例 #19
0
ファイル: Creature_Rating.cs プロジェクト: tuita520/ACE
        public int GetCritDamageResistRating()
        {
            // get from base properties (monsters)?
            var critDamageResistRating = CritDamageResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.CritDamageResistRating);

            var lumAugBonus = 0;

            if (this is Player player)
            {
                lumAugBonus = player.LumAugCritReductionRating;
            }

            return(critDamageResistRating + enchantments + lumAugBonus);
        }
コード例 #20
0
ファイル: Creature_Rating.cs プロジェクト: tuita520/ACE
        public int GetHealingBoostRating()
        {
            // get from base properties (monsters)?
            var healBoostRating = HealingBoostRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.HealingBoostRating);

            var lumAugBonus = 0;

            if (this is Player player)
            {
                lumAugBonus = player.LumAugHealingRating;
            }

            return(healBoostRating + enchantments + lumAugBonus);
        }
コード例 #21
0
ファイル: Player_Death.cs プロジェクト: Mad-Hatz/ACE
        /// <summary>
        /// Inflicts vitae
        /// </summary>
        public void InflictVitaePenalty(int amount = 5)
        {
            DeathLevel  = Level; // for calculating vitae XP
            VitaeCpPool = 0;     // reset vitae XP earned

            var msgDeathLevel  = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.DeathLevel, DeathLevel ?? 0);
            var msgVitaeCpPool = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.VitaeCpPool, VitaeCpPool.Value);

            Session.Network.EnqueueSend(msgDeathLevel, msgVitaeCpPool);

            var vitae = EnchantmentManager.UpdateVitae();

            var spellID          = (uint)SpellId.Vitae;
            var spell            = new Spell(spellID);
            var vitaeEnchantment = new Enchantment(this, Guid.Full, spellID, 0, (EnchantmentMask)spell.StatModType, vitae);

            Session.Network.EnqueueSend(new GameEventMagicUpdateEnchantment(Session, vitaeEnchantment));
        }
コード例 #22
0
ファイル: Player_Xp.cs プロジェクト: dgatewood/ACE
        /// <summary>
        /// A player earns XP through natural progression, ie. kills and quests completed
        /// </summary>
        /// <param name="amount">The amount of XP being added</param>
        /// <param name="xpType">The source of XP being added</param>
        /// <param name="shareable">True if this XP can be shared with Fellowship</param>
        public void EarnXP(long amount, XpType xpType, ShareType shareType = ShareType.All)
        {
            //Console.WriteLine($"{Name}.EarnXP({amount}, {sharable}, {fixedAmount})");

            // apply xp modifier
            var modifier    = PropertyManager.GetDouble("xp_modifier").Item;
            var enchantment = EnchantmentManager.GetXPMod();

            var m_amount = (long)Math.Round(amount * enchantment * modifier);

            if (m_amount < 0)
            {
                log.Warn($"{Name}.EarnXP({amount}, {shareType})");
                log.Warn($"modifier: {modifier}, enchantment: {enchantment}, m_amount: {m_amount}");
                return;
            }

            GrantXP(m_amount, xpType, shareType);
        }
コード例 #23
0
        public int GetArmorVsType(DamageType damageType, int armorVsType)
        {
            // TODO: refactor this class
            var preScaled = (float)BaseArmorMod / Biota.BaseArmor;

            //var resistance = (float)armorVsType / Biota.BaseArmor;
            var resistance = (float)armorVsType / Biota.BaseArmor * preScaled;

            if (double.IsNaN(resistance))
            {
                resistance = 1.0f;
            }

            float mod;
            var   spellVuln = IgnoreMagicResist ? 1.0f : EnchantmentManager.GetVulnerabilityResistanceMod(damageType);
            var   spellProt = IgnoreMagicResist ? 1.0f : EnchantmentManager.GetProtectionResistanceMod(damageType);

            if (WeaponResistanceMod > spellVuln)
            {
                mod = WeaponResistanceMod * spellProt;
            }
            else
            {
                mod = spellVuln * spellProt;
            }

            var baseArmorMod = BaseArmorMod;

            var resistanceMod = resistance / mod;

            if (baseArmorMod < 0)
            {
                resistanceMod = 1.0f + (1.0f - resistanceMod);
            }

            /*Console.WriteLine("BaseArmor: " + Biota.BaseArmor);
             * Console.WriteLine("BaseArmorMod: " + baseArmorMod);
             * Console.WriteLine("Resistance: " + resistance);
             * Console.WriteLine("ResistanceMod: " + resistanceMod);*/

            return((int)Math.Round(baseArmorMod * resistanceMod));
        }
コード例 #24
0
ファイル: Player_Spells.cs プロジェクト: hooper82/ACE
        public void EquipDequipItemFromSet(WorldObject item, List <Spell> spells, List <Spell> prevSpells)
        {
            // compare these 2 spell sets -
            // see which spells are being added, and which are being removed
            var addSpells    = spells.Except(prevSpells);
            var removeSpells = prevSpells.Except(spells);

            // set spells are not affected by mana
            // if it's equipped, it's active.

            foreach (var spell in removeSpells)
            {
                EnchantmentManager.Dispel(EnchantmentManager.GetEnchantment(spell.Id, item.EquipmentSetId.Value));
            }

            foreach (var spell in addSpells)
            {
                CreateItemSpell(item, spell.Id);
            }
        }
コード例 #25
0
ファイル: WorldObject_Tick.cs プロジェクト: drissical/ACE
        /// <summary>
        /// Called every ~5 seconds for WorldObject base
        /// </summary>
        public virtual void Heartbeat(double currentUnixTime)
        {
            if (EnchantmentManager.HasEnchantments)
            {
                EnchantmentManager.HeartBeat(CachedHeartbeatInterval);
            }

            if (RemainingLifespan != null)
            {
                RemainingLifespan -= (int)CachedHeartbeatInterval;

                if (RemainingLifespan <= 0)
                {
                    DeleteObject();
                }
            }

            SetProperty(PropertyFloat.HeartbeatTimestamp, currentUnixTime);
            NextHeartbeatTime = currentUnixTime + CachedHeartbeatInterval;
        }
コード例 #26
0
ファイル: Creature_Rating.cs プロジェクト: tuita520/ACE
        public int GetCritDamageRating()
        {
            // get from base properties (monsters)?
            var critDamageRating = CritDamageRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.CritDamageRating);

            // augmentations
            var augBonus    = 0;
            var lumAugBonus = 0;

            if (this is Player player)
            {
                augBonus    = player.AugmentationCriticalPower * 3;
                lumAugBonus = player.LumAugCritDamageRating;
            }

            return(critDamageRating + enchantments + augBonus + lumAugBonus);
        }
コード例 #27
0
ファイル: Creature_Rating.cs プロジェクト: tuita520/ACE
        public int GetCritRating()
        {
            // crit chance

            // get from base properties (monsters)?
            var critChanceRating = CritRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.CritRating);

            // augmentations
            var augBonus = 0;

            if (this is Player player)
            {
                augBonus = player.AugmentationCriticalExpertise;
            }

            return(critChanceRating + enchantments + augBonus);
        }
コード例 #28
0
        public int GetCritDamageResistRating()
        {
            // get from base properties (monsters)?
            var critDamageResistRating = CritDamageResistRating ?? 0;

            // additive enchantments
            var enchantments = EnchantmentManager.GetRating(PropertyInt.CritDamageResistRating);

            // equipment ratings
            // TODO: caching?
            var equipment = EquippedObjects.Values.Sum(i => i.GearCritDamageResist ?? 0);

            var lumAugBonus = 0;

            if (this is Player player)
            {
                lumAugBonus = player.LumAugCritReductionRating;
            }

            return(critDamageResistRating + equipment + enchantments + lumAugBonus);
        }
コード例 #29
0
        public float GetEffectiveArmorVsType(DamageType damageType, List <WorldObject> armorLayers, WorldObject damageSource, float armorRendingMod = 1.0f)
        {
            var ignoreMagicArmor  = damageSource != null ? damageSource.IgnoreMagicArmor : false;
            var ignoreMagicResist = damageSource != null ? damageSource.IgnoreMagicResist : false;

            // get base AL / RL
            var enchantmentMod = ignoreMagicResist ? 0 : EnchantmentManager.GetBodyArmorMod();

            var baseArmorMod = (float)(Biota.BaseArmor + enchantmentMod);

            // handle armor rending mod here?
            //if (baseArmorMod > 0)
            //baseArmorMod *= armorRendingMod;

            // for creatures, can this be modified via enchantments?
            var armorVsType = Creature.GetArmorVsType(damageType);

            // handle negative baseArmorMod?
            if (baseArmorMod < 0)
            {
                armorVsType = 1.0f + (1.0f - armorVsType);
            }

            var effectiveAL = (float)(baseArmorMod * armorVsType);

            // handle monsters w/ multiple layers of armor
            foreach (var armorLayer in armorLayers)
            {
                effectiveAL += GetArmorMod(armorLayer, damageSource, damageType);
            }

            // Armor Rending reduces physical armor too?
            if (effectiveAL > 0)
            {
                effectiveAL *= armorRendingMod;
            }

            return(effectiveAL);
        }
コード例 #30
0
        /// <summary>
        /// Player Death/Kill, use this to kill a session's player
        /// </summary>
        /// <remarks>
        ///     TODO:
        ///         1. Find the best vitae formula and add vitae
        ///         2. Generate the correct death message, or have it passed in as a parameter.
        ///         3. Find the correct player death noise based on the player model and play on death.
        ///         4. Determine if we need to Send Queued Action for Lifestone Materialize, after Action Location.
        ///         5. Find the health after death formula and Set the correct health
        /// </remarks>
        private void OnKill(Session killerSession)
        {
            ObjectGuid killerId = killerSession.Player.Guid;

            IsAlive        = false;
            Health.Current = 0;  // Set the health to zero
            NumDeaths++;         // Increase the NumDeaths counter
            DeathLevel  = Level; // For calculating vitae XP
            VitaeCpPool = 0;     // Set vitae XP

            // TODO: Generate a death message based on the damage type to pass in to each death message:
            string currentDeathMessage = $"died to {killerSession.Player.Name}.";

            // Send Vicitim Notification, or "Your Death" event to the client:
            // create and send the client death event, GameEventYourDeath
            var msgYourDeath         = new GameEventYourDeath(Session, $"You have {currentDeathMessage}");
            var msgNumDeaths         = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.NumDeaths, NumDeaths ?? 0);
            var msgDeathLevel        = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.DeathLevel, DeathLevel ?? 0);
            var msgVitaeCpPool       = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.VitaeCpPool, VitaeCpPool.Value);
            var msgPurgeEnchantments = new GameEventPurgeAllEnchantments(Session);
            // var msgDeathSound = new GameMessageSound(Guid, Sound.Death1, 1.0f);

            // handle vitae
            var vitae = EnchantmentManager.UpdateVitae();

            var spellID             = (uint)Network.Enum.Spell.Vitae;
            var spellBase           = DatManager.PortalDat.SpellTable.Spells[spellID];
            var spell               = DatabaseManager.World.GetCachedSpell(spellID);
            var vitaeEnchantment    = new Enchantment(this, spellID, (double)spell.Duration, 0, spell.StatModType, vitae);
            var msgVitaeEnchantment = new GameEventMagicUpdateEnchantment(Session, vitaeEnchantment);

            var msgHealthUpdate = new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Health, 0);

            // Send first death message group
            Session.Network.EnqueueSend(msgHealthUpdate, msgYourDeath, msgNumDeaths, msgDeathLevel, msgVitaeCpPool, msgPurgeEnchantments, msgVitaeEnchantment);

            // Broadcast the 019E: Player Killed GameMessage
            ActionBroadcastKill($"{Name} has {currentDeathMessage}", Guid, killerId);
        }