<?phpnamespace App\Data;/** The parser of the room text files (a port of common/roomtext.cpp, parse only). */final class RoomText{ /** * @param string[] $error error message out-param (single element) */ public static function parse(string $text, ?array &$error = null): ?RoomDef { $out = new RoomDef(); $nmap = 0; $nrec = 0; $haveRoom = false; $section = ''; $lineNo = 0; foreach (preg_split('/\r?\n/', $text) as $line) { $lineNo++; $cut = strpos($line, ';'); if ($cut !== false) { $line = substr($line, 0, $cut); } $toks = preg_split('/\s+/', trim($line), -1, PREG_SPLIT_NO_EMPTY); if ($toks === false || $toks === []) { continue; } if (count($toks) === 2 && $toks[0] === 'room') { $out->number = (int)$toks[1]; $haveRoom = true; continue; } if (count($toks) === 1 && ($toks[0] === 'map' || $toks[0] === 'record')) { $section = $toks[0]; continue; } if (count($toks) === 1 && $toks[0] === 'end') { $section = ''; continue; } if ($section === '') { $error = ["line $lineNo: unexpected text outside map/record"]; return null; } foreach ($toks as $t) { if ($section === 'record' && substr($t, -1) === ':') { continue; } if ($section === 'map') { if ($t === '..' || $t === '--') { $v = 0; } elseif (strlen($t) === 2 && ctype_xdigit($t)) { $v = (int)hexdec($t); } else { $error = ["line $lineNo: bad tile '$t' (use two hex digits or '..')"]; return null; } if ($nmap >= 720) { $error = ['map has more than 720 tiles']; return null; } if ($v === 0xFF) { $error = ['tile id FF is reserved (end marker of the original format)']; return null; } $out->map[$nmap++] = $v; } else { if (strlen($t) !== 2 || !ctype_xdigit($t)) { $error = ["line $lineNo: bad byte '$t'"]; return null; } if ($nrec >= 64) { $error = ['record has more than 64 bytes']; return null; } $out->rec[$nrec++] = (int)hexdec($t); } } } if (!$haveRoom) { $error = ["missing 'room N' line"]; return null; } if ($nmap !== 720) { $error = ["map must have 40 x 18 = 720 tiles, found $nmap"]; return null; } if ($nrec !== 64) { $error = ["record must have 64 bytes, found $nrec"]; return null; } return $out; }}