Jump to content

CastSpell improvement


iMod

Recommended Posts

Hello, I was writing a small method that handles casting spells for me and I'm looking for some improvements for it. May you see some issues.

        /// <summary>
        /// Cast a spell
        /// </summary>
        /// <param name="spell">The spell you want to cast</param>
        /// <param name="target">The target you want to cast at</param>
        /// <param name="debuff">The debuff we are looking for</param>
        /// <param name="buffTimeLeft">Recast if buff time is under the given time</param>
        /// <param name="stacks">How much stacks you want at the target</param>
        /// <param name="owner">Flag that determines if we need to be the owner</param>
        /// <param name="force">Force use the skill and ignore debuffs</param>
        /// <returns>Returns true if we can cast the spell otherwise false</returns>
        public static bool CastSpell(Spell spell, WoWUnit target, double buffTimeLeft = 0, int stacks = 0, Spell debuff = null, bool owner = true, bool force = false)
        {
            // Check if the spell is known
            if (!Functions.IsSpellKnown(spell) || target == null)
            {
                // Skip
                return false;
            }

            // Check if buff exists
            bool hasDebuff;
            if (debuff != null)
            {
                hasDebuff = Functions.HasBuff(debuff, target, buffTimeLeft, stacks, owner);
            }
            else
            {
                hasDebuff = Functions.HasBuff(spell, target, buffTimeLeft, stacks, owner);
            }

            // Validate spell
            if (!ObjectManager.Me.IsStunned && !ObjectManager.Me.IsDead && !ObjectManager.Me.IsCast && !target.IsDead && spell.IsSpellUsable && (ObjectManager.Me.Position.DistanceTo(target.Position) <= spell.MaxRange) && (force || !hasDebuff) && !TraceLine.TraceLineGo(target.Position))
            {
                if (target.Guid == ObjectManager.Me.Guid)
                {
                    // Cast on self
                    Lua.LuaDoString($"CastSpellByID({spell.Id}, \"player\")");
                }
                else if (ObjectManager.Me.TargetObject.Guid == target.Guid)
                {
                    // Cast on target
                    Lua.LuaDoString($"CastSpellByID({spell.Id}, \"target\")");
                }
                else if (ObjectManager.Me.TargetObject.Guid != target.Guid)
                {
                    // Offset 3.3.5a
                    uint mouseOverGUID = 0x00BD07A0;

                    // Set target
                    Memory.WowMemory.Memory.WriteUInt64(mouseOverGUID, target.Guid);

                    // Cast on mouseover
                    Lua.LuaDoString($"CastSpellByID({spell.Id}, \"mouseover\")");
                }
                else
                {
                    throw new Exception("Something went wrong with the targeting.");
                }

                // Log
                Logging.WriteDebug($"Cast: {spell.NameInGame} at {target.Name}");

                // Wait until global cooldown is done
                Thread.Sleep(SpellManager.GlobalCooldownTimeLeft());

                // Return
                return true;
            }

            // Return
            return false;
        }

Would be glad if someone could overlook it.

Thanks in andvance
iMod

Edited by iMod
Method update
Link to comment
Share on other sites

41 minutes ago, Schaka said:

Should probably also have some smart way of checking whether the spell is off the GCD - like any interrupt.

Should be checked by "spell.IsSpellUsable"

Link to comment
Share on other sites

49 minutes ago, Schaka said:

No, because you already exit the function, before you get that far.

True, forgot to remove the lines y.y I'm not checking anymore if the GCD is > 0 since i wait at the bottom.

Link to comment
Share on other sites

Hello i have also written something similar on another script language. My method was to register the combatlog and set a timer with a boolean value on it when a spell was cast by me(you can add to this latency & some personal preferences to it).

I've done this, because (for me) the api function wasn't accurate enough.

 

and you can also add some overloads to your method if you need them for e.g.

with list debuffs:

public static bool CastSpell(Spell spell, WoWUnit target, double buffTimeLeft = 0, int stacks = 0, List<Spell> debuffs = null, bool owner = true, bool force = false)
{
	//...
}

 

or with spellname instead:

public static bool CastSpell(string spellname, WoWUnit target, double buffTimeLeft = 0, int stacks = 0, Spell debuff = null, bool owner = true, bool force = false)
{
	//...
}

 

Link to comment
Share on other sites

11 minutes ago, reapler said:

Hello i have also written something similar on another script language. My method was to register the combatlog and set a timer with a boolean value on it when a spell was cast by me(you can add to this latency & some personal preferences to it).

I've done this, because (for me) the api function wasn't accurate enough.

 

