/** Drones aliados: seguem o jogador em órbita e atiram no zumbi mais próximo à vista. */ import { registrarEliminacao } from "./feed"; import { moverComColisao, temLinhaDeVisao } from "./mapa"; import type { Drone, Partida, Zumbi } from "./tipos"; import { DRONE, PASSO } from "./valores"; import { ferir } from "./zumbis"; const RAIO_DO_DRONE = 0.2; const PASSO_MAXIMO = DRONE.velocidade * PASSO; const ANGULO_ENTRE_DRONES = (2 * Math.PI) / 3; const ALTURA_DO_ACERTO = 1.2; export function criarDrone(p: Partida, problemaId: string): Drone { const drone: Drone = { id: p.proximoId++, problemaId, x: p.jogador.x, z: p.jogador.z, rumo: p.jogador.rumo, recarga: DRONE.intervalo, eliminacoes: 0, }; p.drones.push(drone); return drone; } function seguirJogador(p: Partida, drone: Drone, indice: number): void { const angulo = p.jogador.rumo + Math.PI / 2 + indice * ANGULO_ENTRE_DRONES; const dx = p.jogador.x + Math.sin(angulo) * DRONE.distancia - drone.x; const dz = p.jogador.z + Math.cos(angulo) * DRONE.distancia - drone.z; const fracao = Math.min(1, PASSO_MAXIMO / Math.hypot(dx, dz)); [drone.x, drone.z] = moverComColisao( p.mapa, drone.x, drone.z, dx * fracao, dz * fracao, RAIO_DO_DRONE, ); } function zumbiMaisProximo(p: Partida, drone: Drone): Zumbi | undefined { let alvo: Zumbi | undefined; let melhor = Number.POSITIVE_INFINITY; for (const zumbi of p.zumbis) { const d = Math.hypot(zumbi.x - drone.x, zumbi.z - drone.z); if ( zumbi.estado !== "morrendo" && d <= DRONE.alcance && d < melhor && temLinhaDeVisao(p.mapa, drone.x, drone.z, zumbi.x, zumbi.z) ) { alvo = zumbi; melhor = d; } } return alvo; } function atirar(p: Partida, drone: Drone, alvo: Zumbi): void { const dx = alvo.x - drone.x; const dz = alvo.z - drone.z; drone.rumo = Math.atan2(dx, dz); p.eventos.push( { tipo: "tiro", autor: drone.id, arma: "drone", distancia: Math.hypot(dx, dz), }, { tipo: "acerto", zumbiId: alvo.id, cabeca: false, x: alvo.x, y: ALTURA_DO_ACERTO, z: alvo.z, }, ); const matou = ferir(p, alvo, DRONE.dano, drone.id); drone.recarga = DRONE.intervalo; if (matou) registrarEliminacao(p, drone.problemaId, alvo.problemaId); } export function avancarDrones(p: Partida): void { p.drones.forEach((drone, indice) => { seguirJogador(p, drone, indice); drone.recarga = Math.max(0, drone.recarga - 1); if (drone.recarga > 0) return; const alvo = zumbiMaisProximo(p, drone); if (alvo) atirar(p, drone, alvo); }); }