]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/doom/w_wad.c
games/doom: display correct message on medkit pickup when health low (thanks qu7uux)
[plan9front.git] / sys / src / games / doom / w_wad.c
1 // Emacs style mode select   -*- C++ -*- 
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // $Log:$
18 //
19 // DESCRIPTION:
20 //      Handles WAD file header, directory, lump I/O.
21 //
22 //-----------------------------------------------------------------------------
23
24
25 static const char
26 rcsid[] = "$Id: w_wad.c,v 1.5 1997/02/03 16:47:57 b1 Exp $";
27
28
29 #ifdef NORMALUNIX
30 #include <ctype.h>
31 #include <sys/types.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <malloc.h>
35 #include <fcntl.h>
36 #include <sys/stat.h>
37 #include <alloca.h>
38 #define O_BINARY                0
39 #endif
40
41 #include "doomtype.h"
42 #include "m_swap.h"
43 #include "i_system.h"
44 #include "z_zone.h"
45
46 #include "w_wad.h"
47
48
49 //
50 // GLOBALS
51 //
52
53 // Location of each lump on disk.
54 lumpinfo_t*             lumpinfo;               
55 int                     numlumps;
56
57 void**                  lumpcache;
58
59
60 #define strcmpi strcasecmp
61
62 void strupr (char* s)
63 {
64     while (*s) { *s = toupper(*s); s++; }
65 }
66
67 vlong
68 filelength(int fd) 
69 {
70         vlong l;
71         Dir *d;
72
73         d = dirfstat(fd);
74         if(d == nil)
75                 sysfatal("dirfstat: %r");
76         l = d->length;
77         free(d);
78         return l;       /* lump file lenghts in doom are ints */
79 }
80
81
82 void
83 ExtractFileBase
84 ( char*         path,
85   char*         dest )
86 {
87     char*       src;
88     int         length;
89
90     src = path + strlen(path) - 1;
91     
92     // back up until a \ or the start
93     while (src != path
94            && *(src-1) != '\\'
95            && *(src-1) != '/')
96     {
97         src--;
98     }
99     
100     // copy up to eight characters
101     memset (dest,0,8);
102     length = 0;
103     
104     while (*src && *src != '.')
105     {
106         if (++length == 9)
107             I_Error ("Filename base of %s >8 chars",path);
108
109         *dest++ = toupper((int)*src++);
110     }
111 }
112
113
114
115
116
117 //
118 // LUMP BASED ROUTINES.
119 //
120
121 //
122 // W_AddFile
123 // All files are optional, but at least one file must be
124 //  found (PWAD, if all required lumps are present).
125 // Files with a .wad extension are wadlink files
126 //  with multiple lumps.
127 // Other files are single lumps with the base filename
128 //  for the lump name.
129 //
130 // If filename starts with a tilde, the file is handled
131 //  specially to allow map reloads.
132 // But: the reload feature is a fragile hack...
133
134 int                     reloadlump;
135 char*                   reloadname;
136
137
138 void W_AddFile (char *filename)
139 {
140     wadinfo_t           header;
141     lumpinfo_t*         lump_p;
142     unsigned            i;
143     int                 handle;
144     int                 length;
145     int                 startlump;
146     filelump_t*         fileinfo;
147     filelump_t          singleinfo;
148     int                 storehandle;
149     void                *freefileinfo = nil;
150     
151     // open the file and add to directory
152
153     // handle reload indicator.
154     if (filename[0] == '~')
155     {
156         filename++;
157         reloadname = filename;
158         reloadlump = numlumps;
159     }
160
161     if ( (handle = I_Open(filename)) == -1 )            
162     {
163         printf (" couldn't open %s\n",filename);
164         return;
165     }
166
167     printf (" adding %s\n",filename);
168     startlump = numlumps;
169         
170     if (cistrcmp (filename+strlen(filename)-3 , "wad" ) )
171     {
172         // single lump file
173         fileinfo = &singleinfo;
174         singleinfo.filepos = 0;
175         singleinfo.size = LONG(filelength(handle));
176         ExtractFileBase (filename, singleinfo.name);
177         numlumps++;
178     }
179     else 
180     {
181         // WAD file
182         I_Read (handle, &header, sizeof(header));
183         if (strncmp(header.identification,"IWAD",4))
184         {
185             // Homebrew levels?
186             if (strncmp(header.identification,"PWAD",4))
187             {
188                 I_Error ("Wad file %s doesn't have IWAD "
189                          "or PWAD id\n", filename);
190             }
191             
192             // ???modifiedgame = true;          
193         }
194         header.numlumps = LONG(header.numlumps);
195         header.infotableofs = LONG(header.infotableofs);
196         length = header.numlumps*sizeof(filelump_t);
197         fileinfo = malloc (length); freefileinfo=fileinfo;
198         I_Seek (handle, header.infotableofs);
199         I_Read (handle, fileinfo, length);
200         numlumps += header.numlumps;
201     }
202
203     
204     // Fill in lumpinfo
205     lumpinfo = realloc (lumpinfo, numlumps*sizeof(lumpinfo_t));
206
207     if (!lumpinfo)
208         I_Error ("Couldn't realloc lumpinfo");
209
210     lump_p = &lumpinfo[startlump];
211         
212     storehandle = reloadname ? -1 : handle;
213         
214     for (i=startlump ; i<numlumps ; i++,lump_p++, fileinfo++)
215     {
216         lump_p->handle = storehandle;
217         lump_p->position = LONG(fileinfo->filepos);
218         lump_p->size = LONG(fileinfo->size);
219         strncpy (lump_p->name, fileinfo->name, 8);
220     }
221         
222     if (reloadname)
223         I_Close (handle);
224
225     if (freefileinfo)
226         free(freefileinfo);
227 }
228
229
230
231
232 //
233 // W_Reload
234 // Flushes any of the reloadable lumps in memory
235 //  and reloads the directory.
236 //
237 void W_Reload (void)
238 {
239     wadinfo_t           header;
240     int                 lumpcount;
241     lumpinfo_t*         lump_p;
242     unsigned            i;
243     int                 handle;
244     int                 length;
245     filelump_t*         fileinfo;
246         
247     if (!reloadname)
248         return;
249                 
250     if ( (handle = I_Open (reloadname)) == -1)
251         I_Error ("W_Reload: couldn't open %s",reloadname);
252
253     I_Read (handle, &header, sizeof(header));
254     lumpcount = LONG(header.numlumps);
255     header.infotableofs = LONG(header.infotableofs);
256     length = lumpcount*sizeof(filelump_t);
257     fileinfo = malloc (length);
258     I_Seek (handle, header.infotableofs);
259     I_Read (handle, fileinfo, length);
260     
261     // Fill in lumpinfo
262     lump_p = &lumpinfo[reloadlump];
263         
264     for (i=reloadlump ;
265          i<reloadlump+lumpcount ;
266          i++,lump_p++, fileinfo++)
267     {
268         if (lumpcache[i])
269             Z_Free (lumpcache[i]);
270
271         lump_p->position = LONG(fileinfo->filepos);
272         lump_p->size = LONG(fileinfo->size);
273     }
274         
275     I_Close (handle);
276     free(fileinfo);
277 }
278
279
280
281 //
282 // W_InitMultipleFiles
283 // Pass a null terminated list of files to use.
284 // All files are optional, but at least one file
285 //  must be found.
286 // Files with a .wad extension are idlink files
287 //  with multiple lumps.
288 // Other files are single lumps with the base filename
289 //  for the lump name.
290 // Lump names can appear multiple times.
291 // The name searcher looks backwards, so a later file
292 //  does override all earlier ones.
293 //
294 void W_InitMultipleFiles (char** filenames)
295 {       
296     int         size;
297     
298     // open all the files, load headers, and count lumps
299     numlumps = 0;
300
301     // will be realloced as lumps are added
302     lumpinfo = malloc(1);       
303
304     for ( ; *filenames ; filenames++)
305         W_AddFile (*filenames);
306
307     if (!numlumps)
308         I_Error ("W_InitFiles: no files found");
309     
310     // set up caching
311     size = numlumps * sizeof(*lumpcache);
312     lumpcache = malloc (size);
313     
314     if (!lumpcache)
315         I_Error ("Couldn't allocate lumpcache");
316
317     memset (lumpcache,0, size);
318 }
319
320
321
322
323 //
324 // W_InitFile
325 // Just initialize from a single file.
326 //
327 void W_InitFile (char* filename)
328 {
329     char*       names[2];
330
331     names[0] = filename;
332     names[1] = NULL;
333     W_InitMultipleFiles (names);
334 }
335
336
337
338 //
339 // W_NumLumps
340 //
341 int W_NumLumps (void)
342 {
343     return numlumps;
344 }
345
346
347
348 //
349 // W_CheckNumForName
350 // Returns -1 if name not found.
351 //
352
353 int W_CheckNumForName (char* name)
354 {
355     union {
356         char    s[9];
357         int     x[2];
358         
359     } name8;
360     
361     int         v1;
362     int         v2;
363     lumpinfo_t* lump_p;
364
365     // make the name into two integers for easy compares
366     strncpy (name8.s,name,8);
367
368     // in case the name was a fill 8 chars
369     name8.s[8] = 0;
370
371     // case insensitive
372     strupr (name8.s);           
373
374     v1 = name8.x[0];
375     v2 = name8.x[1];
376
377
378     // scan backwards so patch lump files take precedence
379     lump_p = lumpinfo + numlumps;
380
381     while (lump_p-- != lumpinfo)
382     {
383         if ( *(int *)lump_p->name == v1
384              && *(int *)&lump_p->name[4] == v2)
385         {
386             return lump_p - lumpinfo;
387         }
388     }
389
390     // TFB. Not found.
391     return -1;
392 }
393
394
395
396
397 //
398 // W_GetNumForName
399 // Calls W_CheckNumForName, but bombs out if not found.
400 //
401 int W_GetNumForName (char* name)
402 {
403     int i;
404
405     i = W_CheckNumForName (name);
406     
407     if (i == -1)
408       I_Error ("W_GetNumForName: %s not found!", name);
409       
410     return i;
411 }
412
413
414 //
415 // W_LumpLength
416 // Returns the buffer size needed to load the given lump.
417 //
418 int W_LumpLength (int lump)
419 {
420     if (lump >= numlumps)
421         I_Error ("W_LumpLength: %i >= numlumps",lump);
422
423     return lumpinfo[lump].size;
424 }
425
426
427
428 //
429 // W_ReadLump
430 // Loads the lump into the given buffer,
431 //  which must be >= W_LumpLength().
432 //
433 void
434 W_ReadLump
435 ( int           lump,
436   void*         dest )
437 {
438     int         c;
439     lumpinfo_t* l;
440     int         handle;
441         
442     if (lump >= numlumps)
443         I_Error ("W_ReadLump: %i >= numlumps",lump);
444
445     l = lumpinfo+lump;
446         
447     // ??? I_BeginRead ();
448         
449     if (l->handle == -1)
450     {
451         // reloadable file, so use open / read / close
452         if ( (handle = I_Open (reloadname)) == -1)
453             I_Error ("W_ReadLump: couldn't open %s",reloadname);
454     }
455     else
456         handle = l->handle;
457                 
458     I_Seek (handle, l->position);
459     c = I_Read (handle, dest, l->size);
460
461     if (c < l->size)
462         I_Error ("W_ReadLump: only read %i of %i on lump %i",
463                  c,l->size,lump);       
464
465     if (l->handle == -1)
466         I_Close (handle);
467
468     // ??? I_EndRead ();
469 }
470
471
472
473
474 //
475 // W_CacheLumpNum
476 //
477 void*
478 W_CacheLumpNum
479 ( int           lump,
480   int           tag )
481 {
482     if ((unsigned)lump >= numlumps)
483         I_Error ("W_CacheLumpNum: %i >= numlumps",lump);
484                 
485     if (!lumpcache[lump])
486     {
487         // read the lump in
488         
489         //printf ("cache miss on lump %i\n",lump);
490         Z_Malloc (W_LumpLength (lump), tag, &lumpcache[lump]);
491         W_ReadLump (lump, lumpcache[lump]);
492     }
493     else
494     {
495         //printf ("cache hit on lump %i\n",lump);
496         Z_ChangeTag (lumpcache[lump],tag);
497     }
498         
499     return lumpcache[lump];
500 }
501
502
503
504 //
505 // W_CacheLumpName
506 //
507 void*
508 W_CacheLumpName
509 ( char*         name,
510   int           tag )
511 {
512     return W_CacheLumpNum (W_GetNumForName(name), tag);
513 }
514
515
516 //
517 // W_Profile
518 //
519 int             info[2500][10];
520 int             profilecount;
521
522 void W_Profile (void)
523 {
524     int         i;
525     memblock_t* block;
526     void*       ptr;
527     char        ch;
528     FILE*       f;
529     int         j;
530     char        name[9];
531         
532         
533     for (i=0 ; i<numlumps ; i++)
534     {   
535         ptr = lumpcache[i];
536         if (!ptr)
537         {
538             continue;
539         }
540         else
541         {
542             block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
543             if (block->tag < PU_PURGELEVEL)
544                 ch = 'S';
545             else
546                 ch = 'P';
547         }
548         info[i][profilecount] = ch;
549     }
550     profilecount++;
551         
552     f = fopen ("waddump.txt","w");
553     name[8] = 0;
554
555     for (i=0 ; i<numlumps ; i++)
556     {
557         memcpy (name,lumpinfo[i].name,8);
558
559         for (j=0 ; j<8 ; j++)
560             if (!name[j])
561                 break;
562
563         for ( ; j<8 ; j++)
564             name[j] = ' ';
565
566         fprintf (f,"%s ",name);
567
568         for (j=0 ; j<profilecount ; j++)
569             fprintf (f,"    %c",info[i][j]);
570
571         fprintf (f,"\n");
572     }
573     fclose (f);
574 }
575
576