public override bool Do() { if (em == null) { return(true); // WTF! } // mount if we're really far away if (monster.DistanceToSelf >= mountRange) { if (PPather.PatherSettings.UseMount != "Never Mount") { if (PPather.PatherSettings.UseMount == "Always Mount" || (PPather.PatherSettings.UseMount == "Let Task Decide" && UseMount == true)) { Helpers.Mount.MountUp(); } } } if (GContext.Main.Me.Target != monster && tabSpam.IsReady && monster.DistanceToSelf < 50f && monster.Reaction != GReaction.Friendly) { GContext.Main.SendKey("Common.Target"); tabSpam.Reset(); } if (GetLocation().GetDistanceTo(to) > GContext.Main.MeleeDistance && monster.DistanceToSelf < 30f || updateTimer.IsReady) { // need a new path, monster moved to = GetLocation(); em = new EasyMover(ppather, to, false, true); updateTimer.Reset(); } MoveResult = em.move(howClose); if (MoveResult != EasyMover.MoveResult.Moving) { return(true); // done, can't do more } Location meLocation = new Location(GContext.Main.Me.Location); if (meLocation.GetDistanceTo(to) < howClose) { PPather.mover.Stop(); Helpers.Mount.Dismount(); monster.Face(PPather.PI / 8); return(true); } return(false); }
//Combat overrride public override GCombatResult KillTarget(GUnit Target, bool IsAmbush) { //Stop walking/turning Context.ReleaseSpinRun(); /* RecursiveBot 2.17.1 A * the following is the logical switch to control if the spell * shuffle function is called. This removes the randomizing of spells * but does not give the ability to cast them in any order. */ if (USE_SPELLSHUFFLE) { SpellShuffle(ref SPELL_ORDER); } SoulShardCount = CountSoulShards(); Reset(); //Call function to wait for player death if (Target.IsPlayer) { if (((GPlayer)Target).IsSameFaction) { Context.ClearTarget(); return GCombatResult.Success; } else if (FIGHT_BACK) { Context.Log("Attempting PVP..."); return PVP(Target); } else { Context.Log("No PVP"); WaitForPlayerDeath(); return GCombatResult.Died; } } //Send in pet and wait for predefined amount of time /* RecursiveBot 2.17.1 G * The following change was to ensure that multiple Petattacks weren't sent * due to the logic flow. */ if (Me.HasLivePet && PET_ATTACK && !Me.Pet.IsInCombat) { SendKey("Common.PetAttack"); //Context.Log("DBG - KillTarget Send Pet routine started!"); if (WAIT_FOR_PET_AGGRO) { Context.Log("Waiting for pet to approach target"); bool temp; temp = WaitForEngage(Target,(PET_AGGRO_DELAY * 1000)); if (temp) { Context.Log("Pet aggroed target"); } else { Context.Log("Pet failed to aggro target"); } } Thread.Sleep(500); } while (true) { //Refresh the target Target.Refresh(true); //Check the current GCombatResult GCombatResult CommonResult = Context.CheckCommonCombatResult((GMonster)Target, IsAmbush); //Return the GCombatResult if (CommonResult != GCombatResult.Unknown) { SoulShardCount = CountSoulShards(); if (USE_CONSUMESHADOWS) { TwoSecTimer.Reset(); while (!TwoSecTimer.IsReady) { Thread.Sleep(150); if (!Me.IsInCombat) { TwoSecTimer.ForceReady(); } } PetHealth(); } return CommonResult; } else if (Target.IsDead) { SoulShardCount = CountSoulShards(); if (USE_CONSUMESHADOWS) { TwoSecTimer.Reset(); while (!TwoSecTimer.IsReady) { Thread.Sleep(100); if (!Me.IsInCombat) { TwoSecTimer.ForceReady(); } } // PetHealth(); //Moved to outside of If statement to resolve pet deaths } return GCombatResult.Success; } PetHealth(); Target.Face(); if (Me.HasLivePet && PET_ATTACK && RETURN_PET && DoReturnPet && Target.Health < HealthToReturnPet && Target.DistanceToSelf > 10 && Target.Target == Me.Pet) { Context.Log("Returning the pet to me! Come to papa!"); SendKey("Common.PetFollow"); DoReturnPet = false; } if (Target.DistanceToSelf > PullDistance && Target.DistanceToSelf < (PullDistance + TARGET_DUMP_DISTANCE)) { Target.Approach(PullDistance - 2, false); } if (Target.DistanceToSelf > (PullDistance + TARGET_DUMP_DISTANCE)) { Context.ClearTarget(); return GCombatResult.Success; } //Stop Walking, Face Context.ReleaseSpinRun(); TargetUnit(Target, false); //Deal with players if (FIGHT_BACK) { //Decide what to do depending on what is returned switch (CheckPlayers(Target)) { case 0: break; case 1: Context.Log("Targeted by enemy faction, fighting back!"); return GCombatResult.SuccessWithAdd; case -1: Context.Log("Target by enemy faction but unable to target them"); break; } } //Deal with adds //Context.Log("DBG - Are we set to deal with adds?" + DEAL_WITH_ADDS); if (DEAL_WITH_ADDS) { // Context.Log("DBG - Starting Check Add's function call"); CheckAdds(Target); } //Check health //Context.Log("DBG - Me.IsInCombat is returning" + Me.IsInCombat); CheckHealth(Me.IsInCombat); //Changed Parameter from true to Me.IsInCombat //Check pet /* RecursiveBot 2.17.1 B * The following was changed to check if the player is mounted before running * CheckPet() due to the fact that checkpet would call for a resummon upon * finding a target and not having a pet. * This is a quick fix. Logic for checking a pet might need rework. */ if (!IsMounted(Me)) { CheckPet(); } if (!Target.IsDead) { //Cast Debuffs //Context.Log("DBG - Test Target Not Dead code initiated"); CastSequence(Target, false); ShadowCheck(Target); //Check various things if (PetHealth()) { } else if (DrainSoul(Target)) { } else if (DrainLife(Target, false)) { } else if (PrimaryAttack(Target)) { } else if (CheckMana(Target) && !IsMounted()) { } else LastResort(Target); } Thread.Sleep(150); } }
//Cast wand void Wand(GUnit Target) { Target.Face(); if (!Interface.IsKeyFiring("PL.Wand")) { SendKey("PL.Wand"); Thread.Sleep(MISCDELAY); } }
//Target a specified unit if not already targeted void TargetUnit(GUnit Target, bool FirstTarget) { Target.Refresh(true); if (Target.IsDead || (Me.TargetGUID == Target.GUID)) return; Target.Face(); Target.SetAsTarget(FirstTarget); }
//PVP combat function GCombatResult PVP(GUnit Target) { PVPTimer.Reset(); //Reset timers Reset(); //Sets an anchor to keep from getting too far away GLocation startLocation = Me.Location; //Send in pet and wait for predefined amount of time if (Me.HasLivePet && PET_ATTACK) { SendKey("Common.PetAttack"); } if (Target.DistanceToSelf > FearRange) Target.Approach(FearRange - 3, false); CastSpell("PL.Fear", Target); //While less than PVPTimer seconds passed... while (!PVPTimer.IsReady) { Target.Refresh(true); //If target is dead, return to start point and report Success if (Target.IsDead) { SoulShardCount = CountSoulShards(); Context.Log("Killed target, returning to start"); Movement.MoveToLocation(startLocation, 20, false); return GCombatResult.Success; } //If further than 40 away from start, return to start point and report Success else if (startLocation.DistanceToSelf > (PullDistance + TARGET_DUMP_DISTANCE)) { SoulShardCount = CountSoulShards(); Context.Log("Straying too far, returning to start"); Movement.MoveToLocation(startLocation, 20, false); return GCombatResult.Success; } Me.Refresh(true); if (Me.IsDead) { return GCombatResult.Died; } //If target further than PullDistance and less than 60, approach to PullDistance if (Target.DistanceToSelf > PullDistance && Target.DistanceToSelf < (PullDistance + TARGET_DUMP_DISTANCE)) Target.Approach(PullDistance - 3, false); if (Target.DistanceToSelf > (PullDistance + TARGET_DUMP_DISTANCE)) //Added 2.15 dump target if too far { Context.Log("We tried to fight " + Target.Name + " but we travelled > " + TARGET_DUMP_DISTANCE + " to fight him. Resetting!"); SendKey("Common.ClearTargetMacro"); if (Me.HasLivePet && RETURN_PET) { Context.Log("Recalling Pet."); SendKey("Common.PetFollow"); } return GCombatResult.Success; } //Stop Walking, Face Context.ReleaseSpinRun(); Target.Face(); TargetUnit(Target, false); //Check health CheckHealth(Me.IsInCombat); /* RecursiveBot 2.17.1 B * Following check is to ensure that we don't resummon a pet needlessly. Quick fix * to the summon new pet every time your mounted and have a target. */ if (!IsMounted(Me)) { CheckPet(); } if (!Target.IsDead) { //Cast Debuffs CastSequence(Target, false); //Cast Fear if (Fear.IsReady) { if (Target.DistanceToSelf > FearRange) Target.Approach(FearRange - 3, false); CastSpell("PL.Fear", Target); Fear.Reset(); } ShadowCheck(Target); //Check various things if (PetHealth()) { } /*else if (DrainSoul(Target)) { }*/ else if (CheckMana(Target)) { } else if (DrainLife(Target, false)) { } else if (PrimaryAttack(Target)) { } else LastResort(Target); } Thread.Sleep(100); } //If timer runs out, return to start point and report Bugged Context.Log("PVP Timer expired, returning to start."); Movement.MoveToLocation(startLocation, 20, false); return GCombatResult.Success; }
//Checks for and casts Drain Life bool DrainLife(GUnit Target, bool ForceUse) { //Added logging to Drainlife for testing BEANS //Context.Log("DrainLife function check on ForceUse is " + ForceUse); //Context.Log("My health pct is "+Me.Health+" and my mana pct is " + Me.Mana); CheckHealth(Me.IsInCombat); if ((USE_DRAINLIFE && (Me.Health < DRAINLIFE_PCT) || ForceUse)) { //Because its channeling it will often kill before we have a chance to drain soul so we do castspellwithinterrupt to fix it //Context.Log("DrainLife SS Check - My current SS count is " + SoulShardCount + " with a max of " + SOULSHARDS_MAX); if (SoulShardCount < SOULSHARDS_MAX && (Target.Health < MIN_MOB_HEALTH_PCT)) { ShadowCheck(Target); if (USE_LIFETAP && (Me.Health > EMERGENCY_HEALTH)) { //Context.Log("Casting Lifetap from within DrainLife function"); CastSpell("PL.Lifetap"); Thread.Sleep(250); } if (SoulShardCount < 1) { SoulShardCount = 0; } Target.Face(); if (!Target.IsDead) { CastSwitchSpell("PL.DrainLife", "PL.DrainSoul", Target, DRAINSOUL_PCT); return true; } else { return false; } } else { ShadowCheck(Target); //Context.Log("Use Lifetap is " + USE_LIFETAP); if (USE_LIFETAP && (Me.Health > MIN_HEALTH_PCT) && (Me.Mana < MIN_MANA_PCT)) { //Context.Log("Casting Lifetap from within DrainLife function"); CastSpell("PL.Lifetap"); Thread.Sleep(250); } try { Target.Face(); if (!Target.IsDead) { CastSpell("PL.DrainLife"); Thread.Sleep(250); } if ((Me.Health < MIN_HEALTH_PCT) && (Me.Mana > .3)&&(!Target.IsDead)) //If we are low on health and have at least 30% lets throw another Drain Life { Target.Face(); CastSpell("PL.DrainLife"); Thread.Sleep(250); } } catch (Exception e) { if (Target == null) Context.Log("You errored out during DrainLife - Notes Target = null so I tried to bomb out."); else Context.Log("You Errored out during DrainLife - \r\n " + e.ToString()); } return true; } } return false; }
//Checks mana (Overloaded) - First check Drain Mana, Second check Life Tap bool CheckMana(GUnit Target) { if (USE_DRAINMANA && Target.Mana > .5 && Me.Mana > .1 && Me.Health > MIN_HEALTH_PCT && (Me.Mana < DRAINMANA_PCT || (USE_FEEDMANA && Me.HasLivePet && Me.Pet.Mana < FEEDMANA_PCT))) { // Context.Log("CheckMana SS Check - My current SS count is " + SoulShardCount + " with a max of " + SOULSHARDS_MAX); if (SoulShardCount < SOULSHARDS_MAX) { if (SoulShardCount < 1) { SoulShardCount = 0; } Target.Face(); CastSwitchSpell("PL.DrainMana", "PL.DrainSoul", Target, DRAINSOUL_PCT); } else { Target.Face(); CastSpell("PL.DrainMana"); } return true; } else if (USE_DARKPACT && Me.HasLivePet && Me.Mana < MIN_MANA_PCT && Me.Pet.Mana > MaintainPetMana) { CastSpell("PL.DarkPact"); return true; } else if (USE_LIFETAP && (Me.Health > MIN_HEALTH_PCT) && (Me.Mana < MIN_MANA_PCT || (USE_FEEDMANA && Me.HasLivePet && Me.Pet.Mana < FEEDMANA_PCT))) { CastSpell("PL.Lifetap"); return true; } return false; }
//Takes two spells. First MUST be channeling, second CAN be channeling. void CastSwitchSpell(string FirstSpell, string SecondSpell, GUnit Target, double TargetHealthToSwitch) { Context.Log(Format(Replace(Replace(FirstSpell, "PL.", "Casting: "), "Common.", "Casting: "))); if (Interface.IsKeyFiring("PL.Wand")) { SendKey("PL.Wand"); GlobalCooldown.Reset(); } if (Me.IsSitting) { SendKey("Common.Back"); Thread.Sleep(200); } GlobalCooldown.Wait(); Target.Face(); //Context.CastSpell(FirstSpell, false, true); Context.SendKey(FirstSpell); GlobalCooldown.Reset(); OneSecTimer.Reset(); while (!OneSecTimer.IsReady) { Thread.Sleep(100); if (Me.IsCasting) { while (Me.IsCasting) { if (Target.Health < TargetHealthToSwitch) { CastSpell(SecondSpell); break; } Target.Face(); Thread.Sleep(100); } break; } } }
//Modified Context.CastSpell() (Overloaded - directional casting) - turns off wand, waits for key, pause for specified delay, cast - keeps facing target while casting void CastSpell(string Spell, GUnit Target) { Context.Log(Format(Replace(Replace(Spell, "PL.", "Casting: "), "Common.", "Casting: "))); if (Interface.IsKeyFiring("PL.Wand")) { SendKey("PL.Wand"); GlobalCooldown.Reset(); } if (Me.IsSitting) { SendKey("Common.Back"); Thread.Sleep(200); } GlobalCooldown.Wait(); while (!Interface.IsKeyReady(Spell)) { Thread.Sleep(200); } Target.Face(); //Context.CastSpell(Spell, false, true); Context.SendKey(Spell); GlobalCooldown.Reset(); OneSecTimer.Reset(); while (!OneSecTimer.IsReady) { Thread.Sleep(100); if (Me.IsCasting) { while (Me.IsCasting) { Target.Face(); Thread.Sleep(100); } break; } } }
//Checks for and casts ShadowBolt bool CastShadowBolt(GUnit Target) { if (Target.Health > MIN_MOB_HEALTH_PCT && Me.Mana > MIN_MANA_PCT) { //Context.Log("DBG - ShadowBolt code!"); if (Target.DistanceToSelf > ShadowBoltRange) Target.Approach(ShadowBoltRange, false); Target.Face(); CastSpell("PL.ShadowBolt", Target); Thread.Sleep(250); return true; } return false; }
//Debuff cast sequence void CastSequence(GUnit Target, bool ForceAll) { //Check if monster health is great enough to debuff SoulShardCount = CountSoulShards(); if (Target.Health > MIN_MOB_HEALTH_PCT) { int i; //Loop for length of spell array for (i = 0; (i < SPELL_ORDER.Length && !Target.IsDead); i++) { ShadowCheck(Target); //Check for min mana if (Me.Mana > MIN_MANA_PCT && Me.Health > EMERGENCY_HEALTH && Target.Health > MIN_MOB_HEALTH_PCT && Target.DistanceToSelf < (PullDistance + TARGET_DUMP_DISTANCE)) { if (Target.IsDead) { break; } if (USE_BLOODFURY && BloodFury.IsReady) { CastSpell("PL.BloodFury"); BloodFury.Reset(); GlobalCooldown.ForceReady(); Thread.Sleep(MISCDELAY); } //Switch to select correct spell //Context.Log("Casting spell '" + SPELL_ORDER[i] + "' which is spell " + (i+1) + " of " + SPELL_ORDER.Length + "!"); Thread.Sleep(250); CheckHealth(Me.IsInCombat); /* RecursiveBot 2.17.1 D * The following is to ensure that we send in the pet after dismounting * and starting to cast. */ if (Me.HasLivePet && PET_ATTACK && !Me.Pet.IsInCombat) { //Context.Log("Your pet should being attacking now"); SendKey("Common.PetAttack"); } switch (SPELL_ORDER[i]) { case "UnstableAffliction": //Context.Log("DBG - Unstable Affliction ready check is " + UnstableAffliction.IsReady); while (!Interface.IsKeyReady("PL."+SPELL_ORDER[i])) { Thread.Sleep(150); } if (UnstableAffliction.IsReady || ForceUnstableAffliction || ForceAll) { if (ForceUnstableAffliction) Context.Log("Recast"); Target.Face(); CastSpell("PL.UnstableAffliction"); Thread.Sleep(150); if (!ForceAll) { UnstableAffliction.Reset(); ForceUnstableAffliction = false; } } break; case "SiphonLife": //Context.Log("DBG - Siphon Life ready check is " + SiphonLife.IsReady); while (!Interface.IsKeyReady("PL."+SPELL_ORDER[i])) { Thread.Sleep(150); } if (SiphonLife.IsReady || ForceSiphonLife || ForceAll) { if (ForceSiphonLife) Context.Log("Recast"); Target.Face(); CastSpell("PL.SiphonLife"); Thread.Sleep(150); if (!ForceAll) { SiphonLife.Reset(); ForceSiphonLife = false; } } break; case "CurseofAgony": //Context.Log("DBG - Curse of Agony ready check 1 is " + CurseOfAgony.IsReady); while (!Interface.IsKeyReady("PL."+SPELL_ORDER[i])) { Thread.Sleep(150); } if (CurseOfAgony.IsReady || ForceCurseOfAgony || ForceAll) { if (USE_AMPLIFYCURSE && AmplifyCurse.IsReady) { SendKey("PL.AmplifyCurse"); AmplifyCurse.Reset(); Thread.Sleep(MISCDELAY); } if (ForceCurseOfAgony) Context.Log("Recast"); Target.Face(); CastSpell("PL.CurseofAgony"); Thread.Sleep(150); if (!ForceAll) { CurseOfAgony.Reset(); ForceCurseOfAgony = false; } } break; case "Corruption": //Context.Log("DBG - Corruption ready check 1 is " + Corruption.IsReady); while (!Interface.IsKeyReady("PL."+SPELL_ORDER[i])) { Thread.Sleep(150); } if (Corruption.IsReady || ForceCorruption || ForceAll) { if (ForceCorruption) Context.Log("Recast"); Target.Face(); CastSpell("PL.Corruption", Target); Thread.Sleep(150); if (!ForceAll) { Corruption.Reset(); ForceCorruption = false; } } break; case "CurseOfRecklessness": //Context.Log("DBG - CurseOfRecklessness ready check is " + CurseOfRecklessness.IsReady); while (!Interface.IsKeyReady("PL."+SPELL_ORDER[i])) { Thread.Sleep(150); } if (CurseOfRecklessness.IsReady || ForceCurseOfRecklessness || ForceAll) { if (ForceCurseOfRecklessness) Context.Log("Recast"); Target.Face(); CastSpell("PL.CurseOfRecklessness", Target); Thread.Sleep(150); if (!ForceAll) { CurseOfRecklessness.Reset(); ForceCurseOfRecklessness = false; } } break; case "Immolate": //Context.Log("DBG - Immolate ready check 1 is " + Immolate.IsReady); while (!Interface.IsKeyReady("PL."+SPELL_ORDER[i])) { Thread.Sleep(150); } if (Immolate.IsReady || ForceImmolate || ForceAll) { if (ForceImmolate) Context.Log("Recast"); Target.Face(); CastSpell("PL.Immolate", Target); Thread.Sleep(150); if (!ForceAll) { Immolate.Reset(); ForceImmolate = false; } } break; case "Shadowburn": //Context.Log("DBG - Shadowburn ready check is " + Shadowburn.IsReady); while (!Interface.IsKeyReady("PL."+SPELL_ORDER[i])) { Thread.Sleep(150); } if ((Shadowburn.IsReady || ForceShadowburn || ForceAll) && SoulShardCount > 0 && Target.Health < 20) { if (ForceShadowburn) Context.Log("Recast"); Target.Face(); CastSpell("PL.Shadowburn", Target); Thread.Sleep(150); if (!ForceAll) { Shadowburn.Reset(); ForceShadowburn = false; } } break; case "ShadowBolt": //Context.Log("DBG - ShadowBolt ready check is " + ShadowBolt.IsReady); while (!Interface.IsKeyReady("PL."+SPELL_ORDER[i])) { Thread.Sleep(150); } if (ShadowBolt.IsReady || ForceShadowBolt || ForceAll) { if (ForceShadowBolt) Context.Log("Recast"); Target.Face(); CastSpell("PL.ShadowBolt", Target); Thread.Sleep(150); if (!ForceAll) { ShadowBolt.Reset(); ForceShadowBolt = false; } } break; case "Conflagurate": //Context.Log("DBG - Conflagurate ready check is " + Conflagurate.IsReady); while (!Interface.IsKeyReady("PL."+SPELL_ORDER[i])) { Thread.Sleep(150); } if ((Conflagurate.IsReady || ForceConflagurate || ForceAll) && (!Immolate.IsReady)) //We only want to cast if Immolate is on target { if (ForceConflagurate) Context.Log("Recast"); Target.Face(); CastSpell("PL.Conflagurate", Target); Thread.Sleep(150); if (!ForceAll) { Conflagurate.Reset(); ForceConflagurate = false; } } break; case "Incinerate": //Context.Log("DBG - Incinerate ready check is " + Conflagurate.IsReady); while (!Interface.IsKeyReady("PL."+SPELL_ORDER[i])) { Thread.Sleep(150); } if ((Incinerate.IsReady || ForceIncinerate || ForceAll) && (!Immolate.IsReady)) //We only want to cast if Immolate is on target { if (ForceIncinerate) Context.Log("Recast"); Target.Face(); CastSpell("PL.Incinerate", Target); Thread.Sleep(150); if (!ForceAll) { Incinerate.Reset(); ForceIncinerate = false; } } break; } } } } }