What's new
  • Visit Rebornbuddy
  • Visit Panda Profiles
  • Visit LLamamMagic
  • Visit Resources
  • Visit Downloads
  • Visit Portal
RebornBuddy Forums

Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

[Official] Default Combat Routine

Apoc

Well-Known Member
Joined
Jan 16, 2010
Messages
2,790
So, there was a massive rewrite of the combat routine that is patched with Wildbuddy.

This thread is for discussions, bug reports, and feature requests. Please note that I may not always respond to every message left here. If it is a bug report, please follow the standard bug reporting guidelines.

Please include the following information in your bug reports:

What steps will reproduce the problem?

What is the expected result?

What happens instead?

Character Class?
Character Level?

Location (Map, XYZ, etc.. If you do not know what this info is, please restart the bot, and it will print information about your current player, please paste the whole log line here)?

Please provide any additional information below.

Please attach your FULL log file ([post=378165][Guide] How to attach your log[/post])

Please note, that reports without log files, may (and probably will) be ignored.
 
Just ran it quickly on my Stalker and the difference is like night and day. I'll give it a good run through on all the classes but so far it looks great, good work.

Edit: just got an exception on the stalker:

Code:
Unhandled exception!Buddy.Coroutines.CoroutineUnhandledException: Exception was thrown by coroutine ---> System.Exception: Only part of a ReadProcessMemory or WriteProcessMemory request was completed, at addr: 0, Size: 38C0
   at GreyMagic.ExternalProcessMemory.ReadByteBuffer(IntPtr addr, Void* buffer, Int32 count)
   at GreyMagic.MemoryBase.Read[T](IntPtr addr)
   at Buddy.Wildstar.Engine.PerCachedValue`1.get_Value()
   at Buddy.Wildstar.Game.Actors.Actor.get_Guid()
   at Buddy.DefaultRoutine.Targeting.Weigh(Actor actor) in d:\Jamie\User\Documents\Wildbuddy\Routines\Default Routine\Targeting.cs:line 137
   at System.Linq.EnumerableSorter`2.ComputeKeys(TElement[] elements, Int32 count)
   at System.Linq.EnumerableSorter`1.Sort(TElement[] elements, Int32 count)
   at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   at Buddy.DefaultRoutine.Targeting.<.cctor>b__0() in d:\Jamie\User\Documents\Wildbuddy\Routines\Default Routine\Targeting.cs:line 19
   at Buddy.Wildstar.Engine.PerCachedValue`1.get_Value()
   at Buddy.DefaultRoutine.Targeting.get_BestTarget() in d:\Jamie\User\Documents\Wildbuddy\Routines\Default Routine\Targeting.cs:line 102
   at Buddy.DefaultRoutine.DefaultRoutine.<Combat>d__0.MoveNext() in d:\Jamie\User\Documents\Wildbuddy\Routines\Default Routine\DefaultRoutine.cs:line 101
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Buddy.Wildstar.BotCommon.CombatRoutineBase.fN_=Bn-)3P-gKO69D\[!}HYPK.()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Buddy.Coroutines.Coroutine.‬**​
​**​*​*‬‬‎**‬



Log attached. It's a slightly odd one to reproduce as I've just started running it again fine and it hasn't thrown an exception, there was nothing special about the fight that could help you reproduce it from what I can tell. I'll keep an eye out if something becomes a bit more apparent.
 

Attachments

Last edited:
I've noticed it doing that, but it should just continue afterwards. (It happens the frame of a mob death usually, or a mob going out of object manager range)

Did it not continue afterwards?
 
Stalker is working pretty flawlessly also the occurrence of overrunning targets has been reduced however it still happens occasionally.
 
I've noticed it doing that, but it should just continue afterwards. (It happens the frame of a mob death usually, or a mob going out of object manager range)

Did it not continue afterwards?

It seems as if the class can fight (facing the right direction and close enough) it'll continue after this error, if not it'll just stand still spamming the exception.
 
If I have updated combat for this routine for certain classes do I post here?
 
Yes, of course you post here!


I am not going to take credit for this but its some one else I am doing work with on this routine. Im going to just add tons of stuff as time goes on just have a few other routines working on. That with my awesome real life and holidays should get more up now. Things are smoothing out.

This is engineer.

[HIDE]using Buddy.Wildstar.Game.Actors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Buddy.Wildstar.Game;

