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