25/10/2023
WoW Arduino Fisher


Então… eu fiz um negócio.

Aviso Legal
Este projeto é apenas para fins de aprendizado. Não o use para tirar cheatar no jogo e não o teste nos servidores oficiais da Blizzard. A automação de jogo é contra as regras e você pode perder sua conta. Se quiser testar, tente em um servidor private.

Dito isso, deixe-me começar contando a motivação por trás desta ideia. Em algum momento da minha vida como jogador de WoW (quase 12 anos agora), comecei a colecionar achievements.

Para aqueles que não conhecem o WoW, seus personagens podem aprender até cinco profissões — 2 principais e 3 secundárias. Pesca é uma das profissões secundárias (Culinária e Arqueologia são as outras duas disponíveis). Pescando você pode coletar alguns reagentes, consumíveis, materiais de crafting, colecionáveis e mais; você também pode obter algumas conquistas.

Uma dessas conquistas, Old Crafty , pede que você pegue um peixe raro em Orgrimmar (uma das principais cidades do jogo). Fácil, né?

Bem, passei um bom tempo tentando pescá-lo. Mais precisamente, no final, levei quase 15.000 arremessos para pegá-lo. Isso foi muito chato, já que cada arremesso pode levar até cerca de 22 segundos.

Tá, como um pequeno exercício, deve haver uma maneira de automatizar isso reduzindo as chances de ser pego. Um amigo me ensinou recentemente que hoje em dia você pode oficialmente pescar no WoW usando dois atalhos: um para lançar a linha e outro para fisgar o peixe.

Alguns dias atrás, eu estava organizando algumas coisas em casa e encontrei uma caixa cheia de Arduinos, sendo um deles um Arduino Leonardo . Mas o que o torna particularmente útil para este projeto? Ele pode aparecer para um computador conectado como um mouse e teclado, então ele pode enviar apertos de tecla para o computador dizendo ao jogo o que fazer.

Isso nos deixa com um pequeno detalhe: como sabemos se o peixe foi fisgado para que o comando de captura possa ser enviado? Eu não queria usar software para ler a tela ou a memória, pois isso poderia ser facilmente detectado pelo sistema anti-cheat do jogo. Então, sem olhar para a tela, de quais outras formas o jogo pode nos dizer que devemos fisgar o peixe? Pelo som que o jogo faz quando o peixe morde a isca.

Para este projeto, não me preocupei muito com robustez, então há espaço para melhorias. Se eu fosse fazer uma versão melhor disso, eu usaria um módulo amplificador (um amplificador de áudio LM386 ou algo como isto ), para amplificar o sinal que vem da placa de som antes de entrar no Arduino.

Como não usei um amplificador, o circuito é extremamente simples. Basta conectar a saída da placa de som no Arduino. Ligue o terra da placa de som e o terra do Arduino juntos, e envie o sinal para uma das entradas analógicas (escolhi a A1). O circuito é o seguinte:

A saída da placa de som é representada como a caixa de som.

Aqui está o código-fonte para a versão básica do software. Deixarei o código-fonte completo no meu GitHub , junto com alguns truques que implementei para tornar o comportamento do programa um pouco mais aleatório.

#include <Keyboard.h>

#define FISHING_TIMEOUT 25000
#define SOUND_DETECT_THRESHOLD 50

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

// Variável para rastrear se estamos pescando ou não
bool isFishing = false;

// Lança a linha de pesca enviando o pressionamento da tecla de pesca
void fish()
{
    Serial.println("Pescando.");
    Keyboard.write(FISHING_KEY);
    isFishing = true;
}

// Fisga o peixe enviando o pressionamento da tecla de captura
void catch_fish()
{
    // Ignora isso se não estivermos pescando no momento.
    // Isso existe para não enviar múltiplos comandos
    // quando já estiver capturando um peixe.
    if (!isFishing)
    {
        Serial.println("CATCH: chamado quando não está pescando. Ignorando.");
        return;
    }

    // Espera um pouco antes de fisgar o peixe.
    Serial.print("CATCH: atraso de 1500ms antes de fisgar.");
    delay(1500);
    Keyboard.write(CATCH_KEY);
    isFishing = false;
}

void setup()
{
    delay(1000);
    
    // Inicializa as bibliotecas de teclado e serial.
    Keyboard.begin();
    Serial.begin(9600);
    Serial.println("Fisher v0.1");
    
    delay(1000);
}

void loop()
{
    int soundDetect;

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

    // Fica ouvindo o som que o jogo faz quando um peixe é fisgado.
    do
    {
        // Se tempo suficiente passou, talvez tenhamos perdido algum peixe, então começa de novo.
        if (millis() > (fishing_start_time + FISHING_TIMEOUT))
        {
            Serial.println("LOOP: falha ao detectar som de fisgada. Recomeçando.");
            fish();
            fishing_start_time = millis();
        }

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

    // Pegamos um peixe! Eba!
    Serial.println("Peixe detectado.");
    catch_fish();

    // Espera um pouco antes de lançar a linha novamente.
    Serial.print("LOOP: aguarda 2000ms antes de pescar novamente.");
    delay(2000);
}

Tenha em mente que esta não é uma solução perfeita. Como ela depende do som para tomar ações, você precisa pescar em lugares silenciosos, pois ruídos próximos podem ser interpretados como se um peixe tivesse sido fisgado.

Você também precisa manter a janela do WoW em foco para que os comandos de teclado funcionem. Talvez você precise testar diferentes níveis de som e ajustar o código para compensar variações das placas de som.

E lembre-se: eu não me responsabilizo pelo uso deste projeto.

Agora, vamos tentar pegar o Old Ironjaw (mas sem trapacear!) :)