Example #1
0
        public static void ScaleDamageRanged(ACE.Server.WorldObjects.Creature c, ACE.Server.Entity.BaseDamageMod d)
        {
            if (!c.IsMonster)
            {
                return;
            }

            d.BaseDamage.MaxDamage = (int)((float)d.BaseDamage.MaxDamage * S_MONSTERMISSILEDMGINCREASE);
        }
Example #2
0
        public static void ScaleDamageMelee(ACE.Server.WorldObjects.Creature c, ACE.Server.Entity.DamageEvent d)
        {
            if (!c.IsMonster)
            {
                return;
            }

            if (d.HasDamage)
            {
                d.Damage *= S_MONSTERMELEEDMGINCREASE;
            }
        }
Example #3
0
        public static void Scale(ACE.Server.WorldObjects.Creature c)
        {
            if (!c.IsMonster)
            {
                return;
            }

            c.Health.Ranks  += (uint)((float)c.Health.MaxValue * S_MONSTERHPINCREASE);
            c.Health.Current = c.Health.MaxValue;
            //c.Stamina.MaxValue = (int)((float)c.Stamina.MaxValue * 1.2f);
            //c.Stamina.Current = c.Stamina.MaxValue;
            //c.Mana.MaxValue = (int)((float)c.Mana.MaxValue * 1.2f);
            //c.Mana.Current = c.Mana.MaxValue;
        }
Example #4
0
        /// <summary>
        /// Called for a spell projectile to damage its target
        /// </summary>
        public void DamageTarget(WorldObject _target, double?damage, bool critical, bool critDefended, bool overpower)
        {
            var player = ProjectileSource as Player;

            var target       = _target as Creature;
            var targetPlayer = _target as Player;

            if (targetPlayer != null && (targetPlayer.Invincible || targetPlayer.IsDead))
            {
                return;
            }

            uint amount;
            var  percent        = 0.0f;
            var  heritageMod    = 1.0f;
            var  sneakAttackMod = 1.0f;

            // handle life projectiles for stamina / mana
            if (Spell.Category == SpellCategory.StaminaLowering)
            {
                percent = (float)damage / target.Stamina.MaxValue;
                amount  = (uint)-target.UpdateVitalDelta(target.Stamina, (int)-Math.Round(damage.Value));
            }
            else if (Spell.Category == SpellCategory.ManaLowering)
            {
                percent = (float)damage / target.Mana.MaxValue;
                amount  = (uint)-target.UpdateVitalDelta(target.Mana, (int)-Math.Round(damage.Value));
            }
            else
            {
                // for possibly applying sneak attack to magic projectiles,
                // only do this for health-damaging projectiles?
                if (player != null)
                {
                    // TODO: use target direction vs. projectile position, instead of player position
                    // could sneak attack be applied to void DoTs?
                    sneakAttackMod = player.GetSneakAttackMod(target);
                    //Console.WriteLine("Magic sneak attack:  + sneakAttackMod);
                    heritageMod = player.GetHeritageBonus(player.GetEquippedWand()) ? 1.05f : 1.0f;
                }

                // DR / DRR applies for magic too?
                var creatureSource = ProjectileSource as Creature;
                var damageRating   = creatureSource != null?creatureSource.GetDamageRating() : 0;

                var damageRatingMod       = Creature.AdditiveCombine(Creature.GetPositiveRatingMod(damageRating), heritageMod, sneakAttackMod);
                var damageResistRatingMod = Creature.GetNegativeRatingMod(target.GetDamageResistRating(CombatType.Magic));
                damage *= damageRatingMod * damageResistRatingMod;

                //Console.WriteLine($"Damage rating: " + Creature.ModToRating(damageRatingMod));

                percent = (float)damage / target.Health.MaxValue;
                amount  = (uint)-target.UpdateVitalDelta(target.Health, (int)-Math.Round(damage.Value));
                target.DamageHistory.Add(ProjectileSource, Spell.DamageType, amount);

                //if (targetPlayer != null && targetPlayer.Fellowship != null)
                //targetPlayer.Fellowship.OnVitalUpdate(targetPlayer);
            }

            amount = (uint)Math.Round(damage.Value);    // full amount for debugging

            if (target.IsAlive)
            {
                string verb = null, plural = null;
                Strings.GetAttackVerb(Spell.DamageType, percent, ref verb, ref plural);
                var type = Spell.DamageType.GetName().ToLower();

                var critMsg      = critical ? "Critical hit! " : "";
                var sneakMsg     = sneakAttackMod > 1.0f ? "Sneak Attack! " : "";
                var overpowerMsg = overpower ? "Overpower! " : "";

                var nonHealth = Spell.Category == SpellCategory.StaminaLowering || Spell.Category == SpellCategory.ManaLowering;

                if (player != null)
                {
                    var critProt = critDefended ? " Your target's Critical Protection augmentation allows them to avoid your critical hit!" : "";

                    var attackerMsg = $"{critMsg}{overpowerMsg}{sneakMsg}You {verb} {target.Name} for {amount} points with {Spell.Name}.{critProt}";

                    // could these crit / sneak attack?
                    if (nonHealth)
                    {
                        var vital = Spell.Category == SpellCategory.StaminaLowering ? "stamina" : "mana";
                        attackerMsg = $"With {Spell.Name} you drain {amount} points of {vital} from {target.Name}.";
                    }

                    if (!player.SquelchManager.Squelches.Contains(target, ChatMessageType.Magic))
                    {
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat(attackerMsg, ChatMessageType.Magic));
                    }

                    player.Session.Network.EnqueueSend(new GameEventUpdateHealth(player.Session, target.Guid.Full, (float)target.Health.Current / target.Health.MaxValue));
                }

                if (targetPlayer != null)
                {
                    var critProt = critDefended ? " Your Critical Protection augmentation allows you to avoid a critical hit!" : "";

                    var defenderMsg = $"{critMsg}{overpowerMsg}{sneakMsg}{ProjectileSource.Name} {plural} you for {amount} points with {Spell.Name}.{critProt}";

                    if (nonHealth)
                    {
                        var vital = Spell.Category == SpellCategory.StaminaLowering ? "stamina" : "mana";
                        defenderMsg = $"{ProjectileSource.Name} casts {Spell.Name} and drains {amount} points of your {vital}.";
                    }

                    if (!targetPlayer.SquelchManager.Squelches.Contains(ProjectileSource, ChatMessageType.Magic))
                    {
                        targetPlayer.Session.Network.EnqueueSend(new GameMessageSystemChat(defenderMsg, ChatMessageType.Magic));
                    }
                }

                if (!nonHealth)
                {
                    if (target.HasCloakEquipped)
                    {
                        Cloak.TryProcSpell(target, ProjectileSource, percent);
                    }

                    target.EmoteManager.OnDamage(player);

                    if (critical)
                    {
                        target.EmoteManager.OnReceiveCritical(player);
                    }
                }
            }
            else
            {
                var lastDamager = ProjectileSource != null ? new DamageHistoryInfo(ProjectileSource) : null;
                target.OnDeath(lastDamager, Spell.DamageType, critical);
                target.Die();
            }
        }
