# Game Bot Target Investigation

Este arquivo registra o trabalho feito na config `Sem Nome` e nas copias versionadas `Sem Nome v2.x`.

## Objetivo

Corrigir o TargetBot/CaveBot em hunts com ping alto.

O comportamento desejado e:

- Se nao estiver atacando ninguem, fazer scan das criaturas na area e atacar o primeiro monstro valido.
- Se ja estiver atacando um alvo, manter esse alvo.
- Enquanto tiver alvo, comparar os monstros na area e virar somente para um monstro com HP menor de forma estavel.
- Evitar spam de `attack` no mesmo alvo, porque isso parece gerar desalinhamento/freeze com ping alto.
- Manter magias, caminhada e cavebot alinhados durante o combate.
- Criar uma nova pasta de config a cada tentativa: `Sem Nome v2.1`, `Sem Nome v2.2`, etc.

## Problemas observados

- Com ping baixo, algumas colisoes entre target, cavebot, hold target e attack parecem normais porque a resposta do servidor chega rapido.
- Com ping 200 a 300, o target fica piscando/trocando de um monstro para outro.
- Em algumas versoes, o bot mandava `attack`, depois reenviava attack no mesmo alvo e depois ficava sem atacar por alguns instantes.
- O `g_game.getAttackingCreature()` pode ficar atrasado em relacao ao que o bot acabou de pedir para atacar. Isso fez algumas versoes tomarem decisoes erradas.
- Diferencas pequenas de HP entre monstros causam troca desnecessaria se a logica obedecer "qualquer HP menor" de forma literal.
- Scripts auxiliares como `Hold Attack`, `vBot/hold_target.lua`, `vBot/combo.lua`, `cavebot/actions.lua`, `clear_tile.lua` e `stand_lure.lua` tambem podem mandar attack e brigar com o target principal.
- Os logs `[TARGETDBG]` aparecem no console, mas ate agora nao foram encontrados salvos nos `otclientv8.log` locais.

## Arquivos principais alterados nas configs Sem Nome

- `targetbot/target.lua`
  - Seletor de alvo.
  - Scan de criaturas.
  - Regras de troca por HP.
  - Logs de decisao.

- `targetbot/creature_attack.lua`
  - Envio de `g_game.attack`.
  - Bloqueio de spam no mesmo creature id.
  - Reenvio controlado quando o client esta sem alvo.

- `vBot/target_debug.lua`
  - Helper global de logs `[TARGETDBG]`.
  - `AttackGuard` para evitar duplicates de attack vindos de scripts diferentes.

- `Hold Attack.lua` e `vBot/hold_target.lua`
  - Logs de reacquire.
  - Nas versoes recentes, ficam quietos quando TargetBot esta ligado para nao brigar com o alvo principal.

- `vBot/combo.lua`
  - Chamadas diretas de `g_game.attack` passam pela guarda/log.

- `cavebot/actions.lua`, `cavebot/clear_tile.lua`, `cavebot/stand_lure.lua`
  - Ataques auxiliares registrados e/ou guardados.

## Historico das versoes

### Sem Nome

Config original de trabalho. Recebeu a primeira instrumentacao pesada de logs.

Foram adicionados logs em target, cavebot, walking, attack, spells, runes, hold target, combo e scripts auxiliares.

### Sem Nome v2.1

Primeira copia versionada.

Ideia principal:

- escolher alvo por menor HP;
- segurar alvo;
- evitar spam de attack no mesmo creature id;
- retry controlado quando o primeiro attack nao confirmasse.

Problema:

- a trava ficou forte ou confusa demais em alguns cenarios;
- em ping alto podia parecer que nao atacava ou que reatacava em momentos ruins.

### Sem Nome v2.2

Tentativa anti-pisca mais conservadora.

Mudancas:

- margem maior de HP para trocar alvo;
- cooldown minimo entre trocas;
- grace quando alvo some do scan mas o client ainda acha que esta atacando;
- `Hold Target` fica quieto com TargetBot ligado.

Problema:

