Jump to content

Recommended Posts

Good day. Sorry in advance for my english, it's far not my native language.

Searched forum for a while, but still can't find detailed information about handwriting FightClass. Maybe it's because i'm new here, or just because i'm dumb. I'd like to use C#, where can i get more detailed api for it?
For example, i'd like to write some custom functions for a bot, like this:

1) Override Eat function inside the bot. I'd like to force him check an inventory and eat first available food from the list, that is hardcoded inside the FC.

2) While in combat, check inventory for an item, and if it's available, use it. For example, if bot hp <= 15% && bot got "Healing potion"  then bot use "Healing potion"

3) Check target health (not percent, but a number of health that left)

4) Use some abilityes when bot goes to the vendor (for example use blink or sprint to speed that process) and then use this abilities when bot is going back to the profile.


And maybe some others functions, depending on api. Is it even possible?


Thank you for your answers and any advices.

 

Link to comment
https://wrobot.eu/forums/topic/6494-alot-of-questions-about-fightclass-and-api/
Share on other sites

Welcome @Findeh to WRobot, you can find details & templates about fightclasses here.

To get a detailed documentation, you can decompile WRobot's libraries here explained.

 

1 hour ago, Findeh said:

1) Override Eat function inside the bot. I'd like to force him check an inventory and eat first available food from the list, that is hardcoded inside the FC.

For this task you could use "wManager.Events.FightEvents.OnFightEnd"

1 hour ago, Findeh said:

2) While in combat, check inventory for an item, and if it's available, use it. For example, if bot hp <= 15% && bot got "Healing potion"  then bot use "Healing potion"

A plugin already exists here

1 hour ago, Findeh said:

3) Check target health (not percent, but a number of health that left)

"wManager.Wow.ObjectManager.ObjectManager.Me.TargetObject.Health" for futures requests you may search in your decompiler by looking for "health" for example

1 hour ago, Findeh said:

4) Use some abilityes when bot goes to the vendor (for example use blink or sprint to speed that process) and then use this abilities when bot is going back to the profile.

Unfortunately no event exists. But you can check it on a loop: "wManager.Wow.Bot.States.ToTown.GoToTownInProgress"

 

Thanks alot for your answer, it was really wery helpful. Seems like i did almost every function i need, but still few remain. Maybe again it's my stupidity.

1) I was not able to find how do i get spell rank (level). For example, i want to count how many damage spell will do, depending on it's rank. To know will it kill the target, or will it not. Am i able to get spell rank somehow, or make it work any other way maybe?

2) This will be a wery stupid one. I don't get, how some events works. I'm decompiling wManager with ILSpy. Going to wManager/wMnager.Events/ and can't understand the order they are triggering each other at.
For example, if i got "internal void BuffRotation()" class inside my FC, will it use it only after the fight, or only during the fight, or maybe it will use it during patrol?

3) And this one even more stupider. About "wManager.Wow.Bot.States.ToTown.GoToTownInProgress" If i get it right, i am able to chek it? Like this for example?

if (Me.States.ToTown.GoToTownInProgress && SpellName.IsSpellUsable)
{
	SpellName.Launch();
	return;
}

But bot will not use "SpellName" anyway because there is no such event where i can place it? Right?

Thanks alot for any advices or hints. And once again, sorry for my english.

1 hour ago, Findeh said:

1) I was not able to find how do i get spell rank (level). For example, i want to count how many damage spell will do, depending on it's rank. To know will it kill the target, or will it not. Am i able to get spell rank somehow, or make it work any other way maybe?

Logging.Write(Lua.LuaDoString<string>("name, rank, icon, castTime, minRange, maxRange = GetSpellInfo(\"Shadow Word: Pain\")", "rank"));

Can be used. But i guess you could also need "desc = GetSpellDescription(spellId)" but unfortunately for me it doesn't return any string to parse the damage values.

1 hour ago, Findeh said:

2) This will be a wery stupid one. I don't get, how some events works. I'm decompiling wManager with ILSpy. Going to wManager/wMnager.Events/ and can't understand the order they are triggering each other at.
For example, if i got "internal void BuffRotation()" class inside my FC, will it use it only after the fight, or only during the fight, or maybe it will use it during patrol?

Ok let's take FightEvents. I linked a fightclass which has "internal void BuffRotation()" on a loop. Once "public void Initialize()" is called from the interface(start bot), it will loop this method till you stop the bot.

So that means the buffrotation aswell the other methods in your fightclass having no impact / affiliation on "FightEvents".

