<?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; }}