Example #5
0
        /// <summary>
        /// Calculates the damage for a spell projectile
        /// Used by war magic, void magic, and life magic projectiles
        /// </summary>
        public double?CalculateDamage(WorldObject source, WorldObject caster, Creature target, ref bool criticalHit, ref bool critDefended, ref bool overpower)
        {
            var sourcePlayer = source as Player;
            var targetPlayer = target as Player;

            if (source == null || targetPlayer != null && targetPlayer.Invincible == true)
            {
                return(null);
            }

            // target already dead?
            if (target.Health.Current <= 0)
            {
                return(-1);
            }

            // check lifestone protection
            if (targetPlayer != null && targetPlayer.UnderLifestoneProtection)
            {
                if (sourcePlayer != null)
                {
                    sourcePlayer.Session.Network.EnqueueSend(new GameMessageSystemChat($"The Lifestone's magic protects {targetPlayer.Name} from the attack!", ChatMessageType.Magic));
                }

                targetPlayer.HandleLifestoneProtection();
                return(null);
            }

            double damageBonus = 0.0f, warSkillBonus = 0.0f, finalDamage = 0.0f;

            var resistanceType = Creature.GetResistanceType(Spell.DamageType);

            var sourceCreature = source as Creature;

            if (sourceCreature?.Overpower != null)
            {
                overpower = Creature.GetOverpower(sourceCreature, target);
            }

            var resisted = source.TryResistSpell(target, Spell, caster, true);

            if (resisted && !overpower)
            {
                return(null);
            }

            CreatureSkill attackSkill = null;

            if (sourceCreature != null)
            {
                attackSkill = sourceCreature.GetCreatureSkill(Spell.School);
            }

            // critical hit
            var critical = GetWeaponMagicCritFrequency(sourceCreature, attackSkill, target);

            if (ThreadSafeRandom.Next(0.0f, 1.0f) < critical)
            {
                if (targetPlayer != null && targetPlayer.AugmentationCriticalDefense > 0)
                {
                    var criticalDefenseMod    = sourcePlayer != null ? 0.05f : 0.25f;
                    var criticalDefenseChance = targetPlayer.AugmentationCriticalDefense * criticalDefenseMod;

                    if (criticalDefenseChance > ThreadSafeRandom.Next(0.0f, 1.0f))
                    {
                        critDefended = true;
                    }
                }

                if (!critDefended)
                {
                    criticalHit = true;
                }
            }

            var absorbMod = GetAbsorbMod(target);

            bool isPVP = sourcePlayer != null && targetPlayer != null;

            if (isPVP && Spell.IsHarmful)
            {
                Player.UpdatePKTimers(sourcePlayer, targetPlayer);
            }

            var elementalDmgBonus = GetCasterElementalDamageModifier(sourceCreature, target, Spell.DamageType);

            // Possible 2x + damage bonus for the slayer property
            var slayerBonus = GetWeaponCreatureSlayerModifier(sourceCreature, target);

            // life magic projectiles: ie., martyr's hecatomb
            if (Spell.School == MagicSchool.LifeMagic)
            {
                var lifeMagicDamage = LifeProjectileDamage * Spell.DamageRatio;

                // could life magic projectiles crit?
                // if so, did they use the same 1.5x formula as war magic, instead of 2.0x?
                if (criticalHit)
                {
                    damageBonus = lifeMagicDamage * 0.5f * GetWeaponCritDamageMod(sourceCreature, attackSkill, target);
                }

                finalDamage = (lifeMagicDamage + damageBonus) * elementalDmgBonus * slayerBonus * absorbMod;
                return(finalDamage);
            }
            // war/void magic projectiles
            else
            {
                if (criticalHit)
                {
                    // Original:
                    // http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players

                    // Critical Strikes: In addition to the skill-based damage bonus, each projectile spell has a 2% chance of causing a critical hit on the target and doing increased damage.
                    // A magical critical hit is similar in some respects to melee critical hits (although the damage calculation is handled differently).
                    // While a melee critical hit automatically does twice the maximum damage of the weapon, a magical critical hit will do an additional half the minimum damage of the spell.
                    // For instance, a magical critical hit from a level 7 spell, which does 110-180 points of damage, would add an additional 55 points of damage to the spell.

                    // Later updated for PvE only:

                    // http://acpedia.org/wiki/Announcements_-_2004/07_-_Treaties_in_Stone#Letter_to_the_Players

                    // Currently when a War Magic spell scores a critical hit, it adds a multiple of the base damage of the spell to a normal damage roll.
                    // Starting in July, War Magic critical hits will instead add a multiple of the maximum damage of the spell.
                    // No more crits that do less damage than non-crits!

                    if (isPVP) // PvP: 50% of the MIN damage added to normal damage roll
                    {
                        damageBonus = Spell.MinDamage * 0.5f;
                    }
                    else   // PvE: 50% of the MAX damage added to normal damage roll
                    {
                        damageBonus = Spell.MaxDamage * 0.5f;
                    }

                    var critDamageMod = GetWeaponCritDamageMod(sourceCreature, attackSkill, target);

                    damageBonus *= critDamageMod;
                }

                /* War Magic skill-based damage bonus
                 * http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players
                 */
                if (sourcePlayer != null)
                {
                    // per retail stats, level 8 difficulty is capped to 350 instead of 400
                    // without this, level 7s have the potential to deal more damage than level 8s
                    var difficulty = Math.Min(Spell.Power, 350);
                    var magicSkill = sourcePlayer.GetCreatureSkill(Spell.School).Current;

                    if (magicSkill > difficulty)
                    {
                        // Bonus clamped to a maximum of 50%
                        //var percentageBonus = Math.Clamp((magicSkill - Spell.Power) / 100.0f, 0.0f, 0.5f);
                        var percentageBonus = (magicSkill - difficulty) / 1000.0f;

                        warSkillBonus = Spell.MinDamage * percentageBonus;
                    }
                }
                var baseDamage = ThreadSafeRandom.Next(Spell.MinDamage, Spell.MaxDamage);

                var weaponResistanceMod = GetWeaponResistanceModifier(sourceCreature, attackSkill, Spell.DamageType);

                // if attacker/weapon has IgnoreMagicResist directly, do not transfer to spell projectile
                // only pass if SpellProjectile has it directly, such as 2637 - Invoking Aun Tanua

                var resistanceMod = Math.Max(0.0f, target.GetResistanceMod(resistanceType, this, null, weaponResistanceMod));

                finalDamage = baseDamage + damageBonus + warSkillBonus;

                finalDamage *= resistanceMod * elementalDmgBonus * slayerBonus * absorbMod;

                return(finalDamage);
            }
        }
