1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2004 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *     Dehacked file support
31  *     New for the TeamTNT "Boom" engine
32  *
33  * Author: Ty Halderman, TeamTNT
34  *
35  *--------------------------------------------------------------------*/
36 
37 // killough 5/2/98: fixed headers, removed rendunant external declarations:
38 #include "doomdef.h"
39 #include "doomtype.h"
40 #include "doomstat.h"
41 #include "d_deh.h"
42 #include "sounds.h"
43 #include "info.h"
44 #include "m_cheat.h"
45 #include "p_inter.h"
46 #include "p_enemy.h"
47 #include "g_game.h"
48 #include "d_think.h"
49 #include "w_wad.h"
50 #include "m_argv.h"
51 #include "m_misc.h"
52 #include "e6y.h"//e6y
53 
54 // CPhipps - modify to use logical output routine
55 #include "lprintf.h"
56 
57 #define TRUE 1
58 #define FALSE 0
59 
60 // e6y: for compatibility with BOOM deh parser
deh_strcasecmp(const char * str1,const char * str2)61 int deh_strcasecmp(const char *str1, const char *str2)
62 {
63   if (prboom_comp[PC_BOOM_DEH_PARSER].state &&
64       compatibility_level >= boom_compatibility_compatibility &&
65       compatibility_level <= boom_202_compatibility)
66   {
67     return strcmp(str1, str2);
68   }
69   else
70   {
71     return strcasecmp(str1, str2);
72   }
73 }
deh_getBitsDelims(void)74 const char * deh_getBitsDelims(void)
75 {
76   if (prboom_comp[PC_BOOM_DEH_PARSER].state &&
77       compatibility_level >= boom_compatibility_compatibility &&
78       compatibility_level <= boom_202_compatibility)
79   {
80     return "+";
81   }
82   else
83   {
84     return ",+| \t\f\r";
85   }
86 }
87 
88 // If false, dehacked cheat replacements are ignored.
89 int deh_apply_cheats = true;
90 
91 // killough 10/98: new functions, to allow processing DEH files in-memory
92 // (e.g. from wads)
93 
94 typedef struct {
95   /* cph 2006/08/06 -
96    * if lump != NULL, lump is the start of the lump,
97    * inp is the current read pos. */
98   const byte *inp, *lump;
99   long size;
100   /* else, !lump, and f is the file being read */
101   FILE* f;
102 } DEHFILE;
103 
104 // killough 10/98: emulate IO whether input really comes from a file or not
105 
dehfgets(char * buf,size_t n,DEHFILE * fp)106 static char *dehfgets(char *buf, size_t n, DEHFILE *fp)
107 {
108   if (!fp->lump)                                     // If this is a real file,
109     return (fgets)(buf, n, fp->f);                   // return regular fgets
110   if (!n || !*fp->inp || fp->size<=0)                // If no more characters
111     return NULL;
112   if (n==1)
113     fp->size--, *buf = *fp->inp++;
114   else
115     {                                                // copy buffer
116       char *p = buf;
117       while (n>1 && *fp->inp && fp->size &&
118              (n--, fp->size--, *p++ = *fp->inp++) != '\n')
119         ;
120       *p = 0;
121     }
122   return buf;                                        // Return buffer pointer
123 }
124 
dehfeof(DEHFILE * fp)125 static int dehfeof(DEHFILE *fp)
126 {
127   return !fp->lump ? feof(fp->f) : !*fp->inp || fp->size<=0;
128 }
129 
dehfgetc(DEHFILE * fp)130 static int dehfgetc(DEHFILE *fp)
131 {
132   return !fp->lump ? fgetc(fp->f) : fp->size > 0 ?
133     fp->size--, *fp->inp++ : EOF;
134 }
135 
136 // haleyjd 9/22/99
137 int HelperThing = -1;     // in P_SpawnMapThing to substitute helper thing
138 
139 // variables used in other routines
140 dboolean deh_pars = FALSE; // in wi_stuff to allow pars in modified games
141 
142 // #include "d_deh.h" -- we don't do that here but we declare the
143 // variables.  This externalizes everything that there is a string
144 // set for in the language files.  See d_deh.h for detailed comments,
145 // original English values etc.  These are set to the macro values,
146 // which are set by D_ENGLSH.H or D_FRENCH.H(etc).  BEX files are a
147 // better way of changing these strings globally by language.
148 
149 // ====================================================================
150 // Any of these can be changed using the bex extensions
151 #include "dstrings.h"  // to get the initial values
152 /* cph - const's
153  *     - removed redundant "can't XXX in a netgame" strings.
154  */
155 const char *s_D_DEVSTR    = D_DEVSTR;
156 const char *s_D_CDROM     = D_CDROM;
157 const char *s_PRESSKEY    = PRESSKEY;
158 const char *s_PRESSYN     = PRESSYN;
159 const char *s_QUITMSG     = QUITMSG;
160 const char *s_QSAVESPOT   = QSAVESPOT; // PRESSKEY;
161 const char *s_SAVEDEAD    = SAVEDEAD;  // PRESSKEY; // remove duplicate y/n
162 const char *s_QSPROMPT    = QSPROMPT;  // PRESSYN;
163 const char *s_QLPROMPT    = QLPROMPT;  // PRESSYN;
164 const char *s_NEWGAME     = NEWGAME;   // PRESSKEY;
165 const char *s_RESTARTLEVEL= RESTARTLEVEL; // PRESSYN;
166 const char *s_NIGHTMARE   = NIGHTMARE; // PRESSYN;
167 const char *s_SWSTRING    = SWSTRING;  // PRESSKEY;
168 const char *s_MSGOFF      = MSGOFF;
169 const char *s_MSGON       = MSGON;
170 const char *s_NETEND      = NETEND;    // PRESSKEY;
171 const char *s_ENDGAME     = ENDGAME;   // PRESSYN; // killough 4/4/98: end
172 const char *s_DOSY        = DOSY;
173 const char *s_DETAILHI    = DETAILHI;
174 const char *s_DETAILLO    = DETAILLO;
175 const char *s_GAMMALVL0   = GAMMALVL0;
176 const char *s_GAMMALVL1   = GAMMALVL1;
177 const char *s_GAMMALVL2   = GAMMALVL2;
178 const char *s_GAMMALVL3   = GAMMALVL3;
179 const char *s_GAMMALVL4   = GAMMALVL4;
180 const char *s_EMPTYSTRING = EMPTYSTRING;
181 const char *s_GOTARMOR    = GOTARMOR;
182 const char *s_GOTMEGA     = GOTMEGA;
183 const char *s_GOTHTHBONUS = GOTHTHBONUS;
184 const char *s_GOTARMBONUS = GOTARMBONUS;
185 const char *s_GOTSTIM     = GOTSTIM;
186 const char *s_GOTMEDINEED = GOTMEDINEED;
187 const char *s_GOTMEDIKIT  = GOTMEDIKIT;
188 const char *s_GOTSUPER    = GOTSUPER;
189 const char *s_GOTBLUECARD = GOTBLUECARD;
190 const char *s_GOTYELWCARD = GOTYELWCARD;
191 const char *s_GOTREDCARD  = GOTREDCARD;
192 const char *s_GOTBLUESKUL = GOTBLUESKUL;
193 const char *s_GOTYELWSKUL = GOTYELWSKUL;
194 const char *s_GOTREDSKULL = GOTREDSKULL;
195 const char *s_GOTINVUL    = GOTINVUL;
196 const char *s_GOTBERSERK  = GOTBERSERK;
197 const char *s_GOTINVIS    = GOTINVIS;
198 const char *s_GOTSUIT     = GOTSUIT;
199 const char *s_GOTMAP      = GOTMAP;
200 const char *s_GOTVISOR    = GOTVISOR;
201 const char *s_GOTMSPHERE  = GOTMSPHERE;
202 const char *s_GOTCLIP     = GOTCLIP;
203 const char *s_GOTCLIPBOX  = GOTCLIPBOX;
204 const char *s_GOTROCKET   = GOTROCKET;
205 const char *s_GOTROCKBOX  = GOTROCKBOX;
206 const char *s_GOTCELL     = GOTCELL;
207 const char *s_GOTCELLBOX  = GOTCELLBOX;
208 const char *s_GOTSHELLS   = GOTSHELLS;
209 const char *s_GOTSHELLBOX = GOTSHELLBOX;
210 const char *s_GOTBACKPACK = GOTBACKPACK;
211 const char *s_GOTBFG9000  = GOTBFG9000;
212 const char *s_GOTCHAINGUN = GOTCHAINGUN;
213 const char *s_GOTCHAINSAW = GOTCHAINSAW;
214 const char *s_GOTLAUNCHER = GOTLAUNCHER;
215 const char *s_GOTPLASMA   = GOTPLASMA;
216 const char *s_GOTSHOTGUN  = GOTSHOTGUN;
217 const char *s_GOTSHOTGUN2 = GOTSHOTGUN2;
218 const char *s_PD_BLUEO    = PD_BLUEO;
219 const char *s_PD_REDO     = PD_REDO;
220 const char *s_PD_YELLOWO  = PD_YELLOWO;
221 const char *s_PD_BLUEK    = PD_BLUEK;
222 const char *s_PD_REDK     = PD_REDK;
223 const char *s_PD_YELLOWK  = PD_YELLOWK;
224 const char *s_PD_BLUEC    = PD_BLUEC;
225 const char *s_PD_REDC     = PD_REDC;
226 const char *s_PD_YELLOWC  = PD_YELLOWC;
227 const char *s_PD_BLUES    = PD_BLUES;
228 const char *s_PD_REDS     = PD_REDS;
229 const char *s_PD_YELLOWS  = PD_YELLOWS;
230 const char *s_PD_ANY      = PD_ANY;
231 const char *s_PD_ALL3     = PD_ALL3;
232 const char *s_PD_ALL6     = PD_ALL6;
233 const char *s_GGSAVED     = GGSAVED;
234 const char *s_HUSTR_MSGU  = HUSTR_MSGU;
235 const char *s_HUSTR_E1M1  = HUSTR_E1M1;
236 const char *s_HUSTR_E1M2  = HUSTR_E1M2;
237 const char *s_HUSTR_E1M3  = HUSTR_E1M3;
238 const char *s_HUSTR_E1M4  = HUSTR_E1M4;
239 const char *s_HUSTR_E1M5  = HUSTR_E1M5;
240 const char *s_HUSTR_E1M6  = HUSTR_E1M6;
241 const char *s_HUSTR_E1M7  = HUSTR_E1M7;
242 const char *s_HUSTR_E1M8  = HUSTR_E1M8;
243 const char *s_HUSTR_E1M9  = HUSTR_E1M9;
244 const char *s_HUSTR_E2M1  = HUSTR_E2M1;
245 const char *s_HUSTR_E2M2  = HUSTR_E2M2;
246 const char *s_HUSTR_E2M3  = HUSTR_E2M3;
247 const char *s_HUSTR_E2M4  = HUSTR_E2M4;
248 const char *s_HUSTR_E2M5  = HUSTR_E2M5;
249 const char *s_HUSTR_E2M6  = HUSTR_E2M6;
250 const char *s_HUSTR_E2M7  = HUSTR_E2M7;
251 const char *s_HUSTR_E2M8  = HUSTR_E2M8;
252 const char *s_HUSTR_E2M9  = HUSTR_E2M9;
253 const char *s_HUSTR_E3M1  = HUSTR_E3M1;
254 const char *s_HUSTR_E3M2  = HUSTR_E3M2;
255 const char *s_HUSTR_E3M3  = HUSTR_E3M3;
256 const char *s_HUSTR_E3M4  = HUSTR_E3M4;
257 const char *s_HUSTR_E3M5  = HUSTR_E3M5;
258 const char *s_HUSTR_E3M6  = HUSTR_E3M6;
259 const char *s_HUSTR_E3M7  = HUSTR_E3M7;
260 const char *s_HUSTR_E3M8  = HUSTR_E3M8;
261 const char *s_HUSTR_E3M9  = HUSTR_E3M9;
262 const char *s_HUSTR_E4M1  = HUSTR_E4M1;
263 const char *s_HUSTR_E4M2  = HUSTR_E4M2;
264 const char *s_HUSTR_E4M3  = HUSTR_E4M3;
265 const char *s_HUSTR_E4M4  = HUSTR_E4M4;
266 const char *s_HUSTR_E4M5  = HUSTR_E4M5;
267 const char *s_HUSTR_E4M6  = HUSTR_E4M6;
268 const char *s_HUSTR_E4M7  = HUSTR_E4M7;
269 const char *s_HUSTR_E4M8  = HUSTR_E4M8;
270 const char *s_HUSTR_E4M9  = HUSTR_E4M9;
271 const char *s_HUSTR_1     = HUSTR_1;
272 const char *s_HUSTR_2     = HUSTR_2;
273 const char *s_HUSTR_3     = HUSTR_3;
274 const char *s_HUSTR_4     = HUSTR_4;
275 const char *s_HUSTR_5     = HUSTR_5;
276 const char *s_HUSTR_6     = HUSTR_6;
277 const char *s_HUSTR_7     = HUSTR_7;
278 const char *s_HUSTR_8     = HUSTR_8;
279 const char *s_HUSTR_9     = HUSTR_9;
280 const char *s_HUSTR_10    = HUSTR_10;
281 const char *s_HUSTR_11    = HUSTR_11;
282 const char *s_HUSTR_12    = HUSTR_12;
283 const char *s_HUSTR_13    = HUSTR_13;
284 const char *s_HUSTR_14    = HUSTR_14;
285 const char *s_HUSTR_15    = HUSTR_15;
286 const char *s_HUSTR_16    = HUSTR_16;
287 const char *s_HUSTR_17    = HUSTR_17;
288 const char *s_HUSTR_18    = HUSTR_18;
289 const char *s_HUSTR_19    = HUSTR_19;
290 const char *s_HUSTR_20    = HUSTR_20;
291 const char *s_HUSTR_21    = HUSTR_21;
292 const char *s_HUSTR_22    = HUSTR_22;
293 const char *s_HUSTR_23    = HUSTR_23;
294 const char *s_HUSTR_24    = HUSTR_24;
295 const char *s_HUSTR_25    = HUSTR_25;
296 const char *s_HUSTR_26    = HUSTR_26;
297 const char *s_HUSTR_27    = HUSTR_27;
298 const char *s_HUSTR_28    = HUSTR_28;
299 const char *s_HUSTR_29    = HUSTR_29;
300 const char *s_HUSTR_30    = HUSTR_30;
301 const char *s_HUSTR_31    = HUSTR_31;
302 const char *s_HUSTR_32    = HUSTR_32;
303 const char *s_PHUSTR_1    = PHUSTR_1;
304 const char *s_PHUSTR_2    = PHUSTR_2;
305 const char *s_PHUSTR_3    = PHUSTR_3;
306 const char *s_PHUSTR_4    = PHUSTR_4;
307 const char *s_PHUSTR_5    = PHUSTR_5;
308 const char *s_PHUSTR_6    = PHUSTR_6;
309 const char *s_PHUSTR_7    = PHUSTR_7;
310 const char *s_PHUSTR_8    = PHUSTR_8;
311 const char *s_PHUSTR_9    = PHUSTR_9;
312 const char *s_PHUSTR_10   = PHUSTR_10;
313 const char *s_PHUSTR_11   = PHUSTR_11;
314 const char *s_PHUSTR_12   = PHUSTR_12;
315 const char *s_PHUSTR_13   = PHUSTR_13;
316 const char *s_PHUSTR_14   = PHUSTR_14;
317 const char *s_PHUSTR_15   = PHUSTR_15;
318 const char *s_PHUSTR_16   = PHUSTR_16;
319 const char *s_PHUSTR_17   = PHUSTR_17;
320 const char *s_PHUSTR_18   = PHUSTR_18;
321 const char *s_PHUSTR_19   = PHUSTR_19;
322 const char *s_PHUSTR_20   = PHUSTR_20;
323 const char *s_PHUSTR_21   = PHUSTR_21;
324 const char *s_PHUSTR_22   = PHUSTR_22;
325 const char *s_PHUSTR_23   = PHUSTR_23;
326 const char *s_PHUSTR_24   = PHUSTR_24;
327 const char *s_PHUSTR_25   = PHUSTR_25;
328 const char *s_PHUSTR_26   = PHUSTR_26;
329 const char *s_PHUSTR_27   = PHUSTR_27;
330 const char *s_PHUSTR_28   = PHUSTR_28;
331 const char *s_PHUSTR_29   = PHUSTR_29;
332 const char *s_PHUSTR_30   = PHUSTR_30;
333 const char *s_PHUSTR_31   = PHUSTR_31;
334 const char *s_PHUSTR_32   = PHUSTR_32;
335 const char *s_THUSTR_1    = THUSTR_1;
336 const char *s_THUSTR_2    = THUSTR_2;
337 const char *s_THUSTR_3    = THUSTR_3;
338 const char *s_THUSTR_4    = THUSTR_4;
339 const char *s_THUSTR_5    = THUSTR_5;
340 const char *s_THUSTR_6    = THUSTR_6;
341 const char *s_THUSTR_7    = THUSTR_7;
342 const char *s_THUSTR_8    = THUSTR_8;
343 const char *s_THUSTR_9    = THUSTR_9;
344 const char *s_THUSTR_10   = THUSTR_10;
345 const char *s_THUSTR_11   = THUSTR_11;
346 const char *s_THUSTR_12   = THUSTR_12;
347 const char *s_THUSTR_13   = THUSTR_13;
348 const char *s_THUSTR_14   = THUSTR_14;
349 const char *s_THUSTR_15   = THUSTR_15;
350 const char *s_THUSTR_16   = THUSTR_16;
351 const char *s_THUSTR_17   = THUSTR_17;
352 const char *s_THUSTR_18   = THUSTR_18;
353 const char *s_THUSTR_19   = THUSTR_19;
354 const char *s_THUSTR_20   = THUSTR_20;
355 const char *s_THUSTR_21   = THUSTR_21;
356 const char *s_THUSTR_22   = THUSTR_22;
357 const char *s_THUSTR_23   = THUSTR_23;
358 const char *s_THUSTR_24   = THUSTR_24;
359 const char *s_THUSTR_25   = THUSTR_25;
360 const char *s_THUSTR_26   = THUSTR_26;
361 const char *s_THUSTR_27   = THUSTR_27;
362 const char *s_THUSTR_28   = THUSTR_28;
363 const char *s_THUSTR_29   = THUSTR_29;
364 const char *s_THUSTR_30   = THUSTR_30;
365 const char *s_THUSTR_31   = THUSTR_31;
366 const char *s_THUSTR_32   = THUSTR_32;
367 const char *s_HUSTR_CHATMACRO1   = HUSTR_CHATMACRO1;
368 const char *s_HUSTR_CHATMACRO2   = HUSTR_CHATMACRO2;
369 const char *s_HUSTR_CHATMACRO3   = HUSTR_CHATMACRO3;
370 const char *s_HUSTR_CHATMACRO4   = HUSTR_CHATMACRO4;
371 const char *s_HUSTR_CHATMACRO5   = HUSTR_CHATMACRO5;
372 const char *s_HUSTR_CHATMACRO6   = HUSTR_CHATMACRO6;
373 const char *s_HUSTR_CHATMACRO7   = HUSTR_CHATMACRO7;
374 const char *s_HUSTR_CHATMACRO8   = HUSTR_CHATMACRO8;
375 const char *s_HUSTR_CHATMACRO9   = HUSTR_CHATMACRO9;
376 const char *s_HUSTR_CHATMACRO0   = HUSTR_CHATMACRO0;
377 const char *s_HUSTR_TALKTOSELF1  = HUSTR_TALKTOSELF1;
378 const char *s_HUSTR_TALKTOSELF2  = HUSTR_TALKTOSELF2;
379 const char *s_HUSTR_TALKTOSELF3  = HUSTR_TALKTOSELF3;
380 const char *s_HUSTR_TALKTOSELF4  = HUSTR_TALKTOSELF4;
381 const char *s_HUSTR_TALKTOSELF5  = HUSTR_TALKTOSELF5;
382 const char *s_HUSTR_MESSAGESENT  = HUSTR_MESSAGESENT;
383 const char *s_HUSTR_PLRGREEN     = HUSTR_PLRGREEN;
384 const char *s_HUSTR_PLRINDIGO    = HUSTR_PLRINDIGO;
385 const char *s_HUSTR_PLRBROWN     = HUSTR_PLRBROWN;
386 const char *s_HUSTR_PLRRED       = HUSTR_PLRRED;
387 const char *s_AMSTR_FOLLOWON     = AMSTR_FOLLOWON;
388 const char *s_AMSTR_FOLLOWOFF    = AMSTR_FOLLOWOFF;
389 const char *s_AMSTR_GRIDON       = AMSTR_GRIDON;
390 const char *s_AMSTR_GRIDOFF      = AMSTR_GRIDOFF;
391 const char *s_AMSTR_MARKEDSPOT   = AMSTR_MARKEDSPOT;
392 const char *s_AMSTR_MARKSCLEARED = AMSTR_MARKSCLEARED;
393 // CPhipps - automap rotate & overlay
394 const char* s_AMSTR_ROTATEON     = AMSTR_ROTATEON;
395 const char* s_AMSTR_ROTATEOFF    = AMSTR_ROTATEOFF;
396 const char* s_AMSTR_OVERLAYON    = AMSTR_OVERLAYON;
397 const char* s_AMSTR_OVERLAYOFF   = AMSTR_OVERLAYOFF;
398 // e6y: textured automap
399 const char* s_AMSTR_TEXTUREDON   = AMSTR_TEXTUREDON;
400 const char* s_AMSTR_TEXTUREDOFF  = AMSTR_TEXTUREDOFF;
401 
402 const char *s_STSTR_MUS          = STSTR_MUS;
403 const char *s_STSTR_NOMUS        = STSTR_NOMUS;
404 const char *s_STSTR_DQDON        = STSTR_DQDON;
405 const char *s_STSTR_DQDOFF       = STSTR_DQDOFF;
406 const char *s_STSTR_KFAADDED     = STSTR_KFAADDED;
407 const char *s_STSTR_FAADDED      = STSTR_FAADDED;
408 const char *s_STSTR_NCON         = STSTR_NCON;
409 const char *s_STSTR_NCOFF        = STSTR_NCOFF;
410 const char *s_STSTR_BEHOLD       = STSTR_BEHOLD;
411 const char *s_STSTR_BEHOLDX      = STSTR_BEHOLDX;
412 const char *s_STSTR_CHOPPERS     = STSTR_CHOPPERS;
413 const char *s_STSTR_CLEV         = STSTR_CLEV;
414 const char *s_STSTR_COMPON       = STSTR_COMPON;
415 const char *s_STSTR_COMPOFF      = STSTR_COMPOFF;
416 const char *s_E1TEXT     = E1TEXT;
417 const char *s_E2TEXT     = E2TEXT;
418 const char *s_E3TEXT     = E3TEXT;
419 const char *s_E4TEXT     = E4TEXT;
420 const char *s_C1TEXT     = C1TEXT;
421 const char *s_C2TEXT     = C2TEXT;
422 const char *s_C3TEXT     = C3TEXT;
423 const char *s_C4TEXT     = C4TEXT;
424 const char *s_C5TEXT     = C5TEXT;
425 const char *s_C6TEXT     = C6TEXT;
426 const char *s_P1TEXT     = P1TEXT;
427 const char *s_P2TEXT     = P2TEXT;
428 const char *s_P3TEXT     = P3TEXT;
429 const char *s_P4TEXT     = P4TEXT;
430 const char *s_P5TEXT     = P5TEXT;
431 const char *s_P6TEXT     = P6TEXT;
432 const char *s_T1TEXT     = T1TEXT;
433 const char *s_T2TEXT     = T2TEXT;
434 const char *s_T3TEXT     = T3TEXT;
435 const char *s_T4TEXT     = T4TEXT;
436 const char *s_T5TEXT     = T5TEXT;
437 const char *s_T6TEXT     = T6TEXT;
438 const char *s_CC_ZOMBIE  = CC_ZOMBIE;
439 const char *s_CC_SHOTGUN = CC_SHOTGUN;
440 const char *s_CC_HEAVY   = CC_HEAVY;
441 const char *s_CC_IMP     = CC_IMP;
442 const char *s_CC_DEMON   = CC_DEMON;
443 const char *s_CC_LOST    = CC_LOST;
444 const char *s_CC_CACO    = CC_CACO;
445 const char *s_CC_HELL    = CC_HELL;
446 const char *s_CC_BARON   = CC_BARON;
447 const char *s_CC_ARACH   = CC_ARACH;
448 const char *s_CC_PAIN    = CC_PAIN;
449 const char *s_CC_REVEN   = CC_REVEN;
450 const char *s_CC_MANCU   = CC_MANCU;
451 const char *s_CC_ARCH    = CC_ARCH;
452 const char *s_CC_SPIDER  = CC_SPIDER;
453 const char *s_CC_CYBER   = CC_CYBER;
454 const char *s_CC_HERO    = CC_HERO;
455 // Ty 03/30/98 - new substitutions for background textures
456 //               during int screens
457 const char *bgflatE1     = "FLOOR4_8"; // end of DOOM Episode 1
458 const char *bgflatE2     = "SFLR6_1";  // end of DOOM Episode 2
459 const char *bgflatE3     = "MFLR8_4";  // end of DOOM Episode 3
460 const char *bgflatE4     = "MFLR8_3";  // end of DOOM Episode 4
461 const char *bgflat06     = "SLIME16";  // DOOM2 after MAP06
462 const char *bgflat11     = "RROCK14";  // DOOM2 after MAP11
463 const char *bgflat20     = "RROCK07";  // DOOM2 after MAP20
464 const char *bgflat30     = "RROCK17";  // DOOM2 after MAP30
465 const char *bgflat15     = "RROCK13";  // DOOM2 going MAP15 to MAP31
466 const char *bgflat31     = "RROCK19";  // DOOM2 going MAP31 to MAP32
467 const char *bgcastcall   = "BOSSBACK"; // Panel behind cast call
468 
469 const char *startup1     = "";  // blank lines are default and are not printed
470 const char *startup2     = "";
471 const char *startup3     = "";
472 const char *startup4     = "";
473 const char *startup5     = "";
474 
475 /* Ty 05/03/98 - externalized
476  * cph - updated for prboom */
477 const char *savegamename = PACKAGE"-savegame";
478 
479 // end d_deh.h variable declarations
480 // ====================================================================
481 
482 // Do this for a lookup--the pointer (loaded above) is cross-referenced
483 // to a string key that is the same as the define above.  We will use
484 // strdups to set these new values that we read from the file, orphaning
485 // the original value set above.
486 
487 // CPhipps - make strings pointed to const
488 typedef struct {
489   const char **ppstr;  // doubly indirect pointer to string
490   const char *lookup;  // pointer to lookup string name
491   const char *orig;
492 } deh_strs;
493 
494 /* CPhipps - const
495  *         - removed redundant "Can't XXX in a netgame" strings
496  */
497 static deh_strs deh_strlookup[] = {
498   {&s_D_DEVSTR,"D_DEVSTR"},
499   {&s_D_CDROM,"D_CDROM"},
500   {&s_PRESSKEY,"PRESSKEY"},
501   {&s_PRESSYN,"PRESSYN"},
502   {&s_QUITMSG,"QUITMSG"},
503   {&s_QSAVESPOT,"QSAVESPOT"},
504   {&s_SAVEDEAD,"SAVEDEAD"},
505   /* cph - disabled to prevent format string attacks in WAD files
506   {&s_QSPROMPT,"QSPROMPT"},
507   {&s_QLPROMPT,"QLPROMPT"},*/
508   {&s_NEWGAME,"NEWGAME"},
509   {&s_RESTARTLEVEL,"RESTARTLEVEL"},
510   {&s_NIGHTMARE,"NIGHTMARE"},
511   {&s_SWSTRING,"SWSTRING"},
512   {&s_MSGOFF,"MSGOFF"},
513   {&s_MSGON,"MSGON"},
514   {&s_NETEND,"NETEND"},
515   {&s_ENDGAME,"ENDGAME"},
516   {&s_DOSY,"DOSY"},
517   {&s_DETAILHI,"DETAILHI"},
518   {&s_DETAILLO,"DETAILLO"},
519   {&s_GAMMALVL0,"GAMMALVL0"},
520   {&s_GAMMALVL1,"GAMMALVL1"},
521   {&s_GAMMALVL2,"GAMMALVL2"},
522   {&s_GAMMALVL3,"GAMMALVL3"},
523   {&s_GAMMALVL4,"GAMMALVL4"},
524   {&s_EMPTYSTRING,"EMPTYSTRING"},
525   {&s_GOTARMOR,"GOTARMOR"},
526   {&s_GOTMEGA,"GOTMEGA"},
527   {&s_GOTHTHBONUS,"GOTHTHBONUS"},
528   {&s_GOTARMBONUS,"GOTARMBONUS"},
529   {&s_GOTSTIM,"GOTSTIM"},
530   {&s_GOTMEDINEED,"GOTMEDINEED"},
531   {&s_GOTMEDIKIT,"GOTMEDIKIT"},
532   {&s_GOTSUPER,"GOTSUPER"},
533   {&s_GOTBLUECARD,"GOTBLUECARD"},
534   {&s_GOTYELWCARD,"GOTYELWCARD"},
535   {&s_GOTREDCARD,"GOTREDCARD"},
536   {&s_GOTBLUESKUL,"GOTBLUESKUL"},
537   {&s_GOTYELWSKUL,"GOTYELWSKUL"},
538   {&s_GOTREDSKULL,"GOTREDSKULL"},
539   {&s_GOTINVUL,"GOTINVUL"},
540   {&s_GOTBERSERK,"GOTBERSERK"},
541   {&s_GOTINVIS,"GOTINVIS"},
542   {&s_GOTSUIT,"GOTSUIT"},
543   {&s_GOTMAP,"GOTMAP"},
544   {&s_GOTVISOR,"GOTVISOR"},
545   {&s_GOTMSPHERE,"GOTMSPHERE"},
546   {&s_GOTCLIP,"GOTCLIP"},
547   {&s_GOTCLIPBOX,"GOTCLIPBOX"},
548   {&s_GOTROCKET,"GOTROCKET"},
549   {&s_GOTROCKBOX,"GOTROCKBOX"},
550   {&s_GOTCELL,"GOTCELL"},
551   {&s_GOTCELLBOX,"GOTCELLBOX"},
552   {&s_GOTSHELLS,"GOTSHELLS"},
553   {&s_GOTSHELLBOX,"GOTSHELLBOX"},
554   {&s_GOTBACKPACK,"GOTBACKPACK"},
555   {&s_GOTBFG9000,"GOTBFG9000"},
556   {&s_GOTCHAINGUN,"GOTCHAINGUN"},
557   {&s_GOTCHAINSAW,"GOTCHAINSAW"},
558   {&s_GOTLAUNCHER,"GOTLAUNCHER"},
559   {&s_GOTPLASMA,"GOTPLASMA"},
560   {&s_GOTSHOTGUN,"GOTSHOTGUN"},
561   {&s_GOTSHOTGUN2,"GOTSHOTGUN2"},
562   {&s_PD_BLUEO,"PD_BLUEO"},
563   {&s_PD_REDO,"PD_REDO"},
564   {&s_PD_YELLOWO,"PD_YELLOWO"},
565   {&s_PD_BLUEK,"PD_BLUEK"},
566   {&s_PD_REDK,"PD_REDK"},
567   {&s_PD_YELLOWK,"PD_YELLOWK"},
568   {&s_PD_BLUEC,"PD_BLUEC"},
569   {&s_PD_REDC,"PD_REDC"},
570   {&s_PD_YELLOWC,"PD_YELLOWC"},
571   {&s_PD_BLUES,"PD_BLUES"},
572   {&s_PD_REDS,"PD_REDS"},
573   {&s_PD_YELLOWS,"PD_YELLOWS"},
574   {&s_PD_ANY,"PD_ANY"},
575   {&s_PD_ALL3,"PD_ALL3"},
576   {&s_PD_ALL6,"PD_ALL6"},
577   {&s_GGSAVED,"GGSAVED"},
578   {&s_HUSTR_MSGU,"HUSTR_MSGU"},
579   {&s_HUSTR_E1M1,"HUSTR_E1M1"},
580   {&s_HUSTR_E1M2,"HUSTR_E1M2"},
581   {&s_HUSTR_E1M3,"HUSTR_E1M3"},
582   {&s_HUSTR_E1M4,"HUSTR_E1M4"},
583   {&s_HUSTR_E1M5,"HUSTR_E1M5"},
584   {&s_HUSTR_E1M6,"HUSTR_E1M6"},
585   {&s_HUSTR_E1M7,"HUSTR_E1M7"},
586   {&s_HUSTR_E1M8,"HUSTR_E1M8"},
587   {&s_HUSTR_E1M9,"HUSTR_E1M9"},
588   {&s_HUSTR_E2M1,"HUSTR_E2M1"},
589   {&s_HUSTR_E2M2,"HUSTR_E2M2"},
590   {&s_HUSTR_E2M3,"HUSTR_E2M3"},
591   {&s_HUSTR_E2M4,"HUSTR_E2M4"},
592   {&s_HUSTR_E2M5,"HUSTR_E2M5"},
593   {&s_HUSTR_E2M6,"HUSTR_E2M6"},
594   {&s_HUSTR_E2M7,"HUSTR_E2M7"},
595   {&s_HUSTR_E2M8,"HUSTR_E2M8"},
596   {&s_HUSTR_E2M9,"HUSTR_E2M9"},
597   {&s_HUSTR_E3M1,"HUSTR_E3M1"},
598   {&s_HUSTR_E3M2,"HUSTR_E3M2"},
599   {&s_HUSTR_E3M3,"HUSTR_E3M3"},
600   {&s_HUSTR_E3M4,"HUSTR_E3M4"},
601   {&s_HUSTR_E3M5,"HUSTR_E3M5"},
602   {&s_HUSTR_E3M6,"HUSTR_E3M6"},
603   {&s_HUSTR_E3M7,"HUSTR_E3M7"},
604   {&s_HUSTR_E3M8,"HUSTR_E3M8"},
605   {&s_HUSTR_E3M9,"HUSTR_E3M9"},
606   {&s_HUSTR_E4M1,"HUSTR_E4M1"},
607   {&s_HUSTR_E4M2,"HUSTR_E4M2"},
608   {&s_HUSTR_E4M3,"HUSTR_E4M3"},
609   {&s_HUSTR_E4M4,"HUSTR_E4M4"},
610   {&s_HUSTR_E4M5,"HUSTR_E4M5"},
611   {&s_HUSTR_E4M6,"HUSTR_E4M6"},
612   {&s_HUSTR_E4M7,"HUSTR_E4M7"},
613   {&s_HUSTR_E4M8,"HUSTR_E4M8"},
614   {&s_HUSTR_E4M9,"HUSTR_E4M9"},
615   {&s_HUSTR_1,"HUSTR_1"},
616   {&s_HUSTR_2,"HUSTR_2"},
617   {&s_HUSTR_3,"HUSTR_3"},
618   {&s_HUSTR_4,"HUSTR_4"},
619   {&s_HUSTR_5,"HUSTR_5"},
620   {&s_HUSTR_6,"HUSTR_6"},
621   {&s_HUSTR_7,"HUSTR_7"},
622   {&s_HUSTR_8,"HUSTR_8"},
623   {&s_HUSTR_9,"HUSTR_9"},
624   {&s_HUSTR_10,"HUSTR_10"},
625   {&s_HUSTR_11,"HUSTR_11"},
626   {&s_HUSTR_12,"HUSTR_12"},
627   {&s_HUSTR_13,"HUSTR_13"},
628   {&s_HUSTR_14,"HUSTR_14"},
629   {&s_HUSTR_15,"HUSTR_15"},
630   {&s_HUSTR_16,"HUSTR_16"},
631   {&s_HUSTR_17,"HUSTR_17"},
632   {&s_HUSTR_18,"HUSTR_18"},
633   {&s_HUSTR_19,"HUSTR_19"},
634   {&s_HUSTR_20,"HUSTR_20"},
635   {&s_HUSTR_21,"HUSTR_21"},
636   {&s_HUSTR_22,"HUSTR_22"},
637   {&s_HUSTR_23,"HUSTR_23"},
638   {&s_HUSTR_24,"HUSTR_24"},
639   {&s_HUSTR_25,"HUSTR_25"},
640   {&s_HUSTR_26,"HUSTR_26"},
641   {&s_HUSTR_27,"HUSTR_27"},
642   {&s_HUSTR_28,"HUSTR_28"},
643   {&s_HUSTR_29,"HUSTR_29"},
644   {&s_HUSTR_30,"HUSTR_30"},
645   {&s_HUSTR_31,"HUSTR_31"},
646   {&s_HUSTR_32,"HUSTR_32"},
647   {&s_PHUSTR_1,"PHUSTR_1"},
648   {&s_PHUSTR_2,"PHUSTR_2"},
649   {&s_PHUSTR_3,"PHUSTR_3"},
650   {&s_PHUSTR_4,"PHUSTR_4"},
651   {&s_PHUSTR_5,"PHUSTR_5"},
652   {&s_PHUSTR_6,"PHUSTR_6"},
653   {&s_PHUSTR_7,"PHUSTR_7"},
654   {&s_PHUSTR_8,"PHUSTR_8"},
655   {&s_PHUSTR_9,"PHUSTR_9"},
656   {&s_PHUSTR_10,"PHUSTR_10"},
657   {&s_PHUSTR_11,"PHUSTR_11"},
658   {&s_PHUSTR_12,"PHUSTR_12"},
659   {&s_PHUSTR_13,"PHUSTR_13"},
660   {&s_PHUSTR_14,"PHUSTR_14"},
661   {&s_PHUSTR_15,"PHUSTR_15"},
662   {&s_PHUSTR_16,"PHUSTR_16"},
663   {&s_PHUSTR_17,"PHUSTR_17"},
664   {&s_PHUSTR_18,"PHUSTR_18"},
665   {&s_PHUSTR_19,"PHUSTR_19"},
666   {&s_PHUSTR_20,"PHUSTR_20"},
667   {&s_PHUSTR_21,"PHUSTR_21"},
668   {&s_PHUSTR_22,"PHUSTR_22"},
669   {&s_PHUSTR_23,"PHUSTR_23"},
670   {&s_PHUSTR_24,"PHUSTR_24"},
671   {&s_PHUSTR_25,"PHUSTR_25"},
672   {&s_PHUSTR_26,"PHUSTR_26"},
673   {&s_PHUSTR_27,"PHUSTR_27"},
674   {&s_PHUSTR_28,"PHUSTR_28"},
675   {&s_PHUSTR_29,"PHUSTR_29"},
676   {&s_PHUSTR_30,"PHUSTR_30"},
677   {&s_PHUSTR_31,"PHUSTR_31"},
678   {&s_PHUSTR_32,"PHUSTR_32"},
679   {&s_THUSTR_1,"THUSTR_1"},
680   {&s_THUSTR_2,"THUSTR_2"},
681   {&s_THUSTR_3,"THUSTR_3"},
682   {&s_THUSTR_4,"THUSTR_4"},
683   {&s_THUSTR_5,"THUSTR_5"},
684   {&s_THUSTR_6,"THUSTR_6"},
685   {&s_THUSTR_7,"THUSTR_7"},
686   {&s_THUSTR_8,"THUSTR_8"},
687   {&s_THUSTR_9,"THUSTR_9"},
688   {&s_THUSTR_10,"THUSTR_10"},
689   {&s_THUSTR_11,"THUSTR_11"},
690   {&s_THUSTR_12,"THUSTR_12"},
691   {&s_THUSTR_13,"THUSTR_13"},
692   {&s_THUSTR_14,"THUSTR_14"},
693   {&s_THUSTR_15,"THUSTR_15"},
694   {&s_THUSTR_16,"THUSTR_16"},
695   {&s_THUSTR_17,"THUSTR_17"},
696   {&s_THUSTR_18,"THUSTR_18"},
697   {&s_THUSTR_19,"THUSTR_19"},
698   {&s_THUSTR_20,"THUSTR_20"},
699   {&s_THUSTR_21,"THUSTR_21"},
700   {&s_THUSTR_22,"THUSTR_22"},
701   {&s_THUSTR_23,"THUSTR_23"},
702   {&s_THUSTR_24,"THUSTR_24"},
703   {&s_THUSTR_25,"THUSTR_25"},
704   {&s_THUSTR_26,"THUSTR_26"},
705   {&s_THUSTR_27,"THUSTR_27"},
706   {&s_THUSTR_28,"THUSTR_28"},
707   {&s_THUSTR_29,"THUSTR_29"},
708   {&s_THUSTR_30,"THUSTR_30"},
709   {&s_THUSTR_31,"THUSTR_31"},
710   {&s_THUSTR_32,"THUSTR_32"},
711   {&s_HUSTR_CHATMACRO1,"HUSTR_CHATMACRO1"},
712   {&s_HUSTR_CHATMACRO2,"HUSTR_CHATMACRO2"},
713   {&s_HUSTR_CHATMACRO3,"HUSTR_CHATMACRO3"},
714   {&s_HUSTR_CHATMACRO4,"HUSTR_CHATMACRO4"},
715   {&s_HUSTR_CHATMACRO5,"HUSTR_CHATMACRO5"},
716   {&s_HUSTR_CHATMACRO6,"HUSTR_CHATMACRO6"},
717   {&s_HUSTR_CHATMACRO7,"HUSTR_CHATMACRO7"},
718   {&s_HUSTR_CHATMACRO8,"HUSTR_CHATMACRO8"},
719   {&s_HUSTR_CHATMACRO9,"HUSTR_CHATMACRO9"},
720   {&s_HUSTR_CHATMACRO0,"HUSTR_CHATMACRO0"},
721   {&s_HUSTR_TALKTOSELF1,"HUSTR_TALKTOSELF1"},
722   {&s_HUSTR_TALKTOSELF2,"HUSTR_TALKTOSELF2"},
723   {&s_HUSTR_TALKTOSELF3,"HUSTR_TALKTOSELF3"},
724   {&s_HUSTR_TALKTOSELF4,"HUSTR_TALKTOSELF4"},
725   {&s_HUSTR_TALKTOSELF5,"HUSTR_TALKTOSELF5"},
726   {&s_HUSTR_MESSAGESENT,"HUSTR_MESSAGESENT"},
727   {&s_HUSTR_PLRGREEN,"HUSTR_PLRGREEN"},
728   {&s_HUSTR_PLRINDIGO,"HUSTR_PLRINDIGO"},
729   {&s_HUSTR_PLRBROWN,"HUSTR_PLRBROWN"},
730   {&s_HUSTR_PLRRED,"HUSTR_PLRRED"},
731   //{c_HUSTR_KEYGREEN,"HUSTR_KEYGREEN"},
732   //{c_HUSTR_KEYINDIGO,"HUSTR_KEYINDIGO"},
733   //{c_HUSTR_KEYBROWN,"HUSTR_KEYBROWN"},
734   //{c_HUSTR_KEYRED,"HUSTR_KEYRED"},
735   {&s_AMSTR_FOLLOWON,"AMSTR_FOLLOWON"},
736   {&s_AMSTR_FOLLOWOFF,"AMSTR_FOLLOWOFF"},
737   {&s_AMSTR_GRIDON,"AMSTR_GRIDON"},
738   {&s_AMSTR_GRIDOFF,"AMSTR_GRIDOFF"},
739   {&s_AMSTR_MARKEDSPOT,"AMSTR_MARKEDSPOT"},
740   {&s_AMSTR_MARKSCLEARED,"AMSTR_MARKSCLEARED"},
741   {&s_STSTR_MUS,"STSTR_MUS"},
742   {&s_STSTR_NOMUS,"STSTR_NOMUS"},
743   {&s_STSTR_DQDON,"STSTR_DQDON"},
744   {&s_STSTR_DQDOFF,"STSTR_DQDOFF"},
745   {&s_STSTR_KFAADDED,"STSTR_KFAADDED"},
746   {&s_STSTR_FAADDED,"STSTR_FAADDED"},
747   {&s_STSTR_NCON,"STSTR_NCON"},
748   {&s_STSTR_NCOFF,"STSTR_NCOFF"},
749   {&s_STSTR_BEHOLD,"STSTR_BEHOLD"},
750   {&s_STSTR_BEHOLDX,"STSTR_BEHOLDX"},
751   {&s_STSTR_CHOPPERS,"STSTR_CHOPPERS"},
752   {&s_STSTR_CLEV,"STSTR_CLEV"},
753   {&s_STSTR_COMPON,"STSTR_COMPON"},
754   {&s_STSTR_COMPOFF,"STSTR_COMPOFF"},
755   {&s_E1TEXT,"E1TEXT"},
756   {&s_E2TEXT,"E2TEXT"},
757   {&s_E3TEXT,"E3TEXT"},
758   {&s_E4TEXT,"E4TEXT"},
759   {&s_C1TEXT,"C1TEXT"},
760   {&s_C2TEXT,"C2TEXT"},
761   {&s_C3TEXT,"C3TEXT"},
762   {&s_C4TEXT,"C4TEXT"},
763   {&s_C5TEXT,"C5TEXT"},
764   {&s_C6TEXT,"C6TEXT"},
765   {&s_P1TEXT,"P1TEXT"},
766   {&s_P2TEXT,"P2TEXT"},
767   {&s_P3TEXT,"P3TEXT"},
768   {&s_P4TEXT,"P4TEXT"},
769   {&s_P5TEXT,"P5TEXT"},
770   {&s_P6TEXT,"P6TEXT"},
771   {&s_T1TEXT,"T1TEXT"},
772   {&s_T2TEXT,"T2TEXT"},
773   {&s_T3TEXT,"T3TEXT"},
774   {&s_T4TEXT,"T4TEXT"},
775   {&s_T5TEXT,"T5TEXT"},
776   {&s_T6TEXT,"T6TEXT"},
777   {&s_CC_ZOMBIE,"CC_ZOMBIE"},
778   {&s_CC_SHOTGUN,"CC_SHOTGUN"},
779   {&s_CC_HEAVY,"CC_HEAVY"},
780   {&s_CC_IMP,"CC_IMP"},
781   {&s_CC_DEMON,"CC_DEMON"},
782   {&s_CC_LOST,"CC_LOST"},
783   {&s_CC_CACO,"CC_CACO"},
784   {&s_CC_HELL,"CC_HELL"},
785   {&s_CC_BARON,"CC_BARON"},
786   {&s_CC_ARACH,"CC_ARACH"},
787   {&s_CC_PAIN,"CC_PAIN"},
788   {&s_CC_REVEN,"CC_REVEN"},
789   {&s_CC_MANCU,"CC_MANCU"},
790   {&s_CC_ARCH,"CC_ARCH"},
791   {&s_CC_SPIDER,"CC_SPIDER"},
792   {&s_CC_CYBER,"CC_CYBER"},
793   {&s_CC_HERO,"CC_HERO"},
794   {&bgflatE1,"BGFLATE1"},
795   {&bgflatE2,"BGFLATE2"},
796   {&bgflatE3,"BGFLATE3"},
797   {&bgflatE4,"BGFLATE4"},
798   {&bgflat06,"BGFLAT06"},
799   {&bgflat11,"BGFLAT11"},
800   {&bgflat20,"BGFLAT20"},
801   {&bgflat30,"BGFLAT30"},
802   {&bgflat15,"BGFLAT15"},
803   {&bgflat31,"BGFLAT31"},
804   {&bgcastcall,"BGCASTCALL"},
805   // Ty 04/08/98 - added 5 general purpose startup announcement
806   // strings for hacker use.  See m_menu.c
807   {&startup1,"STARTUP1"},
808   {&startup2,"STARTUP2"},
809   {&startup3,"STARTUP3"},
810   {&startup4,"STARTUP4"},
811   {&startup5,"STARTUP5"},
812   {&savegamename,"SAVEGAMENAME"},  // Ty 05/03/98
813 };
814 
815 static int deh_numstrlookup =
816 sizeof(deh_strlookup)/sizeof(deh_strlookup[0]);
817 
818 const char *deh_newlevel = "NEWLEVEL"; // CPhipps - const
819 
820 // DOOM shareware/registered/retail (Ultimate) names.
821 // CPhipps - const**const
822 const char **const mapnames[] =
823 {
824   &s_HUSTR_E1M1,
825   &s_HUSTR_E1M2,
826   &s_HUSTR_E1M3,
827   &s_HUSTR_E1M4,
828   &s_HUSTR_E1M5,
829   &s_HUSTR_E1M6,
830   &s_HUSTR_E1M7,
831   &s_HUSTR_E1M8,
832   &s_HUSTR_E1M9,
833 
834   &s_HUSTR_E2M1,
835   &s_HUSTR_E2M2,
836   &s_HUSTR_E2M3,
837   &s_HUSTR_E2M4,
838   &s_HUSTR_E2M5,
839   &s_HUSTR_E2M6,
840   &s_HUSTR_E2M7,
841   &s_HUSTR_E2M8,
842   &s_HUSTR_E2M9,
843 
844   &s_HUSTR_E3M1,
845   &s_HUSTR_E3M2,
846   &s_HUSTR_E3M3,
847   &s_HUSTR_E3M4,
848   &s_HUSTR_E3M5,
849   &s_HUSTR_E3M6,
850   &s_HUSTR_E3M7,
851   &s_HUSTR_E3M8,
852   &s_HUSTR_E3M9,
853 
854   &s_HUSTR_E4M1,
855   &s_HUSTR_E4M2,
856   &s_HUSTR_E4M3,
857   &s_HUSTR_E4M4,
858   &s_HUSTR_E4M5,
859   &s_HUSTR_E4M6,
860   &s_HUSTR_E4M7,
861   &s_HUSTR_E4M8,
862   &s_HUSTR_E4M9,
863 
864   &deh_newlevel,  // spares?  Unused.
865   &deh_newlevel,
866   &deh_newlevel,
867   &deh_newlevel,
868   &deh_newlevel,
869   &deh_newlevel,
870   &deh_newlevel,
871   &deh_newlevel,
872   &deh_newlevel
873 };
874 
875 // CPhipps - const**const
876 const char **const mapnames2[] = // DOOM 2 map names.
877 {
878   &s_HUSTR_1,
879   &s_HUSTR_2,
880   &s_HUSTR_3,
881   &s_HUSTR_4,
882   &s_HUSTR_5,
883   &s_HUSTR_6,
884   &s_HUSTR_7,
885   &s_HUSTR_8,
886   &s_HUSTR_9,
887   &s_HUSTR_10,
888   &s_HUSTR_11,
889 
890   &s_HUSTR_12,
891   &s_HUSTR_13,
892   &s_HUSTR_14,
893   &s_HUSTR_15,
894   &s_HUSTR_16,
895   &s_HUSTR_17,
896   &s_HUSTR_18,
897   &s_HUSTR_19,
898   &s_HUSTR_20,
899 
900   &s_HUSTR_21,
901   &s_HUSTR_22,
902   &s_HUSTR_23,
903   &s_HUSTR_24,
904   &s_HUSTR_25,
905   &s_HUSTR_26,
906   &s_HUSTR_27,
907   &s_HUSTR_28,
908   &s_HUSTR_29,
909   &s_HUSTR_30,
910   &s_HUSTR_31,
911   &s_HUSTR_32,
912 };
913 
914 // CPhipps - const**const
915 const char **const mapnamesp[] = // Plutonia WAD map names.
916 {
917   &s_PHUSTR_1,
918   &s_PHUSTR_2,
919   &s_PHUSTR_3,
920   &s_PHUSTR_4,
921   &s_PHUSTR_5,
922   &s_PHUSTR_6,
923   &s_PHUSTR_7,
924   &s_PHUSTR_8,
925   &s_PHUSTR_9,
926   &s_PHUSTR_10,
927   &s_PHUSTR_11,
928 
929   &s_PHUSTR_12,
930   &s_PHUSTR_13,
931   &s_PHUSTR_14,
932   &s_PHUSTR_15,
933   &s_PHUSTR_16,
934   &s_PHUSTR_17,
935   &s_PHUSTR_18,
936   &s_PHUSTR_19,
937   &s_PHUSTR_20,
938 
939   &s_PHUSTR_21,
940   &s_PHUSTR_22,
941   &s_PHUSTR_23,
942   &s_PHUSTR_24,
943   &s_PHUSTR_25,
944   &s_PHUSTR_26,
945   &s_PHUSTR_27,
946   &s_PHUSTR_28,
947   &s_PHUSTR_29,
948   &s_PHUSTR_30,
949   &s_PHUSTR_31,
950   &s_PHUSTR_32,
951 };
952 
953 // CPhipps - const**const
954 const char **const mapnamest[] = // TNT WAD map names.
955 {
956   &s_THUSTR_1,
957   &s_THUSTR_2,
958   &s_THUSTR_3,
959   &s_THUSTR_4,
960   &s_THUSTR_5,
961   &s_THUSTR_6,
962   &s_THUSTR_7,
963   &s_THUSTR_8,
964   &s_THUSTR_9,
965   &s_THUSTR_10,
966   &s_THUSTR_11,
967 
968   &s_THUSTR_12,
969   &s_THUSTR_13,
970   &s_THUSTR_14,
971   &s_THUSTR_15,
972   &s_THUSTR_16,
973   &s_THUSTR_17,
974   &s_THUSTR_18,
975   &s_THUSTR_19,
976   &s_THUSTR_20,
977 
978   &s_THUSTR_21,
979   &s_THUSTR_22,
980   &s_THUSTR_23,
981   &s_THUSTR_24,
982   &s_THUSTR_25,
983   &s_THUSTR_26,
984   &s_THUSTR_27,
985   &s_THUSTR_28,
986   &s_THUSTR_29,
987   &s_THUSTR_30,
988   &s_THUSTR_31,
989   &s_THUSTR_32,
990 };
991 
992 // Function prototypes
993 void    lfstrip(char *);     // strip the \r and/or \n off of a line
994 void    rstrip(char *);      // strip trailing whitespace
995 char *  ptr_lstrip(char *);  // point past leading whitespace
996 dboolean deh_GetData(char *, char *, uint_64_t *, char **, FILE *);
997 dboolean deh_procStringSub(char *, char *, char *, FILE *);
998 char *  dehReformatStr(char *);
999 
1000 // Prototypes for block processing functions
1001 // Pointers to these functions are used as the blocks are encountered.
1002 
1003 static void deh_procThing(DEHFILE *fpin, FILE* fpout, char *line);
1004 static void deh_procFrame(DEHFILE *, FILE*, char *);
1005 static void deh_procPointer(DEHFILE *, FILE*, char *);
1006 static void deh_procSounds(DEHFILE *, FILE*, char *);
1007 static void deh_procAmmo(DEHFILE *, FILE*, char *);
1008 static void deh_procWeapon(DEHFILE *, FILE*, char *);
1009 static void deh_procSprite(DEHFILE *, FILE*, char *);
1010 static void deh_procCheat(DEHFILE *, FILE*, char *);
1011 static void deh_procMisc(DEHFILE *, FILE*, char *);
1012 static void deh_procText(DEHFILE *, FILE*, char *);
1013 static void deh_procPars(DEHFILE *, FILE*, char *);
1014 static void deh_procStrings(DEHFILE *, FILE*, char *);
1015 static void deh_procError(DEHFILE *, FILE*, char *);
1016 static void deh_procBexCodePointers(DEHFILE *, FILE*, char *);
1017 static void deh_procHelperThing(DEHFILE *, FILE *, char *); // haleyjd 9/22/99
1018 // haleyjd: handlers to fully deprecate the DeHackEd text section
1019 static void deh_procBexSounds(DEHFILE *, FILE *, char *);
1020 static void deh_procBexMusic(DEHFILE *, FILE *, char *);
1021 static void deh_procBexSprites(DEHFILE *, FILE *, char *);
1022 
1023 // Structure deh_block is used to hold the block names that can
1024 // be encountered, and the routines to use to decipher them
1025 
1026 typedef struct
1027 {
1028   const char *key;       // a mnemonic block code name // CPhipps - const*
1029   void (*const fptr)(DEHFILE *, FILE*, char *); // handler
1030 } deh_block;
1031 
1032 #define DEH_BUFFERMAX 1024 // input buffer area size, hardcodedfor now
1033 // killough 8/9/98: make DEH_BLOCKMAX self-adjusting
1034 #define DEH_BLOCKMAX (sizeof deh_blocks/sizeof*deh_blocks)  // size of array
1035 #define DEH_MAXKEYLEN 32 // as much of any key as we'll look at
1036 #define DEH_MOBJINFOMAX 24 // number of ints in the mobjinfo_t structure (!)
1037 
1038 // Put all the block header values, and the function to be called when that
1039 // one is encountered, in this array:
1040 static const deh_block deh_blocks[] = { // CPhipps - static const
1041   /* 0 */  {"Thing",deh_procThing},
1042   /* 1 */  {"Frame",deh_procFrame},
1043   /* 2 */  {"Pointer",deh_procPointer},
1044   /* 3 */  {"Sound",deh_procSounds},  // Ty 03/16/98 corrected from "Sounds"
1045   /* 4 */  {"Ammo",deh_procAmmo},
1046   /* 5 */  {"Weapon",deh_procWeapon},
1047   /* 6 */  {"Sprite",deh_procSprite},
1048   /* 7 */  {"Cheat",deh_procCheat},
1049   /* 8 */  {"Misc",deh_procMisc},
1050   /* 9 */  {"Text",deh_procText},  // --  end of standard "deh" entries,
1051 
1052   //     begin BOOM Extensions (BEX)
1053 
1054   /* 10 */ {"[STRINGS]",deh_procStrings}, // new string changes
1055   /* 11 */ {"[PARS]",deh_procPars}, // alternative block marker
1056   /* 12 */ {"[CODEPTR]",deh_procBexCodePointers}, // bex codepointers by mnemonic
1057    /* 13 */ {"[HELPER]", deh_procHelperThing}, // helper thing substitution haleyjd 9/22/99
1058    /* 14 */ {"[SPRITES]", deh_procBexSprites}, // bex style sprites
1059    /* 15 */ {"[SOUNDS]", deh_procBexSounds},   // bex style sounds
1060    /* 16 */ {"[MUSIC]", deh_procBexMusic},     // bex style music
1061    /* 17 */ {"", deh_procError} // dummy to handle anything else
1062 };
1063 
1064 // flag to skip included deh-style text, used with INCLUDE NOTEXT directive
1065 static dboolean includenotext = false;
1066 
1067 // MOBJINFO - Dehacked block name = "Thing"
1068 // Usage: Thing nn (name)
1069 // These are for mobjinfo_t types.  Each is an integer
1070 // within the structure, so we can use index of the string in this
1071 // array to offset by sizeof(int) into the mobjinfo_t array at [nn]
1072 // * things are base zero but dehacked considers them to start at #1. ***
1073 // CPhipps - static const
1074 
1075 static const char *deh_mobjinfo[DEH_MOBJINFOMAX] =
1076 {
1077   "ID #",                // .doomednum
1078   "Initial frame",       // .spawnstate
1079   "Hit points",          // .spawnhealth
1080   "First moving frame",  // .seestate
1081   "Alert sound",         // .seesound
1082   "Reaction time",       // .reactiontime
1083   "Attack sound",        // .attacksound
1084   "Injury frame",        // .painstate
1085   "Pain chance",         // .painchance
1086   "Pain sound",          // .painsound
1087   "Close attack frame",  // .meleestate
1088   "Far attack frame",    // .missilestate
1089   "Death frame",         // .deathstate
1090   "Exploding frame",     // .xdeathstate
1091   "Death sound",         // .deathsound
1092   "Speed",               // .speed
1093   "Width",               // .radius
1094   "Height",              // .height
1095   "Mass",                // .mass
1096   "Missile damage",      // .damage
1097   "Action sound",        // .activesound
1098   "Bits",                // .flags
1099   "Bits2",               // .flags
1100   "Respawn frame"        // .raisestate
1101 };
1102 
1103 // Strings that are used to indicate flags ("Bits" in mobjinfo)
1104 // This is an array of bit masks that are related to p_mobj.h
1105 // values, using the smae names without the MF_ in front.
1106 // Ty 08/27/98 new code
1107 //
1108 // killough 10/98:
1109 //
1110 // Convert array to struct to allow multiple values, make array size variable
1111 
1112 #define DEH_MOBJFLAGMAX (sizeof deh_mobjflags/sizeof*deh_mobjflags)
1113 
1114 struct deh_mobjflags_s {
1115   const char *name; // CPhipps - const*
1116   uint_64_t value;
1117 };
1118 
1119 // CPhipps - static const
1120 static const struct deh_mobjflags_s deh_mobjflags[] = {
1121   {"SPECIAL",      MF_SPECIAL}, // call  P_Specialthing when touched
1122   {"SOLID",        MF_SOLID}, // block movement
1123   {"SHOOTABLE",    MF_SHOOTABLE}, // can be hit
1124   {"NOSECTOR",     MF_NOSECTOR}, // invisible but touchable
1125   {"NOBLOCKMAP",   MF_NOBLOCKMAP}, // inert but displayable
1126   {"AMBUSH",       MF_AMBUSH}, // deaf monster
1127   {"JUSTHIT",      MF_JUSTHIT}, // will try to attack right back
1128   {"JUSTATTACKED", MF_JUSTATTACKED}, // take at least 1 step before attacking
1129   {"SPAWNCEILING", MF_SPAWNCEILING}, // initially hang from ceiling
1130   {"NOGRAVITY",    MF_NOGRAVITY}, // don't apply gravity during play
1131   {"DROPOFF",      MF_DROPOFF}, // can jump from high places
1132   {"PICKUP",       MF_PICKUP}, // will pick up items
1133   {"NOCLIP",       MF_NOCLIP}, // goes through walls
1134   {"SLIDE",        MF_SLIDE}, // keep info about sliding along walls
1135   {"FLOAT",        MF_FLOAT}, // allow movement to any height
1136   {"TELEPORT",     MF_TELEPORT}, // don't cross lines or look at heights
1137   {"MISSILE",      MF_MISSILE}, // don't hit same species, explode on block
1138   {"DROPPED",      MF_DROPPED}, // dropped, not spawned (like ammo clip)
1139   {"SHADOW",       MF_SHADOW}, // use fuzzy draw like spectres
1140   {"NOBLOOD",      MF_NOBLOOD}, // puffs instead of blood when shot
1141   {"CORPSE",       MF_CORPSE}, // so it will slide down steps when dead
1142   {"INFLOAT",      MF_INFLOAT}, // float but not to target height
1143   {"COUNTKILL",    MF_COUNTKILL}, // count toward the kills total
1144   {"COUNTITEM",    MF_COUNTITEM}, // count toward the items total
1145   {"SKULLFLY",     MF_SKULLFLY}, // special handling for flying skulls
1146   {"NOTDMATCH",    MF_NOTDMATCH}, // do not spawn in deathmatch
1147 
1148   // killough 10/98: TRANSLATION consists of 2 bits, not 1:
1149 
1150   {"TRANSLATION",  MF_TRANSLATION1}, // for Boom bug-compatibility
1151   {"TRANSLATION1", MF_TRANSLATION1}, // use translation table for color (players)
1152   {"TRANSLATION2", MF_TRANSLATION2}, // use translation table for color (players)
1153   {"UNUSED1",      MF_TRANSLATION2}, // unused bit # 1 -- For Boom bug-compatibility
1154   {"UNUSED2",      MF_UNUSED2},      // unused bit # 2 -- For Boom compatibility
1155   {"UNUSED3",      MF_UNUSED3},      // unused bit # 3 -- For Boom compatibility
1156   {"UNUSED4",      MF_TRANSLUCENT},  // unused bit # 4 -- For Boom compatibility
1157   {"TRANSLUCENT",  MF_TRANSLUCENT},  // apply translucency to sprite (BOOM)
1158   {"TOUCHY",       MF_TOUCHY},       // dies on contact with solid objects (MBF)
1159   {"BOUNCES",      MF_BOUNCES},      // bounces off floors, ceilings and maybe walls (MBF)
1160   {"FRIEND",       MF_FRIEND},       // a friend of the player(s) (MBF)
1161 };
1162 
1163 // STATE - Dehacked block name = "Frame" and "Pointer"
1164 // Usage: Frame nn
1165 // Usage: Pointer nn (Frame nn)
1166 // These are indexed separately, for lookup to the actual
1167 // function pointers.  Here we'll take whatever Dehacked gives
1168 // us and go from there.  The (Frame nn) after the pointer is the
1169 // real place to put this value.  The "Pointer" value is an xref
1170 // that Dehacked uses and is useless to us.
1171 // * states are base zero and have a dummy #0 (TROO)
1172 
1173 static const char *deh_state[] = // CPhipps - static const*
1174 {
1175   "Sprite number",    // .sprite (spritenum_t) // an enum
1176   "Sprite subnumber", // .frame (long)
1177   "Duration",         // .tics (long)
1178   "Next frame",       // .nextstate (statenum_t)
1179   // This is set in a separate "Pointer" block from Dehacked
1180   "Codep Frame",      // pointer to first use of action (actionf_t)
1181   "Unknown 1",        // .misc1 (long)
1182   "Unknown 2"         // .misc2 (long)
1183 };
1184 
1185 // SFXINFO_STRUCT - Dehacked block name = "Sounds"
1186 // Sound effects, typically not changed (redirected, and new sfx put
1187 // into the pwad, but not changed here.  Can you tell that Gregdidn't
1188 // know what they were for, mostly?  Can you tell that I don't either?
1189 // Mostly I just put these into the same slots as they are in the struct.
1190 // This may not be supported in our -deh option if it doesn't make sense by then.
1191 
1192 // * sounds are base zero but have a dummy #0
1193 
1194 static const char *deh_sfxinfo[] = // CPhipps - static const*
1195 {
1196   "Offset",     // pointer to a name string, changed in text
1197   "Zero/One",   // .singularity (int, one at a time flag)
1198   "Value",      // .priority
1199   "Zero 1",     // .link (sfxinfo_t*) referenced sound if linked
1200   "Zero 2",     // .pitch
1201   "Zero 3",     // .volume
1202   "Zero 4",     // .data (SAMPLE*) sound data
1203   "Neg. One 1", // .usefulness
1204   "Neg. One 2"  // .lumpnum
1205 };
1206 
1207 // MUSICINFO is not supported in Dehacked.  Ignored here.
1208 // * music entries are base zero but have a dummy #0
1209 
1210 // SPRITE - Dehacked block name = "Sprite"
1211 // Usage = Sprite nn
1212 // Sprite redirection by offset into the text area - unsupported by BOOM
1213 // * sprites are base zero and dehacked uses it that way.
1214 
1215 // static const char *deh_sprite[] = // CPhipps - static const*
1216 // {
1217 //   "Offset"      // supposed to be the offset into the text section
1218 // };
1219 
1220 // AMMO - Dehacked block name = "Ammo"
1221 // usage = Ammo n (name)
1222 // Ammo information for the few types of ammo
1223 
1224 static const char *deh_ammo[] = // CPhipps - static const*
1225 {
1226   "Max ammo",   // maxammo[]
1227   "Per ammo"    // clipammo[]
1228 };
1229 
1230 // WEAPONS - Dehacked block name = "Weapon"
1231 // Usage: Weapon nn (name)
1232 // Basically a list of frames and what kind of ammo (see above)it uses.
1233 
1234 static const char *deh_weapon[] = // CPhipps - static const*
1235 {
1236   "Ammo type",      // .ammo
1237   "Deselect frame", // .upstate
1238   "Select frame",   // .downstate
1239   "Bobbing frame",  // .readystate
1240   "Shooting frame", // .atkstate
1241   "Firing frame"    // .flashstate
1242 };
1243 
1244 // CHEATS - Dehacked block name = "Cheat"
1245 // Usage: Cheat 0
1246 // Always uses a zero in the dehacked file, for consistency.  No meaning.
1247 // These are just plain funky terms compared with id's
1248 //
1249 // killough 4/18/98: integrated into main cheat table now (see st_stuff.c)
1250 
1251 // MISC - Dehacked block name = "Misc"
1252 // Usage: Misc 0
1253 // Always uses a zero in the dehacked file, for consistency.  No meaning.
1254 
1255 static const char *deh_misc[] = // CPhipps - static const*
1256 {
1257   "Initial Health",    // initial_health
1258   "Initial Bullets",   // initial_bullets
1259   "Max Health",        // maxhealth
1260   "Max Armor",         // max_armor
1261   "Green Armor Class", // green_armor_class
1262   "Blue Armor Class",  // blue_armor_class
1263   "Max Soulsphere",    // max_soul
1264   "Soulsphere Health", // soul_health
1265   "Megasphere Health", // mega_health
1266   "God Mode Health",   // god_health
1267   "IDFA Armor",        // idfa_armor
1268   "IDFA Armor Class",  // idfa_armor_class
1269   "IDKFA Armor",       // idkfa_armor
1270   "IDKFA Armor Class", // idkfa_armor_class
1271   "BFG Cells/Shot",    // BFGCELLS
1272   "Monsters Infight"   // Unknown--not a specific number it seems, but
1273   // the logic has to be here somewhere or
1274   // it'd happen always
1275 };
1276 
1277 // TEXT - Dehacked block name = "Text"
1278 // Usage: Text fromlen tolen
1279 // Dehacked allows a bit of adjustment to the length (why?)
1280 
1281 // BEX extension [CODEPTR]
1282 // Usage: Start block, then each line is:
1283 // FRAME nnn = PointerMnemonic
1284 
1285 typedef struct {
1286   actionf_t cptr;  // actual pointer to the subroutine
1287   const char *lookup;  // mnemonic lookup string to be specified in BEX
1288   // CPhipps - const*
1289 } deh_bexptr;
1290 
1291 static const deh_bexptr deh_bexptrs[] = // CPhipps - static const
1292 {
1293   {A_Light0,          "A_Light0"},
1294   {A_WeaponReady,     "A_WeaponReady"},
1295   {A_Lower,           "A_Lower"},
1296   {A_Raise,           "A_Raise"},
1297   {A_Punch,           "A_Punch"},
1298   {A_ReFire,          "A_ReFire"},
1299   {A_FirePistol,      "A_FirePistol"},
1300   {A_Light1,          "A_Light1"},
1301   {A_FireShotgun,     "A_FireShotgun"},
1302   {A_Light2,          "A_Light2"},
1303   {A_FireShotgun2,    "A_FireShotgun2"},
1304   {A_CheckReload,     "A_CheckReload"},
1305   {A_OpenShotgun2,    "A_OpenShotgun2"},
1306   {A_LoadShotgun2,    "A_LoadShotgun2"},
1307   {A_CloseShotgun2,   "A_CloseShotgun2"},
1308   {A_FireCGun,        "A_FireCGun"},
1309   {A_GunFlash,        "A_GunFlash"},
1310   {A_FireMissile,     "A_FireMissile"},
1311   {A_Saw,             "A_Saw"},
1312   {A_FirePlasma,      "A_FirePlasma"},
1313   {A_BFGsound,        "A_BFGsound"},
1314   {A_FireBFG,         "A_FireBFG"},
1315   {A_BFGSpray,        "A_BFGSpray"},
1316   {A_Explode,         "A_Explode"},
1317   {A_Pain,            "A_Pain"},
1318   {A_PlayerScream,    "A_PlayerScream"},
1319   {A_Fall,            "A_Fall"},
1320   {A_XScream,         "A_XScream"},
1321   {A_Look,            "A_Look"},
1322   {A_Chase,           "A_Chase"},
1323   {A_FaceTarget,      "A_FaceTarget"},
1324   {A_PosAttack,       "A_PosAttack"},
1325   {A_Scream,          "A_Scream"},
1326   {A_SPosAttack,      "A_SPosAttack"},
1327   {A_VileChase,       "A_VileChase"},
1328   {A_VileStart,       "A_VileStart"},
1329   {A_VileTarget,      "A_VileTarget"},
1330   {A_VileAttack,      "A_VileAttack"},
1331   {A_StartFire,       "A_StartFire"},
1332   {A_Fire,            "A_Fire"},
1333   {A_FireCrackle,     "A_FireCrackle"},
1334   {A_Tracer,          "A_Tracer"},
1335   {A_SkelWhoosh,      "A_SkelWhoosh"},
1336   {A_SkelFist,        "A_SkelFist"},
1337   {A_SkelMissile,     "A_SkelMissile"},
1338   {A_FatRaise,        "A_FatRaise"},
1339   {A_FatAttack1,      "A_FatAttack1"},
1340   {A_FatAttack2,      "A_FatAttack2"},
1341   {A_FatAttack3,      "A_FatAttack3"},
1342   {A_BossDeath,       "A_BossDeath"},
1343   {A_CPosAttack,      "A_CPosAttack"},
1344   {A_CPosRefire,      "A_CPosRefire"},
1345   {A_TroopAttack,     "A_TroopAttack"},
1346   {A_SargAttack,      "A_SargAttack"},
1347   {A_HeadAttack,      "A_HeadAttack"},
1348   {A_BruisAttack,     "A_BruisAttack"},
1349   {A_SkullAttack,     "A_SkullAttack"},
1350   {A_Metal,           "A_Metal"},
1351   {A_SpidRefire,      "A_SpidRefire"},
1352   {A_BabyMetal,       "A_BabyMetal"},
1353   {A_BspiAttack,      "A_BspiAttack"},
1354   {A_Hoof,            "A_Hoof"},
1355   {A_CyberAttack,     "A_CyberAttack"},
1356   {A_PainAttack,      "A_PainAttack"},
1357   {A_PainDie,         "A_PainDie"},
1358   {A_KeenDie,         "A_KeenDie"},
1359   {A_BrainPain,       "A_BrainPain"},
1360   {A_BrainScream,     "A_BrainScream"},
1361   {A_BrainDie,        "A_BrainDie"},
1362   {A_BrainAwake,      "A_BrainAwake"},
1363   {A_BrainSpit,       "A_BrainSpit"},
1364   {A_SpawnSound,      "A_SpawnSound"},
1365   {A_SpawnFly,        "A_SpawnFly"},
1366   {A_BrainExplode,    "A_BrainExplode"},
1367   {A_Detonate,        "A_Detonate"},       // killough 8/9/98
1368   {A_Mushroom,        "A_Mushroom"},       // killough 10/98
1369   {A_Die,             "A_Die"},            // killough 11/98
1370   {A_Spawn,           "A_Spawn"},          // killough 11/98
1371   {A_Turn,            "A_Turn"},           // killough 11/98
1372   {A_Face,            "A_Face"},           // killough 11/98
1373   {A_Scratch,         "A_Scratch"},        // killough 11/98
1374   {A_PlaySound,       "A_PlaySound"},      // killough 11/98
1375   {A_RandomJump,      "A_RandomJump"},     // killough 11/98
1376   {A_LineEffect,      "A_LineEffect"},     // killough 11/98
1377 
1378   // This NULL entry must be the last in the list
1379   {NULL,              "A_NULL"},  // Ty 05/16/98
1380 };
1381 
1382 // to hold startup code pointers from INFO.C
1383 // CPhipps - static
1384 static actionf_t deh_codeptr[NUMSTATES];
1385 
1386 // haleyjd: support for BEX SPRITES, SOUNDS, and MUSIC
1387 char *deh_spritenames[NUMSPRITES + 1];
1388 char *deh_musicnames[NUMMUSIC + 1];
1389 char *deh_soundnames[NUMSFX + 1];
1390 
D_BuildBEXTables(void)1391 void D_BuildBEXTables(void)
1392 {
1393    int i;
1394 
1395    // moved from ProcessDehFile, then we don't need the static int i
1396    for (i = 0; i < NUMSTATES; i++)  // remember what they start as for deh xref
1397      deh_codeptr[i] = states[i].action;
1398 
1399    for(i = 0; i < NUMSPRITES; i++)
1400       deh_spritenames[i] = strdup(sprnames[i]);
1401    deh_spritenames[NUMSPRITES] = NULL;
1402 
1403    for(i = 1; i < NUMMUSIC; i++)
1404       deh_musicnames[i] = strdup(S_music[i].name);
1405    deh_musicnames[0] = deh_musicnames[NUMMUSIC] = NULL;
1406 
1407    for(i = 1; i < NUMSFX; i++)
1408       deh_soundnames[i] = strdup(S_sfx[i].name);
1409    deh_soundnames[0] = deh_soundnames[NUMSFX] = NULL;
1410 }
1411 
1412 // ====================================================================
1413 // ProcessDehFile
1414 // Purpose: Read and process a DEH or BEX file
1415 // Args:    filename    -- name of the DEH/BEX file
1416 //          outfilename -- output file (DEHOUT.TXT), appended to here
1417 // Returns: void
1418 //
1419 // killough 10/98:
1420 // substantially modified to allow input from wad lumps instead of .deh files.
1421 
ProcessDehFile(const char * filename,const char * outfilename,int lumpnum)1422 void ProcessDehFile(const char *filename, const char *outfilename, int lumpnum)
1423 {
1424   static FILE *fileout;       // In case -dehout was used
1425   DEHFILE infile, *filein = &infile;    // killough 10/98
1426   char inbuffer[DEH_BUFFERMAX];  // Place to put the primary infostring
1427 
1428   // Open output file if we're writing output
1429   if (outfilename && *outfilename && !fileout)
1430     {
1431       static dboolean firstfile = true; // to allow append to output log
1432       if (!strcmp(outfilename, "-"))
1433         fileout = stdout;
1434       else
1435         if (!(fileout=fopen(outfilename, firstfile ? "wt" : "at")))
1436           {
1437             lprintf(LO_WARN, "Could not open -dehout file %s\n... using stdout.\n",
1438                    outfilename);
1439             fileout = stdout;
1440           }
1441       firstfile = false;
1442     }
1443 
1444   // killough 10/98: allow DEH files to come from wad lumps
1445 
1446   if (filename)
1447     {
1448       if (!(infile.f = fopen(filename,"rt")))
1449         {
1450           lprintf(LO_WARN, "-deh file %s not found\n",filename);
1451           return;  // should be checked up front anyway
1452         }
1453       infile.lump = NULL;
1454     }
1455   else  // DEH file comes from lump indicated by third argument
1456     {
1457       infile.size = W_LumpLength(lumpnum);
1458       infile.inp = infile.lump = W_CacheLumpNum(lumpnum);
1459       filename = "(WAD)";
1460     }
1461 
1462   lprintf(LO_INFO, "Loading DEH file %s\n",filename);
1463   if (fileout) fprintf(fileout,"\nLoading DEH file %s\n\n",filename);
1464 
1465   // move deh_codeptr initialisation to D_BuildBEXTables
1466 
1467   // loop until end of file
1468 
1469   while (dehfgets(inbuffer,sizeof(inbuffer),filein))
1470     {
1471       unsigned i;
1472 
1473       lfstrip(inbuffer);
1474       if (fileout) fprintf(fileout,"Line='%s'\n",inbuffer);
1475       if (!*inbuffer || *inbuffer == '#' || *inbuffer == ' ')
1476         continue; /* Blank line or comment line */
1477 
1478       // -- If DEH_BLOCKMAX is set right, the processing is independently
1479       // -- handled based on data in the deh_blocks[] structure array
1480 
1481       // killough 10/98: INCLUDE code rewritten to allow arbitrary nesting,
1482       // and to greatly simplify code, fix memory leaks, other bugs
1483 
1484       if (!strnicmp(inbuffer,"INCLUDE",7)) // include a file
1485         {
1486           // preserve state while including a file
1487           // killough 10/98: moved to here
1488 
1489           char *nextfile;
1490           dboolean oldnotext = includenotext;       // killough 10/98
1491 
1492           // killough 10/98: exclude if inside wads (only to discourage
1493           // the practice, since the code could otherwise handle it)
1494 
1495           if (infile.lump)
1496             {
1497               if (fileout)
1498                 fprintf(fileout,
1499                         "No files may be included from wads: %s\n",inbuffer);
1500               continue;
1501             }
1502 
1503           // check for no-text directive, used when including a DEH
1504           // file but using the BEX format to handle strings
1505 
1506           if (!strnicmp(nextfile = ptr_lstrip(inbuffer+7),"NOTEXT",6))
1507             includenotext = true, nextfile = ptr_lstrip(nextfile+6);
1508 
1509           if (fileout)
1510             fprintf(fileout,"Branching to include file %s...\n", nextfile);
1511 
1512           // killough 10/98:
1513           // Second argument must be NULL to prevent closing fileout too soon
1514 
1515           ProcessDehFile(nextfile,NULL,0); // do the included file
1516 
1517           includenotext = oldnotext;
1518           if (fileout) fprintf(fileout,"...continuing with %s\n",filename);
1519           continue;
1520         }
1521 
1522       for (i=0; i<DEH_BLOCKMAX; i++)
1523         if (!strncasecmp(inbuffer,deh_blocks[i].key,strlen(deh_blocks[i].key)))
1524           { // matches one
1525             if (fileout)
1526               fprintf(fileout,"Processing function [%d] for %s\n",
1527                       i, deh_blocks[i].key);
1528             deh_blocks[i].fptr(filein,fileout,inbuffer);  // call function
1529             break;  // we got one, that's enough for this block
1530           }
1531     }
1532 
1533   if (infile.lump)
1534     W_UnlockLumpNum(lumpnum);                 // Mark purgable
1535   else
1536     fclose(infile.f);                         // Close real file
1537 
1538   if (outfilename)   // killough 10/98: only at top recursion level
1539     {
1540       if (fileout != stdout)
1541         fclose(fileout);
1542       fileout = NULL;
1543     }
1544 }
1545 
1546 // ====================================================================
1547 // deh_procBexCodePointers
1548 // Purpose: Handle [CODEPTR] block, BOOM Extension
1549 // Args:    fpin  -- input file stream
1550 //          fpout -- output file stream (DEHOUT.TXT)
1551 //          line  -- current line in file to process
1552 // Returns: void
1553 //
deh_procBexCodePointers(DEHFILE * fpin,FILE * fpout,char * line)1554 static void deh_procBexCodePointers(DEHFILE *fpin, FILE* fpout, char *line)
1555 {
1556   char key[DEH_MAXKEYLEN];
1557   char inbuffer[DEH_BUFFERMAX];
1558   int indexnum;
1559   char mnemonic[DEH_MAXKEYLEN];  // to hold the codepointer mnemonic
1560   int i; // looper
1561   dboolean found; // know if we found this one during lookup or not
1562 
1563   // Ty 05/16/98 - initialize it to something, dummy!
1564   strncpy(inbuffer,line,DEH_BUFFERMAX);
1565 
1566   // for this one, we just read 'em until we hit a blank line
1567   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
1568     {
1569       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
1570       lfstrip(inbuffer);
1571       if (!*inbuffer) break;   // killough 11/98: really exit on blank line
1572 
1573       // killough 8/98: allow hex numbers in input:
1574       if ( (3 != sscanf(inbuffer,"%s %i = %s", key, &indexnum, mnemonic))
1575            || (stricmp(key,"FRAME")) )  // NOTE: different format from normal
1576         {
1577           if (fpout) fprintf(fpout,
1578                              "Invalid BEX codepointer line - must start with 'FRAME': '%s'\n",
1579                              inbuffer);
1580           return;  // early return
1581         }
1582 
1583       if (fpout) fprintf(fpout,"Processing pointer at index %d: %s\n",
1584                          indexnum, mnemonic);
1585       if (indexnum < 0 || indexnum >= NUMSTATES)
1586         {
1587           if (fpout) fprintf(fpout,"Bad pointer number %d of %d\n",
1588                              indexnum, NUMSTATES);
1589           return; // killough 10/98: fix SegViol
1590         }
1591       strcpy(key,"A_");  // reusing the key area to prefix the mnemonic
1592       strcat(key,ptr_lstrip(mnemonic));
1593 
1594       found = FALSE;
1595       i= -1; // incremented to start at zero at the top of the loop
1596       do  // Ty 05/16/98 - fix loop logic to look for null ending entry
1597         {
1598           ++i;
1599           if (!stricmp(key,deh_bexptrs[i].lookup))
1600             {  // Ty 06/01/98  - add  to states[].action for new djgcc version
1601               states[indexnum].action = deh_bexptrs[i].cptr; // assign
1602               if (fpout) fprintf(fpout,
1603                                  " - applied %s from codeptr[%d] to states[%d]\n",
1604                                  deh_bexptrs[i].lookup,i,indexnum);
1605               found = TRUE;
1606             }
1607         } while (!found && (deh_bexptrs[i].cptr != NULL));
1608 
1609       if (!found)
1610         if (fpout) fprintf(fpout,
1611                            "Invalid frame pointer mnemonic '%s' at %d\n",
1612                            mnemonic, indexnum);
1613     }
1614   return;
1615 }
1616 
1617 //---------------------------------------------------------------------------
1618 // To be on the safe, compatible side, we manually convert DEH bitflags
1619 // to prboom types - POPE
1620 //---------------------------------------------------------------------------
getConvertedDEHBits(uint_64_t bits)1621 static uint_64_t getConvertedDEHBits(uint_64_t bits) {
1622   static const uint_64_t bitMap[32] = {
1623     /* cf linuxdoom-1.10 p_mobj.h */
1624     MF_SPECIAL, // 0 Can be picked up - When touched the thing can be picked up.
1625     MF_SOLID, // 1 Obstacle - The thing is solid and will not let you (or others) pass through it
1626     MF_SHOOTABLE, // 2 Shootable - Can be shot.
1627     MF_NOSECTOR, // 3 Total Invisibility - Invisible, but can be touched
1628     MF_NOBLOCKMAP, // 4 Don't use the blocklinks (inert but displayable)
1629     MF_AMBUSH, // 5 Semi deaf - The thing is a deaf monster
1630     MF_JUSTHIT, // 6 In pain - Will try to attack right back after being hit
1631     MF_JUSTATTACKED, // 7 Steps before attack - Will take at least one step before attacking
1632     MF_SPAWNCEILING, // 8 Hangs from ceiling - When the level starts, this thing will be at ceiling height.
1633     MF_NOGRAVITY, // 9 No gravity - Gravity does not affect this thing
1634     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.
1635     MF_PICKUP, // 11 Pick up items - The thing can pick up gettable items.
1636     MF_NOCLIP, // 12 No clipping - Thing can walk through walls.
1637     MF_SLIDE, // 13 Slides along walls - Keep info about sliding along walls (don't really know much about this one).
1638     MF_FLOAT, // 14 Floating - Thing can move to any height
1639     MF_TELEPORT, // 15 Semi no clipping - Don't cross lines or look at teleport heights. (don't really know much about this one either).
1640     MF_MISSILE, // 16 Projectiles - Behaves like a projectile, explodes when hitting something that blocks movement
1641     MF_DROPPED, // 17 Disappearing weapon - Dropped, not spawned (like an ammo clip) I have not had much success in using this one.
1642     MF_SHADOW, // 18 Partial invisibility - Drawn like a spectre.
1643     MF_NOBLOOD, // 19 Puffs (vs. bleeds) - If hit will spawn bullet puffs instead of blood splats.
1644     MF_CORPSE, // 20 Sliding helpless - Will slide down steps when dead.
1645     MF_INFLOAT, // 21 No auto levelling - float but not to target height (?)
1646     MF_COUNTKILL, // 22 Affects kill % - counted as a killable enemy and affects percentage kills on level summary.
1647     MF_COUNTITEM, // 23 Affects item % - affects percentage items gathered on level summary.
1648     MF_SKULLFLY, // 24 Running - special handling for flying skulls.
1649     MF_NOTDMATCH, // 25 Not in deathmatch - do not spawn in deathmatch (like keys)
1650     MF_TRANSLATION1, // 26 Color 1 (grey / red)
1651     MF_TRANSLATION2, // 27 Color 2 (brown / red)
1652     // Convert bit 28 to MF_TOUCHY, not (MF_TRANSLATION1|MF_TRANSLATION2)
1653     // fixes bug #1576151 (part 1)
1654     MF_TOUCHY, // 28 - explodes on contact (MBF)
1655     MF_BOUNCES, // 29 - bounces off walls and floors (MBF)
1656     MF_FRIEND, // 30 - friendly monster helps players (MBF)
1657     MF_TRANSLUCENT // e6y: Translucency via dehacked/bex doesn't work without it
1658   };
1659   int i;
1660   uint_64_t shiftBits = bits;
1661   uint_64_t convertedBits = 0;
1662   for (i=0; i<32; i++) {
1663     if (shiftBits & 0x1) convertedBits |= bitMap[i];
1664     shiftBits >>= 1;
1665   }
1666   return convertedBits;
1667 }
1668 
1669 //---------------------------------------------------------------------------
1670 // See usage below for an explanation of this function's existence - POPE
1671 //---------------------------------------------------------------------------
setMobjInfoValue(int mobjInfoIndex,int keyIndex,uint_64_t value)1672 static void setMobjInfoValue(int mobjInfoIndex, int keyIndex, uint_64_t value) {
1673   mobjinfo_t *mi;
1674   if (mobjInfoIndex >= NUMMOBJTYPES || mobjInfoIndex < 0) return;
1675   mi = &mobjinfo[mobjInfoIndex];
1676   switch (keyIndex) {
1677     case 0: mi->doomednum = (int)value; return;
1678     case 1: mi->spawnstate = (int)value; return;
1679     case 2: mi->spawnhealth = (int)value; return;
1680     case 3: mi->seestate = (int)value; return;
1681     case 4: mi->seesound = (int)value; return;
1682     case 5: mi->reactiontime = (int)value; return;
1683     case 6: mi->attacksound = (int)value; return;
1684     case 7: mi->painstate = (int)value; return;
1685     case 8: mi->painchance = (int)value; return;
1686     case 9: mi->painsound = (int)value; return;
1687     case 10: mi->meleestate = (int)value; return;
1688     case 11: mi->missilestate = (int)value; return;
1689     case 12: mi->deathstate = (int)value; return;
1690     case 13: mi->xdeathstate = (int)value; return;
1691     case 14: mi->deathsound = (int)value; return;
1692     case 15: mi->speed = (int)value; return;
1693     case 16: mi->radius = (int)value; return;
1694     case 17: mi->height = (int)value; return;
1695     case 18: mi->mass = (int)value; return;
1696     case 19: mi->damage = (int)value; return;
1697     case 20: mi->activesound = (int)value; return;
1698     case 21: mi->flags = value; return;
1699     // e6y
1700     // Correction of wrong processing of "Respawn frame" entry.
1701     // There is no more synch on http://www.doomworld.com/sda/dwdemo/w303-115.zip
1702     // (with correction in PIT_CheckThing)
1703     case 22:
1704       if (prboom_comp[PC_FORCE_INCORRECT_PROCESSING_OF_RESPAWN_FRAME_ENTRY].state)
1705       {
1706         mi->raisestate = (int)value;
1707         return;
1708       }
1709       break;
1710     case 23:
1711       if (!prboom_comp[PC_FORCE_INCORRECT_PROCESSING_OF_RESPAWN_FRAME_ENTRY].state)
1712       {
1713         mi->raisestate = (int)value;
1714         return;
1715       }
1716       break;
1717     default: return;
1718   }
1719 }
1720 
1721 // ====================================================================
1722 // deh_procThing
1723 // Purpose: Handle DEH Thing block
1724 // Args:    fpin  -- input file stream
1725 //          fpout -- output file stream (DEHOUT.TXT)
1726 //          line  -- current line in file to process
1727 // Returns: void
1728 //
1729 // Ty 8/27/98 - revised to also allow mnemonics for
1730 // bit masks for monster attributes
1731 //
1732 
deh_procThing(DEHFILE * fpin,FILE * fpout,char * line)1733 static void deh_procThing(DEHFILE *fpin, FILE* fpout, char *line)
1734 {
1735   char key[DEH_MAXKEYLEN];
1736   char inbuffer[DEH_BUFFERMAX];
1737   uint_64_t value;      // All deh values are ints or longs
1738   int indexnum;
1739   int ix;
1740   char *strval;
1741 
1742   strncpy(inbuffer,line,DEH_BUFFERMAX);
1743   if (fpout) fprintf(fpout,"Thing line: '%s'\n",inbuffer);
1744 
1745   // killough 8/98: allow hex numbers in input:
1746   ix = sscanf(inbuffer,"%s %i",key, &indexnum);
1747   if (fpout) fprintf(fpout,"count=%d, Thing %d\n",ix, indexnum);
1748 
1749   // Note that the mobjinfo[] array is base zero, but object numbers
1750   // in the dehacked file start with one.  Grumble.
1751   --indexnum;
1752 
1753   // now process the stuff
1754   // Note that for Things we can look up the key and use its offset
1755   // in the array of key strings as an int offset in the structure
1756 
1757   // get a line until a blank or end of file--it's not
1758   // blank now because it has our incoming key in it
1759   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
1760     {
1761       // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
1762       // No more desync on HACX demos.
1763       int bGetData;
1764 
1765       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
1766       lfstrip(inbuffer);  // toss the end of line
1767 
1768       // killough 11/98: really bail out on blank lines (break != continue)
1769       if (!*inbuffer) break;  // bail out with blank line between sections
1770 
1771       // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
1772       // No more desync on HACX demos.
1773       bGetData = deh_GetData(inbuffer,key,&value,&strval,fpout);
1774       if (!bGetData)
1775       // Old code: if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
1776         {
1777           if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
1778           continue;
1779         }
1780       for (ix=0; ix<DEH_MOBJINFOMAX; ix++) {
1781         if (deh_strcasecmp(key,deh_mobjinfo[ix])) continue;
1782 
1783         if (deh_strcasecmp(key,"Bits")) {
1784           // standard value set
1785 
1786           // The old code here was the cause of a DEH-related bug in prboom.
1787           // When the mobjinfo_t.flags member was graduated to an int64, this
1788           // code was caught unawares and was indexing each property of the
1789           // mobjinfo as if it were still an int32. This caused sets of the
1790           // "raisestate" member to partially overwrite the "flags" member,
1791           // thus screwing everything up and making most DEH patches result in
1792           // unshootable enemy types. Moved to a separate function above
1793           // and stripped of all hairy struct address indexing. - POPE
1794           setMobjInfoValue(indexnum, ix, value);
1795         }
1796         else {
1797           // bit set
1798           // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
1799           // No more desync on HACX demos.
1800           if (bGetData==1) { // proff
1801             value = getConvertedDEHBits(value);
1802             mobjinfo[indexnum].flags = value;
1803             DEH_mobjinfo_bits[indexnum] = true; //e6y: changed by DEH
1804           }
1805           else {
1806             // figure out what the bits are
1807             value = 0;
1808 
1809             // killough 10/98: replace '+' kludge with strtok() loop
1810             // Fix error-handling case ('found' var wasn't being reset)
1811             //
1812             // Use OR logic instead of addition, to allow repetition
1813             for (;(strval = strtok(strval,deh_getBitsDelims())); strval = NULL) {
1814               size_t iy;
1815               for (iy=0; iy < DEH_MOBJFLAGMAX; iy++) {
1816                 if (deh_strcasecmp(strval,deh_mobjflags[iy].name)) continue;
1817                 if (fpout) {
1818                   fprintf(fpout,
1819                     "ORed value 0x%08lX%08lX %s\n",
1820                     (unsigned long)(deh_mobjflags[iy].value>>32) & 0xffffffff,
1821                     (unsigned long)deh_mobjflags[iy].value & 0xffffffff, strval
1822                   );
1823                 }
1824                 value |= deh_mobjflags[iy].value;
1825                 break;
1826               }
1827               if (iy >= DEH_MOBJFLAGMAX && fpout) {
1828                 fprintf(fpout, "Could not find bit mnemonic %s\n", strval);
1829               }
1830             }
1831 
1832             // Don't worry about conversion -- simply print values
1833             if (fpout) {
1834               fprintf(fpout,
1835                 "Bits = 0x%08lX%08lX\n",
1836                 (unsigned long)(value>>32) & 0xffffffff,
1837                 (unsigned long)value & 0xffffffff
1838               );
1839             }
1840             mobjinfo[indexnum].flags = value; // e6y
1841             DEH_mobjinfo_bits[indexnum] = true; //e6y: changed by DEH
1842           }
1843         }
1844         if (fpout) {
1845           fprintf(fpout,
1846             "Assigned 0x%08lx%08lx to %s(%d) at index %d\n",
1847             (unsigned long)(value>>32) & 0xffffffff,
1848             (unsigned long)value & 0xffffffff, key, indexnum, ix
1849           );
1850         }
1851       }
1852     }
1853   return;
1854 }
1855 
1856 // ====================================================================
1857 // deh_procFrame
1858 // Purpose: Handle DEH Frame block
1859 // Args:    fpin  -- input file stream
1860 //          fpout -- output file stream (DEHOUT.TXT)
1861 //          line  -- current line in file to process
1862 // Returns: void
1863 //
deh_procFrame(DEHFILE * fpin,FILE * fpout,char * line)1864 static void deh_procFrame(DEHFILE *fpin, FILE* fpout, char *line)
1865 {
1866   char key[DEH_MAXKEYLEN];
1867   char inbuffer[DEH_BUFFERMAX];
1868   uint_64_t value;      // All deh values are ints or longs
1869   int indexnum;
1870 
1871   strncpy(inbuffer,line,DEH_BUFFERMAX);
1872 
1873   // killough 8/98: allow hex numbers in input:
1874   sscanf(inbuffer,"%s %i",key, &indexnum);
1875   if (fpout) fprintf(fpout,"Processing Frame at index %d: %s\n",indexnum,key);
1876   if (indexnum < 0 || indexnum >= NUMSTATES)
1877     if (fpout) fprintf(fpout,"Bad frame number %d of %d\n",indexnum, NUMSTATES);
1878 
1879   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
1880     {
1881       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
1882       lfstrip(inbuffer);
1883       if (!*inbuffer) break;         // killough 11/98
1884       if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
1885         {
1886           if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
1887           continue;
1888         }
1889       if (!deh_strcasecmp(key,deh_state[0]))  // Sprite number
1890         {
1891           if (fpout) fprintf(fpout," - sprite = %lld\n",value);
1892           states[indexnum].sprite = (spritenum_t)value;
1893         }
1894       else
1895         if (!deh_strcasecmp(key,deh_state[1]))  // Sprite subnumber
1896           {
1897             if (fpout) fprintf(fpout," - frame = %lld\n",value);
1898             states[indexnum].frame = (long)value; // long
1899           }
1900         else
1901           if (!deh_strcasecmp(key,deh_state[2]))  // Duration
1902             {
1903               if (fpout) fprintf(fpout," - tics = %lld\n",value);
1904               states[indexnum].tics = (long)value; // long
1905             }
1906           else
1907             if (!deh_strcasecmp(key,deh_state[3]))  // Next frame
1908               {
1909                 if (fpout) fprintf(fpout," - nextstate = %lld\n",value);
1910                 states[indexnum].nextstate = (statenum_t)value;
1911               }
1912             else
1913               if (!deh_strcasecmp(key,deh_state[4]))  // Codep frame (not set in Frame deh block)
1914                 {
1915                   if (fpout) fprintf(fpout," - codep, should not be set in Frame section!\n");
1916                   /* nop */ ;
1917                 }
1918               else
1919                 if (!deh_strcasecmp(key,deh_state[5]))  // Unknown 1
1920                   {
1921                     if (fpout) fprintf(fpout," - misc1 = %lld\n",value);
1922                     states[indexnum].misc1 = (long)value; // long
1923                   }
1924                 else
1925                   if (!deh_strcasecmp(key,deh_state[6]))  // Unknown 2
1926                     {
1927                       if (fpout) fprintf(fpout," - misc2 = %lld\n",value);
1928                       states[indexnum].misc2 = (long)value; // long
1929                     }
1930                   else
1931                     if (fpout) fprintf(fpout,"Invalid frame string index for '%s'\n",key);
1932     }
1933   return;
1934 }
1935 
1936 // ====================================================================
1937 // deh_procPointer
1938 // Purpose: Handle DEH Code pointer block, can use BEX [CODEPTR] instead
1939 // Args:    fpin  -- input file stream
1940 //          fpout -- output file stream (DEHOUT.TXT)
1941 //          line  -- current line in file to process
1942 // Returns: void
1943 //
deh_procPointer(DEHFILE * fpin,FILE * fpout,char * line)1944 static void deh_procPointer(DEHFILE *fpin, FILE* fpout, char *line) // done
1945 {
1946   char key[DEH_MAXKEYLEN];
1947   char inbuffer[DEH_BUFFERMAX];
1948   uint_64_t value;      // All deh values are ints or longs
1949   int indexnum;
1950   size_t i; // looper
1951 
1952   strncpy(inbuffer,line,DEH_BUFFERMAX);
1953   // NOTE: different format from normal
1954 
1955   // killough 8/98: allow hex numbers in input, fix error case:
1956   if (sscanf(inbuffer,"%*s %*i (%s %i)",key, &indexnum) != 2)
1957     {
1958       if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
1959       return;
1960     }
1961 
1962   if (fpout) fprintf(fpout,"Processing Pointer at index %d: %s\n",indexnum, key);
1963   if (indexnum < 0 || indexnum >= NUMSTATES)
1964     {
1965       if (fpout)
1966         fprintf(fpout,"Bad pointer number %d of %d\n",indexnum, NUMSTATES);
1967       return;
1968     }
1969 
1970   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
1971     {
1972       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
1973       lfstrip(inbuffer);
1974       if (!*inbuffer) break;       // killough 11/98
1975       if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
1976         {
1977           if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
1978           continue;
1979         }
1980 
1981       if (value >= NUMSTATES)
1982         {
1983           if (fpout)
1984             fprintf(fpout,"Bad pointer number %lld of %d\n",value, NUMSTATES);
1985           return;
1986         }
1987 
1988       if (!deh_strcasecmp(key,deh_state[4]))  // Codep frame (not set in Frame deh block)
1989         {
1990           states[indexnum].action = deh_codeptr[value];
1991           if (fpout) fprintf(fpout," - applied from codeptr[%lld] to states[%d]\n",
1992            value,indexnum);
1993           // Write BEX-oriented line to match:
1994           // for (i=0;i<NUMSTATES;i++) could go past the end of the array
1995           for (i=0;i<sizeof(deh_bexptrs)/sizeof(*deh_bexptrs);i++)
1996             {
1997               if (!memcmp(&deh_bexptrs[i].cptr,&deh_codeptr[value],sizeof(actionf_t)))
1998                 {
1999                   if (fpout) fprintf(fpout,"BEX [CODEPTR] -> FRAME %d = %s\n",
2000                                      indexnum, &deh_bexptrs[i].lookup[2]);
2001                   break;
2002                 }
2003               if (deh_bexptrs[i].cptr == NULL) // stop at null entry
2004                 break;
2005             }
2006         }
2007       else
2008         if (fpout) fprintf(fpout,"Invalid frame pointer index for '%s' at %lld\n",
2009                            key, value);
2010     }
2011   return;
2012 }
2013 
2014 // ====================================================================
2015 // deh_procSounds
2016 // Purpose: Handle DEH Sounds block
2017 // Args:    fpin  -- input file stream
2018 //          fpout -- output file stream (DEHOUT.TXT)
2019 //          line  -- current line in file to process
2020 // Returns: void
2021 //
deh_procSounds(DEHFILE * fpin,FILE * fpout,char * line)2022 static void deh_procSounds(DEHFILE *fpin, FILE* fpout, char *line)
2023 {
2024   char key[DEH_MAXKEYLEN];
2025   char inbuffer[DEH_BUFFERMAX];
2026   uint_64_t value;      // All deh values are ints or longs
2027   int indexnum;
2028 
2029   strncpy(inbuffer,line,DEH_BUFFERMAX);
2030 
2031   // killough 8/98: allow hex numbers in input:
2032   sscanf(inbuffer,"%s %i",key, &indexnum);
2033   if (fpout) fprintf(fpout,"Processing Sounds at index %d: %s\n",
2034                      indexnum, key);
2035   if (indexnum < 0 || indexnum >= NUMSFX)
2036     if (fpout) fprintf(fpout,"Bad sound number %d of %d\n",
2037                        indexnum, NUMSFX);
2038 
2039   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2040     {
2041       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2042       lfstrip(inbuffer);
2043       if (!*inbuffer) break;         // killough 11/98
2044       if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
2045         {
2046           if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2047           continue;
2048         }
2049       if (!deh_strcasecmp(key,deh_sfxinfo[0]))  // Offset
2050         /* nop */ ;  // we don't know what this is, I don't think
2051       else
2052         if (!deh_strcasecmp(key,deh_sfxinfo[1]))  // Zero/One
2053           S_sfx[indexnum].singularity = (int)value;
2054         else
2055           if (!deh_strcasecmp(key,deh_sfxinfo[2]))  // Value
2056             S_sfx[indexnum].priority = (int)value;
2057           else
2058             if (!deh_strcasecmp(key,deh_sfxinfo[3]))  // Zero 1
2059               //S_sfx[indexnum].link = (sfxinfo_t *)value;
2060               ; // .link - don't set pointers from DeHackEd
2061             else
2062               if (!deh_strcasecmp(key,deh_sfxinfo[4]))  // Zero 2
2063                 S_sfx[indexnum].pitch = (int)value;
2064               else
2065                 if (!deh_strcasecmp(key,deh_sfxinfo[5]))  // Zero 3
2066                   S_sfx[indexnum].volume = (int)value;
2067                 else
2068                   if (!deh_strcasecmp(key,deh_sfxinfo[6]))  // Zero 4
2069                     //S_sfx[indexnum].data = (void *) value; // killough 5/3/98: changed cast
2070                     ; // .data - don't set pointers from DeHackEd
2071                   else
2072                     if (!deh_strcasecmp(key,deh_sfxinfo[7]))  // Neg. One 1
2073                       S_sfx[indexnum].usefulness = (int)value;
2074                     else
2075                       if (!deh_strcasecmp(key,deh_sfxinfo[8]))  // Neg. One 2
2076                         S_sfx[indexnum].lumpnum = (int)value;
2077                       else
2078                         if (fpout) fprintf(fpout,
2079                                            "Invalid sound string index for '%s'\n",key);
2080     }
2081   return;
2082 }
2083 
2084 // ====================================================================
2085 // deh_procAmmo
2086 // Purpose: Handle DEH Ammo block
2087 // Args:    fpin  -- input file stream
2088 //          fpout -- output file stream (DEHOUT.TXT)
2089 //          line  -- current line in file to process
2090 // Returns: void
2091 //
deh_procAmmo(DEHFILE * fpin,FILE * fpout,char * line)2092 static void deh_procAmmo(DEHFILE *fpin, FILE* fpout, char *line)
2093 {
2094   char key[DEH_MAXKEYLEN];
2095   char inbuffer[DEH_BUFFERMAX];
2096   uint_64_t value;      // All deh values are ints or longs
2097   int indexnum;
2098 
2099   strncpy(inbuffer,line,DEH_BUFFERMAX);
2100 
2101   // killough 8/98: allow hex numbers in input:
2102   sscanf(inbuffer,"%s %i",key, &indexnum);
2103   if (fpout) fprintf(fpout,"Processing Ammo at index %d: %s\n",
2104                      indexnum, key);
2105   if (indexnum < 0 || indexnum >= NUMAMMO)
2106     if (fpout) fprintf(fpout,"Bad ammo number %d of %d\n",
2107                        indexnum,NUMAMMO);
2108 
2109   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2110     {
2111       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2112       lfstrip(inbuffer);
2113       if (!*inbuffer) break;       // killough 11/98
2114       if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
2115         {
2116           if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2117           continue;
2118         }
2119       if (!deh_strcasecmp(key,deh_ammo[0]))  // Max ammo
2120         maxammo[indexnum] = (int)value;
2121       else
2122         if (!deh_strcasecmp(key,deh_ammo[1]))  // Per ammo
2123           clipammo[indexnum] = (int)value;
2124         else
2125           if (fpout) fprintf(fpout,"Invalid ammo string index for '%s'\n",key);
2126     }
2127   return;
2128 }
2129 
2130 // ====================================================================
2131 // deh_procWeapon
2132 // Purpose: Handle DEH Weapon block
2133 // Args:    fpin  -- input file stream
2134 //          fpout -- output file stream (DEHOUT.TXT)
2135 //          line  -- current line in file to process
2136 // Returns: void
2137 //
deh_procWeapon(DEHFILE * fpin,FILE * fpout,char * line)2138 static void deh_procWeapon(DEHFILE *fpin, FILE* fpout, char *line)
2139 {
2140   char key[DEH_MAXKEYLEN];
2141   char inbuffer[DEH_BUFFERMAX];
2142   uint_64_t value;      // All deh values are ints or longs
2143   int indexnum;
2144 
2145   strncpy(inbuffer,line,DEH_BUFFERMAX);
2146 
2147   // killough 8/98: allow hex numbers in input:
2148   sscanf(inbuffer,"%s %i",key, &indexnum);
2149   if (fpout) fprintf(fpout,"Processing Weapon at index %d: %s\n",
2150                      indexnum, key);
2151   if (indexnum < 0 || indexnum >= NUMWEAPONS)
2152     if (fpout) fprintf(fpout,"Bad weapon number %d of %d\n",
2153                        indexnum, NUMAMMO);
2154 
2155   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2156     {
2157       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2158       lfstrip(inbuffer);
2159       if (!*inbuffer) break;       // killough 11/98
2160       if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
2161         {
2162           if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2163           continue;
2164         }
2165       if (!deh_strcasecmp(key,deh_weapon[0]))  // Ammo type
2166         weaponinfo[indexnum].ammo = (ammotype_t)value;
2167       else
2168         if (!deh_strcasecmp(key,deh_weapon[1]))  // Deselect frame
2169           weaponinfo[indexnum].upstate = (int)value;
2170         else
2171           if (!deh_strcasecmp(key,deh_weapon[2]))  // Select frame
2172             weaponinfo[indexnum].downstate = (int)value;
2173           else
2174             if (!deh_strcasecmp(key,deh_weapon[3]))  // Bobbing frame
2175               weaponinfo[indexnum].readystate = (int)value;
2176             else
2177               if (!deh_strcasecmp(key,deh_weapon[4]))  // Shooting frame
2178                 weaponinfo[indexnum].atkstate = (int)value;
2179               else
2180                 if (!deh_strcasecmp(key,deh_weapon[5]))  // Firing frame
2181                   weaponinfo[indexnum].flashstate = (int)value;
2182                 else
2183                   if (fpout) fprintf(fpout,"Invalid weapon string index for '%s'\n",key);
2184     }
2185   return;
2186 }
2187 
2188 // ====================================================================
2189 // deh_procSprite
2190 // Purpose: Dummy - we do not support the DEH Sprite block
2191 // Args:    fpin  -- input file stream
2192 //          fpout -- output file stream (DEHOUT.TXT)
2193 //          line  -- current line in file to process
2194 // Returns: void
2195 //
deh_procSprite(DEHFILE * fpin,FILE * fpout,char * line)2196 static void deh_procSprite(DEHFILE *fpin, FILE* fpout, char *line) // Not supported
2197 {
2198   char key[DEH_MAXKEYLEN];
2199   char inbuffer[DEH_BUFFERMAX];
2200   int indexnum;
2201 
2202   // Too little is known about what this is supposed to do, and
2203   // there are better ways of handling sprite renaming.  Not supported.
2204 
2205   strncpy(inbuffer,line,DEH_BUFFERMAX);
2206 
2207   // killough 8/98: allow hex numbers in input:
2208   sscanf(inbuffer,"%s %i",key, &indexnum);
2209   if (fpout) fprintf(fpout,
2210                      "Ignoring Sprite offset change at index %d: %s\n",indexnum, key);
2211   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2212     {
2213       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2214       lfstrip(inbuffer);
2215       if (!*inbuffer) break;      // killough 11/98
2216       // ignore line
2217       if (fpout) fprintf(fpout,"- %s\n",inbuffer);
2218     }
2219   return;
2220 }
2221 
2222 // ====================================================================
2223 // deh_procPars
2224 // Purpose: Handle BEX extension for PAR times
2225 // Args:    fpin  -- input file stream
2226 //          fpout -- output file stream (DEHOUT.TXT)
2227 //          line  -- current line in file to process
2228 // Returns: void
2229 //
deh_procPars(DEHFILE * fpin,FILE * fpout,char * line)2230 static void deh_procPars(DEHFILE *fpin, FILE* fpout, char *line) // extension
2231 {
2232   char key[DEH_MAXKEYLEN];
2233   char inbuffer[DEH_BUFFERMAX];
2234   int indexnum;
2235   int episode, level, partime, oldpar;
2236 
2237   // new item, par times
2238   // usage: After [PARS] Par 0 section identifier, use one or more of these
2239   // lines:
2240   //  par 3 5 120
2241   //  par 14 230
2242   // The first would make the par for E3M5 be 120 seconds, and the
2243   // second one makes the par for MAP14 be 230 seconds.  The number
2244   // of parameters on the line determines which group of par values
2245   // is being changed.  Error checking is done based on current fixed
2246   // array sizes of[4][10] and [32]
2247 
2248   strncpy(inbuffer,line,DEH_BUFFERMAX);
2249 
2250   // killough 8/98: allow hex numbers in input:
2251   sscanf(inbuffer,"%s %i",key, &indexnum);
2252   if (fpout) fprintf(fpout,
2253                      "Processing Par value at index %d: %s\n",indexnum, key);
2254   // indexnum is a dummy entry
2255   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2256     {
2257       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2258       lfstrip(M_Strlwr(inbuffer)); // lowercase it
2259       if (!*inbuffer) break;      // killough 11/98
2260       if (3 != sscanf(inbuffer,"par %i %i %i",&episode, &level, &partime))
2261         { // not 3
2262           if (2 != sscanf(inbuffer,"par %i %i",&level, &partime))
2263             { // not 2
2264               if (fpout) fprintf(fpout,"Invalid par time setting string: %s\n",inbuffer);
2265             }
2266           else
2267             { // is 2
2268               // Ty 07/11/98 - wrong range check, not zero-based
2269               if (level < 1 || level > 32) // base 0 array (but 1-based parm)
2270                 {
2271                   if (fpout) fprintf(fpout,"Invalid MAPnn value MAP%d\n",level);
2272                 }
2273               else
2274                 {
2275                   oldpar = cpars[level-1];
2276                   if (fpout) fprintf(fpout,"Changed par time for MAP%02d from %d to %d\n",level,oldpar,partime);
2277                   cpars[level-1] = partime;
2278                   deh_pars = TRUE;
2279                 }
2280             }
2281         }
2282       else
2283         { // is 3
2284           // note that though it's a [4][10] array, the "left" and "top" aren't used,
2285           // effectively making it a base 1 array.
2286           // Ty 07/11/98 - level was being checked against max 3 - dumb error
2287           // Note that episode 4 does not have par times per original design
2288           // in Ultimate DOOM so that is not supported here.
2289           if (episode < 1 || episode > 3 || level < 1 || level > 9)
2290             {
2291               if (fpout) fprintf(fpout,
2292                                  "Invalid ExMx values E%dM%d\n",episode, level);
2293             }
2294           else
2295             {
2296               oldpar = pars[episode][level];
2297               pars[episode][level] = partime;
2298               if (fpout) fprintf(fpout,
2299                                  "Changed par time for E%dM%d from %d to %d\n",
2300                                  episode,level,oldpar,partime);
2301               deh_pars = TRUE;
2302             }
2303         }
2304     }
2305   return;
2306 }
2307 
2308 // ====================================================================
2309 // deh_procCheat
2310 // Purpose: Handle DEH Cheat block
2311 // Args:    fpin  -- input file stream
2312 //          fpout -- output file stream (DEHOUT.TXT)
2313 //          line  -- current line in file to process
2314 // Returns: void
2315 //
deh_procCheat(DEHFILE * fpin,FILE * fpout,char * line)2316 static void deh_procCheat(DEHFILE *fpin, FILE* fpout, char *line) // done
2317 {
2318   char key[DEH_MAXKEYLEN];
2319   char inbuffer[DEH_BUFFERMAX];
2320   uint_64_t value;      // All deh values are ints or longs
2321   char ch = 0; // CPhipps - `writable' null string to initialise...
2322   char *strval = &ch;  // pointer to the value area
2323   int ix, iy;   // array indices
2324   char *p;  // utility pointer
2325 
2326   if (fpout) fprintf(fpout,"Processing Cheat: %s\n",line);
2327 
2328   strncpy(inbuffer,line,DEH_BUFFERMAX);
2329   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2330     {
2331       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2332       lfstrip(inbuffer);
2333       if (!*inbuffer) break;       // killough 11/98
2334       if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
2335         {
2336           if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2337           continue;
2338         }
2339       // Otherwise we got a (perhaps valid) cheat name,
2340       // so look up the key in the array
2341 
2342       // killough 4/18/98: use main cheat code table in st_stuff.c now
2343       for (ix=0; cheat[ix].cheat; ix++)
2344         if (cheat[ix].deh_cheat)   // killough 4/18/98: skip non-deh
2345           {
2346             if (!stricmp(key,cheat[ix].deh_cheat))  // found the cheat, ignored case
2347               {
2348                 // replace it but don't overflow it.  Use current length as limit.
2349                 // Ty 03/13/98 - add 0xff code
2350                 // Deal with the fact that the cheats in deh files are extended
2351                 // with character 0xFF to the original cheat length, which we don't do.
2352                 for (iy=0; strval[iy]; iy++)
2353                   strval[iy] = (strval[iy]==(char)0xff) ? '\0' : strval[iy];
2354 
2355                 iy = ix;     // killough 4/18/98
2356 
2357                 // Ty 03/14/98 - skip leading spaces
2358                 p = strval;
2359                 while (*p == ' ') ++p;
2360                 // Ty 03/16/98 - change to use a strdup and orphan the original
2361                 // Also has the advantage of allowing length changes.
2362                 // strncpy(cheat[iy].cheat,p,strlen(cheat[iy].cheat));
2363 #if 0
2364                 {    // killough 9/12/98: disable cheats which are prefixes of this one
2365                   int i;
2366                   for (i=0; cheat[i].cheat; i++)
2367                     if (cheat[i].when & not_deh &&
2368                         !strncasecmp(cheat[i].cheat,
2369                                      cheat[iy].cheat,
2370                                      strlen(cheat[i].cheat)) && i != iy)
2371           cheat[i].deh_modified = true;
2372                 }
2373 #endif
2374                 //e6y: ability to ignore cheats in dehacked files.
2375                 if (deh_apply_cheats && !M_CheckParm("-nocheats"))
2376                 {
2377                   cheat[iy].cheat = strdup(p);
2378                   if (fpout) fprintf(fpout,
2379                     "Assigned new cheat '%s' to cheat '%s'at index %d\n",
2380                     p, cheat[ix].deh_cheat, iy); // killough 4/18/98
2381                 }
2382 
2383               }
2384           }
2385       if (fpout) fprintf(fpout,"- %s\n",inbuffer);
2386     }
2387   return;
2388 }
2389 
2390 // ====================================================================
2391 // deh_procMisc
2392 // Purpose: Handle DEH Misc block
2393 // Args:    fpin  -- input file stream
2394 //          fpout -- output file stream (DEHOUT.TXT)
2395 //          line  -- current line in file to process
2396 // Returns: void
2397 //
deh_procMisc(DEHFILE * fpin,FILE * fpout,char * line)2398 static void deh_procMisc(DEHFILE *fpin, FILE* fpout, char *line) // done
2399 {
2400   char key[DEH_MAXKEYLEN];
2401   char inbuffer[DEH_BUFFERMAX];
2402   uint_64_t value;      // All deh values are ints or longs
2403 
2404   strncpy(inbuffer,line,DEH_BUFFERMAX);
2405   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2406     {
2407       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2408       lfstrip(inbuffer);
2409       if (!*inbuffer) break;    // killough 11/98
2410       if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
2411         {
2412           if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2413           continue;
2414         }
2415       // Otherwise it's ok
2416       if (fpout) fprintf(fpout,"Processing Misc item '%s'\n", key);
2417 
2418       if (!deh_strcasecmp(key,deh_misc[0]))  // Initial Health
2419         initial_health = (int)value;
2420       else
2421         if (!deh_strcasecmp(key,deh_misc[1]))  // Initial Bullets
2422           initial_bullets = (int)value;
2423         else
2424           if (!deh_strcasecmp(key,deh_misc[2]))  // Max Health
2425             IsDehMaxHealth = true, deh_maxhealth = (int)value; //e6y
2426           else
2427             if (!deh_strcasecmp(key,deh_misc[3]))  // Max Armor
2428               max_armor = (int)value;
2429             else
2430               if (!deh_strcasecmp(key,deh_misc[4]))  // Green Armor Class
2431                 green_armor_class = (int)value;
2432               else
2433                 if (!deh_strcasecmp(key,deh_misc[5]))  // Blue Armor Class
2434                   blue_armor_class = (int)value;
2435                 else
2436                   if (!deh_strcasecmp(key,deh_misc[6]))  // Max Soulsphere
2437                     IsDehMaxSoul = true, deh_max_soul = (int)value; //e6y
2438                   else
2439                     if (!deh_strcasecmp(key,deh_misc[7]))  // Soulsphere Health
2440                       soul_health = (int)value;
2441                     else
2442                       if (!deh_strcasecmp(key,deh_misc[8]))  // Megasphere Health
2443                         IsDehMegaHealth = true, deh_mega_health = (int)value; //e6y
2444                       else
2445                         if (!deh_strcasecmp(key,deh_misc[9]))  // God Mode Health
2446                           god_health = (int)value;
2447                         else
2448                           if (!deh_strcasecmp(key,deh_misc[10]))  // IDFA Armor
2449                             idfa_armor = (int)value;
2450                           else
2451                             if (!deh_strcasecmp(key,deh_misc[11]))  // IDFA Armor Class
2452                               idfa_armor_class = (int)value;
2453                             else
2454                               if (!deh_strcasecmp(key,deh_misc[12]))  // IDKFA Armor
2455                                 idkfa_armor = (int)value;
2456                               else
2457                                 if (!deh_strcasecmp(key,deh_misc[13]))  // IDKFA Armor Class
2458                                   idkfa_armor_class = (int)value;
2459                                 else
2460                                   if (!deh_strcasecmp(key,deh_misc[14]))  // BFG Cells/Shot
2461                                     bfgcells = (int)value;
2462                                   else
2463                                     if (!deh_strcasecmp(key,deh_misc[15])) { // Monsters Infight
2464                                       // e6y: Dehacked support - monsters infight
2465                                       if (value == 202) monsters_infight = 0;
2466                                       else if (value == 221) monsters_infight = 1;
2467                                       else if (fpout) fprintf(fpout,
2468                                         "Invalid value for 'Monsters Infight': %i", (int)value);
2469 
2470                                       /* No such switch in DOOM - nop */ //e6y ;
2471                                     } else
2472                                       if (fpout) fprintf(fpout,
2473                                                          "Invalid misc item string index for '%s'\n",key);
2474     }
2475   return;
2476 }
2477 
2478 // ====================================================================
2479 // deh_procText
2480 // Purpose: Handle DEH Text block
2481 // Notes:   We look things up in the current information and if found
2482 //          we replace it.  At the same time we write the new and
2483 //          improved BEX syntax to the log file for future use.
2484 // Args:    fpin  -- input file stream
2485 //          fpout -- output file stream (DEHOUT.TXT)
2486 //          line  -- current line in file to process
2487 // Returns: void
2488 //
deh_procText(DEHFILE * fpin,FILE * fpout,char * line)2489 static void deh_procText(DEHFILE *fpin, FILE* fpout, char *line)
2490 {
2491   char key[DEH_MAXKEYLEN];
2492   char inbuffer[DEH_BUFFERMAX*2];  // can't use line -- double size buffer too.
2493   int i; // loop variable
2494   int fromlen, tolen;  // as specified on the text block line
2495   int usedlen;  // shorter of fromlen and tolen if not matched
2496   dboolean found = FALSE;  // to allow early exit once found
2497   char* line2 = NULL;   // duplicate line for rerouting
2498 
2499   // e6y
2500   // Correction for DEHs which swap the values of two strings. For example:
2501   // Text 4 4  Text 4 4;   Text 6 6      Text 6 6
2502   // BOSSBOS2  BOS2BOSS;   RUNNINSTALKS  STALKSRUNNIN
2503   // It corrects buggy behaviour on "All Hell is Breaking Loose" TC
2504   // http://www.doomworld.com/idgames/index.php?id=6480
2505   static dboolean sprnames_state[NUMSPRITES+1];
2506   static dboolean S_sfx_state[NUMSFX];
2507   static dboolean S_music_state[NUMMUSIC];
2508 
2509   // Ty 04/11/98 - Included file may have NOTEXT skip flag set
2510   if (includenotext) // flag to skip included deh-style text
2511     {
2512       if (fpout) fprintf(fpout,
2513                          "Skipped text block because of notext directive\n");
2514       strcpy(inbuffer,line);
2515       while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2516         dehfgets(inbuffer, sizeof(inbuffer), fpin);  // skip block
2517       // Ty 05/17/98 - don't care if this fails
2518       return; // ************** Early return
2519     }
2520 
2521   // killough 8/98: allow hex numbers in input:
2522   sscanf(line,"%s %i %i",key,&fromlen,&tolen);
2523   if (fpout) fprintf(fpout,
2524                      "Processing Text (key=%s, from=%d, to=%d)\n",
2525                      key, fromlen, tolen);
2526 
2527   // killough 10/98: fix incorrect usage of feof
2528   {
2529     int c, totlen = 0;
2530     while (totlen < fromlen + tolen && (c = dehfgetc(fpin)) != EOF)
2531       if (c != '\r')
2532 	inbuffer[totlen++] = c;
2533     inbuffer[totlen]='\0';
2534   }
2535 
2536   // if the from and to are 4, this may be a sprite rename.  Check it
2537   // against the array and process it as such if it matches.  Remember
2538   // that the original names are (and should remain) uppercase.
2539   // Future: this will be from a separate [SPRITES] block.
2540   if (fromlen==4 && tolen==4)
2541     {
2542       i=0;
2543       while (sprnames[i])  // null terminated list in info.c //jff 3/19/98
2544         {                                                      //check pointer
2545           if (!strnicmp(sprnames[i],inbuffer,fromlen) && !sprnames_state[i])         //not first char
2546             {
2547               if (fpout) fprintf(fpout,
2548                                  "Changing name of sprite at index %d from %s to %*s\n",
2549                                  i,sprnames[i],tolen,&inbuffer[fromlen]);
2550               // Ty 03/18/98 - not using strdup because length is fixed
2551 
2552               // killough 10/98: but it's an array of pointers, so we must
2553               // use strdup unless we redeclare sprnames and change all else
2554         {
2555     // CPhipps - fix constness problem
2556     char *s;
2557     sprnames[i] = s = strdup(sprnames[i]);
2558 
2559     //e6y: flag the sprite as changed
2560     sprnames_state[i] = true;
2561 
2562     strncpy(s,&inbuffer[fromlen],tolen);
2563         }
2564               found = TRUE;
2565               break;  // only one will match--quit early
2566             }
2567           ++i;  // next array element
2568         }
2569     }
2570   else
2571     if (fromlen < 7 && tolen < 7)  // lengths of music and sfx are 6 or shorter
2572       {
2573         usedlen = (fromlen < tolen) ? fromlen : tolen;
2574         if (fromlen != tolen)
2575           if (fpout) fprintf(fpout,
2576                              "Warning: Mismatched lengths from=%d, to=%d, used %d\n",
2577                              fromlen, tolen, usedlen);
2578         // Try sound effects entries - see sounds.c
2579         for (i=1; i<NUMSFX; i++)
2580           {
2581             // avoid short prefix erroneous match
2582             if (strlen(S_sfx[i].name) != (size_t)fromlen) continue;
2583             if (!strnicmp(S_sfx[i].name,inbuffer,fromlen) && !S_sfx_state[i])
2584               {
2585                 if (fpout) fprintf(fpout,
2586                                    "Changing name of sfx from %s to %*s\n",
2587                                    S_sfx[i].name,usedlen,&inbuffer[fromlen]);
2588 
2589                 S_sfx[i].name = strdup(&inbuffer[fromlen]);
2590 
2591                 //e6y: flag the SFX as changed
2592                 S_sfx_state[i] = true;
2593 
2594                 found = TRUE;
2595                 break;  // only one matches, quit early
2596               }
2597           }
2598         if (!found)  // not yet
2599           {
2600             // Try music name entries - see sounds.c
2601             for (i=1; i<NUMMUSIC; i++)
2602               {
2603                 // avoid short prefix erroneous match
2604                 if (strlen(S_music[i].name) != (size_t)fromlen) continue;
2605                 if (!strnicmp(S_music[i].name,inbuffer,fromlen) && !S_music_state[i])
2606                   {
2607                     if (fpout) fprintf(fpout,
2608                                        "Changing name of music from %s to %*s\n",
2609                                        S_music[i].name,usedlen,&inbuffer[fromlen]);
2610 
2611                     S_music[i].name = strdup(&inbuffer[fromlen]);
2612 
2613                     //e6y: flag the music as changed
2614                     S_music_state[i] = true;
2615 
2616                     found = TRUE;
2617                     break;  // only one matches, quit early
2618                   }
2619               }
2620           }  // end !found test
2621       }
2622 
2623   if (!found) // Nothing we want to handle here--see if strings can deal with it.
2624     {
2625       if (fpout) fprintf(fpout,"Checking text area through strings for '%.12s%s' from=%d to=%d\n",inbuffer, (strlen(inbuffer) > 12) ? "..." : "",fromlen,tolen);
2626       if ((size_t)fromlen <= strlen(inbuffer))
2627         {
2628           line2 = strdup(&inbuffer[fromlen]);
2629           inbuffer[fromlen] = '\0';
2630         }
2631 
2632       deh_procStringSub(NULL, inbuffer, line2, fpout);
2633     }
2634   free(line2); // may be NULL, ignored by free()
2635   return;
2636 }
2637 
deh_procError(DEHFILE * fpin,FILE * fpout,char * line)2638 static void deh_procError(DEHFILE *fpin, FILE* fpout, char *line)
2639 {
2640   char inbuffer[DEH_BUFFERMAX];
2641 
2642   strncpy(inbuffer,line,DEH_BUFFERMAX);
2643   if (fpout) fprintf(fpout,"Unmatched Block: '%s'\n",inbuffer);
2644   return;
2645 }
2646 
2647 // ====================================================================
2648 // deh_procStrings
2649 // Purpose: Handle BEX [STRINGS] extension
2650 // Args:    fpin  -- input file stream
2651 //          fpout -- output file stream (DEHOUT.TXT)
2652 //          line  -- current line in file to process
2653 // Returns: void
2654 //
deh_procStrings(DEHFILE * fpin,FILE * fpout,char * line)2655 static void deh_procStrings(DEHFILE *fpin, FILE* fpout, char *line)
2656 {
2657   char key[DEH_MAXKEYLEN];
2658   char inbuffer[DEH_BUFFERMAX];
2659   uint_64_t value;    // All deh values are ints or longs
2660   char *strval;      // holds the string value of the line
2661   static size_t maxstrlen = 128; // maximum string length, bumped 128 at
2662   // a time as needed
2663   // holds the final result of the string after concatenation
2664   static char *holdstring = NULL;
2665   dboolean found = false;  // looking for string continuation
2666 
2667   if (fpout) fprintf(fpout,"Processing extended string substitution\n");
2668 
2669   if (!holdstring) holdstring = malloc(maxstrlen*sizeof(*holdstring));
2670 
2671   *holdstring = '\0';  // empty string to start with
2672   strncpy(inbuffer,line,DEH_BUFFERMAX);
2673   // Ty 04/24/98 - have to allow inbuffer to start with a blank for
2674   // the continuations of C1TEXT etc.
2675   while (!dehfeof(fpin) && *inbuffer)  /* && (*inbuffer != ' ') */
2676     {
2677       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2678       if (*inbuffer == '#') continue;  // skip comment lines
2679       lfstrip(inbuffer);
2680       if (!*inbuffer) break;  // killough 11/98
2681       if (!*holdstring) // first one--get the key
2682         {
2683           if (!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
2684             {
2685               if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2686               continue;
2687             }
2688         }
2689       while (strlen(holdstring) + strlen(inbuffer) > maxstrlen) // Ty03/29/98 - fix stupid error
2690         {
2691     // killough 11/98: allocate enough the first time
2692           maxstrlen = strlen(holdstring) + strlen(inbuffer);
2693           if (fpout) fprintf(fpout,
2694                              "* increased buffer from to %d for buffer size %d\n",
2695                              maxstrlen,(int)strlen(inbuffer));
2696           holdstring = realloc(holdstring,maxstrlen*sizeof(*holdstring));
2697         }
2698       // concatenate the whole buffer if continuation or the value iffirst
2699       strcat(holdstring,ptr_lstrip(((*holdstring) ? inbuffer : strval)));
2700       rstrip(holdstring);
2701       // delete any trailing blanks past the backslash
2702       // note that blanks before the backslash will be concatenated
2703       // but ones at the beginning of the next line will not, allowing
2704       // indentation in the file to read well without affecting the
2705       // string itself.
2706       if (holdstring[strlen(holdstring)-1] == '\\')
2707         {
2708           holdstring[strlen(holdstring)-1] = '\0';
2709           continue; // ready to concatenate
2710         }
2711       if (*holdstring) // didn't have a backslash, trap above would catch that
2712         {
2713           // go process the current string
2714           found = deh_procStringSub(key, NULL, holdstring, fpout);  // supply keyand not search string
2715 
2716           if (!found)
2717             if (fpout) fprintf(fpout,
2718                                "Invalid string key '%s', substitution skipped.\n",key);
2719 
2720           *holdstring = '\0';  // empty string for the next one
2721         }
2722     }
2723   return;
2724 }
2725 
2726 // ====================================================================
2727 // deh_procStringSub
2728 // Purpose: Common string parsing and handling routine for DEH and BEX
2729 // Args:    key       -- place to put the mnemonic for the string if found
2730 //          lookfor   -- original value string to look for
2731 //          newstring -- string to put in its place if found
2732 //          fpout     -- file stream pointer for log file (DEHOUT.TXT)
2733 // Returns: dboolean: True if string found, false if not
2734 //
deh_procStringSub(char * key,char * lookfor,char * newstring,FILE * fpout)2735 dboolean deh_procStringSub(char *key, char *lookfor, char *newstring, FILE *fpout)
2736 {
2737   dboolean found; // loop exit flag
2738   int i;  // looper
2739 
2740   found = false;
2741   for (i=0;i<deh_numstrlookup;i++)
2742     {
2743       if (deh_strlookup[i].orig == NULL)
2744       {
2745         deh_strlookup[i].orig = *deh_strlookup[i].ppstr;
2746       }
2747       found = lookfor ?
2748         !stricmp(deh_strlookup[i].orig,lookfor) :
2749         !stricmp(deh_strlookup[i].lookup,key);
2750 
2751       if (found)
2752         {
2753     char *t;
2754           *deh_strlookup[i].ppstr = t = strdup(newstring); // orphan originalstring
2755           found = true;
2756           // Handle embedded \n's in the incoming string, convert to 0x0a's
2757           {
2758             const char *s;
2759             for (s=*deh_strlookup[i].ppstr; *s; ++s, ++t)
2760               {
2761                 if (*s == '\\' && (s[1] == 'n' || s[1] == 'N')) //found one
2762       ++s, *t = '\n';  // skip one extra for second character
2763                 else
2764                   *t = *s;
2765               }
2766             *t = '\0';  // cap off the target string
2767           }
2768 
2769           if (key)
2770             if (fpout) fprintf(fpout,
2771                                "Assigned key %s => '%s'\n",key,newstring);
2772 
2773           if (!key)
2774             if (fpout) fprintf(fpout,
2775                                "Assigned '%.12s%s' to'%.12s%s' at key %s\n",
2776                                lookfor, (strlen(lookfor) > 12) ? "..." : "",
2777                                newstring, (strlen(newstring) > 12) ? "..." :"",
2778                                deh_strlookup[i].lookup);
2779 
2780           if (!key) // must have passed an old style string so showBEX
2781             if (fpout) fprintf(fpout,
2782                                "*BEX FORMAT:\n%s = %s\n*END BEX\n",
2783                                deh_strlookup[i].lookup,
2784                                dehReformatStr(newstring));
2785 
2786           break;
2787         }
2788     }
2789   if (!found)
2790     if (fpout) fprintf(fpout,
2791                        "Could not find '%.12s'\n",key ? key: lookfor);
2792 
2793   return found;
2794 }
2795 
2796 //========================================================================
2797 // haleyjd 9/22/99
2798 //
2799 // deh_procHelperThing
2800 //
2801 // Allows handy substitution of any thing for helper dogs.  DEH patches
2802 // are being made frequently for this purpose and it requires a complete
2803 // rewiring of the DOG thing.  I feel this is a waste of effort, and so
2804 // have added this new [HELPER] BEX block
2805 
deh_procHelperThing(DEHFILE * fpin,FILE * fpout,char * line)2806 static void deh_procHelperThing(DEHFILE *fpin, FILE *fpout, char *line)
2807 {
2808   char key[DEH_MAXKEYLEN];
2809   char inbuffer[DEH_BUFFERMAX];
2810   uint_64_t value;      // All deh values are ints or longs
2811 
2812   strncpy(inbuffer,line,DEH_BUFFERMAX);
2813   while (!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2814   {
2815       if (!dehfgets(inbuffer, sizeof(inbuffer), fpin)) break;
2816       lfstrip(inbuffer);
2817       if (!*inbuffer) break;
2818       if (!deh_GetData(inbuffer,key,&value,NULL,fpout)) // returns TRUE if ok
2819       {
2820           if (fpout) fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2821           continue;
2822       }
2823       // Otherwise it's ok
2824       if (fpout)
2825       {
2826         fprintf(fpout,"Processing Helper Thing item '%s'\n", key);
2827         fprintf(fpout,"value is %i", (int)value);
2828       }
2829       if (!strncasecmp(key, "type", 4))
2830         HelperThing = (int)value;
2831   }
2832   return;
2833 }
2834 
2835 //
2836 // deh_procBexSprites
2837 //
2838 // Supports sprite name substitutions without requiring use
2839 // of the DeHackEd Text block
2840 //
deh_procBexSprites(DEHFILE * fpin,FILE * fpout,char * line)2841 static void deh_procBexSprites(DEHFILE *fpin, FILE *fpout, char *line)
2842 {
2843    char key[DEH_MAXKEYLEN];
2844    char inbuffer[DEH_BUFFERMAX];
2845    uint_64_t value;    // All deh values are ints or longs
2846    char *strval;  // holds the string value of the line
2847    char candidate[5];
2848    int  rover;
2849 
2850    if(fpout)
2851       fprintf(fpout,"Processing sprite name substitution\n");
2852 
2853    strncpy(inbuffer,line,DEH_BUFFERMAX);
2854 
2855    while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2856    {
2857       if(!dehfgets(inbuffer, sizeof(inbuffer), fpin))
2858         break;
2859       if(*inbuffer == '#')
2860         continue;  // skip comment lines
2861       lfstrip(inbuffer);
2862       if(!*inbuffer)
2863         break;  // killough 11/98
2864       if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
2865       {
2866         if(fpout)
2867           fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2868         continue;
2869       }
2870       // do it
2871       memset(candidate, 0, sizeof(candidate));
2872       strncpy(candidate, ptr_lstrip(strval), 4);
2873       if(strlen(candidate) != 4)
2874       {
2875 	 if(fpout)
2876 	    fprintf(fpout, "Bad length for sprite name '%s'\n",
2877 	            candidate);
2878 	 continue;
2879       }
2880 
2881       rover = 0;
2882       while(deh_spritenames[rover])
2883       {
2884 	 if(!strncasecmp(deh_spritenames[rover], key, 4))
2885 	 {
2886 	    if(fpout)
2887 	       fprintf(fpout, "Substituting '%s' for sprite '%s'\n",
2888 	               candidate, deh_spritenames[rover]);
2889 
2890 	    sprnames[rover] = strdup(candidate);
2891 	    break;
2892 	 }
2893 	 rover++;
2894       }
2895    }
2896 }
2897 
2898 // ditto for sound names
deh_procBexSounds(DEHFILE * fpin,FILE * fpout,char * line)2899 static void deh_procBexSounds(DEHFILE *fpin, FILE *fpout, char *line)
2900 {
2901    char key[DEH_MAXKEYLEN];
2902    char inbuffer[DEH_BUFFERMAX];
2903    uint_64_t value;    // All deh values are ints or longs
2904    char *strval;  // holds the string value of the line
2905    char candidate[7];
2906    int  rover;
2907    size_t len;
2908 
2909    if(fpout)
2910       fprintf(fpout,"Processing sound name substitution\n");
2911 
2912    strncpy(inbuffer,line,DEH_BUFFERMAX);
2913 
2914    while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2915    {
2916       if(!dehfgets(inbuffer, sizeof(inbuffer), fpin))
2917 	 break;
2918       if(*inbuffer == '#')
2919 	 continue;  // skip comment lines
2920       lfstrip(inbuffer);
2921       if(!*inbuffer)
2922 	 break;  // killough 11/98
2923       if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
2924       {
2925 	 if(fpout)
2926 	    fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2927 	 continue;
2928       }
2929       // do it
2930       memset(candidate, 0, 7);
2931       strncpy(candidate, ptr_lstrip(strval), 6);
2932       len = strlen(candidate);
2933       if(len < 1 || len > 6)
2934       {
2935 	 if(fpout)
2936 	    fprintf(fpout, "Bad length for sound name '%s'\n",
2937 	            candidate);
2938 	 continue;
2939       }
2940 
2941       rover = 1;
2942       while(deh_soundnames[rover])
2943       {
2944 	 if(!strncasecmp(deh_soundnames[rover], key, 6))
2945 	 {
2946 	    if(fpout)
2947 	       fprintf(fpout, "Substituting '%s' for sound '%s'\n",
2948 	               candidate, deh_soundnames[rover]);
2949 
2950 	    S_sfx[rover].name = strdup(candidate);
2951 	    break;
2952 	 }
2953 	 rover++;
2954       }
2955    }
2956 }
2957 
2958 // ditto for music names
deh_procBexMusic(DEHFILE * fpin,FILE * fpout,char * line)2959 static void deh_procBexMusic(DEHFILE *fpin, FILE *fpout, char *line)
2960 {
2961    char key[DEH_MAXKEYLEN];
2962    char inbuffer[DEH_BUFFERMAX];
2963    uint_64_t value;    // All deh values are ints or longs
2964    char *strval;  // holds the string value of the line
2965    char candidate[7];
2966    int  rover;
2967    size_t len;
2968 
2969    if(fpout)
2970       fprintf(fpout,"Processing music name substitution\n");
2971 
2972    strncpy(inbuffer,line,DEH_BUFFERMAX);
2973 
2974    while(!dehfeof(fpin) && *inbuffer && (*inbuffer != ' '))
2975    {
2976       if(!dehfgets(inbuffer, sizeof(inbuffer), fpin))
2977 	 break;
2978       if(*inbuffer == '#')
2979 	 continue;  // skip comment lines
2980       lfstrip(inbuffer);
2981       if(!*inbuffer)
2982 	 break;  // killough 11/98
2983       if(!deh_GetData(inbuffer,key,&value,&strval,fpout)) // returns TRUE if ok
2984       {
2985 	 if(fpout)
2986 	    fprintf(fpout,"Bad data pair in '%s'\n",inbuffer);
2987 	 continue;
2988       }
2989       // do it
2990       memset(candidate, 0, 7);
2991       strncpy(candidate, ptr_lstrip(strval), 6);
2992       len = strlen(candidate);
2993       if(len < 1 || len > 6)
2994       {
2995 	 if(fpout)
2996 	    fprintf(fpout, "Bad length for music name '%s'\n",
2997 	            candidate);
2998 	 continue;
2999       }
3000 
3001       rover = 1;
3002       while(deh_musicnames[rover])
3003       {
3004 	 if(!strncasecmp(deh_musicnames[rover], key, 6))
3005 	 {
3006 	    if(fpout)
3007 	       fprintf(fpout, "Substituting '%s' for music '%s'\n",
3008 	               candidate, deh_musicnames[rover]);
3009 
3010 	    S_music[rover].name = strdup(candidate);
3011 	    break;
3012 	 }
3013 	 rover++;
3014       }
3015    }
3016 }
3017 
3018 // ====================================================================
3019 // General utility function(s)
3020 // ====================================================================
3021 
3022 // ====================================================================
3023 // dehReformatStr
3024 // Purpose: Convert a string into a continuous string with embedded
3025 //          linefeeds for "\n" sequences in the source string
3026 // Args:    string -- the string to convert
3027 // Returns: the converted string (converted in a static buffer)
3028 //
dehReformatStr(char * string)3029 char *dehReformatStr(char *string)
3030 {
3031   static char buff[DEH_BUFFERMAX]; // only processing the changed string,
3032   //  don't need double buffer
3033   char *s, *t;
3034 
3035   s = string;  // source
3036   t = buff;    // target
3037   // let's play...
3038 
3039   while (*s)
3040     {
3041       if (*s == '\n')
3042         ++s, *t++ = '\\', *t++ = 'n', *t++ = '\\', *t++='\n';
3043       else
3044         *t++ = *s++;
3045     }
3046   *t = '\0';
3047   return buff;
3048 }
3049 
3050 // ====================================================================
3051 // lfstrip
3052 // Purpose: Strips CR/LF off the end of a string
3053 // Args:    s -- the string to work on
3054 // Returns: void -- the string is modified in place
3055 //
3056 // killough 10/98: only strip at end of line, not entire string
3057 
lfstrip(char * s)3058 void lfstrip(char *s)  // strip the \r and/or \n off of a line
3059 {
3060   char *p = s+strlen(s);
3061   while (p > s && (*--p=='\r' || *p=='\n'))
3062     *p = 0;
3063 }
3064 
3065 // ====================================================================
3066 // rstrip
3067 // Purpose: Strips trailing blanks off a string
3068 // Args:    s -- the string to work on
3069 // Returns: void -- the string is modified in place
3070 //
rstrip(char * s)3071 void rstrip(char *s)  // strip trailing whitespace
3072 {
3073   char *p = s+strlen(s);         // killough 4/4/98: same here
3074   while (p > s && isspace(*--p)) // break on first non-whitespace
3075     *p='\0';
3076 }
3077 
3078 // ====================================================================
3079 // ptr_lstrip
3080 // Purpose: Points past leading whitespace in a string
3081 // Args:    s -- the string to work on
3082 // Returns: char * pointing to the first nonblank character in the
3083 //          string.  The original string is not changed.
3084 //
ptr_lstrip(char * p)3085 char *ptr_lstrip(char *p)  // point past leading whitespace
3086 {
3087   while (isspace(*p))
3088     p++;
3089   return p;
3090 }
3091 
3092 // ====================================================================
3093 // deh_GetData
3094 // Purpose: Get a key and data pair from a passed string
3095 // Args:    s -- the string to be examined
3096 //          k -- a place to put the key
3097 //          l -- pointer to a long integer to store the number
3098 //          strval -- a pointer to the place in s where the number
3099 //                    value comes from.  Pass NULL to not use this.
3100 //          fpout  -- stream pointer to output log (DEHOUT.TXT)
3101 // Notes:   Expects a key phrase, optional space, equal sign,
3102 //          optional space and a value, mostly an int but treated
3103 //          as a long just in case.  The passed pointer to hold
3104 //          the key must be DEH_MAXKEYLEN in size.
3105 
deh_GetData(char * s,char * k,uint_64_t * l,char ** strval,FILE * fpout)3106 dboolean deh_GetData(char *s, char *k, uint_64_t *l, char **strval, FILE *fpout)
3107 {
3108   char *t;  // current char
3109   int val; // to hold value of pair
3110   char buffer[DEH_MAXKEYLEN];  // to hold key in progress
3111   // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
3112   // No more desync on HACX demos.
3113   dboolean okrc = 1;  // assume good unless we have problems
3114   int i;  // iterator
3115 
3116   *buffer = '\0';
3117   val = 0;  // defaults in case not otherwise set
3118   for (i=0, t=s; *t && i < DEH_MAXKEYLEN; t++, i++)
3119     {
3120       if (*t == '=') break;
3121       buffer[i] = *t;  // copy it
3122     }
3123   buffer[--i] = '\0';  // terminate the key before the '='
3124   if (!*t)  // end of string with no equal sign
3125     {
3126       okrc = FALSE;
3127     }
3128   else
3129     {
3130       if (!*++t)
3131         {
3132           val = 0;  // in case "thiskey =" with no value
3133           okrc = FALSE;
3134         }
3135       // we've incremented t
3136       // e6y: Correction of wrong processing of Bits parameter if its value is equal to zero
3137       // No more desync on HACX demos.
3138       // Old code: e6y val = strtol(t,NULL,0);  // killough 8/9/98: allow hex or octal input
3139       if (!M_StrToInt(t,&val))
3140       {
3141         val = 0;
3142         okrc = 2;
3143       }
3144     }
3145 
3146   // go put the results in the passed pointers
3147   *l = val;  // may be a faked zero
3148 
3149   // if spaces between key and equal sign, strip them
3150   strcpy(k,ptr_lstrip(buffer));  // could be a zero-length string
3151 
3152   if (strval != NULL) // pass NULL if you don't want this back
3153     *strval = t;      // pointer, has to be somewhere in s,
3154   // even if pointing at the zero byte.
3155 
3156   return(okrc);
3157 }
3158