namespace Buddy.DefaultRoutine.Classes
{
/*
Engineer Ability Breakdown - (V = Volatility)

Mode: Provoke - 60s CD - Instant - +10V/s for 10s (Defensive CD)
Mode: Eradicate - 60s CD - Instant - +10V/s for 10s (DPS CD)

Obstruct Vision - 30s CD - Instant - Interrupt + Blind
Zap - 30s CD - Instant - Stun/Interrupt

Recursive Matrix - 30s CD - Instant - Applies Defense/Stalwart around self for 10s (Defensive CD)
Shatter Impairment - 20s CD - Instant - Removes all CCs and gives absorb [T4 - grants Empower, T8 - cleanses 2 debuffs]
Personal Defense Unit - 45s CD - Instant - Grants Defense for it's duration, shield absorb when it dies [T4 causes it to last 60s instead of 30, T8 - restores health as well]
Unstable Anomaly - 10s CD - Instant - Applies Wound

Urgent Withdrawl - 1s CD - Instant - Snares targets [T4 gives Snare CC break, T8 grants CC immunity for 1.5s]

Artillerybot - No CD[15s bot]- Instant - Summons Pet, grants Barrage
Bruiserbot - No CD[15s bot]- Instant - Summons Pet, grants Blitz (taunt)
Diminisherbot - No CD[15s bot]- Instant - Just a damage/snare bot. [T4 - Grants 5% max health when active] (Tank bot)
Repairbot - No CD[15s bot]- Instant - Shield repair bot [T4 grants 15% shield mitigation] (Tank bot)

Quick Burst - 8s CD - Instant - [Spell Proc] (T8 best used above 80V)
Feedback - 8s CD - Instant - [Spell Proc]

Mortar Strike - 10s CD - Instant - -25V
Electrocute - No CD - 3s Channel - -8V/tick (0.5s tick) [T4 grants Empower (6 stacks total)]
Unsteady Miasma - No CD - Instant - -40V, Applies Blunder
Bolt Caster - No CD - Instant - -25V
Particle Ejector - No CD - 3s Channel - -5V/tick (0.5s tick) 135% threat
Thresher - No CD - Instant - -50V

Volatile Injection - 20s CD - Instant - +5V/tick (1s tick for 10s) [50V total] Applies Defense and Empower
Disruptive Module - 12s CD - 2s Cast - +5V/tick (1s tick for 6s) [30V total] Restores shield to self +4 allies [T4 increases shield mitigation, T8 30-70V restores shield per tick]
Shock Pulse - 10s CD - 1.25s Cast - +10V Applies Snare
Bio Shell - 10s CD - 1.9s Cast - +30V (T4 instant cast between 30-70V) Applies Expose for 11s
Target Acquisition - 10s CD - 3s Channel - +3V every 0.25s (per tick on the mob) [36V total] consumes applied "marks" at the end of channel
Ricochet - 6s CD - 1.25s Cast - +20V, Applies Exhaust, +110% threat
Energy Auger - 6s CD - 1.75s Cast - +30V
Flak Cannon - No CD - 2.5s Channel - +5V per tick (0.5s tick) [25V total] +110% threat
Pulse Blast - No CD - 1.25s Cast - +15V


Code Red - 45s CD - Instant - AoE Taunt
Hyper Wave - 15s CD - Instant - Taunt
*/
public class Engineer : BaseCombatClass
{
internal override async Task<bool> Pull(Actor target)
{
return await Combat();


}

internal async Task<bool> TryCastBots()
{
// Do some pet management here...
// Ensure the pets are actually in "Assist" mode. This is most useful for us.
await EnsurePetStances();

// Now keep up all the bots, and more or less just spam their abilities whenever we can.
// NOTE: The spell tooltip in-game changes when you summon a pet. However, the ability internally doesn't change names.
// So this will not only summon the bots, but also "spam" their abilities whenever they're off CD
if (await SelfCast("Artillerybot"))
return true;
if (await SelfCast("Bruiserbot"))
return true;
if (await SelfCast("Diminisherbot"))
return true;
if (await SelfCast("Repairbot"))
return true;




return false;
}

internal override async Task<bool> Combat()
{
// Cast Interrupts
if (Target.IsCasting && await CastAny("Zap", "Obstruct Vision"))
return true;

// Pop our DPS innate.
if (Me.InnateResource <= 30 && await SelfCast("Mode: Eradicate"))
return true;

// If we're in trouble, pop our defensive innate.
if (Me.HealthPercent < 30 && await SelfCast("Mode: Provoke"))
return true;

// Shatter Impairment is a CC cleanse, and at T8 also a debuff cleanse
if ((Me.GetActiveCCs().Count > 0 || (IsSpellTier("Shatter Impairment", 8) && Me.Buffs.Any(b => b.IsHarmful))) && await SelfCast("Shatter Impairment"))
return true;

// A defensive CD
if (Me.HealthPercent < 50 && await Cast("Recursive Matrix"))
return true;

// Buffs/Debuffs
if (await CastAny("Personal Defense Unit", "Unstable Anomaly"))
return true;

// T4 UW gives us a snare break
if (IsSpellTier("Urgent Withdrawl", 4) && Me.GetActiveCCs().Any(c => c == CCStateType.Snare) && await Cast("Urgent Withdrawl"))
return true;

// TODO: Taunts!
//if (await CastAny("Hyper Wave", "Code Red"))
// return true;

if (Me.HasBuff("Dealt Critical Damage"))
{
// QB T8 does a ton more damage at 80+ Volatility.
// So lets include that logic.
if (IsSpellTier("Quick Burst", 8))
{
if (Me.InnateResource > 80 && await Cast("Quick Burst"))
return true;
}
else
{
// Non-T8, just cast as soon as it's up
if (await Cast("Quick Burst"))
return true;
}
}

if (IsSpellProcReady("Feedback") && await Cast("Feedback"))
return true;


//Activates our Volatility Generator/Critical Buff first before attacking
if (await SelfCast("Volatile Injection"))
return true;



// Increased priority for Tier 4 Bioshell and Ricochet, if you are in "The Zone" (30-70 volatility)
// NOTE*** Add in 'IsSpellTier("Bio Shell", 4) && ' Once IsSpellTier is fixed. (Currently Assumes you have tier 4 Bio Shell)
if (Me.InnateResource >= 30 && Me.InnateResource <= 70 && await Cast("Bio Shell"))
return true;
if (IsSpellTier("Ricochet", 4) && Me.InnateResource >= 30 && Me.InnateResource <= 70 && await Cast("Ricochet"))
return true;


// The following are all going to be "cast when high Volatility"
// TODO: Engineer spenders are quite clunky. Only 1 has a cooldown. So you need to manage Volatility pretty well.
// Mortar Strike is the only with a CD, so cast it whenever it's up.

// NOTE IsSpellProcReady (not used for procs in this context) is used to prevent unnecessary spamming of abilities,
// and instead used to increase the responsiveness of bot abilities (bottom of rotation)

if (await CastAny("Mortar Strike"))
return true;

if (Me.InnateResource > 80 && await Cast("Thresher"))
return true;
if (Me.InnateResource > 80 && await Cast("Unsteady Miasma"))
return true;
if (Me.InnateResource >= 38 && IsSpellProcReady("Electrocute") && await Cast("Electrocute"))
return true;
if (Me.InnateResource > 80 && IsSpellProcReady("Particle Ejector") && await Cast("Particle Ejector"))
return true;
if (Me.InnateResource > 35 && await Cast("Bolt Caster"))
return true;


// These are all volatility builders, ordered by CD and "usefulness"
// IsSpellProcReady prevents builders below from interrupting spenders.
// Only applies this logic if either particle ejector or electrocute are slotted however.
if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))
|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Disruptive Module"))
return true;
if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))
|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Shock Pulse"))
return true;
if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))
|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Target Acquisition"))
return true;
if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))
|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Energy Auger"))
return true;
if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))
|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Ricochet"))
return true;
if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))
|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Bio Shell"))
return true;
if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))
|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Flak Cannon"))
return true;
if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))
|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Pulse Blast"))
return true;