- ainda fazia confusoes no alvo;
- mudava alvo desnecessariamente em alguns cenarios.

### Sem Nome v2.3

Tentativa de remover a fonte de desalinhamento do retry.

Mudancas:

- removido retry automatico no mesmo alvo;
- se ja mandou attack naquele creature id, nao manda outro ate trocar/limpar o alvo;
- troca de alvo precisa ser mais madura.

Problema:

- em alguns testes nao virava attack em nenhum alvo, provavelmente por guardar demais ou por depender demais do estado confirmado do client.

### Sem Nome v2.4

Logica simplificada conforme objetivo discutido:

- se nao tem alvo, pega o primeiro monstro valido;
- se tem alvo, so compara se outro monstro tem HP menor;
- scan mais barato: evita path/config em criatura que nao importa.

Problema:

- obedecer "qualquer HP menor" literalmente fez o alvo trocar de um para outro quando os HPs oscilavam pouco.

### Sem Nome v2.5

Versao atual para teste.

Mudancas principais:

- introduz `desiredTargetId`, um alvo desejado estavel do bot;
- separa "alvo que o bot quer" do `g_game.getAttackingCreature()`, que pode atrasar com ping;
- se nao tem alvo desejado/atual, pega o primeiro monstro valido;
- se tem alvo desejado, mantem ele;
- so troca para outro se passar margem de HP e cooldown;
- continua com anti-spam de attack no mesmo creature id;
- permite reenvio curto apenas quando o client esta sem alvo.

Logs importantes:

```text
[TARGETDBG][target.desired.set]
[TARGETDBG][target.desired.clear]
[TARGETDBG][target.selected.change]
[TARGETDBG][target.scan.no_switch]
[TARGETDBG][target.attack.hold]
[TARGETDBG][target.attack.no_target_resend]
[TARGETDBG][attack.guard_skip]
```

### Sem Nome v2.7 (RECOMENDADA)

Igual a v2.6 + correcao da PISCADA (quadrado de ataque piscando).

- Causa: `targetbot/creature_priority.lua` com `rpSafe` ligado dava
  `cancelAttackAndFollow()` quando o alvo passava do `maxDistance`, mas ainda
  retornava priority=1 (marcava como alvo valido). Resultado: ataca -> cancela ->
  re-ataca em loop = piscada. Em Baiak, com paredes, o pathLen de um bicho perto
  passa de 10 e dispara isso.
- Fix: no ramo rpSafe+too_far agora retorna 0 (alvo nao-valido), entao nao ha
  ataque pra cancelar. A seguranca do rpSafe (nao atacar longe/perto de player)
  continua; o bot passa a atacar o bicho perto em vez de piscar no longe.
- Debug religado em modo ENXUTO (`TargetDebug.verbose=false`): so loga
  `target.cancel/switch/acquire/lost/selected/hold`, sem inflar o log.

Regra nova: cada mudanca vira uma pasta nova (v2.8, v2.9...), nao sobrescrever a
versao ja testada.

### Sem Nome v2.6

Reescrita limpa do `target.lua` depois de um diagnostico completo (ver secao abaixo).
Joga fora a maquina de estados confusa (`desiredTargetId` + `lockedTargetId` +
`pendingSwitch` + AttackGuard entrelacado + margens escaladas por ping) e usa UM
estado so: `committedId` (o alvo travado).

Logica:

- Sem alvo: avalia todos os monstros e trava no melhor (maior priority; desempate
  por distancia e id -> deterministico, nao "primeiro do scan").
- Com alvo: mantem o alvo travado; so vira para outro se o outro tiver HP no minimo
  `SWITCH_HP_MARGIN` (20%) menor, respeitando `SWITCH_COOLDOWN` (800ms) desde a
  ultima troca; nunca larga alvo com HP <= `FINISH_HP` (15%).
- O alvo travado e resolvido da area COMPLETA (12x12), entao a reducao para 6x6 em
  aglomeracao nunca derruba o alvo.
- Grace: se o alvo some do scan por 1 tick mas continua vivo e visivel, segura por
  `LOST_GRACE` (700ms) antes de desistir; se morreu/saiu de vez, reacquire na hora
  (sem ficar parado depois de matar).
