coroutines use a different syntax than Pure/Default do. I don't know if I can explain it, mostly because I've never developed anything for a coroutine, but they seem to start with the conditional and then call the spell. I'm not sure if one is better than the other, I'm just observing that most newer routines are using coroutines, so I wondered if that's something we could look into.
You mean this for instance? http://ultimacr.googlecode.com/svn/trunk/UltimaCR/ Looks more work then we got now?!?
As far as I know the only thing holding us back from having a CR written using coroutines is an AbilityManager.Cast() that returns true/false. At least that was where I got hung up attempting to write a CR using Coroutines .
Yeah it would be more complex and require a nearly complete rewrite. At the same time, I wonder if it has the potential to fix issues like stealth targeting or companion targeting that have plagued the bot since jump. I don't know the answer to those questions, hence why I asked Ama what he thought about coroutines.
What about this? https://www.thebuddyforum.com/buddy...-ability-activation-question.html#post2028170 EDIT: Here it is in the API: http://docs.buddywing.com/search.html?SearchText=abilitymanager.cast
He means making the routine multithreaded. I'd have to look at some code to see what tasks are being done asynchronously, but it could help a bit.
I had a look at UltimaCR (and the Reborn bot) and it appears that they are using an extended/expanded version of TreeSharp that includes coroutine support (namely TreeSharp.ActionRunCoroutine). Unless that functionality is ported across from the other Bot frameworks, that will need to implemented. Regarding a Cast method that returns bool, I have this but have not yet used it as AbilityActivate does not appear to work for all abilities: Code: public bool Cast(string spell, TorCharacter onUnit) { TorAbility abl = null; if (onUnit.IsDead || onUnit.HealthPercent < .1f) { return false; } abl = AbilityManager.KnownAbilities.FirstOrDefault(t => t.Name == spell); if (abl == null) { return false; } float mindist = abl.MinRange; float maxdist = abl.MaxRange; float dist = onUnit.Distance; float ec = abl.ActionPointCost + abl.EnergyCost + abl.ForceCost + abl.HeatCost; if (abl.IsValid && onUnit.InLineOfSight && dist <= maxdist && dist >= mindist && this.Me.ResourceStat >= ec) { if (AbilityManager.CanCast(spell, onUnit)) { EffectResult res; return Me.AbilityActivate(abl, onUnit, out res); } } return false; }
Sounds like improvement, but also a shitload of work. But may i suggest we get aevitas First on the way, with fixing class detection. There are still some classes being reported wrongly. But if you need any help, we can pick this up with more people.
Oe nice! Could you possibly, maybe explain the code a bit what you are doing per line? For learning purpose's
Sure. Added some comments (should have probably done that in the first place) Code: public bool Cast(string spell, TorCharacter onUnit) { //Initialize temporary variable to hold ability object TorAbility abl = null; //Check that target is actually alive if (onUnit.IsDead || onUnit.HealthPercent < .1f) { return false; } //Retrieve the target spell/ability from the Ability Manager using the name abl = AbilityManager.KnownAbilities.FirstOrDefault(t => t.Name == spell); //Return false if no ability by that name was found if (abl == null) { return false; } //Initialize variables used to check if the spell can be fired float mindist = abl.MinRange; //Spell's minimum allowed range float maxdist = abl.MaxRange; //Spell's maximum alowed range float dist = onUnit.Distance; //Distance between us and the target float ec = abl.ActionPointCost + abl.EnergyCost + abl.ForceCost + abl.HeatCost; //Sum of all cost types for this spell //Is this a valid ability + target is line of sight + target is within the allowed range for the spell + we have enough resources to trigger the spell if (abl.IsValid && onUnit.InLineOfSight && dist <= maxdist && dist >= mindist && this.Me.ResourceStat >= ec) { //Check with the Ability Manager if we can actually trigger the spell if (AbilityManager.CanCast(spell, onUnit)) { //Required output variable for AbilityActivate EffectResult res; //Return true or false depending on whether the spell was cast or not return Me.AbilityActivate(abl, onUnit, out res); } } //Default return value of false return false; } Logic/code is from MercCast and MercCastNew in Joes. Me.AbilityActivate doesn't always work in my tests but AbilityManager.Cast does, so it can probably be replaced above (returning true after it is executed)
Thanks Teo for the explanation. Althow this piece of code wonders me: Code: //Check that target is actually alive if (onUnit.IsDead [B]|| onUnit.HealthPercent < .1f[/B]) { return false; } Ive seen with joes and other routines that if the npc has some HP but thats between 0-1% the bot wont attack anymore. The game reports it if im correct at 0 but still can have some HP. The code as you wrote it now, says if below a certain % it wont attack anymore. I would rather change it to if dead or not attackable (the npc turns from red to green, mostly if you need to speak to him). Ive seen this behaviour with bosses, where it would just not attack on the last 50 HP and still my char got the killing blow by not attacking. Anyways thats for later, lets see if this route is viable
That would also hopefully improve the problem with npcs turning blue for whatever reason and the bot freaking out.
Yeah it would Be best if we could read the state the npc is in like it can detect strong or elite mobs. If red, attack, if blue, ignore and so on.
Would something like this cover all cases? Code: if (onUnit.IsDead || onUnit.IsDeleted || (onUnit.Guid != Me.Guid && (!onUnit.IsTargetable || !onUnit.IsHostile || onUnit.IsNeutral || onUnit.IsFriendly))){ return false; } Where onUnit is the parameter from the function posted before.
A shitload of checks, but in my opinion needed to not keep the bot in the I need to attack mode but I can't loop.
Here are some of the checks I used for my WoW routines: Code: !Me.IsAlive || Me.IsCasting || Me.IsChanneling || Me.Mounted || Me.OnTaxi for pre-combat Code: !Me.IsAlive || !Me.GotTarget || !Me.CurrentTarget.IsAlive || Me.CurrentTarget.IsFriendly for combat Code: public static bool isUnitValid(this WoWUnit Unit, double Range) { return Unit != null && Unit.IsValid && Unit.IsAlive && Unit.Attackable && Unit.DistanceSqr <= Range * Range; } public static bool isValidEnemy(this WoWUnit Unit, double Range) { return Unit != null && Unit.IsValid && Unit.IsAlive && Unit.Attackable && !Unit.IsFriendly && !Unit.IsMe && !Unit.IsCritter && !Unit.IsNonCombatPet && Unit.CanSelect && Unit.DistanceSqr <= Range * Range; } public static bool isValidFriendly(this WoWUnit Unit, double Range) { return Unit != null && Unit.IsValid && Unit.IsAlive && !Unit.Attackable && Unit.IsFriendly && !Unit.IsCritter && !Unit.IsNonCombatPet && Unit.CanSelect && Unit.DistanceSqr <= Range * Range; } unit evaluation
Should these questions about CoRoutines and such be moved to another forum (like Community Developers or Support) to better coordinate with Aevitas or one of the other devs that have access to change the BW Api about was is needed/missing?
I think the developer section is more for This dont you think? If we get a few onboard, maybe we got something done with the devs?