Ejemplo n.º 1
0
        /// <summary>
        /// Executes the style of the given player. Prints
        /// out messages to the player notifying him of his success or failure.
        /// </summary>
        /// <param name="living">The living executing the styles</param>
        /// <param name="attackData">
        /// The AttackData that will be modified to contain the 
        /// new damage and the executed style.
        /// </param>
        /// <param name="weapon">The weapon used to execute the style</param>
        /// <returns>true if a style was performed, false if not</returns>
        public static bool ExecuteStyle(GameLiving living, AttackData attackData, InventoryItem weapon)
        {
            //First thing in processors, lock the objects you modify
            //This way it makes sure the objects are not modified by
            //several different threads at the same time!

            GamePlayer player = living as GamePlayer;
            lock (living)
            {
                //Does the player want to execute a style at all?
                if (attackData.Style == null)
                    return false;

                if (weapon != null && weapon.Object_Type == (int)eObjectType.Shield)
                {
                    attackData.AnimationId = (weapon.Hand != 1) ? attackData.Style.Icon : attackData.Style.TwoHandAnimation; // 2h shield?
                }
                int fatCost = 0;
                if (weapon != null)
                    fatCost = CalculateEnduranceCost(living, attackData.Style, weapon.SPD_ABS);

                //Reduce endurance if styled attack missed
                switch (attackData.AttackResult)
                {
                    case GameLiving.eAttackResult.Blocked:
                    case GameLiving.eAttackResult.Evaded:
                    case GameLiving.eAttackResult.Missed:
                    case GameLiving.eAttackResult.Parried:
                        if (player != null) //No mob endu lost yet
                            living.Endurance -= Math.Max(1, fatCost / 2);
                        return false;
                }

                //Ignore all other attack results
                if (attackData.AttackResult != GameLiving.eAttackResult.HitUnstyled
                    && attackData.AttackResult != GameLiving.eAttackResult.HitStyle)
                    return false;

                //Did primary and backup style fail?
                if (!CanUseStyle(living, attackData.Style, weapon))
                {
                    if (player != null)
                    {
                        // reduce players endurance, full endurance if failed style
                        player.Endurance -= fatCost;

                        //"You must be hidden to perform this style!"
                        //Print a style-fail message
                        player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "StyleProcessor.ExecuteStyle.ExecuteFail", attackData.Style.Name), eChatType.CT_YouHit, eChatLoc.CL_SystemWindow);
                    }
                    return false;
                }
                else
                {
                    //Style worked! Print out some nice info and add the damage! :)
                    //Growth * Style Spec * Effective Speed / Unstyled Damage Cap

                    bool staticGrowth = attackData.Style.StealthRequirement;  //static growth is not a function of (effective) weapon speed
                    double absorbRatio = attackData.Damage / living.UnstyledDamageCap(weapon); //scaling factor for style damage
                    double effectiveWeaponSpeed = living.AttackSpeed(weapon) * 0.001;
                    double styleGrowth = Math.Max(0,attackData.Style.GrowthOffset + attackData.Style.GrowthRate * living.GetModifiedSpecLevel(attackData.Style.Spec));
                    double styleDamageBonus = living.GetModified(eProperty.StyleDamage) * 0.01 - 1;

                    if (staticGrowth)
                    {
                        if (living.AttackWeapon.Item_Type == Slot.TWOHAND)
                        {
                            styleGrowth = styleGrowth * 1.25 + living.WeaponDamage(living.AttackWeapon) * Math.Max(0,living.AttackWeapon.SPD_ABS - 21) * 10 / 66d;
                        }
                        attackData.StyleDamage = (int)(absorbRatio * styleGrowth * ServerProperties.Properties.CS_OPENING_EFFECTIVENESS);
                    }
                    else
                        attackData.StyleDamage = (int)(absorbRatio * styleGrowth * effectiveWeaponSpeed);

                    attackData.StyleDamage += (int)(attackData.Damage * styleDamageBonus);

                    //Eden - style absorb bonus
                    int absorb=0;
                    if(attackData.Target is GamePlayer && attackData.Target.GetModified(eProperty.StyleAbsorb) > 0)
                    {
                        absorb=(int)Math.Floor((double)attackData.StyleDamage * ((double)attackData.Target.GetModified(eProperty.StyleAbsorb)/100));
                        attackData.StyleDamage -= absorb;
                    }

                    //Increase regular damage by styledamage ... like on live servers
                    attackData.Damage += attackData.StyleDamage;

                    if (player != null)
                    {
                        // reduce players endurance
                        player.Endurance -= fatCost;

                        if(absorb > 0)
                        {
                            player.Out.SendMessage("A barrier absorbs " + absorb + " damage!", eChatType.CT_YouHit, eChatLoc.CL_SystemWindow);
                            if(living is GamePlayer) (living as GamePlayer).Out.SendMessage("A barrier absorbs " + absorb + " damage!", eChatType.CT_YouHit, eChatLoc.CL_SystemWindow);
                        }
                    }

                    #region StyleProcs
                    if (attackData.Style.Procs.Count > 0)
                    {
                        ISpellHandler effect;

                        // If ClassID = 0, use the proc for any class, unless there is also a proc with a ClassID
                        // that matches the player's CharacterClass.ID, or for mobs, the style's ClassID - then use
                        // the class-specific proc instead of the ClassID=0 proc
                        if (!attackData.Style.RandomProc)
                        {
                            List<Tuple<Spell, int, int>> procsToExecute = new List<Tuple<Spell, int, int>>();
                            bool onlyExecuteClassSpecific = false;

                            foreach (Tuple<Spell, int, int> proc in attackData.Style.Procs)
                            {
                                if (player != null && proc.Item2 == player.CharacterClass.ID)
                                {
                                    procsToExecute.Add(proc);
                                    onlyExecuteClassSpecific = true;
                                }
                                else if (proc.Item2 == attackData.Style.ClassID || proc.Item2 == 0)
                                {
                                    procsToExecute.Add(proc);
                                }
                            }

                            foreach (Tuple<Spell, int, int> procToExecute in procsToExecute)
                            {
                                if (onlyExecuteClassSpecific && procToExecute.Item2 == 0)
                                    continue;

                                if (Util.Chance(procToExecute.Item3))
                                {
                                    effect = CreateMagicEffect(living, attackData.Target, procToExecute.Item1.ID);
                                    //effect could be null if the SpellID is bigger than ushort
                                    if (effect != null)
                                    {
                                        attackData.StyleEffects.Add(effect);
                                        if (attackData.Style.OpeningRequirementType == Style.eOpening.Offensive || attackData.Style.OpeningRequirementType == Style.eOpening.Defensive)
                                        {
                                            effect.UseMinVariance = true;
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            //Add one proc randomly
                            int random = Util.Random(attackData.Style.Procs.Count - 1);
                            //effect could be null if the SpellID is bigger than ushort
                            effect = CreateMagicEffect(living, attackData.Target, attackData.Style.Procs[random].Item1.ID);
                            if (effect != null)
                            {
                                attackData.StyleEffects.Add(effect);
                                if (attackData.Style.OpeningRequirementType == Style.eOpening.Offensive || attackData.Style.OpeningRequirementType == Style.eOpening.Defensive)
                                {
                                    effect.UseMinVariance = true;
                                }
                            }
                        }
                    }
                    #endregion StyleProcs

                    #region Animation
                    if (weapon != null)
                        attackData.AnimationId = (weapon.Hand != 1) ? attackData.Style.Icon : attackData.Style.TwoHandAnimation; // special animation for two-hand
                    else if (living.Inventory != null)
                        attackData.AnimationId = (living.Inventory.GetItem(eInventorySlot.RightHandWeapon) != null) ? attackData.Style.Icon : attackData.Style.TwoHandAnimation; // special animation for two-hand
                    else
                        attackData.AnimationId = attackData.Style.Icon;
                    #endregion Animation

                    return true;
                }
            }
        }