- Nao usa `g_game.getAttackingCreature()` para escolher (isso atrasa com ping). Ele
  so e usado em `creature_attack.lua` para decidir se reenvia o `attack`.
- `creature_attack.lua`: envio simples com debounce (reenvia so a cada 400ms se o
  servidor nao confirmou). Fim do "ataca / para / ataca" causado pela trava antiga.

As 4 constantes ficam no topo de `target.lua` para ajuste fino.

Logs uteis da v2.6:

```text
target.acquire   (travou num alvo novo)
target.selected  (mudou o alvo mostrado)
target.switch    (virou por HP menor, mostra hp antes/depois)
target.hold      (segurando alvo sumido dentro do grace)
target.lost      (soltou: dead_or_gone ou unreachable_timeout)
```

## Diagnostico confirmado (causa do "vive virando")

Levantado por analise + verificacao adversarial das versoes v2.1..v2.5. Causas
internas do `target.lua` (todas confirmadas como alcancaveis no codigo):

1. Sem grace: se o alvo saia do scan por 1 tick, `desiredTargetId` era zerado na
   hora e um monstro DIFERENTE era escolhido no tick seguinte. `getLockedTargetLostGrace`
   existia mas nunca era chamado (codigo morto). -> causa principal.
2. A reducao 12x12 -> 6x6 em aglomeracao (>10 monstros) derrubava o alvo entre 4-6
   sqm, forcando re-target. Thrash ligado ao tamanho do grupo.
3. O loop de troca por HP nao tinha permanencia: trocava em cadeia pelo mais fraco
   do pacote (A->B->C->D), espalhando dano em vez de matar um.
4. A reaquisicao usava o "primeiro da lista de scan", que muda de ordem a cada tick.
5. `desiredTargetId` (instantaneo) vs `getAttackingCreature()` (atrasado por ping)
   geravam churn A->B->A so por causa do lag.

A v2.6 corrige as cinco.

### Fonte EXTERNA de troca (importante)

Alem do `target.lua`, existem scripts que mandam `attack` num alvo DIFERENTE e NAO
sao suprimidos com o TargetBot ligado (o AttackGuard so dedupa o MESMO id):

- `vBot/combo.lua` (LEADER TARGET / SERVER LEADER TARGET) ataca o alvo do lider a
  cada 10ms -> briga direto com o TargetBot. Se voce NAO usa combo de lider,
  mantenha essa opcao desligada; se usa, ela vai puxar o alvo.
- `cavebot/actions.lua` (goto/unclog), `cavebot/stand_lure.lua` (rushlure) e
  `cavebot/clear_tile.lua` atacam o monstro que bloqueia o caminho -> so quando
  travado/limpando tile, mas pode virar o alvo nesses momentos.
- `Hold Attack.lua` e `vBot/hold_target.lua`: OK, ja ficam quietos com TargetBot on.
- `vBot/AttackBot.lua`: OK, so lanca no alvo atual, nao troca alvo.

Se depois da v2.6 ainda houver troca, o suspeito numero 1 e o combo de lider.

## Proximo teste

Testar `Sem Nome v2.6`.

O teste deve observar:

- se trava no alvo e para de piscar entre monstros com HP parecido;
- se vira para outro so quando a diferenca de HP e real (>= 20%);
- se nao fica parado depois de matar (reacquire imediato);
- se em aglomeracao nao troca ao cruzar 10 monstros / distancia 3;
- se magias, runas, caminhada e loot continuam funcionando.

Se ainda trocar, checar se o combo de lider esta ligado, e coletar logs com:

```text
target.acquire
target.selected
target.switch
target.hold
target.lost
```

## Regra de versionamento

Nao sobrescrever a versao testada.

Cada ajuste novo deve criar uma nova pasta:

```text
Sem Nome v2.6
Sem Nome v2.7
Sem Nome v2.8
```

Assim da para comparar qual tentativa foi testada e qual comportamento mudou.
