/* Emacs style mode select -*- C++ -*- *----------------------------------------------------------------------------- * * * PrBoom a Doom port merged with LxDoom and LSDLDoom * based on BOOM, a modified and improved DOOM engine * Copyright (C) 1999 by * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman * Copyright (C) 1999-2000 by * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * DESCRIPTION: * Dehacked file support * New for the TeamTNT "Boom" engine * * Author: Ty Halderman, TeamTNT * *--------------------------------------------------------------------*/ // killough 5/2/98: fixed headers, removed rendunant external declarations: #include "doomdef.h" #include "doomtype.h" #include "doomstat.h" #include "sounds.h" #include "info.h" #include "m_cheat.h" #include "p_inter.h" #include "g_game.h" #include "d_think.h" #include "w_wad.h" #include "sscanf.h" #include "rockmacros.h" #define TRUE 1 #define FALSE 0 char* strlwr(char* str) { char* p; for (p=str; *p; p++) *p = tolower(*p); return str; } // killough 10/98: new functions, to allow processing DEH files in-memory // (e.g. from wads) typedef struct { const byte *inp; // Pointer to string size_t size; // Bytes remaining in string int fd; // Current file descriptor } DEHFILE; // killough 10/98: emulate IO whether input really comes from a file or not char *dehfgets(char *buf, size_t n, DEHFILE *fp) { char *p; if (fp->fd >= 0) { // If this is a real file, int r = read_line(fp->fd, buf, (unsigned)n); // return regular line read return (r > 0) ? buf : NULL; } n = MIN(fp->size, n); if (n == 0 || *fp->inp == '\0') // If no more characters return NULL; p = buf; while (--n > 0) { unsigned char c = *fp->inp++; fp->size--; if ( c == '\n' ) break; if ( c != '\r' ) *p++ = c; } *p = '\0'; return buf; // Return buffer pointer } int dehfeof(DEHFILE *fp) { if (fp->fd >= 0) { off_t size = filesize(fp->fd); off_t offset = lseek(fp->fd, 0, SEEK_CUR); return (size <= 0 || offset < 0 || offset >= size) ? 1 : 0; } return (fp->size == 0 || *fp->inp == '\0') ? 1 : 0; } int dehfgetc(DEHFILE *fp) { if (fp->fd >= 0) { unsigned char c; if (read(fp->fd, &c, 1) == 1) return (unsigned int)c; } else if (fp->size > 0) { return fp->size--, *fp->inp++; } return EOF; } // variables used in other routines boolean deh_pars = FALSE; // in wi_stuff to allow pars in modified games // #include "d_deh.h" -- we don't do that here but we declare the // variables. This externalizes everything that there is a string // set for in the language files. See d_deh.h for detailed comments, // original English values etc. These are set to the macro values, // which are set by D_ENGLSH.H or D_FRENCH.H(etc). BEX files are a // better way of changing these strings globally by language. // ==================================================================== // Any of these can be changed using the bex extensions #include "dstrings.h" // to get the initial values /* cph - const's * - removed redundant "can't XXX in a netgame" strings. */ const char *s_D_DEVSTR = D_DEVSTR; const char *s_D_CDROM = D_CDROM; const char *s_PRESSKEY = PRESSKEY; const char *s_PRESSYN = PRESSYN; const char *s_QUITMSG = QUITMSG; const char *s_QSAVESPOT = QSAVESPOT; // PRESSKEY; const char *s_SAVEDEAD = SAVEDEAD; // PRESSKEY; // remove duplicate y/n const char *s_QSPROMPT = QSPROMPT; // PRESSYN; const char *s_QLPROMPT = QLPROMPT; // PRESSYN; const char *s_NEWGAME = NEWGAME; // PRESSKEY; const char *s_RESTARTLEVEL= RESTARTLEVEL; // PRESSYN; const char *s_NIGHTMARE = NIGHTMARE; // PRESSYN; const char *s_SWSTRING = SWSTRING; // PRESSKEY; const char *s_MSGOFF = MSGOFF; const char *s_MSGON = MSGON; const char *s_NETEND = NETEND; // PRESSKEY; const char *s_ENDGAME = ENDGAME; // PRESSYN; // killough 4/4/98: end const char *s_DOSY = DOSY; const char *s_DETAILHI = DETAILHI; const char *s_DETAILLO = DETAILLO; const char *s_GAMMALVL0 = GAMMALVL0; const char *s_GAMMALVL1 = GAMMALVL1; const char *s_GAMMALVL2 = GAMMALVL2; const char *s_GAMMALVL3 = GAMMALVL3; const char *s_GAMMALVL4 = GAMMALVL4; const char *s_EMPTYSTRING = EMPTYSTRING; const char *s_GOTARMOR = GOTARMOR; const char *s_GOTMEGA = GOTMEGA; const char *s_GOTHTHBONUS = GOTHTHBONUS; const char *s_GOTARMBONUS = GOTARMBONUS; const char *s_GOTSTIM = GOTSTIM; const char *s_GOTMEDINEED = GOTMEDINEED; const char *s_GOTMEDIKIT = GOTMEDIKIT; const char *s_GOTSUPER = GOTSUPER; const char *s_GOTBLUECARD = GOTBLUECARD; const char *s_GOTYELWCARD = GOTYELWCARD; const char *s_GOTREDCARD = GOTREDCARD; const char *s_GOTBLUESKUL = GOTBLUESKUL; const char *s_GOTYELWSKUL = GOTYELWSKUL; const char *s_GOTREDSKULL = GOTREDSKULL; const char *s_GOTINVUL = GOTINVUL; const char *s_GOTBERSERK = GOTBERSERK; const char *s_GOTINVIS = GOTINVIS; const char *s_GOTSUIT = GOTSUIT; const char *s_GOTMAP = GOTMAP; const char *s_GOTVISOR = GOTVISOR; const char *s_GOTMSPHERE = GOTMSPHERE; const char *s_GOTCLIP = GOTCLIP; const char *s_GOTCLIPBOX = GOTCLIPBOX; const char *s_GOTROCKET = GOTROCKET; const char *s_GOTROCKBOX = GOTROCKBOX; const char *s_GOTCELL = GOTCELL; const char *s_GOTCELLBOX = GOTCELLBOX; const char *s_GOTSHELLS = GOTSHELLS; const char *s_GOTSHELLBOX = GOTSHELLBOX; const char *s_GOTBACKPACK = GOTBACKPACK; const char *s_GOTBFG9000 = GOTBFG9000; const char *s_GOTCHAINGUN = GOTCHAINGUN; const char *s_GOTCHAINSAW = GOTCHAINSAW; const char *s_GOTLAUNCHER = GOTLAUNCHER; const char *s_GOTPLASMA = GOTPLASMA; const char *s_GOTSHOTGUN = GOTSHOTGUN; const char *s_GOTSHOTGUN2 = GOTSHOTGUN2; const char *s_PD_BLUEO = PD_BLUEO; const char *s_PD_REDO = PD_REDO; const char *s_PD_YELLOWO = PD_YELLOWO; const char *s_PD_BLUEK = PD_BLUEK; const char *s_PD_REDK = PD_REDK; const char *s_PD_YELLOWK = PD_YELLOWK; const char *s_PD_BLUEC = PD_BLUEC; const char *s_PD_REDC = PD_REDC; const char *s_PD_YELLOWC = PD_YELLOWC; const char *s_PD_BLUES = PD_BLUES; const char *s_PD_REDS = PD_REDS; const char *s_PD_YELLOWS = PD_YELLOWS; const char *s_PD_ANY = PD_ANY; const char *s_PD_ALL3 = PD_ALL3; const char *s_PD_ALL6 = PD_ALL6; const char *s_GGSAVED = GGSAVED; const char *s_HUSTR_MSGU = HUSTR_MSGU; const char *s_HUSTR_E1M1 = HUSTR_E1M1; const char *s_HUSTR_E1M2 = HUSTR_E1M2; const char *s_HUSTR_E1M3 = HUSTR_E1M3; const char *s_HUSTR_E1M4 = HUSTR_E1M4; const char *s_HUSTR_E1M5 = HUSTR_E1M5; const char *s_HUSTR_E1M6 = HUSTR_E1M6; const char *s_HUSTR_E1M7 = HUSTR_E1M7; const char *s_HUSTR_E1M8 = HUSTR_E1M8; const char *s_HUSTR_E1M9 = HUSTR_E1M9; const char *s_HUSTR_E2M1 = HUSTR_E2M1; const char *s_HUSTR_E2M2 = HUSTR_E2M2; const char *s_HUSTR_E2M3 = HUSTR_E2M3; const char *s_HUSTR_E2M4 = HUSTR_E2M4; const char *s_HUSTR_E2M5 = HUSTR_E2M5; const char *s_HUSTR_E2M6 = HUSTR_E2M6; const char *s_HUSTR_E2M7 = HUSTR_E2M7; const char *s_HUSTR_E2M8 = HUSTR_E2M8; const char *s_HUSTR_E2M9 = HUSTR_E2M9; const char *s_HUSTR_E3M1 = HUSTR_E3M1; const char *s_HUSTR_E3M2 = HUSTR_E3M2; const char *s_HUSTR_E3M3 = HUSTR_E3M3; const char *s_HUSTR_E3M4 = HUSTR_E3M4; const char *s_HUSTR_E3M5 = HUSTR_E3M5; const char *s_HUSTR_E3M6 = HUSTR_E3M6; const char *s_HUSTR_E3M7 = HUSTR_E3M7; const char *s_HUSTR_E3M8 = HUSTR_E3M8; const char *s_HUSTR_E3M9 = HUSTR_E3M9; const char *s_HUSTR_E4M1 = HUSTR_E4M1; const char *s_HUSTR_E4M2 = HUSTR_E4M2; const char *s_HUSTR_E4M3 = HUSTR_E4M3; const char *s_HUSTR_E4M4 = HUSTR_E4M4; const char *s_HUSTR_E4M5 = HUSTR_E4M5; const char *s_HUSTR_E4M6 = HUSTR_E4M6; const char *s_HUSTR_E4M7 = HUSTR_E4M7; const char *s_HUSTR_E4M8 = HUSTR_E4M8; const char *s_HUSTR_E4M9 = HUSTR_E4M9; const char *s_HUSTR_1 = HUSTR_1; const char *s_HUSTR_2 = HUSTR_2; const char *s_HUSTR_3 = HUSTR_3; const char *s_HUSTR_4 = HUSTR_4; const char *s_HUSTR_5 = HUSTR_5; const char *s_HUSTR_6 = HUSTR_6; const char *s_HUSTR_7 = HUSTR_7; const char *s_HUSTR_8 = HUSTR_8; const char *s_HUSTR_9 = HUSTR_9; const char *s_HUSTR_10 = HUSTR_10; const char *s_HUSTR_11 = HUSTR_11; const char *s_HUSTR_12 = HUSTR_12; const char *s_HUSTR_13 = HUSTR_13; const char *s_HUSTR_14 = HUSTR_14; const char *s_HUSTR_15 = HUSTR_15; const char *s_HUSTR_16 = HUSTR_16; const char *s_HUSTR_17 = HUSTR_17; const char *s_HUSTR_18 = HUSTR_18; const char *s_HUSTR_19 = HUSTR_19; const char *s_HUSTR_20 = HUSTR_20; const char *s_HUSTR_21 = HUSTR_21; const char *s_HUSTR_22 = HUSTR_22; const char *s_HUSTR_23 = HUSTR_23; const char *s_HUSTR_24 = HUSTR_24; const char *s_HUSTR_25 = HUSTR_25; const char *s_HUSTR_26 = HUSTR_26; const char *s_HUSTR_27 = HUSTR_27; const char *s_HUSTR_28 = HUSTR_28; const char *s_HUSTR_29 = HUSTR_29; const char *s_HUSTR_30 = HUSTR_30; const char *s_HUSTR_31 = HUSTR_31; const char *s_HUSTR_32 = HUSTR_32; const char *s_PHUSTR_1 = PHUSTR_1; const char *s_PHUSTR_2 = PHUSTR_2; const char *s_PHUSTR_3 = PHUSTR_3; const char *s_PHUSTR_4 = PHUSTR_4; const char *s_PHUSTR_5 = PHUSTR_5; const char *s_PHUSTR_6 = PHUSTR_6; const char *s_PHUSTR_7 = PHUSTR_7; const char *s_PHUSTR_8 = PHUSTR_8; const char *s_PHUSTR_9 = PHUSTR_9; const char *s_PHUSTR_10 = PHUSTR_10; const char *s_PHUSTR_11 = PHUSTR_11; const char *s_PHUSTR_12 = PHUSTR_12; const char *s_PHUSTR_13 = PHUSTR_13; const char *s_PHUSTR_14 = PHUSTR_14; const char *s_PHUSTR_15 = PHUSTR_15; const char *s_PHUSTR_16 = PHUSTR_16; const char *s_PHUSTR_17 = PHUSTR_17; const char *s_PHUSTR_18 = PHUSTR_18; const char *s_PHUSTR_19 = PHUSTR_19; const char *s_PHUSTR_20 = PHUSTR_20; const char *s_PHUSTR_21 = PHUSTR_21; const char *s_PHUSTR_22 = PHUSTR_22; const char *s_PHUSTR_23 = PHUSTR_23; const char *s_PHUSTR_24 = PHUSTR_24; const char *s_PHUSTR_25 = PHUSTR_25; const char *s_PHUSTR_26 = PHUSTR_26; const char *s_PHUSTR_27 = PHUSTR_27; const char *s_PHUSTR_28 = PHUSTR_28; const char *s_PHUSTR_29 = PHUSTR_29; const char *s_PHUSTR_30 = PHUSTR_30; const char *s_PHUSTR_31 = PHUSTR_31; const char *s_PHUSTR_32 = PHUSTR_32; const char *s_THUSTR_1 = THUSTR_1; const char *s_THUSTR_2 = THUSTR_2; const char *s_THUSTR_3 = THUSTR_3; const char *s_THUSTR_4 = THUSTR_4; const char *s_THUSTR_5 = THUSTR_5; const char *s_THUSTR_6 = THUSTR_6; const char *s_THUSTR_7 = THUSTR_7; const char *s_THUSTR_8 = THUSTR_8; const char *s_THUSTR_9 = THUSTR_9; const char *s_THUSTR_10 = THUSTR_10; const char *s_THUSTR_11 = THUSTR_11; const char *s_THUSTR_12 = THUSTR_12; const char *s_THUSTR_13 = THUSTR_13; const char *s_THUSTR_14 = THUSTR_14; const char *s_THUSTR_15 = THUSTR_15; const char *s_THUSTR_16 = THUSTR_16; const char *s_THUSTR_17 = THUSTR_17; const char *s_THUSTR_18 = THUSTR_18; const char *s_THUSTR_19 = THUSTR_19; const char *s_THUSTR_20 = THUSTR_20; const char *s_THUSTR_21 = THUSTR_21; const char *s_THUSTR_22 = THUSTR_22; const char *s_THUSTR_23 = THUSTR_23; const char *s_THUSTR_24 = THUSTR_24; const char *s_THUSTR_25 = THUSTR_25; const char *s_THUSTR_26 = THUSTR_26; const char *s_THUSTR_27 = THUSTR_27; const char *s_THUSTR_28 = THUSTR_28; const char *s_THUSTR_29 = THUSTR_29; const char *s_THUSTR_30 = THUSTR_30; const char *s_THUSTR_31 = THUSTR_31; const char *s_THUSTR_32 = THUSTR_32; const char *s_HUSTR_CHATMACRO1 = HUSTR_CHATMACRO1; const char *s_HUSTR_CHATMACRO2 = HUSTR_CHATMACRO2; const char *s_HUSTR_CHATMACRO3 = HUSTR_CHATMACRO3; const char *s_HUSTR_CHATMACRO4 = HUSTR_CHATMACRO4; const char *s_HUSTR_CHATMACRO5 = HUSTR_CHATMACRO5; const char *s_HUSTR_CHATMACRO6 = HUSTR_CHATMACRO6; const char *s_HUSTR_CHATMACRO7 = HUSTR_CHATMACRO7; const char *s_HUSTR_CHATMACRO8 = HUSTR_CHATMACRO8; const char *s_HUSTR_CHATMACRO9 = HUSTR_CHATMACRO9; const char *s_HUSTR_CHATMACRO0 = HUSTR_CHATMACRO0; const char *s_HUSTR_TALKTOSELF1 = HUSTR_TALKTOSELF1; const char *s_HUSTR_TALKTOSELF2 = HUSTR_TALKTOSELF2; const char *s_HUSTR_TALKTOSELF3 = HUSTR_TALKTOSELF3; const char *s_HUSTR_TALKTOSELF4 = HUSTR_TALKTOSELF4; const char *s_HUSTR_TALKTOSELF5 = HUSTR_TALKTOSELF5; const char *s_HUSTR_MESSAGESENT = HUSTR_MESSAGESENT; const char *s_HUSTR_PLRGREEN = HUSTR_PLRGREEN; const char *s_HUSTR_PLRINDIGO = HUSTR_PLRINDIGO; const char *s_HUSTR_PLRBROWN = HUSTR_PLRBROWN; const char *s_HUSTR_PLRRED = HUSTR_PLRRED; //char sc_HUSTR_KEYGREEN = HUSTR_KEYGREEN; //char sc_HUSTR_KEYINDIGO = HUSTR_KEYINDIGO; //char sc_HUSTR_KEYBROWN = HUSTR_KEYBROWN; //char sc_HUSTR_KEYRED = HUSTR_KEYRED; const char *s_AMSTR_FOLLOWON = AMSTR_FOLLOWON; const char *s_AMSTR_FOLLOWOFF = AMSTR_FOLLOWOFF; const char *s_AMSTR_GRIDON = AMSTR_GRIDON; const char *s_AMSTR_GRIDOFF = AMSTR_GRIDOFF; const char *s_AMSTR_MARKEDSPOT = AMSTR_MARKEDSPOT; const char *s_AMSTR_MARKSCLEARED = AMSTR_MARKSCLEARED; // CPhipps - automap rotate & overlay const char* s_AMSTR_ROTATEON = AMSTR_ROTATEON; const char* s_AMSTR_ROTATEOFF = AMSTR_ROTATEOFF; const char* s_AMSTR_OVERLAYON = AMSTR_OVERLAYON; const char* s_AMSTR_OVERLAYOFF = AMSTR_OVERLAYOFF; const char *s_STSTR_MUS = STSTR_MUS; const char *s_STSTR_NOMUS = STSTR_NOMUS; const char *s_STSTR_DQDON = STSTR_DQDON; const char *s_STSTR_DQDOFF = STSTR_DQDOFF; const char *s_STSTR_KFAADDED = STSTR_KFAADDED; const char *s_STSTR_FAADDED = STSTR_FAADDED; const char *s_STSTR_NCON = STSTR_NCON; const char *s_STSTR_NCOFF = STSTR_NCOFF; const char *s_STSTR_BEHOLD = STSTR_BEHOLD; const char *s_STSTR_BEHOLDX = STSTR_BEHOLDX; const char *s_STSTR_CHOPPERS = STSTR_CHOPPERS; const char *s_STSTR_CLEV = STSTR_CLEV; const char *s_STSTR_COMPON = STSTR_COMPON; const char *s_STSTR_COMPOFF = STSTR_COMPOFF; const char *s_E1TEXT = E1TEXT; const char *s_E2TEXT = E2TEXT; const char *s_E3TEXT = E3TEXT; const char *s_E4TEXT = E4TEXT; const char *s_C1TEXT = C1TEXT; const char *s_C2TEXT = C2TEXT; const char *s_C3TEXT = C3TEXT; const char *s_C4TEXT = C4TEXT; const char *s_C5TEXT = C5TEXT; const char *s_C6TEXT = C6TEXT; const char *s_P1TEXT = P1TEXT; const char *s_P2TEXT = P2TEXT; const char *s_P3TEXT = P3TEXT; const char *s_P4TEXT = P4TEXT; const char *s_P5TEXT = P5TEXT; const char *s_P6TEXT = P6TEXT; const char *s_T1TEXT = T1TEXT; const char *s_T2TEXT = T2TEXT; const char *s_T3TEXT = T3TEXT; const char *s_T4TEXT = T4TEXT; const char *s_T5TEXT = T5TEXT; const char *s_T6TEXT = T6TEXT; const char *s_CC_ZOMBIE = CC_ZOMBIE; const char *s_CC_SHOTGUN = CC_SHOTGUN; const char *s_CC_HEAVY = CC_HEAVY; const char *s_CC_IMP = CC_IMP; const char *s_CC_DEMON = CC_DEMON; const char *s_CC_LOST = CC_LOST; const char *s_CC_CACO = CC_CACO; const char *s_CC_HELL = CC_HELL; const char *s_CC_BARON = CC_BARON; const char *s_CC_ARACH = CC_ARACH; const char *s_CC_PAIN = CC_PAIN; const char *s_CC_REVEN = CC_REVEN; const char *s_CC_MANCU = CC_MANCU; const char *s_CC_ARCH = CC_ARCH; const char *s_CC_SPIDER = CC_SPIDER; const char *s_CC_CYBER = CC_CYBER; const char *s_CC_HERO = CC_HERO; // Ty 03/30/98 - new substitutions for background textures // during int screens const char *bgflatE1 = "FLOOR4_8"; // end of DOOM Episode 1 const char *bgflatE2 = "SFLR6_1"; // end of DOOM Episode 2 const char *bgflatE3 = "MFLR8_4"; // end of DOOM Episode 3 const char *bgflatE4 = "MFLR8_3"; // end of DOOM Episode 4 const char *bgflat06 = "SLIME16"; // DOOM2 after MAP06 const char *bgflat11 = "RROCK14"; // DOOM2 after MAP11 const char *bgflat20 = "RROCK07"; // DOOM2 after MAP20 const char *bgflat30 = "RROCK17"; // DOOM2 after MAP30 const char *bgflat15 = "RROCK13"; // DOOM2 going MAP15 to MAP31 const char *bgflat31 = "RROCK19"; // DOOM2 going MAP31 to MAP32 const char *bgcastcall = "BOSSBACK"; // Panel behind cast call const char *startup1 = ""; // blank lines are default and are not printed const char *startup2 = ""; const char *startup3 = ""; const char *startup4 = ""; const char *startup5 = ""; /* Ty 05/03/98 - externalized * cph - updated for prboom */ const char *savegamename = "prbmsav"; // end d_deh.h variable declarations // ==================================================================== // Do this for a lookup--the pointer (loaded above) is cross-referenced // to a string key that is the same as the define above. We will use // strdups to set these new values that we read from the file, orphaning // the original value set above. // CPhipps - make strings pointed to const typedef struct { const char **ppstr; // doubly indirect pointer to string const char *lookup; // pointer to lookup string name } deh_strs; /* CPhipps - const, static * - removed redundant "Can't XXX in a netgame" strings */ static const deh_strs deh_strlookup[] = { {&s_D_DEVSTR,"D_DEVSTR"}, {&s_D_CDROM,"D_CDROM"}, {&s_PRESSKEY,"PRESSKEY"}, {&s_PRESSYN,"PRESSYN"}, {&s_QUITMSG,"QUITMSG"}, {&s_QSAVESPOT,"QSAVESPOT"}, {&s_SAVEDEAD,"SAVEDEAD"}, /* cph - disabled to prevent format string attacks in WAD files {&s_QSPROMPT,"QSPROMPT"}, {&s_QLPROMPT,"QLPROMPT"},*/ {&s_NEWGAME,"NEWGAME"}, {&s_RESTARTLEVEL,"RESTARTLEVEL"}, {&s_NIGHTMARE,"NIGHTMARE"}, {&s_SWSTRING,"SWSTRING"}, {&s_MSGOFF,"MSGOFF"}, {&s_MSGON,"MSGON"}, {&s_NETEND,"NETEND"}, {&s_ENDGAME,"ENDGAME"}, {&s_DOSY,"DOSY"}, {&s_DETAILHI,"DETAILHI"}, {&s_DETAILLO,"DETAILLO"}, {&s_GAMMALVL0,"GAMMALVL0"}, {&s_GAMMALVL1,"GAMMALVL1"}, {&s_GAMMALVL2,"GAMMALVL2"}, {&s_GAMMALVL3,"GAMMALVL3"}, {&s_GAMMALVL4,"GAMMALVL4"}, {&s_EMPTYSTRING,"EMPTYSTRING"}, {&s_GOTARMOR,"GOTARMOR"}, {&s_GOTMEGA,"GOTMEGA"}, {&s_GOTHTHBONUS,"GOTHTHBONUS"}, {&s_GOTARMBONUS,"GOTARMBONUS"}, {&s_GOTSTIM,"GOTSTIM"}, {&s_GOTMEDINEED,"GOTMEDINEED"}, {&s_GOTMEDIKIT,"GOTMEDIKIT"}, {&s_GOTSUPER,"GOTSUPER"}, {&s_GOTBLUECARD,"GOTBLUECARD"}, {&s_GOTYELWCARD,"GOTYELWCARD"}, {&s_GOTREDCARD,"GOTREDCARD"}, {&s_GOTBLUESKUL,"GOTBLUESKUL"}, {&s_GOTYELWSKUL,"GOTYELWSKUL"}, {&s_GOTREDSKULL,"GOTREDSKULL"}, {&s_GOTINVUL,"GOTINVUL"}, {&s_GOTBERSERK,"GOTBERSERK"}, {&s_GOTINVIS,"GOTINVIS"}, {&s_GOTSUIT,"GOTSUIT"}, {&s_GOTMAP,"GOTMAP"}, {&s_GOTVISOR,"GOTVISOR"}, {&s_GOTMSPHERE,"GOTMSPHERE"}, {&s_GOTCLIP,"GOTCLIP"}, {&s_GOTCLIPBOX,"GOTCLIPBOX"}, {&s_GOTROCKET,"GOTROCKET"}, {&s_GOTROCKBOX,"GOTROCKBOX"}, {&s_GOTCELL,"GOTCELL"}, {&s_GOTCELLBOX,"GOTCELLBOX"}, {&s_GOTSHELLS,"GOTSHELLS"}, {&s_GOTSHELLBOX,"GOTSHELLBOX"}, {&s_GOTBACKPACK,"GOTBACKPACK"}, {&s_GOTBFG9000,"GOTBFG9000"}, {&s_GOTCHAINGUN,"GOTCHAINGUN"}, {&s_GOTCHAINSAW,"GOTCHAINSAW"}, {&s_GOTLAUNCHER,"GOTLAUNCHER"}, {&s_GOTPLASMA,"GOTPLASMA"}, {&s_GOTSHOTGUN,"GOTSHOTGUN"}, {&s_GOTSHOTGUN2,"GOTSHOTGUN2"}, {&s_PD_BLUEO,"PD_BLUEO"}, {&s_PD_REDO,"PD_REDO"}, {&s_PD_YELLOWO,"PD_YELLOWO"}, {&s_PD_BLUEK,"PD_BLUEK"}, {&s_PD_REDK,"PD_REDK"}, {&s_PD_YELLOWK,"PD_YELLOWK"}, {&s_PD_BLUEC,"PD_BLUEC"}, {&s_PD_REDC,"PD_REDC"}, {&s_PD_YELLOWC,"PD_YELLOWC"}, {&s_PD_BLUES,"PD_BLUES"}, {&s_PD_REDS,"PD_REDS"}, {&s_PD_YELLOWS,"PD_YELLOWS"}, {&s_PD_ANY,"PD_ANY"}, {&s_PD_ALL3,"PD_ALL3"}, {&s_PD_ALL6,"PD_ALL6"}, {&s_GGSAVED,"GGSAVED"}, {&s_HUSTR_MSGU,"HUSTR_MSGU"}, {&s_HUSTR_E1M1,"HUSTR_E1M1"}, {&s_HUSTR_E1M2,"HUSTR_E1M2"}, {&s_HUSTR_E1M3,"HUSTR_E1M3"}, {&s_HUSTR_E1M4,"HUSTR_E1M4"}, {&s_HUSTR_E1M5,"HUSTR_E1M5"}, {&s_HUSTR_E1M6,"HUSTR_E1M6"}, {&s_HUSTR_E1M7,"HUSTR_E1M7"}, {&s_HUSTR_E1M8,"HUSTR_E1M8"}, {&s_HUSTR_E1M9,"HUSTR_E1M9"}, {&s_HUSTR_E2M1,"HUSTR_E2M1"}, {&s_HUSTR_E2M2,"HUSTR_E2M2"}, {&s_HUSTR_E2M3,"HUSTR_E2M3"}, {&s_HUSTR_E2M4,"HUSTR_E2M4"}, {&s_HUSTR_E2M5,"HUSTR_E2M5"}, {&s_HUSTR_E2M6,"HUSTR_E2M6"}, {&s_HUSTR_E2M7,"HUSTR_E2M7"}, {&s_HUSTR_E2M8,"HUSTR_E2M8"}, {&s_HUSTR_E2M9,"HUSTR_E2M9"}, {&s_HUSTR_E3M1,"HUSTR_E3M1"}, {&s_HUSTR_E3M2,"HUSTR_E3M2"}, {&s_HUSTR_E3M3,"HUSTR_E3M3"}, {&s_HUSTR_E3M4,"HUSTR_E3M4"}, {&s_HUSTR_E3M5,"HUSTR_E3M5"}, {&s_HUSTR_E3M6,"HUSTR_E3M6"}, {&s_HUSTR_E3M7,"HUSTR_E3M7"}, {&s_HUSTR_E3M8,"HUSTR_E3M8"}, {&s_HUSTR_E3M9,"HUSTR_E3M9"}, {&s_HUSTR_E4M1,"HUSTR_E4M1"}, {&s_HUSTR_E4M2,"HUSTR_E4M2"}, {&s_HUSTR_E4M3,"HUSTR_E4M3"}, {&s_HUSTR_E4M4,"HUSTR_E4M4"}, {&s_HUSTR_E4M5,"HUSTR_E4M5"}, {&s_HUSTR_E4M6,"HUSTR_E4M6"}, {&s_HUSTR_E4M7,"HUSTR_E4M7"}, {&s_HUSTR_E4M8,"HUSTR_E4M8"}, {&s_HUSTR_E4M9,"HUSTR_E4M9"}, {&s_HUSTR_1,"HUSTR_1"}, {&s_HUSTR_2,"HUSTR_2"}, {&s_HUSTR_3,"HUSTR_3"}, {&s_HUSTR_4,"HUSTR_4"}, {&s_HUSTR_5,"HUSTR_5"}, {&s_HUSTR_6,"HUSTR_6"}, {&s_HUSTR_7,"HUSTR_7"}, {&s_HUSTR_8,"HUSTR_8"}, {&s_HUSTR_9,"HUSTR_9"}, {&s_HUSTR_10,"HUSTR_10"}, {&s_HUSTR_11,"HUSTR_11"}, {&s_HUSTR_12,"HUSTR_12"}, {&s_HUSTR_13,"HUSTR_13"}, {&s_HUSTR_14,"HUSTR_14"}, {&s_HUSTR_15,"HUSTR_15"}, {&s_HUSTR_16,"HUSTR_16"}, {&s_HUSTR_17,"HUSTR_17"}, {&s_HUSTR_18,"HUSTR_18"}, {&s_HUSTR_19,"HUSTR_19"}, {&s_HUSTR_20,"HUSTR_20"}, {&s_HUSTR_21,"HUSTR_21"}, {&s_HUSTR_22,"HUSTR_22"}, {&s_HUSTR_23,"HUSTR_23"}, {&s_HUSTR_24,"HUSTR_24"}, {&s_HUSTR_25,"HUSTR_25"}, {&s_HUSTR_26,"HUSTR_26"}, {&s_HUSTR_27,"HUSTR_27"}, {&s_HUSTR_28,"HUSTR_28"}, {&s_HUSTR_29,"HUSTR_29"}, {&s_HUSTR_30,"HUSTR_30"}, {&s_HUSTR_31,"HUSTR_31"}, {&s_HUSTR_32,"HUSTR_32"}, {&s_PHUSTR_1,"PHUSTR_1"}, {&s_PHUSTR_2,"PHUSTR_2"}, {&s_PHUSTR_3,"PHUSTR_3"}, {&s_PHUSTR_4,"PHUSTR_4"}, {&s_PHUSTR_5,"PHUSTR_5"}, {&s_PHUSTR_6,"PHUSTR_6"}, {&s_PHUSTR_7,"PHUSTR_7"}, {&s_PHUSTR_8,"PHUSTR_8"}, {&s_PHUSTR_9,"PHUSTR_9"}, {&s_PHUSTR_10,"PHUSTR_10"}, {&s_PHUSTR_11,"PHUSTR_11"}, {&s_PHUSTR_12,"PHUSTR_12"}, {&s_PHUSTR_13,"PHUSTR_13"}, {&s_PHUSTR_14,"PHUSTR_14"}, {&s_PHUSTR_15,"PHUSTR_15"}, {&s_PHUSTR_16,"PHUSTR_16"}, {&s_PHUSTR_17,"PHUSTR_17"}, {&s_PHUSTR_18,"PHUSTR_18"}, {&s_PHUSTR_19,"PHUSTR_19"}, {&s_PHUSTR_20,"PHUSTR_20"}, {&s_PHUSTR_21,"PHUSTR_21"}, {&s_PHUSTR_22,"PHUSTR_22"}, {&s_PHUSTR_23,"PHUSTR_23"}, {&s_PHUSTR_24,"PHUSTR_24"}, {&s_PHUSTR_25,"PHUSTR_25"}, {&s_PHUSTR_26,"PHUSTR_26"}, {&s_PHUSTR_27,"PHUSTR_27"}, {&s_PHUSTR_28,"PHUSTR_28"}, {&s_PHUSTR_29,"PHUSTR_29"}, {&s_PHUSTR_30,"PHUSTR_30"}, {&s_PHUSTR_31,"PHUSTR_31"}, {&s_PHUSTR_32,"PHUSTR_32"}, {&s_THUSTR_1,"THUSTR_1"}, {&s_THUSTR_2,"THUSTR_2"}, {&s_THUSTR_3,"THUSTR_3"}, {&s_THUSTR_4,"THUSTR_4"}, {&s_THUSTR_5,"THUSTR_5"}, {&s_THUSTR_6,"THUSTR_6"}, {&s_THUSTR_7,"THUSTR_7"}, {&s_THUSTR_8,"THUSTR_8"}, {&s_THUSTR_9,"THUSTR_9"}, {&s_THUSTR_10,"THUSTR_10"}, {&s_THUSTR_11,"THUSTR_11"}, {&s_THUSTR_12,"THUSTR_12"}, {&s_THUSTR_13,"THUSTR_13"}, {&s_THUSTR_14,"THUSTR_14"}, {&s_THUSTR_15,"THUSTR_15"}, {&s_THUSTR_16,"THUSTR_16"}, {&s_THUSTR_17,"THUSTR_17"}, {&s_THUSTR_18,"THUSTR_18"}, {&s_THUSTR_19,"THUSTR_19"}, {&s_THUSTR_20,"THUSTR_20"}, {&s_THUSTR_21,"THUSTR_21"}, {&s_THUSTR_22,"THUSTR_22"}, {&s_THUSTR_23,"THUSTR_23"}, {&s_THUSTR_24,"THUSTR_24"}, {&s_THUSTR_25,"THUSTR_25"}, {&s_THUSTR_26,"THUSTR_26"}, {&s_THUSTR_27,"THUSTR_27"}, {&s_THUSTR_28,"THUSTR_28"}, {&s_THUSTR_29,"THUSTR_29"}, {&s_THUSTR_30,"THUSTR_30"}, {&s_THUSTR_31,"THUSTR_31"}, {&s_THUSTR_32,"THUSTR_32"}, {&s_HUSTR_CHATMACRO1,"HUSTR_CHATMACRO1"}, {&s_HUSTR_CHATMACRO2,"HUSTR_CHATMACRO2"}, {&s_HUSTR_CHATMACRO3,"HUSTR_CHATMACRO3"}, {&s_HUSTR_CHATMACRO4,"HUSTR_CHATMACRO4"}, {&s_HUSTR_CHATMACRO5,"HUSTR_CHATMACRO5"}, {&s_HUSTR_CHATMACRO6,"HUSTR_CHATMACRO6"}, {&s_HUSTR_CHATMACRO7,"HUSTR_CHATMACRO7"}, {&s_HUSTR_CHATMACRO8,"HUSTR_CHATMACRO8"}, {&s_HUSTR_CHATMACRO9,"HUSTR_CHATMACRO9"}, {&s_HUSTR_CHATMACRO0,"HUSTR_CHATMACRO0"}, {&s_HUSTR_TALKTOSELF1,"HUSTR_TALKTOSELF1"}, {&s_HUSTR_TALKTOSELF2,"HUSTR_TALKTOSELF2"}, {&s_HUSTR_TALKTOSELF3,"HUSTR_TALKTOSELF3"}, {&s_HUSTR_TALKTOSELF4,"HUSTR_TALKTOSELF4"}, {&s_HUSTR_TALKTOSELF5,"HUSTR_TALKTOSELF5"}, {&s_HUSTR_MESSAGESENT,"HUSTR_MESSAGESENT"}, {&s_HUSTR_PLRGREEN,"HUSTR_PLRGREEN"}, {&s_HUSTR_PLRINDIGO,"HUSTR_PLRINDIGO"}, {&s_HUSTR_PLRBROWN,"HUSTR_PLRBROWN"}, {&s_HUSTR_PLRRED,"HUSTR_PLRRED"}, //{c_HUSTR_KEYGREEN,"HUSTR_KEYGREEN"}, //{c_HUSTR_KEYINDIGO,"HUSTR_KEYINDIGO"}, //{c_HUSTR_KEYBROWN,"HUSTR_KEYBROWN"}, //{c_HUSTR_KEYRED,"HUSTR_KEYRED"}, {&s_AMSTR_FOLLOWON,"AMSTR_FOLLOWON"}, {&s_AMSTR_FOLLOWOFF,"AMSTR_FOLLOWOFF"}, {&s_AMSTR_GRIDON,"AMSTR_GRIDON"}, {&s_AMSTR_GRIDOFF,"AMSTR_GRIDOFF"}, {&s_AMSTR_MARKEDSPOT,"AMSTR_MARKEDSPOT"}, {&s_AMSTR_MARKSCLEARED,"AMSTR_MARKSCLEARED"}, {&s_STSTR_MUS,"STSTR_MUS"}, {&s_STSTR_NOMUS,"STSTR_NOMUS"}, {&s_STSTR_DQDON,"STSTR_DQDON"}, {&s_STSTR_DQDOFF,"STSTR_DQDOFF"}, {&s_STSTR_KFAADDED,"STSTR_KFAADDED"}, {&s_STSTR_FAADDED,"STSTR_FAADDED"}, {&s_STSTR_NCON,"STSTR_NCON"}, {&s_STSTR_NCOFF,"STSTR_NCOFF"}, {&s_STSTR_BEHOLD,"STSTR_BEHOLD"}, {&s_STSTR_BEHOLDX,"STSTR_BEHOLDX"}, {&s_STSTR_CHOPPERS,"STSTR_CHOPPERS"}, {&s_STSTR_CLEV,"STSTR_CLEV"}, {&s_STSTR_COMPON,"STSTR_COMPON"}, {&s_STSTR_COMPOFF,"STSTR_COMPOFF"}, {&s_E1TEXT,"E1TEXT"}, {&s_E2TEXT,"E2TEXT"}, {&s_E3TEXT,"E3TEXT"}, {&s_E4TEXT,"E4TEXT"}, {&s_C1TEXT,"C1TEXT"}, {&s_C2TEXT,"C2TEXT"}, {&s_C3TEXT,"C3TEXT"}, {&s_C4TEXT,"C4TEXT"}, {&s_C5TEXT,"C5TEXT"}, {&s_C6TEXT,"C6TEXT"}, {&s_P1TEXT,"P1TEXT"}, {&s_P2TEXT,"P2TEXT"}, {&s_P3TEXT,"P3TEXT"}, {&s_P4TEXT,"P4TEXT"}, {&s_P5TEXT,"P5TEXT"}, {&s_P6TEXT,"P6TEXT"}, {&s_T1TEXT,"T1TEXT"}, {&s_T2TEXT,"T2TEXT"}, {&s_T3TEXT,"T3TEXT"}, {&s_T4TEXT,"T4TEXT"}, {&s_T5TEXT,"T5TEXT"}, {&s_T6TEXT,"T6TEXT"}, {&s_CC_ZOMBIE,"CC_ZOMBIE"}, {&s_CC_SHOTGUN,"CC_SHOTGUN"}, {&s_CC_HEAVY,"CC_HEAVY"}, {&s_CC_IMP,"CC_IMP"}, {&s_CC_DEMON,"CC_DEMON"}, {&s_CC_LOST,"CC_LOST"}, {&s_CC_CACO,"CC_CACO"}, {&s_CC_HELL,"CC_HELL"}, {&s_CC_BARON,"CC_BARON"}, {&s_CC_ARACH,"CC_ARACH"}, {&s_CC_PAIN,"CC_PAIN"}, {&s_CC_REVEN,"CC_REVEN"}, {&s_CC_MANCU,"CC_MANCU"}, {&s_CC_ARCH,"CC_ARCH"}, {&s_CC_SPIDER,"CC_SPIDER"}, {&s_CC_CYBER,"CC_CYBER"}, {&s_CC_HERO,"CC_HERO"}, {&bgflatE1,"BGFLATE1"}, {&bgflatE2,"BGFLATE2"}, {&bgflatE3,"BGFLATE3"}, {&bgflatE4,"BGFLATE4"}, {&bgflat06,"BGFLAT06"}, {&bgflat11,"BGFLAT11"}, {&bgflat20,"BGFLAT20"}, {&bgflat30,"BGFLAT30"}, {&bgflat15,"BGFLAT15"}, {&bgflat31,"BGFLAT31"}, {&bgcastcall,"BGCASTCALL"}, // Ty 04/08/98 - added 5 general purpose startup announcement // strings for hacker use. See m_menu.c {&startup1,"STARTUP1"}, {&startup2,"STARTUP2"}, {&startup3,"STARTUP3"}, {&startup4,"STARTUP4"}, {&startup5,"STARTUP5"}, {&savegamename,"SAVEGAMENAME"}, // Ty 05/03/98 }; static int deh_numstrlookup = sizeof(deh_strlookup)/sizeof(deh_strlookup[0]); const char *deh_newlevel = "NEWLEVEL"; // CPhipps - const // DOOM shareware/registered/retail (Ultimate) names. // CPhipps - const**const const char **const mapnames[] = { &s_HUSTR_E1M1, &s_HUSTR_E1M2, &s_HUSTR_E1M3, &s_HUSTR_E1M4, &s_HUSTR_E1M5, &s_HUSTR_E1M6, &s_HUSTR_E1M7, &s_HUSTR_E1M8, &s_HUSTR_E1M9, &s_HUSTR_E2M1, &s_HUSTR_E2M2, &s_HUSTR_E2M3, &s_HUSTR_E2M4, &s_HUSTR_E2M5, &s_HUSTR_E2M6, &s_HUSTR_E2M7, &s_HUSTR_E2M8, &s_HUSTR_E2M9, &s_HUSTR_E3M1, &s_HUSTR_E3M2, &s_HUSTR_E3M3, &s_HUSTR_E3M4, &s_HUSTR_E3M5, &s_HUSTR_E3M6, &s_HUSTR_E3M7, &s_HUSTR_E3M8, &s_HUSTR_E3M9, &s_HUSTR_E4M1, &s_HUSTR_E4M2, &s_HUSTR_E4M3, &s_HUSTR_E4M4, &s_HUSTR_E4M5, &s_HUSTR_E4M6, &s_HUSTR_E4M7, &s_HUSTR_E4M8, &s_HUSTR_E4M9, &deh_newlevel, // spares? Unused. &deh_newlevel, &deh_newlevel, &deh_newlevel, &deh_newlevel, &deh_newlevel, &deh_newlevel, &deh_newlevel, &deh_newlevel }; // CPhipps - const**const const char **const mapnames2[] = // DOOM 2 map names. { &s_HUSTR_1, &s_HUSTR_2, &s_HUSTR_3, &s_HUSTR_4, &s_HUSTR_5, &s_HUSTR_6, &s_HUSTR_7, &s_HUSTR_8, &s_HUSTR_9, &s_HUSTR_10, &s_HUSTR_11, &s_HUSTR_12, &s_HUSTR_13, &s_HUSTR_14, &s_HUSTR_15, &s_HUSTR_16, &s_HUSTR_17, &s_HUSTR_18, &s_HUSTR_19, &s_HUSTR_20, &s_HUSTR_21, &s_HUSTR_22, &s_HUSTR_23, &s_HUSTR_24, &s_HUSTR_25, &s_HUSTR_26, &s_HUSTR_27, &s_HUSTR_28, &s_HUSTR_29, &s_HUSTR_30, &s_HUSTR_31, &s_HUSTR_32, }; // CPhipps - const**const const char **const mapnamesp[] = // Plutonia WAD map names. { &s_PHUSTR_1, &s_PHUSTR_2, &s_PHUSTR_3, &s_PHUSTR_4, &s_PHUSTR_5, &s_PHUSTR_6, &s_PHUSTR_7, &s_PHUSTR_8, &s_PHUSTR_9, &s_PHUSTR_10, &s_PHUSTR_11, &s_PHUSTR_12, &s_PHUSTR_13, &s_PHUSTR_14, &s_PHUSTR_15, &s_PHUSTR_16, &s_PHUSTR_17, &s_PHUSTR_18, &s_PHUSTR_19, &s_PHUSTR_20, &s_PHUSTR_21, &s_PHUSTR_22, &s_PHUSTR_23, &s_PHUSTR_24, &s_PHUSTR_25, &s_PHUSTR_26, &s_PHUSTR_27, &s_PHUSTR_28, &s_PHUSTR_29, &s_PHUSTR_30, &s_PHUSTR_31, &s_PHUSTR_32, }; // CPhipps - const**const const char **const mapnamest[] = // TNT WAD map names. { &s_THUSTR_1, &s_THUSTR_2, &s_THUSTR_3, &s_THUSTR_4, &s_THUSTR_5, &s_THUSTR_6, &s_THUSTR_7, &s_THUSTR_8, &s_THUSTR_9, &s_THUSTR_10, &s_THUSTR_11, &s_THUSTR_12, &s_THUSTR_13, &s_THUSTR_14, &s_THUSTR_15, &s_THUSTR_16, &s_THUSTR_17, &s_THUSTR_18, &s_THUSTR_19, &s_THUSTR_20, &s_THUSTR_21, &s_THUSTR_22, &s_THUSTR_23, &s_THUSTR_24, &s_THUSTR_25, &s_THUSTR_26, &s_THUSTR_27, &s_THUSTR_28, &s_THUSTR_29, &s_THUSTR_30, &s_THUSTR_31, &s_THUSTR_32, }; // Function prototypes void rstrip(char *); // strip trailing whitespace char * ptr_lstrip(char *); // point past leading whitespace boolean deh_GetData(char *, char *, uint_64_t *, char **, int ); boolean deh_procStringSub(char *, char *, char *, int ); char * dehReformatStr(char *); // Prototypes for block processing functions // Pointers to these functions are used as the blocks are encountered. void deh_procThing(DEHFILE *, int, char *); void deh_procFrame(DEHFILE *, int, char *); void deh_procPointer(DEHFILE *, int, char *); void deh_procSounds(DEHFILE *, int, char *); void deh_procAmmo(DEHFILE *, int, char *); void deh_procWeapon(DEHFILE *, int, char *); void deh_procSprite(DEHFILE *, int, char *); void deh_procCheat(DEHFILE *, int, char *); void deh_procMisc(DEHFILE *, int, char *); void deh_procText(DEHFILE *, int, char *); void deh_procPars(DEHFILE *, int, char *); void deh_procStrings(DEHFILE *, int, char *); void deh_procError(DEHFILE *, int, char *); void deh_procBexCodePointers(DEHFILE *, int, char *); // Structure deh_block is used to hold the block names that can // be encountered, and the routines to use to decipher them typedef struct { const char *key; // a mnemonic block code name // CPhipps - const* void (*const fptr)(DEHFILE *, int, char *); // handler } deh_block; #define DEH_BUFFERMAX 1024 // input buffer area size, hardcodedfor now // killough 8/9/98: make DEH_BLOCKMAX self-adjusting #define DEH_BLOCKMAX (sizeof deh_blocks/sizeof*deh_blocks) // size of array #define DEH_MAXKEYLEN 32 // as much of any key as we'll look at #define DEH_MOBJINFOMAX 24 // number of ints in the mobjinfo_t structure (!) // Put all the block header values, and the function to be called when that // one is encountered, in this array: static const deh_block deh_blocks[] = { // CPhipps - static const /* 0 */ {"Thing",deh_procThing}, /* 1 */ {"Frame",deh_procFrame}, /* 2 */ {"Pointer",deh_procPointer}, /* 3 */ {"Sound",deh_procSounds}, // Ty 03/16/98 corrected from "Sounds" /* 4 */ {"Ammo",deh_procAmmo}, /* 5 */ {"Weapon",deh_procWeapon}, /* 6 */ {"Sprite",deh_procSprite}, /* 7 */ {"Cheat",deh_procCheat}, /* 8 */ {"Misc",deh_procMisc}, /* 9 */ {"Text",deh_procText}, // -- end of standard "deh" entries, // begin BOOM Extensions (BEX) /* 10 */ {"[STRINGS]",deh_procStrings}, // new string changes /* 11 */ {"[PARS]",deh_procPars}, // alternative block marker /* 12 */ {"[CODEPTR]",deh_procBexCodePointers}, // bex codepointers by mnemonic /* 13 */ {"",deh_procError} // dummy to handle anything else }; // flag to skip included deh-style text, used with INCLUDE NOTEXT directive static boolean includenotext = false; // MOBJINFO - Dehacked block name = "Thing" // Usage: Thing nn (name) // These are for mobjinfo_t types. Each is an integer // within the structure, so we can use index of the string in this // array to offset by sizeof(int) into the mobjinfo_t array at [nn] // * things are base zero but dehacked considers them to start at #1. *** // CPhipps - static const static const char *deh_mobjinfo[DEH_MOBJINFOMAX] = { "ID #", // .doomednum "Initial frame", // .spawnstate "Hit points", // .spawnhealth "First moving frame", // .seestate "Alert sound", // .seesound "Reaction time", // .reactiontime "Attack sound", // .attacksound "Injury frame", // .painstate "Pain chance", // .painchance "Pain sound", // .painsound "Close attack frame", // .meleestate "Far attack frame", // .missilestate "Death frame", // .deathstate "Exploding frame", // .xdeathstate "Death sound", // .deathsound "Speed", // .speed "Width", // .radius "Height", // .height "Mass", // .mass "Missile damage", // .damage "Action sound", // .activesound "Bits", // .flags "Bits2", // .flags "Respawn frame" // .raisestate }; // Strings that are used to indicate flags ("Bits" in mobjinfo) // This is an array of bit masks that are related to p_mobj.h // values, using the smae names without the MF_ in front. // Ty 08/27/98 new code // // killough 10/98: // // Convert array to struct to allow multiple values, make array size variable #define DEH_MOBJFLAGMAX (sizeof deh_mobjflags/sizeof*deh_mobjflags) struct deh_mobjflags_s { const char *name; // CPhipps - const* uint_64_t value; }; // CPhipps - static const static const struct deh_mobjflags_s deh_mobjflags[] = { {"SPECIAL", MF_SPECIAL}, // call P_Specialthing when touched {"SOLID", MF_SOLID}, // block movement {"SHOOTABLE", MF_SHOOTABLE}, // can be hit {"NOSECTOR", MF_NOSECTOR}, // invisible but touchable {"NOBLOCKMAP", MF_NOBLOCKMAP}, // inert but displayable {"AMBUSH", MF_AMBUSH}, // deaf monster {"JUSTHIT", MF_JUSTHIT}, // will try to attack right back {"JUSTATTACKED", MF_JUSTATTACKED}, // take at least 1 step before attacking {"SPAWNCEILING", MF_SPAWNCEILING}, // initially hang from ceiling {"NOGRAVITY", MF_NOGRAVITY}, // don't apply gravity during play {"DROPOFF", MF_DROPOFF}, // can jump from high places {"PICKUP", MF_PICKUP}, // will pick up items {"NOCLIP", MF_NOCLIP}, // goes through walls {"SLIDE", MF_SLIDE}, // keep info about sliding along walls {"FLOAT", MF_FLOAT}, // allow movement to any height {"TELEPORT", MF_TELEPORT}, // don't cross lines or look at heights {"MISSILE", MF_MISSILE}, // don't hit same species, explode on block {"DROPPED", MF_DROPPED}, // dropped, not spawned (like ammo clip) {"SHADOW", MF_SHADOW}, // use fuzzy draw like spectres {"NOBLOOD", MF_NOBLOOD}, // puffs instead of blood when shot {"CORPSE", MF_CORPSE}, // so it will slide down steps when dead {"INFLOAT", MF_INFLOAT}, // float but not to target height {"COUNTKILL", MF_COUNTKILL}, // count toward the kills total {"COUNTITEM", MF_COUNTITEM}, // count toward the items total {"SKULLFLY", MF_SKULLFLY}, // special handling for flying skulls {"NOTDMATCH", MF_NOTDMATCH}, // do not spawn in deathmatch // killough 10/98: TRANSLATION consists of 2 bits, not 1: {"TRANSLATION", MF_TRANSLATION1}, // for Boom bug-compatibility {"TRANSLATION1", MF_TRANSLATION1}, // use translation table for color (players) {"TRANSLATION2", MF_TRANSLATION2}, // use translation table for color (players) {"UNUSED1", MF_TRANSLATION2}, // unused bit # 1 -- For Boom bug-compatibility {"UNUSED2", MF_STEALTH}, // unused bit # 2 -- For Boom compatibility {"STEALTH", MF_STEALTH}, // for stealth monsters {"UNUSED3", MF_TRANSLUC25}, // unused bit # 3 -- For Boom compatibility {"UNUSED4", MF_TRANSLUC50}, // unused bit # 4 -- For Boom compatibility {"TRANSLUC25", MF_TRANSLUC25}, // Translucency 25% {"TRANSLUC50", MF_TRANSLUC50}, // Translucency 50% {"TRANSLUC75", MF_TRANSLUC75}, // Translucency 25% + Translucency 50% = 75% {"TRANSLUCENT", MF_TRANSLUCENT}, // apply translucency to sprite (BOOM) {"TOUCHY", MF_TOUCHY},// dies on contact with solid objects (MBF) {"BOUNCES", MF_BOUNCES},// bounces off floors, ceilings and maybe walls {"FRIEND", MF_FRIEND},// a friend of the player(s) (MBF) }; // STATE - Dehacked block name = "Frame" and "Pointer" // Usage: Frame nn // Usage: Pointer nn (Frame nn) // These are indexed separately, for lookup to the actual // function pointers. Here we'll take whatever Dehacked gives // us and go from there. The (Frame nn) after the pointer is the // real place to put this value. The "Pointer" value is an xref // that Dehacked uses and is useless to us. // * states are base zero and have a dummy #0 (TROO) static const char *deh_state[] = // CPhipps - static const* { "Sprite number", // .sprite (spritenum_t) // an enum "Sprite subnumber", // .frame (long) "Duration", // .tics (long) "Next frame", // .nextstate (statenum_t) // This is set in a separate "Pointer" block from Dehacked "Codep Frame", // pointer to first use of action (actionf_t) "Unknown 1", // .misc1 (long) "Unknown 2" // .misc2 (long) }; // SFXINFO_STRUCT - Dehacked block name = "Sounds" // Sound effects, typically not changed (redirected, and new sfx put // into the pwad, but not changed here. Can you tell that Gregdidn't // know what they were for, mostly? Can you tell that I don't either? // Mostly I just put these into the same slots as they are in the struct. // This may not be supported in our -deh option if it doesn't make sense by then. // * sounds are base zero but have a dummy #0 static const char *deh_sfxinfo[] = // CPhipps - static const* { "Offset", // pointer to a name string, changed in text "Zero/One", // .singularity (int, one at a time flag) "Value", // .priority "Zero 1", // .link (sfxinfo_t*) referenced sound if linked "Zero 2", // .pitch "Zero 3", // .volume "Zero 4", // .data (SAMPLE*) sound data "Neg. One 1", // .usefulness "Neg. One 2" // .lumpnum }; // MUSICINFO is not supported in Dehacked. Ignored here. // * music entries are base zero but have a dummy #0 #if 0 // CPhipps - unused? // SPRITE - Dehacked block name = "Sprite" // Usage = Sprite nn // Sprite redirection by offset into the text area - unsupported by BOOM // * sprites are base zero and dehacked uses it that way. static const char *deh_sprite[] = // CPhipps - static const* { "Offset" // supposed to be the offset into the text section }; #endif // AMMO - Dehacked block name = "Ammo" // usage = Ammo n (name) // Ammo information for the few types of ammo static const char *deh_ammo[] = // CPhipps - static const* { "Max ammo", // maxammo[] "Per ammo" // clipammo[] }; // WEAPONS - Dehacked block name = "Weapon" // Usage: Weapon nn (name) // Basically a list of frames and what kind of ammo (see above)it uses. static const char *deh_weapon[] = // CPhipps - static const* { "Ammo type", // .ammo "Deselect frame", // .upstate "Select frame", // .downstate "Bobbing frame", // .readystate "Shooting frame", // .atkstate "Firing frame" // .flashstate }; // CHEATS - Dehacked block name = "Cheat" // Usage: Cheat 0 // Always uses a zero in the dehacked file, for consistency. No meaning. // These are just plain funky terms compared with id's // // killough 4/18/98: integrated into main cheat table now (see st_stuff.c) // MISC - Dehacked block name = "Misc" // Usage: Misc 0 // Always uses a zero in the dehacked file, for consistency. No meaning. static const char *deh_misc[] = // CPhipps - static const* { "Initial Health", // initial_health "Initial Bullets", // initial_bullets "Max Health", // maxhealth "Max Armor", // max_armor "Green Armor Class", // green_armor_class "Blue Armor Class", // blue_armor_class "Max Soulsphere", // max_soul "Soulsphere Health", // soul_health "Megasphere Health", // mega_health "God Mode Health", // god_health "IDFA Armor", // idfa_armor "IDFA Armor Class", // idfa_armor_class "IDKFA Armor", // idkfa_armor "IDKFA Armor Class", // idkfa_armor_class "BFG Cells/Shot", // BFGCELLS "Monsters Infight" // Unknown--not a specific number it seems, but // the logic has to be here somewhere or // it'd happen always }; // TEXT - Dehacked block name = "Text" // Usage: Text fromlen tolen // Dehacked allows a bit of adjustment to the length (why?) // BEX extension [CODEPTR] // Usage: Start block, then each line is: // FRAME nnn = PointerMnemonic // External references to action functions scattered about the code extern void A_Light0(); extern void A_WeaponReady(); extern void A_Lower(); extern void A_Raise(); extern void A_Punch(); extern void A_ReFire(); extern void A_FirePistol(); extern void A_Light1(); extern void A_FireShotgun(); extern void A_Light2(); extern void A_FireShotgun2(); extern void A_CheckReload(); extern void A_OpenShotgun2(); extern void A_LoadShotgun2(); extern void A_CloseShotgun2(); extern void A_FireCGun(); extern void A_GunFlash(); extern void A_FireMissile(); extern void A_Saw(); extern void A_FirePlasma(); extern void A_BFGsound(); extern void A_FireBFG(); extern void A_BFGSpray(); extern void A_Explode(); extern void A_Pain(); extern void A_PlayerScream(); extern void A_Fall(); extern void A_XScream(); extern void A_Look(); extern void A_Chase(); extern void A_FaceTarget(); extern void A_PosAttack(); extern void A_Scream(); extern void A_SPosAttack(); extern void A_VileChase(); extern void A_VileStart(); extern void A_VileTarget(); extern void A_VileAttack(); extern void A_StartFire(); extern void A_Fire(); extern void A_FireCrackle(); extern void A_Tracer(); extern void A_SkelWhoosh(); extern void A_SkelFist(); extern void A_SkelMissile(); extern void A_FatRaise(); extern void A_FatAttack1(); extern void A_FatAttack2(); extern void A_FatAttack3(); extern void A_BossDeath(); extern void A_CPosAttack(); extern void A_CPosRefire(); extern void A_TroopAttack(); extern void A_SargAttack(); extern void A_HeadAttack(); extern void A_BruisAttack(); extern void A_SkullAttack(); extern void A_Metal(); extern void A_SpidRefire(); extern void A_BabyMetal(); extern void A_BspiAttack(); extern void A_Hoof(); extern void A_CyberAttack(); extern void A_PainAttack(); extern void A_PainDie(); extern void A_KeenDie(); extern void A_BrainPain(); extern void A_BrainScream(); extern void A_BrainDie(); extern void A_BrainAwake(); extern void A_BrainSpit(); extern void A_SpawnSound(); extern void A_SpawnFly(); extern void A_BrainExplode(); extern void A_Detonate(); // killough 8/9/98 extern void A_Mushroom(); // killough 10/98 extern void A_Die(); // killough 11/98 extern void A_Spawn(); // killough 11/98 extern void A_Turn(); // killough 11/98 extern void A_Face(); // killough 11/98 extern void A_Scratch(); // killough 11/98 extern void A_PlaySound(); // killough 11/98 extern void A_RandomJump(); // killough 11/98 extern void A_LineEffect(); // killough 11/98 typedef struct { actionf_t cptr; // actual pointer to the subroutine const char *lookup; // mnemonic lookup string to be specified in BEX // CPhipps - const* } deh_bexptr; static const deh_bexptr deh_bexptrs[] = // CPhipps - static const { {A_Light0, "A_Light0"}, {A_WeaponReady, "A_WeaponReady"}, {A_Lower, "A_Lower"}, {A_Raise, "A_Raise"}, {A_Punch, "A_Punch"}, {A_ReFire, "A_ReFire"}, {A_FirePistol, "A_FirePistol"}, {A_Light1, "A_Light1"}, {A_FireShotgun, "A_FireShotgun"}, {A_Light2, "A_Light2"}, {A_FireShotgun2, "A_FireShotgun2"}, {A_CheckReload, "A_CheckReload"}, {A_OpenShotgun2, "A_OpenShotgun2"}, {A_LoadShotgun2, "A_LoadShotgun2"}, {A_CloseShotgun2, "A_CloseShotgun2"}, {A_FireCGun, "A_FireCGun"}, {A_GunFlash, "A_GunFlash"}, {A_FireMissile, "A_FireMissile"}, {A_Saw, "A_Saw"}, {A_FirePlasma, "A_FirePlasma"}, {A_BFGsound, "A_BFGsound"}, {A_FireBFG, "A_FireBFG"}, {A_BFGSpray, "A_BFGSpray"}, {A_Explode, "A_Explode"}, {A_Pain, "A_Pain"}, {A_PlayerScream, "A_PlayerScream"}, {A_Fall, "A_Fall"}, {A_XScream, "A_XScream"}, {A_Look, "A_Look"}, {A_Chase, "A_Chase"}, {A_FaceTarget, "A_FaceTarget"}, {A_PosAttack, "A_PosAttack"}, {A_Scream, "A_Scream"}, {A_SPosAttack, "A_SPosAttack"}, {A_VileChase, "A_VileChase"}, {A_VileStart, "A_VileStart"}, {A_VileTarget, "A_VileTarget"}, {A_VileAttack, "A_VileAttack"}, {A_StartFire, "A_StartFire"}, {A_Fire, "A_Fire"}, {A_FireCrackle, "A_FireCrackle"}, {A_Tracer, "A_Tracer"}, {A_SkelWhoosh, "A_SkelWhoosh"}, {A_SkelFist, "A_SkelFist"}, {A_SkelMissile, "A_SkelMissile"}, {A_FatRaise, "A_FatRaise"}, {A_FatAttack1, "A_FatAttack1"}, {A_FatAttack2, "A_FatAttack2"}, {A_FatAttack3, "A_FatAttack3"}, {A_BossDeath, "A_BossDeath"}, {A_CPosAttack, "A_CPosAttack"}, {A_CPosRefire, "A_CPosRefire"}, {A_TroopAttack, "A_TroopAttack"}, {A_SargAttack, "A_SargAttack"}, {A_HeadAttack, "A_HeadAttack"}, {A_BruisAttack, "A_BruisAttack"}, {A_SkullAttack, "A_SkullAttack"}, {A_Metal, "A_Metal"}, {A_SpidRefire, "A_SpidRefire"}, {A_BabyMetal, "A_BabyMetal"}, {A_BspiAttack, "A_BspiAttack"}, {A_Hoof, "A_Hoof"}, {A_CyberAttack, "A_CyberAttack"}, {A_PainAttack, "A_PainAttack"}, {A_PainDie, "A_PainDie"}, {A_KeenDie, "A_KeenDie"}, {A_BrainPain, "A_BrainPain"}, {A_BrainScream, "A_BrainScream"}, {A_BrainDie, "A_BrainDie"}, {A_BrainAwake, "A_BrainAwake"}, {A_BrainSpit, "A_BrainSpit"}, {A_SpawnSound, "A_SpawnSound"}, {A_SpawnFly, "A_SpawnFly"}, {A_BrainExplode, "A_BrainExplode"}, {A_Detonate, "A_Detonate"}, // killough 8/9/98 {A_Mushroom, "A_Mushroom"}, // killough 10/98 {A_Die, "A_Die"}, // killough 11/98 {A_Spawn, "A_Spawn"}, // killough 11/98 {A_Turn, "A_Turn"}, // killough 11/98 {A_Face, "A_Face"}, // killough 11/98 {A_Scratch, "A_Scratch"}, // killough 11/98 {A_PlaySound, "A_PlaySound"}, // killough 11/98 {A_RandomJump, "A_RandomJump"}, // killough 11/98 {A_LineEffect, "A_LineEffect"}, // killough 11/98 // This NULL entry must be the last in the list {NULL, "A_NULL"}, // Ty 05/16/98 }; // to hold startup code pointers from INFO.C // CPhipps - static static actionf_t deh_codeptr[NUMSTATES]; // ==================================================================== // ProcessDehFile // Purpose: Read and process a DEH or BEX file // Args: filename -- name of the DEH/BEX file // outfilename -- output file (DEHOUT.TXT), appended to here // Returns: void // // killough 10/98: // substantially modified to allow input from wad lumps instead of .deh files. void ProcessDehFile(const char *filename, const char *outfilename, int lumpnum) { static int fileout = -1; // In case -dehout was used DEHFILE infile, *filein = &infile; // killough 10/98 char inbuffer[DEH_BUFFERMAX]; // Place to put the primary infostring // Open output file if we're writing output if (outfilename && *outfilename && fileout < 0) { static boolean firstfile = true; // to allow append to output log if (strcmp(outfilename, "-")) { fileout = open(outfilename, firstfile ? O_WRONLY | O_CREAT : O_WRONLY | O_APPEND); if (fileout < 0) { printf( "Could not open -dehout file %s\n... using stdout.\n", outfilename); } } firstfile = false; } // killough 10/98: allow DEH files to come from wad lumps if (filename) { if ((infile.fd = open(filename,O_RDONLY)) < 0) { printf( "-deh file %s not found\n",filename); return; // should be checked up front anyway } infile.inp = NULL; } else // DEH file comes from lump indicated by third argument { int size = W_LumpLength(lumpnum); infile.size = (size < 0) ? 0 : (ssize_t)size; infile.inp = W_CacheLumpNum(lumpnum); filename = "(WAD)"; } printf("Loading DEH file %s\n",filename); if (fileout >= 0) fdprintf(fileout,"\nLoading DEH file %s\n\n",filename); { static int i; // killough 10/98: only run once, by keeping index static for (; i= 0) fdprintf(fileout,"Line='%s'\n",inbuffer); if (!*inbuffer || *inbuffer == '#' || *inbuffer == ' ') continue; /* Blank line or comment line */ // -- If DEH_BLOCKMAX is set right, the processing is independently // -- handled based on data in the deh_blocks[] structure array // killough 10/98: INCLUDE code rewritten to allow arbitrary nesting, // and to greatly simplify code, fix memory leaks, other bugs if (!strncasecmp(inbuffer,"INCLUDE",7)) // include a file { // preserve state while including a file // killough 10/98: moved to here char *nextfile; boolean oldnotext = includenotext; // killough 10/98 // killough 10/98: exclude if inside wads (only to discourage // the practice, since the code could otherwise handle it) if (infile.inp) { if (fileout >= 0) fdprintf(fileout, "No files may be included from wads: %s\n", inbuffer); continue; } // check for no-text directive, used when including a DEH // file but using the BEX format to handle strings if (!strncasecmp(nextfile = ptr_lstrip(inbuffer+7),"NOTEXT",6)) includenotext = true, nextfile = ptr_lstrip(nextfile+6); if (fileout >= 0) fdprintf(fileout,"Branching to include file %s...\n", nextfile); // killough 10/98: // Second argument must be NULL to prevent closing fileout too soon ProcessDehFile(nextfile,NULL,0); // do the included file includenotext = oldnotext; if (fileout >= 0) fdprintf(fileout,"...continuing with %s\n",filename); continue; } for (i=0; i= 0) fdprintf(fileout,"Processing function [%d] for %s\n", i, deh_blocks[i].key); deh_blocks[i].fptr(filein,fileout,inbuffer); // call function break; // we got one, that's enough for this block } } if (infile.inp) { W_UnlockLumpNum(lumpnum); // Mark purgable } if (infile.fd >= 0) { close(infile.fd); // Close real file infile.fd = -1; } if (fileout >= 0) { close(fileout); fileout = -1; } } // ==================================================================== // deh_procBexCodePointers // Purpose: Handle [CODEPTR] block, BOOM Extension // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procBexCodePointers(DEHFILE *fpin, int fpout, char *line) { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; int indexnum; char mnemonic[DEH_MAXKEYLEN]; // to hold the codepointer mnemonic int i; // looper boolean found; // know if we found this one during lookup or not // Ty 05/16/98 - initialize it to something, dummy! strncpy(inbuffer,line,DEH_BUFFERMAX); // for this one, we just read 'em until we hit a blank line while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; if (!*inbuffer) break; // killough 11/98: really exit on blank line // killough 8/98: allow hex numbers in input: if ( (3 != sscanf(inbuffer,"%s %d = %s", key, &indexnum, mnemonic)) || (strcasecmp(key,"FRAME")) ) // NOTE: different format from normal { if (fpout) fdprintf(fpout, "Invalid BEX codepointer line - must start with 'FRAME': '%s'\n", inbuffer); return; // early return } if (fpout) fdprintf(fpout,"Processing pointer at index %d: %s\n", indexnum, mnemonic); if (indexnum < 0 || indexnum >= NUMSTATES) { if (fpout) fdprintf(fpout,"Bad pointer number %d of %d\n", indexnum, NUMSTATES); return; // killough 10/98: fix SegViol } strcpy(key,"A_"); // reusing the key area to prefix the mnemonic strcat(key,ptr_lstrip(mnemonic)); found = FALSE; i= -1; // incremented to start at zero at the top of the loop do // Ty 05/16/98 - fix loop logic to look for null ending entry { ++i; if (!strcasecmp(key,deh_bexptrs[i].lookup)) { // Ty 06/01/98 - add to states[].action for new djgcc version states[indexnum].action = deh_bexptrs[i].cptr; // assign if (fpout) fdprintf(fpout, " - applied %s from codeptr[%d] to states[%d]\n", deh_bexptrs[i].lookup,i,indexnum); found = TRUE; } } while (!found && (deh_bexptrs[i].cptr != NULL)); if (!found) if (fpout) fdprintf(fpout, "Invalid frame pointer mnemonic '%s' at %d\n", mnemonic, indexnum); } return; } //--------------------------------------------------------------------------- // To be on the safe, compatible side, we manually convert DEH bitflags // to prboom types - POPE //--------------------------------------------------------------------------- uint_64_t getConvertedDEHBits(uint_64_t bits) { static const uint_64_t bitMap[32] = { /* cf linuxdoom-1.10 p_mobj.h */ MF_SPECIAL, // 0 Can be picked up. When touched the thing can be picked up. MF_SOLID, // 1 Obstacle. The thing is solid and will not let you (or others) pass through it MF_SHOOTABLE, // 2 Shootable. Can be shot. MF_NOSECTOR, // 3 Total Invisibility. Invisible, but can be touched MF_NOBLOCKMAP, // 4 Don't use the blocklinks (inert but displayable) MF_AMBUSH, // 5 Semi deaf. The thing is a deaf monster MF_JUSTHIT, // 6 In pain. Will try to attack right back after being hit MF_JUSTATTACKED, // 7 Steps before attack. Will take at least one step before attacking MF_SPAWNCEILING, // 8 Hangs from ceiling. When the level starts, this thing will be at ceiling height. MF_NOGRAVITY, // 9 No gravity – Gravity does not affect this thing MF_DROPOFF, // 10 Travels over cliffs – Monsters normally do not walk off ledges/steps they could not walk up. With this set they can walk off any height of cliff. Usually only used for flying monsters. MF_PICKUP, // 11 Pick up items – The thing can pick up gettable items. MF_NOCLIP, // 12 No clipping - Thing can walk through walls. MF_SLIDE, // 13 Slides along walls – Keep info about sliding along walls (don’t really know much about this one). MF_FLOAT, // 14 Floating – Thing can move to any height MF_TELEPORT, // 15 Semi no clipping – Don’t cross lines or look at teleport heights. (don’t really know much about this one either). MF_MISSILE, // 16 Projectiles – Behaves like a projectile, explodes when hitting something that blocks movement MF_DROPPED, // 17 Disappearing weapon – Dropped, not spawned (like an ammo clip) I have not had much success in using this one. MF_SHADOW, // 18 Partial invisibility – Drawn like a spectre. MF_NOBLOOD, // 19 Puffs (vs. bleeds) – If hit will spawn bullet puffs instead of blood splats. MF_CORPSE, // 20 Sliding helpless – Will slide down steps when dead. MF_INFLOAT, // 21 No auto levelling - float but not to target height (?) MF_COUNTKILL, // 22 Affects kill % – counted as a killable enemy and affects percentage kills on level summary. MF_COUNTITEM, // 23 Affects item % –affects percentage items gathered on level summary. MF_SKULLFLY, // 24 Running - special handling for flying skulls. MF_NOTDMATCH, // 25 Not in deathmatch - do not spawn in deathmatch (like keys) MF_TRANSLATION1, // 26 Color 1 (grey / red) MF_TRANSLATION2, // 27 Color 2 (brown / red) MF_TRANSLATION, // 28 and 29 allow the green colours in a thing’s graphics to be remapped to a different colour like the players uniforms in multiplayer games. Leaving all the bits alone, the thing stays green. Setting 26 it becomes grey. Setting 27 it becomes brown. Setting both 26 and 27 it becomes red. MF_TRANSLATION, 0, 0 }; int i; uint_64_t shiftBits = bits; uint_64_t convertedBits = 0; for (i=0; i<32; i++) { if (shiftBits & 0x1) convertedBits |= bitMap[i]; shiftBits >>= 1; } return convertedBits; } //--------------------------------------------------------------------------- // See usage below for an explanation of this function's existence - POPE //--------------------------------------------------------------------------- void setMobjInfoValue(int mobjInfoIndex, int keyIndex, uint_64_t value) { mobjinfo_t *mi; if (mobjInfoIndex >= NUMMOBJTYPES || mobjInfoIndex < 0) return; mi = &mobjinfo[mobjInfoIndex]; switch (keyIndex) { case 0: mi->doomednum = (int)value; return; case 1: mi->spawnstate = (int)value; return; case 2: mi->spawnhealth = (int)value; return; case 3: mi->seestate = (int)value; return; case 4: mi->seesound = (int)value; return; case 5: mi->reactiontime = (int)value; return; case 6: mi->attacksound = (int)value; return; case 7: mi->painstate = (int)value; return; case 8: mi->painchance = (int)value; return; case 9: mi->painsound = (int)value; return; case 10: mi->meleestate = (int)value; return; case 11: mi->missilestate = (int)value; return; case 12: mi->deathstate = (int)value; return; case 13: mi->xdeathstate = (int)value; return; case 14: mi->deathsound = (int)value; return; case 15: mi->speed = (int)value; return; case 16: mi->radius = (int)value; return; case 17: mi->height = (int)value; return; case 18: mi->mass = (int)value; return; case 19: mi->damage = (int)value; return; case 20: mi->activesound = (int)value; return; case 21: mi->flags = value; return; case 22: mi->raisestate = (int)value; return; default: return; } } // ==================================================================== // deh_procThing // Purpose: Handle DEH Thing block // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // // Ty 8/27/98 - revised to also allow mnemonics for // bit masks for monster attributes // void deh_procThing(DEHFILE *fpin, int fpout, char *line) { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; uint_64_t value; // All deh values are ints or longs int indexnum; int ix; char *strval; strncpy(inbuffer,line,DEH_BUFFERMAX); if (fpout) fdprintf(fpout,"Thing line: '%s'\n",inbuffer); // killough 8/98: allow hex numbers in input: ix = sscanf(inbuffer,"%s %d",key, &indexnum); if (fpout) fdprintf(fpout,"count=%d, Thing %d\n",ix, indexnum); // Note that the mobjinfo[] array is base zero, but object numbers // in the dehacked file start with one. Grumble. --indexnum; // now process the stuff // Note that for Things we can look up the key and use its offset // in the array of key strings as an int offset in the structure // get a line until a blank or end of file--it's not // blank now because it has our incoming key in it while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; // killough 11/98: really bail out on blank lines (break != continue) if (!*inbuffer) break; // bail out with blank line between sections if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok { if (fpout) fdprintf(fpout,"Bad data pair in '%s'\n",inbuffer); continue; } for (ix=0; ix>32) & 0xffffffff, (unsigned long)deh_mobjflags[iy].value & 0xffffffff, strval ); } value |= deh_mobjflags[iy].value; break; } if (iy >= DEH_MOBJFLAGMAX && fpout) { fdprintf(fpout, "Could not find bit mnemonic %s\n", strval); } } // Don't worry about conversion -- simply print values if (fpout) { fdprintf(fpout, "Bits = 0x%08lX%08lX\n", (unsigned long)(value>>32) & 0xffffffff, (unsigned long)value & 0xffffffff ); } } } if (fpout) { fdprintf(fpout, "Assigned 0x%08lx%08lx to %s(%d) at index %d\n", (unsigned long)(value>>32) & 0xffffffff, (unsigned long)value & 0xffffffff, key, indexnum, ix ); } } } return; } // ==================================================================== // deh_procFrame // Purpose: Handle DEH Frame block // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procFrame(DEHFILE *fpin, int fpout, char *line) { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; uint_64_t value; // All deh values are ints or longs int indexnum; strncpy(inbuffer,line,DEH_BUFFERMAX); // killough 8/98: allow hex numbers in input: sscanf(inbuffer,"%s %d",key, &indexnum); if (fpout) fdprintf(fpout,"Processing Frame at index %d: %s\n",indexnum,key); if (indexnum < 0 || indexnum >= NUMSTATES) if (fpout) fdprintf(fpout,"Bad frame number %d of %d\n",indexnum, NUMSTATES); while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; if (!*inbuffer) break; // killough 11/98 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok { if (fpout) fdprintf(fpout,"Bad data pair in '%s'\n",inbuffer); continue; } if (!strcasecmp(key,deh_state[0])) // Sprite number { if (fpout) fdprintf(fpout," - sprite = %ld\n",(long)value); states[indexnum].sprite = (spritenum_t)value; } else if (!strcasecmp(key,deh_state[1])) // Sprite subnumber { if (fpout) fdprintf(fpout," - frame = %ld\n",(long)value); states[indexnum].frame = (long)value; // long } else if (!strcasecmp(key,deh_state[2])) // Duration { if (fpout) fdprintf(fpout," - tics = %ld\n",(long)value); states[indexnum].tics = (long)value; // long } else if (!strcasecmp(key,deh_state[3])) // Next frame { if (fpout) fdprintf(fpout," - nextstate = %ld\n",(long)value); states[indexnum].nextstate = (statenum_t)value; } else if (!strcasecmp(key,deh_state[4])) // Codep frame (not set in Frame deh block) { if (fpout) fdprintf(fpout," - codep, should not be set in Frame section!\n"); /* nop */ ; } else if (!strcasecmp(key,deh_state[5])) // Unknown 1 { if (fpout) fdprintf(fpout," - misc1 = %ld\n",(long)value); states[indexnum].misc1 = (long)value; // long } else if (!strcasecmp(key,deh_state[6])) // Unknown 2 { if (fpout) fdprintf(fpout," - misc2 = %ld\n",(long)value); states[indexnum].misc2 = (long)value; // long } else if (fpout) fdprintf(fpout,"Invalid frame string index for '%s'\n",key); } return; } // ==================================================================== // deh_procPointer // Purpose: Handle DEH Code pointer block, can use BEX [CODEPTR] instead // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procPointer(DEHFILE *fpin, int fpout, char *line) // done { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; uint_64_t value; // All deh values are ints or longs int indexnum; int i; // looper strncpy(inbuffer,line,DEH_BUFFERMAX); // NOTE: different format from normal // killough 8/98: allow hex numbers in input, fix error case: if (sscanf(inbuffer,"%*s %*i (%s %i)",key, &indexnum) != 2) { if (fpout) fdprintf(fpout,"Bad data pair in '%s'\n",inbuffer); return; } if (fpout) fdprintf(fpout,"Processing Pointer at index %d: %s\n",indexnum, key); if (indexnum < 0 || indexnum >= NUMSTATES) { if (fpout) fdprintf(fpout,"Bad pointer number %d of %d\n",indexnum, NUMSTATES); return; } while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; if (!*inbuffer) break; // killough 11/98 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok { if (fpout) fdprintf(fpout,"Bad data pair in '%s'\n",inbuffer); continue; } if ((signed)value < 0 || value >= NUMSTATES) { if (fpout) fdprintf(fpout,"Bad pointer number %lld of %d\n",value, NUMSTATES); return; } if (!strcasecmp(key,deh_state[4])) // Codep frame (not set in Frame deh block) { states[indexnum].action = deh_codeptr[value]; if (fpout) fdprintf(fpout," - applied from codeptr[%ld] to states[%d]\n", (long)value,indexnum); // Write BEX-oriented line to match: for (i=0;i FRAME %d = %s\n", indexnum, &deh_bexptrs[i].lookup[2]); break; } } } else if (fpout) fdprintf(fpout,"Invalid frame pointer index for '%s' at %lld\n", key, value); } return; } // ==================================================================== // deh_procSounds // Purpose: Handle DEH Sounds block // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procSounds(DEHFILE *fpin, int fpout, char *line) { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; uint_64_t value; // All deh values are ints or longs int indexnum; strncpy(inbuffer,line,DEH_BUFFERMAX); // killough 8/98: allow hex numbers in input: sscanf(inbuffer,"%s %d",key, &indexnum); if (fpout) fdprintf(fpout,"Processing Sounds at index %d: %s\n", indexnum, key); if (indexnum < 0 || indexnum >= NUMSFX) if (fpout) fdprintf(fpout,"Bad sound number %d of %d\n", indexnum, NUMSFX); while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; if (!*inbuffer) break; // killough 11/98 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok { if (fpout) fdprintf(fpout,"Bad data pair in '%s'\n",inbuffer); continue; } if (!strcasecmp(key,deh_sfxinfo[0])) // Offset /* nop */ ; // we don't know what this is, I don't think else if (!strcasecmp(key,deh_sfxinfo[1])) // Zero/One S_sfx[indexnum].singularity = (int)value; else if (!strcasecmp(key,deh_sfxinfo[2])) // Value S_sfx[indexnum].priority = (int)value; else if (!strcasecmp(key,deh_sfxinfo[3])) // Zero 1 S_sfx[indexnum].link = (sfxinfo_t *)((long) value); else if (!strcasecmp(key,deh_sfxinfo[4])) // Zero 2 S_sfx[indexnum].pitch = (int)value; else if (!strcasecmp(key,deh_sfxinfo[5])) // Zero 3 S_sfx[indexnum].volume = (int)value; else if (!strcasecmp(key,deh_sfxinfo[6])) // Zero 4 S_sfx[indexnum].data = (void *) ((long) value); // killough 5/3/98: changed cast else if (!strcasecmp(key,deh_sfxinfo[7])) // Neg. One 1 S_sfx[indexnum].usefulness = (int)value; else if (!strcasecmp(key,deh_sfxinfo[8])) // Neg. One 2 S_sfx[indexnum].lumpnum = (int)value; else if (fpout) fdprintf(fpout, "Invalid sound string index for '%s'\n",key); } return; } // ==================================================================== // deh_procAmmo // Purpose: Handle DEH Ammo block // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procAmmo(DEHFILE *fpin, int fpout, char *line) { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; uint_64_t value; // All deh values are ints or longs int indexnum; strncpy(inbuffer,line,DEH_BUFFERMAX); // killough 8/98: allow hex numbers in input: sscanf(inbuffer,"%s %i",key, &indexnum); if (fpout) fdprintf(fpout,"Processing Ammo at index %d: %s\n", indexnum, key); if (indexnum < 0 || indexnum >= NUMAMMO) if (fpout) fdprintf(fpout,"Bad ammo number %d of %d\n", indexnum,NUMAMMO); while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; if (!*inbuffer) break; // killough 11/98 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok { if (fpout) fdprintf(fpout,"Bad data pair in '%s'\n",inbuffer); continue; } if (!strcasecmp(key,deh_ammo[0])) // Max ammo maxammo[indexnum] = (int)value; else if (!strcasecmp(key,deh_ammo[1])) // Per ammo clipammo[indexnum] = (int)value; else if (fpout) fdprintf(fpout,"Invalid ammo string index for '%s'\n",key); } return; } // ==================================================================== // deh_procWeapon // Purpose: Handle DEH Weapon block // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procWeapon(DEHFILE *fpin, int fpout, char *line) { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; uint_64_t value; // All deh values are ints or longs int indexnum; strncpy(inbuffer,line,DEH_BUFFERMAX); // killough 8/98: allow hex numbers in input: sscanf(inbuffer,"%s %d",key, &indexnum); if (fpout) fdprintf(fpout,"Processing Weapon at index %d: %s\n", indexnum, key); if (indexnum < 0 || indexnum >= NUMWEAPONS) if (fpout) fdprintf(fpout,"Bad weapon number %d of %d\n", indexnum, NUMAMMO); while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; if (!*inbuffer) break; // killough 11/98 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok { if (fpout) fdprintf(fpout,"Bad data pair in '%s'\n",inbuffer); continue; } if (!strcasecmp(key,deh_weapon[0])) // Ammo type weaponinfo[indexnum].ammo = (ammotype_t)value; else if (!strcasecmp(key,deh_weapon[1])) // Deselect frame weaponinfo[indexnum].upstate = (int)value; else if (!strcasecmp(key,deh_weapon[2])) // Select frame weaponinfo[indexnum].downstate = (int)value; else if (!strcasecmp(key,deh_weapon[3])) // Bobbing frame weaponinfo[indexnum].readystate = (int)value; else if (!strcasecmp(key,deh_weapon[4])) // Shooting frame weaponinfo[indexnum].atkstate = (int)value; else if (!strcasecmp(key,deh_weapon[5])) // Firing frame weaponinfo[indexnum].flashstate = (int)value; else if (fpout) fdprintf(fpout,"Invalid weapon string index for '%s'\n",key); } return; } // ==================================================================== // deh_procSprite // Purpose: Dummy - we do not support the DEH Sprite block // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procSprite(DEHFILE *fpin, int fpout, char *line) // Not supported { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; int indexnum; // Too little is known about what this is supposed to do, and // there are better ways of handling sprite renaming. Not supported. strncpy(inbuffer,line,DEH_BUFFERMAX); // killough 8/98: allow hex numbers in input: sscanf(inbuffer,"%s %d",key, &indexnum); if (fpout) fdprintf(fpout, "Ignoring Sprite offset change at index %d: %s\n",indexnum, key); while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; if (!*inbuffer) break; // killough 11/98 // ignore line if (fpout) fdprintf(fpout,"- %s\n",inbuffer); } return; } // ==================================================================== // deh_procPars // Purpose: Handle BEX extension for PAR times // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procPars(DEHFILE *fpin, int fpout, char *line) // extension { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; int indexnum; int episode, level, partime, oldpar; // new item, par times // usage: After [PARS] Par 0 section identifier, use one or more of these // lines: // par 3 5 120 // par 14 230 // The first would make the par for E3M5 be 120 seconds, and the // second one makes the par for MAP14 be 230 seconds. The number // of parameters on the line determines which group of par values // is being changed. Error checking is done based on current fixed // array sizes of[4][10] and [32] strncpy(inbuffer,line,DEH_BUFFERMAX); // killough 8/98: allow hex numbers in input: sscanf(inbuffer,"%s %d",key, &indexnum); if (fpout) fdprintf(fpout, "Processing Par value at index %d: %s\n",indexnum, key); // indexnum is a dummy entry while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; strlwr(inbuffer); // lowercase it if (!*inbuffer) break; // killough 11/98 if (3 != sscanf(inbuffer,"par %d %d %d",&episode, &level, &partime)) { // not 3 if (2 != sscanf(inbuffer,"par %d %d",&level, &partime)) { // not 2 if (fpout) fdprintf(fpout,"Invalid par time setting string: %s\n",inbuffer); } else { // is 2 // Ty 07/11/98 - wrong range check, not zero-based if (level < 1 || level > 32) // base 0 array (but 1-based parm) { if (fpout) fdprintf(fpout,"Invalid MAPnn value MAP%d\n",level); } else { oldpar = cpars[level-1]; if (fpout) fdprintf(fpout,"Changed par time for MAP%d from %d to %d\n",level,oldpar,partime); cpars[level-1] = partime; deh_pars = TRUE; } } } else { // is 3 // note that though it's a [4][10] array, the "left" and "top" aren't used, // effectively making it a base 1 array. // Ty 07/11/98 - level was being checked against max 3 - dumb error // Note that episode 4 does not have par times per original design // in Ultimate DOOM so that is not supported here. if (episode < 1 || episode > 3 || level < 1 || level > 9) { if (fpout) fdprintf(fpout, "Invalid ExMx values E%dM%d\n",episode, level); } else { oldpar = pars[episode][level]; pars[episode][level] = partime; if (fpout) fdprintf(fpout, "Changed par time for E%dM%d from %d to %d\n", episode,level,oldpar,partime); deh_pars = TRUE; } } } return; } // ==================================================================== // deh_procCheat // Purpose: Handle DEH Cheat block // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procCheat(DEHFILE *fpin, int fpout, char *line) // done { (void) fpin; (void) fpout; (void) line; /* char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; uint_64_t value; // All deh values are ints or longs char ch = 0; // CPhipps - `writable' null string to initialise... char *strval = &ch; // pointer to the value area int ix, iy; // array indices char *p; // utility pointer if (fpout) fdprintf(fpout,"Processing Cheat: %s\n",line); strncpy(inbuffer,line,DEH_BUFFERMAX); while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; if (!*inbuffer) break; // killough 11/98 if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok { if (fpout) fdprintf(fpout,"Bad data pair in '%s'\n",inbuffer); continue; } // Otherwise we got a (perhaps valid) cheat name, // so look up the key in the array // killough 4/18/98: use main cheat code table in st_stuff.c now for (ix=0; cheat[ix].cheat; ix++) if (cheat[ix].deh_cheat) // killough 4/18/98: skip non-deh { if (!stricmp(key,cheat[ix].deh_cheat)) // found the cheat, ignored case { // replace it but don't overflow it. Use current length as limit. // Ty 03/13/98 - add 0xff code // Deal with the fact that the cheats in deh files are extended // with character 0xFF to the original cheat length, which we don't do. for (iy=0; strval[iy]; iy++) strval[iy] = (strval[iy]==(char)0xff) ? '\0' : strval[iy]; iy = ix; // killough 4/18/98 // Ty 03/14/98 - skip leading spaces p = strval; while (*p == ' ') ++p; // Ty 03/16/98 - change to use a strdup and orphan the original // Also has the advantage of allowing length changes. // strncpy(cheat[iy].cheat,p,strlen(cheat[iy].cheat)); #if 0 { // killough 9/12/98: disable cheats which are prefixes of this one int i; for (i=0; cheat[i].cheat; i++) if (cheat[i].when & not_deh && !strncasecmp(cheat[i].cheat, cheat[iy].cheat, strlen(cheat[i].cheat)) && i != iy) cheat[i].deh_modified = true; } #endif cheat[iy].cheat = strdup(p); if (fpout) fdprintf(fpout, "Assigned new cheat '%s' to cheat '%s'at index %d\n", p, cheat[ix].deh_cheat, iy); // killough 4/18/98 } } if (fpout) fdprintf(fpout,"- %s\n",inbuffer); } return; */ } // ==================================================================== // deh_procMisc // Purpose: Handle DEH Misc block // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procMisc(DEHFILE *fpin, int fpout, char *line) // done { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; uint_64_t value; // All deh values are ints or longs strncpy(inbuffer,line,DEH_BUFFERMAX); while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; if (!*inbuffer) break; // killough 11/98 if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok { if (fpout) fdprintf(fpout,"Bad data pair in '%s'\n",inbuffer); continue; } // Otherwise it's ok if (fpout) fdprintf(fpout,"Processing Misc item '%s'\n", key); if (!strcasecmp(key,deh_misc[0])) // Initial Health initial_health = (int)value; else if (!strcasecmp(key,deh_misc[1])) // Initial Bullets initial_bullets = (int)value; else if (!strcasecmp(key,deh_misc[2])) // Max Health maxhealth = (int)value; else if (!strcasecmp(key,deh_misc[3])) // Max Armor max_armor = (int)value; else if (!strcasecmp(key,deh_misc[4])) // Green Armor Class green_armor_class = (int)value; else if (!strcasecmp(key,deh_misc[5])) // Blue Armor Class blue_armor_class = (int)value; else if (!strcasecmp(key,deh_misc[6])) // Max Soulsphere max_soul = (int)value; else if (!strcasecmp(key,deh_misc[7])) // Soulsphere Health soul_health = (int)value; else if (!strcasecmp(key,deh_misc[8])) // Megasphere Health mega_health = (int)value; else if (!strcasecmp(key,deh_misc[9])) // God Mode Health god_health = (int)value; else if (!strcasecmp(key,deh_misc[10])) // IDFA Armor idfa_armor = (int)value; else if (!strcasecmp(key,deh_misc[11])) // IDFA Armor Class idfa_armor_class = (int)value; else if (!strcasecmp(key,deh_misc[12])) // IDKFA Armor idkfa_armor = (int)value; else if (!strcasecmp(key,deh_misc[13])) // IDKFA Armor Class idkfa_armor_class = (int)value; else if (!strcasecmp(key,deh_misc[14])) // BFG Cells/Shot bfgcells = (int)value; else if (!strcasecmp(key,deh_misc[15])) // Monsters Infight /* No such switch in DOOM - nop */ ; else if (fpout) fdprintf(fpout, "Invalid misc item string index for '%s'\n",key); } return; } // ==================================================================== // deh_procText // Purpose: Handle DEH Text block // Notes: We look things up in the current information and if found // we replace it. At the same time we write the new and // improved BEX syntax to the log file for future use. // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procText(DEHFILE *fpin, int fpout, char *line) { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX*2]; // can't use line -- double size buffer too. int i; // loop variable int fromlen, tolen; // as specified on the text block line int usedlen; // shorter of fromlen and tolen if not matched boolean found = FALSE; // to allow early exit once found char* line2 = NULL; // duplicate line for rerouting // Ty 04/11/98 - Included file may have NOTEXT skip flag set if (includenotext) // flag to skip included deh-style text { if (fpout) fdprintf(fpout, "Skipped text block because of notext directive\n"); strcpy(inbuffer,line); while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' ')) dehfgets(inbuffer, sizeof(inbuffer), fpin); // skip block // Ty 05/17/98 - don't care if this fails return; // ************** Early return } // killough 8/98: allow hex numbers in input: sscanf(line,"%s %d %d",key,&fromlen,&tolen); if (fpout) fdprintf(fpout, "Processing Text (key=%s, from=%d, to=%d)\n", key, fromlen, tolen); // killough 10/98: fix incorrect usage of feof { int c, totlen = 0; while (totlen < fromlen + tolen && (c = dehfgetc(fpin)) != EOF) inbuffer[totlen++] = c; inbuffer[totlen]='\0'; } // if the from and to are 4, this may be a sprite rename. Check it // against the array and process it as such if it matches. Remember // that the original names are (and should remain) uppercase. // Future: this will be from a separate [SPRITES] block. if (fromlen==4 && tolen==4) { i=0; while (sprnames[i]) // null terminated list in info.c //jff 3/19/98 { //check pointer if (!strncasecmp(sprnames[i],inbuffer,fromlen)) //not first char { if (fpout) fdprintf(fpout, "Changing name of sprite at index %d from %s to %*s\n", i,sprnames[i],tolen,&inbuffer[fromlen]); // Ty 03/18/98 - not using strdup because length is fixed // killough 10/98: but it's an array of pointers, so we must // use strdup unless we redeclare sprnames and change all else { // CPhipps - fix constness problem char *s; sprnames[i] = s = strdup(sprnames[i]); strncpy(s,&inbuffer[fromlen],tolen); } found = TRUE; break; // only one will match--quit early } ++i; // next array element } } else if (fromlen < 7 && tolen < 7) // lengths of music and sfx are 6 or shorter { usedlen = (fromlen < tolen) ? fromlen : tolen; if (fromlen != tolen) if (fpout) fdprintf(fpout, "Warning: Mismatched lengths from=%d, to=%d, used %d\n", fromlen, tolen, usedlen); // Try sound effects entries - see sounds.c for (i=1; i 12) ? "..." : "",fromlen,tolen); if ((size_t)fromlen <= strlen(inbuffer)) { line2 = strdup(&inbuffer[fromlen]); inbuffer[fromlen] = '\0'; } deh_procStringSub(NULL, inbuffer, line2, fpout); } free(line2); // may be NULL, ignored by free() return; } void deh_procError(DEHFILE *fpin, int fpout, char *line) { (void)fpin; char inbuffer[DEH_BUFFERMAX]; strncpy(inbuffer,line,DEH_BUFFERMAX); if (fpout) fdprintf(fpout,"Unmatched Block: '%s'\n",inbuffer); return; } // ==================================================================== // deh_procStrings // Purpose: Handle BEX [STRINGS] extension // Args: fpin -- input file stream // fpout -- output file stream (DEHOUT.TXT) // line -- current line in file to process // Returns: void // void deh_procStrings(DEHFILE *fpin, int fpout, char *line) { char key[DEH_MAXKEYLEN]; char inbuffer[DEH_BUFFERMAX]; uint_64_t value; // All deh values are ints or longs char *strval; // holds the string value of the line static int maxstrlen = 128; // maximum string length, bumped 128 at // a time as needed // holds the final result of the string after concatenation static char *holdstring = NULL; boolean found = false; // looking for string continuation if (fpout) fdprintf(fpout,"Processing extended string substitution\n"); if (!holdstring) holdstring = malloc(maxstrlen*sizeof(*holdstring)); *holdstring = '\0'; // empty string to start with strncpy(inbuffer,line,DEH_BUFFERMAX); // Ty 04/24/98 - have to allow inbuffer to start with a blank for // the continuations of C1TEXT etc. while (!dehfeof(fpin) && *inbuffer) /* && (*inbuffer != ' ') */ { if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break; if (*inbuffer == '#') continue; // skip comment lines if (!*inbuffer) break; // killough 11/98 if (!*holdstring) // first one--get the key { if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok { if (fpout) fdprintf(fpout,"Bad data pair in '%s'\n",inbuffer); continue; } } while (strlen(holdstring) + strlen(inbuffer) > (size_t)maxstrlen) // Ty03/29/98 - fix stupid error { // killough 11/98: allocate enough the first time maxstrlen += strlen(holdstring) + strlen(inbuffer) - maxstrlen; if (fpout) fdprintf(fpout, "* increased buffer from to %d for buffer size %d\n", maxstrlen,(int)strlen(inbuffer)); holdstring = realloc(holdstring,maxstrlen*sizeof(*holdstring)); } // concatenate the whole buffer if continuation or the value iffirst strcat(holdstring,ptr_lstrip(((*holdstring) ? inbuffer : strval))); rstrip(holdstring); // delete any trailing blanks past the backslash // note that blanks before the backslash will be concatenated // but ones at the beginning of the next line will not, allowing // indentation in the file to read well without affecting the // string itself. if (holdstring[strlen(holdstring)-1] == '\\') { holdstring[strlen(holdstring)-1] = '\0'; continue; // ready to concatenate } if (*holdstring) // didn't have a backslash, trap above would catch that { // go process the current string found = deh_procStringSub(key, NULL, holdstring, fpout); // supply keyand not search string if (!found) if (fpout) fdprintf(fpout, "Invalid string key '%s', substitution skipped.\n",key); *holdstring = '\0'; // empty string for the next one } } return; } // ==================================================================== // deh_procStringSub // Purpose: Common string parsing and handling routine for DEH and BEX // Args: key -- place to put the mnemonic for the string if found // lookfor -- original value string to look for // newstring -- string to put in its place if found // fpout -- file stream pointer for log file (DEHOUT.TXT) // Returns: boolean: True if string found, false if not // boolean deh_procStringSub(char *key, char *lookfor, char *newstring, int fpout) { boolean found; // loop exit flag int i; // looper found = false; for (i=0;i '%s'\n",key,newstring); if (!key) if (fpout) fdprintf(fpout, "Assigned '%s%s' to'%s%s' at key %s\n", lookfor, (strlen(lookfor) > 12) ? "..." : "", newstring, (strlen(newstring) > 12) ? "..." :"", deh_strlookup[i].lookup); if (!key) // must have passed an old style string so showBEX if (fpout) fdprintf(fpout, "*BEX FORMAT:\n%s = %s\n*END BEX\n", deh_strlookup[i].lookup, dehReformatStr(newstring)); break; } } if (!found) if (fpout) fdprintf(fpout, "Could not find '%s'\n",key ? key: lookfor); return found; } // ==================================================================== // General utility function(s) // ==================================================================== // ==================================================================== // dehReformatStr // Purpose: Convert a string into a continuous string with embedded // linefeeds for "\n" sequences in the source string // Args: string -- the string to convert // Returns: the converted string (converted in a static buffer) // char *dehReformatStr(char *string) { static char buff[DEH_BUFFERMAX]; // only processing the changed string, // don't need double buffer char *s, *t; s = string; // source t = buff; // target // let's play... while (*s) { if (*s == '\n') ++s, *t++ = '\\', *t++ = 'n', *t++ = '\\', *t++='\n'; else *t++ = *s++; } *t = '\0'; return buff; } // ==================================================================== // rstrip // Purpose: Strips trailing blanks off a string // Args: s -- the string to work on // Returns: void -- the string is modified in place // void rstrip(char *s) // strip trailing whitespace { char *p = s+strlen(s); // killough 4/4/98: same here while (p > s && isspace(*--p)) // break on first non-whitespace *p='\0'; } // ==================================================================== // ptr_lstrip // Purpose: Points past leading whitespace in a string // Args: s -- the string to work on // Returns: char * pointing to the first nonblank character in the // string. The original string is not changed. // char *ptr_lstrip(char *p) // point past leading whitespace { while (isspace(*p)) p++; return p; } // ==================================================================== // deh_GetData // Purpose: Get a key and data pair from a passed string // Args: s -- the string to be examined // k -- a place to put the key // l -- pointer to a long integer to store the number // strval -- a pointer to the place in s where the number // value comes from. Pass NULL to not use this. // fpout -- stream pointer to output log (DEHOUT.TXT) // Notes: Expects a key phrase, optional space, equal sign, // optional space and a value, mostly an int but treated // as a long just in case. The passed pointer to hold // the key must be DEH_MAXKEYLEN in size. boolean deh_GetData(char *s, char *k, uint_64_t *l, char **strval, int fpout) { (void)fpout; char *t; // current char long val; // to hold value of pair char buffer[DEH_MAXKEYLEN]; // to hold key in progress boolean okrc = TRUE; // assume good unless we have problems int i; // iterator *buffer = '\0'; val = 0; // defaults in case not otherwise set for (i=0, t=s; *t && i < DEH_MAXKEYLEN; t++, i++) { if (*t == '=') break; buffer[i] = *t; // copy it } buffer[--i] = '\0'; // terminate the key before the '=' if (!*t) // end of string with no equal sign { okrc = FALSE; } else { if (!*++t) { val = 0; // in case "thiskey =" with no value okrc = FALSE; } // we've incremented t val = atoi(t);//strtol(t,NULL,0); // killough 8/9/98: allow hex or octal input } // go put the results in the passed pointers *l = val; // may be a faked zero // if spaces between key and equal sign, strip them strcpy(k,ptr_lstrip(buffer)); // could be a zero-length string if (strval != NULL) // pass NULL if you don't want this back *strval = t; // pointer, has to be somewhere in s, // even if pointing at the zero byte. return(okrc); }