.json), and the level cache. */ final class Campaign { public const LEVELS = ['m1', 'm2', 'm3']; public const SKILLS = [1 => 'I CAN WIN THIS', 2 => 'BRING IT ON', 3 => 'NO MERCY']; /** @var array parsed level files */ private static array $data = []; public static function next(string $id): ?string { $i = array_search($id, self::LEVELS, true); return $i === false ? null : (self::LEVELS[$i + 1] ?? null); } /** A fresh Level (geometry changes while playing: doors, lifts...). */ public static function level(string $file, string $id): Level { self::$data[$id] ??= json_decode((string)file_get_contents($file), true) ?: throw new \RuntimeException("Bad level $file"); return new Level($id, self::$data[$id], Info::THING_LEGEND); } }