if (await TryCastBots())
return true;


return false;
}

private async Task EnsurePetStances()
{
foreach (var pet in GameManager.CurrentPets)
{
if (pet.Stance != PetStance.Assist)
{
GameManager.Lua.DoString("Pet_SetStance(0, 4)");
// Only need to set it once. This changes it for all pets, so... yeah
return;
}
}
}
}
}[/HIDE]

// NOTE*** Add in 'IsSpellTier("Bio Shell", 4) && ' Once IsSpellTier is fixed. (Currently Assumes you have tier 4 Bio Not working correctly.


Esper Build


[HIDE]using Buddy.Wildstar.Game.Actors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Buddy.DefaultRoutine.Classes
{
public class Esper : BaseCombatClass
{
internal override async Task<bool> Pull(Actor target)
{
return await Combat();
}


internal override async Task<bool> Heal()
{
if (Me.Buffs.Count(c => c.IsHarmful) > 0 && await Cast("Catharsis"))
return true;

if (await HandleHealSpender())
return true;

if (Me.InnateResource < 3 && await SelfCast("Fixation"))
return true;

var lowestAlly = PartyMembers.OrderBy(p => p.HealthPercent).FirstOrDefault();

if (lowestAlly != null)
{
if (lowestAlly.HealthPercent < 80 && await CastOn("Phantasmal Armor", () => lowestAlly))
return true;
if (lowestAlly.HealthPercent < 80 && await CastOn("Projected Spirit", () => lowestAlly))
return true;
if (lowestAlly.HealthPercent < 80 && await CastOn("Pyrokinetic Flame", () => lowestAlly))
return true;
if (lowestAlly.HealthPercent < 80 && await CastOn("Mirage", () => lowestAlly))
return true;
if (lowestAlly.HealthPercent < 80 && await Cast("Soothe"))
return true;
if (lowestAlly.HealthPercent < 80 && await Cast("Warden"))
return true;
if (lowestAlly.HealthPercent < 80 && await Cast("Bolster"))
return true;
if (lowestAlly.HealthPercent < 80 && await Cast("Mind Over Body"))
return true;
if ((lowestAlly.HealthPercent < 80 || Me.ManaPercent < 30) && await SelfCast("Meditate"))
return true;
}

return false;
}

internal override async Task<bool> Combat()
{


if (Me.GetActiveCCs().Count > 0 && await Cast("Fade Out"))
return true;

if (Target.IsCasting && await CastAny("Shockwave", "Crush", "Incapacitate"))
return true;

if (await EnsureCombatBuffs())
return true;

if (await HandleCombatSpender())
return true;

if (Me.HealthPercent < 85 && await SelfCast("Phantasmal Armor"))
return true;

if (await CastAny("Spectral Swarm", "Restraint", "Geist", "Psychic Frenzy", "Blade Dance"))
return true;

if (await SelfCast("Spectral Form"))
return true;




//TODO: Illusionary Blades

//if (await CastAny("Concentrated Blade", "Telekinetic Strike")) //Concentrated Blade bugged
// return true;

return false;
}

private async Task<bool> EnsureCombatBuffs()
{
if (!Target.HasBuff("Expose") && await Cast("Haunt"))
return true;

return false;
}

private async Task<bool> HandleCombatSpender()
{
// Best to cast @ 5 resource for maximum impact
var resource = Me.InnateResource;

// Now combat spenders
if (resource >= 3 && await Cast("Reap"))
return true;
if (resource >= 5 && await Cast("Mind Burst"))
return true;
if (resource >= 5 && await Cast("Telekinetic Storm"))
return true;

return false;
}


private async Task<bool> HandleHealSpender()
{
var resource = Me.InnateResource;
var hpAverage = PartyMembers.Average(p => p.HealthPercent);

// Heal before Combat
if (resource >= 5 && Me.HealthPercent < 80 && await Cast("Mental Boon"))
return true;
if (resource >= 5 && hpAverage < 70 && await Cast("Reverie"))
return true;
if (resource >= 5 && hpAverage < 70 && await Cast("Mending Banner"))
return true;

return false;
}
}
}



