private void updateLastUsedAbilities(Skill lastusedskill) { int lastusedskillINDEX=LastUsedAbilities.IndexOf(lastusedskill); Skill[] clone_lastusedabilities = new Skill[LastUsedAbilities.Length]; LastUsedAbilities.CopyTo(clone_lastusedabilities, 0); LastUsedAbilities[0] = lastusedskill; //Increase the index of all skills above the last used skill index. for (int i = 0; i < lastusedskillINDEX; i++) { LastUsedAbilities[i + 1] = clone_lastusedabilities[i]; } }
///<summary> ///Searches for any abilities that have set the OutOfCombat Movement Criteria. ///</summary> internal Vector3 FindOutOfCombatMovementPower(out Skill MovementAbility, Vector3 Destination) { MovementAbility = null; foreach (var item in Abilities.Values.Where(A => A.FOutOfCombatMovement != null)) { if (item.CheckPreCastConditionMethod()) { Vector3 AbilityTargetVector = item.FOutOfCombatMovement.Invoke(Destination); if (AbilityTargetVector != Vector3.Zero) { MovementAbility = item; return AbilityTargetVector; } } } return Vector3.Zero; }
internal virtual void RecreateAbilities() { ContainsAnyPrimarySkill = false; ContainsNonRangedCombatSkill = false; ContainsPiercingSkill = false; Abilities = new Dictionary<SNOPower, Skill>(); var uninitalizedSkills=new Dictionary<SNOPower, Skill>(); //Create the abilities foreach (var item in Hotbar.HotbarSkills) { Skill newAbility = FunkyGame.Hero.Class.CreateAbility(item.Power); if (newAbility.IsPrimarySkill) ContainsAnyPrimarySkill = true; //combat ability set property if (ObjectCache.CheckFlag((SkillExecutionFlags.ClusterLocation | SkillExecutionFlags.ClusterTarget | SkillExecutionFlags.ClusterTargetNearest | SkillExecutionFlags.Location | SkillExecutionFlags.Target), newAbility.ExecutionType)) newAbility.IsCombat = true; if (!ContainsNonRangedCombatSkill && !newAbility.IsRanged && !newAbility.IsProjectile && ObjectCache.CheckFlag((SkillExecutionFlags.Target | SkillExecutionFlags.ClusterTarget), newAbility.ExecutionType)) ContainsNonRangedCombatSkill = true; uninitalizedSkills.Add(item.Power,newAbility); Logger.DBLog.DebugFormat("[Funky] Added Skill {0} using RuneIndex {1}", newAbility.Power, newAbility.RuneIndex); } foreach (var item in uninitalizedSkills) { Skill skill = item.Value; skill.Initialize(); if (skill.IsPrimarySkill) ContainsAnyPrimarySkill = true; if (skill.IsPiercing) ContainsPiercingSkill = true; Skill.CreateSkillLogicConditions(ref skill); skill.SuccessfullyUsed += AbilitySuccessfullyUsed; Abilities.Add(item.Key, skill); Logger.DBLog.DebugFormat("[Funky] Skill {0} has been initalized", item.Key); } //Sort Abilities SortedAbilities = Abilities.Values.OrderByDescending(a => a.Priority).ThenBy(a => a.Range).ToList(); //No default rage generation Ability.. then we add the Instant Melee Ability. if (!ContainsAnyPrimarySkill) { Skill defaultAbility = FunkyGame.Hero.Class.DefaultAttack; defaultAbility.Initialize(); Skill.CreateSkillLogicConditions(ref defaultAbility); Abilities.Add(defaultAbility.Power, defaultAbility); //Hotbar.RuneIndexCache.Add(defaultAbility.Power, -1); Logger.DBLog.DebugFormat("[Funky] Added Skill {0}", defaultAbility.Power); //No Primary Skill.. Check if Default Attack can be used! if (!FunkyBaseExtension.Settings.Combat.AllowDefaultAttackAlways) { Logger.DBLog.Warn("**** Warning ****"); Logger.DBLog.Warn("No Primary Skill Found and Allow Default Attack Always Is Disabled!"); Logger.DBLog.Warn("This may cause idles to occur.. Enable AllowDefaultAttackAlways setting found under Combat Tab."); Logger.DBLog.Warn("**** Warning ****"); } } LastUsedAbilities = new Skill[Abilities.Count]; int indexCount = 0; foreach (var ability in Abilities.Values) { LastUsedAbilities[indexCount] = ability; indexCount++; } // if (AC == ActorClass.Monk && Hotbar.HasPower(SNOPower.Monk_ExplodingPalm)) UsesDOTDPSAbility = true; if (AC == ActorClass.Witchdoctor && (Hotbar.HasPower(SNOPower.Witchdoctor_Haunt) || Hotbar.HasPower(SNOPower.Witchdoctor_Locust_Swarm))) UsesDOTDPSAbility = true; if (AC == ActorClass.Barbarian && Hotbar.HasPower(SNOPower.Barbarian_Rend)) UsesDOTDPSAbility = true; LastUsedAbility = LastUsedAbilities[0]; PowerPrime = DefaultAttack; }
///<summary> ///Returns a power for Buffing. ///</summary> internal bool FindBuffPower(out Skill BuffAbility) { BuffAbility = null; foreach (var item in Abilities.Values.Where(A => A.IsBuff)) { if (item.CheckPreCastConditionMethod()) { if (item.CheckBuffConditionMethod()) { BuffAbility = item; Skill.SetupAbilityForUse(ref BuffAbility, null); return true; } } } return false; }
///<summary> ///Returns a power for Combat Buffing. ///</summary> internal bool FindCombatBuffPower(CacheUnit unit,out Skill BuffAbility) { BuffAbility = null; foreach (var item in Abilities.Values.Where(A => A.IsBuff && A.UseageType.HasFlag(SkillUseage.Combat | SkillUseage.Anywhere))) { if (item.CheckPreCastConditionMethod()) { if (item.CheckCombatConditionMethod(unit: unit)) { BuffAbility = item; Skill.SetupAbilityForUse(ref BuffAbility, unit); return true; } } } return false; }
private static void CreateTargetConditions(ref Skill ability) { //No Conditions Set by default.. (?? May have to verify Ability execution can be Target) //-- Ranged Abilities that do not set any single target conditions will never be checked for LOS. if (ability.SingleUnitCondition.Count == 0) { //No Default Conditions Set.. however if Ability uses target as a execution type then we implement the LOS conditions. if (ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.Target)) ability.SingleUnitCondition.Add(new UnitTargetConditions(TargetProperties.None)); else return; } //Attach Line of Sight Criteria to each entry foreach (UnitTargetConditions condition in ability.SingleUnitCondition) { var combatCriteria = condition.Criteria; CreateLineOfSightTargetCheck(ref combatCriteria, ability); condition.Criteria = combatCriteria; } }
internal void AbilitySuccessfullyUsed(Skill ability, bool reorderAbilities) { if (ability.IsCombat) { LastUsedACombatAbility = DateTime.Now; } LastUsedAbility = ability; //Only Sort When Non-Channeling! if (reorderAbilities) SortedAbilities = Abilities.Values.OrderByDescending(a => a.Priority).ThenByDescending(a => a.LastUsedMilliseconds).ToList(); }
private static void CreateLineOfSightTargetCheck(ref Func<CacheUnit, bool> CombatCriteria, Skill ability) { if (ability.IsRanged) { CombatCriteria += (unit) => { if (!unit.IgnoresLOSCheck && unit.IsTargetableAndAttackable) { LOSInfo LOSINFO = unit.LineOfSight; if (LOSINFO.LastLOSCheckMS > 2000) { //!LOSINFO.LOSTest(FunkyGame.Hero.Position, true, ServerObjectIntersection: ability.IsProjectile, Flags: NavCellFlags.AllowProjectile) if (!LOSINFO.LOSTest(FunkyGame.Hero.Position, true, false, ability.IsProjectile, ability.IsProjectile ? NavCellFlags.AllowProjectile:NavCellFlags.None)) { //Raycast failed.. reset LOS Check -- for valid checking. if (!LOSINFO.RayCast.Value || (LOSINFO.ObjectIntersection.HasValue && !LOSINFO.ObjectIntersection.Value)) { unit.RequiresLOSCheck = true; return false; } //if (LOSINFO.NavCellProjectile.HasValue && !LOSINFO.NavCellProjectile.Value) //NavCellFlag Walk Failed //{ // bool MovementException = ((FunkyGame.Targeting.Cache.CurrentUnitTarget.MonsterTeleport || FunkyGame.Targeting.Cache.CurrentTarget.IsTransformUnit) && FunkyGame.Targeting.Cache.CurrentUnitTarget.AnimState == AnimationState.Transform); // if (!MovementException) return false; //} } } //else if (LOSINFO.ObjectIntersection.HasValue && !LOSINFO.ObjectIntersection.Value) //{ // return false; //} } return true; }; } else if (ability.Range > 0) {//Melee CombatCriteria += (unit) => { if (!unit.IgnoresLOSCheck && unit.IsTargetableAndAttackable) { float radiusDistance = unit.RadiusDistance; //Check if within interaction range.. if (radiusDistance > ability.Range) { //Verify LOS walk LOSInfo LOSINFO = unit.LineOfSight; if (LOSINFO.LastLOSCheckMS > 2000)//||!LOSINFO.NavCellWalk.HasValue) { if (!LOSINFO.LOSTest(FunkyGame.Hero.Position, true, ServerObjectIntersection: false)) { //bool MovementException=((FunkyGame.Targeting.Cache.CurrentUnitTarget.MonsterTeleport||FunkyGame.Targeting.Cache.CurrentTarget.IsTransformUnit)&&FunkyGame.Targeting.Cache.CurrentUnitTarget.AnimState==Zeta.Internals.Actors.AnimationState.Transform); //Raycast failed.. reset LOS Check -- for valid checking. if (!LOSINFO.RayCast.Value) unit.RequiresLOSCheck = true; //else if (!LOSINFO.NavCellWalk.Value) //NavCellFlag Walk Failed //{ // bool MovementException = ((FunkyGame.Targeting.Cache.CurrentUnitTarget.MonsterTeleport || FunkyGame.Targeting.Cache.CurrentTarget.IsTransformUnit) && FunkyGame.Targeting.Cache.CurrentUnitTarget.AnimState == Zeta.Internals.Actors.AnimationState.Transform); // if (!MovementException) // return false; //} } } //else if (LOSINFO.NavCellWalk.HasValue&&!LOSINFO.NavCellWalk.Value) //{ // return false; //} } } return true; }; } }
private static void CreateClusterConditions(ref Skill ability) { if (ability.ClusterConditions.Count == 0) return; //if (ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.ClusterTarget) || ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.ClusterTargetNearest)) //{ // foreach (var condition in ability.ClusterConditions) // { // Func<bool> combatCriteria = condition.Criteria; // CreateLineOfSightTargetCheck(ref combatCriteria, ability); // condition.Criteria = combatCriteria; // } //} }
public static void UsePower(ref Skill ability) { if (!ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.RemoveBuff)) { ability.SuccessUsed = ZetaDia.Me.UsePower(ability.Power, ability.TargetPosition, ability.WorldID, ability.TargetACDGUID); } else { ZetaDia.Me.GetBuff(ability.Power).Cancel(); ability.SuccessUsed = true; } }
/// <summary> /// Resets usage variables and sets the target location or target ID depending on what condition passed. /// </summary> /// <param name="ability"></param> /// <param name="obj"></param> /// <param name="Destructible"></param> public static void SetupAbilityForUse(ref Skill ability, CacheObject obj, bool Destructible = false) { ability.MinimumRange = ability.Range; ability.TargetPosition_ = Vector3.Zero; ability._targetAcdguid = -1; ability.WaitLoopsBefore_ = ability.WaitVars.PreLoops; ability.WaitLoopsAfter_ = ability.WaitVars.PostLoops; ability.CanCastFlags = PowerManager.CanCastFlags.None; ability.SuccessUsed_ = null; ability.Target_ = null; ability.preActivationFinished = false; ability.ActivationFinished = false; ability.postActivationFinished = false; //Destructible Setup if (Destructible) { if (!ability.IsRanged) ability.MinimumRange = 8f; else ability.MinimumRange = 30f; bool LocationalAttack = (CacheIDLookup.hashDestructableLocationTarget.Contains(obj.SNOID) || DateTime.Now.Subtract(PowerCacheLookup.dictAbilityLastFailed[ability.Power]).TotalMilliseconds < 1000); if (LocationalAttack) { Vector3 attacklocation = obj.Position; if (!ability.IsRanged) { //attacklocation=MathEx.CalculatePointFrom(FunkyGame.Hero.Class_.Data.Position,Bot.Target.CurrentTarget.Position, 0.25f); attacklocation = MathEx.GetPointAt(FunkyGame.Hero.Position, 0.50f, Navigation.Navigation.FindDirection(FunkyGame.Hero.Position, obj.Position, true)); } else { attacklocation = MathEx.GetPointAt(obj.Position, 1f, Navigation.Navigation.FindDirection(obj.Position, FunkyGame.Hero.Position, true)); } attacklocation.Z = Navigation.Navigation.MGP.GetHeight(attacklocation.ToVector2()); ability.TargetPosition = attacklocation; } else { if (obj.AcdGuid.HasValue) ability.TargetACDGUID = obj.AcdGuid.Value; } return; } if (ability.LastConditionPassed == ConditionCriteraTypes.Cluster) { CacheUnit ClusterUnit; //Cluster Target -- Aims for Centeroid Unit if (ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.ClusterTarget) && CheckClusterConditions(ability.LastClusterConditionSuccessful)) //Cluster ACDGUID { ClusterUnit = FunkyGame.Targeting.Cache.Clusters.AbilityClusterCache(ability.LastClusterConditionSuccessful)[0].GetNearestUnitToCenteroid(); if (ClusterUnit.AcdGuid.HasValue) ability.TargetACDGUID = ClusterUnit.AcdGuid.Value; ability.Target_ = ClusterUnit; return; } //Cluster Location -- Aims for Center of Cluster if (ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.ClusterLocation) && CheckClusterConditions(ability.LastClusterConditionSuccessful)) //Cluster Target Position { ability.TargetPosition = (Vector3)FunkyGame.Targeting.Cache.Clusters.AbilityClusterCache(ability.LastClusterConditionSuccessful)[0].Midpoint; return; } //Cluster Location Nearest if (ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.ClusterLocationNearest) && CheckClusterConditions(ability.LastClusterConditionSuccessful)) //Cluster Target Position { ability.TargetPosition = FunkyGame.Targeting.Cache.Clusters.AbilityClusterCache(ability.LastClusterConditionSuccessful)[0].ListUnits[0].Position; return; } //Cluster Target Nearest -- Gets nearest unit in cluster as target. if (ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.ClusterTargetNearest) && CheckClusterConditions(ability.LastClusterConditionSuccessful)) //Cluster Target Position { ClusterUnit = FunkyGame.Targeting.Cache.Clusters.AbilityClusterCache(ability.LastClusterConditionSuccessful)[0].ListUnits[0]; if (ClusterUnit.AcdGuid.HasValue) ability.TargetACDGUID = ClusterUnit.AcdGuid.Value; ability.Target_ = ClusterUnit; return; } } if (ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.Location)) //Current Target Position { ability.TargetPosition = obj.Position; ability.Target_ = (CacheUnit)obj; } else if (ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.Self)) //Current Bot Position ability.TargetPosition = FunkyGame.Hero.Position; else if (ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.ZigZagPathing)) //Zig-Zag Pathing { FunkyGame.Navigation.vPositionLastZigZagCheck = FunkyGame.Hero.Position; if (FunkyGame.Hero.Class.ShouldGenerateNewZigZagPath()) FunkyGame.Hero.Class.GenerateNewZigZagPath(); ability.TargetPosition = FunkyGame.Navigation.vSideToSideTarget; } else if (ObjectCache.CheckFlag(ability.ExecutionType, SkillExecutionFlags.Target)) //Current Target ACDGUID { if (obj is CacheUnit) ability.Target_ = (CacheUnit)obj; if (obj.AcdGuid.HasValue) ability.TargetACDGUID = obj.AcdGuid.Value; } }
public static void CreateSkillLogicConditions(ref Skill ability) { //CreatePreCastConditions(ref ability.FcriteriaPreCast, ability); CreateTargetConditions(ref ability); CreateClusterConditions(ref ability); //Check if the 4 primary combat conditions are null -- and if the custom condition is not.. if (ability.SingleUnitCondition.Count == 0 && ability.ClusterConditions.Count == 0 && ability.FcriteriaCombat != null) ability.TestCustomCombatConditions = true; }