and you can also add some overloads to your method if you need them for e.g.

with list debuffs:


public static bool CastSpell(Spell spell, WoWUnit target, double buffTimeLeft = 0, int stacks = 0, List<Spell> debuffs = null, bool owner = true, bool force = false)
{
	//...
}

 

or with spellname instead:


public static bool CastSpell(string spellname, WoWUnit target, double buffTimeLeft = 0, int stacks = 0, Spell debuff = null, bool owner = true, bool force = false)
{
	//...
}

 

Thanks, i still had some other overloads but i never used them so they'r gone. So what kind of language are you using for it? I also thought about to use the ingame function instead of lua. I wish i could just use the hook to load my own object manager and own object classes but it seems i have to write my own for it y.y

Link to comment
Share on other sites

@iMod I've used a more or less modified lua engine from a guy that had written it for 4.3.4 but i got tired with cataclysm and couldn't use the stuff for other Wow expansions(so i came here and learned abit C#) and with objectmanager/hook i'm not sure but i don't think you need to write much or? i mean you can get the base address, pointers and as well other objects and lookup/add descriptors or offsets from the already existing manager. For e.g. i needed something to check a descriptorfield wheter item is soulbound or not(i don't know anymore where exactly i've found it) but i figured out later that the function already exist haha

Anyway here is how it looked like:

    public class Descriptor
    {
        private static uint Descriptor_Offset = 0x8;

        //not in api Can be added later
        /*public static uint Read(WoWDynamicObject obj, Descriptors.DynamicObjectFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }*/

        public static uint Read(WoWItem obj, Descriptors.ItemFields field)
        {
            return Read(obj.GetBaseAddress, (uint) field);
        }

        public static uint Read(WoWObject obj, Descriptors.ObjectFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }

        public static uint Read(WoWContainer obj, Descriptors.ContainerFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }

        public static uint Read(WoWCorpse obj, Descriptors.CorpseFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }
        
        public static uint Read(WoWGameObject obj, Descriptors.GameObjectFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }

        public static uint Read(WoWPlayer obj, Descriptors.PlayerFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }

        public static uint Read(WoWUnit obj, Descriptors.UnitFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }

        public static uint Read(uint obj, uint field )
        {
            try
            {
                if (obj != null)
                {
                    uint address = Memory.WowMemory.Memory.ReadUInt32(obj + Descriptor_Offset);
                    return Memory.WowMemory.Memory.ReadUInt32(address + field);
                }

            }
            catch (Exception ex)
            {
                Logging.WriteError("Error: " + ex);
                return 0;
            }
            return 0;
        }
        //Add Write
    }

Maybe you also don't need to write for yourself for your goal

Link to comment
Share on other sites

7 minutes ago, reapler said:

I've used a more or less modified lua engine from a guy that had wriiten it for 4.3.4 but i got tired with cataclysm and couldn't use the stuff for other Wow expansions(so i came here and learned abit C#) and with objectmanager/hook i'm not sure but i don't think you need to write much or? i mean you can get the base address, pointers and as well other objects and lookup/add descriptors or offsets from the already existing manager. For e.g. i needed something to check a descriptorfield wheter item is soulbound or not(i don't know anymore where exactly i've found it) but i figured out later that the function already exist haha

Anyway here is how it looked like:


    public class Descriptor
    {
        private static uint Descriptor_Offset = 0x8;

        //not in api Can be added later
        /*public static uint Read(WoWDynamicObject obj, Descriptors.DynamicObjectFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }*/

        public static uint Read(WoWItem obj, Descriptors.ItemFields field)
        {
            return Read(obj.GetBaseAddress, (uint) field);
        }

        public static uint Read(WoWObject obj, Descriptors.ObjectFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }

        public static uint Read(WoWContainer obj, Descriptors.ContainerFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }

        public static uint Read(WoWCorpse obj, Descriptors.CorpseFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }
        
        public static uint Read(WoWGameObject obj, Descriptors.GameObjectFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }

        public static uint Read(WoWPlayer obj, Descriptors.PlayerFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }

        public static uint Read(WoWUnit obj, Descriptors.UnitFields field)
        {
            return Read(obj.GetBaseAddress, (uint)field);
        }

        public static uint Read(uint obj, uint field )
        {
            try
            {
                if (obj != null)
                {
                    uint address = Memory.WowMemory.Memory.ReadUInt32(obj + Descriptor_Offset);
                    return Memory.WowMemory.Memory.ReadUInt32(address + field);
                }

            }
            catch (Exception ex)
            {
                Logging.WriteError("Error: " + ex);
                return 0;
            }
            return 0;
        }
        //Add Write
    }

Maybe you also don't need to write for yourself for your goal

Thanks dude, i still have all descriptor and offsets i think but my problem atm is that i have some trouble with the asm stuff ^.^ I think i just need to invest some more time in it to get everything nice and clean :) Yeah this bot was way cleaner few years ago =/ now it feels kinda overloaded and slow and this lua memory issue is horrible =/

Link to comment
Share on other sites

Hey reapler do you know haw to cast the spell on guid without targeting ,focusing etc? It was possible on cata (wow+ hack ) to use spell on enemy unit ( like interrupt or something ) without targetting it so you don't loose your focus and target ( very nice for arenas etc ) it was like third focus and when you cast a spell it land on the target and it was in the combat log but there was no targeting the target whatsoever it was working thru simple CastSpellByName("spellname",characterGuid) but I thing there was some kind of internall wraper inside the wow+ or some modification to cast spell by name lua function.

Link to comment
Share on other sites

2 hours ago, forerun said:

Oh well something new but I don't dig in asm ( :( ) Can you write here how to do it for 5.4.8 pandaria ? Plz ;) I can manage c# but not how to use the internal function from wrobot level.

Never tried it with wrobot but i will give it a try later.

Take a look at "Marshal.GetDelegateForFunctionPointer"

[5.4.8 18414]
CastSpell = 0x4F9983

Update:
Some problems with rebase the pointer.

Link to comment
Share on other sites

Hello, to use descriptor you can use WRobto API like:

uint address = wManager.Wow.ObjectManager.ObjectManager.Me.GetDescriptorAddress(wManager.Wow.Patchables.Descriptors.PlayerFields.NextLevelXP);
int result = wManager.Wow.Memory.WowMemory.Memory.ReadInt32(address);

If you don't want to use focus, you can try to use "mouseover":

                    WoWUnit target; // ... your target
                    uint s_MouseOver = 0x00BD0798; // 3.3.5 http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/298310-3-3-5-offsets.html#post1902575
                    wManager.Wow.Memory.WowMemory.Memory.WriteUInt64(s_MouseOver, target.Guid);
                    SpellManager.CastSpellByNameOn("Spell Name", "mouseover");

 

Link to comment
Share on other sites

3 hours ago, Droidz said:

Hello, to use descriptor you can use WRobto API like:


uint address = wManager.Wow.ObjectManager.ObjectManager.Me.GetDescriptorAddress(wManager.Wow.Patchables.Descriptors.PlayerFields.NextLevelXP);
int result = wManager.Wow.Memory.WowMemory.Memory.ReadInt32(address);

If you don't want to use focus, you can try to use "mouseover":


                    WoWUnit target; // ... your target
                    uint s_MouseOver = 0x00BD0798; // 3.3.5 http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/298310-3-3-5-offsets.html#post1902575
                    wManager.Wow.Memory.WowMemory.Memory.WriteUInt64(s_MouseOver, target.Guid);
                    SpellManager.CastSpellByNameOn("Spell Name", "mouseover");

 

I guess that's a brilliant solution to overwrite guid for this purpose :) but it needs the mouseoverguid instead of mouseover for 3.3.5:

        public void CastSpell(string spellName, WoWUnit unit)
        {
            uint MouseOverGUID = 0x00BD07A0;
            wManager.Wow.Memory.WowMemory.Memory.WriteUInt64(MouseOverGUID, unit.Guid);
            SpellManager.CastSpellByNameOn(spellName, "mouseover");
        }

and @forerun i belive you need to search it couldn't find the offset myself currently :/

 

Link to comment
Share on other sites

6 hours ago, Droidz said:

Hello, to use descriptor you can use WRobto API like:


uint address = wManager.Wow.ObjectManager.ObjectManager.Me.GetDescriptorAddress(wManager.Wow.Patchables.Descriptors.PlayerFields.NextLevelXP);
int result = wManager.Wow.Memory.WowMemory.Memory.ReadInt32(address);

If you don't want to use focus, you can try to use "mouseover":


                    WoWUnit target; // ... your target
                    uint s_MouseOver = 0x00BD0798; // 3.3.5 http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/298310-3-3-5-offsets.html#post1902575
                    wManager.Wow.Memory.WowMemory.Memory.WriteUInt64(s_MouseOver, target.Guid);
                    SpellManager.CastSpellByNameOn("Spell Name", "mouseover");

 

Disables my right click and i can't turn my camera anymore for some reasons o.O kinda strange

Link to comment
Share on other sites

Ok I get it working 5.4.8 18414 offset.

MouseGuid  = Wow.exe+D65B28

After that all is ok and you can cast havoc on not current target without changing the current target and spam shadowburn without changing current target - useful thing. And I don't get strange behaviour nothing is blocked etc. I can run around cast shadwoburn and nuke main target in the same time.

 

Link to comment
Share on other sites

1 hour ago, forerun said:

Ok I get it working 5.4.8 18414 offset.

MouseGuid  = Wow.exe+D65B28

After that all is ok and you can cast havoc on not current target without changing the current target and spam shadowburn without changing current target - useful thing. And I don't get strange behaviour nothing is blocked etc. I can run around cast shadwoburn and nuke main target in the same time.

 

Sounds good i think i have to test the other pointer that @reapler posted. Hopefully its the solution.

Link to comment
Share on other sites

Ok don't wanna be rude but

0x00BD0798

Is static ? If so you need add wow base memory adress to that to work. On panda you need to do that because the base is different each time wow is executed so the final adress will be different. In the code above that thing is not present.

Link to comment
Share on other sites

13 minutes ago, forerun said:

Ok don't wanna be rude but


0x00BD0798

Is static ? If so you need add wow base memory adress to that to work. On panda you need to do that because the base is different each time wow is executed so the final adress will be different. In the code above that thing is not present.

Thats not rude ;) i'm kinda new to that stuff so i'm glad if i get some infos. I'll try that out later.