Example #6
0
        /// <summary>
        /// Main entry point for getting the armor mod
        /// </summary>
        public float GetArmorMod(DamageType damageType, List <WorldObject> armorLayers, Creature attacker, WorldObject weapon, float armorRendingMod = 1.0f)
        {
            var effectiveArmorVsType = GetEffectiveArmorVsType(damageType, armorLayers, attacker, weapon, armorRendingMod);

            return(SkillFormula.CalcArmorMod(effectiveArmorVsType));
        }
Example #7
0
        public float GetEffectiveArmorVsType(DamageType damageType, List <WorldObject> armorLayers, Creature attacker, WorldObject weapon, float armorRendingMod = 1.0f)
        {
            var ignoreMagicArmor  = (weapon?.IgnoreMagicArmor ?? false) || (attacker?.IgnoreMagicArmor ?? false);
            var ignoreMagicResist = (weapon?.IgnoreMagicResist ?? false) || (attacker?.IgnoreMagicResist ?? false);

            // get base AL / RL
            var armorVsType = Biota.Value.BaseArmor * (float)Creature.GetArmorVsType(damageType);

            // additive enchantments:
            // imperil / armor
            var enchantmentMod = ignoreMagicResist ? 0 : EnchantmentManager.GetBodyArmorMod();

            var effectiveAL = armorVsType + enchantmentMod;

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

            // armor rending reduces base armor + all physical armor too?
            if (effectiveAL > 0)
            {
                effectiveAL *= armorRendingMod;
            }

            return(effectiveAL);
        }
Example #8
0
 /// <summary>
 /// Called when a player or creature starts an attack
 /// </summary>
 public void OnAttack(Creature target)
 {
     // self-procs happen on attack, regardless if the attack is successfully landed
     TryProcEquippedItems(this, true);
 }
Example #9
0
 public Creature_BodyPart(Creature creature, KeyValuePair <CombatBodyPart, PropertiesBodyPart> biota)
 {
     Creature = creature;
     Biota    = biota;
 }