The "FightEvents" or the other events in WRobot are triggered from the bot behavior itself (you can imagine like a guy reporting you what he's doing).

So this "guy" tells you:

     I attack now this npc  = "wManager.Events.FightEvents.OnFightStart"

     While fighting i also report whats going on every ~30ms = "wManager.Events.FightEvents.OnFightLoop"

     the fight is over = "wManager.Events.FightEvents.OnFightEnd"

This is useful for plugins for example but if you are going to write a fightclass, you wouldn't really need it.

If you want to write a plugin which uses an item or do other action after a fight end, you could subscribe it like this:

            wManager.Events.FightEvents.OnFightEnd += delegate
            {
                wManager.Wow.Helpers.SpellManager.CastSpellByIdLUA(8690); //cast hearthstone
            };

 

1 hour ago, Findeh said:

But bot will not use "SpellName" anyway because there is no such event where i can place it? Right?

If you write an plugin you could use your snippet on a loop or by subscribing it to "wManager.Events.MovementEvents.OnMoveToPulse".

But i guess you are writing a fightclass anyway, so you can put this snippet to buffrotation or directly to while loop:

    internal void BuffRotation()
    {
        if (ObjectManager.Me.IsMounted)
            return;
        //if not mounted cast sprint
        var spelltocast = new Spell("Sprint");
        if (wManager.Wow.Bot.States.ToTown.GoToTownInProgress && spelltocast.IsSpellUsable)
        {
            spelltocast.Launch();
        }
    }

or directly in while loop:

    internal void Rotation()
    {

        Logging.Write("[My fightclass] Is started.");
        while (_isLaunched)
        {
            try
            {
                if (!Products.InPause)
                {
                    if (!ObjectManager.Me.IsDeadMe)
                    {
                        BuffRotation();

                        var spelltocast = new Spell("Sprint");
                        if (wManager.Wow.Bot.States.ToTown.GoToTownInProgress && spelltocast.IsSpellUsable && !ObjectManager.Me.IsMounted)
                        {
                            spelltocast.Launch();
                        }

                        if (Fight.InFight && ObjectManager.Me.Target > 0)
                        {
                            Pull();
                            CombatRotation();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logging.WriteError("[My fightclass] ERROR: " + e);
            }

            Thread.Sleep(10); // Pause 10 ms to reduce the CPU usage.
        }
        Logging.Write("[My fightclass] Is now stopped.");
    }

So you can see in the end it doesn't really matter. It's just for a better structure & readability.

Some event samples

                #region Events

                // Listen to events
                EventsLuaWithArgs.OnEventsLuaWithArgs += delegate (LuaEventsId id, List<string> args)
                {
                    #region PLAYER_REGEN_ENABLED

                    if (id == LuaEventsId.PLAYER_REGEN_ENABLED)
                    {
                        Functions.InCombat = false;
                    }

                    if (id == LuaEventsId.PLAYER_REGEN_DISABLED)
                    {
                        Functions.InCombat = true;
                    }

                    #endregion

                    #region MODIFIER_STATE_CHANGED

                    if (id == LuaEventsId.MODIFIER_STATE_CHANGED && args.Count == 2)
                    {
                        //  Possible values are LSHIFT, RSHIFT, LCTRL, RCTRL, LALT, and RALT
                        string key = args[0];

                        // 1 means that the the key has been pressed. 0 means that the key has been released
                        int state = int.Parse(args[1]);

                        // AOE mode
                        if (key == "LALT" && state == 0)
                        {
                            // Set status
                            rotation.AoeMode = !rotation.AoeMode;

                            // Write to chat
                            string message = $"iRotation AoeModes: {(rotation.AoeMode ? "|cFF00FF00On.|r" : "|cFFFF0000Off.|r")}";
                            Lua.LuaDoString($"print(\"{message}\")");
                        }

                        // Burst mode
                        if (key == "LCTRL" && state == 0)
                        {
                            // Set status
                            rotation.BurstMode = !rotation.BurstMode;

                            // Write to chat
                            string message = $"iRotation BurstMode: {(rotation.BurstMode ? "|cFF00FF00On.|r" : "|cFFFF0000Off.|r")}";
                            Lua.LuaDoString($"print(\"{message}\")");
                        }
                    }

                    #endregion
                };

                #endregion

 

You have convinced me. For items use, i'll better write a plugin separately from the Fight Class. Thank you.

Seems like did evrithing except one thing, thank to your answers. Much appreciate it.

Thing that i stuck at is Spell Rank. Seems like i'm just handicapped. What this string should return?

3 hours ago, reapler said:

Logging.Write(Lua.LuaDoString<string>("name, rank, icon, castTime, minRange, maxRange = GetSpellInfo(\"Shadow Word: Pain\")", "rank"));

If do understand it right, GetSpellInfo Will return SpellInfo object, that is, according to wManager/wManager.Wow.Class :

public class SpellInfo
	{
		public uint ID;
		public string Name = "";
		public string SubName = "";
		public string Icon = "";
		public int CastTime;
		public float MinRange;
		public float MaxRange;
	}

Seems like i don't get it :(  there is no spell rank field, anyway :(

The goal is to calculate damage. I can make a table with all Spell damage numbers depending on it's rank. (Some damage are static in vanilla).
Then all i need to get a current rank of the spell as an integer, then get a damage number for it from the table and compare that damage number with current health of the target.
if (ObjectManager.Target.Health <= damage) we should use the spell.
else we should not.

This is a main thing i'm stuck at :( Can't solve it.

I do need my rogue to know, should he use Eviscerate at 2 Combo Points and that will end the fight, or wait should it wait for 3 or for 4 and so on. As far as i see, most of rogue fight class that i am able to download, just use Eviscerate when reach some static combo point number (3 or 5) without any logic behind it.

 

55 minutes ago, Findeh said:

If do understand it right, GetSpellInfo Will return SpellInfo object, that is, according to wManager/wManager.Wow.Class :

Yes, that's right but with my snippet you get a string from your spell with lua in this case: "Shadow Word: Pain".

 

I made a simple method:

    public Spell Spell_(string name) => new Spell(name)
    {
        Icon = 
            Lua.LuaDoString<string>(
                "name, rank, icon, castTime, minRange, maxRange = GetSpellInfo(\"" + name + "\")", "rank")
    };

This overrides "Icon" to spell's rank. I guess it's not added in vanilla, because it was forgotten as it was backported :)

 

Usage:

    public void Initialize()
    {
        wManager.Wow.Class.Spell eviscerate = Spell_("Eviscerate");
        robotManager.Helpful.Logging.Write("Get information of spell: " + eviscerate.Name);
        robotManager.Helpful.Logging.Write("Spell rank: "+eviscerate.Icon);//now field ".Icon" returns the rank if you use "public Spell Spell_(string name) => new Spell(name)"
        robotManager.Helpful.Logging.Write("Spell id: "+eviscerate.Id);
    }

 

Thanks alot for your help and answers, but guess i'll give up soon.
Can't make it work. Just getting a bunch of errors when i start it with this code.

Additionally, trying to force it use some spells when there is 2 or more attackers around. Using constuction like this:

// If we are under attack from 3 or more mobs use Adrenaline Rush
		if (ObjectManager.GetUnitAttackPlayer().Count(u => u.GetDistance <= 6) > 2)
		{
			if (AdrenalineRush.KnownSpell && AdrenalineRush.IsSpellUsable)
			{
				AdrenalineRush.Launch();
			}
		}

But then again, got an errors saying that .Count can't be used like that. Don't know why again, because there is no documentation.

Addittionally my bots don't skin units, have tryed different min and max MS settings, 0-100, 30-50, 30-100, 300-500, even 100-1000, no result.

No metter what FC am i using, mine one, or downloaded, my bots only autoattack and not using any spells. Again, i don't get why. Is it a trial version issue or what? If it's so, how am i able to understand will it do all i need him to do, or will it just move around botlike and autoattack till get banned in a hour, because it looks wery botish

It's funny, I was just trying to do something similar in C# wanting to use an ability if certain amount of hostiles was within my range, and I am getting the same error with .Count:

Quote

Non-invocable member 'System.Collections.Generic.List<wManager.Wow.ObjectManager.WoWUnit>.Count' cannot be used like a method.

 

Yeah, the error message is very clear. Count is a property, you cannot call it like a method (such as "Count(args...)").

if (ObjectManager.GetUnitAttackPlayer().Where(u => u.GetDistance <= 6).ToList().Count > 2)

Should do the trick

Thanks @Matenia for the assist with the count issue!  I am going to try it out now.

Error:

'System.Collections.Generic.List<wManager.Wow.ObjectManager.WoWUnit>' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument of type 'System.Collections.Generic.List<wManager.Wow.ObjectManager.WoWUnit>' could be found (are you missing a using directive or an assembly reference?)

 

@apexx Namespace System.Linq is not referenced. So you need to copy this on the top of your code:

using System.Linq;

Both .Where() & .Count() are included in Linq, that's the reason why .Count() couldn't work because it doesn't had an overload available.

So in the end you can use this:

            if (ObjectManager.GetUnitAttackPlayer().Count(u => u.GetDistance <= 6) > 2)
            {
            }

Or use other Linq methods.

25 minutes ago, reapler said:

@apexx Namespace System.Linq is not referenced. So you need to copy this on the top of your code:


using System.Linq;

Both .Where() & .Count() are included in Linq, that's the reason why .Count() couldn't work because it doesn't had an overload available.

So in the end you can use this:


            if (ObjectManager.GetUnitAttackPlayer().Count(u => u.GetDistance <= 6) > 2)
            {
            }

Or use other Linq methods.

Didn't know Linq hatd Count() - for some reason I had gotten compile errors before. iMod recently told me I could use .NET later than 4.0 too, maybe that's why I hadn't noticed it so far.

I am using Visual Studio 2013 with .Net Framework 4.5

Before you guys supplied me with the Namespace System.Linq reference, I managed to get my rotation working using

private int HostileUnitsInRange(int range)
    {
        var unitAttackPlayer = ObjectManager.GetUnitAttackPlayer();

        if (unitAttackPlayer.Count <= 0)
            return 0;

        var hostileUnitsAttacking = unitAttackPlayer.FindAll(u => u != null && u.IsValid && u.IsTargetingMe && u.GetDistance <= range);
        return hostileUnitsAttacking.Count;
    }

 

  • 3 weeks later...

Good day, guys.

I'm tyrying to make a construction that checks is target can bleed or not. Have found the CreatureTypeTarget() function, that returns String, but not sure how should i compare strings in c#. Trying to use that construction, but it says something like: "wManager.Wow.ObjectManager.WowUnit.CreatureTypeTarget can not be used as a method".

private bool TargetCanBleed()
	{
		return ( (object.Equals("Elemental", ObjectManager.Me.CreatureTypeTarget())) || 
			 (object.Equals("Mechanical", ObjectManager.Me.CreatureTypeTarget())) );
	}

 

How should i compare them right, to make function return bool result? Thank you in advance for any advices.

 

 

@Findeh

    private bool CanBleed(WoWUnit unit)
    {
        return unit.CreatureTypeTarget != "Elemental" 
               && unit.CreatureTypeTarget != "Mechanical";
    }

Usage:

        if (CanBleed(ObjectManager.Me.TargetObject))
        {
            new Spell("Rend").Launch();
        }

 

Got a new problem now, at my rotation the is peace of code for Buff
i have formed it as a void Buff() function and placed all buffs inside, no problems with that.
Now i need to call this function with the criteria:
"if not fighting"

the problem is, if i place it inside the if (!ObjectManager.Me.IsDeadMe) without any criteria, like this:
 

if (!ObjectManager.Me.IsDeadMe)
{
	Buff();

	if (Fight.InFight && ObjectManager.Me.Target > 0)
	{
		FightRotation();
  	}
}


then i'll buff during combat as well.


if i place it with criteria like this:

if (!ObjectManager.Me.IsDeadMe)
{
	if (!Fight.InFight)
	{
		Buff();
	}

	if (Fight.InFight && ObjectManager.Me.Target > 0)
	{
		FightRotation();
  	}
}

The weird things happens. For example, bot runs, decides to Buff(), goes inside that function, body-pulls the mob (just because continue to run his path, for example). Now he is in combat, but he does not live Buff() function, and don't continue to buff, even though his buffs are usable in combat. Guess it's because of !Fight.InFight criteria before Buff().
So he just autoattack the mob, don't do FightRotation() because he is not in the FightRotation() code block.

If he kills the mob with his autoattack, he just continue to buff from the place where he stopt and then runs as normal, till the next situation like this.

So i need to code a condition where Buff() will be priority number 1, but only if we not in combat. And if during the buff the combat started, we should quit the Buff() and start the FightnRotation()

Is it even possible? Thank you in advance.

Okay, nwm, have fixed that with !ObjectManager.Me.InCombat
So if some one interested:
 

if (!ObjectManager.Me.IsDeadMe)
{
	if (!ObjectManager.Me.InCombat)
	{
		Buff();
	}

	if (Fight.InFight && ObjectManager.Me.Target > 0)
	{
		FightRotation();
  	}
}


This will work. You will stop do Buff(), quit this code section and will go to FightRotation if during the Buff() the combat was started.

Question is still open. Why is it happening? Why bot is not following the code in FC?
Additional things
1) Any default (in build) function to cencel shapesifting?
2) How to crate Fairie Fire (Feral) spell?
public Spell FaerieFire = new Spell("Faerie Fire (Feral)");
and
public Spell FaerieFire = new Spell("Faerie Fire (Feral)()");
Not working for me.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...