<Profile Name="Badland Test" Author="Dr. Kid" Version="1.0">
<Grind>
<Repair PreferClosest="true" PreferFirst="false">
<RepairNPCs>
<RepairNPC Name="Quartermaster Klazrak" CreatureId="36576" X="-22480.97" Y="-942.832" Z="-27820.3" MapId="2997"/>
</RepairNPCs>
</Repair>
<Vendor>
<VendorNPC Name="Quartermaster Klazrak" CreatureId="36576" X="-22480.97" Y="-942.832" Z="-27820.3" MapId="2997"/>
</Vendor>
<GrindArea>
<Hotspot X="-22469.0781" Y="-975.8047" Z="-27239.8047" Timeout="60" Range="40"/>
<Hotspot X="-22567.3379" Y="-988.9558" Z="-27140.877" Timeout="60" Range="40"/>
<Hotspot X="-22530.3633" Y="-995.952637" Z="-26998.3047" Timeout="60" Range="40"/>
<Hotspot X="-22409.625" Y="-988.459" Z="-27111.0547" Timeout="60" Range="40"/>
</GrindArea>
</Grind>
</Profile>
[/HIDE]


I will post updated spellslinger but spellsurge resource doesn't work correctly. It always puts the value at 0 no matter what I do.

if (IsSpellTier("Bio Shell", 4) && Me.InnateResource >= 30 && Me.InnateResource <= 70 && await Cast("Bio Shell"))
return true;