Example #10
0
        public DamageEvent DamageTarget(Creature target, WorldObject damageSource)
        {
            if (target.Health.Current <= 0)
            {
                return(null);
            }

            // check PK status
            var targetPlayer = target as Player;

            if (targetPlayer != null)
            {
                var pkError = CheckPKStatusVsTarget(this, targetPlayer, null);
                if (pkError != null)
                {
                    Session.Network.EnqueueSend(new GameEventWeenieErrorWithString(Session, pkError[0], target.Name));
                    targetPlayer.Session.Network.EnqueueSend(new GameEventWeenieErrorWithString(targetPlayer.Session, pkError[1], Name));
                    return(null);
                }
            }

            /*float? damage = null;
             * if (targetPlayer != null)
             * {
             *  damage = CalculateDamagePVP(target, damageSource, damageType, ref critical, ref sneakAttack, ref bodyPart);
             *
             *  // TODO: level up shield mod?
             *  if (targetPlayer.Invincible ?? false)
             *      damage = 0.0f;
             * }
             * else
             *  damage = CalculateDamage(target, damageSource, ref critical, ref sneakAttack);*/

            var damageEvent = DamageEvent.CalculateDamage(this, target, damageSource);

            if (damageEvent.HasDamage)
            {
                OnDamageTarget(target, damageEvent.CombatType, damageEvent.IsCritical);

                if (targetPlayer != null)
                {
                    targetPlayer.TakeDamage(this, damageEvent.DamageType, damageEvent.Damage, damageEvent.BodyPart, damageEvent.IsCritical);
                }
                else
                {
                    target.TakeDamage(this, damageEvent.DamageType, damageEvent.Damage, damageEvent.IsCritical);
                }
            }
            else
            {
                if (targetPlayer != null && targetPlayer.UnderLifestoneProtection)
                {
                    Session.Network.EnqueueSend(new GameMessageSystemChat($"The Lifestone's magic protects {target.Name} from the attack!", ChatMessageType.Magic));
                }
                else
                {
                    Session.Network.EnqueueSend(new GameMessageSystemChat($"{target.Name} evaded your attack.", ChatMessageType.CombatSelf));
                }
            }

            if (damageEvent.HasDamage && target.IsAlive)
            {
                var attackConditions = new AttackConditions();
                if (damageEvent.RecklessnessMod > 1.0f)
                {
                    attackConditions |= AttackConditions.Recklessness;
                }
                if (damageEvent.SneakAttackMod > 1.0f)
                {
                    attackConditions |= AttackConditions.SneakAttack;
                }

                // notify attacker
                var intDamage = (uint)Math.Round(damageEvent.Damage);

                Session.Network.EnqueueSend(new GameEventAttackerNotification(Session, target.Name, damageEvent.DamageType, (float)intDamage / target.Health.MaxValue, intDamage, damageEvent.IsCritical, attackConditions));

                // splatter effects
                if (targetPlayer == null)
                {
                    Session.Network.EnqueueSend(new GameMessageSound(target.Guid, Sound.HitFlesh1, 0.5f));
                    if (damageEvent.Damage >= target.Health.MaxValue * 0.25f)
                    {
                        var painSound = (Sound)Enum.Parse(typeof(Sound), "Wound" + ThreadSafeRandom.Next(1, 3), true);
                        Session.Network.EnqueueSend(new GameMessageSound(target.Guid, painSound, 1.0f));
                    }
                    var splatter = (PlayScript)Enum.Parse(typeof(PlayScript), "Splatter" + GetSplatterHeight() + GetSplatterDir(target));
                    Session.Network.EnqueueSend(new GameMessageScript(target.Guid, splatter));
                }

                // handle Dirty Fighting
                if (GetCreatureSkill(Skill.DirtyFighting).AdvancementClass >= SkillAdvancementClass.Trained)
                {
                    FightDirty(target);
                }
            }

            if (damageEvent.Damage > 0.0f)
            {
                Session.Network.EnqueueSend(new GameEventUpdateHealth(Session, target.Guid.Full, (float)target.Health.Current / target.Health.MaxValue));
            }

            if (targetPlayer == null)
            {
                OnAttackMonster(target);
            }

            return(damageEvent);
        }
Example #11
0
 protected static void WriteIdentifyObjectCreatureProfile(BinaryWriter writer, Creature creature, bool success)
 {
     var creatureProfile = new CreatureProfile(creature, success);
     writer.Write(creatureProfile);
 }
Example #12
0
        /// <summary>
        /// Calculates the damage for a spell projectile
        /// Used by war magic, void magic, and life magic projectiles
        /// </summary>
        public double?CalculateDamage(WorldObject source, Creature target, ref bool criticalHit, ref bool critDefended)
        {
            var sourcePlayer = source as Player;
            var targetPlayer = target as Player;

            if (source == null || targetPlayer != null && targetPlayer.Invincible == true)
            {
                return(null);
            }

            // target already dead?
            if (target.Health.Current <= 0)
            {
                return(-1);
            }

            // check lifestone protection
            if (targetPlayer != null && targetPlayer.UnderLifestoneProtection)
            {
                if (sourcePlayer != null)
                {
                    sourcePlayer.Session.Network.EnqueueSend(new GameMessageSystemChat($"The Lifestone's magic protects {targetPlayer.Name} from the attack!", ChatMessageType.Magic));
                }

                targetPlayer.HandleLifestoneProtection();
                return(null);
            }

            double damageBonus = 0.0f, warSkillBonus = 0.0f, finalDamage = 0.0f;

            var resistanceType = Creature.GetResistanceType(Spell.DamageType);

            var resisted = source.ResistSpell(target, Spell);

            if (resisted != null && resisted == true)
            {
                return(null);
            }

            CreatureSkill attackSkill    = null;
            var           sourceCreature = source as Creature;

            if (sourceCreature != null)
            {
                attackSkill = sourceCreature.GetCreatureSkill(Spell.School);
            }

            // critical hit
            var critical = GetWeaponMagicCritFrequencyModifier(sourceCreature, attackSkill, target);

            if (ThreadSafeRandom.Next(0.0f, 1.0f) < critical)
            {
                if (targetPlayer != null && targetPlayer.AugmentationCriticalDefense > 0)
                {
                    var criticalDefenseMod    = sourcePlayer != null ? 0.05f : 0.25f;
                    var criticalDefenseChance = targetPlayer.AugmentationCriticalDefense * criticalDefenseMod;

                    if (criticalDefenseChance > ThreadSafeRandom.Next(0.0f, 1.0f))
                    {
                        critDefended = true;
                    }
                }

                if (!critDefended)
                {
                    criticalHit = true;
                }
            }

            var shieldMod = GetShieldMod(target);

            bool isPVP = sourcePlayer != null && targetPlayer != null;

            if (isPVP && Spell.IsHarmful)
            {
                Player.UpdatePKTimers(sourcePlayer, targetPlayer);
            }

            var elementalDmgBonus = GetCasterElementalDamageModifier(sourceCreature, target, Spell.DamageType);

            // Possible 2x + damage bonus for the slayer property
            var slayerBonus = GetWeaponCreatureSlayerModifier(sourceCreature, target);

            // life magic projectiles: ie., martyr's hecatomb
            if (Spell.School == MagicSchool.LifeMagic)
            {
                var lifeMagicDamage = LifeProjectileDamage * Spell.DamageRatio;

                // could life magic projectiles crit?
                // if so, did they use the same 1.5x formula as war magic, instead of 2.0x?
                if (criticalHit)
                {
                    damageBonus = lifeMagicDamage * 0.5f * GetWeaponCritDamageMod(sourceCreature, attackSkill, target);
                }

                finalDamage = (lifeMagicDamage + damageBonus) * elementalDmgBonus * slayerBonus * shieldMod;
                return(finalDamage);
            }
            // war/void magic projectiles
            else
            {
                if (criticalHit)
                {
                    if (isPVP) // PvP: 50% of the MIN damage added to normal damage roll
                    {
                        damageBonus = Spell.MinDamage * 0.5f;
                    }
                    else   // PvE: 50% of the MAX damage added to normal damage roll
                    {
                        damageBonus = Spell.MaxDamage * 0.5f;
                    }

                    var critDamageMod = GetWeaponCritDamageMod(sourceCreature, attackSkill, target);

                    damageBonus *= critDamageMod;
                }

                /* War Magic skill-based damage bonus
                 * http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players
                 */
                if (sourcePlayer != null)
                {
                    // per retail stats, level 8 difficulty is capped to 350 instead of 400
                    // without this, level 7s have the potential to deal more damage than level 8s
                    var difficulty = Math.Min(Spell.Power, 350);
                    var magicSkill = sourcePlayer.GetCreatureSkill(Spell.School).Current;

                    if (magicSkill > difficulty)
                    {
                        // Bonus clamped to a maximum of 50%
                        //var percentageBonus = Math.Clamp((magicSkill - Spell.Power) / 100.0f, 0.0f, 0.5f);
                        var percentageBonus = (magicSkill - difficulty) / 1000.0f;

                        warSkillBonus = Spell.MinDamage * percentageBonus;
                    }
                }
                var baseDamage = ThreadSafeRandom.Next(Spell.MinDamage, Spell.MaxDamage);

                var weaponResistanceMod = GetWeaponResistanceModifier(sourceCreature, attackSkill, Spell.DamageType);

                finalDamage  = baseDamage + damageBonus + warSkillBonus;
                finalDamage *= target.GetResistanceMod(resistanceType, null, weaponResistanceMod)
                               * elementalDmgBonus * slayerBonus * shieldMod;

                return(finalDamage);
            }
        }