Link to comment
Share on other sites

Allright it is working now :angry: had some issues in my spell logic. Oh and btw I don't need to add the base. I noticed one issue... sometimes the game switches the target to the mouseover mob.

Update: Yey it seems that if the target you have is not attaking you it will target the "mouseover" mob.
              First post updated.

Link to comment
Share on other sites

  • 1 month later...

So, I've tried using this MouseOver cast on Live, and I am not having any luck.

I tried @Droidz method above, like this

            uint s_MouseOverGUID = 0x00F3EDC0;
            Memory.WowMemory.Memory.WriteInt128(s_MouseOverGUID, target.Guid);

            SpellManager.CastSpellByNameOn(spell.Name, "mouseover");

This gives me You Have No Target in game unless I actually move the mouse over a target, and it will cast on that target even if the target I'm trying to override mouse-over for is a different target.

I got the offset from here: http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/619264-wow-7-2-0-24015-offsets-post3731214.html#post3731214

I tried the LUA method like this:

            uint s_MouseOverGUID = 0x00F3EDC0;
            Memory.WowMemory.Memory.WriteInt128(s_MouseOverGUID, target.Guid);

            Lua.LuaDoString(string.Format("CastSpellByID(\"{0}\", \"mouseover\")", spell.Id.ToString()));

