[Wow classic TBC] A start point to make your own bot menu

User Tag List

Results 1 to 2 of 2
  1. #1
    0xd5d's Avatar Member
    Reputation
    11
    Join Date
    Mar 2021
    Posts
    20
    Thanks G/R
    22/5
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [Wow classic TBC] A start point to make your own bot

    Hey there,
    I've been lurking on this forum for a while now. After all I got from it, I think it's now my turn to contribute
    This post will describe my 1+ year journey making a bot, and will reference other useful links. I hope this thread can be the starting point for other people to start making wow bots :-)

    About me: I'm a software engineer in a big tech company everyone knows, with 5+ year of experience. I've always been amazed by the World of Warcraft game. I've started making very uneffective bots when I was younger. Now, making bots that really work is not only a way to learn a lot, but also to avoid spending hours killing pigs in the game :-)




    1. The pixel bot

    Before diving into implementation, I've first did some investigations about how to make a bot. I've read a couple of books, and I came to the conclusion that making memory editing bots was too risky (Blizzard detection leading to ban) and too complex.
    So I first started to make a pixel bot whose goal was to farm mobs and level up my character.

    What is a pixel bot ?
    It's a program which reads pixel in the game as input, to take decisions. I'm not going to spend a lot of time on that part, because making a pixel bot is actually not very complex and there are already plenty very useful resources on that forum.
    For instance: How to make a bot kind of tutorial => wow...-tutorial.html
    Example to add colored pixel in a wow lua addon: Happy-Pixels/DataToColor at master . MicahRCM/Happy-Pixels . GitHub

    There are 2 interesting parts here that I'd like to mention:

    A/ Navigation system
    The bot was getting the position from pixels in the game representing the lua code: UnitPosition("Player"). To build a navigation system, I've made a tool to record the position of the player. This tool had a GUI which allowed me to "click" to mark a cell (= a (x,y) position) as non walkable. So given a zone where I wanted my character to farm, I first had to walk through that zone and mark the non walkable parts of it. Recording those points allowed me to find the walkable / non walkable part, hence providing enough data for my character to randomly walk in a given zone.

    The algorithm was that one:
    * Find a random destination in the current zone
    * Go to that destination (use A* algorithm)
    * While walking, if there are mobs, start a fight.

    The mob selection was simply made by pressing tab regularly & checking the target of my character.

    The facing algorithm (given a position A and an Orientation, which angle do you turn to face position B?) can be deduced for the other "kinda tutorial" thread

    Code:
            double getangle(double y1, double y2, double x1, double x2)
                {
                double ang =    Math.Atan2(x1 - x2, y1 - y2)/Math.PI;
                if (ang < 0) ang += 2; // this is used to avoind negative numbers. 
                return Math.Round(ang*1000);
                }
    You'll find this method in other posts as well.

    B/ Looting mobs
    To loot mobs, I've used an image hashing library to recognize the mouse icon. So once the fight was done, I just moved the mouse around the middle of the screen and compared the mouse icon to icon I had previously saved.

    The algorithm was that one:
    * Move the mouse
    * Get current mouse icon
    * ImageHash(current mouse icon) == ImageHash(loot icon) ? => then loot

    You can find more about this technique here: Blog (see the looting part). The used library is that one: GitHub - jforshee/ImageHashing.

    How do you find the mouse icon in [langage]?
    I believe you can type this in google to find it out (this is how I actually did)

    C/ Sending mouse and keyboard events to the game
    This was the hardest part of the pixel bot. To avoid detection, I've made a driver which runs in kernel mode. And I spent a lot of time trying to test it, because I was using an Hyper V virtual machine and it is actually not supported So even if my driver was working, I couldn't test it through the virtual machine.
    A nice resource to build a windows driver: Write a Hello World Windows Driver (KMDF) - Windows drivers | Microsoft Docs
    Another one: https://docs.microsoft.com/en-us/win...client-drivers
    Third one: https://github.com/MicrosoftDocs/win...ent-drivers.md
    You can also find github example of HID keyboard & mouse kernel mode driver.

    Overall, the pixel bot did a great job and I successfully reached level 70 and got rich enough to buy the fast flying mount.
    But there were some drawbacks:
    * The bot could not work for pvp battleground, because some lua apis are disabled in battleground (like the position)
    * The navigation system was not really precise. Z coordinate can't be retrieved using the LUA API, and the manual recording part was not only tedious but also led to not super precise cells. The navigation was clearly random and I've seen other player detecting my character as a bot because not fighting well enough when attacked in PVP. Actually the bot had no knowledge of its environment.




    2. The memory editing bot

    This is where things get interesting. A memory editing bot is getting information from the wow process memory. It is actually reading the WOW's memory. Such bot can also write to the WOW's memory, for instance to call existing method (example: click to move, providing the position where you want to move to).

    There are kings on this forum (hello Razzue!) who are really good and write posts to give offsets from where you can read the data you want (example: wor...d-43638-a.html).
    The thing is, it's very hard to understand how these people are actually doing to retrieve those offsets. There are some tutorials (like this one: wor...e-stuff-5.html), but overall I think there are missing resources on that topic.

    What are offsets?
    They are actually numbers you can add from a memory pointer to get either a value or another pointer. The nice thing is that they change each time you build a new version of the WoW client, so the offsets have to be looked for again for each client update...

    One way of finding these offset is runtime analysis: analyse wow process memory at runtime. A software like cheat engine can be used to monitor the WoW process memory. The big idea is to look for a value using that tool (for instance, your health) to find out where in memory this value resides. Then, by looking at how this value is accessed (for instance, by attaching a debugger), you can reproduce the value access in an external tool (ex: your bot).
    The goal of this thread is not to make you learn how to use tools like Cheat engine, I believe you can find plenty of existing resources online. I think Blizzard detects the use of cheat engine and this usage can get you banned. To avoid detection, you might rebuild locally a modified version of the software (and change a few things like the software name before rebuilding). But attaching a debugger may trigger Blizzard anti cheat system... (aka Warden)

    Another way to find the offset is to do static analysis. A disassembler is used to transform the binary to "readable" code. So by disassembling the wow client, you get the actual code which gets executed by the WoW client. Then, you can browse it to understand how it works. The nice thing is that once you get a non obfuscated version of the client (see here: https://github.com/maikel233/WoWIDB/.../wow%20classic and there: https://www.ownedcore.com/forums/wor...-memory-5.html and there wor...bfuscator.html), then there is 0 risk for you to get banned while you analyze the binary.
    Once you've conducted your static analysis, you can then try to find an opcode pattern to recognize an offset. If you're a king legend like Razzue, you can then make a tool to automatically detect offsets. As you've understood, this is way out of my knowledge currently.

    What I've done to learn reverse engineering is to download the Ghidra software (https://github.com/NationalSecurityAgency/ghidra) and tried to disassemble an old version of the game (WOW 3.3.5a). Using an old version of the client is easier than the current version because it is obfuscated (see this thread: wor...on-coming.html).
    Overall, I was able thanks to some posts on this forum to understand from Ghidra how to iterate through the object manager, but this was not easy.
    The issue with Ghidra is that it fails at disassembling the actual version of the game unobfuscated (I get a NullReferenceException ). So a concurrent product should be used, for instance, IDA Free version. Many kings on this forum are using IDA Pro, which is expansive. So these kings may actually be professional reverse engineer...

    What is the object manager?
    The object manager is a structure used by WoW to represent the game objects. In this structure, you'll find all players, mobs, herbs, ... So for instance if you want to get all surrounding players, you'll walk the object manager to find those. To iterate through the object manager in wow classic TBC, the Razzue's post linked above can be helpful. For other versions of the game, you can find the answer on this forum (or on existing bots on github...).

    To understand how to use the offsets for WoW classic TBC, you can have a look at existing bot to see the class & enums used: https://github.com/mmalka/TheNoobBot

    Here are key interesting points:
    A/ Navigation system
    This system is based on the pixel bot one. I recommend reading the Pixel bot part first to have a better understanding.

    Overall I recommend having a look at this thread (https://drewkestell.us/Article/6/Chapter/20) which gives a lot of information. To build an effective navigation system, the idea is to use the game map files to build a navigation mesh. I've reused the tools provided in the above article to build the maps used by my bot, but I plan to dig deeper in this part later.
    Currently, the navigation system is working pretty well:
    * Get the position of the player by reading wow process memory (see king Razzue's post)
    * Using Detour, find a path to a destination. You can find more on how to use Detour in drewkestell blog.

    The maps I've used are the ones which were with WoW 3.3.5a version (they are still up to date for Wow classic TBC).

    Here is a nice code to avoid finger injury to convert the map id retrieved using Razzue's offset to a map id used by the blog shared above. I believe you can find the zone id directly in memory, but...I haven't looked for the offset (as mentioned the offset are game version dependent and the WowClassicMapId is freely provided by Razzue in its offset list).

    Code:
    public enum WowClassicMapId
    {
        Ragefire_Chasm_Dungeon_Orgrimmar = 213,
        Zul_Farrak_Orphan_Tanaris = 219,
        The_Temple_of_Atal_Hakkar_Dungeon_Swamp_of_Sorrows = 220,
        Blackfathom_Deeps_Dungeon_Ashenvale_1 = 221,
        Blackfathom_Deeps_Dungeon_Ashenvale_2 = 222,
        Blackfathom_Deeps_Dungeon_Ashenvale_3 = 223,
        The_Stockade_Dungeon_Stormwind_City = 225,
        Gnomeregan_Dungeon_Dun_Morogh_1 = 226,
        Gnomeregan_Dungeon_Dun_Morogh_2 = 227,
        Gnomeregan_Dungeon_Dun_Morogh_3 = 228,
        Gnomeregan_Dungeon_Dun_Morogh_4 = 229,
        Uldaman_Dungeon_Badlands_1 = 230,
        Uldaman_Dungeon_Badlands_2 = 231,
        Molten_Core_Dungeon_Burning_Steppes = 232,
        Dire_Maul_Orphan_Feralas = 234,
        Dire_Maul_Dungeon_Feralas_1 = 235,
        Dire_Maul_Dungeon_Feralas_2 = 236,
        Dire_Maul_Dungeon_Feralas_3 = 237,
        Dire_Maul_Dungeon_Feralas_4 = 238,
        Dire_Maul_Dungeon_Feralas_5 = 239,
        Dire_Maul_Dungeon_Feralas_6 = 240,
        Blackrock_Depths_Dungeon_Searing_Gorge_1 = 242,
        Blackrock_Depths_Dungeon_Searing_Gorge_2 = 243,
        The_Shattered_Halls_Dungeon_Hellfire_Peninsula = 246,
        Ruins_of_Ahn_Qiraj_Orphan_Silithus = 247,
        Onyxia_s_Lair_Dungeon_Dustwallow_Marsh = 248,
        Blackrock_Spire_Dungeon_Burning_Steppes_1 = 250,
        Blackrock_Spire_Dungeon_Burning_Steppes_2 = 251,
        Blackrock_Spire_Dungeon_Burning_Steppes_3 = 252,
        Blackrock_Spire_Dungeon_Burning_Steppes_4 = 253,
        Blackrock_Spire_Dungeon_Burning_Steppes_5 = 254,
        Blackrock_Spire_Dungeon_Burning_Steppes_6 = 255,
        Auchenai_Crypts_Dungeon_Terokkar_Forest_7 = 256,
        Auchenai_Crypts_Dungeon_Terokkar_Forest_8 = 257,
        Sethekk_Halls_Dungeon_Terokkar_Forest_1 = 258,
        Sethekk_Halls_Dungeon_Terokkar_Forest_2 = 259,
        Shadow_Labyrinth_Dungeon_Terokkar_Forest = 260,
        The_Blood_Furnace_Dungeon_Hellfire_Peninsula = 261,
        The_Underbog_Dungeon_Zangarmarsh = 262,
        The_Steamvault_Dungeon_Zangarmarsh_1 = 263,
        The_Steamvault_Dungeon_Zangarmarsh_2 = 264,
        The_Slave_Pens_Dungeon_Zangarmarsh = 265,
        The_Botanica_Dungeon_Netherstorm = 266,
        The_Mechanar_Dungeon_Netherstorm_1 = 267,
        The_Mechanar_Dungeon_Netherstorm_2 = 268,
        The_Arcatraz_Dungeon_Netherstorm_3 = 269,
        The_Arcatraz_Dungeon_Netherstorm_4 = 270,
        The_Arcatraz_Dungeon_Netherstorm_5 = 271,
        ManaTombs_Dungeon_Terokkar_Forest = 272,
        The_Black_Morass_Orphan_Tanaris = 273,
        Old_Hillsbrad_Foothills_Orphan_Tanaris = 274,
        Wailing_Caverns_Dungeon_The_Barrens = 279,
        Maraudon_Dungeon_Desolace_1 = 280,
        Maraudon_Dungeon_Desolace_2 = 281,
        Blackwing_Lair_Dungeon_Burning_Steppes_1 = 287,
        Blackwing_Lair_Dungeon_Burning_Steppes_2 = 288,
        Blackwing_Lair_Dungeon_Burning_Steppes_3 = 289,
        Blackwing_Lair_Dungeon_Burning_Steppes_4 = 290,
        The_Deadmines_Dungeon_Westfall_1 = 291,
        The_Deadmines_Dungeon_Westfall_2 = 292,
        Razorfen_Downs_Dungeon_Thousand_Needles = 300,
        Razorfen_Kraul_Dungeon_The_Barrens = 301,
        Scarlet_Monastery_Dungeon_Tirisfal_Glades_1 = 302,
        Scarlet_Monastery_Dungeon_Tirisfal_Glades_2 = 303,
        Scarlet_Monastery_Dungeon_Tirisfal_Glades_3 = 304,
        Scarlet_Monastery_Dungeon_Tirisfal_Glades_4 = 305,
        ScholomanceOLD_Dungeon_Western_Plaguelands_1 = 306,
        ScholomanceOLD_Dungeon_Western_Plaguelands_2 = 307,
        ScholomanceOLD_Dungeon_Western_Plaguelands_3 = 308,
        ScholomanceOLD_Dungeon_Western_Plaguelands_4 = 309,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_1 = 310,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_2 = 311,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_3 = 312,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_4 = 313,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_5 = 314,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_6 = 315,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_7 = 316,
        Stratholme_Dungeon_Eastern_Plaguelands_1 = 317,
        Stratholme_Dungeon_Eastern_Plaguelands_2 = 318,
        Ahn_Qiraj_Dungeon_Silithus_1 = 319,
        Ahn_Qiraj_Dungeon_Silithus_2 = 320,
        Ahn_Qiraj_Dungeon_Silithus_3 = 321,
        Hyjal_Summit_Orphan_Tanaris = 329,
        Gruul_s_Lair_Dungeon_Blade_s_Edge_Mountains = 330,
        Magtheridon_s_Lair_Dungeon_Hellfire_Peninsula = 331,
        Zul_Aman_Orphan_Ghostlands = 333,
        Tempest_Keep_Dungeon_Netherstorm_1 = 334,
        Tempest_Keep_Dungeon_Netherstorm_2 = 1555,
        Sunwell_Plateau_Dungeon_Isle_of_Quel_Danas = 335,
        Sunwell_Plateau_Dungeon_Sunwell_Plateau = 336,
        Zul_Gurub_Orphan_Stranglethorn_Vale_1 = 233,
        Zul_Gurub_Orphan_Stranglethorn_Vale_2 = 337,
        Black_Temple_Dungeon_Shadowmoon_Valley = 339,
        Hellfire_Ramparts_Dungeon_Hellfire_Peninsula = 347,
        Karazhan_Dungeon_Deadwind_Pass_1 = 350,
        Karazhan_Dungeon_Deadwind_Pass_2 = 351,
        Karazhan_Dungeon_Deadwind_Pass_3 = 352,
        Karazhan_Dungeon_Deadwind_Pass_4 = 353,
        Karazhan_Dungeon_Deadwind_Pass_5 = 354,
        Karazhan_Dungeon_Deadwind_Pass_6 = 355,
        Karazhan_Dungeon_Deadwind_Pass_7 = 356,
        Karazhan_Dungeon_Deadwind_Pass_8 = 357,
        Karazhan_Dungeon_Deadwind_Pass_9 = 358,
        Karazhan_Dungeon_Deadwind_Pass_10 = 359,
        Karazhan_Dungeon_Deadwind_Pass_11 = 360,
        Karazhan_Dungeon_Deadwind_Pass_12 = 361,
        Karazhan_Dungeon_Deadwind_Pass_13 = 362,
        Karazhan_Dungeon_Deadwind_Pass_14 = 363,
        Karazhan_Dungeon_Deadwind_Pass_15 = 364,
        Karazhan_Dungeon_Deadwind_Pass_16 = 365,
        Karazhan_Dungeon_Deadwind_Pass_17 = 366,
        Cosmic_Cosmic = 946,
        Azeroth_World_Cosmic = 947,
        Outland_Continent = 987,
        Durotar_Zone_Kalimdor = 1411,
        Mulgore_Zone_Kalimdor = 1412,
        The_Barrens_Zone_Kalimdor = 1413,
        Kalimdor_Continent_Azeroth = 1414,
        Eastern_Kingdoms_Continent_Azeroth = 1415,
        Alterac_Mountains_Zone_Eastern_Kingdoms = 1416,
        Arathi_Highlands_Zone_Eastern_Kingdoms = 1417,
        Badlands_Zone_Eastern_Kingdoms = 1418,
        Blasted_Lands_Zone_Eastern_Kingdoms = 1419,
        Tirisfal_Glades_Zone_Eastern_Kingdoms = 1420,
        Silverpine_Forest_Zone_Eastern_Kingdoms = 1421,
        Western_Plaguelands_Zone_Eastern_Kingdoms = 1422,
        Eastern_Plaguelands_Zone_Eastern_Kingdoms = 1423,
        Hillsbrad_Foothills_Zone_Eastern_Kingdoms = 1424,
        The_Hinterlands_Zone_Eastern_Kingdoms = 1425,
        Dun_Morogh_Zone_Eastern_Kingdoms = 1426,
        Searing_Gorge_Zone_Eastern_Kingdoms = 1427,
        Burning_Steppes_Zone_Eastern_Kingdoms = 1428,
        Elwynn_Forest_Zone_Eastern_Kingdoms = 1429,
        Deadwind_Pass_Zone_Eastern_Kingdoms = 1430,
        Duskwood_Zone_Eastern_Kingdoms = 1431,
        Loch_Modan_Zone_Eastern_Kingdoms = 1432,
        Redridge_Mountains_Zone_Eastern_Kingdoms = 1433,
        Stranglethorn_Vale_Zone_Eastern_Kingdoms = 1434,
        Swamp_of_Sorrows_Zone_Eastern_Kingdoms = 1435,
        Westfall_Zone_Eastern_Kingdoms = 1436,
        Wetlands_Zone_Eastern_Kingdoms = 1437,
        Teldrassil_Zone_Kalimdor = 1438,
        Darkshore_Zone_Kalimdor = 1439,
        Ashenvale_Zone_Kalimdor = 1440,
        Thousand_Needles_Zone_Kalimdor = 1441,
        Stonetalon_Mountains_Zone_Kalimdor = 1442,
        Desolace_Zone_Kalimdor = 1443,
        Feralas_Zone_Kalimdor = 1444,
        Dustwallow_Marsh_Zone_Kalimdor = 1445,
        Tanaris_Zone_Kalimdor = 1446,
        Azshara_Zone_Kalimdor = 1447,
        Felwood_Zone_Kalimdor = 1448,
        Un_Goro_Crater_Zone_Kalimdor = 1449,
        Moonglade_Zone_Kalimdor = 1450,
        Silithus_Zone_Kalimdor = 1451,
        Winterspring_Zone_Kalimdor = 1452,
        Stormwind_City_Zone_Eastern_Kingdoms = 1453,
        Orgrimmar_Zone_Kalimdor = 1454,
        Ironforge_Zone_Eastern_Kingdoms = 1455,
        Thunder_Bluff_Zone_Kalimdor = 1456,
        Darnassus_Zone_Kalimdor = 1457,
        Undercity_Zone_Eastern_Kingdoms = 1458,
        Alterac_Valley_Zone_Azeroth = 1459,
        Warsong_Gulch_Zone_Azeroth = 1460,
        Arathi_Basin_Zone_Azeroth = 1461,
        Eastern_Kingdoms_Continent = 1463,
        Kalimdor_Continent = 1464,
        Serpentshrine_Cavern_Dungeon_Zangarmarsh_1 = 332,
        Serpentshrine_Cavern_Dungeon_Zangarmarsh_2 = 1554,
        Eversong_Woods_Zone_Eastern_Kingdoms = 1941,
        Ghostlands_Zone_Eastern_Kingdoms = 1942,
        Azuremyst_Isle_Zone_Kalimdor = 1943,
        Hellfire_Peninsula_Zone_Outland = 1944,
        Outland_Continent_Cosmic = 1945,
        Zangarmarsh_Zone_Outland = 1946,
        The_Exodar_Zone_Kalimdor = 1947,
        Shadowmoon_Valley_Zone_Outland = 1948,
        Blade_s_Edge_Mountains_Zone_Outland = 1949,
        Bloodmyst_Isle_Zone_Kalimdor = 1950,
        Nagrand_Zone_Outland = 1951,
        Terokkar_Forest_Zone_Outland = 1952,
        Netherstorm_Zone_Outland = 1953,
        Silvermoon_City_Zone_Eastern_Kingdoms = 1954,
        Shattrath_City_Zone_Outland = 1955,
        Eye_of_the_Storm_Zone_Netherstorm = 1956,
        Isle_of_Quel_Danas_Zone_Eastern_Kingdoms = 1957,
    }
    
    public enum WowMapId
        {
            AhnkahetTheOldKingdom = 619,    // Azjol_LowerCity
            AhnQirajTemple = 531,           // AhnQirajTemple
            AlteracValley = 30,             // PVPZone01
            ArathiBasin = 529,              // PVPZone04
            AuchenaiCrypts = 558,           // AuchindounDraenei
            AzjolNerub = 601,               // Azjol_Uppercity
            AzsharaCrater = 37,             // PVPZone02
            BlackfathomDeeps = 48,          // Blackfathom
            BlackMorass = 269,              // CavernsOfTime
            BlackrockDepths = 230,          // BlackrockDepths
            BlackrockSpire = 229,           // BlackRockSpire
            BlackTemple = 564,              // BlackTemple
            BlackwingLair = 469,            // BlackwingLair
            BladesEdgeArena = 562,          // bladesedgearena
            ChampionsHall = 449,            // AlliancePVPBarracks
            DalaranSewers = 617,            // DalaranArena
            Deadmines = 36,                 // DeadminesInstance
            DeeprunTram = 369,              // DeeprunTram
            DireMaul = 429,                 // DireMaul
            DrakTharonKeep = 600,           // DrakTheronKeep
            EasternKingdoms = 0,            // Azeroth
            EbonHold = 609,                 // DeathKnightStart
            EmeraldDream = 169,             // EmeraldDream
            EyeOfTheStorm = 566,            // NetherstormBG
            Gnomeregan = 90,                // GnomeragonInstance
            GruulsLair = 565,               // GruulsLair
            Gundrak = 604,                  // GunDrak
            HallOfLegends = 450,            // HordePVPBarracks
            HallsOfLighting = 602,          // Ulduar80
            HallsOfReflection = 668,        // HallsOfReflection
            HallsOfStone = 599,             // Ulduar70
            HellfireRamparts = 543,         // HellfireRampart
            IcecrownCitadel = 631,          // IcecrownCitadel
            IsleOfConquest = 628,           // IsleofConquest
            Kalimdor = 1,                   // Kalimdor
            Karazhan = 532,                 // Karazahn
            MagistersTerrace = 585,         // Sunwell5ManFix
            MagtheridonsLair = 544,         // HellfireRaid
            ManaTombs = 557,                // AuchindounEthereal
            Mauradon = 349,                 // Mauradon
            MoltenCore = 409,               // MoltenCore
            NagrandArena = 559,             // PVPZone05
            Naxxramas = 533,                // Stratholme Raid
            Northrend = 571,                // Northrend
            OldHillsbradFoothills = 560,    // HillsbradPast
            OnyxiasLair = 249,              // OnyxiaLairInstance
            Outland = 530,                  // Expansion01
            PitOfSaron = 658,               // QuarryOfTears
            RagefireChasm = 389,            // OrgrimmarInstance
            RazorfenDowns = 129,            // RazorfenDowns
            RazorfenKraul = 47,             // RazorfenKraulInstance
            RuinsOfAhnQiraj = 509,          // AhnQiraj
            RuinsOfLordaeron = 572,         // PVPLordaeron
            ScarletMonastery = 189,         // MonasteryInstances
            Scholomance = 289,              // SchoolofNecromancy
            SerpentshrineCavern = 548,      // CoilfangRaid
            SethekkHalls = 556,             // AuchindounDemon
            ShadowfangKeep = 33,            // Shadowfang
            ShadowLabyrinth = 555,          // AuchindounShadow
            Stormwind = 723,                // Stormwind
            StormwindStockade = 34,         // StormwindJail
            StrandOfTheAncients = 607,      // NorthrendBG
            SunkenTemple = 109,             // SunkenTemple
            TempestKeep = 550,              // TempestKeepRaid
            TheArcatraz = 552,              // TempestKeepArcane
            TheBattleForMountHyjal = 534,   // HyjalPast
            TheBloodFurnace = 542,          // HellfireDemon
            TheBotanica = 553,              // TempestKeepAtrium
            TheCullingOfStratholme = 595,   // StratholmeCOT
            TheEyeOfEternity = 616,         // NexusRaid
            TheForgeOfSouls = 632,          // IcecrownCitadel5Man
            TheMechanar = 554,              // TempestKeepFactory
            TheNexus = 576,                 // Nexus70
            TheObsidianSanctum = 615,       // ChamberOfAspectsBlack
            TheOculus = 578,                // Nexus80
            TheRingOfValor = 618,           // OrgrimmarArena
            TheRubySanctum = 724,           // ChamberOfAspectsRed
            TheShatteredHalls = 540,        // HellfireMilitary
            TheSlavePens = 547,             // CoilfangDraenei
            TheSteamvault = 545,            // CoilfangPumping
            TheSunwell = 580,               // SunwellPlateau
            TheUnderbog = 546,              // CoilfangMarsh
            TrialOfTheChampion = 650,       // ArgentTournamentDungeon
            TrialOfTheCrusader = 649,       // ArgentTournamentRaid
            Uldaman = 70,                   // Uldaman
            Ulduar = 603,                   // UlduarRaid
            UnderMine = 2,                  // UnderMine
            UtgardeKeep = 574,              // Valgarde70
            UtgardePinnacle = 575,          // UtgardePinnacle
            VaultOfArchavon = 624,          // WintergraspRaid
            VioletHold = 608,               // DalaranPrison
            WailingCaverns = 43,            // WailingCaverns
            WarsongGulch = 489,             // PVPZone03
            ZulAman = 568,                  // ZulAman
            ZulFarrak = 209,                // TanarisInstance
            ZulGurub = 309                  // Zul'gurub
        }
    
        private WowMapId ToWowMapId(WowClassicMapId mapId)
        {
            switch (mapId)
            {
                case WowClassicMapId.Ragefire_Chasm_Dungeon_Orgrimmar:
                    return WowMapId.RagefireChasm;
                
                case WowClassicMapId.Zul_Farrak_Orphan_Tanaris:
                    return WowMapId.ZulFarrak;
                    
                case WowClassicMapId.Blackfathom_Deeps_Dungeon_Ashenvale_1:
                case WowClassicMapId.Blackfathom_Deeps_Dungeon_Ashenvale_2:
                case WowClassicMapId.Blackfathom_Deeps_Dungeon_Ashenvale_3:
                    return WowMapId.BlackfathomDeeps;
                
                case WowClassicMapId.The_Stockade_Dungeon_Stormwind_City:
                    return WowMapId.StormwindStockade;
                    
                case WowClassicMapId.Gnomeregan_Dungeon_Dun_Morogh_1:
                case WowClassicMapId.Gnomeregan_Dungeon_Dun_Morogh_2:
                case WowClassicMapId.Gnomeregan_Dungeon_Dun_Morogh_3:
                case WowClassicMapId.Gnomeregan_Dungeon_Dun_Morogh_4:
                    return WowMapId.Gnomeregan;
                
                case WowClassicMapId.Uldaman_Dungeon_Badlands_1:
                case WowClassicMapId.Uldaman_Dungeon_Badlands_2:
                    return WowMapId.Uldaman;
                
                case WowClassicMapId.Molten_Core_Dungeon_Burning_Steppes:
                    return WowMapId.MoltenCore;
                
                case WowClassicMapId.Dire_Maul_Orphan_Feralas:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_1:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_2:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_3:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_4:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_5:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_6:
                    return WowMapId.DireMaul;
                
                case WowClassicMapId.Blackrock_Depths_Dungeon_Searing_Gorge_1:
                case WowClassicMapId.Blackrock_Depths_Dungeon_Searing_Gorge_2:
                    return WowMapId.BlackrockDepths;
                
                case WowClassicMapId.The_Shattered_Halls_Dungeon_Hellfire_Peninsula:
                    return WowMapId.TheShatteredHalls;
                
                case WowClassicMapId.Ruins_of_Ahn_Qiraj_Orphan_Silithus:
                    return WowMapId.RuinsOfAhnQiraj;
                
                case WowClassicMapId.Onyxia_s_Lair_Dungeon_Dustwallow_Marsh:
                    return WowMapId.OnyxiasLair;
                
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_1:
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_2:
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_3:
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_4:
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_5:
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_6:
                    return WowMapId.BlackrockSpire;
                
                case WowClassicMapId.Auchenai_Crypts_Dungeon_Terokkar_Forest_7:
                case WowClassicMapId.Auchenai_Crypts_Dungeon_Terokkar_Forest_8:
                    return WowMapId.AuchenaiCrypts;
                
                case WowClassicMapId.Sethekk_Halls_Dungeon_Terokkar_Forest_1:
                case WowClassicMapId.Sethekk_Halls_Dungeon_Terokkar_Forest_2:
                    return WowMapId.SethekkHalls;
                
                case WowClassicMapId.Shadow_Labyrinth_Dungeon_Terokkar_Forest:
                    return WowMapId.ShadowLabyrinth;
                
                case WowClassicMapId.The_Blood_Furnace_Dungeon_Hellfire_Peninsula:
                    return WowMapId.TheBloodFurnace;
                
                case WowClassicMapId.The_Underbog_Dungeon_Zangarmarsh:
                    return WowMapId.TheUnderbog;
                
                case WowClassicMapId.The_Steamvault_Dungeon_Zangarmarsh_1:
                case WowClassicMapId.The_Steamvault_Dungeon_Zangarmarsh_2:
                    return WowMapId.TheSteamvault;
                
                case WowClassicMapId.The_Slave_Pens_Dungeon_Zangarmarsh:
                    return WowMapId.TheSlavePens;
                
                case WowClassicMapId.The_Botanica_Dungeon_Netherstorm:
                    return WowMapId.TheBotanica;
                
                case WowClassicMapId.The_Mechanar_Dungeon_Netherstorm_1:
                case WowClassicMapId.The_Mechanar_Dungeon_Netherstorm_2:
                    return WowMapId.TheMechanar;
                
                case WowClassicMapId.The_Arcatraz_Dungeon_Netherstorm_3:
                case WowClassicMapId.The_Arcatraz_Dungeon_Netherstorm_4:
                case WowClassicMapId.The_Arcatraz_Dungeon_Netherstorm_5:
                    return WowMapId.TheArcatraz;
    
                case WowClassicMapId.ManaTombs_Dungeon_Terokkar_Forest:
                    return WowMapId.ManaTombs;
                
                case WowClassicMapId.The_Black_Morass_Orphan_Tanaris:
                    return WowMapId.BlackMorass;
                
                case WowClassicMapId.Old_Hillsbrad_Foothills_Orphan_Tanaris:
                    return WowMapId.OldHillsbradFoothills;
                
                case WowClassicMapId.Wailing_Caverns_Dungeon_The_Barrens:
                    return WowMapId.WailingCaverns;
                    
                case WowClassicMapId.Blackwing_Lair_Dungeon_Burning_Steppes_1:
                case WowClassicMapId.Blackwing_Lair_Dungeon_Burning_Steppes_2:
                case WowClassicMapId.Blackwing_Lair_Dungeon_Burning_Steppes_3:
                case WowClassicMapId.Blackwing_Lair_Dungeon_Burning_Steppes_4:
                    return WowMapId.BlackwingLair;
                
                case WowClassicMapId.The_Deadmines_Dungeon_Westfall_1:
                case WowClassicMapId.The_Deadmines_Dungeon_Westfall_2:
                    return WowMapId.Deadmines;
                
                case WowClassicMapId.Razorfen_Downs_Dungeon_Thousand_Needles:
                    return WowMapId.RazorfenDowns;
                
                case WowClassicMapId.Razorfen_Kraul_Dungeon_The_Barrens:
                    return WowMapId.RazorfenKraul;
                
                case WowClassicMapId.Scarlet_Monastery_Dungeon_Tirisfal_Glades_1:
                case WowClassicMapId.Scarlet_Monastery_Dungeon_Tirisfal_Glades_2:
                case WowClassicMapId.Scarlet_Monastery_Dungeon_Tirisfal_Glades_3:
                case WowClassicMapId.Scarlet_Monastery_Dungeon_Tirisfal_Glades_4:
                    return WowMapId.ScarletMonastery;
                
                case WowClassicMapId.ScholomanceOLD_Dungeon_Western_Plaguelands_1:
                case WowClassicMapId.ScholomanceOLD_Dungeon_Western_Plaguelands_2:
                case WowClassicMapId.ScholomanceOLD_Dungeon_Western_Plaguelands_3:
                case WowClassicMapId.ScholomanceOLD_Dungeon_Western_Plaguelands_4:
                    return WowMapId.Scholomance;
                
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_1:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_2:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_3:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_4:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_5:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_6:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_7:
                    return WowMapId.ShadowfangKeep;
                
                case WowClassicMapId.Stratholme_Dungeon_Eastern_Plaguelands_1:
                case WowClassicMapId.Stratholme_Dungeon_Eastern_Plaguelands_2:
                    return WowMapId.TheCullingOfStratholme;
                
                case WowClassicMapId.Ahn_Qiraj_Dungeon_Silithus_1:
                case WowClassicMapId.Ahn_Qiraj_Dungeon_Silithus_2:
                case WowClassicMapId.Ahn_Qiraj_Dungeon_Silithus_3:
                    return WowMapId.AhnQirajTemple;
                
                case WowClassicMapId.Hyjal_Summit_Orphan_Tanaris:
                    return WowMapId.TheBattleForMountHyjal;
                
                case WowClassicMapId.Gruul_s_Lair_Dungeon_Blade_s_Edge_Mountains:
                    return WowMapId.GruulsLair;
                
                case WowClassicMapId.Magtheridon_s_Lair_Dungeon_Hellfire_Peninsula:
                    return WowMapId.MagtheridonsLair;
                
                case WowClassicMapId.Zul_Aman_Orphan_Ghostlands:
                    return WowMapId.ZulAman;
                
                case WowClassicMapId.Tempest_Keep_Dungeon_Netherstorm_1:
                case WowClassicMapId.Tempest_Keep_Dungeon_Netherstorm_2:
                    return WowMapId.TempestKeep;
                
                case WowClassicMapId.Sunwell_Plateau_Dungeon_Isle_of_Quel_Danas:
                case WowClassicMapId.Sunwell_Plateau_Dungeon_Sunwell_Plateau:
                    return WowMapId.TheSunwell;    
                    
                case WowClassicMapId.Zul_Gurub_Orphan_Stranglethorn_Vale_1:
                case WowClassicMapId.Zul_Gurub_Orphan_Stranglethorn_Vale_2:
                    return WowMapId.ZulGurub;
                
                case WowClassicMapId.Black_Temple_Dungeon_Shadowmoon_Valley:
                    return WowMapId.BlackTemple;
                
                case WowClassicMapId.Hellfire_Ramparts_Dungeon_Hellfire_Peninsula:
                    return WowMapId.HellfireRamparts;
                
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_1:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_2:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_3:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_4:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_5:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_6:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_7:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_8:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_9:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_10:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_11:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_12:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_13:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_14:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_15:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_16:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_17:
                    return WowMapId.Karazhan;
                
                case WowClassicMapId.Azeroth_World_Cosmic:
                case WowClassicMapId.Kalimdor_Continent_Azeroth:
                case WowClassicMapId.Eastern_Kingdoms_Continent_Azeroth:
                case WowClassicMapId.Alterac_Mountains_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Arathi_Highlands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Badlands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Blasted_Lands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Tirisfal_Glades_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Silverpine_Forest_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Western_Plaguelands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Eastern_Plaguelands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Hillsbrad_Foothills_Zone_Eastern_Kingdoms:
                case WowClassicMapId.The_Hinterlands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Dun_Morogh_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Searing_Gorge_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Burning_Steppes_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Elwynn_Forest_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Deadwind_Pass_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Duskwood_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Loch_Modan_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Redridge_Mountains_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Stranglethorn_Vale_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Swamp_of_Sorrows_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Westfall_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Wetlands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Stormwind_City_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Ironforge_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Undercity_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Eastern_Kingdoms_Continent:
                case WowClassicMapId.Eversong_Woods_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Ghostlands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Silvermoon_City_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Isle_of_Quel_Danas_Zone_Eastern_Kingdoms:
                    return WowMapId.EasternKingdoms;
                
                case WowClassicMapId.Outland_Continent:
                case WowClassicMapId.Hellfire_Peninsula_Zone_Outland:
                case WowClassicMapId.Outland_Continent_Cosmic:
                case WowClassicMapId.Zangarmarsh_Zone_Outland:
                case WowClassicMapId.Shadowmoon_Valley_Zone_Outland:
                case WowClassicMapId.Blade_s_Edge_Mountains_Zone_Outland:
                case WowClassicMapId.Nagrand_Zone_Outland:
                case WowClassicMapId.Terokkar_Forest_Zone_Outland:
                case WowClassicMapId.Netherstorm_Zone_Outland:
                case WowClassicMapId.Shattrath_City_Zone_Outland:
                    return WowMapId.Outland;
                
                case WowClassicMapId.Durotar_Zone_Kalimdor:
                case WowClassicMapId.Mulgore_Zone_Kalimdor:
                case WowClassicMapId.The_Barrens_Zone_Kalimdor:
                case WowClassicMapId.Teldrassil_Zone_Kalimdor:
                case WowClassicMapId.Darkshore_Zone_Kalimdor:
                case WowClassicMapId.Ashenvale_Zone_Kalimdor:
                case WowClassicMapId.Thousand_Needles_Zone_Kalimdor:
                case WowClassicMapId.Stonetalon_Mountains_Zone_Kalimdor:
                case WowClassicMapId.Desolace_Zone_Kalimdor:
                case WowClassicMapId.Feralas_Zone_Kalimdor:
                case WowClassicMapId.Dustwallow_Marsh_Zone_Kalimdor:
                case WowClassicMapId.Tanaris_Zone_Kalimdor:
                case WowClassicMapId.Azshara_Zone_Kalimdor:
                case WowClassicMapId.Felwood_Zone_Kalimdor:
                case WowClassicMapId.Un_Goro_Crater_Zone_Kalimdor:
                case WowClassicMapId.Moonglade_Zone_Kalimdor:
                case WowClassicMapId.Silithus_Zone_Kalimdor:
                case WowClassicMapId.Winterspring_Zone_Kalimdor:
                case WowClassicMapId.Orgrimmar_Zone_Kalimdor:
                case WowClassicMapId.Thunder_Bluff_Zone_Kalimdor:
                case WowClassicMapId.Darnassus_Zone_Kalimdor:
                case WowClassicMapId.Kalimdor_Continent:
                case WowClassicMapId.Azuremyst_Isle_Zone_Kalimdor:
                case WowClassicMapId.The_Exodar_Zone_Kalimdor:
                case WowClassicMapId.Bloodmyst_Isle_Zone_Kalimdor:
                    return WowMapId.Kalimdor;
                    
                case WowClassicMapId.Alterac_Valley_Zone_Azeroth:
                    return WowMapId.AlteracValley;
                
                case WowClassicMapId.Warsong_Gulch_Zone_Azeroth:
                    return WowMapId.WarsongGulch;
                
                case WowClassicMapId.Arathi_Basin_Zone_Azeroth:
                    return WowMapId.ArathiBasin;
                    
                case WowClassicMapId.Serpentshrine_Cavern_Dungeon_Zangarmarsh_1:
                case WowClassicMapId.Serpentshrine_Cavern_Dungeon_Zangarmarsh_2:
                    return WowMapId.SerpentshrineCavern;
                    
                case WowClassicMapId.Eye_of_the_Storm_Zone_Netherstorm:
                    return WowMapId.EyeOfTheStorm;
                    
                case WowClassicMapId.Cosmic_Cosmic:
                case WowClassicMapId.Maraudon_Dungeon_Desolace_1:
                case WowClassicMapId.Maraudon_Dungeon_Desolace_2:
                case WowClassicMapId.The_Temple_of_Atal_Hakkar_Dungeon_Swamp_of_Sorrows:
                default:
                    throw new ArgumentOutOfRangeException(nameof(mapId), mapId, null);
            }
        }
    Future learnings:
    * I'd like to understand how are people doing to find game offsets. With my free IDA version, I'm not able to find all LUA APIs in the WoW classic TBC client (it may come from the obfuscation) so I find it really hard to understand the logic & to find the offsets by myself. I wonder if people with the Pro version have the same issue... I've started to quickly have a look (here: https://www.ownedcore.com/forums/wor...ed-binary.html) but I need to spend more time on that part.
    * When time allows, I'll dig into the recast / detour usage (and actually understand that page: https://wowdev.wiki/ADT/v18 because I really don't know how to interpret the games files thanks to this wiki ). The final goal would be to be able to build a navmesh for at least a zone by myself.

    Side note: I won't provide the code I've written for my bot. I believe the information shared here can lead you on the road to build your own bot :-)
    Last edited by 0xd5d; 05-25-2022 at 01:48 PM.

    [Wow classic TBC] A start point to make your own bot
  2. Thanks Creepwalker, darkness92, alison9, Razzue (4 members gave Thanks to 0xd5d for this useful post)
  3. #2
    alison9's Avatar Member
    Reputation
    1
    Join Date
    Jun 2022
    Posts
    2
    Thanks G/R
    1/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by 0xd5d View Post
    Hey there,
    I've been lurking on this forum for a while now. After all I got from it, I think it's now my turn to contribute
    This post will describe my 1+ year journey making a bot, and will reference other useful links. I hope this thread can be the starting point for other people to start making wow bots :-)

    About me: I'm a software engineer in a big tech company everyone knows, with 5+ year of experience. I've always been amazed by the World of Warcraft game. I've started making very uneffective bots when I was younger. Now, making bots that really work is not only a way to learn a lot, but also to avoid spending hours killing pigs in the game :-)




    1. The pixel bot

    Before diving into implementation, I've first did some investigations about how to make a bot. I've read a couple of books, and I came to the conclusion that making memory editing bots was too risky (Blizzard detection leading to ban) and too complex.
    So I first started to make a pixel bot whose goal was to farm mobs and level up my character.

    What is a pixel bot ?
    It's a program which reads pixel in the game as input, to take decisions. I'm not going to spend a lot of time on that part, because making a pixel bot is actually not very complex and there are already plenty very useful resources on that forum.
    For instance: How to make a bot kind of tutorial => wow...-tutorial.html
    Example to add colored pixel in a wow lua addon: Happy-Pixels/DataToColor at master . MicahRCM/Happy-Pixels . GitHub

    There are 2 interesting parts here that I'd like to mention:

    A/ Navigation system
    The bot was getting the position from pixels in the game representing the lua code: UnitPosition("Player"). To build a navigation system, I've made a tool to record the position of the player. This tool had a GUI which allowed me to "click" to mark a cell (= a (x,y) position) as non walkable. So given a zone where I wanted my character to farm, I first had to walk through that zone and mark the non walkable parts of it. Recording those points allowed me to find the walkable / non walkable part, hence providing enough data for my character to randomly walk in a given zone.

    The algorithm was that one:
    * Find a random destination in the current zone
    * Go to that destination (use A* algorithm)
    * While walking, if there are mobs, start a fight.

    The mob selection was simply made by pressing tab regularly & checking the target of my character.

    The facing algorithm (given a position A and an Orientation, which angle do you turn to face position B?) can be deduced for the other "kinda tutorial" thread

    Code:
            double getangle(double y1, double y2, double x1, double x2)
                {
                double ang =    Math.Atan2(x1 - x2, y1 - y2)/Math.PI;
                if (ang < 0) ang += 2; // this is used to avoind negative numbers. 
                return Math.Round(ang*1000);
                }
    You'll find this method in other posts as well.

    B/ Looting mobs
    To loot mobs, I've used an image hashing library to recognize the mouse icon. So once the fight was done, I just moved the mouse around the middle of the screen and compared the mouse icon to icon I had previously saved.

    The algorithm was that one:
    * Move the mouse
    * Get current mouse icon
    * ImageHash(current mouse icon) == ImageHash(loot icon) ? => then loot

    You can find more about this technique here: Blog (see the looting part). The used library is that one: GitHub - jforshee/ImageHashing.

    How do you find the mouse icon in [langage]?
    I believe you can type this in google to find it out (this is how I actually did)

    C/ Sending mouse and keyboard events to the game
    This was the hardest part of the pixel bot. To avoid detection, I've made a driver which runs in kernel mode. And I spent a lot of time trying to test it, because I was using an Hyper V virtual machine and it is actually not supported So even if my driver was working, I couldn't test it through the virtual machine.
    A nice resource to build a windows driver: Write a Hello World Windows Driver (KMDF) - Windows drivers | Microsoft Docs
    Another one: https://docs.microsoft.com/en-us/win...client-drivers
    Third one: https://github.com/MicrosoftDocs/win...ent-drivers.md
    You can also find github example of HID keyboard & mouse kernel mode driver.

    Overall, the pixel bot did a great job and I successfully reached level 70 and got rich enough to buy the fast flying mount.
    But there were some drawbacks:
    * The bot could not work for pvp battleground, because some lua apis are disabled in battleground (like the position)
    * The navigation system was not really precise. Z coordinate can't be retrieved using the LUA API, and the manual recording part was not only tedious but also led to not super precise cells. The navigation was clearly random and I've seen other player detecting my character as a bot because not fighting well enough when attacked in PVP. Actually the bot had no knowledge of its environment.




    2. The memory editing bot

    This is where things get interesting. A memory editing bot is getting information from the wow process memory. It is actually reading the WOW's memory. Such bot can also write to the WOW's memory, for instance to call existing method (example: click to move, providing the position where you want to move to).

    There are kings on this forum (hello Razzue!) who are really good and write posts to give offsets from where you can read the data you want (example: wor...d-43638-a.html).
    The thing is, it's very hard to understand how these people are actually doing to retrieve those offsets. There are some tutorials (like this one: wor...e-stuff-5.html), but overall I think there are missing resources on that topic.

    What are offsets?
    They are actually numbers you can add from a memory pointer to get either a value or another pointer. The nice thing is that they change each time you build a new version of the WoW client, so the offsets have to be looked for again for each client update...

    One way of finding these offset is runtime analysis: analyse wow process memory at runtime. A software like cheat engine can be used to monitor the WoW process memory. The big idea is to look for a value using that tool (for instance, your health) to find out where in memory this value resides. Then, by looking at how this value is accessed (for instance, by attaching a debugger), you can reproduce the value access in an external tool (ex: your bot).
    The goal of this thread is not to make you learn how to use tools like Cheat engine, I believe you can find plenty of existing resources online. I think Blizzard detects the use of cheat engine and this usage can get you banned. To avoid detection, you might rebuild locally a modified version of the software (and change a few things like the software name before rebuilding). But attaching a debugger may trigger Blizzard anti cheat system... (aka Warden)

    Another way to find the offset is to do static analysis. A disassembler is used to transform the binary to "readable" code. So by disassembling the wow client, you get the actual code which gets executed by the WoW client. Then, you can browse it to understand how it works. The nice thing is that once you get a non obfuscated version of the client (see here: https://github.com/maikel233/WoWIDB/.../wow%20classic and there: https://www.ownedcore.com/forums/wor...-memory-5.html and there wor...bfuscator.html), then there is 0 risk for you to get banned while you analyze the binary.
    Once you've conducted your static analysis, you can then try to find an opcode pattern to recognize an offset. If you're a king legend like Razzue, you can then make a tool to automatically detect offsets. As you've understood, this is way out of my knowledge currently.

    What I've done to learn reverse engineering is to download the Ghidra software (https://github.com/NationalSecurityAgency/ghidra) and tried to disassemble an old version of the game (WOW 3.3.5a). Using an old version of the client is easier than the current version because it is obfuscated (see this thread: wor...on-coming.html).
    Overall, I was able thanks to some posts on this forum to understand from Ghidra how to iterate through the object manager, but this was not easy.
    The issue with Ghidra is that it fails at disassembling the actual version of the game unobfuscated (I get a NullReferenceException ). So a concurrent product should be used, for instance, IDA Free version. Many kings on this forum are using IDA Pro, which is expansive. So these kings may actually be professional reverse engineer...

    What is the object manager?
    The object manager is a structure used by WoW to represent the game objects. In this structure, you'll find all players, mobs, herbs, ... So for instance if you want to get all surrounding players, you'll walk the object manager to find those. To iterate through the object manager in wow classic TBC, the Razzue's post linked above can be helpful. For other versions of the game, you can find the answer on this forum (or on existing bots on github...).

    To understand how to use the offsets for WoW classic TBC, you can have a look at existing bot to see the class & enums used: https://github.com/mmalka/TheNoobBot

    Here are key interesting points:
    A/ Navigation system
    This system is based on the pixel bot one. I recommend reading the Pixel bot part first to have a better understanding.

    Overall I recommend having a look at this thread (https://drewkestell.us/Article/6/Chapter/20) which gives a lot of information. To build an effective navigation system, the idea is to use the game map files to build a navigation mesh. I've reused the tools provided in the above article to build the maps used by my bot, but I plan to dig deeper in this part later.
    Currently, the navigation system is working pretty well:
    * Get the position of the player by reading wow process memory (see king Razzue's post)
    * Using Detour, find a path to a destination. You can find more on how to use Detour in drewkestell blog.

    The maps I've used are the ones which were with WoW 3.3.5a version (they are still up to date for Wow classic TBC).

    Here is a nice code to avoid finger injury to convert the map id retrieved using Razzue's offset to a map id used by the blog shared above. I believe you can find the zone id directly in memory, but...I haven't looked for the offset (as mentioned the offset are game version dependent and the WowClassicMapId is freely provided by Razzue in its offset list).

    Code:
    public enum WowClassicMapId
    {
        Ragefire_Chasm_Dungeon_Orgrimmar = 213,
        Zul_Farrak_Orphan_Tanaris = 219,
        The_Temple_of_Atal_Hakkar_Dungeon_Swamp_of_Sorrows = 220,
        Blackfathom_Deeps_Dungeon_Ashenvale_1 = 221,
        Blackfathom_Deeps_Dungeon_Ashenvale_2 = 222,
        Blackfathom_Deeps_Dungeon_Ashenvale_3 = 223,
        The_Stockade_Dungeon_Stormwind_City = 225,
        Gnomeregan_Dungeon_Dun_Morogh_1 = 226,
        Gnomeregan_Dungeon_Dun_Morogh_2 = 227,
        Gnomeregan_Dungeon_Dun_Morogh_3 = 228,
        Gnomeregan_Dungeon_Dun_Morogh_4 = 229,
        Uldaman_Dungeon_Badlands_1 = 230,
        Uldaman_Dungeon_Badlands_2 = 231,
        Molten_Core_Dungeon_Burning_Steppes = 232,
        Dire_Maul_Orphan_Feralas = 234,
        Dire_Maul_Dungeon_Feralas_1 = 235,
        Dire_Maul_Dungeon_Feralas_2 = 236,
        Dire_Maul_Dungeon_Feralas_3 = 237,
        Dire_Maul_Dungeon_Feralas_4 = 238,
        Dire_Maul_Dungeon_Feralas_5 = 239,
        Dire_Maul_Dungeon_Feralas_6 = 240,
        Blackrock_Depths_Dungeon_Searing_Gorge_1 = 242,
        Blackrock_Depths_Dungeon_Searing_Gorge_2 = 243,
        The_Shattered_Halls_Dungeon_Hellfire_Peninsula = 246,
        Ruins_of_Ahn_Qiraj_Orphan_Silithus = 247,
        Onyxia_s_Lair_Dungeon_Dustwallow_Marsh = 248,
        Blackrock_Spire_Dungeon_Burning_Steppes_1 = 250,
        Blackrock_Spire_Dungeon_Burning_Steppes_2 = 251,
        Blackrock_Spire_Dungeon_Burning_Steppes_3 = 252,
        Blackrock_Spire_Dungeon_Burning_Steppes_4 = 253,
        Blackrock_Spire_Dungeon_Burning_Steppes_5 = 254,
        Blackrock_Spire_Dungeon_Burning_Steppes_6 = 255,
        Auchenai_Crypts_Dungeon_Terokkar_Forest_7 = 256,
        Auchenai_Crypts_Dungeon_Terokkar_Forest_8 = 257,
        Sethekk_Halls_Dungeon_Terokkar_Forest_1 = 258,
        Sethekk_Halls_Dungeon_Terokkar_Forest_2 = 259,
        Shadow_Labyrinth_Dungeon_Terokkar_Forest = 260,
        The_Blood_Furnace_Dungeon_Hellfire_Peninsula = 261,
        The_Underbog_Dungeon_Zangarmarsh = 262,
        The_Steamvault_Dungeon_Zangarmarsh_1 = 263,
        The_Steamvault_Dungeon_Zangarmarsh_2 = 264,
        The_Slave_Pens_Dungeon_Zangarmarsh = 265,
        The_Botanica_Dungeon_Netherstorm = 266,
        The_Mechanar_Dungeon_Netherstorm_1 = 267,
        The_Mechanar_Dungeon_Netherstorm_2 = 268,
        The_Arcatraz_Dungeon_Netherstorm_3 = 269,
        The_Arcatraz_Dungeon_Netherstorm_4 = 270,
        The_Arcatraz_Dungeon_Netherstorm_5 = 271,
        ManaTombs_Dungeon_Terokkar_Forest = 272,
        The_Black_Morass_Orphan_Tanaris = 273,
        Old_Hillsbrad_Foothills_Orphan_Tanaris = 274,
        Wailing_Caverns_Dungeon_The_Barrens = 279,
        Maraudon_Dungeon_Desolace_1 = 280,
        Maraudon_Dungeon_Desolace_2 = 281,
        Blackwing_Lair_Dungeon_Burning_Steppes_1 = 287,
        Blackwing_Lair_Dungeon_Burning_Steppes_2 = 288,
        Blackwing_Lair_Dungeon_Burning_Steppes_3 = 289,
        Blackwing_Lair_Dungeon_Burning_Steppes_4 = 290,
        The_Deadmines_Dungeon_Westfall_1 = 291,
        The_Deadmines_Dungeon_Westfall_2 = 292,
        Razorfen_Downs_Dungeon_Thousand_Needles = 300,
        Razorfen_Kraul_Dungeon_The_Barrens = 301,
        Scarlet_Monastery_Dungeon_Tirisfal_Glades_1 = 302,
        Scarlet_Monastery_Dungeon_Tirisfal_Glades_2 = 303,
        Scarlet_Monastery_Dungeon_Tirisfal_Glades_3 = 304,
        Scarlet_Monastery_Dungeon_Tirisfal_Glades_4 = 305,
        ScholomanceOLD_Dungeon_Western_Plaguelands_1 = 306,
        ScholomanceOLD_Dungeon_Western_Plaguelands_2 = 307,
        ScholomanceOLD_Dungeon_Western_Plaguelands_3 = 308,
        ScholomanceOLD_Dungeon_Western_Plaguelands_4 = 309,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_1 = 310,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_2 = 311,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_3 = 312,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_4 = 313,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_5 = 314,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_6 = 315,
        Shadowfang_Keep_Dungeon_Silverpine_Forest_7 = 316,
        Stratholme_Dungeon_Eastern_Plaguelands_1 = 317,
        Stratholme_Dungeon_Eastern_Plaguelands_2 = 318,
        Ahn_Qiraj_Dungeon_Silithus_1 = 319,
        Ahn_Qiraj_Dungeon_Silithus_2 = 320,
        Ahn_Qiraj_Dungeon_Silithus_3 = 321,
        Hyjal_Summit_Orphan_Tanaris = 329,
        Gruul_s_Lair_Dungeon_Blade_s_Edge_Mountains = 330,
        Magtheridon_s_Lair_Dungeon_Hellfire_Peninsula = 331,
        Zul_Aman_Orphan_Ghostlands = 333,
        Tempest_Keep_Dungeon_Netherstorm_1 = 334,
        Tempest_Keep_Dungeon_Netherstorm_2 = 1555,
        Sunwell_Plateau_Dungeon_Isle_of_Quel_Danas = 335,
        Sunwell_Plateau_Dungeon_Sunwell_Plateau = 336,
        Zul_Gurub_Orphan_Stranglethorn_Vale_1 = 233,
        Zul_Gurub_Orphan_Stranglethorn_Vale_2 = 337,
        Black_Temple_Dungeon_Shadowmoon_Valley = 339,
        Hellfire_Ramparts_Dungeon_Hellfire_Peninsula = 347,
        Karazhan_Dungeon_Deadwind_Pass_1 = 350,
        Karazhan_Dungeon_Deadwind_Pass_2 = 351,
        Karazhan_Dungeon_Deadwind_Pass_3 = 352,
        Karazhan_Dungeon_Deadwind_Pass_4 = 353,
        Karazhan_Dungeon_Deadwind_Pass_5 = 354,
        Karazhan_Dungeon_Deadwind_Pass_6 = 355,
        Karazhan_Dungeon_Deadwind_Pass_7 = 356,
        Karazhan_Dungeon_Deadwind_Pass_8 = 357,
        Karazhan_Dungeon_Deadwind_Pass_9 = 358,
        Karazhan_Dungeon_Deadwind_Pass_10 = 359,
        Karazhan_Dungeon_Deadwind_Pass_11 = 360,
        Karazhan_Dungeon_Deadwind_Pass_12 = 361,
        Karazhan_Dungeon_Deadwind_Pass_13 = 362,
        Karazhan_Dungeon_Deadwind_Pass_14 = 363,
        Karazhan_Dungeon_Deadwind_Pass_15 = 364,
        Karazhan_Dungeon_Deadwind_Pass_16 = 365,
        Karazhan_Dungeon_Deadwind_Pass_17 = 366,
        Cosmic_Cosmic = 946,
        Azeroth_World_Cosmic = 947,
        Outland_Continent = 987,
        Durotar_Zone_Kalimdor = 1411,
        Mulgore_Zone_Kalimdor = 1412,
        The_Barrens_Zone_Kalimdor = 1413,
        Kalimdor_Continent_Azeroth = 1414,
        Eastern_Kingdoms_Continent_Azeroth = 1415,
        Alterac_Mountains_Zone_Eastern_Kingdoms = 1416,
        Arathi_Highlands_Zone_Eastern_Kingdoms = 1417,
        Badlands_Zone_Eastern_Kingdoms = 1418,
        Blasted_Lands_Zone_Eastern_Kingdoms = 1419,
        Tirisfal_Glades_Zone_Eastern_Kingdoms = 1420,
        Silverpine_Forest_Zone_Eastern_Kingdoms = 1421,
        Western_Plaguelands_Zone_Eastern_Kingdoms = 1422,
        Eastern_Plaguelands_Zone_Eastern_Kingdoms = 1423,
        Hillsbrad_Foothills_Zone_Eastern_Kingdoms = 1424,
        The_Hinterlands_Zone_Eastern_Kingdoms = 1425,
        Dun_Morogh_Zone_Eastern_Kingdoms = 1426,
        Searing_Gorge_Zone_Eastern_Kingdoms = 1427,
        Burning_Steppes_Zone_Eastern_Kingdoms = 1428,
        Elwynn_Forest_Zone_Eastern_Kingdoms = 1429,
        Deadwind_Pass_Zone_Eastern_Kingdoms = 1430,
        Duskwood_Zone_Eastern_Kingdoms = 1431,
        Loch_Modan_Zone_Eastern_Kingdoms = 1432,
        Redridge_Mountains_Zone_Eastern_Kingdoms = 1433,
        Stranglethorn_Vale_Zone_Eastern_Kingdoms = 1434,
        Swamp_of_Sorrows_Zone_Eastern_Kingdoms = 1435,
        Westfall_Zone_Eastern_Kingdoms = 1436,
        Wetlands_Zone_Eastern_Kingdoms = 1437,
        Teldrassil_Zone_Kalimdor = 1438,
        Darkshore_Zone_Kalimdor = 1439,
        Ashenvale_Zone_Kalimdor = 1440,
        Thousand_Needles_Zone_Kalimdor = 1441,
        Stonetalon_Mountains_Zone_Kalimdor = 1442,
        Desolace_Zone_Kalimdor = 1443,
        Feralas_Zone_Kalimdor = 1444,
        Dustwallow_Marsh_Zone_Kalimdor = 1445,
        Tanaris_Zone_Kalimdor = 1446,
        Azshara_Zone_Kalimdor = 1447,
        Felwood_Zone_Kalimdor = 1448,
        Un_Goro_Crater_Zone_Kalimdor = 1449,
        Moonglade_Zone_Kalimdor = 1450,
        Silithus_Zone_Kalimdor = 1451,
        Winterspring_Zone_Kalimdor = 1452,
        Stormwind_City_Zone_Eastern_Kingdoms = 1453,
        Orgrimmar_Zone_Kalimdor = 1454,
        Ironforge_Zone_Eastern_Kingdoms = 1455,
        Thunder_Bluff_Zone_Kalimdor = 1456,
        Darnassus_Zone_Kalimdor = 1457,
        Undercity_Zone_Eastern_Kingdoms = 1458,
        Alterac_Valley_Zone_Azeroth = 1459,
        Warsong_Gulch_Zone_Azeroth = 1460,
        Arathi_Basin_Zone_Azeroth = 1461,
        Eastern_Kingdoms_Continent = 1463,
        Kalimdor_Continent = 1464,
        Serpentshrine_Cavern_Dungeon_Zangarmarsh_1 = 332,
        Serpentshrine_Cavern_Dungeon_Zangarmarsh_2 = 1554,
        Eversong_Woods_Zone_Eastern_Kingdoms = 1941,
        Ghostlands_Zone_Eastern_Kingdoms = 1942,
        Azuremyst_Isle_Zone_Kalimdor = 1943,
        Hellfire_Peninsula_Zone_Outland = 1944,
        Outland_Continent_Cosmic = 1945,
        Zangarmarsh_Zone_Outland = 1946,
        The_Exodar_Zone_Kalimdor = 1947,
        Shadowmoon_Valley_Zone_Outland = 1948,
        Blade_s_Edge_Mountains_Zone_Outland = 1949,
        Bloodmyst_Isle_Zone_Kalimdor = 1950,
        Nagrand_Zone_Outland = 1951,
        Terokkar_Forest_Zone_Outland = 1952,
        Netherstorm_Zone_Outland = 1953,
        Silvermoon_City_Zone_Eastern_Kingdoms = 1954,
        Shattrath_City_Zone_Outland = 1955,
        Eye_of_the_Storm_Zone_Netherstorm = 1956,
        Isle_of_Quel_Danas_Zone_Eastern_Kingdoms = 1957,
    }
    
    public enum WowMapId
        {
            AhnkahetTheOldKingdom = 619,    // Azjol_LowerCity
            AhnQirajTemple = 531,           // AhnQirajTemple
            AlteracValley = 30,             // PVPZone01
            ArathiBasin = 529,              // PVPZone04
            AuchenaiCrypts = 558,           // AuchindounDraenei
            AzjolNerub = 601,               // Azjol_Uppercity
            AzsharaCrater = 37,             // PVPZone02
            BlackfathomDeeps = 48,          // Blackfathom
            BlackMorass = 269,              // CavernsOfTime
            BlackrockDepths = 230,          // BlackrockDepths
            BlackrockSpire = 229,           // BlackRockSpire
            BlackTemple = 564,              // BlackTemple
            BlackwingLair = 469,            // BlackwingLair
            BladesEdgeArena = 562,          // bladesedgearena
            ChampionsHall = 449,            // AlliancePVPBarracks
            DalaranSewers = 617,            // DalaranArena
            Deadmines = 36,                 // DeadminesInstance
            DeeprunTram = 369,              // DeeprunTram
            DireMaul = 429,                 // DireMaul
            DrakTharonKeep = 600,           // DrakTheronKeep
            EasternKingdoms = 0,            // Azeroth
            EbonHold = 609,                 // DeathKnightStart
            EmeraldDream = 169,             // EmeraldDream
            EyeOfTheStorm = 566,            // NetherstormBG
            Gnomeregan = 90,                // GnomeragonInstance
            GruulsLair = 565,               // GruulsLair
            Gundrak = 604,                  // GunDrak
            HallOfLegends = 450,            // HordePVPBarracks
            HallsOfLighting = 602,          // Ulduar80
            HallsOfReflection = 668,        // HallsOfReflection
            HallsOfStone = 599,             // Ulduar70
            HellfireRamparts = 543,         // HellfireRampart
            IcecrownCitadel = 631,          // IcecrownCitadel
            IsleOfConquest = 628,           // IsleofConquest
            Kalimdor = 1,                   // Kalimdor
            Karazhan = 532,                 // Karazahn
            MagistersTerrace = 585,         // Sunwell5ManFix
            MagtheridonsLair = 544,         // HellfireRaid
            ManaTombs = 557,                // AuchindounEthereal
            Mauradon = 349,                 // Mauradon
            MoltenCore = 409,               // MoltenCore
            NagrandArena = 559,             // PVPZone05
            Naxxramas = 533,                // Stratholme Raid
            Northrend = 571,                // Northrend
            OldHillsbradFoothills = 560,    // HillsbradPast
            OnyxiasLair = 249,              // OnyxiaLairInstance
            Outland = 530,                  // Expansion01
            PitOfSaron = 658,               // QuarryOfTears
            RagefireChasm = 389,            // OrgrimmarInstance
            RazorfenDowns = 129,            // RazorfenDowns
            RazorfenKraul = 47,             // RazorfenKraulInstance
            RuinsOfAhnQiraj = 509,          // AhnQiraj
            RuinsOfLordaeron = 572,         // PVPLordaeron
            ScarletMonastery = 189,         // MonasteryInstances
            Scholomance = 289,              // SchoolofNecromancy
            SerpentshrineCavern = 548,      // CoilfangRaid
            SethekkHalls = 556,             // AuchindounDemon
            ShadowfangKeep = 33,            // Shadowfang
            ShadowLabyrinth = 555,          // AuchindounShadow
            Stormwind = 723,                // Stormwind
            StormwindStockade = 34,         // StormwindJail
            StrandOfTheAncients = 607,      // NorthrendBG
            SunkenTemple = 109,             // SunkenTemple
            TempestKeep = 550,              // TempestKeepRaid
            TheArcatraz = 552,              // TempestKeepArcane
            TheBattleForMountHyjal = 534,   // HyjalPast
            TheBloodFurnace = 542,          // HellfireDemon
            TheBotanica = 553,              // TempestKeepAtrium
            TheCullingOfStratholme = 595,   // StratholmeCOT
            TheEyeOfEternity = 616,         // NexusRaid
            TheForgeOfSouls = 632,          // IcecrownCitadel5Man
            TheMechanar = 554,              // TempestKeepFactory
            TheNexus = 576,                 // Nexus70
            TheObsidianSanctum = 615,       // ChamberOfAspectsBlack
            TheOculus = 578,                // Nexus80
            TheRingOfValor = 618,           // OrgrimmarArena
            TheRubySanctum = 724,           // ChamberOfAspectsRed
            TheShatteredHalls = 540,        // HellfireMilitary
            TheSlavePens = 547,             // CoilfangDraenei
            TheSteamvault = 545,            // CoilfangPumping
            TheSunwell = 580,               // SunwellPlateau
            TheUnderbog = 546,              // CoilfangMarsh
            TrialOfTheChampion = 650,       // ArgentTournamentDungeon
            TrialOfTheCrusader = 649,       // ArgentTournamentRaid
            Uldaman = 70,                   // Uldaman
            Ulduar = 603,                   // UlduarRaid
            UnderMine = 2,                  // UnderMine
            UtgardeKeep = 574,              // Valgarde70
            UtgardePinnacle = 575,          // UtgardePinnacle
            VaultOfArchavon = 624,          // WintergraspRaid
            VioletHold = 608,               // DalaranPrison
            WailingCaverns = 43,            // WailingCaverns
            WarsongGulch = 489,             // PVPZone03
            ZulAman = 568,                  // ZulAman
            ZulFarrak = 209,                // TanarisInstance
            ZulGurub = 309                  // Zul'gurub
        }
    
        private WowMapId ToWowMapId(WowClassicMapId mapId)
        {
            switch (mapId)
            {
                case WowClassicMapId.Ragefire_Chasm_Dungeon_Orgrimmar:
                    return WowMapId.RagefireChasm;
                
                case WowClassicMapId.Zul_Farrak_Orphan_Tanaris:
                    return WowMapId.ZulFarrak;
                    
                case WowClassicMapId.Blackfathom_Deeps_Dungeon_Ashenvale_1:
                case WowClassicMapId.Blackfathom_Deeps_Dungeon_Ashenvale_2:
                case WowClassicMapId.Blackfathom_Deeps_Dungeon_Ashenvale_3:
                    return WowMapId.BlackfathomDeeps;
                
                case WowClassicMapId.The_Stockade_Dungeon_Stormwind_City:
                    return WowMapId.StormwindStockade;
                    
                case WowClassicMapId.Gnomeregan_Dungeon_Dun_Morogh_1:
                case WowClassicMapId.Gnomeregan_Dungeon_Dun_Morogh_2:
                case WowClassicMapId.Gnomeregan_Dungeon_Dun_Morogh_3:
                case WowClassicMapId.Gnomeregan_Dungeon_Dun_Morogh_4:
                    return WowMapId.Gnomeregan;
                
                case WowClassicMapId.Uldaman_Dungeon_Badlands_1:
                case WowClassicMapId.Uldaman_Dungeon_Badlands_2:
                    return WowMapId.Uldaman;
                
                case WowClassicMapId.Molten_Core_Dungeon_Burning_Steppes:
                    return WowMapId.MoltenCore;
                
                case WowClassicMapId.Dire_Maul_Orphan_Feralas:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_1:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_2:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_3:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_4:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_5:
                case WowClassicMapId.Dire_Maul_Dungeon_Feralas_6:
                    return WowMapId.DireMaul;
                
                case WowClassicMapId.Blackrock_Depths_Dungeon_Searing_Gorge_1:
                case WowClassicMapId.Blackrock_Depths_Dungeon_Searing_Gorge_2:
                    return WowMapId.BlackrockDepths;
                
                case WowClassicMapId.The_Shattered_Halls_Dungeon_Hellfire_Peninsula:
                    return WowMapId.TheShatteredHalls;
                
                case WowClassicMapId.Ruins_of_Ahn_Qiraj_Orphan_Silithus:
                    return WowMapId.RuinsOfAhnQiraj;
                
                case WowClassicMapId.Onyxia_s_Lair_Dungeon_Dustwallow_Marsh:
                    return WowMapId.OnyxiasLair;
                
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_1:
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_2:
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_3:
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_4:
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_5:
                case WowClassicMapId.Blackrock_Spire_Dungeon_Burning_Steppes_6:
                    return WowMapId.BlackrockSpire;
                
                case WowClassicMapId.Auchenai_Crypts_Dungeon_Terokkar_Forest_7:
                case WowClassicMapId.Auchenai_Crypts_Dungeon_Terokkar_Forest_8:
                    return WowMapId.AuchenaiCrypts;
                
                case WowClassicMapId.Sethekk_Halls_Dungeon_Terokkar_Forest_1:
                case WowClassicMapId.Sethekk_Halls_Dungeon_Terokkar_Forest_2:
                    return WowMapId.SethekkHalls;
                
                case WowClassicMapId.Shadow_Labyrinth_Dungeon_Terokkar_Forest:
                    return WowMapId.ShadowLabyrinth;
                
                case WowClassicMapId.The_Blood_Furnace_Dungeon_Hellfire_Peninsula:
                    return WowMapId.TheBloodFurnace;
                
                case WowClassicMapId.The_Underbog_Dungeon_Zangarmarsh:
                    return WowMapId.TheUnderbog;
                
                case WowClassicMapId.The_Steamvault_Dungeon_Zangarmarsh_1:
                case WowClassicMapId.The_Steamvault_Dungeon_Zangarmarsh_2:
                    return WowMapId.TheSteamvault;
                
                case WowClassicMapId.The_Slave_Pens_Dungeon_Zangarmarsh:
                    return WowMapId.TheSlavePens;
                
                case WowClassicMapId.The_Botanica_Dungeon_Netherstorm:
                    return WowMapId.TheBotanica;
                
                case WowClassicMapId.The_Mechanar_Dungeon_Netherstorm_1:
                case WowClassicMapId.The_Mechanar_Dungeon_Netherstorm_2:
                    return WowMapId.TheMechanar;
                
                case WowClassicMapId.The_Arcatraz_Dungeon_Netherstorm_3:
                case WowClassicMapId.The_Arcatraz_Dungeon_Netherstorm_4:
                case WowClassicMapId.The_Arcatraz_Dungeon_Netherstorm_5:
                    return WowMapId.TheArcatraz;
    
                case WowClassicMapId.ManaTombs_Dungeon_Terokkar_Forest:
                    return WowMapId.ManaTombs;
                
                case WowClassicMapId.The_Black_Morass_Orphan_Tanaris:
                    return WowMapId.BlackMorass;
                
                case WowClassicMapId.Old_Hillsbrad_Foothills_Orphan_Tanaris:
                    return WowMapId.OldHillsbradFoothills;
                
                case WowClassicMapId.Wailing_Caverns_Dungeon_The_Barrens:
                    return WowMapId.WailingCaverns;
                    
                case WowClassicMapId.Blackwing_Lair_Dungeon_Burning_Steppes_1:
                case WowClassicMapId.Blackwing_Lair_Dungeon_Burning_Steppes_2:
                case WowClassicMapId.Blackwing_Lair_Dungeon_Burning_Steppes_3:
                case WowClassicMapId.Blackwing_Lair_Dungeon_Burning_Steppes_4:
                    return WowMapId.BlackwingLair;
                
                case WowClassicMapId.The_Deadmines_Dungeon_Westfall_1:
                case WowClassicMapId.The_Deadmines_Dungeon_Westfall_2:
                    return WowMapId.Deadmines;
                
                case WowClassicMapId.Razorfen_Downs_Dungeon_Thousand_Needles:
                    return WowMapId.RazorfenDowns;
                
                case WowClassicMapId.Razorfen_Kraul_Dungeon_The_Barrens:
                    return WowMapId.RazorfenKraul;
                
                case WowClassicMapId.Scarlet_Monastery_Dungeon_Tirisfal_Glades_1:
                case WowClassicMapId.Scarlet_Monastery_Dungeon_Tirisfal_Glades_2:
                case WowClassicMapId.Scarlet_Monastery_Dungeon_Tirisfal_Glades_3:
                case WowClassicMapId.Scarlet_Monastery_Dungeon_Tirisfal_Glades_4:
                    return WowMapId.ScarletMonastery;
                
                case WowClassicMapId.ScholomanceOLD_Dungeon_Western_Plaguelands_1:
                case WowClassicMapId.ScholomanceOLD_Dungeon_Western_Plaguelands_2:
                case WowClassicMapId.ScholomanceOLD_Dungeon_Western_Plaguelands_3:
                case WowClassicMapId.ScholomanceOLD_Dungeon_Western_Plaguelands_4:
                    return WowMapId.Scholomance;
                
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_1:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_2:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_3:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_4:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_5:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_6:
                case WowClassicMapId.Shadowfang_Keep_Dungeon_Silverpine_Forest_7:
                    return WowMapId.ShadowfangKeep;
                
                case WowClassicMapId.Stratholme_Dungeon_Eastern_Plaguelands_1:
                case WowClassicMapId.Stratholme_Dungeon_Eastern_Plaguelands_2:
                    return WowMapId.TheCullingOfStratholme;
                
                case WowClassicMapId.Ahn_Qiraj_Dungeon_Silithus_1:
                case WowClassicMapId.Ahn_Qiraj_Dungeon_Silithus_2:
                case WowClassicMapId.Ahn_Qiraj_Dungeon_Silithus_3:
                    return WowMapId.AhnQirajTemple;
                
                case WowClassicMapId.Hyjal_Summit_Orphan_Tanaris:
                    return WowMapId.TheBattleForMountHyjal;
                
                case WowClassicMapId.Gruul_s_Lair_Dungeon_Blade_s_Edge_Mountains:
                    return WowMapId.GruulsLair;
                
                case WowClassicMapId.Magtheridon_s_Lair_Dungeon_Hellfire_Peninsula:
                    return WowMapId.MagtheridonsLair;
                
                case WowClassicMapId.Zul_Aman_Orphan_Ghostlands:
                    return WowMapId.ZulAman;
                
                case WowClassicMapId.Tempest_Keep_Dungeon_Netherstorm_1:
                case WowClassicMapId.Tempest_Keep_Dungeon_Netherstorm_2:
                    return WowMapId.TempestKeep;
                
                case WowClassicMapId.Sunwell_Plateau_Dungeon_Isle_of_Quel_Danas:
                case WowClassicMapId.Sunwell_Plateau_Dungeon_Sunwell_Plateau:
                    return WowMapId.TheSunwell;    
                    
                case WowClassicMapId.Zul_Gurub_Orphan_Stranglethorn_Vale_1:
                case WowClassicMapId.Zul_Gurub_Orphan_Stranglethorn_Vale_2:
                    return WowMapId.ZulGurub;
                
                case WowClassicMapId.Black_Temple_Dungeon_Shadowmoon_Valley:
                    return WowMapId.BlackTemple;
                
                case WowClassicMapId.Hellfire_Ramparts_Dungeon_Hellfire_Peninsula:
                    return WowMapId.HellfireRamparts;
                
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_1:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_2:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_3:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_4:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_5:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_6:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_7:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_8:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_9:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_10:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_11:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_12:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_13:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_14:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_15:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_16:
                case WowClassicMapId.Karazhan_Dungeon_Deadwind_Pass_17:
                    return WowMapId.Karazhan;
                
                case WowClassicMapId.Azeroth_World_Cosmic:
                case WowClassicMapId.Kalimdor_Continent_Azeroth:
                case WowClassicMapId.Eastern_Kingdoms_Continent_Azeroth:
                case WowClassicMapId.Alterac_Mountains_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Arathi_Highlands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Badlands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Blasted_Lands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Tirisfal_Glades_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Silverpine_Forest_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Western_Plaguelands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Eastern_Plaguelands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Hillsbrad_Foothills_Zone_Eastern_Kingdoms:
                case WowClassicMapId.The_Hinterlands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Dun_Morogh_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Searing_Gorge_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Burning_Steppes_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Elwynn_Forest_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Deadwind_Pass_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Duskwood_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Loch_Modan_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Redridge_Mountains_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Stranglethorn_Vale_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Swamp_of_Sorrows_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Westfall_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Wetlands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Stormwind_City_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Ironforge_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Undercity_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Eastern_Kingdoms_Continent:
                case WowClassicMapId.Eversong_Woods_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Ghostlands_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Silvermoon_City_Zone_Eastern_Kingdoms:
                case WowClassicMapId.Isle_of_Quel_Danas_Zone_Eastern_Kingdoms:
                    return WowMapId.EasternKingdoms;
                
                case WowClassicMapId.Outland_Continent:
                case WowClassicMapId.Hellfire_Peninsula_Zone_Outland:
                case WowClassicMapId.Outland_Continent_Cosmic:
                case WowClassicMapId.Zangarmarsh_Zone_Outland:
                case WowClassicMapId.Shadowmoon_Valley_Zone_Outland:
                case WowClassicMapId.Blade_s_Edge_Mountains_Zone_Outland:
                case WowClassicMapId.Nagrand_Zone_Outland:
                case WowClassicMapId.Terokkar_Forest_Zone_Outland:
                case WowClassicMapId.Netherstorm_Zone_Outland:
                case WowClassicMapId.Shattrath_City_Zone_Outland:
                    return WowMapId.Outland;
                
                case WowClassicMapId.Durotar_Zone_Kalimdor:
                case WowClassicMapId.Mulgore_Zone_Kalimdor:
                case WowClassicMapId.The_Barrens_Zone_Kalimdor:
                case WowClassicMapId.Teldrassil_Zone_Kalimdor:
                case WowClassicMapId.Darkshore_Zone_Kalimdor:
                case WowClassicMapId.Ashenvale_Zone_Kalimdor:
                case WowClassicMapId.Thousand_Needles_Zone_Kalimdor:
                case WowClassicMapId.Stonetalon_Mountains_Zone_Kalimdor:
                case WowClassicMapId.Desolace_Zone_Kalimdor:
                case WowClassicMapId.Feralas_Zone_Kalimdor:
                case WowClassicMapId.Dustwallow_Marsh_Zone_Kalimdor:
                case WowClassicMapId.Tanaris_Zone_Kalimdor:
                case WowClassicMapId.Azshara_Zone_Kalimdor:
                case WowClassicMapId.Felwood_Zone_Kalimdor:
                case WowClassicMapId.Un_Goro_Crater_Zone_Kalimdor:
                case WowClassicMapId.Moonglade_Zone_Kalimdor:
                case WowClassicMapId.Silithus_Zone_Kalimdor:
                case WowClassicMapId.Winterspring_Zone_Kalimdor:
                case WowClassicMapId.Orgrimmar_Zone_Kalimdor:
                case WowClassicMapId.Thunder_Bluff_Zone_Kalimdor:
                case WowClassicMapId.Darnassus_Zone_Kalimdor:
                case WowClassicMapId.Kalimdor_Continent:
                case WowClassicMapId.Azuremyst_Isle_Zone_Kalimdor:
                case WowClassicMapId.The_Exodar_Zone_Kalimdor:
                case WowClassicMapId.Bloodmyst_Isle_Zone_Kalimdor:
                    return WowMapId.Kalimdor;
                    
                case WowClassicMapId.Alterac_Valley_Zone_Azeroth:
                    return WowMapId.AlteracValley;
                
                case WowClassicMapId.Warsong_Gulch_Zone_Azeroth:
                    return WowMapId.WarsongGulch;
                
                case WowClassicMapId.Arathi_Basin_Zone_Azeroth:
                    return WowMapId.ArathiBasin;
                    
                case WowClassicMapId.Serpentshrine_Cavern_Dungeon_Zangarmarsh_1:
                case WowClassicMapId.Serpentshrine_Cavern_Dungeon_Zangarmarsh_2:
                    return WowMapId.SerpentshrineCavern;
                    
                case WowClassicMapId.Eye_of_the_Storm_Zone_Netherstorm:
                    return WowMapId.EyeOfTheStorm;
                    
                case WowClassicMapId.Cosmic_Cosmic:
                case WowClassicMapId.Maraudon_Dungeon_Desolace_1:
                case WowClassicMapId.Maraudon_Dungeon_Desolace_2:
                case WowClassicMapId.The_Temple_of_Atal_Hakkar_Dungeon_Swamp_of_Sorrows:
                default:
                    throw new ArgumentOutOfRangeException(nameof(mapId), mapId, null);
            }
        }
    Future learnings:
    * I'd like to understand how are people doing to find game offsets. With my free IDA version, I'm not able to find all LUA APIs in the WoW classic TBC client (it may come from the obfuscation) so I find it really hard to understand the logic & to find the offsets by myself. I wonder if people with the Pro version have the same issue... I've started to quickly have a look (here: https://www.ownedcore.com/forums/wor...ed-binary.html) but I need to spend more time on that part.
    * When time allows, I'll dig into the recast / detour usage (and actually understand that page: https://wowdev.wiki/ADT/v18 because I really don't know how to interpret the games files thanks to this wiki ). The final goal would be to be able to build a navmesh for at least a zone by myself.

    Side note: I won't provide the code I've written for my bot. I believe the information shared here can lead you on the road to build your own bot :-)
    thank you!

Similar Threads

  1. How to make your own bots!
    By Zeltraz500 in forum World of Warcraft Guides
    Replies: 10
    Last Post: 09-22-2008, 03:35 PM
  2. How to make your own items!!!
    By Ben090 in forum WoW EMU Guides & Tutorials
    Replies: 1
    Last Post: 09-26-2007, 01:08 AM
  3. WoW Emu Section (How to Make Your Own WoW Server)
    By Errage in forum Suggestions
    Replies: 8
    Last Post: 08-21-2007, 11:53 PM
  4. [Easy] How to Make Your Own WoW Forum Avatar!
    By Roflcopterzzz in forum Art & Graphic Design
    Replies: 21
    Last Post: 05-28-2007, 10:09 AM
  5. Make your own Bots for Wow/EQ2
    By HunterHero in forum World of Warcraft Bots and Programs
    Replies: 0
    Last Post: 10-19-2006, 10:05 AM
All times are GMT -5. The time now is 03:20 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search