UK
games/sorcery / src / Data / MapLayout.php · commit 613f5fb
<?phpnamespace App\Data;use App\Game\Values;/** Column/row of each room in the map panel (a port of modern/src/maplayout.cpp). */final class MapLayout{    /** @var array<int, array{col: int, row: int}> per room; col -1 = not reachable */    public array $pos = [];    public int $cols = 0;    public int $rows = 0;    public static function build(Level $level): self    {        $m = new self();        $n = count($level->rooms);        $m->pos = array_fill(0, $n, ['col' => -1, 'row' => -1]);        $unseen = 1 << 20;        $col = array_fill(0, $n, $unseen);        $order = [];        $start = $level->original ? 0 : 0;        if ($start < 0 || $start >= $n) {            $start = 0;        }        $order[] = $start;        $col[$start] = 0;        for ($q = 0; $q < count($order); $q++) {            $r = $order[$q];            $rec = $level->rooms[$r]->rec;            for ($d = 0; $d < 4; $d++) {                $dest = $rec[0x16 + 4 * $d + 2];                if ($rec[0x16 + 4 * $d] === Values::NONE || $dest >= $n || $col[$dest] !== $unseen) {                    continue;                }                $col[$dest] = $col[$r] + ($d < 2 ? -1 : 1);                $order[] = $dest;            }            foreach ($level->extras as $e) {                if ($e->type === Extra::TELEPORTER && $e->room === $r && $e->toRoom < $n && $col[$e->toRoom] === $unseen) {                    $col[$e->toRoom] = $col[$r];                    $order[] = $e->toRoom;                }            }        }        $minc = 0;        $maxc = 0;        foreach ($order as $r) {            $minc = min($minc, $col[$r]);            $maxc = max($maxc, $col[$r]);        }        $fill = array_fill(0, $maxc - $minc + 1, 0);        foreach ($order as $r) {            $c = $col[$r] - $minc;            $m->pos[$r] = ['col' => $c, 'row' => $fill[$c]++];            $m->rows = max($m->rows, $fill[$c]);        }        $m->cols = $maxc - $minc + 1;        return $m;    }}