L'Armure Sacrée d'Antiriad

by davidnurdin · Remakes
not rated yet
▶ Play Source Edit GitHub
games/antiriad-php / src / Antiriad / World.php · commit decc30a
<?phpnamespace App\Antiriad;/** * The original game's data, as tools/extract/export.py took it from the disc (assets/data/world.json): * rooms (exits, palette, ground, objects), animations, movement programs, object types, items, texts, font. * * Units are the original's: x in screen bytes (0-79, 4 virtual pixels each), y in the game's lines * (50 = the top of the playfield, 177 = its bottom line). */final class World{    public const TOP = 50;              // y of the playfield's first line    public const BOTTOM = 178;          // y just under its last line    public const ROOMS = 69;    public const PIXELS_PER_BYTE = 4;    private static ?self $instance = null;    /** @var array<int, array{exits: array<string, ?int>, palette: int, ground: list<string>, walls: list<string>, ceiling: list<string>, objects: list<list<int>>}> */    public array $rooms;    /** @var list<array{x: int, y: int, w: int, h: int, colour: int}> */    public array $sprites;    /** @var list<array{ticks: int, frames: list<int>, end: string, next?: int}> */    public array $anims;    /** @var list<list<int>> 4 bytes per object type */    public array $types;    /** @var list<array{steps: list<list<int>>, end: string}> */    public array $programs;    /** @var list<int> lines per tick while falling */    public array $fall;    /** @var list<list<int>> (room, x, y) of the 4 suit modules */    public array $modules;    /** @var list<list<int>> (room, x, y) of the recharge cells */    public array $cells;    /** @var list<int> (room, x, y) of the suit at the start */    public array $armour;    /** @var list<list<int>> (room, x, y) start places */    public array $start;    /** @var list<string> the original's messages (Spanish edition) */    public array $messages;    /** @var list<list<int>> 14 palettes: 16 pens -> hardware colour */    public array $palettes;    /** @var list<list<int>> hardware colour -> RGB */    public array $hw;    /** @var array{glyphs: list<list<string>>, chars: array<string, int>} */    public array $font;    public static function load(string $path): self    {        if (self::$instance === null) {            $data = json_decode((string)file_get_contents($path), true);            if (!is_array($data)) {                throw new \RuntimeException("$path: not found or not JSON (run tools/extract/extract.sh)");            }            $w = new self();            foreach (['rooms', 'sprites', 'anims', 'types', 'programs', 'fall', 'modules', 'cells', 'armour', 'start',                         'messages', 'palettes', 'hw', 'font'] as $key) {                $w->$key = $data[$key];            }            self::$instance = $w;        }        return self::$instance;    }    public function exit(int $room, string $side): ?int    {        return $this->rooms[$room]['exits'][$side] ?? null;    }    /** Pen 1 or 5 on a line of the playfield's first 8 (x0..x1 in mode 0 pixels): the ceiling test of #6714. */    public function ceilingAt(int $room, int $line, int $x0, int $x1): bool    {        $screen = $line - self::TOP;        if ($screen < 0 || $screen >= 8) {            return false;        }        $row = $this->rooms[$room]['ceiling'][$screen];        for ($x = max(0, $x0); $x <= min(159, $x1); $x++) {            if ($row[$x] === '1') {                return true;            }        }        return false;    }    /** Pen 3 or 7 on the line under (x0..x1 in mode 0 pixels, 0-159): the ground test of #68B4. */    public function groundAt(int $room, int $line, int $x0, int $x1): bool    {        $screen = $line - self::TOP;        if ($screen < 0 || $screen >= 128 || ($screen & 7) !== 0) {            return false;        }        $row = $this->rooms[$room]['ground'][$screen >> 3];        for ($x = max(0, $x0); $x <= min(159, $x1); $x++) {            if ($row[$x] === '1') {                return true;            }        }        return false;    }    /**     * A pixel of pen 7 in screen byte $byte (0-79) between lines $from and $to: a wall (#67B6 scans the     * column Tal walks into). The rooms' walls are hex strings of 80 bits per line.     */    public function wallAt(int $room, int $byte, int $from, int $to): bool    {        if ($byte < 0 || $byte > 79) {            return false;        }        $rows = $this->rooms[$room]['walls'];        $digit = $byte >> 2;        $mask = 8 >> ($byte & 3);        for ($y = max(0, $from - self::TOP), $last = min(127, $to - self::TOP); $y <= $last; $y++) {            if (hexdec($rows[$y][$digit]) & $mask) {                return true;            }        }        return false;    }    /** RGB of a pen in a room palette. */    public function rgb(int $palette, int $pen): array    {        return $this->hw[$this->palettes[$palette][$pen]];    }    /** The type's 4 bytes (byte 0: bit 7 object, bit 6 enemy, bit 5 + low bits a handler; byte 1 bits 7-5 hits). */    public function type(int $type): array    {        return $this->types[$type] ?? [0, 0, 0, 0];    }}