public override void OnPulse() { //don't run if we don't have a navigation provider if (Navigator.NavigationProvider == null) { return; } using (new PerformanceLogger("Pulse")) { //remove tracked avoidances that have completed var removable = _tracked.Where(i => !i.Condition() && AvoidanceManager.Avoids.All(z => z.AvoidInfo != i)).ToList(); if (removable.Any()) { Logger.Info($"Removing {removable.Count} completed spells"); AvoidanceManager.RemoveAllAvoids(i => removable.Contains(i)); _tracked.RemoveAll(x => removable.Contains(x)); } var newSpellCasts = GameObjectManager.GetObjectsOfType <BattleCharacter>() .Where(IsValid) .SelectMany(HandleNewCast) .ToList(); if (newSpellCasts.Any()) { _tracked.AddRange(newSpellCasts); //AvoidanceManager.AvoidInfos.AddRange(newSpellCasts); Logger.Info($"Added: {newSpellCasts.Count()} to the avoidance manager"); } } }
public override void OnPulse() { //don't run if we don't have a navigation provider if (Navigator.NavigationProvider == null) { return; } using (new PerformanceLogger("Pulse")) { //remove tracked avoidances that have completed var removeable = _tracked.Where(i => !i.Condition() && !AvoidanceManager.Avoids.Any(z => z.AvoidInfo == i)).ToList(); if (removeable.Any()) { Logger.Info($"Removing {removeable.Count()} completed spells"); AvoidanceManager.RemoveAllAvoids(i => removeable.Contains(i)); _tracked.RemoveAll(x => removeable.Contains(x)); } var newSpellCasts = GameObjectManager.GetObjectsOfType <BattleCharacter>() .Where(c => c.InCombat && !c.IsMe && c.StatusFlags.HasFlag(StatusFlags.Hostile) && c.CastingSpellId != 0 && IsNearby(c) && c.SpellCastInfo.SpellData.Omen != 0 && //skip spells that don't have an omen !AvoidanceManager.AvoidInfos.Any(s => s.Collection.Contains(c))) .GroupBy(p => p.ObjectId) .SelectMany(o => { var c = o.First(); if (_owners.ContainsKey((ulong)AvoiderType.Spell + c.CastingSpellId)) { Logger.Verbose($"{c.SpellCastInfo.SpellData.LocalizedName} [Spell][Id: {c.CastingSpellId}][Omen: {c.SpellCastInfo.SpellData.Omen}][RawCastType: {c.SpellCastInfo.SpellData.RawCastType}][ObjId: {c.ObjectId}]"); return(_owners[(ulong)AvoiderType.Spell + c.CastingSpellId].Handle(c)); } if (_owners.ContainsKey((ulong)AvoiderType.Omen + c.SpellCastInfo.SpellData.Omen)) { Logger.Verbose($"{c.SpellCastInfo.SpellData.LocalizedName} [Omen][Id: {c.CastingSpellId}][Omen: {c.SpellCastInfo.SpellData.Omen}][RawCastType: {c.SpellCastInfo.SpellData.RawCastType}][ObjId: {c.ObjectId}]"); return(_owners[(ulong)AvoiderType.Omen + c.SpellCastInfo.SpellData.Omen].Handle(c)); } if (_owners.ContainsKey((ulong)AvoiderType.CastType + c.SpellCastInfo.SpellData.RawCastType)) { Logger.Verbose($"{c.SpellCastInfo.SpellData.LocalizedName} [CastType][Id: {c.CastingSpellId}][Omen: {c.SpellCastInfo.SpellData.Omen}][RawCastType: {c.SpellCastInfo.SpellData.RawCastType}][ObjId: {c.ObjectId}]"); return(_owners[(ulong)AvoiderType.CastType + c.SpellCastInfo.SpellData.RawCastType].Handle(c)); } Logger.Verbose($"No Avoid info for: {c.SpellCastInfo.SpellData.LocalizedName} [None][Id: {c.CastingSpellId}][Omen: {c.SpellCastInfo.SpellData.Omen}][RawCastType: {c.SpellCastInfo.SpellData.RawCastType}][ObjId: {c.ObjectId}]"); return(null); }) .Where(i => i != null).ToList(); if (newSpellCasts.Any()) { _tracked.AddRange(newSpellCasts); //AvoidanceManager.AvoidInfos.AddRange(newSpellCasts); Logger.Info($"Added: {newSpellCasts.Count()} to the avoidance manager"); } } }
private void RemoveHook() { if (s_hook == null) { return; } TreeHooks.Instance.RemoveHook("Combat_Main", s_hook); Navigator.NavigationProvider = s_prevNavigator; // Make sure maps for the previous navigator are up-to-date var meshNav = Navigator.NavigationProvider as MeshNavigator; if (meshNav != null) { meshNav.UpdateMaps(); } s_prevNavigator = null; s_hook = null; foreach (var kv in s_avoidDictionary) { AvoidanceManager.RemoveAvoid(kv.Value); QBCLog.DeveloperInfo("Removed the \"{0}\" avoidance definition", kv.Key); } s_avoidDictionary.Clear(); BotEvents.OnPulse -= BotEvents_OnPulse; BotEvents.OnBotStopped -= BotEvents_OnBotStopped; BotEvents.Profile.OnNewOuterProfileLoaded -= Profile_OnNewOuterProfileLoaded; LootTargeting.Instance.RemoveTargetsFilter -= Instance_RemoveTargetsFilter; QBCLog.Info("Uninstalled avoidance system"); }
public override IEnumerable <AvoidInfo> OmenHandle(BattleCharacter spellCaster) { if (spellCaster.SpellCastInfo.SpellData.EffectRange > 45) { Logger.Info("Spell range is > 45. Does this require specific logic?"); } //var loc = spellCaster.SpellCastInfo.CastLocation != Vector3.Zero ? spellCaster.SpellCastInfo.CastLocation : spellCaster.Location; Vector3 center; float range = 0f; if (OmenOverrideManager.TryGetOverride(spellCaster.SpellCastInfo.ActionId, out var omenOverride)) { range = Range(spellCaster, out center, omenOverride.MatrixOverride, omenOverride.RangeOverride); } else { range = Range(spellCaster, out center); } Logger.Info($"Avoid Cirlce: [{center}][Range: {range}]"); var cached = spellCaster.CastingSpellId; return(new[] { AvoidanceManager.AddAvoidLocation( () => spellCaster.IsValid && spellCaster.CastingSpellId == cached, //can run () => center, //LeashPoint 50f, //Leash Radius bc => range + 0.5f, //radiusProducer bc => center, //locationProducer () => new[] { spellCaster } //collectionProducer ) }); }
public void HookAvoidance() { avoidanceManager = new AvoidanceManager(Database); avoidanceBehavoir = avoidanceManager.GetAvoidanceBehavior(); TreeHooks.Instance.AddHook("PreCombatLogic", avoidanceBehavoir); Logger.WriteMessage("Avoidance hooked."); }
public override IEnumerable <AvoidInfo> OmenHandle(BattleCharacter spellCaster) { var cached = spellCaster.CastingSpellId; var square = Square(spellCaster); var result = new List <AvoidInfo>(); result.Add(AvoidanceManager.AddAvoidPolygon( () => spellCaster.IsValid && spellCaster.CastingSpellId == cached, null, 40f, bc => 0f, //rotation bc => 1.0f, //scale bc => 15.0f, //height bc => square, //points bc => spellCaster.Location, () => new[] { spellCaster } //objs )); result.Add(AvoidanceManager.AddAvoidPolygon( () => spellCaster.IsValid && spellCaster.CastingSpellId == cached, null, 40f, bc => (float)Math.PI, //rotation bc => 1.0f, //scale bc => 15.0f, //height bc => square, //points bc => spellCaster.Location, () => new[] { spellCaster } //objs )); result.Add(AvoidanceManager.AddAvoidPolygon( () => spellCaster.IsValid && spellCaster.CastingSpellId == cached, null, 40f, bc => - (float)Math.PI / 2, //rotation bc => 1.0f, //scale bc => 15.0f, //height bc => square, //points bc => spellCaster.Location, () => new[] { spellCaster } //objs )); result.Add(AvoidanceManager.AddAvoidPolygon( () => spellCaster.IsValid && spellCaster.CastingSpellId == cached, null, 40f, bc => (float)Math.PI / 2, //rotation bc => 1.0f, //scale bc => 15.0f, //height bc => square, //points bc => spellCaster.Location, () => new[] { spellCaster } //objs )); return(result); }
public void UnhookAvoidance() { avoidanceManager = null; if (avoidanceBehavoir != null) { TreeHooks.Instance.RemoveHook("PreCombatLogic", avoidanceBehavoir); } avoidanceBehavoir = null; Logger.WriteMessage("Avoidance unhooked."); }
public IEnumerable <AvoidInfo> AddCone(BattleCharacter spellCaster, float arcDegrees) { try { var cachedSpell = spellCaster.CastingSpellId; var m4x4 = spellCaster.OmenMatrix; //sin(0), 0, cos(0) m4x4.Transform(new Vector3(0, 0, 1), out var transformed); var center = m4x4.Center(); var depth = transformed.Distance2D(center); var d = transformed - center; var rot = MathEx.Rotation(d); var rad = (float)Math.Round(MathEx.NormalizeRadian(rot - spellCaster.Heading), 2); var me = Core.Me.Location; Logger.Info("Debug: Rotation: {0} vs Mob heading: {1} = {2}", rot, spellCaster.Heading, rad); return(new[] { AvoidanceManager.AddAvoidUnitCone <BattleCharacter>( () => spellCaster.IsValid && spellCaster.CastingSpellId == cachedSpell, //can run bc => bc.ObjectId == spellCaster.ObjectId, //object selector () => me, //LeashPoint 120, //leash size rad, //rotation depth, //radius / Depth arcDegrees * 1.55f, //arcDegrees bc => bc.Location ), //add something under the mob so we don't get hit by standing at the mobs location. AvoidanceManager.AddAvoidLocation( () => spellCaster.IsValid && spellCaster.CastingSpellId == cachedSpell, //can run spellCaster.CombatReach / 2, () => spellCaster.Location ) }); } catch (Exception ex) { Logger.Error("failed to make cone: {0}", ex); return(null); } }
//public async Task<bool> Handle(SpellCast spellCaster) //{ // var res = inside(spellCaster.CasterLocation, spellCaster.CasterHeading, spellCaster.Data.EffectRange, // spellCaster.Data.XAxisModified > 0 ? spellCast.Data.XAxisModified : spellCaster.Caster.CombatReach); // if (res.Item1) // { // await Help.MoveTo(res.Item2, spellCaster); // } // return Core.Me.IsMelee(); //} public override IEnumerable <AvoidInfo> OmenHandle(BattleCharacter spellCaster) { var cached = spellCaster.CastingSpellId; //var rotation = Rotation(spellCaster); //var cl = spellCaster.SpellCastInfo.CastLocation; var square = Square(spellCaster); return(new[] { AvoidanceManager.AddAvoidPolygon( () => spellCaster.IsValid && spellCaster.CastingSpellId == cached, null, 40f, bc => 0f, //rotation bc => 1.0f, //scale bc => 15.0f, //height bc => square, //points bc => spellCaster.Location, () => new[] { spellCaster } //objs ) }); }
public override void OnStart() { // Acquisition and checking of any sub-elements go here. // A common example: // HuntingGrounds = HuntingGroundsType.GetOrCreate(Element, "HuntingGrounds", HuntingGroundCenter); // IsAttributeProblem |= HuntingGrounds.IsAttributeProblem; // Let QuestBehaviorBase do basic initialization of the behavior, deal with bad or deprecated attributes, // capture configuration state, install BT hooks, etc. This will also update the goal text. var isBehaviorShouldRun = OnStart_QuestBehaviorCore(); if (isBehaviorShouldRun) { if (Command == CommandType.Remove) { if (s_avoidDictionary.ContainsKey(AvoidName)) { QBCLog.DeveloperInfo("Removing \"{0}\" avoid", AvoidName); var avoidInfo = s_avoidDictionary[AvoidName]; s_avoidDictionary.Remove(AvoidName); AvoidanceManager.RemoveAvoid(avoidInfo); } } else if (Command == CommandType.Add) { AvoidInfo avoidInfo = BuildAvoidInfo(); QBCLog.DeveloperInfo("Adding \"{0}\" avoid - Radius: {1}, ObjectId: ({2}), ObjectType: {3}", AvoidName, Radius, string.Join(", ", ObjectIds), ObjectType); s_avoidDictionary[AvoidName] = avoidInfo; AvoidanceManager.AddAvoid(avoidInfo); } } if (s_hook == null && s_avoidDictionary.Any()) { InstallHook(); } // remove hook if no avoid definitions are active else if (s_hook != null && !s_avoidDictionary.Any()) { RemoveHook(); } BehaviorDone(); }
public override IEnumerable <AvoidInfo> OmenHandle(BattleCharacter spellCaster) { if (spellCaster.SpellCastInfo.SpellData.EffectRange > 45) { Logger.Info("Spell range is > 45. Does this require specific logic?"); } //var loc = spellCaster.SpellCastInfo.CastLocation != Vector3.Zero ? spellCaster.SpellCastInfo.CastLocation : spellCaster.Location; var range = Range(spellCaster, out var center); Logger.Info($"Avoid Cirlce: [{center}][Range: {range}]"); var cached = spellCaster.CastingSpellId; return(new[] { AvoidanceManager.AddAvoidLocation( () => spellCaster.IsValid && spellCaster.CastingSpellId == cached, null, 40f, bc => range + 0.5f, bc => center, () => new[] { spellCaster } ) }); }
public static async Task <bool> Run() { // NOT TESTED #region Spell Filters HashSet <uint> Spells = new HashSet <uint>() { 16333, 16334 //Temporary Current , 16337, 16335, 16336 //Undersea Quake , 16338, 16339 //TidalWave (Preview and Execute) //,16328 //Drenching Pulse (Needs a way to avoid others) && Freak Wave //Needs Mechanic for Blue Circle with Red Squares over head to seperate , 16344 //Spinning Dive (Dive Bombs after Maelstrom) , 16376 //Surging Tsunami (Pushback Mechanic) //,16341 //Swirling Tsunami (Donut AOE) need way to detect if me or other player , 16332 //Killer Wave (Stacking Mechanic) //,16326 //Rip Current (Tank Buster to be coded later) }; #endregion #region Custom Mechanics HashSet <uint> SurgingTsunami = new HashSet <uint>() { 16376 }; if (SurgingTsunami.IsCasting() && Core.Me.CurrentHealthPercent > 0) { Logging.Write(Colors.Aquamarine, $"Dungeon Assist Eden Mechanic - Swirling Tsunami Handling - Triggered - To Center"); Vector3 _loc = new Vector3(99, 0, 99); while (Core.Me.Distance(_loc) > 2f) { await CommonTasks.MoveTo(_loc); await Coroutine.Yield(); } Logging.Write(Colors.Aquamarine, $"Dungeon Assist Eden Mechanic - Swirling Tsunami Handling - Sleeping"); await Coroutine.Sleep(3000); if (ActionManager.IsSprintReady) { ActionManager.Sprint(); await Coroutine.Wait(1000, () => !ActionManager.IsSprintReady); } Stopwatch sw = new Stopwatch(); sw.Start(); Logging.Write(Colors.Aquamarine, $"Dungeon Assist Eden Mechanic - Swirling Tsunami Handling - Sleeping 2"); await Coroutine.Sleep(1000); await Coroutine.Yield(); sw.Stop(); Logging.Write(Colors.Aquamarine, $"Dungeon Assist Eden Mechanic - Swirling Tsunami Handling - - Complete"); } #endregion /// Default (缺省) if (Spells.IsCasting() && Core.Me.CurrentHealthPercent > 0) { Logging.Write(Colors.Aquamarine, $"Dungeon Assist Eden Mechanic - Generic Default Handling - Triggered"); //Core.Me.ClearTarget(); //Clears Target await Coroutine.Sleep(700); while (Core.Me.Location.Distance2D(PartyManager.VisibleMembers.Where(x => !x.IsMe && x.BattleCharacter.IsAlive).FirstOrDefault().BattleCharacter.Location) > 1) { if (ActionManager.IsSprintReady) { ActionManager.Sprint(); await Coroutine.Wait(1000, () => !ActionManager.IsSprintReady); } //if (AvoidanceManager.IsRunningOutOfAvoid) //&& in that zone (Mechanics file is loaded only for this zone //{ AvoidanceManager.RemoveAllAvoids((info => true)); AvoidanceManager.ResetNavigation(); //} MovementManager.SetFacing(PartyManager.VisibleMembers.Where(x => !x.IsMe && x.BattleCharacter.IsAlive).FirstOrDefault().BattleCharacter.Location); Logging.Write(Colors.Aquamarine, $"Dungeon Assist Eden Mechanic - Generic Default Handling - Moving to Nearest Alive Party Character"); MovementManager.MoveForwardStart(); if (Core.Me.CurrentHealthPercent <= 0) { break; } Logging.Write(Colors.Aquamarine, $"Dungeon Assist Eden Mechanic - Generic Default Handling - Waiting"); await Coroutine.Sleep(100); MovementManager.MoveStop(); } Logging.Write(Colors.Aquamarine, $"Dungeon Assist Eden Mechanic - Generic Default Handling - Complete"); //await Coroutine.Sleep(1000); await Coroutine.Yield(); } return(false); }
private void BotEvents_OnPulse(object sender, EventArgs args) { AvoidanceManager.Pulse(); }