Sign in
EN
games/doom-jumphp / src / Game / Info.php · commit 8e1cb9f
<?phpnamespace App\Game;/** * The things of IRON ABYSS and their state machines (the shape of info.c: a state = sprite, frame, tics, * action, next state; a frame letter followed by '!' is drawn full bright). Original creatures and items. */final class Info{    public const SOLID = 1, SHOOTABLE = 2, NOBLOOD = 4, SPECIAL = 8, NOGRAVITY = 16, DROPOFF = 32, PICKUP = 64,        MISSILE = 128, CORPSE = 256, COUNTKILL = 512, COUNTITEM = 1024, AMBUSH = 2048, JUSTHIT = 4096,        JUSTATTACKED = 8192, NOCLIP = 16384, DROPPED = 32768, NOSECTOR = 65536, BOSS = 131072;    /** state name => [sprite, frame, tics, action|null, next|null] */    public const STATES = [        'NULL' => ['', 'A', -1, null, null],        'PLAYER' => ['', 'A', -1, null, null],        // the husk: a mining droid gone wrong, shoots bursts        'HUSK_STND' => ['HUSK', 'A', 10, 'look', 'HUSK_STND2'], 'HUSK_STND2' => ['HUSK', 'B', 10, 'look', 'HUSK_STND'],        'HUSK_RUN1' => ['HUSK', 'A', 4, 'chase', 'HUSK_RUN2'], 'HUSK_RUN2' => ['HUSK', 'A', 4, 'chase', 'HUSK_RUN3'],        'HUSK_RUN3' => ['HUSK', 'B', 4, 'chase', 'HUSK_RUN4'], 'HUSK_RUN4' => ['HUSK', 'B', 4, 'chase', 'HUSK_RUN5'],        'HUSK_RUN5' => ['HUSK', 'C', 4, 'chase', 'HUSK_RUN6'], 'HUSK_RUN6' => ['HUSK', 'C', 4, 'chase', 'HUSK_RUN7'],        'HUSK_RUN7' => ['HUSK', 'D', 4, 'chase', 'HUSK_RUN8'], 'HUSK_RUN8' => ['HUSK', 'D', 4, 'chase', 'HUSK_RUN1'],        'HUSK_ATK1' => ['HUSK', 'E', 10, 'faceTarget', 'HUSK_ATK2'], 'HUSK_ATK2' => ['HUSK', 'F!', 8, 'huskShoot', 'HUSK_ATK3'],        'HUSK_ATK3' => ['HUSK', 'E', 8, null, 'HUSK_RUN1'],        'HUSK_PAIN' => ['HUSK', 'G', 3, null, 'HUSK_PAIN2'], 'HUSK_PAIN2' => ['HUSK', 'G', 3, 'pain', 'HUSK_RUN1'],        'HUSK_DIE1' => ['HUSK', 'H!', 5, null, 'HUSK_DIE2'], 'HUSK_DIE2' => ['HUSK', 'I!', 5, 'scream', 'HUSK_DIE3'],        'HUSK_DIE3' => ['HUSK', 'J', 5, 'fall', 'HUSK_DIE4'], 'HUSK_DIE4' => ['HUSK', 'K', 5, null, 'HUSK_DIE5'],        'HUSK_DIE5' => ['HUSK', 'L', -1, null, null],        // the gnasher: a fast biting beast        'GNSH_STND' => ['GNSH', 'A', 10, 'look', 'GNSH_STND2'], 'GNSH_STND2' => ['GNSH', 'B', 10, 'look', 'GNSH_STND'],        'GNSH_RUN1' => ['GNSH', 'A', 2, 'chase', 'GNSH_RUN2'], 'GNSH_RUN2' => ['GNSH', 'A', 2, 'chase', 'GNSH_RUN3'],        'GNSH_RUN3' => ['GNSH', 'B', 2, 'chase', 'GNSH_RUN4'], 'GNSH_RUN4' => ['GNSH', 'B', 2, 'chase', 'GNSH_RUN5'],        'GNSH_RUN5' => ['GNSH', 'C', 2, 'chase', 'GNSH_RUN6'], 'GNSH_RUN6' => ['GNSH', 'C', 2, 'chase', 'GNSH_RUN7'],        'GNSH_RUN7' => ['GNSH', 'D', 2, 'chase', 'GNSH_RUN8'], 'GNSH_RUN8' => ['GNSH', 'D', 2, 'chase', 'GNSH_RUN1'],        'GNSH_ATK1' => ['GNSH', 'E', 8, 'faceTarget', 'GNSH_ATK2'], 'GNSH_ATK2' => ['GNSH', 'F', 8, 'faceTarget', 'GNSH_ATK3'],        'GNSH_ATK3' => ['GNSH', 'F', 8, 'bite', 'GNSH_RUN1'],        'GNSH_PAIN' => ['GNSH', 'G', 2, null, 'GNSH_PAIN2'], 'GNSH_PAIN2' => ['GNSH', 'G', 2, 'pain', 'GNSH_RUN1'],        'GNSH_DIE1' => ['GNSH', 'H', 8, null, 'GNSH_DIE2'], 'GNSH_DIE2' => ['GNSH', 'I', 8, 'scream', 'GNSH_DIE3'],        'GNSH_DIE3' => ['GNSH', 'J', 4, 'fall', 'GNSH_DIE4'], 'GNSH_DIE4' => ['GNSH', 'K', -1, null, null],        // the spitter: claws up close, acid balls from afar        'SPIT_STND' => ['SPIT', 'A', 10, 'look', 'SPIT_STND2'], 'SPIT_STND2' => ['SPIT', 'B', 10, 'look', 'SPIT_STND'],        'SPIT_RUN1' => ['SPIT', 'A', 3, 'chase', 'SPIT_RUN2'], 'SPIT_RUN2' => ['SPIT', 'A', 3, 'chase', 'SPIT_RUN3'],        'SPIT_RUN3' => ['SPIT', 'B', 3, 'chase', 'SPIT_RUN4'], 'SPIT_RUN4' => ['SPIT', 'B', 3, 'chase', 'SPIT_RUN5'],        'SPIT_RUN5' => ['SPIT', 'C', 3, 'chase', 'SPIT_RUN6'], 'SPIT_RUN6' => ['SPIT', 'C', 3, 'chase', 'SPIT_RUN7'],        'SPIT_RUN7' => ['SPIT', 'D', 3, 'chase', 'SPIT_RUN8'], 'SPIT_RUN8' => ['SPIT', 'D', 3, 'chase', 'SPIT_RUN1'],        'SPIT_ATK1' => ['SPIT', 'E', 8, 'faceTarget', 'SPIT_ATK2'], 'SPIT_ATK2' => ['SPIT', 'F!', 8, 'faceTarget', 'SPIT_ATK3'],        'SPIT_ATK3' => ['SPIT', 'G', 6, 'spitAttack', 'SPIT_RUN1'],        'SPIT_PAIN' => ['SPIT', 'H', 2, null, 'SPIT_PAIN2'], 'SPIT_PAIN2' => ['SPIT', 'H', 2, 'pain', 'SPIT_RUN1'],        'SPIT_DIE1' => ['SPIT', 'I', 8, null, 'SPIT_DIE2'], 'SPIT_DIE2' => ['SPIT', 'J', 8, 'scream', 'SPIT_DIE3'],        'SPIT_DIE3' => ['SPIT', 'K', 6, 'fall', 'SPIT_DIE4'], 'SPIT_DIE4' => ['SPIT', 'L', -1, null, null],        // the warden: the armoured guardian of the core, plasma cannon        'WARD_STND' => ['WARD', 'A', 10, 'look', 'WARD_STND2'], 'WARD_STND2' => ['WARD', 'B', 10, 'look', 'WARD_STND'],        'WARD_RUN1' => ['WARD', 'A', 3, 'chase', 'WARD_RUN2'], 'WARD_RUN2' => ['WARD', 'A', 3, 'chase', 'WARD_RUN3'],        'WARD_RUN3' => ['WARD', 'B', 3, 'chase', 'WARD_RUN4'], 'WARD_RUN4' => ['WARD', 'B', 3, 'chase', 'WARD_RUN5'],        'WARD_RUN5' => ['WARD', 'C', 3, 'chase', 'WARD_RUN6'], 'WARD_RUN6' => ['WARD', 'C', 3, 'chase', 'WARD_RUN7'],        'WARD_RUN7' => ['WARD', 'D', 3, 'chase', 'WARD_RUN8'], 'WARD_RUN8' => ['WARD', 'D', 3, 'chase', 'WARD_RUN1'],        'WARD_ATK1' => ['WARD', 'E', 10, 'faceTarget', 'WARD_ATK2'], 'WARD_ATK2' => ['WARD', 'F!', 6, 'wardenFire', 'WARD_ATK3'],        'WARD_ATK3' => ['WARD', 'E', 8, 'faceTarget', 'WARD_ATK4'], 'WARD_ATK4' => ['WARD', 'F!', 6, 'wardenFire', 'WARD_ATK5'],        'WARD_ATK5' => ['WARD', 'E', 8, 'faceTarget', 'WARD_ATK6'], 'WARD_ATK6' => ['WARD', 'F!', 6, 'wardenFire', 'WARD_RUN1'],        'WARD_PAIN' => ['WARD', 'G', 3, null, 'WARD_PAIN2'], 'WARD_PAIN2' => ['WARD', 'G', 3, 'pain', 'WARD_RUN1'],        'WARD_DIE1' => ['WARD', 'H', 8, 'scream', 'WARD_DIE2'], 'WARD_DIE2' => ['WARD', 'I', 8, null, 'WARD_DIE3'],        'WARD_DIE3' => ['WARD', 'J', 8, 'fall', 'WARD_DIE4'], 'WARD_DIE4' => ['WARD', 'K', 30, null, 'WARD_DIE5'],        'WARD_DIE5' => ['WARD', 'K', -1, 'bossDeath', null],        // projectiles        'ACID1' => ['ACID', 'A!', 4, null, 'ACID2'], 'ACID2' => ['ACID', 'B!', 4, null, 'ACID1'],        'ACIDX1' => ['ACID', 'C!', 6, null, 'ACIDX2'], 'ACIDX2' => ['ACID', 'D!', 6, null, 'ACIDX3'], 'ACIDX3' => ['ACID', 'E!', 6, null, null],        'PLSM1' => ['PLSM', 'A!', 4, null, 'PLSM2'], 'PLSM2' => ['PLSM', 'B!', 4, null, 'PLSM1'],        'PLSMX1' => ['PLSM', 'C!', 6, null, 'PLSMX2'], 'PLSMX2' => ['PLSM', 'D!', 6, null, 'PLSMX3'], 'PLSMX3' => ['PLSM', 'E!', 6, null, null],        'IONB1' => ['IONB', 'A!', 3, null, 'IONB2'], 'IONB2' => ['IONB', 'B!', 3, null, 'IONB1'],        'IONBX1' => ['IONB', 'C!', 4, null, 'IONBX2'], 'IONBX2' => ['IONB', 'D!', 4, null, 'IONBX3'], 'IONBX3' => ['IONB', 'E!', 4, null, null],        'PUFF1' => ['PUFF', 'A!', 4, null, 'PUFF2'], 'PUFF2' => ['PUFF', 'B', 4, null, 'PUFF3'], 'PUFF3' => ['PUFF', 'C', 4, null, 'PUFF4'], 'PUFF4' => ['PUFF', 'D', 4, null, null],        'BLUD1' => ['BLUD', 'A', 8, null, 'BLUD2'], 'BLUD2' => ['BLUD', 'B', 8, null, 'BLUD3'], 'BLUD3' => ['BLUD', 'C', 8, null, null],        // barrels explode        'BARL1' => ['BARL', 'A', 6, null, 'BARL2'], 'BARL2' => ['BARL', 'B', 6, null, 'BARL1'],        'BEXP1' => ['BEXP', 'A!', 5, null, 'BEXP2'], 'BEXP2' => ['BEXP', 'B!', 5, 'scream', 'BEXP3'], 'BEXP3' => ['BEXP', 'C!', 5, null, 'BEXP4'],        'BEXP4' => ['BEXP', 'D!', 10, 'explode', 'BEXP5'], 'BEXP5' => ['BEXP', 'E!', 10, null, null],        // items and decorations        'MEDK' => ['MEDK', 'A', -1, null, null], 'STIM' => ['STIM', 'A', -1, null, null],        'VIAL1' => ['VIAL', 'A', 6, null, 'VIAL2'], 'VIAL2' => ['VIAL', 'B!', 6, null, 'VIAL1'],        'ARM11' => ['ARM1', 'A', 6, null, 'ARM12'], 'ARM12' => ['ARM1', 'B!', 7, null, 'ARM11'],        'ARM21' => ['ARM2', 'A', 6, null, 'ARM22'], 'ARM22' => ['ARM2', 'B!', 6, null, 'ARM21'],        'SHRD1' => ['SHRD', 'A', 6, null, 'SHRD2'], 'SHRD2' => ['SHRD', 'B!', 6, null, 'SHRD1'],        'CLIP' => ['CLIP', 'A', -1, null, null], 'AMMO' => ['AMMO', 'A', -1, null, null], 'SHEL' => ['SHEL', 'A', -1, null, null],        'SBOX' => ['SBOX', 'A', -1, null, null], 'CELL' => ['CELL', 'A', -1, null, null],        'RKEY1' => ['RKEY', 'A', 10, null, 'RKEY2'], 'RKEY2' => ['RKEY', 'B!', 10, null, 'RKEY1'],        'BKEY1' => ['BKEY', 'A', 10, null, 'BKEY2'], 'BKEY2' => ['BKEY', 'B!', 10, null, 'BKEY1'],        'YKEY1' => ['YKEY', 'A', 10, null, 'YKEY2'], 'YKEY2' => ['YKEY', 'B!', 10, null, 'YKEY1'],        'ORB1' => ['ORB_', 'A!', 6, null, 'ORB2'], 'ORB2' => ['ORB_', 'B!', 6, null, 'ORB3'], 'ORB3' => ['ORB_', 'C!', 6, null, 'ORB4'], 'ORB4' => ['ORB_', 'D!', 6, null, 'ORB1'],        'SCAT' => ['SCAT', 'A', -1, null, null], 'RIVT' => ['RIVT', 'A', -1, null, null], 'IONG' => ['IONG', 'A', -1, null, null],        'LAMP' => ['LAMP', 'A!', -1, null, null], 'COLU' => ['COLU', 'A!', -1, null, null], 'TREE' => ['TREE', 'A', -1, null, null],        'SKUL' => ['SKUL', 'A', -1, null, null],    ];    /** Thing types (mobjinfo). Missing keys: see DEFAULT. */    public const DEFAULT = [        'spawn' => 'NULL', 'see' => null, 'pain' => null, 'melee' => null, 'missile' => null, 'death' => null,        'health' => 1000, 'reaction' => 8, 'painChance' => 0, 'speed' => 0.0, 'radius' => 20.0, 'height' => 16.0,        'mass' => 100, 'damage' => 0, 'flags' => 0, 'seeSound' => null, 'attackSound' => null, 'painSound' => null,        'deathSound' => null, 'activeSound' => null, 'drop' => null,    ];    public const TYPES = [        'player' => ['spawn' => 'PLAYER', 'health' => 100, 'radius' => 16, 'height' => 56, 'flags' => self::SOLID | self::SHOOTABLE | self::DROPOFF | self::PICKUP,            'painSound' => 'plpain', 'deathSound' => 'pldeath', 'painChance' => 255],        'husk' => ['spawn' => 'HUSK_STND', 'see' => 'HUSK_RUN1', 'pain' => 'HUSK_PAIN', 'missile' => 'HUSK_ATK1', 'death' => 'HUSK_DIE1',            'health' => 30, 'painChance' => 200, 'speed' => 8, 'radius' => 20, 'height' => 56, 'flags' => self::SOLID | self::SHOOTABLE | self::COUNTKILL,            'seeSound' => 'husksit', 'attackSound' => 'pistol', 'painSound' => 'huskpain', 'deathSound' => 'huskdie', 'activeSound' => 'huskact', 'drop' => 'clip'],        'gnasher' => ['spawn' => 'GNSH_STND', 'see' => 'GNSH_RUN1', 'pain' => 'GNSH_PAIN', 'melee' => 'GNSH_ATK1', 'death' => 'GNSH_DIE1',            'health' => 120, 'painChance' => 180, 'speed' => 10, 'radius' => 28, 'height' => 52, 'mass' => 400, 'flags' => self::SOLID | self::SHOOTABLE | self::COUNTKILL,            'seeSound' => 'gnshsit', 'attackSound' => 'gnshbite', 'painSound' => 'gnshpain', 'deathSound' => 'gnshdie', 'activeSound' => 'gnshact'],        'spitter' => ['spawn' => 'SPIT_STND', 'see' => 'SPIT_RUN1', 'pain' => 'SPIT_PAIN', 'melee' => 'SPIT_ATK1', 'missile' => 'SPIT_ATK1', 'death' => 'SPIT_DIE1',            'health' => 60, 'painChance' => 200, 'speed' => 8, 'radius' => 20, 'height' => 56, 'flags' => self::SOLID | self::SHOOTABLE | self::COUNTKILL,            'seeSound' => 'spitsit', 'painSound' => 'spitpain', 'deathSound' => 'spitdie', 'activeSound' => 'spitact'],        'warden' => ['spawn' => 'WARD_STND', 'see' => 'WARD_RUN1', 'pain' => 'WARD_PAIN', 'missile' => 'WARD_ATK1', 'death' => 'WARD_DIE1',            'health' => 700, 'painChance' => 40, 'speed' => 8, 'radius' => 40, 'height' => 100, 'mass' => 1000, 'reaction' => 8,            'flags' => self::SOLID | self::SHOOTABLE | self::COUNTKILL | self::BOSS,            'seeSound' => 'wardsit', 'painSound' => 'wardpain', 'deathSound' => 'warddie', 'activeSound' => 'wardact'],        'acidball' => ['spawn' => 'ACID1', 'death' => 'ACIDX1', 'speed' => 10, 'radius' => 6, 'height' => 8, 'damage' => 3,            'flags' => self::NOBLOOD | self::MISSILE | self::DROPOFF | self::NOGRAVITY, 'seeSound' => 'firesht', 'deathSound' => 'firexpl'],        'plasma' => ['spawn' => 'PLSM1', 'death' => 'PLSMX1', 'speed' => 15, 'radius' => 8, 'height' => 8, 'damage' => 6,            'flags' => self::NOBLOOD | self::MISSILE | self::DROPOFF | self::NOGRAVITY, 'seeSound' => 'plasma', 'deathSound' => 'firexpl'],        'ionball' => ['spawn' => 'IONB1', 'death' => 'IONBX1', 'speed' => 25, 'radius' => 13, 'height' => 8, 'damage' => 5,            'flags' => self::NOBLOOD | self::MISSILE | self::DROPOFF | self::NOGRAVITY, 'deathSound' => 'firexpl'],        'puff' => ['spawn' => 'PUFF1', 'flags' => self::NOBLOOD | self::NOGRAVITY, 'radius' => 1, 'height' => 1],        'blood' => ['spawn' => 'BLUD1', 'radius' => 1, 'height' => 1, 'flags' => self::NOBLOOD],        'barrel' => ['spawn' => 'BARL1', 'death' => 'BEXP1', 'health' => 20, 'radius' => 10, 'height' => 42,            'flags' => self::SOLID | self::SHOOTABLE | self::NOBLOOD, 'deathSound' => 'barrel'],        // items        'medkit' => ['spawn' => 'MEDK', 'flags' => self::SPECIAL], 'stim' => ['spawn' => 'STIM', 'flags' => self::SPECIAL],        'vial' => ['spawn' => 'VIAL1', 'flags' => self::SPECIAL | self::COUNTITEM],        'armor1' => ['spawn' => 'ARM11', 'flags' => self::SPECIAL], 'armor2' => ['spawn' => 'ARM21', 'flags' => self::SPECIAL],        'shard' => ['spawn' => 'SHRD1', 'flags' => self::SPECIAL | self::COUNTITEM],        'clip' => ['spawn' => 'CLIP', 'flags' => self::SPECIAL], 'ammobox' => ['spawn' => 'AMMO', 'flags' => self::SPECIAL],        'shells' => ['spawn' => 'SHEL', 'flags' => self::SPECIAL], 'shellbox' => ['spawn' => 'SBOX', 'flags' => self::SPECIAL],        'cells' => ['spawn' => 'CELL', 'flags' => self::SPECIAL],        'redkey' => ['spawn' => 'RKEY1', 'flags' => self::SPECIAL], 'bluekey' => ['spawn' => 'BKEY1', 'flags' => self::SPECIAL],        'yellowkey' => ['spawn' => 'YKEY1', 'flags' => self::SPECIAL],        'orb' => ['spawn' => 'ORB1', 'flags' => self::SPECIAL | self::COUNTITEM],        'scattergun' => ['spawn' => 'SCAT', 'flags' => self::SPECIAL], 'riveter' => ['spawn' => 'RIVT', 'flags' => self::SPECIAL],        'iongun' => ['spawn' => 'IONG', 'flags' => self::SPECIAL],        'lamp' => ['spawn' => 'LAMP', 'radius' => 16, 'flags' => self::SOLID], 'column' => ['spawn' => 'COLU', 'radius' => 16, 'flags' => self::SOLID],        'tree' => ['spawn' => 'TREE', 'radius' => 16, 'flags' => self::SOLID], 'skulls' => ['spawn' => 'SKUL'],    ];    /** The characters of the "things" layer of the level files. */    public const THING_LEGEND = [        '^' => ['type' => 'player', 'angle' => 90], '>' => ['type' => 'player', 'angle' => 0],        'v' => ['type' => 'player', 'angle' => 270], '<' => ['type' => 'player', 'angle' => 180],        'h' => ['type' => 'husk', 'angle' => 270], 'g' => ['type' => 'gnasher', 'angle' => 270],        's' => ['type' => 'spitter', 'angle' => 270], 'W' => ['type' => 'warden', 'angle' => 270],        'H' => ['type' => 'husk', 'angle' => 270, 'ambush' => true], 'G' => ['type' => 'gnasher', 'angle' => 270, 'ambush' => true],        'S' => ['type' => 'spitter', 'angle' => 270, 'ambush' => true],        '+' => ['type' => 'medkit'], 'm' => ['type' => 'stim'], 'o' => ['type' => 'vial'], 'a' => ['type' => 'armor1'],        'A' => ['type' => 'armor2'], '*' => ['type' => 'shard'], 'c' => ['type' => 'clip'], 'C' => ['type' => 'ammobox'],        'e' => ['type' => 'shells'], 'E' => ['type' => 'shellbox'], 'l' => ['type' => 'cells'],        'r' => ['type' => 'redkey'], 'b' => ['type' => 'bluekey'], 'y' => ['type' => 'yellowkey'], 'O' => ['type' => 'orb'],        '3' => ['type' => 'scattergun'], '4' => ['type' => 'riveter'], '5' => ['type' => 'iongun'],        'B' => ['type' => 'barrel'], 'L' => ['type' => 'lamp'], 'T' => ['type' => 'column'], 't' => ['type' => 'tree'], 'k' => ['type' => 'skulls'],    ];    public static function type(string $name): array    {        return (self::TYPES[$name] ?? throw new \InvalidArgumentException("Unknown thing $name")) + self::DEFAULT;    }}