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