Example #13
0
        /// <summary>
        /// Calculates the damage for a spell projectile
        /// Used by war magic, void magic, and life magic projectiles
        /// </summary>
        public float?CalculateDamage(WorldObject source, WorldObject caster, Creature target, ref bool criticalHit, ref bool critDefended, ref bool overpower)
        {
            var sourcePlayer = source as Player;
            var targetPlayer = target as Player;

            if (source == null || !target.IsAlive || targetPlayer != null && targetPlayer.Invincible)
            {
                return(null);
            }

            // check lifestone protection
            if (targetPlayer != null && targetPlayer.UnderLifestoneProtection)
            {
                if (sourcePlayer != null)
                {
                    sourcePlayer.Session.Network.EnqueueSend(new GameMessageSystemChat($"The Lifestone's magic protects {targetPlayer.Name} from the attack!", ChatMessageType.Magic));
                }

                targetPlayer.HandleLifestoneProtection();
                return(null);
            }

            var critDamageBonus     = 0.0f;
            var weaponCritDamageMod = 1.0f;
            var weaponResistanceMod = 1.0f;
            var resistanceMod       = 1.0f;

            // life magic
            var lifeMagicDamage = 0.0f;

            // war/void magic
            var baseDamage  = 0;
            var skillBonus  = 0.0f;
            var finalDamage = 0.0f;

            var resistanceType = Creature.GetResistanceType(Spell.DamageType);

            var sourceCreature = source as Creature;

            if (sourceCreature?.Overpower != null)
            {
                overpower = Creature.GetOverpower(sourceCreature, target);
            }

            var resisted = source.TryResistSpell(target, Spell, caster, true);

            if (resisted && !overpower)
            {
                return(null);
            }

            CreatureSkill attackSkill = null;

            if (sourceCreature != null)
            {
                attackSkill = sourceCreature.GetCreatureSkill(Spell.School);
            }

            // critical hit
            var criticalChance = GetWeaponMagicCritFrequency(sourceCreature, attackSkill, target);

            if (ThreadSafeRandom.Next(0.0f, 1.0f) < criticalChance)
            {
                if (targetPlayer != null && targetPlayer.AugmentationCriticalDefense > 0)
                {
                    var criticalDefenseMod    = sourcePlayer != null ? 0.05f : 0.25f;
                    var criticalDefenseChance = targetPlayer.AugmentationCriticalDefense * criticalDefenseMod;

                    if (criticalDefenseChance > ThreadSafeRandom.Next(0.0f, 1.0f))
                    {
                        critDefended = true;
                    }
                }

                if (!critDefended)
                {
                    criticalHit = true;
                }
            }

            var absorbMod = GetAbsorbMod(target);

            bool isPVP = sourcePlayer != null && targetPlayer != null;

            //http://acpedia.org/wiki/Announcements_-_2014/01_-_Forces_of_Nature - Aegis is 72% effective in PvP
            if (isPVP && (target.CombatMode == CombatMode.Melee || target.CombatMode == CombatMode.Missile))
            {
                absorbMod  = 1 - absorbMod;
                absorbMod *= 0.72f;
                absorbMod  = 1 - absorbMod;
            }

            if (isPVP && Spell.IsHarmful)
            {
                Player.UpdatePKTimers(sourcePlayer, targetPlayer);
            }

            var elementalDamageMod = GetCasterElementalDamageModifier(sourceCreature, target, Spell.DamageType);

            // Possible 2x + damage bonus for the slayer property
            var slayerMod = GetWeaponCreatureSlayerModifier(sourceCreature, target);

            // life magic projectiles: ie., martyr's hecatomb
            if (Spell.MetaSpellType == ACE.Entity.Enum.SpellType.LifeProjectile)
            {
                lifeMagicDamage = LifeProjectileDamage * Spell.DamageRatio;

                // could life magic projectiles crit?
                // if so, did they use the same 1.5x formula as war magic, instead of 2.0x?
                if (criticalHit)
                {
                    weaponCritDamageMod = GetWeaponCritDamageMod(sourceCreature, attackSkill, target);
                    critDamageBonus     = lifeMagicDamage * 0.5f * weaponCritDamageMod;
                }

                weaponResistanceMod = GetWeaponResistanceModifier(sourceCreature, attackSkill, Spell.DamageType);

                // if attacker/weapon has IgnoreMagicResist directly, do not transfer to spell projectile
                // only pass if SpellProjectile has it directly, such as 2637 - Invoking Aun Tanua

                resistanceMod = (float)Math.Max(0.0f, target.GetResistanceMod(resistanceType, this, null, weaponResistanceMod));

                finalDamage = (lifeMagicDamage + critDamageBonus) * elementalDamageMod * slayerMod * resistanceMod * absorbMod;
            }
            // war/void magic projectiles
            else
            {
                if (criticalHit)
                {
                    // Original:
                    // http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players

                    // Critical Strikes: In addition to the skill-based damage bonus, each projectile spell has a 2% chance of causing a critical hit on the target and doing increased damage.
                    // A magical critical hit is similar in some respects to melee critical hits (although the damage calculation is handled differently).
                    // While a melee critical hit automatically does twice the maximum damage of the weapon, a magical critical hit will do an additional half the minimum damage of the spell.
                    // For instance, a magical critical hit from a level 7 spell, which does 110-180 points of damage, would add an additional 55 points of damage to the spell.

                    // Later updated for PvE only:

                    // http://acpedia.org/wiki/Announcements_-_2004/07_-_Treaties_in_Stone#Letter_to_the_Players

                    // Currently when a War Magic spell scores a critical hit, it adds a multiple of the base damage of the spell to a normal damage roll.
                    // Starting in July, War Magic critical hits will instead add a multiple of the maximum damage of the spell.
                    // No more crits that do less damage than non-crits!

                    if (isPVP) // PvP: 50% of the MIN damage added to normal damage roll
                    {
                        critDamageBonus = Spell.MinDamage * 0.5f;
                    }
                    else   // PvE: 50% of the MAX damage added to normal damage roll
                    {
                        critDamageBonus = Spell.MaxDamage * 0.5f;
                    }

                    weaponCritDamageMod = GetWeaponCritDamageMod(sourceCreature, attackSkill, target);

                    critDamageBonus *= weaponCritDamageMod;
                }

                /* War Magic skill-based damage bonus
                 * http://acpedia.org/wiki/Announcements_-_2002/08_-_Atonement#Letter_to_the_Players
                 */
                if (sourcePlayer != null)
                {
                    // per retail stats, level 8 difficulty is capped to 350 instead of 400
                    // without this, level 7s have the potential to deal more damage than level 8s
                    var difficulty = Math.Min(Spell.Power, 350);    // was skillMod possibility capped to 1.3x for level 7 spells in retail, instead of level 8 difficulty cap?
                    var magicSkill = sourcePlayer.GetCreatureSkill(Spell.School).Current;

                    if (magicSkill > difficulty)
                    {
                        // Bonus clamped to a maximum of 50%
                        //var percentageBonus = Math.Clamp((magicSkill - Spell.Power) / 100.0f, 0.0f, 0.5f);
                        var percentageBonus = (magicSkill - difficulty) / 1000.0f;

                        skillBonus = Spell.MinDamage * percentageBonus;
                    }
                }
                baseDamage = ThreadSafeRandom.Next(Spell.MinDamage, Spell.MaxDamage);

                weaponResistanceMod = GetWeaponResistanceModifier(sourceCreature, attackSkill, Spell.DamageType);

                // if attacker/weapon has IgnoreMagicResist directly, do not transfer to spell projectile
                // only pass if SpellProjectile has it directly, such as 2637 - Invoking Aun Tanua

                resistanceMod = (float)Math.Max(0.0f, target.GetResistanceMod(resistanceType, this, null, weaponResistanceMod));

                if (sourcePlayer != null && targetPlayer != null && Spell.DamageType == DamageType.Nether)
                {
                    // for direct damage from void spells in pvp,
                    // apply void_pvp_modifier *on top of* the player's natural resistance to nether

                    // this supposedly brings the direct damage from void spells in pvp closer to retail
                    resistanceMod *= (float)PropertyManager.GetDouble("void_pvp_modifier").Item;
                }

                finalDamage = baseDamage + critDamageBonus + skillBonus;

                finalDamage *= elementalDamageMod * slayerMod * resistanceMod * absorbMod;
            }

            // show debug info
            if (sourceCreature != null && sourceCreature.DebugDamage.HasFlag(Creature.DebugDamageType.Attacker))
            {
                ShowInfo(sourceCreature, Spell, attackSkill, criticalChance, criticalHit, critDefended, overpower, weaponCritDamageMod, skillBonus, baseDamage, critDamageBonus, elementalDamageMod, slayerMod, weaponResistanceMod, resistanceMod, absorbMod, LifeProjectileDamage, lifeMagicDamage, finalDamage);
            }
            if (target.DebugDamage.HasFlag(Creature.DebugDamageType.Defender))
            {
                ShowInfo(target, Spell, attackSkill, criticalChance, criticalHit, critDefended, overpower, weaponCritDamageMod, skillBonus, baseDamage, critDamageBonus, elementalDamageMod, slayerMod, weaponResistanceMod, resistanceMod, absorbMod, LifeProjectileDamage, lifeMagicDamage, finalDamage);
            }
            return(finalDamage);
        }
