1 /*
2  * Copyright 2000 David Chess; Copyright 2005-2007 Sam Trenholme
3  *
4  * Slump is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License as published by the Free
6  * Software Foundation; either version 2, or (at your option) any later
7  * version.
8  *
9  * Slump is distributed in the hope that it will be useful, but WITHOUT ANY
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with Slump; see the file GPL.  If not, write to the Free
16  * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
17  * 02111-1307, USA.
18  *
19  * Additionally, while not required for redistribution of this program,
20  * the following requests are made when making a derived version of
21  * this program:
22  *
23  * - Slump's code is partly derived from the Doom map generator
24  *   called SLIGE, by David Chess.  Please inform David Chess of
25  *   any derived version that you make.  His email address is at
26  *   the domain "theogeny.com" with the name "chess" placed before
27  *   the at symbol.
28  *
29  * - Please do not call any derivative of this program SLIGE.
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #include <assert.h>
37 #include "slump.h"
38 
39 #include <machine/endian.h>
40 
41 #if BYTE_ORDER == BIG_ENDIAN
42 #define ENDIAN_BIG
43 #endif
44 
45 /* Global variables */
46 
47 extern int current_level_number;
48 extern int global_verbosity;    /* Oooh, a global variable! */
49 extern boolean ok_to_roll;  /* Stop breaking -seed...   */
50 
51 #ifdef ENDIAN_BIG
swap_32(unsigned int in)52 unsigned int swap_32(unsigned int in) {
53 	return ((in >> 24) & 0xff)  | /* hi byte (byte 1) becomes low byte */
54 	       ((in >> 8) & 0xff00) | /* byte 2 becomes byte 3 */
55                ((in & 0xff00) << 8) | /* byte 3 becomes byte 2 */
56 	       ((in & 0xff) << 24)  ; /* low byte becomes hi byte */
57 }
swap_32s(int in)58 int swap_32s(int in) {
59 	return ((in >> 24) & 0xff)  | /* hi byte (byte 1) becomes low byte */
60 	       ((in >> 8) & 0xff00) | /* byte 2 becomes byte 3 */
61                ((in & 0xff00) << 8) | /* byte 3 becomes byte 2 */
62 	       ((in & 0xff) << 24)  ; /* low byte becomes hi byte */
63 }
swap_16(short in)64 short swap_16(short in) {
65 	return ((in >> 8) & 0xff) |
66 	       ((in & 0xff) << 8);
67 }
68 #endif /* ENDIAN_BIG */
69 
70 /* Open a file ready to dump multiple levels into */
OpenDump(config * c)71 dumphandle OpenDump(config *c)
72 {
73   dumphandle answer;
74   struct {
75     char tag[4];
76     unsigned long lmpcount;
77     unsigned long inxoffset;
78   } headerstuff;
79 
80   answer = (dumphandle)malloc(sizeof (*answer));
81   answer->f = fopen(c->outfile,"wb");
82   if (answer->f==NULL) {
83     fprintf(stderr,"Error opening <%s>.\n",c->outfile);
84     perror("Maybe");
85     return NULL;
86   }
87   memcpy(headerstuff.tag,"PWAD",4);
88   /* No endian issues since these values are zero */
89   headerstuff.lmpcount = 0;  /* To be filled in later */
90   headerstuff.inxoffset = 0;
91   fwrite(&headerstuff,sizeof(headerstuff),1,answer->f);
92   answer->offset_to_index = sizeof(headerstuff);  /* Length of the header */
93   answer->index_entry_anchor = 0;
94   answer->lmpcount = 0;
95   return answer;
96 }
97 
98 /* Write out the directory, patch up the header, and close the file */
CloseDump(dumphandle dh)99 void CloseDump(dumphandle dh)
100 {
101   struct {
102     unsigned long offset;
103     unsigned long length;
104     char lumpname[8];
105   } directory_entry;
106 
107   index_entry *ie;
108 
109   /* Write the index entries */
110   for (ie=dh->index_entry_anchor;ie;ie=ie->next) {
111     directory_entry.offset = ie->offset;
112     directory_entry.length = ie->length;
113 #ifdef ENDIAN_BIG
114     directory_entry.offset = swap_32(directory_entry.offset);
115     directory_entry.length = swap_32(directory_entry.length);
116 #endif /* ENDIAN_BIG */
117     memset(directory_entry.lumpname,0,8);
118     memcpy(directory_entry.lumpname,ie->name,strlen(ie->name));
119     fwrite(&directory_entry,sizeof(directory_entry),1,dh->f);
120   }
121 
122   /* Go back and patch up the header */
123   fseek(dh->f,4,SEEK_SET);
124 #ifdef ENDIAN_BIG
125   dh->lmpcount = swap_32(dh->lmpcount);
126   dh->offset_to_index = swap_32(dh->offset_to_index);
127 #endif /* ENDIAN_BIG */
128   fwrite(&(dh->lmpcount),sizeof(unsigned int),1,dh->f);
129   fwrite(&(dh->offset_to_index),sizeof(unsigned int),1,dh->f);
130 #ifdef ENDIAN_BIG
131   /* Swap back in case we use the numbers later */
132   dh->lmpcount = swap_32(dh->lmpcount);
133   dh->offset_to_index = swap_32(dh->offset_to_index);
134 #endif /* ENDIAN_BIG */
135 
136   /* and that's all! */
137   fclose(dh->f);
138 
139 }
140 
141 /* Record the information about a new lmp of the given size */
RegisterLmp(dumphandle dh,char * s,unsigned int size)142 void RegisterLmp(dumphandle dh,char *s,unsigned int size)
143 {
144   index_entry *ie, *ie2;
145 
146   ie = (index_entry *)malloc(sizeof(*ie));
147   ie->next = NULL;
148   /* This list really has to be in frontwards order! */
149   if (dh->index_entry_anchor==NULL) {
150     dh->index_entry_anchor = ie;
151   } else {
152     for (ie2=dh->index_entry_anchor;ie2->next;ie2=ie2->next);
153     ie2->next = ie;
154   }
155   strcpy(ie->name,s);
156   ie->offset = dh->offset_to_index;
157   ie->length = size;
158   dh->offset_to_index+=size;
159   dh->lmpcount++;
160 }
161 
162 /* Given a dumphandle, a music header, a music buffer, a lump name, */
163 /* and for some reason a config, do what's necessary to record it   */
164 /* in the file and index and stuff. */
record_music(dumphandle dh,musheader * mh,byte * buf,char * s,config * c)165 void record_music(dumphandle dh,musheader *mh,byte *buf,char *s,config *c)
166 {
167   unsigned int lsize;
168 
169   lsize = mh->headerlength + mh->muslength;
170   RegisterLmp(dh,s,lsize);
171   /* It'll be a royal pain to endian swap the header, so we just don't
172    * have custom music on big-endian machines */
173 #ifndef ENDIAN_BIG
174   /* Disabled because this was never done
175   fwrite(mh,sizeof(musheader),1,dh->f); */ /* Write fixed header */ /*
176   fwrite(buf,mh->patches*sizeof(short)+mh->muslength,1,dh->f); */
177 #endif
178 }
179 
180 /* Make the special SLINFO lmp, containing whatever we like */
make_slinfo(dumphandle dh,config * c)181 void make_slinfo(dumphandle dh, config *c)
182 {
183   static byte slinfo[100];
184 
185   sprintf(slinfo,"SLUMP (%d.%03d.%02d) %d",
186 		  SOURCE_VERSION,SOURCE_SERIAL,SOURCE_PATCHLEVEL,
187 		  c->ranseed);
188   RegisterLmp(dh,"SLINFO",strlen(slinfo)+1);
189   fwrite(slinfo,strlen(slinfo)+1,1,dh->f);
190 
191 }  /* end make_slinfo() */
192 
193 /* Make sure all teleports are OK; any teleport that is invalid (in other
194  * words, doesn't have a destination) will be made in to an exit */
validate_teleports(linedef * pLinedef,sector * pSector)195 void validate_teleports(linedef *pLinedef, sector *pSector) {
196   int tags[1024];
197   int a = 0;
198   for(a=0;a<1024;a++) {
199 	tags[a] = 0;
200   }
201   for (;pSector!=NULL;pSector=pSector->next) {
202   	if(pSector->tag > 0 && pSector->tag < 1024) {
203 		tags[pSector->tag] = 1;
204 	}
205   }
206   for(;pLinedef != NULL; pLinedef=pLinedef->next) {
207 	if(pLinedef->type == LINEDEF_TELEPORT && pLinedef->tag > 0 &&
208            pLinedef->tag < 1024 && tags[pLinedef->tag] == 0) {
209 		printf("Warning: teleport with invalid tag; "
210                        "making end of level!\n");
211 		pLinedef->type = LINEDEF_W1_END_LEVEL;
212 	}
213   }
214 }
215 
216 /* Write out a PWAD containing just the THINGS, LINEDEFS, SIDEDEFS, */
217 /* VERTEXES, and SECTORS for the given episode/mission.  The user   */
218 /* will have to run a nodebuilder and reject mapper hisself.        */
DumpLevel(dumphandle dh,config * c,level * l,int episode,int mission,int map)219 void DumpLevel(dumphandle dh,config *c,level *l,int episode,int mission,int map)
220 {
221   unsigned int i;
222   sector *pSector;
223   thing *pThing;
224   vertex *pVertex;
225   linedef *pLinedef;
226   sidedef *pSidedef;
227 
228   struct {
229     short x;
230     short y;
231     short angle;
232     short type;
233     short options;
234   } rawthing;
235 
236   struct {
237     short floor_height;
238     short ceiling_height;
239     char floor_flat[8];
240     char ceiling_flat[8];
241     short light_level;
242     short special;
243     short tag;
244   } rawsector;
245 
246   struct {
247     short x;
248     short y;
249   } rawvertex;
250 
251   struct {
252     short x_offset;
253     short y_offset;
254     char upper_texture[8];
255     char lower_texture[8];
256     char middle_texture[8];
257     short sector;
258   } rawsidedef;
259 
260   struct {
261     short from;
262     short to;
263     short flags;
264     short type;
265     short tag;
266     short right;
267     short left;
268   } rawlinedef;
269 
270   char sb[9];
271 
272   /* Register the zero-length marker entry */
273 
274   if (map==0) {
275     sprintf(sb,"E%dM%d",episode,mission);
276   } else {
277     sprintf(sb,"MAP%02d",map);
278   }
279   RegisterLmp(dh,sb,0);
280 
281   /* Number all items, register in the directory */
282 
283   /* Number and count the things, register */
284   for (i=0,pThing=l->thing_anchor;pThing!=NULL;i++) {
285     pThing->number = i;
286     pThing = pThing->next;
287   }
288   RegisterLmp(dh,"THINGS",i*10);
289 
290   /* Count the number of linedefs, register */
291   for (i=0,pLinedef=l->linedef_anchor;pLinedef!=NULL;i++) {
292     pLinedef->number = i;
293     pLinedef = pLinedef->next;
294   }
295   RegisterLmp(dh,"LINEDEFS",i*14);
296 
297   /* Count the number of sidedefs, register */
298   for (i=0,pSidedef=l->sidedef_anchor;pSidedef!=NULL;i++) {
299     pSidedef->number = i;
300     pSidedef = pSidedef->next;
301   }
302   RegisterLmp(dh,"SIDEDEFS",i*30);
303 
304   /* Count the number of vertexes, register */
305   for (i=0,pVertex=l->vertex_anchor;pVertex!=NULL;i++) {
306     pVertex->number = i;
307     pVertex = pVertex->next;
308   }
309   RegisterLmp(dh,"VERTEXES",i*4);
310 
311   if (c->produce_null_lmps) {
312     RegisterLmp(dh,"SEGS",0);
313     RegisterLmp(dh,"SSECTORS",0);
314     RegisterLmp(dh,"NODES",0);
315   }
316 
317   /* Count the number of sectors, register */
318   for (i=0,pSector=l->sector_anchor;pSector!=NULL;i++) {
319     pSector->number = i;
320     pSector = pSector->next;
321   }
322   RegisterLmp(dh,"SECTORS",i*26);
323 
324   if (c->produce_null_lmps) {
325     RegisterLmp(dh,"REJECT",0);
326     RegisterLmp(dh,"BLOCKMAP",0);
327   }
328 
329   /* Now actually write all those lmps */
330   for (pThing=l->thing_anchor;pThing!=NULL;pThing=pThing->next) {
331     rawthing.x = pThing->x;
332     rawthing.y = pThing->y;
333     rawthing.angle = pThing->angle;
334     rawthing.type = pThing->genus->thingid;
335     rawthing.options = pThing->options;
336 #ifdef ENDIAN_BIG
337     rawthing.x = swap_16(rawthing.x);
338     rawthing.y = swap_16(rawthing.y);
339     rawthing.angle = swap_16(rawthing.angle);
340     rawthing.type = swap_16(rawthing.type);
341     rawthing.options = swap_16(rawthing.options);
342 #endif
343     fwrite(&rawthing,sizeof(rawthing),1,dh->f);
344   }
345 
346   /* validate teleports: a teleport without a corresponding
347    * destination is made an exit (fixes slige.c bug) */
348   validate_teleports(l->linedef_anchor,l->sector_anchor);
349 
350   /* and all the linedefs */
351   for (pLinedef=l->linedef_anchor;pLinedef!=NULL;pLinedef=pLinedef->next) {
352     rawlinedef.from = (pLinedef->from)->number;
353     rawlinedef.to = (pLinedef->to)->number;
354     rawlinedef.flags = pLinedef->flags;
355     rawlinedef.type = pLinedef->type;
356     rawlinedef.tag = pLinedef->tag;
357     if (pLinedef->right == NULL) {
358       rawlinedef.right = (short)0xFFFF;     /* actually an error, eh? */
359     } else {
360       rawlinedef.right = (pLinedef->right)->number;
361     }
362     if (pLinedef->left == NULL) {
363       rawlinedef.left = (short)0xFFFF;
364     } else {
365       rawlinedef.left = (pLinedef->left)->number;
366     }
367 #ifdef ENDIAN_BIG
368     rawlinedef.from = swap_16(rawlinedef.from);
369     rawlinedef.to = swap_16(rawlinedef.to);
370     rawlinedef.flags = swap_16(rawlinedef.flags);
371     rawlinedef.type = swap_16(rawlinedef.type);
372     rawlinedef.tag = swap_16(rawlinedef.tag);
373     rawlinedef.left = swap_16(rawlinedef.left);
374     rawlinedef.right = swap_16(rawlinedef.right);
375 #endif
376     fwrite(&rawlinedef,sizeof(rawlinedef),1,dh->f);
377   }
378 
379   /* and all the sidedefs */
380   for (pSidedef=l->sidedef_anchor;pSidedef!=NULL;pSidedef=pSidedef->next) {
381     rawsidedef.x_offset = pSidedef->x_offset;
382     rawsidedef.y_offset = pSidedef->y_offset;
383     memset(rawsidedef.upper_texture,0,8);
384     memcpy(rawsidedef.upper_texture,pSidedef->upper_texture->realname,strlen(pSidedef->upper_texture->realname));
385     pSidedef->upper_texture->used = TRUE;
386     memset(rawsidedef.lower_texture,0,8);
387     memcpy(rawsidedef.lower_texture,pSidedef->lower_texture->realname,strlen(pSidedef->lower_texture->realname));
388     pSidedef->lower_texture->used = TRUE;
389     memset(rawsidedef.middle_texture,0,8);
390     memcpy(rawsidedef.middle_texture,pSidedef->middle_texture->realname,strlen(pSidedef->middle_texture->realname));
391     pSidedef->middle_texture->used = TRUE;
392     rawsidedef.sector = (pSidedef->sector)->number;
393 #ifdef ENDIAN_BIG
394     rawsidedef.x_offset = swap_16(rawsidedef.x_offset);
395     rawsidedef.y_offset = swap_16(rawsidedef.y_offset);
396     rawsidedef.sector = swap_16(rawsidedef.sector);
397 #endif
398     fwrite(&rawsidedef,sizeof(rawsidedef),1,dh->f);
399   }
400 
401   /* and all the vertexes */
402   for (pVertex=l->vertex_anchor;pVertex!=NULL;pVertex=pVertex->next) {
403     rawvertex.x = pVertex->x;
404     rawvertex.y = pVertex->y;
405 #ifdef ENDIAN_BIG
406     rawvertex.x = swap_16(rawvertex.x);
407     rawvertex.y = swap_16(rawvertex.y);
408 #endif
409     fwrite(&rawvertex,sizeof(rawvertex),1,dh->f);
410   }
411 
412   /* and finally all the sectors */
413   for (pSector=l->sector_anchor;pSector!=NULL;pSector=pSector->next) {
414 
415     rawsector.floor_height = pSector->floor_height;
416     rawsector.ceiling_height = pSector->ceiling_height;
417     memset(rawsector.floor_flat,0,8);
418     memcpy(rawsector.floor_flat,pSector->floor_flat->name,strlen(pSector->floor_flat->name));
419     pSector->floor_flat->used = TRUE;
420     memset(rawsector.ceiling_flat,0,8);
421     memcpy(rawsector.ceiling_flat,pSector->ceiling_flat->name,strlen(pSector->ceiling_flat->name));
422     pSector->ceiling_flat->used = TRUE;
423     if(pSector->light_level < ABSOLUTE_MINLIGHT) { /* Rooms can be too dark */
424 	pSector->light_level = ABSOLUTE_MINLIGHT;
425     }
426     rawsector.light_level = pSector->light_level;
427     rawsector.special = pSector->special;
428     rawsector.tag = pSector->tag;
429 #ifdef ENDIAN_BIG
430     rawsector.floor_height = swap_16(rawsector.floor_height);
431     rawsector.ceiling_height = swap_16(rawsector.ceiling_height);
432     rawsector.light_level = swap_16(rawsector.light_level);
433     rawsector.special = swap_16(rawsector.special);
434     rawsector.tag = swap_16(rawsector.tag);
435 #endif
436 
437     fwrite(&rawsector,sizeof(rawsector),1,dh->f);
438   }
439 
440 }  /* end DumpLevel */
441 
442 /* Dump the given texture lmp to the given dump-handle */
dump_texture_lmp(dumphandle dh,texture_lmp * tl)443 void dump_texture_lmp(dumphandle dh,texture_lmp *tl)
444 {
445   int texturecount = 0;
446   int patchcount;
447   int lmpsize,isize,i;
448   custom_texture *ct;
449   patch *p;
450   byte *buf, *tbuf;
451 
452   /* First figure entire lmp size.  Four bytes of tcount... */
453   lmpsize = 4;
454 
455   /* Plus four-plus-22 bytes per texture, plus 10 per patch */
456   for (ct=tl->custom_texture_anchor;ct;ct=ct->next) {
457     texturecount++;
458     lmpsize += 4 + 22;    /* Four bytes index, 22 bytes structure */
459     for (p=ct->patch_anchor;p;p=p->next) lmpsize += 10;
460   }
461 
462   /* Get storage for the lmp itself */
463   buf = (byte *)malloc(lmpsize);
464   tbuf = buf;
465 
466   /* Write in the count */
467 #ifndef ENDIAN_BIG
468   *(int *)tbuf = texturecount;  tbuf += sizeof(int);
469 #else
470   *(int *)tbuf = swap_32s(texturecount); tbuf += sizeof(int);
471 #endif
472 
473   /* Now traverse the textures again, and make the index */
474   isize = 4 + 4 * texturecount;
475   for (ct=tl->custom_texture_anchor;ct;ct=ct->next) {
476 #ifndef ENDIAN_BIG
477     *(int *)tbuf = isize;  tbuf += sizeof(int);
478 #else
479     *(int *)tbuf = swap_32s(isize);  tbuf += sizeof(int);
480 #endif
481     isize += 22;    /* Four bytes index, 22 bytes structure */
482     for (p=ct->patch_anchor;p;p=p->next) isize += 10;
483   }
484 
485   /* Now one last time, writing the data itself */
486   for (ct=tl->custom_texture_anchor;ct;ct=ct->next) {
487     for (i=0;i<(int)strlen(ct->name);i++) {
488       *(tbuf++) = (byte)((ct->name)[i]);
489     }
490     for (i=strlen(ct->name);i<8;i++) {
491       *(tbuf++) = (byte)0;
492     }
493     *(short *)tbuf = 0;  tbuf += sizeof(short);
494     *(short *)tbuf = 0;  tbuf += sizeof(short);
495 #ifndef ENDIAN_BIG
496     *(short *)tbuf = ct->xsize;  tbuf += sizeof(short);
497     *(short *)tbuf = ct->ysize;  tbuf += sizeof(short);
498 #else
499     *(short *)tbuf = swap_16(ct->xsize);  tbuf += sizeof(short);
500     *(short *)tbuf = swap_16(ct->ysize);  tbuf += sizeof(short);
501 #endif
502     *(short *)tbuf = 0;  tbuf += sizeof(short);
503     *(short *)tbuf = 0;  tbuf += sizeof(short);
504     for (patchcount=0,p=ct->patch_anchor;p;p=p->next) patchcount++;
505 #ifndef ENDIAN_BIG
506     *(short *)tbuf = patchcount;  tbuf += sizeof(short);
507 #else
508     *(short *)tbuf = swap_16(patchcount);  tbuf += sizeof(short);
509 #endif
510     for (p=ct->patch_anchor;p;p=p->next) {
511 #ifndef ENDIAN_BIG
512       *(short *)tbuf = p->x;  tbuf += sizeof(short);
513       *(short *)tbuf = p->y;  tbuf += sizeof(short);
514       *(short *)tbuf = p->number;  tbuf += sizeof(short);
515       *(short *)tbuf = 1;  tbuf += sizeof(short);
516 #else
517       *(short *)tbuf = swap_16(p->x);  tbuf += sizeof(short);
518       *(short *)tbuf = swap_16(p->y);  tbuf += sizeof(short);
519       *(short *)tbuf = swap_16(p->number);  tbuf += sizeof(short);
520       *(short *)tbuf = swap_16(1);  tbuf += sizeof(short);
521 #endif
522       *(short *)tbuf = 0;  tbuf += sizeof(short);
523     }
524   }
525 
526   RegisterLmp(dh,tl->name,lmpsize);
527   fwrite(buf,lmpsize,1,dh->f);
528 
529 }
530 
531 /* Allocate, initialize, register with the texture (but don't */
532 /* bother returning) a new patch for this texture */
add_patch(custom_texture * ct,short patchid,short x,short y)533 void add_patch(custom_texture *ct,short patchid,short x,short y)
534 {
535   patch *answer = (patch *)malloc(sizeof(*answer));
536   patch *p;
537 
538   answer->number = patchid;
539   answer->x = x;
540   answer->y = y;
541   answer->next = NULL;
542   /* Simplest if these are in frontward order */
543   if (ct->patch_anchor==NULL) {
544     ct->patch_anchor = answer;
545   } else {
546     for (p=ct->patch_anchor;p->next;p=p->next){};   /* find last */
547     p->next = answer;
548   }
549 }
550 
551 /* Record any custom textures, made from existing patches, that */
552 /* we might want to show off by using.  Only works in DOOM2, sadly. */
553 /* In DOOM I, we'd have to recreate the entire TEXTURE2 (or 1) lump, */
554 /* and then add our stuff to it. */
record_custom_textures(dumphandle dh,config * c)555 void record_custom_textures(dumphandle dh, config *c)
556 {
557   texture_lmp *tl;
558   custom_texture *ct;
559 
560   /* Return if TEXTURE2 not available */
561   if (c->gamemask&(DOOM0_BIT|DOOM1_BIT|DOOMI_BIT)) return;
562 
563   tl = new_texture_lmp("TEXTURE2");
564 
565   ct = new_custom_texture(tl,"GRAYALT",0x80,0x80);
566   add_patch(ct,0x87,0,0);
567   add_patch(ct,0x8a,0,0x40);
568   add_patch(ct,0x8a,0x40,0);
569   add_patch(ct,0x87,0x40,0x40);
570   ct = new_custom_texture(tl,"TEKVINE",0x100,0x80);
571   add_patch(ct,0x19b,0,0);
572   add_patch(ct,0x183,0x40,0);
573   add_patch(ct,0x19b,0x80,0);
574   add_patch(ct,0x183,0xc0,0);
575   add_patch(ct,0x35,0,0);    /* Vines! */
576   ct = new_custom_texture(tl,"WOODVINE",0x100,0x80);
577   add_patch(ct,0x1b1,0,0);    /* WOOD9 */
578   add_patch(ct,0x1b1,0x40,0);    /* WOOD9 */
579   add_patch(ct,0x1b1,0x80,0);    /* WOOD9 */
580   add_patch(ct,0x1b1,0xc0,0);    /* WOOD9 */
581   add_patch(ct,0x35,0,0);    /* Vines! */
582   ct = new_custom_texture(tl,"WOODLITE",0x100,0x80);
583   add_patch(ct,0x1ac,-4,0);   /* Copied from WOOD5 */
584   add_patch(ct,0x1ad,124,0);   /* Copied from WOOD5 */
585   add_patch(ct,0x1ac,252,0);   /* Copied from WOOD5 */
586   add_patch(ct,0x78,32,20);   /* The light overlay */
587   ct = new_custom_texture(tl,"DOORSKUL",0x40,0x48);
588   add_patch(ct,0x6b,0,0);      /* The door */
589   add_patch(ct,0x1ab,21,11);   /* The liddle skull */
590   ct = new_custom_texture(tl,"EXITSWIT",0x40,0x80);
591   add_patch(ct,0x87,0,0);
592   add_patch(ct,0x87,0,64);
593   add_patch(ct,0x177,16,70);
594   add_patch(ct,0x79,16,104);
595   ct = new_custom_texture(tl,"EXITSWIW",0x40,0x80);
596   add_patch(ct,0xdd,0,0);
597   add_patch(ct,0x173,0x0e,0x40);
598   add_patch(ct,0x79,16,104);
599   ct = new_custom_texture(tl,"EXITSWIR",0x40,0x80);
600   add_patch(ct,0x12d,0,0);
601   add_patch(ct,0x173,0x0f,0x42);
602   add_patch(ct,0x79,16,104);
603   ct = new_custom_texture(tl,"MARBGARG",0x40,0x80);
604   add_patch(ct,0x0BD,0,0);      /* MWALL3_1 */
605   add_patch(ct,0x1B2,6,31);     /* SW2_4 */
606 
607   dump_texture_lmp(dh,tl);
608   free_texture_lmp(tl);
609 }  /* end record_custom_textures */
610 
611 byte fbuf[64*64+4];   /* For use in making custom flats and patches; 64x64 */
612 byte pbuf[TLMPSIZE(0x80,0x40)];      /* Also */
613 
614 /* Record any custom flats that we might want to show off by using. */
615 /* This is *much* simpler than textures! */
record_custom_flats(dumphandle dh,config * c,boolean even_unused)616 void record_custom_flats(dumphandle dh, config *c, boolean even_unused)
617 {
618   short i,j,x,x2,y,dx,dy;
619   boolean started = FALSE;
620 
621   if (even_unused || find_flat(c,"SLGRASS1")->used) {
622 
623     if (!started) RegisterLmp(dh,"FF_START",0);
624     started = TRUE;
625     announce(VERBOSE,"SLGRASS1");
626 
627     basic_background2(fbuf,0x7c,4);
628     x = roll(41,64);
629     y = roll(42,64);
630     for (;;) {
631       dx = 1 - roll(43,3);
632       dy = 1 - roll(44,3);
633       if (dx && dy) break;
634     }
635     for (i=512;i;i--) {
636       x += dx;
637       y += dy;
638       if (x<0) x += 64;
639       if (x>63) x -= 64;
640       if (y<0) y += 64;
641       if (y>63) y -= 64;
642       fbuf[64*x+y] = 0xbc+roll(45,4);
643       x2 = (x==0) ? 63 : x-1;
644       fbuf[64*x2+y] = 0xbc;
645       x2 = (x==63) ? 0 : x+1;
646       fbuf[64*x2+y] = 0xbf;
647       if (roll(46,8)==0) dx = 1 - roll(259,3);
648       if (roll(47,8)==0) dy = 1 - roll(260,3);
649       for (;!(dx||dy);) {
650         dx = 1 - roll(48,3);
651         dy = 1 - roll(49,3);
652       }
653     }
654 
655     RegisterLmp(dh,"SLGRASS1",4096);
656     fwrite(fbuf,4096,1,dh->f);
657   }
658 
659   if (even_unused || find_flat(c,"SLSPARKS")->used) {
660 
661     if (!started) RegisterLmp(dh,"FF_START",0);
662     started = TRUE;
663     announce(VERBOSE,"SLSPARKS");
664     memset(fbuf,0,4096);
665     for (i=512;i;i--)
666       fbuf[roll(50,64) + 64*roll(261,64)] = 0xb0 + roll(262,16);
667     RegisterLmp(dh,"SLSPARKS",4096);
668     fwrite(fbuf,4096,1,dh->f);
669   }
670 
671   if (even_unused || find_flat(c,"SLGATE1")->used) {
672 
673     if (!started) RegisterLmp(dh,"FF_START",0);
674     started = TRUE;
675     announce(VERBOSE,"SLGATE1");
676 
677     basic_background2(fbuf,0x9c,4);
678 
679     for (i=4;i<60;i++) {
680       for (j=4;j<60;j++) {
681         dx = abs ( (i<<1) - 63 ) >> 2;
682         dy = abs ( (j<<1) - 63 ) >> 2;
683         x = 0xcf - (dx+dy)/2;
684         x += roll(51,2);
685         x -= roll(52,2);
686         if (x>0xcf) x = 0xcf;
687         if (x<0xc0) x = 0xc0;
688         fbuf[64*i+j] = (byte)x;
689       }
690     }
691 
692     RegisterLmp(dh,"SLGATE1",4096);
693     fwrite(fbuf,4096,1,dh->f);
694   }
695 
696   if (even_unused || find_flat(c,"SLLITE1")->used) {
697 
698     if (!started) RegisterLmp(dh,"FF_START",0);
699     started = TRUE;
700     announce(VERBOSE,"SLLITE1");
701 
702     basic_background2(fbuf,0x94,4);
703 
704     for (i=0;i<4;i++) {
705       for (j=0;j<4;j++) {
706         for (x=3;x<13;x++) {
707           for (y=3;y<13;y++) {
708             if ( (x==3 || x == 12) && (y==3 || y ==12) ) continue;
709             dx = abs ( (x<<1) - 15 ) >> 2;
710             dy = abs ( (y<<1) - 15 ) >> 2;
711             if (dy>dx) dx = dy;
712             x2 = 0xa1 + 2 * dx;
713             x2 += roll(53,2) -
714 		    roll(263,2);
715             if (x2>0xa7) x2 = 0xa7;
716             if (x2<0xa0) x2 = 0xa0;
717             fbuf[64*(16*i+x)+16*j+y] = (byte)x2;
718           }
719         }
720       }
721     }
722 
723     RegisterLmp(dh,"SLLITE1",4096);
724     fwrite(fbuf,4096,1,dh->f);
725   }
726 
727   if (even_unused || find_flat(c,"SLFLAT01")->used) {
728 
729     if (!started) RegisterLmp(dh,"FF_START",0);
730     started = TRUE;
731     announce(VERBOSE,"SLFLAT01");
732 
733     basic_background2(fbuf,0x6b,5);
734     for (i=0;i<4096;i++)
735       if (fbuf[i]>0x6d) fbuf[i] = 0x0;
736     for (i=0;i<64;i++) {
737       fbuf[i] = 0x6b;
738       fbuf[64*i] = 0x6b;
739       fbuf[63*64+i] = 0x6f;
740       fbuf[64*i+63] = 0x6f;
741     }
742 
743     RegisterLmp(dh,"SLFLAT01",4096);
744     fwrite(fbuf,4096,1,dh->f);
745   }
746 
747   if (started) {
748     RegisterLmp(dh,"FF_END",0);
749     RegisterLmp(dh,"F_END",0);      /* Just in case */
750   }
751 }
752 
753 /* Record any custom/replacement patches that we might want to show off */
754 /* by using. */
record_custom_patches(dumphandle dh,config * c,boolean even_unused)755 void record_custom_patches(dumphandle dh, config *c, boolean even_unused)
756 {
757   int rows, columns, i, j, lsize;
758   byte *p, thispel;
759   boolean started = FALSE;
760 
761 
762 
763   if (even_unused || FALSE) {
764 
765     if (!started) {
766       RegisterLmp(dh,"P_START",0);    /* Which?  Both? */
767       RegisterLmp(dh,"PP_START",0);
768     }
769     started = TRUE;
770 
771     rows = 0x80;
772     columns = 0x40;
773     lsize = TLMPSIZE(rows,columns);
774     if (lsize>sizeof(pbuf))
775       announce(ERROR,"Buffer overflow in r_c_t()");
776     p = pbuf;
777     /* The picture header */
778 #ifndef ENDIAN_BIG
779     *(short *)p = columns;         p += sizeof(short);   /* Width */
780     *(short *)p = rows;            p += sizeof(short);   /* Height */
781     *(short *)p = (columns>>1)-1;  p += sizeof(short);   /* Width offset */
782     *(short *)p = rows-5;          p += sizeof(short);   /* Magic */
783 #else
784     *(short *)p = swap_16(columns);         p += sizeof(short);   /* Width */
785     *(short *)p = swap_16(rows);            p += sizeof(short);   /* Height */
786     *(short *)p = swap_16((columns>>1)-1);  p += sizeof(short);   /* Width offset */
787     *(short *)p = swap_16(rows-5);          p += sizeof(short);   /* Magic */
788 #endif
789     /* The pointers to the columns */
790     for (i=0;i<columns;i++) {
791       int z;
792       z = 8 + 4 * (columns) + i * (rows+5);
793 #ifndef ENDIAN_BIG
794       *(int *)p = z;  p += sizeof(int);
795 #else
796       *(int *)p = swap_32s(z);  p += sizeof(int);
797 #endif
798     }
799     /* The columns themselves */
800     for (i=0;i<columns;i++) {
801       /* The column header */
802       *p = 0;           p++;
803       *p = (byte)rows;  p++;
804       /* The column itself, including silly bytes */
805       for (j=-1;j<rows+1;j++) {
806         if (rollpercent(140,10)) thispel = 0xc0 + roll(54,16);
807           else thispel = 0;
808         *p = thispel;  p++;
809       }
810       /* And finally */
811       *p = 0xff; p++;
812     }
813     /* Whew! */
814 
815     RegisterLmp(dh,"WALL51_1",lsize);  /* DOOM I only */
816     fwrite(pbuf,lsize,1,dh->f);
817   }
818 
819   if (even_unused || FALSE) {
820 
821     if (!started) {
822       RegisterLmp(dh,"P_START",0);    /* Which?  Both? */
823       RegisterLmp(dh,"PP_START",0);
824     }
825     started = TRUE;
826 
827     rows = 0x80;
828     columns = 0x40;
829     lsize = TLMPSIZE(rows,columns);
830     if (lsize>sizeof(pbuf))
831       announce(ERROR,"Buffer overflow in r_c_t()");
832     p = pbuf;
833     /* The picture header */
834 #ifndef ENDIAN_BIG
835     *(short *)p = columns;         p += sizeof(short);   /* Width */
836     *(short *)p = rows;            p += sizeof(short);   /* Height */
837     *(short *)p = (columns>>1)-1;  p += sizeof(short);   /* Width offset */
838     *(short *)p = rows-5;          p += sizeof(short);   /* Magic */
839 #else
840     *(short *)p = swap_16(columns);         p += sizeof(short);   /* Width */
841     *(short *)p = swap_16(rows);            p += sizeof(short);   /* Height */
842     *(short *)p = swap_16((columns>>1)-1);  p += sizeof(short);   /* Width offset */
843     *(short *)p = swap_16(rows-5);          p += sizeof(short);   /* Magic */
844 #endif
845     /* The pointers to the columns */
846     for (i=0;i<columns;i++) {
847       int z;
848       z = 8 + 4 * (columns) + i * (rows+5);
849 #ifndef ENDIAN_BIG
850       *(int *)p = z;  p += sizeof(int);
851 #else
852       *(int *)p = swap_32s(z);  p += sizeof(int);
853 #endif
854     }
855     /* The columns themselves */
856     for (i=0;i<columns;i++) {
857       /* The column header */
858       *p = 0;           p++;
859       *p = (byte)rows;  p++;
860       /* The column itself, including silly bytes */
861       for (j=-1;j<rows+1;j++) {
862         if (rollpercent(141,20)) thispel = 0xd0 + roll(55,16);
863           else thispel = 0;
864         *p = thispel;  p++;
865       }
866       /* And finally */
867       *p = 0xff;  p++;
868     }
869     /* Whew! */
870 
871     RegisterLmp(dh,"WALL51_2",lsize);
872     fwrite(pbuf,lsize,1,dh->f);
873   }
874 
875   /* Next is the steel-rollup-door patch.  It's currently put into */
876   /* the WALL51_3 slot, which means it appears in texture SP_DUDE5 */
877   /* (instead of the yucchy dead guy hanging on the wall.)  The    */
878   /* internal name for the texture is SLDOOR1.                     */
879 
880   if (even_unused || find_texture(c,"SLDOOR1")->used) {
881 
882     if (!started) {
883       RegisterLmp(dh,"P_START",0);    /* Which?  Both? */
884       RegisterLmp(dh,"PP_START",0);
885     }
886     started = TRUE;
887 
888 
889     /* First a little correlated noise for "dirtying" */
890     basic_background2(fbuf,0,5);
891 
892     /* Then the actual patch */
893     rows = 0x80;
894     columns = 0x40;
895     lsize = TLMPSIZE(rows,columns);
896     if (lsize>sizeof(pbuf))
897       announce(ERROR,"Buffer overflow in r_c_t()");
898     p = pbuf;
899     /* The picture header */
900 #ifndef ENDIAN_BIG
901     *(short *)p = columns;         p += sizeof(short);   /* Width */
902     *(short *)p = rows;            p += sizeof(short);   /* Height */
903     *(short *)p = (columns>>1)-1;  p += sizeof(short);   /* Width offset */
904     *(short *)p = rows-5;          p += sizeof(short);   /* Magic */
905 #else
906     *(short *)p = swap_16(columns);         p += sizeof(short);   /* Width */
907     *(short *)p = swap_16(rows);            p += sizeof(short);   /* Height */
908     *(short *)p = swap_16((columns>>1)-1);  p += sizeof(short);   /* Width offset */
909     *(short *)p = swap_16(rows-5);          p += sizeof(short);   /* Magic */
910 #endif
911     /* The pointers to the columns */
912     for (i=0;i<columns;i++) {
913       int z;
914       z = 8 + 4 * (columns) + i * (rows+5);
915 #ifndef ENDIAN_BIG
916       *(int *)p = z;  p += sizeof(int);
917 #else
918       *(int *)p = swap_32s(z); p += sizeof(int);
919 #endif
920     }
921     /* The columns themselves */
922     for (i=0;i<columns;i++) {
923       /* The column header */
924       *p = 0;           p++;
925       *p = (byte)rows;  p++;
926       /* The column itself, including silly bytes */
927       for (j=-1;j<rows+1;j++) {
928         thispel = 0x60 + (j+1)%8;
929         if ((j>=0) && (j<rows))
930           thispel += 2 - fbuf[ 64*(i) + (j & 63)];
931         *p = thispel;  p++;
932       }
933       /* And finally */
934       *p = 0xff;  p++;
935     }
936     /* Whew! */
937 
938     RegisterLmp(dh,"WALL51_3",lsize);
939     fwrite(pbuf,lsize,1,dh->f);
940   }
941 
942   if (started) {
943     RegisterLmp(dh,"PP_END",0);
944     RegisterLmp(dh,"P_END",0);
945   }
946 
947 }
948 
949 /* Compose replacements for the music sections used by the */
950 /* given config, and send them out the dumphandle. */
make_music(dumphandle dh,config * c)951 void make_music(dumphandle dh, config *c)
952 {
953   musheader mh;
954   byte *musbuf;
955 
956   /* Definitely a stub! */
957   if (c->gamemask&DOOM1_BIT) {
958     musbuf = one_piece(&mh);
959     record_music(dh,&mh,musbuf,"D_INTROA",c);
960     free(musbuf);
961   }
962   if (c->gamemask&DOOM2_BIT) {
963     musbuf = one_piece(&mh);
964     record_music(dh,&mh,musbuf,"D_DM2TTL",c);
965     free(musbuf);
966   }
967 
968 }  /* end stubby make_music() */
969 
970 /* Make a secret level following the current level.  With luck, */
971 /* the current level has an exit to it! */
make_secret_level(dumphandle dh,haa * oldhaa,config * c)972 void make_secret_level(dumphandle dh, haa *oldhaa, config *c)
973 {
974   config *SecConfig;
975   level SecLevel;
976   haa *SecHaa;
977 
978   SecConfig = (config *)malloc(sizeof(*SecConfig));
979   memcpy(SecConfig,c,sizeof(*c));
980   SecHaa = (haa *)malloc(sizeof(*SecHaa));
981   memcpy(SecHaa,oldhaa,sizeof(*oldhaa));
982   secretize_config(SecConfig);
983   if (SecConfig->map==31) SecConfig->map++;
984   if (SecConfig->map==15) SecConfig->map = 31;
985   if (SecConfig->episode!=0) SecConfig->mission = 9;
986   NewLevel(&SecLevel,SecHaa,SecConfig);
987   DumpLevel(dh,SecConfig,&SecLevel,SecConfig->episode,
988                                    SecConfig->mission,
989                                    SecConfig->map);
990   if (SecConfig->map==31) {
991     SecConfig->map=32;
992     SecConfig->secret_themes = TRUE;
993     NewLevel(&SecLevel,SecHaa,SecConfig);
994     DumpLevel(dh,SecConfig,&SecLevel,SecConfig->episode,
995                                      SecConfig->mission,
996                                      SecConfig->map);
997   }
998 
999 }
1000 
1001