UK
games/doom-jumphp / src / Game / Bot.php · commit 8e1cb9f
<?phpnamespace App\Game;/** * Plays by itself (the title screen's demo, the smoke test): walks the level, opens doors, turns at walls, * shoots the monsters it sees. */final class Bot{    private float $lastX = 0.0;    private float $lastY = 0.0;    private int $stuck = 0;    private float $turnLeft = 0.0;    private int $tics = 0;    public function cmd(World $w): array    {        $this->tics++;        $mo = $w->player->mo;        $cmd = ['forward' => 1.0, 'side' => 0.0, 'turn' => 0.0, 'fire' => false, 'use' => $this->tics % 24 < 2, 'weapon' => null];        // the nearest monster in sight        $best = null;        $bestD = 1400.0;        foreach ($w->mobjs as $th) {            if (!$th->is(Info::COUNTKILL) || $th->health <= 0) {                continue;            }            $d = hypot($th->x - $mo->x, $th->y - $mo->y);            if ($d < $bestD && $w->checkSight($mo, $th)) {                $best = $th;                $bestD = $d;            }        }        if ($best !== null) {            $want = atan2($best->y - $mo->y, $best->x - $mo->x);            $delta = fmod($want - $mo->angle + 5 * M_PI, 2 * M_PI) - M_PI;            $cmd['turn'] = max(-0.12, min(0.12, $delta));            $cmd['fire'] = abs($delta) < 0.12;            $cmd['forward'] = $bestD > 200 ? 0.5 : -0.3;            $cmd['side'] = sin($this->tics / 20) * 0.6;            // the best weapon it has            foreach ([4, 3, 2] as $n) {                $def = Weapons::LIST[$n];                if (!empty($w->player->weapons[$n]) && $w->player->ammo[$def['ammo']] > 0) {                    $cmd['weapon'] = $n;                    break;                }            }            return $cmd;        }        // wander: turn when stuck        $moved = hypot($mo->x - $this->lastX, $mo->y - $this->lastY);        $this->lastX = $mo->x;        $this->lastY = $mo->y;        $this->stuck = $moved < 0.6 ? $this->stuck + 1 : 0;        if ($this->stuck > 6 && $this->turnLeft == 0.0) {            $this->turnLeft = (M_PI / 2 + ($w->random() / 255) * M_PI) * (($w->random() & 1) ? 1 : -1);            $this->stuck = 0;        }        if ($this->turnLeft != 0.0) {            $step = max(-0.12, min(0.12, $this->turnLeft));            $cmd['turn'] = $step;            $this->turnLeft -= $step;            if (abs($this->turnLeft) < 0.01) {                $this->turnLeft = 0.0;            }            $cmd['forward'] = 0.2;        }        return $cmd;    }}