Example #14
0
        /// <summary>
        /// Creates the Life Magic spell
        /// </summary>
        /// <param name="target"></param>
        /// <param name="spell"></param>
        /// <param name="spellStatMod"></param>
        /// <param name="message"></param>
        /// <param name="castByItem"></param>
        /// <returns></returns>
        protected bool LifeMagic(WorldObject target, SpellBase spell, Database.Models.World.Spell spellStatMod, out string message, string castByItem = null)
        {
            string srcVital, destVital, action;
            string targetMsg = null;

            Player   player   = null;
            Creature creature = null;

            if (WeenieClassId == 1)
            {
                player = (Player)this;
            }
            else if (WeenieType == WeenieType.Creature)
            {
                creature = (Creature)this;
            }

            Creature spellTarget;

            if (spell.BaseRangeConstant == 0)
            {
                spellTarget = (Creature)this;
            }
            else
            {
                spellTarget = (Creature)target;
            }

            int newSpellTargetVital;

            switch (spell.MetaSpellType)
            {
            case SpellType.Boost:
                int minBoostValue, maxBoostValue;
                if ((spellStatMod.BoostVariance + spellStatMod.Boost) < spellStatMod.Boost)
                {
                    minBoostValue = (int)(spellStatMod.BoostVariance + spellStatMod.Boost);
                    maxBoostValue = (int)spellStatMod.Boost;
                }
                else
                {
                    minBoostValue = (int)spellStatMod.Boost;
                    maxBoostValue = (int)(spellStatMod.BoostVariance + spellStatMod.Boost);
                }
                int boost = Physics.Common.Random.RollDice(minBoostValue, maxBoostValue);
                if (boost < 0)
                {
                    action = "drain";
                }
                else
                {
                    action = "restore";
                }
                switch (spellStatMod.DamageType)
                {
                case 512:           // Mana
                    newSpellTargetVital = (int)(spellTarget.Mana.Current + boost);
                    srcVital            = "mana";
                    if (newSpellTargetVital < spellTarget.Mana.MaxValue)
                    {
                        if (newSpellTargetVital <= 0)
                        {
                            spellTarget.UpdateVital(spellTarget.Mana, 0);
                        }
                        else
                        {
                            spellTarget.UpdateVital(spellTarget.Mana, (uint)newSpellTargetVital);
                        }
                    }
                    else
                    {
                        spellTarget.UpdateVital(spellTarget.Mana, spellTarget.Mana.MaxValue);
                    }
                    break;

                case 256:           // Stamina
                    newSpellTargetVital = (int)(spellTarget.Stamina.Current + boost);
                    srcVital            = "stamina";
                    if (newSpellTargetVital < spellTarget.Stamina.MaxValue)
                    {
                        if (newSpellTargetVital <= 0)
                        {
                            spellTarget.UpdateVital(spellTarget.Stamina, 0);
                        }
                        else
                        {
                            spellTarget.UpdateVital(spellTarget.Stamina, (uint)newSpellTargetVital);
                        }
                    }
                    else
                    {
                        spellTarget.UpdateVital(spellTarget.Stamina, spellTarget.Stamina.MaxValue);
                    }
                    break;

                default:           // Health
                    newSpellTargetVital = (int)(spellTarget.Health.Current + boost);
                    srcVital            = "health";
                    if (newSpellTargetVital < spellTarget.Health.MaxValue)
                    {
                        if (newSpellTargetVital <= 0)
                        {
                            spellTarget.UpdateVital(spellTarget.Health, 0);
                        }
                        else
                        {
                            spellTarget.UpdateVital(spellTarget.Health, (uint)newSpellTargetVital);
                        }
                    }
                    else
                    {
                        spellTarget.UpdateVital(spellTarget.Health, spellTarget.Health.MaxValue);
                    }
                    break;
                }
                if (this is Player)
                {
                    if (spell.BaseRangeConstant == 0)
                    {
                        message = $"You {action} {Math.Abs(boost).ToString()} {srcVital}";
                    }
                    else
                    {
                        message = $"You {action} {Math.Abs(boost).ToString()} points of {srcVital} from {spellTarget.Name}";
                    }
                }
                else
                {
                    message = null;
                }

                if (target is Player && spell.BaseRangeConstant > 0)
                {
                    targetMsg = $"{Name} casts {spell.Name} and {action}s {Math.Abs(boost)} points of your {srcVital}.";
                }

                break;

            case SpellType.Transfer:
                // Calculate the change in vitals of the target
                Creature caster;
                if (spell.BaseRangeConstant == 0 && spell.BaseRangeMod == 1)
                {
                    caster = spellTarget;
                }
                else
                {
                    caster = (Creature)this;
                }
                uint           vitalChange, casterVitalChange;
                ResistanceType resistanceDrain, resistanceBoost;
                if (spellStatMod.Source == (int)PropertyAttribute2nd.Mana)
                {
                    resistanceDrain = ResistanceType.ManaDrain;
                }
                else if (spellStatMod.Source == (int)PropertyAttribute2nd.Stamina)
                {
                    resistanceDrain = ResistanceType.StaminaDrain;
                }
                else
                {
                    resistanceDrain = ResistanceType.HealthDrain;
                }
                vitalChange = (uint)((spellTarget.GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source) * spellStatMod.Proportion) * spellTarget.GetNaturalResistence(resistanceDrain));
                if (spellStatMod.TransferCap != 0)
                {
                    if (vitalChange > spellStatMod.TransferCap)
                    {
                        vitalChange = (uint)spellStatMod.TransferCap;
                    }
                }
                if (spellStatMod.Destination == (int)PropertyAttribute2nd.Mana)
                {
                    resistanceBoost = ResistanceType.ManaDrain;
                }
                else if (spellStatMod.Source == (int)PropertyAttribute2nd.Stamina)
                {
                    resistanceBoost = ResistanceType.StaminaDrain;
                }
                else
                {
                    resistanceBoost = ResistanceType.HealthDrain;
                }
                casterVitalChange   = (uint)((vitalChange * (1.0f - spellStatMod.LossPercent)) * spellTarget.GetNaturalResistence(resistanceBoost));
                vitalChange         = (uint)(casterVitalChange / (1.0f - spellStatMod.LossPercent));
                newSpellTargetVital = (int)(spellTarget.GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source) - vitalChange);

                // Apply the change in vitals to the target
                switch (spellStatMod.Source)
                {
                case (int)PropertyAttribute2nd.Mana:
                    srcVital = "mana";
                    if (newSpellTargetVital <= 0)
                    {
                        spellTarget.UpdateVital(spellTarget.Mana, 0);
                    }
                    else
                    {
                        spellTarget.UpdateVital(spellTarget.Mana, (uint)newSpellTargetVital);
                    }
                    break;

                case (int)PropertyAttribute2nd.Stamina:
                    srcVital = "stamina";
                    if (newSpellTargetVital <= 0)
                    {
                        spellTarget.UpdateVital(spellTarget.Stamina, 0);
                    }
                    else
                    {
                        spellTarget.UpdateVital(spellTarget.Stamina, (uint)newSpellTargetVital);
                    }
                    break;

                default:           // Health
                    srcVital = "health";
                    if (newSpellTargetVital <= 0)
                    {
                        spellTarget.UpdateVital(spellTarget.Health, 0);
                    }
                    else
                    {
                        spellTarget.UpdateVital(spellTarget.Health, (uint)newSpellTargetVital);
                    }
                    break;
                }

                // Apply the scaled change in vitals to the caster
                uint newCasterVital;
                switch (spellStatMod.Destination)
                {
                case (int)PropertyAttribute2nd.Mana:
                    destVital      = "mana";
                    newCasterVital = caster.Mana.Current + casterVitalChange;
                    caster.UpdateVital(caster.Mana, newCasterVital);
                    break;

                case (int)PropertyAttribute2nd.Stamina:
                    destVital      = "stamina";
                    newCasterVital = caster.Stamina.Current + casterVitalChange;
                    caster.UpdateVital(caster.Stamina, newCasterVital);
                    break;

                default:           // Health
                    destVital      = "health";
                    newCasterVital = caster.Mana.Current + casterVitalChange;
                    caster.UpdateVital(caster.Health, newCasterVital);
                    break;
                }

                if (WeenieClassId == 1)
                {
                    if (target.Guid == Guid)
                    {
                        message = $"You drain {vitalChange.ToString()} points of {srcVital} and apply {casterVitalChange.ToString()} points of {destVital} to yourself";
                    }
                    else
                    {
                        message = $"You drain {vitalChange.ToString()} points of {srcVital} from {spellTarget.Name} and apply {casterVitalChange.ToString()} to yourself";
                    }
                }
                else
                {
                    message = null;
                }

                if (target is Player && target != this)
                {
                    targetMsg = $"You lose {vitalChange} points of {srcVital} due to {Name} casting {spell.Name} on you";
                }

                break;

            case SpellType.LifeProjectile:
                caster = (Creature)this;
                uint damage;
                if (spell.Name.Contains("Blight"))
                {
                    damage         = (uint)(caster.GetCurrentCreatureVital(PropertyAttribute2nd.Mana) * caster.GetNaturalResistence(ResistanceType.ManaDrain));
                    newCasterVital = caster.Mana.Current - damage;
                    if (newCasterVital <= 0)
                    {
                        caster.UpdateVital(caster.Mana, 0);
                    }
                    else
                    {
                        caster.UpdateVital(caster.Mana, (uint)newCasterVital);
                    }
                }
                else if (spell.Name.Contains("Tenacity"))
                {
                    damage         = (uint)(spellTarget.GetCurrentCreatureVital(PropertyAttribute2nd.Stamina) * spellTarget.GetNaturalResistence(ResistanceType.StaminaDrain));
                    newCasterVital = caster.Stamina.Current - damage;
                    if (newCasterVital <= 0)
                    {
                        caster.UpdateVital(caster.Stamina, 0);
                    }
                    else
                    {
                        caster.UpdateVital(caster.Stamina, (uint)newCasterVital);
                    }
                }
                else
                {
                    damage         = (uint)(spellTarget.GetCurrentCreatureVital(PropertyAttribute2nd.Stamina) * spellTarget.GetNaturalResistence(ResistanceType.HealthDrain));
                    newCasterVital = caster.Health.Current - damage;
                    if (newCasterVital <= 0)
                    {
                        caster.UpdateVital(caster.Health, 0);
                    }
                    else
                    {
                        caster.UpdateVital(caster.Health, (uint)newCasterVital);
                    }
                }

                CreateSpellProjectile(this, target, spell.MetaSpellId, (uint)spellStatMod.Wcid, damage);

                if (caster.Health.Current <= 0)
                {
                    caster.Die();

                    if (caster.WeenieClassId == 1)
                    {
                        Strings.DeathMessages.TryGetValue(DamageType.Base, out var messages);
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat("You have killed yourself", ChatMessageType.Broadcast));
                    }
                }
                message = null;
                break;

            case SpellType.Dispel:
                message = "Spell not implemented, yet!";
                break;

            case SpellType.Enchantment:
                message = CreateEnchantment(target, spell, spellStatMod, castByItem);
                break;

            default:
                message = "Spell not implemented, yet!";
                break;
            }

            if (targetMsg != null)
            {
                var playerTarget = target as Player;
                playerTarget.Session.Network.EnqueueSend(new GameMessageSystemChat(targetMsg, ChatMessageType.Magic));
            }

            if (spellTarget.Health.Current == 0)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }