25/10/2023
WoW Arduino Fisher


So… I made a thing.

DISCLAIMER:

This project is intended only as a learning exercise. Don’t use it to take advantage in the game, and don’t try it on Blizz’s live servers. Automation of gameplay is against the rules, and you could lose your account. Try it on a private server if you wish to see it working.

Having said that, let me start by telling you the motivation behind this idea. At some point in my life as a WoW player (almost 12 years now), I began to collect achievements.

For those that doesn’t know WoW, your characters can learn up to five professions - 2 main and 3 secondary. Fishing is one of the secondary professions (Cooking and Archaeology being the other two available). By fishing you can collect some reagents, consumables, crafting materials, collectibles and more; you can also get some achievements.

One of these achievements, Old Crafty, asks you to catch a rare fish in Orgrimmar (one of the main cities in the game). Easy, right?

Well, I spent quite some time trying to fish it up. More precisely, in the end it took me almost 15,000 casts to catch it. Let me say that it was extremely boring, as each cast can take up to about 22 seconds.

Okay, as a little exercise, there must be a way to automatize this while reducing the chances to being caught. As a friend recently taught me, you can officially fish in WoW using two keybinds nowadays: one for casting the line and another for grabbing the fish.

Some days ago I was organizing some stuff around the house and found a box full of Arduinos, one of them being an Arduino Leonardo. But what makes it useful for this project? Well, it can appear to a connected computer as a mouse and keyboard, so it can send keystrokes to the computer telling the game what to do.

That leaves us with one little detail: how do we know if the fish is hooked so the catch keystroke can be sent? I didn’t want to use software for reading the screen or memory, as this could easily be caught by the anti-cheat system in the game. So, without looking at the screen, which other ways can the game tell us that we should catch the fish? By the sound the game makes when fish bite the bait.

For this project, I didn’t put a lot of effort on make it rock solid, so there is some room for improvement. If I would make a better version of this, I would use an amplifier module (an LM386 audio amplifier or something like this), to amplify the signal that comes from the sound card before it enters the Arduino.

As I didn’t use an amplifier, the circuit is extremely simple. Just plug the output of the sound card on the Arduino. Tie the ground signal of the sound card and the ground signal of the Arduino together, and feed the signal to one of the analog inputs (I chose A1). The circuit is as follow:

The sound card output is represented as the speakerbox.

Here is the source code for the basic version of the software. I will leave the full source code on my GitHub, along some tricks that I implemented to make the program behavior a little more random.

#include <Keyboard.h>

#define FISHING_TIMEOUT 25000
#define SOUND_DETECT_THRESHOLD 50

const char FISHING_KEY = '1';
const char CATCH_KEY = 'f';

// Variable to keep track if we are fishing or not
bool isFishing = false;

// Throw the fishing line by issuing the fishing key keystroke
void fish()
{
    Serial.println("Fishing.");
    Keyboard.write(FISHING_KEY);
    isFishing = true;
}

// Catch the fish by issuing the catch key keystroke
void catch_fish()
{
    // Ignore this if we are not currently fishing.
    // This exists so that it doesnt issue multiple keystrokes
    // when already catching a fish.
    if (!isFishing)
    {
        Serial.println("CATCH: called when not fishing. Ignoring.");
        return;
    }

    // Wait sometime before catching the fish.
    Serial.print("CATCH: delay 1500ms before catching.");
    delay(1500);
    Keyboard.write(CATCH_KEY);
    isFishing = false;
}

void setup()
{
    delay(1000);
    
    // Init the keyboard and serial libraries.
    Keyboard.begin();
    Serial.begin(9600);
    Serial.println("Fisher v0.1");
    
    delay(1000);
}

void loop()
{
    int soundDetect;

    fish();
    unsigned long fishing_start_time = millis();

    // Keep listening for the sound the game makes when a fish is hooked.
    do
    {
        // If enough time has elapsed, maybe we missed some fish, so it starts again.
        if (millis() > (fishing_start_time + FISHING_TIMEOUT))
        {
            Serial.println("LOOP: failed to detect catch sound. Starting again.");
            fish();
            fishing_start_time = millis();
        }

        soundDetect = analogRead(A1);
        delay(100);
    } while (soundDetect < SOUND_DETECT_THRESHOLD);

    // We caught some fish! Yay!
    Serial.println("Fish detected.");
    catch_fish();

    // Wait a little before throwing the line again.
    Serial.print("LOOP: wait 2000ms before fishing again.");
    delay(2000);
}

Keep in mind that this is not a perfect solution. As it relies on sound for taking actions, you have to fish in places that are quiet, as nearby noises can make it interpret as if a fish was caught.

You also need to keep the WoW window focused for the keystrokes to work. You may need to try different sound levels and adjust the code to compensate for variations of sound cards.

And remember: I do not take responsibility for the usage of this project.

Now, let’s try to get the Old Ironjaw (without cheating!) :)