/// <summary> /// Tries to queue a new style in the player's style queue. /// Takes care of all conditions like setting backup styles and /// canceling styles if the style was queued already. /// </summary> /// <param name="living">The living to execute the style</param> /// <param name="style">The style to execute</param> public static void TryToUseStyle(GameLiving living, Style style) { //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) { //Dead players can't use styles if (!living.IsAlive) { if (player != null) player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.CantCombatMode"), eChatType.CT_YouHit, eChatLoc.CL_SystemWindow); return; } if (living.IsDisarmed) { if(living is GamePlayer) (living as GamePlayer).Out.SendMessage("You are disarmed and cannot attack!", eChatType.CT_YouHit, eChatLoc.CL_SystemWindow); return; } //Can't use styles with range weapon if (living.ActiveWeaponSlot == GameLiving.eActiveWeaponSlot.Distance) { if (player != null) player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.CantMeleeCombat"), eChatType.CT_YouHit, eChatLoc.CL_SystemWindow); return; } //Put player into attack state before setting the styles //Changing the attack state clears out the styles... if (living.AttackState == false) { living.StartAttack(player.TargetObject); } if (living.TargetObject == null) { if (player != null) player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.MustHaveTarget"), eChatType.CT_System, eChatLoc.CL_SystemWindow); return; } InventoryItem weapon = (style.WeaponTypeRequirement == (int)eObjectType.Shield) ? living.Inventory.GetItem(eInventorySlot.LeftHandWeapon) : living.AttackWeapon; // if (weapon == null) return; // no weapon = no style if (!CheckWeaponType(style, living, weapon)) { if (player != null) { if (style.WeaponTypeRequirement == Style.SpecialWeaponType.DualWield) player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.DualWielding"), eChatType.CT_System, eChatLoc.CL_SystemWindow); else player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.StyleRequires", style.GetRequiredWeaponName()), eChatType.CT_System, eChatLoc.CL_SystemWindow); } return; } if (player != null) //Do mob use endurance? { int fatCost = CalculateEnduranceCost(player, style, weapon.SPD_ABS); if (player.Endurance < fatCost) { player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.Fatigued"), eChatType.CT_System, eChatLoc.CL_SystemWindow); return; } } if (player != null) { Style preRequireStyle = null; if (style.OpeningRequirementType == Style.eOpening.Offensive && style.AttackResultRequirement == Style.eAttackResult.Style) preRequireStyle = SkillBase.GetStyleByID(style.OpeningRequirementValue, player.CharacterClass.ID); //We have not set any primary style yet? if (player.NextCombatStyle == null) { if (preRequireStyle != null) { AttackData lastAD = (AttackData)living.TempProperties.getProperty<object>(GameLiving.LAST_ATTACK_DATA, null); if (lastAD == null || lastAD.AttackResult != GameLiving.eAttackResult.HitStyle || lastAD.Style == null || lastAD.Style.ID != style.OpeningRequirementValue) { player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.PerformStyleBefore", preRequireStyle.Name), eChatType.CT_System, eChatLoc.CL_SystemWindow); return; } } player.NextCombatStyle = style; player.NextCombatBackupStyle = null; player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.PreparePerform", style.Name), eChatType.CT_System, eChatLoc.CL_SystemWindow); if (living.IsEngaging) { // cancel engage effect if exist EngageEffect effect = living.EffectList.GetOfType<EngageEffect>(); if (effect != null) effect.Cancel(false); } // unstealth only on primary style to not break // stealth with non-stealth backup styles if (!style.StealthRequirement) player.Stealth(false); } else { //Have we also set the backupstyle already? if (player.NextCombatBackupStyle != null) { //All styles set, can't change anything now player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.AlreadySelectedStyles"), eChatType.CT_System, eChatLoc.CL_SystemWindow); } else { //Have we pressed the same style button used for the primary style again? if (player.NextCombatStyle.ID == style.ID) { if (player.CancelStyle) { //If yes, we cancel the style player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.NoLongerPreparing", player.NextCombatStyle.Name), eChatType.CT_System, eChatLoc.CL_SystemWindow); player.NextCombatStyle = null; player.NextCombatBackupStyle = null; } else { player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.AlreadyPreparing"), eChatType.CT_System, eChatLoc.CL_SystemWindow); } } else { if (preRequireStyle != null) { AttackData lastAD = (AttackData)living.TempProperties.getProperty<object>(GameLiving.LAST_ATTACK_DATA, null); if (lastAD == null || lastAD.AttackResult != GameLiving.eAttackResult.HitStyle || lastAD.Style == null || lastAD.Style.ID != style.OpeningRequirementValue) { player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.PerformStyleBefore", preRequireStyle.Name), eChatType.CT_System, eChatLoc.CL_SystemWindow); return; } } //If no, set the secondary backup style player.NextCombatBackupStyle = style; player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client, "StyleProcessor.TryToUseStyle.BackupStyle", style.Name, player.NextCombatStyle.Name), eChatType.CT_System, eChatLoc.CL_SystemWindow); } } } } } }