Example #1
0
        /// <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);

            var augMod = 1.0f;

            if (this is Player player && player.AugmentationFasterRegen > 0)
            {
                augMod += player.AugmentationFasterRegen;
            }

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

            // 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}");
        }
Example #2
0
        /// <summary>
        /// Applies some amount of damage to this monster from source
        /// </summary>
        /// <param name="source">The attacker / source of damage</param>
        /// <param name="amount">The amount of damage rounded</param>
        public virtual uint TakeDamage(WorldObject source, DamageType damageType, float amount, bool crit = false)
        {
            var tryDamage = (int)Math.Round(amount);
            var damage    = -UpdateVitalDelta(Health, -tryDamage);

            // TODO: update monster stamina?

            // source should only be null for combined DoT ticks from multiple sources
            if (source != null)
            {
                if (damage >= 0)
                {
                    DamageHistory.Add(source, damageType, (uint)damage);
                }
                else
                {
                    DamageHistory.OnHeal((uint)-damage);
                }
            }

            if (Health.Current <= 0)
            {
                OnDeath(DamageHistory.LastDamager, damageType, crit);

                Die();
            }
            return((uint)Math.Max(0, damage));
        }
Example #3
0
        public virtual void SetMaxVitals()
        {
            var missingHealth = Health.Missing;

            Health.Current  = Health.MaxValue;
            Stamina.Current = Stamina.MaxValue;
            Mana.Current    = Mana.MaxValue;

            DamageHistory.OnHeal(missingHealth);
        }
Example #4
0
        /// <summary>
        /// Updates a particular vital according to regeneration rate
        /// </summary>
        /// <param name="vital">The vital stat to update (health/stamina/mana)</param>
        public void VitalTick(CreatureVital vital)
        {
            if (vital.Current == vital.MaxValue)
            {
                return;
            }

            if (vital.Current > vital.MaxValue)
            {
                UpdateVital(vital, vital.MaxValue);
                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}");
        }
Example #5
0
        /// <summary>
        /// Method used to perform the animation, sound, and vital update on consumption of food or potions
        /// </summary>
        /// <param name="consumableName">Name of the consumable</param>
        /// <param name="sound">Either Sound.Eat1 or Sound.Drink1</param>
        /// <param name="buffType">ConsumableBuffType.Spell,ConsumableBuffType.Health,ConsumableBuffType.Stamina,ConsumableBuffType.Mana</param>
        /// <param name="boostAmount">Amount the Vital is boosted by; can be null, if buffType = ConsumableBuffType.Spell</param>
        /// <param name="spellDID">Id of the spell cast by the consumable; can be null, if buffType != ConsumableBuffType.Spell</param>
        public void ApplyConsumable(string consumableName, Sound sound, ConsumableBuffType buffType, uint?boostAmount, uint?spellDID)
        {
            MotionCommand motionCommand;

            if (sound == Sound.Eat1)
            {
                motionCommand = MotionCommand.Eat;
            }
            else
            {
                motionCommand = MotionCommand.Drink;
            }

            // start the eat/drink motion
            var motion = new Motion(MotionStance.NonCombat, motionCommand);

            EnqueueBroadcastMotion(motion);

            var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId);
            var animTime    = motionTable.GetAnimationLength(CurrentMotionState.Stance, motionCommand, MotionCommand.Ready);

            var actionChain = new ActionChain();

            actionChain.AddDelaySeconds(animTime);

            actionChain.AddAction(this, () =>
            {
                GameMessageSystemChat buffMessage;

                if (buffType == ConsumableBuffType.Spell)
                {
                    bool result = false;

                    uint spellId = spellDID ?? 0;

                    if (spellId != 0)
                    {
                        result = CreateSingleSpell(spellId);
                    }

                    if (result)
                    {
                        var spell   = new Server.Entity.Spell(spellId);
                        buffMessage = new GameMessageSystemChat($"{consumableName} casts {spell.Name} on you.", ChatMessageType.Magic);
                    }
                    else
                    {
                        buffMessage = new GameMessageSystemChat($"Consuming {consumableName} attempted to apply a spell not yet fully implemented.", ChatMessageType.System);
                    }
                }
                else
                {
                    CreatureVital creatureVital;
                    string vitalName;

                    // Null check for safety
                    if (boostAmount == null)
                    {
                        boostAmount = 0;
                    }

                    switch (buffType)
                    {
                    case ConsumableBuffType.Health:
                        creatureVital = Health;
                        vitalName     = "Health";
                        break;

                    case ConsumableBuffType.Mana:
                        creatureVital = Mana;
                        vitalName     = "Mana";
                        break;

                    default:
                        creatureVital = Stamina;
                        vitalName     = "Stamina";
                        break;
                    }

                    var vitalChange = UpdateVitalDelta(creatureVital, (uint)boostAmount);
                    if (vitalName == "Health")
                    {
                        DamageHistory.OnHeal((uint)vitalChange);
                        if (Fellowship != null)
                        {
                            Fellowship.OnVitalUpdate(this);
                        }
                    }

                    buffMessage = new GameMessageSystemChat($"You regain {vitalChange} {vitalName}.", ChatMessageType.Craft);
                }

                var soundEvent = new GameMessageSound(Guid, sound, 1.0f);
                EnqueueBroadcast(soundEvent);

                Session.Network.EnqueueSend(buffMessage);

                // return to original stance
                var returnStance = new Motion(CurrentMotionState.Stance);
                EnqueueBroadcastMotion(returnStance);
            });

            actionChain.EnqueueChain();
        }