/// <summary> /// When Strafe should be cast /// </summary> private static bool StrafeCondition(SkillMeta meta) { meta.CastRange = 65f; //meta.ReUseDelay = 250; meta.TargetPositionSelector = ret => { var kitePoint = NavHelper.FindSafeZone(false, 0, CurrentTarget.Position, true, Trinity.ObjectCache, false); if (kitePoint == Vector3.Zero) { return(TargetUtil.GetZigZagTarget(CurrentTarget.Position, V.F("Barbarian.Whirlwind.ZigZagDistance"))); } else { return(kitePoint); } }; //meta.TargetPositionSelector = ret => NavHelper.FindSafeZone(false, 0, CurrentTarget.Position, true, Trinity.ObjectCache, false); meta.CastFlags = CanCastFlags.NoTimer; meta.RequiredResource = Math.Max(Settings.Combat.DemonHunter.StrafeMinHatred, 12); if (!Player.IsRooted) { return(true); } return(false); }
public SkillMeta(SkillMeta meta) { this.name = meta.name; this.req1 = new SkillReq(meta.req1); this.req2 = new SkillReq(meta.req2); this.effects = meta.effects; }
/// <summary> /// When Chakram should be cast. /// </summary> private static bool ChakramCondition(SkillMeta meta) { meta.CastRange = 50f; // Spam it for Shuriken Cloud buff if (Runes.DemonHunter.ShurikenCloud.IsActive && TimeSincePowerUse(SNOPower.DemonHunter_Chakram) >= 110000 && ((Player.PrimaryResource >= 10 && !IsWaitingForSpecial) || Player.PrimaryResource >= MinEnergyReserve)) { return(true); } // Always cast with Spines of Seething Hatred rune, grants 4 hatred if (Legendary.SpinesOfSeethingHatred.IsEquipped) { return(true); } // Monsters nearby if (TargetUtil.ClusterExists(45f, 4)) { return(true); } return(false); }
/// <summary> /// When Smoke Screen should be cast /// </summary> private static bool SmokeScreenCondition(SkillMeta meta) { meta.CastFlags = CanCastFlags.NoTimer; // Buff Already Active if (GetHasBuff(SNOPower.DemonHunter_ShadowPower)) { return(false); } // Mobs in range if (TargetUtil.AnyMobsInRange(15) || (Legendary.MeticulousBolts.IsEquipped && TargetUtil.AnyMobsInRange(60))) { return(true); } // Defensive Cast if ((Player.CurrentHealthPct <= 0.50 || Player.IsRooted || Player.IsIncapacitated)) { return(true); } // Spam Setting if (Settings.Combat.DemonHunter.SpamSmokeScreen) { return(true); } return(false); }
/// <summary> /// When spike trap should be cast /// </summary> private static bool SpikeTrapCondition(SkillMeta meta) { meta.TargetPositionSelector = SpikeTrapTargetSelector; if (LastPowerUsed != SNOPower.DemonHunter_SpikeTrap) { return(true); } return(false); }
/// <summary> /// When Fan of Knives should be cast /// </summary> private static bool FanOfKnivesCondition(SkillMeta meta) { meta.CastRange = 25f; if (TargetUtil.EliteOrTrashInRange(15) || TargetUtil.AnyTrashInRange(15f, 5, false)) { return(true); } return(false); }
/// <summary> /// When Marked for Death should be cast /// </summary> private static bool MarkedForDeathCondition(SkillMeta meta) { meta.CastRange = 100f; meta.CastFlags = CanCastFlags.NoTimer; if (!CurrentTarget.HasDebuff(SNOPower.DemonHunter_MarkedForDeath) && !SpellTracker.IsUnitTracked(CurrentTarget, SNOPower.DemonHunter_MarkedForDeath)) { return(true); } return(false); }
/// <summary> /// Where Spike trap should be cast /// </summary> private static Vector3 SpikeTrapTargetSelector(SkillMeta skillMeta) { // For distant monsters, try to target a little bit in-front of them (as they run towards us), if it's not a treasure goblin float reducedDistance = 0f; if (CurrentTarget.Distance > 17f && !CurrentTarget.IsTreasureGoblin) { reducedDistance = CurrentTarget.Distance - 17f; if (reducedDistance > 5f) { reducedDistance = 5f; } } return(MathEx.CalculatePointFrom(CurrentTarget.Position, Player.Position, CurrentTarget.Distance - reducedDistance)); }
/// <summary> /// When Vengeance should be cast /// </summary> private static bool VengeanceCondition(SkillMeta meta) { meta.CastFlags = CanCastFlags.NoTimer; if (!Settings.Combat.DemonHunter.VengeanceElitesOnly && TargetUtil.AnyMobsInRange(60f, 6)) { return(true); } if (TargetUtil.IsEliteTargetInRange(100f)) { return(true); } return(false); }
/// <summary> /// When Preperation should be cast /// </summary> private static bool PreperationCondition(SkillMeta meta) { meta.ReUseDelay = Runes.DemonHunter.FocusedMind.IsActive ? 15000 : 500; meta.CastFlags = CanCastFlags.NoTimer; if (!Runes.DemonHunter.Punishment.IsActive && Player.SecondaryResourcePct <= Settings.Combat.DemonHunter.PreperationResourcePct) { return(true); } if (Runes.DemonHunter.Punishment.IsActive && Player.PrimaryResourcePct <= Settings.Combat.DemonHunter.PreperationResourcePct && (TargetUtil.AnyElitesInRange(50f) || Enemies.Nearby.UnitCount > 5)) { return(true); } return(false); }
/// <summary> /// When Sentry should be cast /// </summary> /// <param name="meta"></param> /// <returns></returns> private static bool SentryCondition(SkillMeta meta) { meta.CastRange = 80f; meta.CastFlags = CanCastFlags.NoTimer; if (meta.Skill.Charges == 0) { return(false); } if (TargetUtil.AnyMobsInRange(65) && Trinity.PlayerOwnedDHSentryCount < MaxSentryCount) { return(true); } return(false); }
/// <summary> /// When Impale should be cast /// </summary> private static bool ImpaleCondition(SkillMeta meta) { meta.CastRange = 80f; // Not enough resource if (Player.PrimaryResource <= EnergyReserve) { return(false); } if (!TargetUtil.AnyMobsInRange(12, 4) && CurrentTarget.RadiusDistance <= 75f) { return(true); } return(false); }
/// <summary> /// Get a SkillMeta object /// </summary> /// <param name="skill"></param> /// <returns></returns> public static SkillMeta GetSkillMeta(Skill skill) { SkillMeta s; if (_skillMetas.TryGetValue(skill, out s)) { return(s); } Logger.LogVerbose("GetSkillInfo found no SkillMeta for {0}", skill.Name); var newMeta = new SkillMeta(skill); SetSkillMeta(newMeta); return(newMeta); }
/// <summary> /// When Cluster Arrow should be cast /// </summary> private static bool ClusterArrowCondition(SkillMeta meta) { meta.CastRange = 85f; // Natalyas - Wait for damage buff if (Sets.NatalyasVengeance.IsFullyEquipped && Player.PrimaryResource < 100 && !CacheData.Buffs.HasBuff(SNOPower.P2_ItemPassive_Unique_Ring_053)) { return(false); } // Stay above minimum resource level if (Player.PrimaryResource < EnergyReserve) { return(false); } return(true); }
/// <summary> /// Set skill to use an SkillMeta object /// </summary> public static void SetSkillMeta(SkillMeta newMeta) { if (newMeta.Skill == null) { Logger.Log("SkillInfo set attempt without a reference to a skill"); return; } SkillMeta oldMeta; if (_skillMetas.TryGetValue(newMeta.Skill, out oldMeta)) { oldMeta.Apply(newMeta); } else { _skillMetas.Add(newMeta.Skill, newMeta); } }
/// <summary> /// When Multishot should be cast /// </summary> private static bool MultiShotCondition(SkillMeta meta) { meta.CastRange = 70f; meta.CastFlags = CanCastFlags.NoPowerManager; meta.TargetUnitSelector = ret => TargetUtil.GetClosestUnit(); // Natalyas - Wait for damage buff if (Sets.NatalyasVengeance.IsFullyEquipped && Player.PrimaryResource < 100 && !CacheData.Buffs.HasBuff(SNOPower.P2_ItemPassive_Unique_Ring_053)) { return(false); } if (Sets.UnhallowedEssence.IsMaxBonusActive && TargetUtil.AnyMobsInRange(80f) || TargetUtil.ClusterExists(45, 2)) { return(true); } return(false); }
/// <summary> /// When Rapid Fire should be cast /// </summary> /// <param name="meta"></param> /// <returns></returns> private static bool RapidFireCondition(SkillMeta meta) { meta.CastFlags = CanCastFlags.NoTimer; meta.CastRange = 45f; // Stay above minimum resource level if (Player.PrimaryResource < EnergyReserve || Player.PrimaryResource < Settings.Combat.DemonHunter.RapidFireMinHatred) { return(false); } // Never use it twice in a row if (LastPowerUsed == SNOPower.DemonHunter_RapidFire) { return(false); } return(true); }
/// <summary> /// When Companion should be cast /// </summary> private static bool CompanionCondition(SkillMeta meta) { meta.CastFlags = CanCastFlags.NoTimer; // Use Spider Slow on 4 or more trash mobs in an area or on Unique/Elite/Champion if (Runes.DemonHunter.SpiderCompanion.IsActive && TargetUtil.ClusterExists(25f, 4) && TargetUtil.EliteOrTrashInRange(25f)) { return(true); } //Use Bat when Hatred is Needed if (Runes.DemonHunter.BatCompanion.IsActive && Player.PrimaryResourceMissing >= 60) { return(true); } // Use Boar Taunt on 3 or more trash mobs in an area or on Unique/Elite/Champion if (Runes.DemonHunter.BoarCompanion.IsActive && ((TargetUtil.ClusterExists(20f, 4) && TargetUtil.EliteOrTrashInRange(20f)) || (CurrentTarget.IsBossOrEliteRareUnique && CurrentTarget.Distance <= 20f))) { return(true); } // Ferrets used for picking up Health Globes when low on Health if (Runes.DemonHunter.FerretCompanion.IsActive && Trinity.ObjectCache.Any(o => o.Type == TrinityObjectType.HealthGlobe && o.Distance < 60f) && Player.CurrentHealthPct < EmergencyHealthPotionLimit) { return(true); } // Use Wolf Howl on Unique/Elite/Champion - Would help for farming trash, but trash farming should not need this - Used on Elites to reduce Deaths per hour if (Runes.DemonHunter.WolfCompanion.IsActive && (TargetUtil.AnyElitesInRange(100f) || TargetUtil.AnyMobsInRange(40, 8))) { return(true); } // Companion off CD if (Settings.Combat.DemonHunter.CompanionOffCooldown && TargetUtil.AnyMobsInRange(60)) { return(true); } return(false); }
void Start() { SkillMeta skillMeta = PBMetaManager.Instance.GetMeta <SkillMetaTable, SkillMeta>(100); Debug.Log("act id:" + skillMeta.actId); Debug.Log("name:" + skillMeta.name); Debug.Log("state hit:" + skillMeta.stateHit); Debug.Log("be Attack GainAnger:" + skillMeta.beAttackGainAnger); WeightFormulaMeta weightFormulaMeta = PBMetaManager.Instance.GetMeta <FormulaMetaTable, WeightFormulaMeta>(1); Debug.Log("weight:" + weightFormulaMeta.weight); Debug.Log("a:" + weightFormulaMeta.a); Debug.Log("unit:" + weightFormulaMeta.unit); FunctionFormulaMeta functionFormulaMeta = PBMetaManager.Instance.GetMeta <FormulaMetaTable, FunctionFormulaMeta>(0); Debug.Log("split weight:" + functionFormulaMeta.splitWeight); Debug.Log("split count:" + functionFormulaMeta.splitCount); Debug.Log("spore weight:" + functionFormulaMeta.sporeWeight); }
/// <summary> /// When Shadow Power should be cast /// </summary> private static bool ShadowPowerCondition(SkillMeta meta) { // Buff Already Active if (GetHasBuff(SNOPower.DemonHunter_ShadowPower)) { return(false); } // Not Enough Discipline if (Player.SecondaryResource < 14) { return(false); } // Used Recently if (TimeSincePowerUse(SNOPower.DemonHunter_ShadowPower) < 4500) { return(false); } // Low Health if (Player.CurrentHealthPct <= Trinity.PlayerEmergencyHealthPotionLimit && Player.SecondaryResource >= 14) { return(true); } // Defensive Cast if (Player.IsRooted || TargetUtil.AnyMobsInRange(15)) { return(true); } // Spam Setting if (Settings.Combat.DemonHunter.SpamShadowPower) { return(true); } return(false); }
/// <summary> /// When Rain of Vengeance should be cast /// </summary> private static bool RainOfVengeanceCondition(SkillMeta meta) { meta.CastRange = 90f; meta.CastFlags = CanCastFlags.NoTimer; if (Legendary.CrashingRain.IsEquipped) { meta.TargetPositionSelector = skillMeta => TargetUtil.GetBestClusterPoint(30f, 80f); } if (Settings.Combat.DemonHunter.RainOfVengeanceOffCD || Sets.NatalyasVengeance.IsEquipped) { return(true); } if (TargetUtil.ClusterExists(45f, 4) || TargetUtil.AnyElitesInRange(90f)) { return(true); } return(false); }
/// <summary> /// When Evasive fire should be cast /// </summary> /// <param name="meta"></param> /// <returns></returns> private static bool EvasiveFireCondition(SkillMeta meta) { if (Skills.DemonHunter.Multishot.IsActive || Skills.DemonHunter.Strafe.IsActive) { // Still generates resource when hitting nothing. if (CurrentTarget.IsBoss && !ShouldRefreshBastiansGeneratorBuff) { meta.CastRange = Skills.DemonHunter.Multishot.IsActive ? 80f : 40f; } meta.TargetUnitSelector = ret => TargetUtil.GetClosestUnit(); } if (Legendary.YangsRecurve.IsEquipped && Legendary.DeadMansLegacy.IsEquipped) { // Only use when we have to, it deals basically no damage, just generates resource and bastians buff. return((Player.PrimaryResourcePct < 0.5 || ShouldRefreshBastiansGeneratorBuff) && TargetUtil.AnyMobsInRange(80f)); } return(TargetUtil.AnyMobsInRange(80f)); }
/// <summary> /// When Elemental Arrow should be cast /// </summary> private static bool ElementalArrowCondition(SkillMeta meta) { meta.CastRange = 100f; // Stay above minimum resource level if (Player.PrimaryResource < EnergyReserve && !Legendary.Kridershot.IsEquipped) { return(false); } // Lightning DH if (Runes.DemonHunter.BallLightning.IsActive && Legendary.MeticulousBolts.IsEquipped) { meta.CastRange = 15f; } // Kridershot if (Legendary.Kridershot.IsEquipped) { meta.CastRange = 65f; } return(true); }
/// <summary> /// When Vault should be cast /// </summary> private static bool VaultCondition(SkillMeta meta) { meta.CastRange = 20f; meta.TargetPositionSelector = ret => NavHelper.MainFindSafeZone(Player.Position, true); meta.RequiredResource = Hotbar.Contains(SNOPower.DemonHunter_ShadowPower) ? 22 : 16; meta.ReUseDelay = Settings.Combat.DemonHunter.VaultMovementDelay; if (Settings.Combat.DemonHunter.VaultMode == DemonHunterVaultMode.MovementOnly && IsInCombat) { return(false); } if (Settings.Combat.DemonHunter.VaultMode == DemonHunterVaultMode.CombatOnly && !IsInCombat) { return(false); } if (!Player.IsRooted && (TargetUtil.AnyMobsInRange(7f, 6) || Player.CurrentHealthPct <= 0.7)) { return(true); } return(false); }
/// <summary> /// When Grenade should be cast /// </summary> private static bool GrenadeCondition(SkillMeta meta) { meta.CastRange = 40f; return(true); }
/// <summary> /// When Entangling Shot should be cast /// </summary> private static bool EntanglingShotCondition(SkillMeta meta) { meta.CastRange = 50f; return(true); }
/* * ai sometimes moves for player * gems sometimes given to player when they are not players gems */ public IEnumerator MoveAI() { bool hasSpecial = false; List <SkillMeta> compSkills = new List <SkillMeta>(PanelManager.instance.getComputerSkills()); for (int i = 0; i < compSkills.Count; i++) { bool ready = true; foreach (SkillReq req in new SkillReq[] { compSkills[i].req1, compSkills[i].req2 }) { if (req.has != req.req) { ready = false; } } if (ready) { hasSpecial = true; PanelManager.instance.setActiveSkill(i); yield return(new WaitForSeconds(.5f)); bool found = false; List <Tile> toPoke = new List <Tile>(); SkillMeta meta = compSkills[i]; foreach (SkillEffect eff in meta.effects) { if (eff.effect == SkillEffect.Effect.Poke || eff.effect == SkillEffect.Effect.Slice) { TileMeta.GemType tileType; if (eff.effect == SkillEffect.Effect.Poke) { tileType = ((SkillEffect.PokeSkill)eff).toRemove; } else { tileType = ((SkillEffect.SliceSkill)eff).toRemove; } for (int x = 0; x < xSize; x++) { for (int y = 0; y < ySize; y++) { if (tiles[x, y].GetComponent <Tile>().type.type == tileType) { toPoke.Add(tiles[x, y].GetComponent <Tile>()); } } } found = true; } } if (!found) { tiles[0, 0].GetComponent <Tile>().computerUseSkill(); } else if (toPoke.Count > 0) { Tile[] pkArr = toPoke.ToArray(); GameUtilities.ShuffleArray(pkArr); pkArr[0].computerUseSkill(); } yield return(new WaitForSeconds(.5f)); // while(IsShifting && IsProcessing){} //Debug.Log("IsShifting: " + isShifting().ToString()); Debug.Log("IsProcessing: " + IsThinking().ToString()); int counter = 0; int checksPassed = 0; while (checksPassed < 3 && counter < 30) { yield return(new WaitForSeconds(.25f)); counter++; if (!IsThinking()) { checksPassed++; } else { checksPassed = 0; } } //yield return new WaitForSeconds(.25f); StartCoroutine(loopAIMovement()); break; } } if (!hasSpecial) { // See which gems the computer needs to complete it's skills List <TileMeta.GemType> preferredGems = new List <TileMeta.GemType>(); preferredGems.Add(TileMeta.GemType.Fight); for (int i = 0; i < compSkills.Count; i++) { foreach (SkillReq req in new SkillReq[] { compSkills[i].req1, compSkills[i].req2 }) { if (req.has != req.req && !preferredGems.Contains(req.gem)) { preferredGems.Add(req.gem); } } } int counter = 0; int checksPassed = 0; while (checksPassed < 3 && counter < 30) { yield return(new WaitForSeconds(.25f)); counter++; if (!IsThinking()) { checksPassed++; } else { checksPassed = 0; } } List <coords> validMoves = new List <coords>(); List <coords> preferredMoves = new List <coords>(); int max = 0; int[,] tempBoard = new int[xSize, ySize]; for (int x = 0; x < xSize; x++) { for (int y = 0; y < ySize; y++) { tempBoard[x, y] = (int)tiles[x, y].GetComponent <Tile>().type.type; } } // board 0,0 = temp 0,9 List <Vector2> positions = new List <Vector2>(); int[,] scoreBoard = new int[xSize, ySize]; for (int x = 0; x < xSize; x++) { for (int y = 0; y < ySize; y++) { foreach (Vector2 dir in Tile.adjacentDirections) { int[,] copyBoard = tempBoard.Clone() as int[, ]; if (dir.x + x >= 0 && dir.x + x < xSize && dir.y + y >= 0 && dir.y + y < ySize) { int temp = copyBoard[(int)dir.x + x, (int)dir.y + y]; copyBoard[(int)dir.x + x, (int)dir.y + y] = copyBoard[x, y]; copyBoard[x, y] = temp; // At the two points selected, look out in all the directions and see if we've found a match int mtchA = returnBoardMatches(copyBoard, new Vector2(x, y)); int mtchB = returnBoardMatches(copyBoard, new Vector2((int)dir.x + x, (int)dir.y + y)); int score = mtchA > mtchB ? mtchA : mtchB; scoreBoard[x, y] = score; if (score > 2) { positions.Add(new Vector2(x, y)); validMoves.Add(new coords(tiles[x, y].GetComponent <Tile>(), dir)); if (preferredGems.Contains(tiles[x, y].GetComponent <Tile>().type.type)) { score++; } if (max < score) { Debug.Log("New Max!" + score.ToString()); preferredMoves.Clear(); max = score; } if (max == score) { preferredMoves.Add(new coords(tiles[x, y].GetComponent <Tile>(), dir)); } } } } } } coords[] moves = validMoves.ToArray(); coords[] prefMoves = preferredMoves.ToArray(); GameUtilities.ShuffleArray(moves); GameUtilities.ShuffleArray(prefMoves); if (prefMoves.Length > 0) { Debug.Log("prefMoves: " + prefMoves.Length.ToString()); prefMoves[0].tile.Select(); yield return(new WaitForSeconds(.6f)); prefMoves[0].tile.computerSwap(prefMoves[0].dir); moveWait = WaitForMovement(); StartCoroutine(moveWait); yield return(null); } else if (moves.Length > 0) { Debug.Log("moves: " + moves.Length.ToString()); Debug.Log("moves: " + moves.Length.ToString()); moves[0].tile.Select(); yield return(new WaitForSeconds(.6f)); moves[0].tile.computerSwap(moves[0].dir); moveWait = WaitForMovement(); StartCoroutine(moveWait); yield return(null); } else { // There aren't any moves to make, reset the board and try again reset(true); counter = 0; while (IsThinking() && counter < 30) { yield return(new WaitForSeconds(.25f)); counter++; Debug.Log("Counter: " + counter); //Debug.Log("IsShifting: " + isShifting().ToString()); Debug.Log("IsProcessing: " + IsThinking().ToString()); } //yield return new WaitForSeconds(.25f); StartCoroutine(loopAIMovement()); } } }
/// <summary> /// When Hungering Arrow should be cast /// </summary> private static bool HungeringArrowCondition(SkillMeta meta) { meta.CastRange = 50f; return(true); }
/// <summary> /// When Bolas should be cast /// </summary> private static bool BolasCondition(SkillMeta meta) { meta.CastRange = 50f; return(true); }
/// <summary> /// When Caltrops should be cast /// </summary> private static bool CaltropsCondition(SkillMeta meta) { return(TargetUtil.AnyMobsInRange(40) && !GetHasBuff(SNOPower.DemonHunter_Caltrops)); }