And get the same thing.

Suggestions?

Link to comment
Share on other sites

@jrouten I think you should use 'WriteUInt64'. I guess your returned value from memory is also an ulong(=UInt64) variable like your target.guid. I belive they haven't changed it til legion.

Otherwise you can check whether the offset is really returning your mouseover guid:

At first pick any non moving npc and target it. Try to move your character to a position where the npc is on the left corner on the top of your wow window. Now you need to mouse over the npc(tooltip shouldn't disappear) and get out of the window. As next step you can execute this method to check if the offset is returning the right value:

        public void checkoffset()
        {
            uint MouseOverGUID = 0x00F3EDC0;
            if (wManager.Wow.Memory.WowMemory.Memory.ReadUInt64(MouseOverGUID) == ObjectManager.Me.Target)
            {
                robotManager.Helpful.Logging.Write("offset ok");
            }
            else
            {
                robotManager.Helpful.Logging.Write("Got different values:\n"
                    +"Read guid from memory: "+ wManager.Wow.Memory.WowMemory.Memory.ReadUInt64(MouseOverGUID) +"\nNeeded guid: "+ ObjectManager.Me.Target);
            }
        }

If you've done everything right & it still prints different values you have no choice to search it by yourself ;)

You can take for this task a safe memory tool to search for it or searching it with wrobot in a read loop. First option would be better but i don't know if the tools like cheat engine are safe on live.

 

In the end i can't offer more help(i have no live-account) so i wish you good luck

Link to comment
Share on other sites

I tried using WriteUInt64, but it generates an error since Target.Guid is an Int128.

I was also nervous about using any of the known memory tools with Live, so was hoping to figure this out without having to poke/search. If all else fails, I guess I can create a new account and run it in a VM with proxy

Link to comment
Share on other sites

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...