]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_ca.c
16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / src / lib / 16_ca.c
1 /* Catacomb Apocalypse Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // ID_CA.C\r
20 \r
21 /*\r
22 =============================================================================\r
23 \r
24 Id Software Caching Manager\r
25 ---------------------------\r
26 \r
27 Must be started BEFORE the memory manager, because it needs to get the headers\r
28 loaded into the data segment\r
29 \r
30 =============================================================================\r
31 */\r
32 \r
33 #include "src/lib/16_ca.h"\r
34 #pragma hdrstop\r
35 \r
36 #pragma warn -pro\r
37 #pragma warn -use\r
38 \r
39 #define THREEBYTEGRSTARTS\r
40 //https://github.com/open-watcom/open-watcom-v2/issues/279#issuecomment-244587566 for _seg\r
41 //http://www.shikadi.net/moddingwiki/GameMaps_Format for info on the code\r
42 /*\r
43 =============================================================================\r
44 \r
45                                                  LOCAL CONSTANTS\r
46 \r
47 =============================================================================\r
48 */\r
49 \r
50 /*typedef struct\r
51 {\r
52   word bit0,bit1;       // 0-255 is a character, > is a pointer to a node\r
53 } huffnode;*/\r
54 \r
55 \r
56 /*typedef struct\r
57 {\r
58         unsigned        RLEWtag;\r
59         long            headeroffsets[100];\r
60         byte            tileinfo[];\r
61 } mapfiletype;*/\r
62 \r
63 \r
64 /*\r
65 =============================================================================\r
66 \r
67                                                  GLOBAL VARIABLES\r
68 \r
69 =============================================================================\r
70 */\r
71 \r
72 /*byte          _seg    *tinf;\r
73 int                     mapon;\r
74 \r
75 unsigned        _seg    *mapsegs[3];\r
76 maptype         _seg    *mapheaderseg[NUMMAPS];\r
77 byte            _seg    *audiosegs[NUMSNDCHUNKS];\r
78 void            _seg    *grsegs[NUMCHUNKS];\r
79 \r
80 byte            far     grneeded[NUMCHUNKS];*/\r
81 \r
82 void    (*drawcachebox)         (char *title, unsigned numcache);\r
83 void    (*updatecachebox)       (void);\r
84 void    (*finishcachebox)       (void);\r
85 \r
86 /*\r
87 =============================================================================\r
88 \r
89                                                  LOCAL VARIABLES\r
90 \r
91 =============================================================================\r
92 */\r
93 \r
94 /*extern        long    far     CGAhead;\r
95 extern  long    far     EGAhead;\r
96 extern  byte    CGAdict;\r
97 extern  byte    EGAdict;\r
98 extern  byte    far     maphead;\r
99 extern  byte    mapdict;\r
100 extern  byte    far     audiohead;\r
101 extern  byte    audiodict;*/\r
102 \r
103 void CA_CannotOpen(char *string, global_game_variables_t *gvar);\r
104 \r
105 /*long          _seg *grstarts; // array of offsets in egagraph, -1 for sparse\r
106 long            _seg *audiostarts;      // array of offsets in audio / audiot\r
107 \r
108 #ifdef GRHEADERLINKED\r
109 huffnode        *gvar->ca.grhuffman;\r
110 #else\r
111 huffnode        gvar->ca.grhuffman[255];\r
112 #endif\r
113 \r
114 #ifdef AUDIOHEADERLINKED\r
115 huffnode        *audiohuffman;\r
116 #else\r
117 huffnode        audiohuffman[255];\r
118 #endif\r
119 \r
120 \r
121 int                     grhandle;               // handle to EGAGRAPH\r
122 int                     maphandle;              // handle to MAPTEMP / GAMEMAPS\r
123 int                     audiohandle;    // handle to AUDIOT / AUDIO\r
124 */\r
125 long            chunkcomplen,chunkexplen;\r
126 /*\r
127 SDMode          oldsoundmode;\r
128 \r
129 \r
130 \r
131 void    CAL_DialogDraw (char *title,unsigned numcache);\r
132 void    CAL_DialogUpdate (void);\r
133 void    CAL_DialogFinish (void);*/\r
134 void    CAL_CarmackExpand (unsigned far *source, unsigned far *dest,\r
135                 unsigned length);\r
136 \r
137 \r
138 #ifdef THREEBYTEGRSTARTS\r
139 #define FILEPOSSIZE     3\r
140 //#define       GRFILEPOS(c) (*(long far *)(((byte far *)grstarts)+(c)*3)&0xffffff)\r
141 CASVT GRFILEPOS(int c, global_game_variables_t *gvar)\r
142 {\r
143         CASVT value;\r
144         int     offset;\r
145 \r
146         offset = c*3;\r
147 \r
148         value = *(CASVT far *)(((byte far *)gvar->ca.grstarts)+offset);\r
149 \r
150         value &= 0x00ffffffl;\r
151 \r
152         if (value == 0xffffffl)\r
153                 value = -1;\r
154 \r
155         return value;\r
156 };\r
157 #else\r
158 #define FILEPOSSIZE     4\r
159 //#define       GRFILEPOS(c) (gvar->ca.grstarts[c])\r
160 CASVT GRFILEPOS(int c, global_game_variables_t *gvar)\r
161 {\r
162         return gvar->ca.grstarts[c];\r
163 }\r
164 #endif\r
165 \r
166 /*\r
167 =============================================================================\r
168 \r
169                                            LOW LEVEL ROUTINES\r
170 \r
171 =============================================================================\r
172 */\r
173 \r
174 /*\r
175 ============================\r
176 =\r
177 = CA_OpenDebug / CA_CloseDebug\r
178 =\r
179 = Opens a binary file with the handle "debughandle"\r
180 =\r
181 ============================\r
182 */\r
183 void CA_OpenDebug(global_game_variables_t *gvar)\r
184 {\r
185 #ifdef __BORLANDC__\r
186         unlink("debug.16b");\r
187         gvar->handle.debughandle = open("debug.16b", O_CREAT | O_WRONLY | O_TEXT);\r
188 #endif\r
189 #ifdef __WATCOMC__\r
190         unlink("debug.16w");\r
191         gvar->handle.debughandle = open("debug.16w", O_CREAT | O_WRONLY | O_TEXT);\r
192 #endif\r
193 }\r
194 \r
195 void CA_CloseDebug(global_game_variables_t *gvar)\r
196 {\r
197         close(gvar->handle.debughandle);\r
198 }\r
199 \r
200 \r
201 \r
202 /*\r
203 ============================\r
204 =\r
205 = CAL_GetGrChunkLength\r
206 =\r
207 = Gets the length of an explicit length chunk (not tiles)\r
208 = The file pointer is positioned so the compressed data can be read in next.\r
209 =\r
210 ============================\r
211 */\r
212 \r
213 void CAL_GetGrChunkLength (int chunk,global_game_variables_t *gvar)\r
214 {\r
215         lseek(gvar->ca.file.grhandle,GRFILEPOS(chunk,gvar),SEEK_SET);\r
216         read(gvar->ca.file.grhandle,&gvar->ca.chunkexplen,sizeof(gvar->ca.chunkexplen));\r
217         gvar->ca.chunkcomplen = GRFILEPOS(chunk+1,gvar)-GRFILEPOS(chunk,gvar)-4;\r
218 }\r
219 \r
220 \r
221 /*\r
222 ==========================\r
223 =\r
224 = CA_FarRead\r
225 =\r
226 = Read from a file to a far pointer\r
227 =\r
228 ==========================\r
229 */\r
230 \r
231 boolean CA_FarRead(int handle, byte far *dest, dword length, global_game_variables_t *gvar)\r
232 {\r
233         boolean flag=0;\r
234         //dword fat=0;\r
235         //word segm=0;\r
236         if(gvar->pm.emm.EMSVer<0x40)\r
237         if(length>0xfffflu)\r
238         {\r
239                 printf("File is a fat bakapee\n");\r
240                 //segm=(length%0xfffflu)-1;\r
241                 //fat=segm*0xfffflu;\r
242                 //length-=fat;\r
243                 printf("CA_FarRead doesn't support 64K reads yet!\n");\r
244                 return 0;//TODO: EXPAND!!!\r
245         }\r
246 \r
247         //if(!fat&&!segm)\r
248         //{\r
249         __asm {\r
250                 push    ds\r
251                 mov     bx,[handle]\r
252                 mov     cx,[WORD PTR length]\r
253                 mov     dx,[WORD PTR dest]\r
254                 mov     ds,[WORD PTR dest+2]\r
255                 mov     ah,0x3f                         // READ w/handle\r
256                 int     21h\r
257                 pop     ds\r
258                 jnc     good\r
259                 mov     errno,ax\r
260                 mov     flag,0\r
261                 jmp End\r
262 #ifdef __BORLANDC__\r
263         }\r
264 #endif\r
265 good:\r
266 #ifdef __BORLANDC__\r
267         __asm {\r
268 #endif\r
269                 cmp     ax,[WORD PTR length]\r
270                 je      done\r
271 //              errno = EINVFMT;                        // user manager knows this is bad read\r
272                 mov     flag,0\r
273                 jmp End\r
274 #ifdef __BORLANDC__\r
275         }\r
276 #endif\r
277 done:\r
278 #ifdef __BORLANDC__\r
279         __asm {\r
280 #endif\r
281                 mov     flag,1\r
282 #ifdef __BORLANDC__\r
283         }\r
284 #endif\r
285 End:\r
286 #ifdef __WATCOMC__\r
287         }\r
288 #endif\r
289         return flag;\r
290 }\r
291 \r
292 \r
293 /*\r
294 ==========================\r
295 =\r
296 = CA_SegWrite\r
297 =\r
298 = Write from a file to a far pointer\r
299 =\r
300 ==========================\r
301 */\r
302 \r
303 boolean CA_FarWrite(int handle, byte far *source, dword length, global_game_variables_t *gvar)\r
304 {\r
305         boolean flag=0;\r
306         //dword fat=0;\r
307         //word segm=0;\r
308         if(gvar->pm.emm.EMSVer<0x40)\r
309         if(length>0xfffflu)\r
310         {\r
311                 printf("File is a fat bakapee\n");\r
312                 //segm=(length%0xfffflu)-1;\r
313                 //fat=segm*0xfffflu;\r
314                 //length-=fat;\r
315                 printf("CA_FarWrite doesn't support 64K reads yet!\n");\r
316                 return 0;\r
317         }\r
318 \r
319         //if(!fat&&!segm)\r
320         //{\r
321         __asm {\r
322                 push    ds\r
323                 mov     bx,[handle]\r
324                 mov     cx,[WORD PTR length]\r
325                 mov     dx,[WORD PTR source]\r
326                 mov     ds,[WORD PTR source+2]\r
327                 mov     ah,0x40                 // WRITE w/handle\r
328                 int     21h\r
329                 pop     ds\r
330                 jnc     good\r
331                 mov     errno,ax\r
332                 mov flag,0\r
333                 jmp End\r
334 #ifdef __BORLANDC__\r
335         }\r
336 #endif\r
337 good:\r
338 #ifdef __BORLANDC__\r
339         __asm {\r
340 #endif\r
341                 cmp     ax,[WORD PTR length]\r
342                 je      done\r
343 //              errno = ENOMEM;                         // user manager knows this is bad write\r
344                 mov     flag,0\r
345                 jmp End\r
346 #ifdef __BORLANDC__\r
347         }\r
348 #endif\r
349 done:\r
350 #ifdef __BORLANDC__\r
351         __asm {\r
352 #endif\r
353                 mov     flag,1\r
354 #ifdef __BORLANDC__\r
355         }\r
356 #endif\r
357 End:\r
358 #ifdef __WATCOMC__\r
359         }\r
360 #endif\r
361         return flag;\r
362 }\r
363 \r
364 \r
365 /*\r
366 ==========================\r
367 =\r
368 = CA_ReadFile\r
369 =\r
370 = Reads a file into an allready allocated buffer\r
371 =\r
372 ==========================\r
373 */\r
374 \r
375 boolean CA_ReadFile(char *filename, memptr *ptr, global_game_variables_t *gvar)\r
376 {\r
377         int handle;\r
378         sdword size;\r
379         //long size;\r
380 \r
381         if((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
382                 return false;\r
383 \r
384         size = filelength(handle);\r
385 #ifdef __DEBUG_CA__\r
386         if(dbg_debugca>0){\r
387                 printf("===============================================================================\n");\r
388                 printf("                CA_ReadFile\n");\r
389                 printf("===============================================================================\n");\r
390                 //%04x\r
391                 printf("        ptr=%Fp\n", ptr);\r
392                 printf("        *ptr=%Fp\n", *ptr);\r
393                 printf("        &ptr=%Fp\n", &ptr);\r
394         }\r
395 #endif\r
396         if(!CA_FarRead(handle,*ptr,size, gvar))\r
397         {\r
398                 close(handle);\r
399                 return false;\r
400         }\r
401         close(handle);\r
402         return true;\r
403 }\r
404 \r
405 \r
406 /*\r
407 ==========================\r
408 =\r
409 = CA_WriteFile\r
410 =\r
411 = Writes a file from a memory buffer\r
412 =\r
413 ==========================\r
414 */\r
415 \r
416 boolean CA_WriteFile (char *filename, void far *ptr, long length, global_game_variables_t *gvar)\r
417 {\r
418         int handle;\r
419         //sdword size;\r
420         //long size;\r
421 \r
422         handle = open(filename,O_CREAT | O_BINARY | O_WRONLY,\r
423                                 S_IREAD | S_IWRITE | S_IFREG);\r
424 \r
425         if (handle == -1)\r
426                 return false;\r
427 \r
428         if (!CA_FarWrite (handle,ptr,length, gvar))\r
429         {\r
430                 close(handle);\r
431                 return false;\r
432         }\r
433         close(handle);\r
434         return true;\r
435 }\r
436 \r
437 \r
438 \r
439 /*\r
440 ==========================\r
441 =\r
442 = CA_LoadFile\r
443 =\r
444 = Allocate space for and load a file\r
445 =\r
446 ==========================\r
447 */\r
448 \r
449 boolean CA_LoadFile(char *filename, memptr *ptr, global_game_variables_t *gvar)\r
450 {\r
451         int handle;\r
452         sdword size;\r
453         //long size;\r
454 \r
455         if((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
456                 return false;\r
457 \r
458         size = filelength(handle);\r
459 #ifdef __DEBUG_CA__\r
460         if(dbg_debugca>0){\r
461                 printf("===============================================================================\n");\r
462                 printf("                CA_LoadFile\n");\r
463                 printf("===============================================================================\n");\r
464                 //%04x\r
465                 printf("        ptr=%Fp\n", ptr);\r
466                 printf("        *ptr=%Fp\n", *ptr);\r
467                 printf("        &ptr=%Fp\n", &ptr);\r
468         }\r
469 #endif\r
470         MM_GetPtr(ptr,size, gvar);\r
471 #ifdef __DEBUG_CA__\r
472         if(dbg_debugca>0){\r
473                 //%04x\r
474                 printf("---------------------------------------\n");\r
475                 printf("        ptr=%Fp\n", ptr);\r
476                 printf("        *ptr=%Fp\n", *ptr);\r
477                 printf("        &ptr=%Fp\n", &ptr);\r
478                 printf("-------------------------------------------------------------------------------\n");\r
479         }\r
480 #endif\r
481         if(!CA_FarRead(handle,*ptr,size, gvar))\r
482         {\r
483                 close(handle);\r
484                 return false;\r
485         }\r
486         close(handle);\r
487         return true;\r
488 }\r
489 \r
490 /*\r
491 ============================================================================\r
492 \r
493                 COMPRESSION routines, see JHUFF.C for more\r
494 \r
495 ============================================================================\r
496 */\r
497 \r
498 \r
499 \r
500 /*\r
501 ===============\r
502 =\r
503 = CAL_OptimizeNodes\r
504 =\r
505 = Goes through a huffman table and changes the 256-511 node numbers to the\r
506 = actular address of the node.  Must be called before CAL_HuffExpand\r
507 =\r
508 ===============\r
509 */\r
510 \r
511 void CAL_OptimizeNodes(huffnode *table)\r
512 {\r
513   huffnode *node;\r
514   int i;\r
515 \r
516   node = table;\r
517 \r
518   for (i=0;i<255;i++)\r
519   {\r
520         if (node->bit0 >= 256)\r
521           node->bit0 = (unsigned)(table+(node->bit0-256));\r
522         if (node->bit1 >= 256)\r
523           node->bit1 = (unsigned)(table+(node->bit1-256));\r
524         node++;\r
525   }\r
526 }\r
527 \r
528 \r
529 \r
530 /*\r
531 ======================\r
532 =\r
533 = CAL_HuffExpand\r
534 =\r
535 = Length is the length of the EXPANDED data\r
536 =\r
537 ======================\r
538 */\r
539 \r
540 void CAL_HuffExpand (byte far *source, byte far *dest,\r
541   long length,huffnode *hufftable)\r
542 {\r
543 //  unsigned bit,byte,node,code;\r
544   unsigned sourceseg,sourceoff,destseg,destoff,endoff;\r
545         huffnode *headptr;\r
546 //  huffnode *nodeon;\r
547 \r
548         headptr = hufftable+254;        // head node is allways node 254\r
549 \r
550   source++;     // normalize\r
551   source--;\r
552   dest++;\r
553   dest--;\r
554 \r
555   sourceseg = FP_SEG(source);\r
556   sourceoff = FP_OFF(source);\r
557   destseg = FP_SEG(dest);\r
558   destoff = FP_OFF(dest);\r
559   endoff = destoff+length;\r
560 \r
561 //\r
562 // ds:si source\r
563 // es:di dest\r
564 // ss:bx node pointer\r
565 //\r
566 \r
567         if (length <0xfff0)\r
568         {\r
569 \r
570 //--------------------------\r
571 // expand less than 64k of data\r
572 //--------------------------\r
573 \r
574         __asm {\r
575                 mov     bx,[word ptr headptr]\r
576 \r
577                 mov     si,[sourceoff]\r
578                 mov     di,[destoff]\r
579                 mov     es,[destseg]\r
580                 mov     ds,[sourceseg]\r
581                 mov     ax,[endoff]\r
582 \r
583                 mov     ch,[si]                         // load first byte\r
584                 inc     si\r
585                 mov     cl,1\r
586 #ifdef __BORLANDC__\r
587         }\r
588 #endif\r
589 expandshort:\r
590 #ifdef __BORLANDC__\r
591         __asm {\r
592 #endif\r
593                 test    ch,cl                   // bit set?\r
594                 jnz     bit1short\r
595                 mov     dx,[ss:bx]                      // take bit0 path from node\r
596                 shl     cl,1                            // advance to next bit position\r
597                 jc      newbyteshort\r
598                 jnc     sourceupshort\r
599 #ifdef __BORLANDC__\r
600         }\r
601 #endif\r
602 bit1short:\r
603 #ifdef __BORLANDC__\r
604         __asm {\r
605 #endif\r
606                 mov     dx,[ss:bx+2]            // take bit1 path\r
607                 shl     cl,1                            // advance to next bit position\r
608                 jnc     sourceupshort\r
609 #ifdef __BORLANDC__\r
610         }\r
611 #endif\r
612 newbyteshort:\r
613 #ifdef __BORLANDC__\r
614         __asm {\r
615 #endif\r
616                 mov     ch,[si]                         // load next byte\r
617                 inc     si\r
618                 mov     cl,1                            // back to first bit\r
619 #ifdef __BORLANDC__\r
620         }\r
621 #endif\r
622 sourceupshort:\r
623 #ifdef __BORLANDC__\r
624         __asm {\r
625 #endif\r
626                 or      dh,dh                           // if dx<256 its a byte, else move node\r
627                 jz      storebyteshort\r
628                 mov     bx,dx                           // next node = (huffnode *)code\r
629                 jmp     expandshort\r
630 #ifdef __BORLANDC__\r
631         }\r
632 #endif\r
633 storebyteshort:\r
634 #ifdef __BORLANDC__\r
635         __asm {\r
636 #endif\r
637                 mov     [es:di],dl\r
638                 inc     di                                      // write a decopmpressed byte out\r
639                 mov     bx,[word ptr headptr]           // back to the head node for next bit\r
640 \r
641                 cmp     di,ax                           // done?\r
642                 jne     expandshort\r
643         }\r
644         }\r
645         else\r
646         {\r
647 \r
648 //--------------------------\r
649 // expand more than 64k of data\r
650 //--------------------------\r
651 \r
652   length--;\r
653 \r
654         __asm {\r
655                 mov     bx,[word ptr headptr]\r
656                 mov     cl,1\r
657 \r
658                 mov     si,[sourceoff]\r
659                 mov     di,[destoff]\r
660                 mov     es,[destseg]\r
661                 mov     ds,[sourceseg]\r
662 \r
663                 lodsb                   // load first byte\r
664 #ifdef __BORLANDC__\r
665         }\r
666 #endif\r
667 expand:\r
668 #ifdef __BORLANDC__\r
669         __asm {\r
670 #endif\r
671                 test    al,cl           // bit set?\r
672                 jnz     bit1\r
673                 mov     dx,[ss:bx]      // take bit0 path from node\r
674                 jmp     gotcode\r
675 #ifdef __BORLANDC__\r
676         }\r
677 #endif\r
678 bit1:\r
679 #ifdef __BORLANDC__\r
680         __asm {\r
681 #endif\r
682                 mov     dx,[ss:bx+2]    // take bit1 path\r
683 #ifdef __BORLANDC__\r
684         }\r
685 #endif\r
686 gotcode:\r
687 #ifdef __BORLANDC__\r
688         __asm {\r
689 #endif\r
690                 shl     cl,1            // advance to next bit position\r
691                 jnc     sourceup\r
692                 lodsb\r
693                 cmp     si,0x10         // normalize ds:si\r
694                 jb      sinorm\r
695                 mov     cx,ds\r
696                 inc     cx\r
697                 mov     ds,cx\r
698                 xor     si,si\r
699 #ifdef __BORLANDC__\r
700         }\r
701 #endif\r
702 sinorm:\r
703 #ifdef __BORLANDC__\r
704         __asm {\r
705 #endif\r
706                 mov     cl,1            // back to first bit\r
707 #ifdef __BORLANDC__\r
708         }\r
709 #endif\r
710 sourceup:\r
711 #ifdef __BORLANDC__\r
712         __asm {\r
713 #endif\r
714                 or      dh,dh           // if dx<256 its a byte, else move node\r
715                 jz      storebyte\r
716                 mov     bx,dx           // next node = (huffnode *)code\r
717                 jmp     expand\r
718 #ifdef __BORLANDC__\r
719         }\r
720 #endif\r
721 storebyte:\r
722 #ifdef __BORLANDC__\r
723         __asm {\r
724 #endif\r
725                 mov     [es:di],dl\r
726                 inc     di              // write a decopmpressed byte out\r
727                 mov     bx,[word ptr headptr]   // back to the head node for next bit\r
728 \r
729                 cmp     di,0x10         // normalize es:di\r
730                 jb      dinorm\r
731                 mov     dx,es\r
732                 inc     dx\r
733                 mov     es,dx\r
734                 xor     di,di\r
735 #ifdef __BORLANDC__\r
736         }\r
737 #endif\r
738 dinorm:\r
739 #ifdef __BORLANDC__\r
740         __asm {\r
741 #endif\r
742                 sub     [WORD PTR ss:length],1\r
743                 jnc     expand\r
744                 dec     [WORD PTR ss:length+2]\r
745                 jns     expand          // when length = ffff ffff, done\r
746         }\r
747         }\r
748 \r
749         __asm {\r
750                 mov     ax,ss\r
751                 mov     ds,ax\r
752         }\r
753 \r
754 }\r
755 \r
756 \r
757 /*\r
758 ======================\r
759 =\r
760 = CAL_CarmackExpand\r
761 =\r
762 = Length is the length of the EXPANDED data\r
763 =\r
764 ======================\r
765 */\r
766 \r
767 #define NEARTAG 0xa7\r
768 #define FARTAG  0xa8\r
769 \r
770 void CAL_CarmackExpand (unsigned far *source, unsigned far *dest, unsigned length)\r
771 {\r
772         unsigned        ch,chhigh,count,offset;\r
773         unsigned        far *copyptr, far *inptr, far *outptr;\r
774 \r
775         length/=2;\r
776 \r
777         inptr = source;\r
778         outptr = dest;\r
779 \r
780         while (length)\r
781         {\r
782                 ch = *inptr++;\r
783                 chhigh = ch>>8;\r
784                 if (chhigh == NEARTAG)\r
785                 {\r
786                         count = ch&0xff;\r
787                         if (!count)\r
788                         {                               // have to insert a word containing the tag byte\r
789                                 ch |= *(/*(unsigned char far *)*/inptr)++;\r
790                                 *outptr++ = ch;\r
791                                 length--;\r
792                         }\r
793                         else\r
794                         {\r
795                                 offset = *(/*(unsigned char far *)*/inptr)++;\r
796                                 copyptr = outptr - offset;\r
797                                 length -= count;\r
798                                 while (count--)\r
799                                         *outptr++ = *copyptr++;\r
800                         }\r
801                 }\r
802                 else if (chhigh == FARTAG)\r
803                 {\r
804                         count = ch&0xff;\r
805                         if (!count)\r
806                         {                               // have to insert a word containing the tag byte\r
807                                 ch |= *(/*(unsigned char far *)*/inptr)++;\r
808                                 *outptr++ = ch;\r
809                                 length --;\r
810                         }\r
811                         else\r
812                         {\r
813                                 offset = *inptr++;\r
814                                 copyptr = dest + offset;\r
815                                 length -= count;\r
816                                 while (count--)\r
817                                         *outptr++ = *copyptr++;\r
818                         }\r
819                 }\r
820                 else\r
821                 {\r
822                         *outptr++ = ch;\r
823                         length --;\r
824                 }\r
825         }\r
826 }\r
827 \r
828 \r
829 /*\r
830 ======================\r
831 =\r
832 = CA_RLEWcompress\r
833 =\r
834 ======================\r
835 */\r
836 \r
837 long CA_RLEWCompress (unsigned far *source, long length, unsigned far *dest,\r
838   unsigned rlewtag)\r
839 {\r
840   long complength;\r
841   unsigned value,count,i;\r
842   unsigned far *start,far *end;\r
843 \r
844   start = dest;\r
845 \r
846   end = source + (length+1)/2;\r
847 \r
848 //\r
849 // compress it\r
850 //\r
851   do\r
852   {\r
853         count = 1;\r
854         value = *source++;\r
855         while (*source == value && source<end)\r
856         {\r
857           count++;\r
858           source++;\r
859         }\r
860         if (count>3 || value == rlewtag)\r
861         {\r
862     //\r
863     // send a tag / count / value string\r
864     //\r
865       *dest++ = rlewtag;\r
866       *dest++ = count;\r
867       *dest++ = value;\r
868     }\r
869     else\r
870     {\r
871     //\r
872     // send word without compressing\r
873     //\r
874       for (i=1;i<=count;i++)\r
875         *dest++ = value;\r
876         }\r
877 \r
878   } while (source<end);\r
879 \r
880   complength = 2*(dest-start);\r
881   return complength;\r
882 }\r
883 \r
884 \r
885 /*\r
886 ======================\r
887 =\r
888 = CA_RLEWexpand\r
889 = length is EXPANDED length\r
890 =\r
891 ======================\r
892 */\r
893 \r
894 void CA_RLEWexpand (unsigned far *source, unsigned far *dest,long length,\r
895   unsigned rlewtag)\r
896 {\r
897 //  unsigned value,count,i;\r
898   unsigned far *end;\r
899   unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;\r
900 \r
901 \r
902 //\r
903 // expand it\r
904 //\r
905 #if 0\r
906   do\r
907   {\r
908         value = *source++;\r
909         if (value != rlewtag)\r
910         //\r
911         // uncompressed\r
912         //\r
913           *dest++=value;\r
914         else\r
915         {\r
916         //\r
917         // compressed string\r
918         //\r
919           count = *source++;\r
920           value = *source++;\r
921           for (i=1;i<=count;i++)\r
922         *dest++ = value;\r
923         }\r
924   } while (dest<end);\r
925 #endif\r
926 \r
927   end = dest + (length)/2;\r
928   sourceseg = FP_SEG(source);\r
929   sourceoff = FP_OFF(source);\r
930   destseg = FP_SEG(dest);\r
931   destoff = FP_OFF(dest);\r
932   endseg = FP_SEG(end);\r
933   endoff = FP_OFF(end);\r
934 \r
935 \r
936 //\r
937 // ax = source value\r
938 // bx = tag value\r
939 // cx = repeat counts\r
940 // dx = scratch\r
941 //\r
942 // NOTE: A repeat count that produces 0xfff0 bytes can blow this!\r
943 //\r
944         __asm {\r
945                 mov     bx,rlewtag\r
946                 mov     si,sourceoff\r
947                 mov     di,destoff\r
948                 mov     es,destseg\r
949                 mov     ds,sourceseg\r
950 #ifdef __BORLANDC__\r
951         }\r
952 #endif\r
953 expand:\r
954 #ifdef __BORLANDC__\r
955         __asm {\r
956 #endif\r
957                 lodsw\r
958                 cmp     ax,bx\r
959                 je      repeat\r
960                 stosw\r
961                 jmp     next\r
962 #ifdef __BORLANDC__\r
963         }\r
964 #endif\r
965 repeat:\r
966 #ifdef __BORLANDC__\r
967         __asm {\r
968 #endif\r
969                 lodsw\r
970                 mov     cx,ax           // repeat count\r
971                 lodsw                   // repeat value\r
972                 rep stosw\r
973 #ifdef __BORLANDC__\r
974         }\r
975 #endif\r
976 next:\r
977 #ifdef __BORLANDC__\r
978         __asm {\r
979 #endif\r
980                 cmp     si,0x10         // normalize ds:si\r
981                 jb      sinorm\r
982                 mov     ax,si\r
983                 shr     ax,1\r
984                 shr     ax,1\r
985                 shr     ax,1\r
986                 shr     ax,1\r
987                 mov     dx,ds\r
988                 add     dx,ax\r
989                 mov     ds,dx\r
990                 and     si,0xf\r
991 #ifdef __BORLANDC__\r
992         }\r
993 #endif\r
994 sinorm:\r
995 #ifdef __BORLANDC__\r
996         __asm {\r
997 #endif\r
998                 cmp     di,0x10         // normalize es:di\r
999                 jb      dinorm\r
1000                 mov     ax,di\r
1001                 shr     ax,1\r
1002                 shr     ax,1\r
1003                 shr     ax,1\r
1004                 shr     ax,1\r
1005                 mov     dx,es\r
1006                 add     dx,ax\r
1007                 mov     es,dx\r
1008                 and     di,0xf\r
1009 #ifdef __BORLANDC__\r
1010         }\r
1011 #endif\r
1012 dinorm:\r
1013 #ifdef __BORLANDC__\r
1014         __asm {\r
1015 #endif\r
1016                 cmp     di,ss:endoff\r
1017                 jne     expand\r
1018                 mov     ax,es\r
1019                 cmp     ax,ss:endseg\r
1020                 jb      expand\r
1021 \r
1022                 mov     ax,ss\r
1023                 mov     ds,ax\r
1024         }\r
1025 }\r
1026 \r
1027 \r
1028 /*\r
1029 =============================================================================\r
1030 \r
1031                                          CACHE MANAGER ROUTINES\r
1032 \r
1033 =============================================================================\r
1034 */\r
1035 \r
1036 /*\r
1037 ======================\r
1038 =\r
1039 = CAL_SetupGrFile\r
1040 =\r
1041 ======================\r
1042 */\r
1043 \r
1044 void CAL_SetupGrFile (global_game_variables_t *gvar)\r
1045 {\r
1046         char fname[13];\r
1047         int handle;\r
1048 #if NUMPICS>0\r
1049         memptr compseg;\r
1050 #endif\r
1051 \r
1052 #ifdef GRHEADERLINKED\r
1053 \r
1054         gvar->ca.grhuffman = (huffnode *)&VGAdict;\r
1055         grstarts = (long _seg *)FP_SEG(&VGAhead);\r
1056 \r
1057         CAL_OptimizeNodes (gvar->ca.grhuffman);\r
1058 \r
1059 #else\r
1060 \r
1061 //\r
1062 // load ???dict.ext (huffman dictionary for graphics files)\r
1063 //\r
1064 \r
1065         strcpy(fname,GDICTNAME);\r
1066         strcat(fname,EXTENSION);\r
1067 \r
1068         if ((handle = open(fname,\r
1069                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
1070                 CA_CannotOpen(fname,gvar);\r
1071 \r
1072         read(handle, &gvar->ca.grhuffman, sizeof(gvar->ca.grhuffman));\r
1073         close(handle);\r
1074         CAL_OptimizeNodes (gvar->ca.grhuffman);\r
1075 //\r
1076 // load the data offsets from ???head.ext\r
1077 //\r
1078         MM_GetPtr (MEMPTRCONV gvar->ca.grstarts,(NUMCHUNKS+1)*FILEPOSSIZE, gvar);\r
1079 \r
1080         strcpy(fname,GHEADNAME);\r
1081         strcat(fname,EXTENSION);\r
1082 \r
1083         if ((handle = open(fname,\r
1084                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
1085                 CA_CannotOpen(fname,gvar);\r
1086 \r
1087         CA_FarRead(handle, (memptr)gvar->ca.grstarts, (NUMCHUNKS+1)*FILEPOSSIZE, gvar);\r
1088 \r
1089         close(handle);\r
1090 \r
1091 \r
1092 #endif\r
1093 \r
1094 //\r
1095 // Open the graphics file, leaving it open until the game is finished\r
1096 //\r
1097         strcpy(fname,GFILENAME);\r
1098         strcat(fname,EXTENSION);\r
1099 \r
1100         gvar->ca.file.grhandle = open(fname, O_RDONLY | O_BINARY);\r
1101         if (gvar->ca.file.grhandle == -1)\r
1102                 CA_CannotOpen(fname,gvar);\r
1103 \r
1104 \r
1105 //\r
1106 // load the pic and sprite headers into the arrays in the data segment\r
1107 //\r
1108 #if NUMPICS>0\r
1109         MM_GetPtr(MEMPTRCONV gvar->video.pictable,NUMPICS*sizeof(pictabletype),gvar);\r
1110         CAL_GetGrChunkLength(STRUCTPIC,gvar);           // position file pointer\r
1111         printf("CAL_SetupGrFile:\n");\r
1112         printf("        gvar->ca.chunkcomplen size is %lu\n", gvar->ca.chunkcomplen);\r
1113         MM_GetPtr(&compseg,gvar->ca.chunkcomplen,gvar);\r
1114         IN_Ack(gvar);\r
1115         CA_FarRead (gvar->ca.file.grhandle,compseg,gvar->ca.chunkcomplen,gvar);\r
1116         CAL_HuffExpand (compseg, (byte far *)gvar->video.pictable,NUMPICS*sizeof(pictabletype),gvar->ca.grhuffman);\r
1117         MM_FreePtr(&compseg,gvar);\r
1118 #endif\r
1119 \r
1120 #if NUMPICM>0\r
1121         MM_GetPtr(MEMPTRCONV picmtable,NUMPICM*sizeof(pictabletype));\r
1122         CAL_GetGrChunkLength(STRUCTPICM);               // position file pointer\r
1123         MM_GetPtr(&compseg,gvar->ca.chunkcomplen);\r
1124         CA_FarRead (gvar->ca.file.grhandle,compseg,gvar->ca.chunkcomplen);\r
1125         CAL_HuffExpand (compseg, (byte far *)picmtable,NUMPICS*sizeof(pictabletype),gvar->ca.grhuffman);\r
1126         MM_FreePtr(&compseg);\r
1127 #endif\r
1128 \r
1129 #if NUMSPRITES>0\r
1130         MM_GetPtr(MEMPTRCONV spritetable,NUMSPRITES*sizeof(spritetabletype));\r
1131         CAL_GetGrChunkLength(STRUCTSPRITE);     // position file pointer\r
1132         MM_GetPtr(&compseg,gvar->ca.chunkcomplen);\r
1133         CA_FarRead (gvar->ca.file.grhandle,compseg,gvar->ca.chunkcomplen);\r
1134         CAL_HuffExpand (compseg, (byte far *)spritetable,NUMSPRITES*sizeof(spritetabletype),gvar->ca.grhuffman);\r
1135         MM_FreePtr(&compseg);\r
1136 #endif\r
1137 \r
1138 }\r
1139 \r
1140 //==========================================================================\r
1141 \r
1142 \r
1143 /*\r
1144 ======================\r
1145 =\r
1146 = CAL_SetupMapFile\r
1147 =\r
1148 ======================\r
1149 */\r
1150 \r
1151 void CAL_SetupMapFile (global_game_variables_t *gvar)\r
1152 {\r
1153 #ifndef MAPHEADERLINKED\r
1154         int handle;\r
1155         long length;\r
1156 #endif\r
1157 \r
1158 //\r
1159 // load maphead.ext (offsets and tileinfo for map file)\r
1160 //\r
1161 #ifndef MAPHEADERLINKED\r
1162         if ((handle = open("maphead.mph",\r
1163                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
1164                 Quit (gvar, "Can't open maphead.mph");\r
1165         length = filelength(handle);\r
1166         MM_GetPtr (MEMPTRCONV gvar->ca.tinf,length,gvar);\r
1167         CA_FarRead(handle, gvar->ca.tinf, length,gvar);\r
1168         close(handle);\r
1169 //#else\r
1170 \r
1171         gvar->ca.tinf = (byte _seg *)FP_SEG(&maphead);\r
1172 \r
1173 #endif\r
1174 \r
1175 //\r
1176 // open the data file\r
1177 //\r
1178 //TODO: multiple files\r
1179         if ((gvar->ca.file.maphandle = open("data/test.map",\r
1180                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
1181                 Quit (gvar, "Can't open data/test.map!");\r
1182 /*#ifdef MAPHEADERLINKED\r
1183         if ((maphandle = open("GAMEMAPS.16"ENSION,\r
1184                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
1185                 Quit (gvar, "Can't open GAMEMAPS.16"ENSION"!");\r
1186 #else\r
1187         if ((maphandle = open("MAPTEMP.16"ENSION,\r
1188                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
1189                 Quit (gvar, "Can't open MAPTEMP.16"ENSION"!");\r
1190 #endif*/\r
1191 }\r
1192 \r
1193 //==========================================================================\r
1194 \r
1195 \r
1196 /*\r
1197 ======================\r
1198 =\r
1199 = CAL_SetupAudioFile\r
1200 =\r
1201 ======================\r
1202 */\r
1203 \r
1204 /*void CAL_SetupAudioFile (void)\r
1205 {\r
1206         int handle;\r
1207         long length;\r
1208 \r
1209 //\r
1210 // load maphead.ext (offsets and tileinfo for map file)\r
1211 //\r
1212 #ifndef AUDIOHEADERLINKED\r
1213         if ((handle = open("AUDIOHED.16",\r
1214                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
1215                 Quit (gvar, "Can't open AUDIOHED.16""!");\r
1216         length = filelength(handle);\r
1217         MM_GetPtr (MEMPTRCONV audiostarts,length);\r
1218         CA_FarRead(handle, (byte far *)audiostarts, length);\r
1219         close(handle);\r
1220 #else\r
1221         audiohuffman = (huffnode *)&audiodict;\r
1222         CAL_OptimizeNodes (audiohuffman);\r
1223         audiostarts = (long _seg *)FP_SEG(&audiohead);\r
1224 #endif\r
1225 \r
1226 //\r
1227 // open the data file\r
1228 //\r
1229 #ifndef AUDIOHEADERLINKED\r
1230         if ((audiohandle = open("AUDIOT.16",\r
1231                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
1232                 Quit (gvar, "Can't open AUDIOT.16""!");\r
1233 #else\r
1234         if ((audiohandle = open("AUDIO.16",\r
1235                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
1236                 Quit (gvar, "Can't open AUDIO.16""!");\r
1237 #endif\r
1238 }*/\r
1239 \r
1240 //==========================================================================\r
1241 \r
1242 \r
1243 /*\r
1244 ======================\r
1245 =\r
1246 = CA_Startup\r
1247 =\r
1248 = Open all files and load in headers\r
1249 =\r
1250 ======================\r
1251 */\r
1252 \r
1253 void CA_Startup(global_game_variables_t *gvar)\r
1254 {\r
1255 #ifdef PROFILE\r
1256 #ifdef __BORLANDC__\r
1257         unlink("profile.16b");\r
1258         gvar->handle.profilehandle = open("profile.16b", O_CREAT | O_WRONLY | O_TEXT);\r
1259 #endif\r
1260 #ifdef __WATCOMC__\r
1261         unlink("profile.16w");\r
1262         gvar->handle.profilehandle = open("profile.16w", O_CREAT | O_WRONLY | O_TEXT);\r
1263 #endif\r
1264 #endif//profile\r
1265 \r
1266 #ifdef __BORLANDC__\r
1267         unlink("meminfo.16b");\r
1268         gvar->handle.showmemhandle = open("meminfo.16b", O_CREAT | O_WRONLY | O_TEXT);\r
1269 #endif\r
1270 #ifdef __WATCOMC__\r
1271         unlink("meminfo.16w");\r
1272         gvar->handle.showmemhandle = open("meminfo.16w", O_CREAT | O_WRONLY | O_TEXT);\r
1273 #endif\r
1274 \r
1275 \r
1276 #ifndef NOMAPS\r
1277         CAL_SetupMapFile (gvar);\r
1278 #endif\r
1279 #ifndef NOGRAPHICS\r
1280         CAL_SetupGrFile (gvar);\r
1281 #endif\r
1282 #ifndef NOAUDIO\r
1283         CAL_SetupMapFile (gvar);\r
1284 #endif\r
1285 \r
1286         gvar->ca.camap.mapon = -1;\r
1287         gvar->ca.ca_levelbit = 1;\r
1288         gvar->ca.ca_levelnum = 0;\r
1289 \r
1290 /*      drawcachebox    = CAL_DialogDraw;\r
1291         updatecachebox  = CAL_DialogUpdate;\r
1292         finishcachebox  = CAL_DialogFinish;*/\r
1293 }\r
1294 \r
1295 //==========================================================================\r
1296 \r
1297 \r
1298 /*\r
1299 ======================\r
1300 =\r
1301 = CA_Shutdown\r
1302 =\r
1303 = Closes all files\r
1304 =\r
1305 ======================\r
1306 */\r
1307 \r
1308 void CA_Shutdown(global_game_variables_t *gvar)\r
1309 {\r
1310 #ifdef PROFILE\r
1311         close(gvar->handle.profilehandle);\r
1312 #endif\r
1313         close(gvar->handle.showmemhandle);\r
1314 \r
1315         close(gvar->ca.file.maphandle);\r
1316         close(gvar->ca.file.grhandle);\r
1317         close(gvar->ca.file.audiohandle);\r
1318 }\r
1319 \r
1320 //===========================================================================\r
1321 \r
1322 /*\r
1323 ======================\r
1324 =\r
1325 = CA_CacheAudioChunk\r
1326 =\r
1327 ======================\r
1328 */\r
1329 /*++++\r
1330 void CA_CacheAudioChunk (int chunk)\r
1331 {\r
1332         long    pos,compressed;\r
1333 #ifdef AUDIOHEADERLINKED\r
1334         long    expanded;\r
1335         memptr  bigbufferseg;\r
1336         byte    far *source;\r
1337 #endif\r
1338 \r
1339         if (audiosegs[chunk])\r
1340         {\r
1341                 MM_SetPurge (MEMPTRCONV audiosegs[chunk],0);\r
1342                 return;                                                 // allready in memory\r
1343         }\r
1344 \r
1345 // MDM begin - (GAMERS EDGE)\r
1346 //\r
1347         if (!FindFile("AUDIO.16",NULL,2))\r
1348                 Quit (gvar, "CA_CacheAudioChunk(): Can't find audio files.");\r
1349 //\r
1350 // MDM end\r
1351 \r
1352 //\r
1353 // load the chunk into a buffer, either the miscbuffer if it fits, or allocate\r
1354 // a larger buffer\r
1355 //\r
1356         pos = audiostarts[chunk];\r
1357         compressed = audiostarts[chunk+1]-pos;\r
1358 \r
1359         lseek(audiohandle,pos,SEEK_SET);\r
1360 \r
1361 #ifndef AUDIOHEADERLINKED\r
1362 \r
1363         MM_GetPtr (MEMPTRCONV audiosegs[chunk],compressed);\r
1364         if (mmerror)\r
1365                 return;\r
1366 \r
1367         CA_FarRead(audiohandle,audiosegs[chunk],compressed);\r
1368 \r
1369 #else\r
1370 \r
1371         if (compressed<=BUFFERSIZE)\r
1372         {\r
1373                 CA_FarRead(audiohandle,bufferseg,compressed);\r
1374                 source = bufferseg;\r
1375         }\r
1376         else\r
1377         {\r
1378                 MM_GetPtr(&bigbufferseg,compressed);\r
1379                 if (mmerror)\r
1380                         return;\r
1381                 MM_SetLock (&bigbufferseg,true);\r
1382                 CA_FarRead(audiohandle,bigbufferseg,compressed);\r
1383                 source = bigbufferseg;\r
1384         }\r
1385 \r
1386         expanded = *(long far *)source;\r
1387         source += 4;                    // skip over length\r
1388         MM_GetPtr (MEMPTRCONV audiosegs[chunk],expanded);\r
1389         if (mmerror)\r
1390                 goto done;\r
1391         CAL_HuffExpand (source,audiosegs[chunk],expanded,audiohuffman);\r
1392 \r
1393 done:\r
1394         if (compressed>BUFFERSIZE)\r
1395                 MM_FreePtr(&bigbufferseg);\r
1396 #endif\r
1397 }*/\r
1398 \r
1399 //===========================================================================\r
1400 \r
1401 /*\r
1402 ======================\r
1403 =\r
1404 = CA_LoadAllSounds\r
1405 =\r
1406 = Purges all sounds, then loads all new ones (mode switch)\r
1407 =\r
1408 ======================\r
1409 */\r
1410 /*++++\r
1411 void CA_LoadAllSounds (void)\r
1412 {\r
1413         unsigned        start,i;\r
1414 \r
1415         switch (oldsoundmode)\r
1416         {\r
1417         case sdm_Off:\r
1418                 goto cachein;\r
1419         case sdm_PC:\r
1420                 start = STARTPCSOUNDS;\r
1421                 break;\r
1422         case sdm_AdLib:\r
1423                 start = STARTADLIBSOUNDS;\r
1424                 break;\r
1425         }\r
1426 \r
1427         for (i=0;i<NUMSOUNDS;i++,start++)\r
1428                 if (audiosegs[start])\r
1429                         MM_SetPurge (MEMPTRCONV audiosegs[start],3);            // make purgable\r
1430 \r
1431 cachein:\r
1432 \r
1433         switch (SoundMode)\r
1434         {\r
1435         case sdm_Off:\r
1436                 return;\r
1437         case sdm_PC:\r
1438                 start = STARTPCSOUNDS;\r
1439                 break;\r
1440         case sdm_AdLib:\r
1441                 start = STARTADLIBSOUNDS;\r
1442                 break;\r
1443         }\r
1444 \r
1445         for (i=0;i<NUMSOUNDS;i++,start++)\r
1446                 CA_CacheAudioChunk (start);\r
1447 \r
1448         oldsoundmode = SoundMode;\r
1449 }*/\r
1450 \r
1451 //===========================================================================\r
1452 \r
1453 //????#if GRMODE == EGAGR\r
1454 #if 0\r
1455 \r
1456 /*\r
1457 ======================\r
1458 =\r
1459 = CAL_ShiftSprite\r
1460 =\r
1461 = Make a shifted (one byte wider) copy of a sprite into another area\r
1462 =\r
1463 ======================\r
1464 */\r
1465 \r
1466 unsigned        static  sheight,swidth;\r
1467 boolean static dothemask;\r
1468 \r
1469 void CAL_ShiftSprite (unsigned segment,unsigned source,unsigned dest,\r
1470         unsigned width, unsigned height, unsigned pixshift, boolean domask)\r
1471 {\r
1472 \r
1473         sheight = height;               // because we are going to reassign bp\r
1474         swidth = width;\r
1475         dothemask = domask;\r
1476 \r
1477         __asm {\r
1478                 mov     ax,[segment]\r
1479                 mov     ds,ax           // source and dest are in same segment, and all local\r
1480 \r
1481                 mov     bx,[source]\r
1482                 mov     di,[dest]\r
1483 \r
1484                 mov     bp,[pixshift]\r
1485                 shl     bp,1\r
1486                 mov     bp,WORD PTR [shifttabletable+bp]        // bp holds pointer to shift table\r
1487 \r
1488                 cmp     [ss:dothemask],0\r
1489                 je              skipmask\r
1490 \r
1491 //\r
1492 // table shift the mask\r
1493 //\r
1494                 mov     dx,[ss:sheight]\r
1495 #ifdef __BORLANDC__\r
1496         }\r
1497 #endif\r
1498 domaskrow:\r
1499 #ifdef __BORLANDC__\r
1500         __asm {\r
1501 #endif\r
1502                 mov     BYTE PTR [di],255       // 0xff first byte\r
1503                 mov     cx,ss:[swidth]\r
1504 #ifdef __BORLANDC__\r
1505         }\r
1506 #endif\r
1507 domaskbyte:\r
1508 #ifdef __BORLANDC__\r
1509         __asm {\r
1510 #endif\r
1511                 mov     al,[bx]                         // source\r
1512                 not     al\r
1513                 inc     bx                                      // next source byte\r
1514                 xor     ah,ah\r
1515                 shl     ax,1\r
1516                 mov     si,ax\r
1517                 mov     ax,[bp+si]                      // table shift into two bytes\r
1518                 not     ax\r
1519                 and     [di],al                         // and with first byte\r
1520                 inc     di\r
1521                 mov     [di],ah                         // replace next byte\r
1522 \r
1523                 loop    domaskbyte\r
1524 \r
1525                 inc     di                                      // the last shifted byte has 1s in it\r
1526                 dec     dx\r
1527                 jnz     domaskrow\r
1528 #ifdef __BORLANDC__\r
1529         }\r
1530 #endif\r
1531 skipmask:\r
1532 #ifdef __BORLANDC__\r
1533         __asm {\r
1534 #endif\r
1535 //\r
1536 // table shift the data\r
1537 //\r
1538                 mov     dx,ss:[sheight]\r
1539                 shl     dx,1\r
1540                 shl     dx,1                            // four planes of data\r
1541 #ifdef __BORLANDC__\r
1542         }\r
1543 #endif\r
1544 dodatarow:\r
1545 #ifdef __BORLANDC__\r
1546         __asm {\r
1547 #endif\r
1548                 mov     BYTE PTR [di],0         // 0 first byte\r
1549                 mov     cx,ss:[swidth]\r
1550 #ifdef __BORLANDC__\r
1551         }\r
1552 #endif\r
1553 dodatabyte:\r
1554 #ifdef __BORLANDC__\r
1555         __asm {\r
1556 #endif\r
1557                 mov     al,[bx]                         // source\r
1558                 inc     bx                                      // next source byte\r
1559                 xor     ah,ah\r
1560                 shl     ax,1\r
1561                 mov     si,ax\r
1562                 mov     ax,[bp+si]                      // table shift into two bytes\r
1563                 or      [di],al                         // or with first byte\r
1564                 inc     di\r
1565                 mov     [di],ah                         // replace next byte\r
1566 \r
1567                 loop    dodatabyte\r
1568 \r
1569                 inc     di                                      // the last shifted byte has 0s in it\r
1570                 dec     dx\r
1571                 jnz     dodatarow\r
1572 \r
1573 //\r
1574 // done\r
1575 //\r
1576 \r
1577                 mov     ax,ss                           // restore data segment\r
1578                 mov     ds,ax\r
1579         }\r
1580 \r
1581 }\r
1582 \r
1583 #endif\r
1584 \r
1585 //===========================================================================\r
1586 \r
1587 /*\r
1588 ======================\r
1589 =\r
1590 = CAL_CacheSprite\r
1591 =\r
1592 = Generate shifts and set up sprite structure for a given sprite\r
1593 =\r
1594 ======================\r
1595 */\r
1596 /*++++\r
1597 void CAL_CacheSprite (int chunk, byte far *compressed)\r
1598 {\r
1599         int i;\r
1600         unsigned shiftstarts[5];\r
1601         unsigned smallplane,bigplane,expanded;\r
1602         spritetabletype far *spr;\r
1603         spritetype _seg *dest;\r
1604 \r
1605 #if GRMODE == CGAGR\r
1606 //\r
1607 // CGA has no pel panning, so shifts are never needed\r
1608 //\r
1609         spr = &spritetable[chunk-STARTSPRITES];\r
1610         smallplane = spr->width*spr->height;\r
1611         MM_GetPtr (&grsegs[chunk],smallplane*2+MAXSHIFTS*6);\r
1612         if (mmerror)\r
1613                 return;\r
1614         dest = (spritetype _seg *)grsegs[chunk];\r
1615         dest->sourceoffset[0] = MAXSHIFTS*6;    // start data after 3 unsigned tables\r
1616         dest->planesize[0] = smallplane;\r
1617         dest->width[0] = spr->width;\r
1618 \r
1619 //\r
1620 // expand the unshifted shape\r
1621 //\r
1622         CAL_HuffExpand (compressed, &dest->data[0],smallplane*2,gvar->ca.grhuffman);\r
1623 \r
1624 #endif\r
1625 \r
1626 \r
1627 #if GRMODE == EGAGR\r
1628 \r
1629 //\r
1630 // calculate sizes\r
1631 //\r
1632         spr = &spritetable[chunk-STARTSPRITES];\r
1633         smallplane = spr->width*spr->height;\r
1634         bigplane = (spr->width+1)*spr->height;\r
1635 \r
1636         shiftstarts[0] = MAXSHIFTS*6;   // start data after 3 unsigned tables\r
1637         shiftstarts[1] = shiftstarts[0] + smallplane*5; // 5 planes in a sprite\r
1638         shiftstarts[2] = shiftstarts[1] + bigplane*5;\r
1639         shiftstarts[3] = shiftstarts[2] + bigplane*5;\r
1640         shiftstarts[4] = shiftstarts[3] + bigplane*5;   // nothing ever put here\r
1641 \r
1642         expanded = shiftstarts[spr->shifts];\r
1643         MM_GetPtr (&grsegs[chunk],expanded);\r
1644         if (mmerror)\r
1645                 return;\r
1646         dest = (spritetype _seg *)grsegs[chunk];\r
1647 \r
1648 //\r
1649 // expand the unshifted shape\r
1650 //\r
1651         CAL_HuffExpand (compressed, &dest->data[0],smallplane*5,gvar->ca.grhuffman);\r
1652 \r
1653 //\r
1654 // make the shifts!\r
1655 //\r
1656         switch (spr->shifts)\r
1657         {\r
1658         case    1:\r
1659                 for (i=0;i<4;i++)\r
1660                 {\r
1661                         dest->sourceoffset[i] = shiftstarts[0];\r
1662                         dest->planesize[i] = smallplane;\r
1663                         dest->width[i] = spr->width;\r
1664                 }\r
1665                 break;\r
1666 \r
1667         case    2:\r
1668                 for (i=0;i<2;i++)\r
1669                 {\r
1670                         dest->sourceoffset[i] = shiftstarts[0];\r
1671                         dest->planesize[i] = smallplane;\r
1672                         dest->width[i] = spr->width;\r
1673                 }\r
1674                 for (i=2;i<4;i++)\r
1675                 {\r
1676                         dest->sourceoffset[i] = shiftstarts[1];\r
1677                         dest->planesize[i] = bigplane;\r
1678                         dest->width[i] = spr->width+1;\r
1679                 }\r
1680                 CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0],\r
1681                         dest->sourceoffset[2],spr->width,spr->height,4,true);\r
1682                 break;\r
1683 \r
1684         case    4:\r
1685                 dest->sourceoffset[0] = shiftstarts[0];\r
1686                 dest->planesize[0] = smallplane;\r
1687                 dest->width[0] = spr->width;\r
1688 \r
1689                 dest->sourceoffset[1] = shiftstarts[1];\r
1690                 dest->planesize[1] = bigplane;\r
1691                 dest->width[1] = spr->width+1;\r
1692                 CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0],\r
1693                         dest->sourceoffset[1],spr->width,spr->height,2,true);\r
1694 \r
1695                 dest->sourceoffset[2] = shiftstarts[2];\r
1696                 dest->planesize[2] = bigplane;\r
1697                 dest->width[2] = spr->width+1;\r
1698                 CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0],\r
1699                         dest->sourceoffset[2],spr->width,spr->height,4,true);\r
1700 \r
1701                 dest->sourceoffset[3] = shiftstarts[3];\r
1702                 dest->planesize[3] = bigplane;\r
1703                 dest->width[3] = spr->width+1;\r
1704                 CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0],\r
1705                         dest->sourceoffset[3],spr->width,spr->height,6,true);\r
1706 \r
1707                 break;\r
1708 \r
1709         default:\r
1710                 Quit (gvar, "CAL_CacheSprite: Bad shifts number!");\r
1711         }\r
1712 \r
1713 #endif\r
1714 }*/\r
1715 \r
1716 //===========================================================================\r
1717 \r
1718 \r
1719 /*\r
1720 ======================\r
1721 =\r
1722 = CAL_ExpandGrChunk\r
1723 =\r
1724 = Does whatever is needed with a pointer to a compressed chunk\r
1725 =\r
1726 ======================\r
1727 */\r
1728 /*++++\r
1729 void CAL_ExpandGrChunk (int chunk, byte far *source)\r
1730 {\r
1731         long    expanded;\r
1732 \r
1733 \r
1734         if (chunk >= STARTTILE8 && chunk < STARTEXTERNS)\r
1735         {\r
1736         //\r
1737         // expanded sizes of tile8/16/32 are implicit\r
1738         //\r
1739 \r
1740 #if GRMODE == EGAGR\r
1741 #define BLOCK           32\r
1742 #define MASKBLOCK       40\r
1743 #endif\r
1744 \r
1745 #if GRMODE == CGAGR\r
1746 #define BLOCK           16\r
1747 #define MASKBLOCK       32\r
1748 #endif\r
1749 \r
1750                 if (chunk<STARTTILE8M)                  // tile 8s are all in one chunk!\r
1751                         expanded = BLOCK*NUMTILE8;\r
1752                 else if (chunk<STARTTILE16)\r
1753                         expanded = MASKBLOCK*NUMTILE8M;\r
1754                 else if (chunk<STARTTILE16M)    // all other tiles are one/chunk\r
1755                         expanded = BLOCK*4;\r
1756                 else if (chunk<STARTTILE32)\r
1757                         expanded = MASKBLOCK*4;\r
1758                 else if (chunk<STARTTILE32M)\r
1759                         expanded = BLOCK*16;\r
1760                 else\r
1761                         expanded = MASKBLOCK*16;\r
1762         }\r
1763         else\r
1764         {\r
1765         //\r
1766         // everything else has an explicit size longword\r
1767         //\r
1768                 expanded = *(long far *)source;\r
1769                 source += 4;                    // skip over length\r
1770         }\r
1771 \r
1772 //\r
1773 // allocate final space, decompress it, and free bigbuffer\r
1774 // Sprites need to have shifts made and various other junk\r
1775 //\r
1776         if (chunk>=STARTSPRITES && chunk< STARTTILE8)\r
1777                 CAL_CacheSprite(chunk,source);\r
1778         else\r
1779         {\r
1780                 MM_GetPtr (&grsegs[chunk],expanded);\r
1781                 if (mmerror)\r
1782                         return;\r
1783                 CAL_HuffExpand (source,grsegs[chunk],expanded,gvar->ca.grhuffman);\r
1784         }\r
1785 }\r
1786 */\r
1787 \r
1788 /*\r
1789 ======================\r
1790 =\r
1791 = CAL_ReadGrChunk\r
1792 =\r
1793 = Gets a chunk off disk, optimizing reads to general buffer\r
1794 =\r
1795 ======================\r
1796 */\r
1797 /*++++\r
1798 void CAL_ReadGrChunk (int chunk)\r
1799 {\r
1800         long    pos,compressed;\r
1801         memptr  bigbufferseg;\r
1802         byte    far *source;\r
1803         int             next;\r
1804 \r
1805 //\r
1806 // load the chunk into a buffer, either the miscbuffer if it fits, or allocate\r
1807 // a larger buffer\r
1808 //\r
1809         pos = GRFILEPOS(chunk,gvar);\r
1810         if (pos<0)                                                      // $FFFFFFFF start is a sparse tile\r
1811           return;\r
1812 \r
1813         next = chunk +1;\r
1814         while (GRFILEPOS(next,gvar) == -1)              // skip past any sparse tiles\r
1815                 next++;\r
1816 \r
1817         compressed = GRFILEPOS(next,gvar)-pos;\r
1818 \r
1819         lseek(gvar->ca.file.grhandle,pos,SEEK_SET);\r
1820 \r
1821         if (compressed<=BUFFERSIZE)\r
1822         {\r
1823                 CA_FarRead(gvar->ca.file.grhandle,bufferseg,compressed);\r
1824                 source = bufferseg;\r
1825         }\r
1826         else\r
1827         {\r
1828                 MM_GetPtr(&bigbufferseg,compressed);\r
1829                 if (mmerror)\r
1830                         return;\r
1831                 MM_SetLock (&bigbufferseg,true);\r
1832                 CA_FarRead(gvar->ca.file.grhandle,bigbufferseg,compressed);\r
1833                 source = bigbufferseg;\r
1834         }\r
1835 \r
1836         CAL_ExpandGrChunk (chunk,source);\r
1837 \r
1838         if (compressed>BUFFERSIZE)\r
1839                 MM_FreePtr(&bigbufferseg);\r
1840 }\r
1841 */\r
1842 /*\r
1843 ======================\r
1844 =\r
1845 = CA_CacheGrChunk\r
1846 =\r
1847 = Makes sure a given chunk is in memory, loadiing it if needed\r
1848 =\r
1849 ======================\r
1850 */\r
1851 /*++++\r
1852 void CA_CacheGrChunk (int chunk)\r
1853 {\r
1854         long    pos,compressed;\r
1855         memptr  bigbufferseg;\r
1856         byte    far *source;\r
1857         int             next;\r
1858 \r
1859         gvar->ca.grneeded[chunk] |= ca_levelbit;                // make sure it doesn't get removed\r
1860         if (grsegs[chunk])\r
1861         {\r
1862                 MM_SetPurge (&grsegs[chunk],0);\r
1863                 return;                                                 // allready in memory\r
1864         }\r
1865 \r
1866 // MDM begin - (GAMERS EDGE)\r
1867 //\r
1868         if (!FindFile("EGAGRAPH.16",NULL,2))\r
1869                 Quit (gvar, "CA_CacheGrChunk(): Can't find graphics files.");\r
1870 //\r
1871 // MDM end\r
1872 \r
1873 //\r
1874 // load the chunk into a buffer, either the miscbuffer if it fits, or allocate\r
1875 // a larger buffer\r
1876 //\r
1877         pos = GRFILEPOS(chunk,gvar);\r
1878         if (pos<0)                                                      // $FFFFFFFF start is a sparse tile\r
1879           return;\r
1880 \r
1881         next = chunk +1;\r
1882         while (GRFILEPOS(next) == -1)           // skip past any sparse tiles\r
1883                 next++;\r
1884 \r
1885         compressed = GRFILEPOS(next,gvar)-pos;\r
1886 \r
1887         lseek(gvar->ca.file.grhandle,pos,SEEK_SET);\r
1888 \r
1889         if (compressed<=BUFFERSIZE)\r
1890         {\r
1891                 CA_FarRead(gvar->ca.file.grhandle,bufferseg,compressed);\r
1892                 source = bufferseg;\r
1893         }\r
1894         else\r
1895         {\r
1896                 MM_GetPtr(&bigbufferseg,compressed);\r
1897                 MM_SetLock (&bigbufferseg,true);\r
1898                 CA_FarRead(gvar->ca.file.grhandle,bigbufferseg,compressed);\r
1899                 source = bigbufferseg;\r
1900         }\r
1901 \r
1902         CAL_ExpandGrChunk (chunk,source);\r
1903 \r
1904         if (compressed>BUFFERSIZE)\r
1905                 MM_FreePtr(&bigbufferseg);\r
1906 }\r
1907 */\r
1908 \r
1909 \r
1910 //==========================================================================\r
1911 \r
1912 /*\r
1913 ======================\r
1914 =\r
1915 = CA_CacheMap\r
1916 =\r
1917 ======================\r
1918 */\r
1919 /*++++ segments!\r
1920 void CA_CacheMap (global_game_variables_t *gvar)\r
1921 {\r
1922         long    pos,compressed;\r
1923         int             plane;\r
1924         memptr  *dest,bigbufferseg;\r
1925         unsigned        size;\r
1926         unsigned        far     *source;\r
1927 #ifdef MAPHEADERLINKED\r
1928         memptr  buffer2seg;\r
1929         long    expanded;\r
1930 #endif\r
1931 \r
1932 \r
1933 //\r
1934 // free up memory from last map\r
1935 //\r
1936         if (gvar->ca.camap.mapon>-1 && gvar->ca.camap.mapheaderseg[gvar->ca.camap.mapon])\r
1937                 MM_SetPurge (((memptr)gvar->ca.camap.mapheaderseg[(gvar->ca.camap.mapon)]), 3, gvar);\r
1938         for (plane=0;plane<MAPPLANES;plane++)\r
1939                 if (gvar->ca.camap.mapsegs[plane])\r
1940                         MM_FreePtr ((memptr)gvar->ca.camap.mapsegs[plane], gvar);\r
1941 \r
1942         gvar->ca.camap.mapon = gvar->ca.camap.mapnum;\r
1943 \r
1944 \r
1945 //\r
1946 // load map header\r
1947 // The header will be cached if it is still around\r
1948 //\r
1949 //      if (!gvar->ca.camap.mapheaderseg[gvar->ca.camap.mapnum])\r
1950 //      {\r
1951 //              //pos = ((mapfiletype   _seg *)tinf)->headeroffsets[mapnum];\r
1952 //              //pos = ((_seg *)gvar->ca.camap.tinf)->headeroffsets[gvar->ca.camap.mapnum];\r
1953 //              pos = ((memptr)gvar->ca.camap.tinf)->headeroffsets[gvar->ca.camap.mapnum];\r
1954 //              if (pos<0)                                              // $FFFFFFFF start is a sparse map\r
1955 //                printf("CA_CacheMap: Tried to load a non existent map!");\r
1956 \r
1957 //              MM_GetPtr(MEMPTRCONV gvar->ca.camapheaderseg[mapnum],sizeof(maptype));\r
1958 //              lseek(maphandle,pos,SEEK_SET);\r
1959 //              CA_FarRead (maphandle,(memptr)mapheaderseg[mapnum],sizeof(maptype));\r
1960 //      }\r
1961 //      else\r
1962 //              MM_SetPurge (MEMPTRCONV mapheaderseg[mapnum], 0, &(gvar->mm));\r
1963 \r
1964 //\r
1965 // load the planes in\r
1966 // If a plane's pointer still exists it will be overwritten (levels are\r
1967 // allways reloaded, never cached)\r
1968 //\r
1969 \r
1970         size = mapheaderseg[mapnum]->width * mapheaderseg[mapnum]->height * 2;\r
1971 \r
1972         for (plane = 0; plane<MAPPLANES; plane++)\r
1973         {\r
1974                 //pos = mapheaderseg[mapnum]->planestart[plane];\r
1975                 //compressed = mapheaderseg[mapnum]->planelength[plane];\r
1976 \r
1977                 if (!compressed)\r
1978                         continue;               // the plane is not used in this game\r
1979 \r
1980                 dest = MEMPTRCONV mapsegs[plane];\r
1981                 MM_GetPtr(dest,size);\r
1982 \r
1983                 lseek(maphandle,pos,SEEK_SET);\r
1984                 if (compressed<=BUFFERSIZE)\r
1985                         source = bufferseg;\r
1986                 else\r
1987                 {\r
1988                         MM_GetPtr(&bigbufferseg,compressed);\r
1989                         MM_SetLock (&bigbufferseg,true);\r
1990                         source = bigbufferseg;\r
1991                 }\r
1992 \r
1993                 CA_FarRead(maphandle,(byte far *)source,compressed);\r
1994 #ifdef MAPHEADERLINKED\r
1995                 //\r
1996                 // unhuffman, then unRLEW\r
1997                 // The huffman'd chunk has a two byte expanded length first\r
1998                 // The resulting RLEW chunk also does, even though it's not really\r
1999                 // needed\r
2000                 //\r
2001                 expanded = *source;\r
2002                 source++;\r
2003                 MM_GetPtr (&buffer2seg,expanded);\r
2004                 CAL_CarmackExpand (source, (unsigned far *)buffer2seg,expanded);\r
2005                 CA_RLEWexpand (((unsigned far *)buffer2seg)+1,*dest,size,\r
2006                 ((mapfiletype _seg *)tinf)->RLEWtag);\r
2007                 MM_FreePtr (&buffer2seg);\r
2008 \r
2009 #else\r
2010                 //\r
2011                 // unRLEW, skipping expanded length\r
2012                 //\r
2013                 CA_RLEWexpand (source+1, *dest,size,\r
2014                 ((mapfiletype _seg *)tinf)->RLEWtag);\r
2015 #endif\r
2016 \r
2017                 if (compressed>BUFFERSIZE)\r
2018                         MM_FreePtr(&bigbufferseg);\r
2019         }\r
2020 }//*/\r
2021 \r
2022 //===========================================================================\r
2023 \r
2024 /*\r
2025 ======================\r
2026 =\r
2027 = CA_UpLevel\r
2028 =\r
2029 = Goes up a bit level in the needed lists and clears it out.\r
2030 = Everything is made purgable\r
2031 =\r
2032 ======================\r
2033 */\r
2034 \r
2035 void CA_UpLevel (global_game_variables_t *gvar)\r
2036 {\r
2037         if (gvar->ca.ca_levelnum==7)\r
2038                 printf("CA_UpLevel: Up past level 7!");\r
2039 \r
2040         gvar->ca.ca_levelbit<<=1;\r
2041         gvar->ca.ca_levelnum++;\r
2042 }\r
2043 \r
2044 //===========================================================================\r
2045 \r
2046 /*\r
2047 ======================\r
2048 =\r
2049 = CA_DownLevel\r
2050 =\r
2051 = Goes down a bit level in the needed lists and recaches\r
2052 = everything from the lower level\r
2053 =\r
2054 ======================\r
2055 */\r
2056 \r
2057 void CA_DownLevel (global_game_variables_t *gvar)\r
2058 {\r
2059         if (!gvar->ca.ca_levelnum)\r
2060                 printf("CA_DownLevel: Down past level 0!");\r
2061         gvar->ca.ca_levelbit>>=1;\r
2062         gvar->ca.ca_levelnum--;\r
2063         ////++++++++++++++++++++++++++++++++++++++++++CA_CacheMarks(NULL);\r
2064 }\r
2065 \r
2066 //===========================================================================\r
2067 \r
2068 /*\r
2069 ======================\r
2070 =\r
2071 = CA_ClearMarks\r
2072 =\r
2073 = Clears out all the marks at the current level\r
2074 =\r
2075 ======================\r
2076 */\r
2077 \r
2078 void CA_ClearMarks (global_game_variables_t *gvar)\r
2079 {\r
2080         int i;\r
2081 \r
2082         for (i=0;i<NUMCHUNKS;i++)\r
2083                 gvar->ca.grneeded[i]&=~gvar->ca.ca_levelbit;\r
2084 }\r
2085 \r
2086 //===========================================================================\r
2087 \r
2088 /*\r
2089 ======================\r
2090 =\r
2091 = CA_ClearAllMarks\r
2092 =\r
2093 = Clears out all the marks on all the levels\r
2094 =\r
2095 ======================\r
2096 */\r
2097 \r
2098 void CA_ClearAllMarks (global_game_variables_t *gvar)\r
2099 {\r
2100         _fmemset (gvar->ca.grneeded,0,sizeof(gvar->ca.grneeded));\r
2101         gvar->ca.ca_levelbit = 1;\r
2102         gvar->ca.ca_levelnum = 0;\r
2103 }\r
2104 \r
2105 //===========================================================================\r
2106 \r
2107 /*\r
2108 ======================\r
2109 =\r
2110 = CA_FreeGraphics\r
2111 =\r
2112 ======================\r
2113 */\r
2114 \r
2115 void CA_SetGrPurge (global_game_variables_t *gvar)\r
2116 {\r
2117         int i;\r
2118 \r
2119 //\r
2120 // free graphics\r
2121 //\r
2122         CA_ClearMarks (gvar);\r
2123 \r
2124         for (i=0;i<NUMCHUNKS;i++)\r
2125                 if (gvar->ca.grsegs[i])\r
2126                         MM_SetPurge (gvar->ca.grsegs[i],3, gvar);\r
2127 }\r
2128 \r
2129 \r
2130 /*\r
2131 ======================\r
2132 =\r
2133 = CA_SetAllPurge\r
2134 =\r
2135 = Make everything possible purgable\r
2136 =\r
2137 ======================\r
2138 */\r
2139 \r
2140 void CA_SetAllPurge (global_game_variables_t *gvar)\r
2141 {\r
2142         int i;\r
2143 \r
2144         CA_ClearMarks (gvar);\r
2145 \r
2146 //\r
2147 // free cursor sprite and background save\r
2148 //\r
2149         //____VW_FreeCursor ();\r
2150 \r
2151 //\r
2152 // free map headers and map planes\r
2153 //\r
2154 //      for (i=0;i<NUMMAPS;i++)\r
2155 //              if (gvar->ca.camap.mapheaderseg[i])\r
2156 //                      MM_SetPurge (gvar->ca.camap.mapheaderseg[i],3, gvar);\r
2157 \r
2158         for (i=0;i<3;i++)\r
2159                 if (gvar->ca.mapsegs[i])\r
2160                         MM_FreePtr ((memptr *)&gvar->ca.mapsegs[i], gvar);\r
2161 \r
2162 //\r
2163 // free sounds\r
2164 //\r
2165         for (i=0;i<NUMSNDCHUNKS;i++)\r
2166                 if (gvar->ca.audiosegs[i])\r
2167                         MM_SetPurge ((memptr *)&gvar->ca.audiosegs[i],3, gvar);\r
2168 \r
2169 //\r
2170 // free graphics\r
2171 //\r
2172         CA_SetGrPurge (gvar);\r
2173 }\r
2174 \r
2175 \r
2176 //===========================================================================\r
2177 \r
2178 \r
2179 /*\r
2180 ======================\r
2181 =\r
2182 = CAL_DialogDraw\r
2183 =\r
2184 ======================\r
2185 */\r
2186 /*\r
2187 #define NUMBARS (17l*8)\r
2188 #define BARSTEP 8\r
2189 \r
2190 unsigned        thx,thy,lastx;\r
2191 long            barx,barstep;\r
2192 \r
2193 void    CAL_DialogDraw (char *title,unsigned numcache)\r
2194 {\r
2195         unsigned        homex,homey,x;\r
2196 \r
2197         barstep = (NUMBARS<<16)/numcache;\r
2198 \r
2199 //\r
2200 // draw dialog window (masked tiles 12 - 20 are window borders)\r
2201 //\r
2202         US_CenterWindow (20,8);\r
2203         homex = PrintX;\r
2204         homey = PrintY;\r
2205 \r
2206         US_CPrint ("Loading");\r
2207         fontcolor = F_SECONDCOLOR;\r
2208         US_CPrint (title);\r
2209         fontcolor = F_BLACK;\r
2210 \r
2211 //\r
2212 // draw thermometer bar\r
2213 //\r
2214         thx = homex + 8;\r
2215         thy = homey + 32;\r
2216         VWB_DrawTile8(thx,thy,0);               // CAT3D numbers\r
2217         VWB_DrawTile8(thx,thy+8,3);\r
2218         VWB_DrawTile8(thx,thy+16,6);\r
2219         VWB_DrawTile8(thx+17*8,thy,2);\r
2220         VWB_DrawTile8(thx+17*8,thy+8,5);\r
2221         VWB_DrawTile8(thx+17*8,thy+16,8);\r
2222         for (x=thx+8;x<thx+17*8;x+=8)\r
2223         {\r
2224                 VWB_DrawTile8(x,thy,1);\r
2225                 VWB_DrawTile8(x,thy+8,4);\r
2226                 VWB_DrawTile8(x,thy+16,7);\r
2227         }\r
2228 \r
2229         thx += 4;               // first line location\r
2230         thy += 5;\r
2231         barx = (long)thx<<16;\r
2232         lastx = thx;\r
2233 \r
2234         VW_UpdateScreen();\r
2235 }\r
2236 */\r
2237 \r
2238 /*\r
2239 ======================\r
2240 =\r
2241 = CAL_DialogUpdate\r
2242 =\r
2243 ======================\r
2244 */\r
2245 /*\r
2246 void    CAL_DialogUpdate (void)\r
2247 {\r
2248         unsigned        x,xh;\r
2249 \r
2250         barx+=barstep;\r
2251         xh = barx>>16;\r
2252         if (xh - lastx > BARSTEP)\r
2253         {\r
2254                 for (x=lastx;x<=xh;x++)\r
2255 #if GRMODE == EGAGR\r
2256                         VWB_Vlin (thy,thy+13,x,14);\r
2257 #endif\r
2258 #if GRMODE == CGAGR\r
2259                         VWB_Vlin (thy,thy+13,x,SECONDCOLOR);\r
2260 #endif\r
2261                 lastx = xh;\r
2262                 VW_UpdateScreen();\r
2263         }\r
2264 }*/\r
2265 \r
2266 /*\r
2267 ======================\r
2268 =\r
2269 = CAL_DialogFinish\r
2270 =\r
2271 ======================\r
2272 */\r
2273 /*\r
2274 void    CAL_DialogFinish (void)\r
2275 {\r
2276         unsigned        x,xh;\r
2277 \r
2278         xh = thx + NUMBARS;\r
2279         for (x=lastx;x<=xh;x++)\r
2280 #if GRMODE == EGAGR\r
2281                 VWB_Vlin (thy,thy+13,x,14);\r
2282 #endif\r
2283 #if GRMODE == CGAGR\r
2284                 VWB_Vlin (thy,thy+13,x,SECONDCOLOR);\r
2285 #endif\r
2286         VW_UpdateScreen();\r
2287 \r
2288 }*/\r
2289 \r
2290 //===========================================================================\r
2291 \r
2292 /*\r
2293 ======================\r
2294 =\r
2295 = CA_CacheMarks\r
2296 =\r
2297 ======================\r
2298 *//*++++\r
2299 #define MAXEMPTYREAD    1024\r
2300 \r
2301 void CAL_CacheMarks (char *title, global_game_variables_t *gvar)\r
2302 {\r
2303         boolean dialog;\r
2304         int     i,next,numcache;\r
2305         long    pos,endpos,nextpos,nextendpos,compressed;\r
2306         long    bufferstart,bufferend;  // file position of general buffer\r
2307         byte    far *source;\r
2308         memptr  bigbufferseg;\r
2309 \r
2310         dialog = (title!=NULL);\r
2311 \r
2312         numcache = 0;\r
2313 //\r
2314 // go through and make everything not needed purgable\r
2315 //\r
2316         for (i=0;i<NUMCHUNKS;i++)\r
2317                 if (gvar->ca.grneeded[i]&(gvar->ca.ca_levelbit))//if (grneeded[i]&ca_levelbit)\r
2318                 {\r
2319                         if (gvar->ca.grsegs[i])                                 // its allready in memory, make\r
2320                                 MM_SetPurge(gvar->ca.grsegs[i],0,gvar); // sure it stays there!\r
2321                         else\r
2322                                 numcache++;\r
2323                 }\r
2324                 else\r
2325                 {\r
2326                         if (gvar->ca.grsegs[i])                                 // not needed, so make it purgeable\r
2327                                 MM_SetPurge(gvar->ca.grsegs[i],3,gvar);\r
2328                 }\r
2329 \r
2330         if (!numcache)                  // nothing to cache!\r
2331                 return;\r
2332 \r
2333 // MDM begin - (GAMERS EDGE)\r
2334 //\r
2335 //      if (!FindFile("EGAGRAPH.16",NULL,2))\r
2336 //              Quit (gvar, "CA_CacheMarks(): Can't find graphics files.");\r
2337 //\r
2338 // MDM end\r
2339 \r
2340         if (dialog)\r
2341         {\r
2342 #ifdef PROFILE\r
2343                 write(profilehandle,title,strlen(title));\r
2344                 write(profilehandle,"\n",1);\r
2345 #endif\r
2346                 if (drawcachebox)\r
2347                         drawcachebox(title,numcache);\r
2348         }\r
2349 \r
2350 //\r
2351 // go through and load in anything still needed\r
2352 //\r
2353         bufferstart = bufferend = 0;            // nothing good in buffer now\r
2354 \r
2355         for (i=0;i<NUMCHUNKS;i++)\r
2356                 if ( (gvar->ca.grneeded[i]&(gvar->ca.ca_levelbit)) && !gvar->ca.grsegs[i])\r
2357                 {\r
2358 //\r
2359 // update thermometer\r
2360 //\r
2361                         if (dialog && updatecachebox)\r
2362                                 updatecachebox ();\r
2363 \r
2364                         pos = GRFILEPOS(i,gvar);\r
2365                         if (pos<0)\r
2366                                 continue;\r
2367 \r
2368                         next = i +1;\r
2369                         while (GRFILEPOS(next) == -1)           // skip past any sparse tiles\r
2370                                 next++;\r
2371 \r
2372                         compressed = GRFILEPOS(next,gvar)-pos;\r
2373                         endpos = pos+compressed;\r
2374 \r
2375                         if (compressed<=BUFFERSIZE)\r
2376                         {\r
2377                                 if (bufferstart<=pos\r
2378                                 && bufferend>= endpos)\r
2379                                 {\r
2380                                 // data is allready in buffer\r
2381                                         source = (byte _seg *)bufferseg+(pos-bufferstart);\r
2382                                 }\r
2383                                 else\r
2384                                 {\r
2385                                 // load buffer with a new block from disk\r
2386                                 // try to get as many of the needed blocks in as possible\r
2387                                         while ( next < NUMCHUNKS )\r
2388                                         {\r
2389                                                 while (next < NUMCHUNKS &&\r
2390                                                 !(gvar->video.grneeded[next]&ca_levelbit && !grsegs[next]))\r
2391                                                         next++;\r
2392                                                 if (next == NUMCHUNKS)\r
2393                                                         continue;\r
2394 \r
2395                                                 nextpos = GRFILEPOS(next,gvar);\r
2396                                                 while (GRFILEPOS(++next,gvar) == -1)    // skip past any sparse tiles\r
2397                                                         ;\r
2398                                                 nextendpos = GRFILEPOS(next,gvar);\r
2399                                                 if (nextpos - endpos <= MAXEMPTYREAD\r
2400                                                 && nextendpos-pos <= BUFFERSIZE)\r
2401                                                         endpos = nextendpos;\r
2402                                                 else\r
2403                                                         next = NUMCHUNKS;                       // read pos to posend\r
2404                                         }\r
2405 \r
2406                                         lseek(gvar->ca.file.grhandle,pos,SEEK_SET);\r
2407                                         CA_FarRead(gvar->ca.file.grhandle,(gvar->mm.bufferseg),endpos-pos,gvar);\r
2408                                         bufferstart = pos;\r
2409                                         bufferend = endpos;\r
2410                                         source = bufferseg;\r
2411                                 }\r
2412                         }\r
2413                         else\r
2414                         {\r
2415                         // big chunk, allocate temporary buffer\r
2416                                 MM_GetPtr(&bigbufferseg,compressed,gvar);\r
2417                                 if (mmerror)\r
2418                                         return;\r
2419                                 MM_SetLock (&bigbufferseg,true);\r
2420                                 lseek(gvar->ca.file.grhandle,pos,SEEK_SET);\r
2421                                 CA_FarRead(gvar->ca.file.grhandle,bigbufferseg,compressed,gvar);\r
2422                                 source = bigbufferseg;\r
2423                         }\r
2424 \r
2425                         CAL_ExpandGrChunk (i,source);\r
2426                         if (mmerror)\r
2427                                 return;\r
2428 \r
2429                         if (compressed>BUFFERSIZE)\r
2430                                 MM_FreePtr(&bigbufferseg);\r
2431 \r
2432                 }\r
2433 \r
2434 //\r
2435 // finish up any thermometer remnants\r
2436 //\r
2437                 if (dialog && finishcachebox)\r
2438                         finishcachebox();\r
2439 }*/\r
2440 \r
2441 void CA_CannotOpen(char *string, global_game_variables_t *gvar)\r
2442 {\r
2443  char str[30];\r
2444 \r
2445  strcpy(str,"Can't open ");\r
2446  strcat(str,string);\r
2447  strcat(str,"!\n");\r
2448  Quit (gvar, str);\r
2449 }\r