/// <summary> /// Calculates endurance needed to use style /// </summary> /// <param name="living">The living doing the style</param> /// <param name="style">The style to be used</param> /// <param name="weaponSpd">The weapon speed</param> /// <returns>Endurance needed to use style</returns> public static int CalculateEnduranceCost(GameLiving living, Style style, int weaponSpd) { //[StephenxPimentel] //1.108 - Valhallas Blessing now has a 75% chance to not use endurance. // Apply Valkyrie RA5L effect ValhallasBlessingEffect ValhallasBlessing = living.EffectList.GetOfType<ValhallasBlessingEffect>(); if (ValhallasBlessing != null && Util.Chance(75)) return 0; //Camelot Herald 1.90 : Battlemaster styles will now cost a flat amount of Endurance, regardless of weapon speed if (style.Spec == Specs.Battlemaster) return Math.Max(1, (int)Math.Ceiling((30 * style.EnduranceCost / 40) * living.GetModified(eProperty.FatigueConsumption) * 0.01)); int fatCost = weaponSpd * style.EnduranceCost / 40; if (weaponSpd < 40) fatCost++; fatCost = (int)Math.Ceiling(fatCost * living.GetModified(eProperty.FatigueConsumption) * 0.01); return Math.Max(1, fatCost); }
/// <summary> /// Delve a Style handled by this processor /// </summary> /// <param name="delveInfo"></param> /// <param name="style"></param> /// <param name="player"></param> public static void DelveWeaponStyle(IList<string> delveInfo, Style style, GamePlayer player) { delveInfo.Add(LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.WeaponType", style.GetRequiredWeaponName())); string temp = LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Opening") + " "; if (Style.eOpening.Offensive == style.OpeningRequirementType) { //attacker action result is opening switch (style.AttackResultRequirement) { case Style.eAttackResult.Hit: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.YouHit"); break; case Style.eAttackResult.Miss: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.YouMiss"); break; case Style.eAttackResult.Parry: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.TargetParrys"); break; case Style.eAttackResult.Block: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.TargetBlocks"); break; case Style.eAttackResult.Evade: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.TargetEvades"); break; case Style.eAttackResult.Fumble: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.YouFumble"); break; case Style.eAttackResult.Style: Style reqStyle = SkillBase.GetStyleByID(style.OpeningRequirementValue, player.CharacterClass.ID); if (reqStyle == null) { reqStyle = SkillBase.GetStyleByID(style.OpeningRequirementValue, 0); } temp = LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.OpeningStyle") + " "; if (reqStyle == null) { temp += "(style not found " + style.OpeningRequirementValue + ")"; } else { temp += reqStyle.Name; } break; default: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Any"); break; } } else if (Style.eOpening.Defensive == style.OpeningRequirementType) { //defender action result is opening switch (style.AttackResultRequirement) { case Style.eAttackResult.Miss: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.TargetMisses"); break; case Style.eAttackResult.Hit: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.TargetHits"); break; case Style.eAttackResult.Parry: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.YouParry"); break; case Style.eAttackResult.Block: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.YouBlock"); break; case Style.eAttackResult.Evade: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.YouEvade"); break; case Style.eAttackResult.Fumble: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.TargetFumbles"); break; case Style.eAttackResult.Style: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.TargetStyle"); break; default: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Any"); break; } } else if (Style.eOpening.Positional == style.OpeningRequirementType) { //attacker position to target is opening temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Positional"); switch (style.OpeningRequirementValue) { case (int)Style.eOpeningPosition.Front: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Front"); break; case (int)Style.eOpeningPosition.Back: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Back"); break; case (int)Style.eOpeningPosition.Side: temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Side"); break; } } delveInfo.Add(temp); if (style.OpeningRequirementValue != 0 && style.AttackResultRequirement == 0 && style.OpeningRequirementType == 0) { delveInfo.Add(string.Format("- Error: Opening Requirement '{0}' but requirement type is Any!", style.OpeningRequirementValue)); } temp = ""; foreach (Style st in SkillBase.GetStyleList(style.Spec, player.CharacterClass.ID)) { if (st.AttackResultRequirement == Style.eAttackResult.Style && st.OpeningRequirementValue == style.ID) { temp = (temp == "" ? st.Name : temp + LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Or", st.Name)); } } if (temp == "") { foreach (Style st in player.GetChampionStyleList()) { if (st.AttackResultRequirement == Style.eAttackResult.Style && st.OpeningRequirementValue == style.ID) { temp = (temp == "" ? st.Name : temp + LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Or", st.Name)); } } } if (temp != "") { delveInfo.Add(LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.FollowupStyle", temp)); } temp = LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.FatigueCost") + " "; if (style.EnduranceCost < 5) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryLow"); else if (style.EnduranceCost < 10) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Low"); else if (style.EnduranceCost < 15) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Medium"); else if (style.EnduranceCost < 20) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.High"); else temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryHigh"); delveInfo.Add(temp); temp = LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Damage") + " "; if (style.GrowthRate == 0) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.NoBonus"); else if (style.GrowthRate < .1) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryLow"); else if (style.GrowthRate < .25) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Low"); else if (style.GrowthRate < .5) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Medium"); else if (style.GrowthRate < 1.0) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.High"); else temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryHigh"); temp += " (" + style.GrowthRate + ")"; delveInfo.Add(temp); temp = LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.ToHit") + " "; if (style.BonusToHit <= -20) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryHighPenalty"); else if (style.BonusToHit <= -15) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.HighPenalty"); else if (style.BonusToHit <= -10) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.MediumPenalty"); else if (style.BonusToHit <= -5) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.LowPenalty"); else if (style.BonusToHit < 0) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryLowPenalty"); else if (style.BonusToHit == 0) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.NoBonus"); else if (style.BonusToHit < 5) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryLowBonus"); else if (style.BonusToHit < 10) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.LowBonus"); else if (style.BonusToHit < 15) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.MediumBonus"); else if (style.BonusToHit < 20) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.HighBonus"); else temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryHighBonus"); delveInfo.Add(temp); temp = LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.Defense") + " "; if (style.BonusToDefense <= -20) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryHighPenalty"); else if (style.BonusToDefense <= -15) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.HighPenalty"); else if (style.BonusToDefense <= -10) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.MediumPenalty"); else if (style.BonusToDefense <= -5) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.LowPenalty"); else if (style.BonusToDefense < 0) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryLowPenalty"); else if (style.BonusToDefense == 0) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.NoBonus"); else if (style.BonusToDefense < 5) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryLowBonus"); else if (style.BonusToDefense < 10) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.LowBonus"); else if (style.BonusToDefense < 15) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.MediumBonus"); else if (style.BonusToDefense < 20) temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.HighBonus"); else temp += LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.VeryHighBonus"); delveInfo.Add(temp); if (style.Procs.Count > 0) { temp = LanguageMgr.GetTranslation(player.Client, "DetailDisplayHandler.HandlePacket.TargetEffect") + " "; SpellLine styleLine = SkillBase.GetSpellLine(GlobalSpellsLines.Combat_Styles_Effect); if (styleLine != null) { foreach (DBStyleXSpell proc in style.Procs) { // RR4: we added all the procs to the style, now it's time to check for class ID if (proc.ClassID != 0 && proc.ClassID != player.CharacterClass.ID) continue; Spell spell = SkillBase.GetSpellByID(proc.SpellID); if (spell != null) { ISpellHandler spellHandler = ScriptMgr.CreateSpellHandler(player.Client.Player, spell, styleLine); if (spellHandler == null) { temp += spell.Name + " (Not implemented yet)"; delveInfo.Add(temp); } else { temp += spell.Name; delveInfo.Add(temp); delveInfo.Add(" ");//empty line delveInfo.AddRange(spellHandler.DelveInfo); } } } } } if (player.Client.Account.PrivLevel > 1) { delveInfo.Add(" "); delveInfo.Add("--- Style Technical Information ---"); delveInfo.Add(" "); delveInfo.Add(string.Format("ID: {0}", style.ID)); delveInfo.Add(string.Format("ClassID: {0}", style.ClassID)); delveInfo.Add(string.Format("Icon: {0}", style.Icon)); delveInfo.Add(string.Format("TwoHandAnimation: {0}", style.TwoHandAnimation)); delveInfo.Add(string.Format("Spec: {0}", style.Spec)); delveInfo.Add(string.Format("SpecLevelRequirement: {0}", style.SpecLevelRequirement)); delveInfo.Add(string.Format("Level: {0}", style.Level)); delveInfo.Add(string.Format("GrowthRate: {0}", style.GrowthRate)); delveInfo.Add(string.Format("Endurance: {0}", style.EnduranceCost)); delveInfo.Add(string.Format("StealthRequirement: {0}", style.StealthRequirement)); delveInfo.Add(string.Format("WeaponTypeRequirement: {0}", style.WeaponTypeRequirement)); string indicator = ""; if (style.OpeningRequirementValue != 0 && style.AttackResultRequirement == 0 && style.OpeningRequirementType == 0) { indicator = "!!"; } delveInfo.Add(string.Format("AttackResultRequirement: {0}({1}) {2}", style.AttackResultRequirement, (int)style.AttackResultRequirement, indicator)); delveInfo.Add(string.Format("OpeningRequirementType: {0}({1}) {2}", style.OpeningRequirementType, (int)style.OpeningRequirementType, indicator)); delveInfo.Add(string.Format("OpeningRequirementValue: {0}", style.OpeningRequirementValue)); delveInfo.Add(string.Format("ArmorHitLocation: {0}({1})", style.ArmorHitLocation, (int)style.ArmorHitLocation)); delveInfo.Add(string.Format("BonusToDefense: {0}", style.BonusToDefense)); delveInfo.Add(string.Format("BonusToHit: {0}", style.BonusToHit)); if (style.Procs != null && style.Procs.Count > 0) { delveInfo.Add(" "); string procs = ""; foreach (DBStyleXSpell spell in style.Procs) { if (procs != "") procs += ", "; procs += spell.SpellID; } delveInfo.Add(string.Format("Procs: {0}", procs)); delveInfo.Add(string.Format("RandomProc: {0}", style.RandomProc)); } } }
/// <summary> /// Returns whether player has correct weapon /// active for particular style /// </summary> /// <param name="style">The style to execute</param> /// <param name="living">The living wanting to execute the style</param> /// <param name="weapon">The weapon used to execute the style</param> /// <returns>true if correct weapon active</returns> protected static bool CheckWeaponType(Style style, GameLiving living, InventoryItem weapon) { if (living is GameNPC) return true; GamePlayer player = living as GamePlayer; if (player == null) return false; switch (style.WeaponTypeRequirement) { case Style.SpecialWeaponType.DualWield: // both weapons are needed to use style, // shield is not a weapon here InventoryItem rightHand = player.AttackWeapon; InventoryItem leftHand = player.Inventory.GetItem(eInventorySlot.LeftHandWeapon); if (rightHand == null || leftHand == null || (rightHand.Item_Type != Slot.RIGHTHAND && rightHand.Item_Type != Slot.LEFTHAND)) return false; if (style.Spec == Specs.HandToHand && (rightHand.Object_Type != (int)eObjectType.HandToHand || leftHand.Object_Type != (int)eObjectType.HandToHand)) return false; else if (style.Spec == Specs.Fist_Wraps && (rightHand.Object_Type != (int)eObjectType.FistWraps || leftHand.Object_Type != (int)eObjectType.FistWraps)) return false; return leftHand.Object_Type != (int)eObjectType.Shield; case Style.SpecialWeaponType.AnyWeapon: // TODO: style can be used with any weapon type, // shield is not a weapon here return weapon != null; default: // WeaponTypeRequirement holds eObjectType of weapon needed for style // no weapon = can't use style if (weapon == null) return false; // can't use shield styles if no active weapon if (style.WeaponTypeRequirement == (int)eObjectType.Shield && (player.AttackWeapon == null || (player.AttackWeapon.Item_Type != Slot.RIGHTHAND && player.AttackWeapon.Item_Type != Slot.LEFTHAND))) return false; // weapon type check return GameServer.ServerRules.IsObjectTypesEqual( (eObjectType)style.WeaponTypeRequirement, (eObjectType)weapon.Object_Type); } }
/// <summary> /// Returns wether this player can use a particular style /// right now. Tests for all preconditions like prerequired /// styles, previous attack result, ... /// </summary> /// <param name="living">The living wanting to execute a style</param> /// <param name="style">The style to execute</param> /// <param name="weapon">The weapon used to execute the style</param> /// <returns>true if the player can execute the style right now, false if not</returns> public static bool CanUseStyle(GameLiving living, Style style, 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! lock (living) { GameLiving target = living.TargetObject as GameLiving; if (target == null) return false; //Required attack result GameLiving.eAttackResult requiredAttackResult = GameLiving.eAttackResult.Any; switch (style.AttackResultRequirement) { case Style.eAttackResult.Any: requiredAttackResult = GameLiving.eAttackResult.Any; break; case Style.eAttackResult.Block: requiredAttackResult = GameLiving.eAttackResult.Blocked; break; case Style.eAttackResult.Evade: requiredAttackResult = GameLiving.eAttackResult.Evaded; break; case Style.eAttackResult.Fumble: requiredAttackResult = GameLiving.eAttackResult.Fumbled; break; case Style.eAttackResult.Hit: requiredAttackResult = GameLiving.eAttackResult.HitUnstyled; break; case Style.eAttackResult.Style: requiredAttackResult = GameLiving.eAttackResult.HitStyle; break; case Style.eAttackResult.Miss: requiredAttackResult = GameLiving.eAttackResult.Missed; break; case Style.eAttackResult.Parry: requiredAttackResult = GameLiving.eAttackResult.Parried; break; } AttackData lastAD = (AttackData)living.TempProperties.getProperty<object>(GameLiving.LAST_ATTACK_DATA, null); switch (style.OpeningRequirementType) { case Style.eOpening.Offensive: //Style required before this one? if (style.OpeningRequirementValue != 0 && (lastAD == null || lastAD.AttackResult != GameLiving.eAttackResult.HitStyle || lastAD.Style == null || lastAD.Style.ID != style.OpeningRequirementValue || lastAD.Target != target)) // style chains are possible only on the same target { //DOLConsole.WriteLine("Offensive: Opening Requirement style needed failed!("+style.OpeningRequirementValue+")"); return false; } //Last attack result GameLiving.eAttackResult lastRes = (lastAD != null) ? lastAD.AttackResult : GameLiving.eAttackResult.Any; if (requiredAttackResult != GameLiving.eAttackResult.Any && lastRes != requiredAttackResult) { //DOLConsole.WriteLine("Offensive: AttackResult Requirement failed!("+requiredAttackResult.ToString()+", was "+lastRes+")"); return false; } break; case Style.eOpening.Defensive: AttackData targetsLastAD = (AttackData)target.TempProperties.getProperty<object>(GameLiving.LAST_ATTACK_DATA, null); //Last attack result if (requiredAttackResult != GameLiving.eAttackResult.Any) { if (targetsLastAD == null || targetsLastAD.Target != living) { return false; } if (requiredAttackResult != GameLiving.eAttackResult.HitStyle && targetsLastAD.AttackResult != requiredAttackResult) { //DOLConsole.WriteLine("Defensive: AttackResult Requirement failed!("+requiredAttackResult.ToString()+", was "+lastEnemyRes+")"); return false; } else if (requiredAttackResult == GameLiving.eAttackResult.HitStyle && targetsLastAD.Style == null) { //DOLConsole.WriteLine("Defensive: AttackResult Requirement failed!("+requiredAttackResult.ToString()+", was "+lastEnemyRes+")"); return false; } } break; case Style.eOpening.Positional: //check here if target is in front of attacker if (!living.IsObjectInFront(target, 120)) return false; //you can't use positional styles on keep doors or walls if ((target is GameKeepComponent || target is GameKeepDoor) && (Style.eOpeningPosition)style.OpeningRequirementValue != Style.eOpeningPosition.Front) return false; // get players angle on target float angle = target.GetAngle( living ); //player.Out.SendDebugMessage("Positional check: "+style.OpeningRequirementValue+" angle "+angle+" target heading="+target.Heading); switch ((Style.eOpeningPosition)style.OpeningRequirementValue) { //Back Styles //60 degree since 1.62 patch case Style.eOpeningPosition.Back: if (!(angle >= 150 && angle < 210)) return false; break; // Side Styles //105 degree since 1.62 patch case Style.eOpeningPosition.Side: if (!(angle >= 45 && angle < 150) && !(angle >= 210 && angle < 315)) return false; break; // Front Styles // 90 degree case Style.eOpeningPosition.Front: if (!(angle >= 315 || angle < 45)) return false; break; } //DOLConsole.WriteLine("Positional check success: "+style.OpeningRequirementValue); break; } if (style.StealthRequirement && !living.IsStealthed) return false; if (!CheckWeaponType(style, living, weapon)) return false; // if(player.Endurance < CalculateEnduranceCost(style, weapon.SPD_ABS)) // return false; return true; } }
/// <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); } } } } } }
public static void WriteStyleInfo(IList<string> objectInfo, Style style, GameClient client) { client.Player.DelveWeaponStyle(objectInfo, style); }
public static int LoadSpecializations() { m_syncLockUpdates.EnterWriteLock(); try { IList<DBSpecialization> specs = GameServer.Database.SelectAllObjects<DBSpecialization>(); int count = 0; if (specs != null) { // Clear Spec Cache m_specsByName.Clear(); // Clear SpecXAbility Cache (Ability Career) m_specsAbilities.Clear(); // Clear SpecXSpellLine Cache (Spell Career) m_specsSpellLines.Clear(); // Clear Style Cache (Style Career) m_specsStyles.Clear(); // Clear Style ID Cache (Utils...) m_styleIndex.Clear(); // Clear Style X Spell Cache (Style Procs...) m_stylesProcs.Clear(); foreach (DBSpecialization spec in specs) { StringBuilder str = new StringBuilder("Specialization "); str.AppendFormat("{0} - ", spec.KeyName); Specialization gameSpec = null; if (Util.IsEmpty(spec.Implementation, true) == false) { gameSpec = GetNewSpecializationInstance(spec.KeyName, spec.Implementation, spec.Name, spec.Icon, spec.SpecializationID); } else { gameSpec = new Specialization(spec.KeyName, spec.Name, spec.Icon, spec.SpecializationID); } if (log.IsDebugEnabled) log.DebugFormat("Specialization {0} successfuly instanciated from {1} (expected {2})", spec.KeyName, gameSpec.GetType().FullName, spec.Implementation); Tuple<Type, string, ushort, int> entry = new Tuple<Type, string, ushort, int>(gameSpec.GetType(), spec.Name, spec.Icon, spec.SpecializationID); // Now we have an instanciated Specialization, Cache their properties in Skillbase to prevent using too much memory // As most skill objects are duplicated for every game object use... // Load SpecXAbility count = 0; if (spec.AbilityConstraints != null) { if (!m_specsAbilities.ContainsKey(spec.KeyName)) m_specsAbilities.Add(spec.KeyName, new List<Tuple<string, byte, int, int>>()); foreach (DBSpecXAbility specx in spec.AbilityConstraints) { try { m_specsAbilities[spec.KeyName].Add(new Tuple<string, byte, int, int>(m_abilityIndex[specx.AbilityKey].KeyName, (byte)specx.SpecLevel, specx.AbilityLevel, specx.ClassId)); count++; } catch (Exception e) { if (log.IsWarnEnabled) log.WarnFormat("Specialization : {0} while adding Spec X Ability {1}, from Spec {2}({3}), Level {4}", e.Message, specx.AbilityKey, specx.Spec, specx.SpecLevel, specx.AbilityLevel); } } // sort them according to required levels m_specsAbilities[spec.KeyName].Sort((i, j) => i.Item2.CompareTo(j.Item2)); } str.AppendFormat("{0} Ability Constraint, ", count); // Load SpecXSpellLine count = 0; if (spec.SpellLines != null) { foreach (DBSpellLine line in spec.SpellLines) { if (!m_specsSpellLines.ContainsKey(spec.KeyName)) m_specsSpellLines.Add(spec.KeyName, new List<Tuple<SpellLine, int>>()); try { m_specsSpellLines[spec.KeyName].Add(new Tuple<SpellLine, int>(m_spellLineIndex[line.KeyName], line.ClassIDHint)); count++; } catch (Exception e) { if (log.IsWarnEnabled) log.WarnFormat("Specialization : {0} while adding Spec X SpellLine {1} from Spec {2}, ClassID {3}", e.Message, line.KeyName, line.Spec, line.ClassIDHint); } } } str.AppendFormat("{0} Spell Line, ", count); // Load DBStyle count = 0; if (spec.Styles != null) { foreach (DBStyle specStyle in spec.Styles) { // Update Style Career if (!m_specsStyles.ContainsKey(spec.KeyName)) { m_specsStyles.Add(spec.KeyName, new Dictionary<int, List<Tuple<Style, byte>>>()); } if (!m_specsStyles[spec.KeyName].ContainsKey(specStyle.ClassId)) { m_specsStyles[spec.KeyName].Add(specStyle.ClassId, new List<Tuple<Style, byte>>()); } Style newStyle = new Style(specStyle); m_specsStyles[spec.KeyName][specStyle.ClassId].Add(new Tuple<Style, byte>(newStyle, (byte)specStyle.SpecLevelRequirement)); // Update Style Index. KeyValuePair<int, int> styleKey = new KeyValuePair<int, int>(newStyle.ID, specStyle.ClassId); if (!m_styleIndex.ContainsKey(styleKey)) { m_styleIndex.Add(styleKey, newStyle); count++; } else { if (log.IsWarnEnabled) log.WarnFormat("Specialization {0} - Duplicate Style Key, StyleID {1} : ClassID {2}, Ignored...", spec.KeyName, newStyle.ID, specStyle.ClassId); } // load Procs if (specStyle.AttachedProcs != null) { foreach (DBStyleXSpell styleProc in specStyle.AttachedProcs) { if (m_spellIndex.ContainsKey(styleProc.SpellID)) { if (!m_stylesProcs.ContainsKey(specStyle.ID)) { m_stylesProcs.Add(specStyle.ID, new Dictionary<int, Tuple<Spell, int>>()); } if (!m_stylesProcs[specStyle.ID].ContainsKey(styleProc.ClassID)) m_stylesProcs[specStyle.ID].Add(styleProc.ClassID, new Tuple<Spell, int>(m_spellIndex[styleProc.SpellID], styleProc.Chance)); } } } } } // We've added all the styles to their respective lists. Now lets go through and sort them by their level foreach (string keyname in m_specsStyles.Keys) { foreach (int classid in m_specsStyles[keyname].Keys) m_specsStyles[keyname][classid].Sort((i, j) => i.Item2.CompareTo(j.Item2)); } str.AppendFormat("{0} Styles", count); if (log.IsDebugEnabled) log.Debug(str.ToString()); // Add spec to global Spec Index Cache if (!m_specsByName.ContainsKey(spec.KeyName)) { m_specsByName.Add(spec.KeyName, entry); } else { if (log.IsWarnEnabled) log.WarnFormat("Specialization {0} is duplicated ignoring...", spec.KeyName); } } specs = null; } if (log.IsInfoEnabled) log.InfoFormat("Total specializations loaded: {0}", m_specsByName.Count); } finally { m_syncLockUpdates.ExitWriteLock(); } return m_specsByName.Count; }
/// <summary> /// Get List of Spell, ClassId, Chance Constraints for this Style Procs... /// </summary> /// <param name="style"></param> /// <returns></returns> public static IList<Tuple<Spell, int, int>> GetStyleProcsByID(Style style) { List<Tuple<Spell, int, int>> procres = new List<Tuple<Spell, int, int>>(); m_syncLockUpdates.EnterReadLock(); Dictionary<int, Tuple<Spell, int>> entries = new Dictionary<int, Tuple<Spell, int>>(); try { if (m_stylesProcs.ContainsKey(style.ID)) { entries = new Dictionary<int, Tuple<Spell, int>>(m_stylesProcs[style.ID]); } } finally { m_syncLockUpdates.ExitReadLock(); } foreach(KeyValuePair<int, Tuple<Spell, int>> item in entries) procres.Add(new Tuple<Spell, int, int>(item.Value.Item1, item.Key, item.Value.Item2)); return procres; }
/// <summary> /// Add a new style to a specialization. If the specialization does not exist it will be created. /// After adding all styles call SortStyles to sort the list by level /// </summary> /// <param name="style"></param> public static void AddScriptedStyle(Specialization spec, DBStyle style) { m_syncLockUpdates.EnterWriteLock(); try { if (!m_specsStyles.ContainsKey(spec.KeyName)) m_specsStyles.Add(spec.KeyName, new Dictionary<int, List<Tuple<Style, byte>>>()); if (!m_specsStyles[spec.KeyName].ContainsKey(style.ClassId)) m_specsStyles[spec.KeyName].Add(style.ClassId, new List<Tuple<Style, byte>>()); Style st = new Style(style); m_specsStyles[spec.KeyName][style.ClassId].Add(new Tuple<Style, byte>(st, (byte)style.SpecLevelRequirement)); KeyValuePair<int, int> styleKey = new KeyValuePair<int, int>(st.ID, style.ClassId); if (!m_styleIndex.ContainsKey(styleKey)) m_styleIndex.Add(styleKey, st); if (!m_specsByName.ContainsKey(spec.KeyName)) RegisterSpec(spec); } finally { m_syncLockUpdates.ExitWriteLock(); } }
/// <summary> /// Add a new style to a specialization. If the specialization does not exist it will be created. /// After adding all styles call SortStyles to sort the list by level /// </summary> /// <param name="style"></param> public static void AddScriptedStyle(Specialization spec, DBStyle style) { string hashKey = string.Format("{0}|{1}", style.SpecKeyName, style.ClassId); List<Style> styleList; if (!m_styleLists.TryGetValue(hashKey, out styleList)) { styleList = new List<Style>(); m_styleLists.Add(hashKey, styleList); } Style st = new Style(style); //(procs) Add procs to the style, 0 is used for normal style if (m_styleSpells.ContainsKey(st.ID)) { // now we add every proc to the style (even if ClassID != 0) foreach (byte classID in Enum.GetValues(typeof(eCharacterClass))) { if (m_styleSpells[st.ID].ContainsKey(classID)) { foreach (DBStyleXSpell styleSpells in m_styleSpells[st.ID][classID]) st.Procs.Add(styleSpells); } } } styleList.Add(st); KeyValuePair<int, int> styleKey = new KeyValuePair<int, int>(st.ID, style.ClassId); if (!m_stylesByIDClass.ContainsKey(styleKey)) m_stylesByIDClass.Add(styleKey, st); if (!m_specsByName.ContainsKey(spec.KeyName)) RegisterSpec(spec); }
public static int LoadSpecializations() { var specs = GameServer.Database.SelectAllObjects<DBSpecialization>(); if (specs != null) { m_specsByName.Clear(); m_styleLists.Clear(); m_stylesByIDClass.Clear(); foreach (DBSpecialization spec in specs) { if (spec.Styles != null) { foreach (DBStyle specStyle in spec.Styles) { string hashKey = string.Format("{0}|{1}", specStyle.SpecKeyName, specStyle.ClassId); List<Style> styleList; if (!m_styleLists.TryGetValue(hashKey, out styleList)) { styleList = new List<Style>(); m_styleLists.Add(hashKey, styleList); } Style style = new Style(specStyle); //(procs) Add procs to the style, 0 is used for normal style if (m_styleSpells.ContainsKey(style.ID)) { // now we add every proc to the style (even if ClassID != 0) foreach (byte classID in Enum.GetValues(typeof(eCharacterClass))) { if (m_styleSpells[style.ID].ContainsKey(classID)) { foreach (DBStyleXSpell styleSpells in m_styleSpells[style.ID][classID]) style.Procs.Add(styleSpells); } } } styleList.Add(style); KeyValuePair<int, int> styleKey = new KeyValuePair<int, int>(style.ID, specStyle.ClassId); if (!m_stylesByIDClass.ContainsKey(styleKey)) { m_stylesByIDClass.Add(styleKey, style); } } } RegisterSpec(new Specialization(spec.KeyName, spec.Name, spec.Icon)); int specAbCount = 0; if (m_specAbilities.ContainsKey(spec.KeyName)) { specAbCount = m_specAbilities[spec.KeyName].Count; } if (log.IsDebugEnabled) { int styleCount = 0; if (spec.Styles != null) { styleCount = spec.Styles.Length; } log.Debug("Specialization: " + spec.Name + ", " + styleCount + " styles, " + specAbCount + " abilities"); } } // We've added all the styles to their respective lists. Now lets go through and sort them by their level SortStylesByLevel(); } if (log.IsInfoEnabled) log.Info("Total specializations loaded: " + ((specs != null) ? specs.Count : 0)); return (specs != null) ? specs.Count : 0; }
/// <summary> /// Creates a new style line /// </summary> /// <param name="keyName">The key name of this styleLine</param> /// <param name="name">The name of this styleLine, eg. "Blades"</param> /// <param name="styles">The styles for this StyleLine</param> public StyleLine(string keyName, string name, Style[] styles) : base(keyName, name, 0) { m_styles = styles; }
protected override AttackData MakeAttack(GameObject target, InventoryItem weapon, Style style, double effectiveness, int interruptDuration, bool dualWield) { if (target is GamePlayer) { if (Util.Chance(10)) { StealToken(target as GamePlayer); } } return base.MakeAttack(target, weapon, style, effectiveness, interruptDuration, dualWield); }