Once I tweak a few things Im going to add in support for health pots to using items in inventory like xp flasks etc. I just want to clean up everything make sure its going smooth before I start adding nonsense.
 
IsSpellTier doesn't work properly?

On all the things I tested, it was working correctly. Do you mind printing out what is wrong with it?
 
Also, some things either don't make sense (excuse my lack of high-level rotation knowledge), and others can be condensed.

Code:
[COLOR=#333333]if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))[/COLOR]
[COLOR=#333333]|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Disruptive Module"))[/COLOR]
[COLOR=#333333]return true;[/COLOR]
[COLOR=#333333]if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))[/COLOR]
[COLOR=#333333]|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Shock Pulse"))[/COLOR]
[COLOR=#333333]return true; [/COLOR]
[COLOR=#333333]if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))[/COLOR]
[COLOR=#333333]|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Target Acquisition"))[/COLOR]
[COLOR=#333333]return true; [/COLOR]
[COLOR=#333333]if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))[/COLOR]
[COLOR=#333333]|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Energy Auger"))[/COLOR]
[COLOR=#333333]return true; [/COLOR]
[COLOR=#333333]if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))[/COLOR]
[COLOR=#333333]|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Ricochet"))[/COLOR]
[COLOR=#333333]return true; [/COLOR]
[COLOR=#333333]if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))[/COLOR]
[COLOR=#333333]|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Bio Shell"))[/COLOR]
[COLOR=#333333]return true; [/COLOR]
[COLOR=#333333]if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))[/COLOR]
[COLOR=#333333]|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Flak Cannon"))[/COLOR]
[COLOR=#333333]return true; [/COLOR]
[COLOR=#333333]if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))[/COLOR]
[COLOR=#333333]|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute"))) && await Cast("Pulse Blast"))[/COLOR]
[COLOR=#333333]return true;

Can easily be condensed into

Code:
[/COLOR]			var procsReady = ((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute")) || (!HasSpell("Particle Ejector") && !HasSpell("Electrocute")));			if (procsReady && await CastAny("Disruptive Module","Shock Pulse", "Target Acquisition", "Energy Auger", "Ricochet", "Bio Shell", "Flak Cannon", "Pulse Blast"))
				return true;

Is there a reason to cast bots after your normal filler? Last I checked, they weren't on the GCD, and could be cast at any time.
 
Spellslinger


[HIDE]using Buddy.Wildstar.Game.Actors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Buddy.DefaultRoutine.Classes
{
public class SpellSlinger : BaseCombatClass
{
internal override async Task<bool> Pull(Actor target)
{
return await Combat();
}

internal override async Task<bool> Heal()
{

var lowestPercent = PartyMembers.OrderBy(p => p.HealthPercent).FirstOrDefault();

if (!Me.HasBuff("Healing Salve") && await Cast("Healing Salve"))
return true;
if (!Me.HasBuff("Beacon") && await Cast("Affinity"))
return true;

if (lowestPercent == null)
return false;

var hPercent = lowestPercent.HealthPercent;

if (hPercent < 90 && await CastOn("Runes of Protection", () => lowestPercent))
return true;
if (hPercent < 70 && await CastOn("Vitality Burst", () => lowestPercent))
return true;
if (hPercent < 90 && await CastOn("Astral Infusion", () => lowestPercent))
return true;
if (hPercent < 80 && await CastOn("Dual Fire", () => lowestPercent))
return true;
if (hPercent < 80 && await CastOn("Healing Torrent", () => lowestPercent))
return true;
if (hPercent < 30 && await CastOn("Voidspring", () => lowestPercent))
return true;
if (hPercent < 90 && await CastOn("Regenerative Pulse", () => lowestPercent))
return true;
if (hPercent < 70 && await CastOn("Sustain", () => lowestPercent))
return true;


return false;
}

internal override async Task<bool> Combat()
{
// Interrupt
if (Target.IsCasting && await CastAny("Arcane Shock", "Gate"))
return true;

// Cleanse CC
if (Me.HasCleansableCC() && await SelfCast("Void Slip"))
return true;

// Cleanse buffs
if (Me.Buffs.Count(c => c.IsHarmful) > 0 && await Cast("Purify"))
return true;

// Maintain Target & self buffs
if (await EnsureBuffs())
return true;

// Handle innate ability
//if (await HandleInnate())
// return true;

if (Target.HealthPercent < 30 && await Cast("Assassinate"))
return true;

if (Me.HasBuff("Dealt Critical Damage") && await Cast("Flame Burst"))
return true;

if (!Target.HasBuff("Ignite") && await Cast("Ignite"))
return true;

if (await Cast("Flash Freeze"))
return true;

//TODO: Charged Shot

//If spell surge is down, and there exists a special available to use. -> Turns spell surge on
if (!Me.HasBuff("Spell Surge") && (IsSpellProcReady("Arcane Missiles") || IsSpellProcReady("Chill") || IsSpellProcReady("True Shot") || IsSpellProcReady("Rapid Fire") || IsSpellProcReady("Wild Barrage") ) && await SelfCast("Spell Surge") )
return true;


//use a "special" attack.
if (await CastAny("Arcane Missiles", "Chill", "True Shot", "Rapid Fire", "Wild Barrage"))
return true;

//if spell surge is up, and quick draw is usable (not mid animation for a special for example), toggles it off
//However, it will remain on if we have a excess amount of spell surge available
//Me.InnateResource currently does nothing
if ((Me.HasBuff("Spell Surge") && IsSpellProcReady("Quick Draw")) && (Me.InnateResource > 75) && await SelfCast("Spell Surge"))
return true;


//Uses a non-surged quick draw if no specials are available.
if (await CastAny("Quick Draw"))
return true;

return false;
}

private async Task<bool> EnsureBuffs()
{


if (!Me.HasBuff("Empower") && await Cast("Void Pact"))
return true;
if (Me.HealthPercent < 85 && await SelfCast("Phase Shift"))
return true;

return false;
}

private async Task<bool> HandleInnate()
{
// Turn on or maintain Spell Surge
if (!Me.HasBuff("Spell Surge") && await SelfCast("Spell Surge"))
return true;

return false;
}
}
}[/HIDE]


I will adjust engineer some. but its set that way so it using resources correctly. Otherwise it will not use volatility correctly. Here I changed it up some.

[HIDE]using Buddy.Wildstar.Game.Actors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Buddy.Wildstar.Game;

namespace Buddy.DefaultRoutine.Classes
{
/*
Engineer Ability Breakdown - (V = Volatility)

Mode: Provoke - 60s CD - Instant - +10V/s for 10s (Defensive CD)
Mode: Eradicate - 60s CD - Instant - +10V/s for 10s (DPS CD)

Obstruct Vision - 30s CD - Instant - Interrupt + Blind
Zap - 30s CD - Instant - Stun/Interrupt

Recursive Matrix - 30s CD - Instant - Applies Defense/Stalwart around self for 10s (Defensive CD)
Shatter Impairment - 20s CD - Instant - Removes all CCs and gives absorb [T4 - grants Empower, T8 - cleanses 2 debuffs]
Personal Defense Unit - 45s CD - Instant - Grants Defense for it's duration, shield absorb when it dies [T4 causes it to last 60s instead of 30, T8 - restores health as well]
Unstable Anomaly - 10s CD - Instant - Applies Wound

Urgent Withdrawl - 1s CD - Instant - Snares targets [T4 gives Snare CC break, T8 grants CC immunity for 1.5s]

Artillerybot - No CD[15s bot]- Instant - Summons Pet, grants Barrage
Bruiserbot - No CD[15s bot]- Instant - Summons Pet, grants Blitz (taunt)
Diminisherbot - No CD[15s bot]- Instant - Just a damage/snare bot. [T4 - Grants 5% max health when active] (Tank bot)
Repairbot - No CD[15s bot]- Instant - Shield repair bot [T4 grants 15% shield mitigation] (Tank bot)

Quick Burst - 8s CD - Instant - [Spell Proc] (T8 best used above 80V)
Feedback - 8s CD - Instant - [Spell Proc]

Mortar Strike - 10s CD - Instant - -25V
Electrocute - No CD - 3s Channel - -8V/tick (0.5s tick) [T4 grants Empower (6 stacks total)]
Unsteady Miasma - No CD - Instant - -40V, Applies Blunder
Bolt Caster - No CD - Instant - -25V
Particle Ejector - No CD - 3s Channel - -5V/tick (0.5s tick) 135% threat
Thresher - No CD - Instant - -50V

Volatile Injection - 20s CD - Instant - +5V/tick (1s tick for 10s) [50V total] Applies Defense and Empower
Disruptive Module - 12s CD - 2s Cast - +5V/tick (1s tick for 6s) [30V total] Restores shield to self +4 allies [T4 increases shield mitigation, T8 30-70V restores shield per tick]
Shock Pulse - 10s CD - 1.25s Cast - +10V Applies Snare
Bio Shell - 10s CD - 1.9s Cast - +30V (T4 instant cast between 30-70V) Applies Expose for 11s
Target Acquisition - 10s CD - 3s Channel - +3V every 0.25s (per tick on the mob) [36V total] consumes applied "marks" at the end of channel
Ricochet - 6s CD - 1.25s Cast - +20V, Applies Exhaust, +110% threat
Energy Auger - 6s CD - 1.75s Cast - +30V
Flak Cannon - No CD - 2.5s Channel - +5V per tick (0.5s tick) [25V total] +110% threat
Pulse Blast - No CD - 1.25s Cast - +15V


Code Red - 45s CD - Instant - AoE Taunt
Hyper Wave - 15s CD - Instant - Taunt
*/
public class Engineer : BaseCombatClass
{
internal override async Task<bool> Pull(Actor target)
{
return await Combat();


}

internal async Task<bool> TryCastBots()
{
// Do some pet management here...
// Ensure the pets are actually in "Assist" mode. This is most useful for us.
await EnsurePetStances();

// Now keep up all the bots, and more or less just spam their abilities whenever we can.
// NOTE: The spell tooltip in-game changes when you summon a pet. However, the ability internally doesn't change names.
// So this will not only summon the bots, but also "spam" their abilities whenever they're off CD
if (await SelfCast("Artillerybot"))
return true;
if (await SelfCast("Bruiserbot"))
return true;
if (await SelfCast("Diminisherbot"))
return true;
if (await SelfCast("Repairbot"))
return true;




return false;
}

internal override async Task<bool> Combat()
{
// Cast Interrupts
if (Target.IsCasting && await CastAny("Zap", "Obstruct Vision"))
return true;

// Pop our DPS innate.
if (Me.InnateResource <= 30 && await SelfCast("Mode: Eradicate"))
return true;

// If we're in trouble, pop our defensive innate.
if (Me.HealthPercent < 30 && await SelfCast("Mode: Provoke"))
return true;

// Shatter Impairment is a CC cleanse, and at T8 also a debuff cleanse
if ((Me.GetActiveCCs().Count > 0 || (IsSpellTier("Shatter Impairment", 8) && Me.Buffs.Any(b => b.IsHarmful))) && await SelfCast("Shatter Impairment"))
return true;

// A defensive CD
if (Me.HealthPercent < 50 && await Cast("Recursive Matrix"))
return true;

// Buffs/Debuffs
if (await CastAny("Personal Defense Unit", "Unstable Anomaly"))
return true;

// T4 UW gives us a snare break
if (IsSpellTier("Urgent Withdrawl", 4) && Me.GetActiveCCs().Any(c => c == CCStateType.Snare) && await Cast("Urgent Withdrawl"))
return true;

// TODO: Taunts!
//if (await CastAny("Hyper Wave", "Code Red"))
// return true;

if (Me.HasBuff("Dealt Critical Damage"))
{
// QB T8 does a ton more damage at 80+ Volatility.
// So lets include that logic.
if (IsSpellTier("Quick Burst", 8))
{
if (Me.InnateResource > 80 && await Cast("Quick Burst"))
return true;
}
else
{
// Non-T8, just cast as soon as it's up
if (await Cast("Quick Burst"))
return true;
}
}

if (IsSpellProcReady("Feedback") && await Cast("Feedback"))
return true;


//Activates our Volatility Generator/Critical Buff first before attacking
if (await SelfCast("Volatile Injection"))
return true;

//Uses a DPS gadget
if (await SelfCast("Power"))
return true;



// Increased priority for Tier 4 Bioshell and Ricochet, if you are in "The Zone" (30-70 volatility)
// NOTE*** Add in 'IsSpellTier("Bio Shell", 4) && ' Once IsSpellTier is fixed. (Currently Assumes you have tier 4 Bio Shell)
if (Me.InnateResource >= 30 && Me.InnateResource <= 70 && await Cast("Bio Shell"))
return true;
if (IsSpellTier("Ricochet", 4) && Me.InnateResource >= 30 && Me.InnateResource <= 70 && await Cast("Ricochet"))
return true;


// The following are all going to be "cast when high Volatility"
// TODO: Engineer spenders are quite clunky. Only 1 has a cooldown. So you need to manage Volatility pretty well.
// Mortar Strike is the only with a CD, so cast it whenever it's up.

// NOTE IsSpellProcReady (not used for procs in this context) is used to prevent unnecessary spamming of abilities,
// and instead used to increase the responsiveness of bot abilities (bottom of rotation)

if (await CastAny("Mortar Strike"))
return true;

if (Me.InnateResource > 80 && await Cast("Thresher"))
return true;
if (Me.InnateResource > 80 && await Cast("Unsteady Miasma"))
return true;
if (Me.InnateResource >= 38 && IsSpellProcReady("Electrocute") && await Cast("Electrocute"))
return true;
if (Me.InnateResource > 80 && IsSpellProcReady("Particle Ejector") && await Cast("Particle Ejector"))
return true;
if (Me.InnateResource > 35 && await Cast("Bolt Caster"))
return true;


// These are all volatility builders, ordered by CD and "usefulness"
// IsSpellProcReady prevents builders below from interrupting spenders.
// Only applies this logic if either particle ejector or electrocute are slotted however.
if (((IsSpellProcReady("Particle Ejector") || IsSpellProcReady("Electrocute"))
|| (!HasSpell("Particle Ejector") && !HasSpell("Electrocute")))
&& await CastAny("Disruptive Module", "Shock Pulse", "Target Acquisition", "Energy Auger", "Ricochet", "Bio Shell", "Flak Cannon", "Pulse Blast"))
return true;


if (await TryCastBots())
return true;



return false;
}

private async Task EnsurePetStances()
{
foreach (var pet in GameManager.CurrentPets)
{
if (pet.Stance != PetStance.Assist)
{
GameManager.Lua.DoString("Pet_SetStance(0, 4)");
// Only need to set it once. This changes it for all pets, so... yeah
return;
}
}
}
}
}[/HIDE]


isspelltier doesn't work for bioshell. T4 doesn't seem to work correctly when I call it up. Line 157 you can see how I have stuff commented out.



Reason for spamming bot is because the bots get out of range. Then they stop working and etc. This way it allows them to trail you at all times.
 
Last edited:
Low level warrior seems to be trying to spam Rampage while having low/no KE, any ideas?

Code:
2014-12-27 04:40:19,852 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:19,853 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:19,947 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:19,948 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:20,042 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:20,043 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:20,140 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:20,140 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:20,235 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:20,235 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:20,324 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:20,324 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:20,409 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:20,409 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:20,501 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:20,501 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:20,614 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:20,614 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:20,714 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:20,715 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:20,805 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:20,805 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:20,905 [Pulsator Thread] INFO  SpellManager - Down: 1669148952
2014-12-27 04:40:20,905 [Pulsator Thread] INFO  SpellManager - Up: 1417084944
2014-12-27 04:40:21,015 [Pulsator Thread] INFO  SpellManager - Down: 1669148952

i get that spammed in the logs when it happens it seems
 
Last edited:
Inside Targeting.cs, at line 97 you'll find the following:

Code:
if (!_pullTarget.IsValid)

Change it to

Code:
if (_pullTarget != null && !_pullTarget.IsValid)

I'll commit this as well to the SVN repo.
 
I'm sometimes seeing issues with warriors that makes me wonder if there's some bugginess around reading kinetic energy - upon initiating combat, the bot will try to spam Rampage - which requires kinetic energy (rage) - if none is present from previous battles, it will just stand there attempting to spam the button.

You can see this with a fairly new character, as rampage is the default second skill unlock for the class.

Thanks!
 
I'm sometimes seeing issues with warriors that makes me wonder if there's some bugginess around reading kinetic energy - upon initiating combat, the bot will try to spam Rampage - which requires kinetic energy (rage) - if none is present from previous battles, it will just stand there attempting to spam the button.

You can see this with a fairly new character, as rampage is the default second skill unlock for the class.

Thanks!


I updated warrior but I haven't posted it here yet. Was doing some rework for melee and will post asap. Also gadgets will be added.
 
Hey there,

is this CR or any CR here for the Wildstar bot still supported? Because I'm thinking about to buy this bot but when there are no CR's then it's wasting my money.

All of the threads here are from last year so I'm not very enthusiastic.
 
Forums have just been slow :)

This CR is very much still supported, as it's packaged with the bot.
 
Back
Top