private bool IsWithinArticulationLimits(WoWUnit vehicle, WoWUnit potentialTarget) { if ((vehicle == null) || !vehicle.IsValid) { return(false); } if ((potentialTarget == null) || !potentialTarget.IsValid) { return(false); } double neededAzimuth = Math.Atan((potentialTarget.Location.Z - vehicle.Location.Z) / vehicle.Location.Distance2D(potentialTarget.Location)); double neededFacing = WoWMathHelper.CalculateNeededFacing(vehicle.Location, potentialTarget.Location); neededFacing = WoWMathHelper.NormalizeRadian((float)neededFacing); if ((neededFacing < CannonArticulation_HeadingMin) || (neededFacing > CannonArticulation_HeadingMax)) { return(false); } if ((neededAzimuth < CannonArticulation_AzimuthMin) || (neededAzimuth > CannonArticulation_AzimuthMax)) { return(false); } return(true); }
private async Task <bool> UtilityCoroutine_MoveAndUseCatapult() { if (!Query.IsInVehicle() || !IsViable(SelectedCatapult)) { return(false); } // Move vehicle into position... if (!Navigator.AtLocation(CurrentTask.PositionForLaunch)) { Navigator.MoveTo(CurrentTask.PositionForLaunch); return(true); } // Adjust heading... if (!WoWMathHelper.IsFacing(WoWMovement.ActiveMover.Location, GetVehicleFacing(), CurrentTask.PositionToLand, WoWMathHelper.DegreesToRadians(0.5f))) { // Handle heading... double neededHeading = WoWMathHelper.CalculateNeededFacing(Me.Location, CurrentTask.PositionToLand); neededHeading = WoWMathHelper.NormalizeRadian((float)neededHeading); QBCLog.Info("Adjusting firing heading"); Me.SetFacing((float)neededHeading); await Coroutine.Sleep(200); return(true); } // Adjust azimuth... double currentAzimuth = WoWMathHelper.NormalizeRadian(Lua.GetReturnVal <float>("return VehicleAimGetAngle();", 0)); double neededAzimuth = NormalizeAngleToPi(CurrentTask.NeededAzimuth); double azimuthChangeRequired = neededAzimuth - currentAzimuth; if (Math.Abs(azimuthChangeRequired) >= 0.01) { QBCLog.Info("Adjusting firing azimuth"); // NB: VehicleAimIncrement() handles negative values of 'increment' correctly... Lua.DoString("VehicleAimIncrement({0})", azimuthChangeRequired); await Coroutine.Sleep(200); return(true); } // Fire.. QBCLog.Info("Firing Catapult"); Lua.DoString(Lua_LaunchCommand); await Coroutine.Wait(3000, () => !Query.IsInVehicle()); return(true); }
public static bool IsFacing2D(WoWPoint me, float myFacingRadians, WoWPoint target, float arcRadians) { me.Z = target.Z = 0; arcRadians = WoWMathHelper.NormalizeRadian(arcRadians); float num = WoWMathHelper.CalculateNeededFacing(me, target); float num2 = WoWMathHelper.NormalizeRadian(num - myFacingRadians); if (num2 > 3.1415926535897931) { num2 = (float)(6.2831853071795862 - num2); } bool result = (num2 <= arcRadians / 2f); return(result); }
internal static bool TestLineOfSight(C_WoWObject obj) { if (obj.LineofsightResult && obj.Distance <= obj.InteractRange) { return(true); } if (!obj._lineofSightWaitTimer.IsFinished && (obj.Distance > 30f || obj.LineofSightWaitTimer.TimeLeft.TotalMilliseconds > 750)) { return(obj.LineofsightResult); } var neededFacing = WoWMathHelper.CalculateNeededFacing(Character.Player.Location, obj.Location); var testPoints = new List <WoWPoint> { WoWMathHelper.GetPointAt(obj.Location, obj.InteractRange, neededFacing - 3.141593f, 0f), WoWMathHelper.GetPointAt(obj.Location, obj.InteractRange, neededFacing - 2.356194f, 0f), WoWMathHelper.GetPointAt(obj.Location, obj.InteractRange, neededFacing - 1.570796f, 0f), WoWMathHelper.GetPointAt(obj.Location, obj.InteractRange, neededFacing - 0.7853982f, 0f), WoWMathHelper.GetPointAt(obj.Location, obj.InteractRange, neededFacing, 0f), WoWMathHelper.GetPointAt(obj.Location, obj.InteractRange, neededFacing + 3.141593f, 0f), WoWMathHelper.GetPointAt(obj.Location, obj.InteractRange, neededFacing + 2.356194f, 0f), WoWMathHelper.GetPointAt(obj.Location, obj.InteractRange, neededFacing + 1.570796f, 0f), WoWMathHelper.GetPointAt(obj.Location, obj.InteractRange, neededFacing + 0.7853982f, 0f) }; foreach (var testPoint in testPoints) { if (GameWorld.IsInLineOfSight(Character.Player.TraceLinePosition, testPoint.Add(0f, 0f, 1.24f))) { obj.LineofsightResult = true; obj._lineofsightPoint = testPoint; break; } } obj.LineofSightWaitTimer.Reset(); return(obj.LineofsightResult); }
private Vector3 FindNewStationPoint(WoWUnit desiredTarget, double offsetRadians = 0.0) { if (!Query.IsViable(desiredTarget)) { desiredTarget = FindMobToKill(MobId_ScarletBallista); } var myLocation = WoWMovement.ActiveMover.Location; var preferredDistance = StyxWoW.Random.Next((int)TargetDistance2DMin + 1, (int)TargetDistance2DMax); var targetLocation = desiredTarget.Location; // To evade, we just rotate in a (counter-clockwise) circle around our selected target... var escapeHeading = WoWMathHelper.CalculateNeededFacing(targetLocation, myLocation); escapeHeading = WoWMathHelper.NormalizeRadian((float)(escapeHeading + offsetRadians + (TAU / 14))); var escapePoint = targetLocation.RayCast(escapeHeading, (float)preferredDistance); return(new Vector3(escapePoint.X, escapePoint.Y, targetLocation.Z).Add(0.0, 0.0, TargetHeightMinimum + TargetHeightVariance)); }
// NB: In WoW, larger headings are to left, and larger Azimuths are up private void AimAndFireCannon(WoWUnit vehicle, WoWUnit target) { // Handle heading... double traveltime = target.Distance / (NurongsCannonShot_FeetPerSecond * 3.0f /*feet to yards*/); WoWPoint targetLeadPoint = target.Location.RayCast(target.RenderFacing, (float)(target.MovementInfo.CurrentSpeed * traveltime)); float neededHeading = WoWMathHelper.CalculateNeededFacing(Me.Location, targetLeadPoint); neededHeading = WoWMathHelper.NormalizeRadian(neededHeading); Me.SetFacing(neededHeading); // Handle Azimuth... // "Location" is measured at the feet of the toon. We want to aim for the 'middle' of the toon's // height. double currentAzimuth = NormalizeAngleToPi(Lua.GetReturnVal <double>("return VehicleAimGetAngle();", 0)); double neededAzimuth = Math.Atan((target.Location.Z - vehicle.Location.Z + (GetBoundingHeight(target) / 2)) // Middle of toon height / vehicle.Location.Distance2D(target.Location)); neededAzimuth = NormalizeAngleToPi(neededAzimuth); // Execute fire... // NB: VehicleAimIncrement() handles negative values of 'increment' correctly... Lua.DoString("VehicleAimIncrement({0}); {1}", (neededAzimuth - currentAzimuth), NurongsCannonShot_LuaCommand); }
private Composite CreateCombatBehavior() { // NB: We'll be running right over some hostiles while in the barrel. // Even with a PullDistance set to one, HBcore and the CombatRoutine are going to try to pull these mobs. // Thus, this behavior runs at "higher than combat" priority, and prevents the CombatRoutine from executing // while this behavior is in progress. // // NB: We need to allow lower BT nodes to run when the behavior is finished; otherwise, HB will not // process the change of _isBehaviorDone state. return(new Decorator(context => !_isBehaviorDone, new PrioritySelector(context => _combatContext.Update(), // If quest is done, behavior is done... new Decorator(context => !UtilIsProgressRequirementsMet(QuestId, QuestRequirementInLog, QuestRequirementComplete), new Action(context => { _isBehaviorDone = true; QBCLog.Info("Finished"); })), // If not in Keg Bomb Vehicle, move to it and get inside... new Decorator(context => !Query.IsInVehicle() && (_combatContext.KegBomb != null), new PrioritySelector( new Decorator(context => _combatContext.KegBomb.Distance > _combatContext.KegBomb.InteractRange, new Action(context => { Navigator.MoveTo(_combatContext.KegBomb.Location); })), new Decorator(context => Me.IsMoving, new Action(context => { WoWMovement.MoveStop(); })), new Decorator(context => !Me.IsSafelyFacing(_combatContext.KegBomb), new Action(context => { _combatContext.KegBomb.Face(); })), new Sequence( // N.B. we need to wait a bit before jumping in vehicle after a round - // due to a bug that prevents bot from leaving vehicle until a relog new WaitContinue(2, context => false, new ActionAlwaysSucceed()), new Action(context => { _combatContext.ReInitialize(); _combatContext.KegBomb.Interact(); QBCLog.Info("Started barrel roll #{0}", ++_barrelRollCount); return RunStatus.Failure; })), new Wait(TimeSpan.FromMilliseconds(1000), context => false, new ActionAlwaysSucceed()) )), // If we are in the vehicle... new Decorator(context => Query.IsInVehicle() && (_combatContext.KegBombVehicle != null), new PrioritySelector( // If we've been in the barrel too long, just blow it up... // Blacklist whatever target we were after, and try again new Decorator(context => (_combatContext.BarrelRollingTimer.ElapsedMilliseconds > BarrelRollingTimeBeforeRetrying) && !_combatContext.IsKegIgnited, new Action(context => { QBCLog.Warning("We've been in the barrel too long--we're blowing it up to try again"); IgniteKeg(_combatContext); if (_combatContext.SelectedTarget != null) { Blacklist.Add(_combatContext.SelectedTarget, BlacklistFlags.Combat, TimeSpan.FromMinutes(3)); } })), // Select target, if not present... new Decorator(context => _combatContext.SelectedTarget == null, new Action(context => ChooseTarget(_combatContext))), // If we have a target, guide barrel to target... new Decorator(context => _combatContext.SelectedTarget != null, new Action(context => { float neededFacing = WoWMathHelper.CalculateNeededFacing(_combatContext.KegBombVehicle.Location, _combatContext.SelectedTarget.Location); neededFacing = WoWMathHelper.NormalizeRadian(neededFacing); float neededRotation = Math.Abs(neededFacing - _combatContext.KegBombVehicle.RenderFacing); neededRotation = WoWMathHelper.NormalizeRadian(neededRotation); // If we need to rotate heading 'too hard' to hit the target, then we missed the target... // Blow up the current barrel, blacklist the target, and try again if (((neededRotation > (Math.PI / 2)) && (neededRotation < ((Math.PI * 2) - (Math.PI / 2)))) && !_combatContext.IsKegIgnited) { QBCLog.Warning("We passed the selected target--igniting barrel to try again."); IgniteKeg(_combatContext); Blacklist.Add(_combatContext.SelectedTarget, BlacklistFlags.Combat, TimeSpan.FromMinutes(3)); } // Ignite the keg at the appropriate time... if (_combatContext.SelectedTarget.Distance <= IgniteDistance) { IgniteKeg(_combatContext); } // Guide the keg to target... Me.SetFacing(neededFacing); return RunStatus.Success; })) )) ))); }
private static async Task <bool> TrappingBehavior(bool inCombat) { if (TargetManager.CombatType != TargetManager.CombatFlags.Trapping || !TargetManager.CombatObject.Trappable) { return(false); } bool withinTrapDistance = TargetManager.CombatObject.Distance <= TargetManager.PullDistance; var traps = nearbyTraps; if (traps.Count == 0 && withinTrapDistance) { if (Player.Inventory.Trap != null) { if (Player.Inventory.Trap.ref_WoWItem.Usable && !Player.Inventory.Trap.OnCooldown) { TreeRoot.StatusText = "Trapping Behavior"; Player.Inventory.Trap.Use(); await CommonCoroutines.SleepForRandomUiInteractionTime(); return(true); } } } if (inCombat) { TreeRoot.StatusText = "Trapping Behavior"; //We want to move the target to our trap.. // -If we don't have aggro than we should move to the target // -Else we should wait near our trap. if (!TargetManager.CombatObject.IsTargetingMe) { //Wait for movement.. if (!withinTrapDistance) { return(false); } } else { //Move to nearest trap.. if (traps.Count > 0) { var nearestTrap = traps[0]; var distance = nearestTrap.Location.Distance(TargetManager.CombatObject.Location); if (distance > 1.5f || _trapMovement == null) { if (_trapMovement == null || _trapMovement.CurrentMovementQueue.Count == 0) { //Get the current side facing flipped! float requiredFacingDegrees = WoWMathHelper.RadiansToDegrees( WoWMathHelper.CalculateNeededFacing( TargetManager.CombatObject.Location, nearestTrap.Location)); _trapMovement = new Movement( nearestTrap.GetSidePoint(requiredFacingDegrees, 8f), 5f, "Trap Point"); } if (_trapMovement != null) { await _trapMovement.MoveTo(); } return(true); } } } } else if (withinTrapDistance) //Not in Combat { if (RoutineManager.Current.CombatBehavior != null && await RoutineManager.Current.CombatBehavior.ExecuteCoroutine()) { TreeRoot.StatusText = "Combat Behavior"; return(true); } } return(false); }
public static Composite CreateHolyHealOnlyBehavior(bool selfOnly, bool moveInRange) { // Atonement - Tab 1 index 10 - 1/2 pts HealerManager.NeedHealTargeting = true; return(new PrioritySelector( ret => selfOnly ? StyxWoW.Me : HealerManager.Instance.FirstUnit, new Decorator( ret => ret != null && (moveInRange || ((WoWUnit)ret).InLineOfSpellSight && ((WoWUnit)ret).DistanceSqr < 40 * 40), new PrioritySelector( Spell.WaitForCast(), new Decorator( ret => moveInRange, Movement.CreateMoveToLosBehavior(ret => (WoWUnit)ret)), Spell.Cast("Shadowfiend", ret => StyxWoW.Me.ManaPercent <= 80 && StyxWoW.Me.GotTarget), Spell.BuffSelf("Desperate Prayer", ret => StyxWoW.Me.HealthPercent <= 50), Spell.BuffSelf("Hymn of Hope", ret => StyxWoW.Me.ManaPercent <= 15 && (!SpellManager.HasSpell("Shadowfiend") || SpellManager.Spells["Shadowfiend"].Cooldown)), Spell.BuffSelf("Divine Hymn", ret => Unit.NearbyFriendlyPlayers.Count(p => p.HealthPercent <= SingularSettings.Instance.Priest.DivineHymnHealth) >= SingularSettings.Instance.Priest.DivineHymnCount), Spell.BuffSelf("Chakra"), Spell.Cast( "Prayer of Mending", ret => (WoWUnit)ret, ret => ret is WoWPlayer && Group.Tanks.Contains((WoWPlayer)ret) && !((WoWUnit)ret).HasMyAura("Prayer of Mending", 3) && Group.Tanks.Where(t => t != (WoWPlayer)ret).All(p => !p.HasMyAura("Prayer of Mending"))), Spell.Heal( "Renew", ret => (WoWUnit)ret, ret => ret is WoWPlayer && Group.Tanks.Contains((WoWPlayer)ret) && !((WoWUnit)ret).HasMyAura("Renew")), Spell.Heal("Prayer of Healing", ret => (WoWUnit)ret, ret => StyxWoW.Me.HasAura("Serendipity", 2) && Unit.NearbyFriendlyPlayers.Count(p => p.HealthPercent <= SingularSettings.Instance.Priest.PrayerOfHealingSerendipityHealth) >= SingularSettings.Instance.Priest.PrayerOfHealingSerendipityCount), Spell.Heal("Circle of Healing", ret => (WoWUnit)ret, ret => Unit.NearbyFriendlyPlayers.Count(p => p.HealthPercent <= SingularSettings.Instance.Priest.CircleOfHealingHealth) >= SingularSettings.Instance.Priest.CircleOfHealingCount), Spell.CastOnGround( "Holy Word: Sanctuary", ret => Clusters.GetBestUnitForCluster(Unit.NearbyFriendlyPlayers.Select(p => p.ToUnit()), ClusterType.Radius, 10f).Location, ret => Clusters.GetClusterCount((WoWUnit)ret, Unit.NearbyFriendlyPlayers.Select(p => p.ToUnit()), ClusterType.Radius, 10f) >= 4), Spell.Heal( "Holy Word: Serenity", ret => (WoWUnit)ret, ret => ret is WoWPlayer && Group.Tanks.Contains((WoWPlayer)ret)), Spell.Buff("Guardian Spirit", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent <= 10), Spell.CastOnGround("Lightwell", ret => StyxWoW.Me.Location.RayCast(WoWMathHelper.CalculateNeededFacing(StyxWoW.Me.Location, ((WoWUnit)ret).Location), 15f)), Spell.Heal( "Flash Heal", ret => (WoWUnit)ret, ret => StyxWoW.Me.HasAura("Surge of Light") && ((WoWUnit)ret).HealthPercent <= 90), Spell.Heal( "Flash Heal", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent < SingularSettings.Instance.Priest.HolyFlashHeal), Spell.Heal( "Greater Heal", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent < SingularSettings.Instance.Priest.HolyGreaterHeal), Spell.Heal( "Heal", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent < SingularSettings.Instance.Priest.HolyHeal), new Decorator( ret => StyxWoW.Me.Combat && StyxWoW.Me.GotTarget && Unit.NearbyFriendlyPlayers.Count(u => u.IsInMyPartyOrRaid) == 0, new PrioritySelector( Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Helpers.Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), Spell.Buff("Shadow Word: Pain", true), Spell.Cast("Holy Word: Chastise"), Spell.Cast("Holy Fire"), Spell.Cast("Smite"), Movement.CreateMoveToTargetBehavior(true, 35f) )), new Decorator( ret => moveInRange, Movement.CreateMoveToTargetBehavior(true, 35f, ret => (WoWUnit)ret)) // Divine Hymn // Desperate Prayer // Prayer of Mending // Prayer of Healing // Power Word: Barrier // TODO: Add smite healing. Only if Atonement is talented. (Its useless otherwise) )))); }