]> 4ch.mooo.com Git - 16.git/blob - 16/keen456/KEEN4-6/ID_RF.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / ID_RF.C
1 /* Reconstructed Commander Keen 4-6 Source Code\r
2  * Copyright (C) 2021 K1n9_Duk3\r
3  *\r
4  * This file is primarily based on:\r
5  * Catacomb 3-D Source Code\r
6  * Copyright (C) 1993-2014 Flat Rock Software\r
7  *\r
8  * This program is free software; you can redistribute it and/or modify\r
9  * it under the terms of the GNU General Public License as published by\r
10  * the Free Software Foundation; either version 2 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU General Public License along\r
19  * with this program; if not, write to the Free Software Foundation, Inc.,\r
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
21  */\r
22 \r
23 // ID_RF.C\r
24 \r
25 /*\r
26 =============================================================================\r
27 \r
28 notes\r
29 -----\r
30 \r
31 scrolling more than one tile / refresh forces a total redraw\r
32 \r
33 two overlapping sprites of equal priority can change drawing order when\r
34 updated\r
35 \r
36 =============================================================================\r
37 */\r
38 \r
39 #include "ID_HEADS.H"\r
40 #pragma hdrstop\r
41 \r
42 /*\r
43 =============================================================================\r
44 \r
45                                                  LOCAL CONSTANTS\r
46 \r
47 =============================================================================\r
48 */\r
49 \r
50 #define SCREENTILESWIDE 20\r
51 #define SCREENTILESHIGH 13\r
52 \r
53 #define SCREENSPACE             (SCREENWIDTH*240)\r
54 #define FREEEGAMEM              (0x10000l-3l*SCREENSPACE)\r
55 \r
56 //\r
57 // the update array must have enough space for two screens that can float\r
58 // up two two tiles each way\r
59 //\r
60 // (PORTTILESWIDE+1)*PORTTILESHIGH must be even so the arrays can be cleared\r
61 // by word width instructions\r
62 \r
63 #define UPDATESCREENSIZE        (UPDATEWIDE*PORTTILESHIGH+2)\r
64 #define UPDATESPARESIZE         (UPDATEWIDE*2+4)\r
65 #define UPDATESIZE                      (UPDATESCREENSIZE+2*UPDATESPARESIZE)\r
66 \r
67 #define G_EGASX_SHIFT   7       // global >> ?? = screen x\r
68 #define G_CGASX_SHIFT   6       // global >> ?? = screen x\r
69 #define G_SY_SHIFT              4       // global >> ?? = screen y\r
70 \r
71 unsigned        SX_T_SHIFT;             // screen x >> ?? = tile EGA = 1, CGA = 2;\r
72 #define SY_T_SHIFT              4       // screen y >> ?? = tile\r
73 \r
74 \r
75 #define EGAPORTSCREENWIDE       42\r
76 #define CGAPORTSCREENWIDE       84\r
77 #define PORTSCREENHIGH          224\r
78 \r
79 #define UPDATESCREENSIZE        (UPDATEWIDE*PORTTILESHIGH+2)\r
80 #define UPDATESPARESIZE         (UPDATEWIDE*2+4)\r
81 #define UPDATESIZE                      (UPDATESCREENSIZE+2*UPDATESPARESIZE)\r
82 \r
83 #define MAXSCROLLEDGES  6\r
84 \r
85 /*\r
86 =============================================================================\r
87 \r
88                                                    LOCAL TYPES\r
89 \r
90 =============================================================================\r
91 */\r
92 \r
93 typedef struct spriteliststruct\r
94 {\r
95         int                     screenx,screeny;\r
96         int                     width,height;\r
97 \r
98         unsigned        grseg,sourceofs,planesize;\r
99         drawtype        draw;\r
100         unsigned        tilex,tiley,tilewide,tilehigh;\r
101         int                     priority,updatecount;\r
102         struct spriteliststruct **prevptr,*nextsprite;\r
103 } spritelisttype;\r
104 \r
105 \r
106 typedef struct\r
107 {\r
108         int                     screenx,screeny;\r
109         int                     width,height;\r
110 } eraseblocktype;\r
111 \r
112 \r
113 typedef struct\r
114 {\r
115         unsigned        current;                // foreground tiles have high bit set\r
116         int                     count;\r
117 #ifdef KEEN6\r
118         unsigned        soundtile;\r
119         unsigned        visible;\r
120         int             sound;\r
121 #endif\r
122 } tiletype;\r
123 \r
124 \r
125 typedef struct animtilestruct\r
126 {\r
127         unsigned        x,y,tile;\r
128         tiletype        *chain;\r
129         unsigned        far *mapplane;\r
130         struct animtilestruct **prevptr,*nexttile;\r
131 } animtiletype;\r
132 \r
133 /*\r
134 =============================================================================\r
135 \r
136                                                  GLOBAL VARIABLES\r
137 \r
138 =============================================================================\r
139 */\r
140 \r
141 unsigned        tics;\r
142 long            lasttimecount;\r
143 \r
144 boolean         compatability;                  // crippled refresh for wierdo SVGAs\r
145 \r
146 unsigned        mapwidth,mapheight,mapbyteswide,mapwordswide\r
147                         ,mapbytesextra,mapwordsextra;\r
148 unsigned        mapbwidthtable[MAXMAPHEIGHT];\r
149 \r
150 //\r
151 // Global : Actor coordinates are in this, at 1/16 th of a pixel, to allow\r
152 // for fractional movement and acceleration.\r
153 //\r
154 // Tiles  : Tile offsets from the upper left corner of the current map.\r
155 //\r
156 // Screen : Graphics level offsets from map origin, x in bytes, y in pixels.\r
157 // originxscreen is the same spot as originxtile, just with extra precision\r
158 // so graphics don't need to be done in tile boundaries.\r
159 //\r
160 \r
161 unsigned        originxglobal,originyglobal;\r
162 unsigned        originxtile,originytile;\r
163 unsigned        originxscreen,originyscreen;\r
164 unsigned        originmap;\r
165 unsigned        originxmin,originxmax,originymin,originymax;\r
166 \r
167 unsigned        masterofs;\r
168 \r
169 //\r
170 // Table of the offsets from bufferofs of each tile spot in the\r
171 // view port.  The extra wide tile should never be drawn, but the space\r
172 // is needed to account for the extra 0 in the update arrays.  Built by\r
173 // RF_Startup\r
174 //\r
175 \r
176 unsigned        blockstarts[UPDATEWIDE*UPDATEHIGH];\r
177 unsigned        updatemapofs[UPDATEWIDE*UPDATEHIGH];\r
178 \r
179 unsigned        uwidthtable[PORTTILESHIGH];             // lookup instead of multiply\r
180 \r
181 byte            update[2][UPDATESIZE];\r
182 byte            *updateptr,*baseupdateptr,                                              // current start of update window\r
183                         *updatestart[2],\r
184                         *baseupdatestart[2];\r
185 \r
186 /*\r
187 =============================================================================\r
188 \r
189                                                  LOCAL VARIABLES\r
190 \r
191 =============================================================================\r
192 */\r
193 \r
194 static          char    scratch[20],str[80];\r
195 \r
196 tiletype        allanims[MAXANIMTYPES];\r
197 unsigned        numanimchains;\r
198 \r
199 void            (*refreshvector) (void);\r
200 \r
201 unsigned        screenstart[3] =\r
202         {0,SCREENSPACE,SCREENSPACE*2};\r
203 \r
204 unsigned        xpanmask;                       // prevent panning to odd pixels\r
205 \r
206 unsigned        screenpage;                     // screen currently being displayed\r
207 unsigned        otherpage;\r
208 \r
209 \r
210 spritelisttype  spritearray[MAXSPRITES],*prioritystart[PRIORITIES],\r
211                                 *spritefreeptr;\r
212 \r
213 animtiletype    animarray[MAXANIMTILES],*animhead,*animfreeptr;\r
214 \r
215 int                             animfreespot;\r
216 \r
217 eraseblocktype  eraselist[2][MAXSPRITES],*eraselistptr[2];\r
218 \r
219 int             hscrollblocks,vscrollblocks;\r
220 int             hscrolledge[MAXSCROLLEDGES],vscrolledge[MAXSCROLLEDGES];\r
221 \r
222 /*\r
223 =============================================================================\r
224 \r
225                                                  LOCAL PROTOTYPES\r
226 \r
227 =============================================================================\r
228 */\r
229 \r
230 void RFL_NewTile (unsigned updateoffset);\r
231 void RFL_MaskForegroundTiles (void);\r
232 void RFL_UpdateTiles (void);\r
233 \r
234 void RFL_BoundScroll (int x, int y);\r
235 void RFL_CalcOriginStuff (long x, long y);\r
236 void RFL_ClearScrollBlocks (void);\r
237 void RFL_InitSpriteList (void);\r
238 void RFL_InitAnimList (void);\r
239 void RFL_CheckForAnimTile (unsigned x, unsigned y);\r
240 void RFL_AnimateTiles (void);\r
241 void RFL_RemoveAnimsOnX (unsigned x);\r
242 void RFL_RemoveAnimsOnY (unsigned y);\r
243 void RFL_EraseBlocks (void);\r
244 void RFL_UpdateSprites (void);\r
245 \r
246 \r
247 /*\r
248 =============================================================================\r
249 \r
250                                          GRMODE INDEPENDANT ROUTINES\r
251 \r
252 =============================================================================\r
253 */\r
254 \r
255 \r
256 /*\r
257 =====================\r
258 =\r
259 = RF_Startup\r
260 =\r
261 =====================\r
262 */\r
263 \r
264 static  char *ParmStrings[] = {"comp",""};\r
265 \r
266 void RF_Startup (void)\r
267 {\r
268         int i,x,y;\r
269         unsigned        *blockstart;\r
270 \r
271 #ifndef KEEN\r
272         //\r
273         // Keen 4-6 store the compatability setting in the game's config file.\r
274         // The setting is loaded from that file AFTER RF_Startup is executed,\r
275         // making this check useless (unless the config file doesn't exist).\r
276         // Instead, US_Startup now checks for that parameter after the config\r
277         // file has been read.\r
278         //\r
279         if (grmode == EGAGR)\r
280                 for (i = 1;i < _argc;i++)\r
281                         if (US_CheckParm(_argv[i],ParmStrings) == 0)\r
282                         {\r
283                                 compatability = true;\r
284                                 break;\r
285                         }\r
286 #endif\r
287 \r
288         for (i=0;i<PORTTILESHIGH;i++)\r
289                 uwidthtable[i] = UPDATEWIDE*i;\r
290 \r
291         originxmin = originymin = MAPBORDER*TILEGLOBAL;\r
292 \r
293         eraselistptr[0] = &eraselist[0][0];\r
294         eraselistptr[1] = &eraselist[1][0];\r
295 \r
296 \r
297 \r
298         if (grmode == EGAGR)\r
299         {\r
300                 SX_T_SHIFT = 1;\r
301 \r
302                 baseupdatestart[0] = &update[0][UPDATESPARESIZE];\r
303                 baseupdatestart[1] = &update[1][UPDATESPARESIZE];\r
304 \r
305                 screenpage = 0;\r
306                 otherpage = 1;\r
307                 displayofs = screenstart[screenpage];\r
308                 bufferofs = screenstart[otherpage];\r
309                 masterofs = screenstart[2];\r
310 \r
311                 updateptr = baseupdatestart[otherpage];\r
312 \r
313                 blockstart = &blockstarts[0];\r
314                 for (y=0;y<UPDATEHIGH;y++)\r
315                         for (x=0;x<UPDATEWIDE;x++)\r
316                                 *blockstart++ = SCREENWIDTH*16*y+x*TILEWIDTH;\r
317 \r
318                 xpanmask = 6;   // dont pan to odd pixels\r
319         }\r
320 \r
321         else if (grmode == CGAGR)\r
322         {\r
323                 SX_T_SHIFT = 2;\r
324 \r
325                 updateptr = baseupdateptr = &update[0][UPDATESPARESIZE];\r
326 \r
327                 bufferofs = 0;\r
328                 masterofs = 0x8000;\r
329 \r
330                 blockstart = &blockstarts[0];\r
331                 for (y=0;y<UPDATEHIGH;y++)\r
332                         for (x=0;x<UPDATEWIDE;x++)\r
333                                 *blockstart++ = SCREENWIDTH*16*y+x*TILEWIDTH;\r
334         }\r
335 }\r
336 \r
337 \r
338 \r
339 \r
340 /*\r
341 =====================\r
342 =\r
343 = RF_Shutdown\r
344 =\r
345 =====================\r
346 */\r
347 \r
348 void RF_Shutdown (void)\r
349 {\r
350 \r
351 }\r
352 \r
353 //===========================================================================\r
354 \r
355 \r
356 /*\r
357 =====================\r
358 =\r
359 = RF_FixOfs\r
360 =\r
361 = Sets bufferofs,displayofs, and masterofs to regular values, for the\r
362 = occasions when you have moved them around manually\r
363 =\r
364 =====================\r
365 */\r
366 \r
367 void RF_FixOfs (void)\r
368 {\r
369         screenstart[0] = 0;\r
370         screenstart[1] = SCREENSPACE;\r
371         screenstart[2] = SCREENSPACE*2;\r
372 \r
373         if (grmode == EGAGR)\r
374         {\r
375                 screenpage = 0;\r
376                 otherpage = 1;\r
377                 panx = pany = pansx = pansy = panadjust = 0;\r
378                 displayofs = screenstart[screenpage];\r
379                 bufferofs = screenstart[otherpage];\r
380                 masterofs = screenstart[2];\r
381                 VW_SetScreen (displayofs,0);\r
382         }\r
383         else\r
384         {\r
385                 panx = pany = pansx = pansy = panadjust = 0;\r
386                 bufferofs = 0;\r
387                 masterofs = 0x8000;\r
388         }\r
389 }\r
390 \r
391 \r
392 //===========================================================================\r
393 \r
394 /*\r
395 =====================\r
396 =\r
397 = RF_NewMap\r
398 =\r
399 = Makes some convienient calculations based on maphead->\r
400 =\r
401 =====================\r
402 */\r
403 \r
404 void RF_NewMap (void)\r
405 {\r
406         int i,x,y;\r
407         unsigned spot,*table;\r
408 \r
409         mapwidth = mapheaderseg[mapon]->width;\r
410         mapbyteswide = 2*mapwidth;\r
411         mapheight = mapheaderseg[mapon]->height;\r
412         mapwordsextra = mapwidth-PORTTILESWIDE;\r
413         mapbytesextra = 2*mapwordsextra;\r
414 \r
415 //\r
416 // make a lookup table for the maps left edge\r
417 //\r
418         if (mapheight > MAXMAPHEIGHT)\r
419                 Quit ("RF_NewMap: Map too tall!");\r
420         spot = 0;\r
421         for (i=0;i<mapheight;i++)\r
422         {\r
423           mapbwidthtable[i] = spot;\r
424           spot += mapbyteswide;\r
425         }\r
426 \r
427 //\r
428 // fill in updatemapofs with the new width info\r
429 //\r
430         table = &updatemapofs[0];\r
431         for (y=0;y<PORTTILESHIGH;y++)\r
432                 for (x=0;x<UPDATEWIDE;x++)\r
433                         *table++ = mapbwidthtable[y]+x*2;\r
434 \r
435 //\r
436 // the y max value clips off the bottom half of a tile so a map that is\r
437 // 13 + MAPBORDER*2 tile high will not scroll at all vertically\r
438 //\r
439         originxmax = (mapwidth-MAPBORDER-SCREENTILESWIDE)*TILEGLOBAL;\r
440         originymax = (mapheight-MAPBORDER-SCREENTILESHIGH)*TILEGLOBAL;\r
441         if (originxmax<originxmin)              // for very small maps\r
442                 originxmax=originxmin;\r
443         if (originymax<originymin)\r
444                 originymax=originymin;\r
445 \r
446 //\r
447 // clear out the lists\r
448 //\r
449         RFL_InitSpriteList ();\r
450         RFL_InitAnimList ();\r
451         RFL_ClearScrollBlocks ();\r
452         RF_SetScrollBlock (0,MAPBORDER-1,true);\r
453         RF_SetScrollBlock (0,mapheight-MAPBORDER,true);\r
454         RF_SetScrollBlock (MAPBORDER-1,0,false);\r
455         RF_SetScrollBlock (mapwidth-MAPBORDER,0,false);\r
456 \r
457 \r
458         lasttimecount = TimeCount;              // setup for adaptive timing\r
459         tics = 1;\r
460 }\r
461 \r
462 //===========================================================================\r
463 \r
464 #ifdef KEEN6\r
465 /*\r
466 ==========================\r
467 =\r
468 = RFL_CheckTileSound\r
469 =\r
470 = Checks if the tile plays a sound and if so adds that info to the animation\r
471 =\r
472 ==========================\r
473 */\r
474 \r
475 #define NUMSOUNDTILES 2\r
476 typedef struct {\r
477         unsigned tilenums[NUMSOUNDTILES];\r
478         int sounds[NUMSOUNDTILES];\r
479 } tilesoundtype;\r
480 \r
481 tilesoundtype far soundtiles = {\r
482         {2152|0x8000, 2208|0x8000},\r
483         {SND_STOMP,   SND_FLAME}\r
484 };\r
485 \r
486 void RFL_CheckTileSound(tiletype *anim, unsigned tile)\r
487 {\r
488         int i;\r
489 \r
490         for (i=0; i<NUMSOUNDTILES; i++)\r
491         {\r
492                 if (soundtiles.tilenums[i] == tile)\r
493                 {\r
494                         anim->soundtile = tile;\r
495                         anim->sound = soundtiles.sounds[i];\r
496                         break;\r
497                 }\r
498         }\r
499 }\r
500 \r
501 #endif\r
502 \r
503 //===========================================================================\r
504 \r
505 /*\r
506 ==========================\r
507 =\r
508 = RF_MarkTileGraphics\r
509 =\r
510 = Goes through mapplane[0/1] and marks all background/foreground tiles\r
511 = needed, then follows all animation sequences to make sure animated\r
512 = tiles get all the stages.  Every unique animating tile is given an\r
513 = entry in allanims[], so every instance of that tile will animate at the\r
514 = same rate.  The info plane for each animating tile will hold a pointer\r
515 = into allanims[], therefore you can't have both an animating foreground\r
516 = and background tile in the same spot!\r
517 =\r
518 ==========================\r
519 */\r
520 \r
521 void RF_MarkTileGraphics (void)\r
522 {\r
523         unsigned        size;\r
524         int                     tile,next,anims,change;\r
525         unsigned        far     *start,far *end,far *info;\r
526         unsigned        i,tilehigh;\r
527         char            str[80],str2[10];\r
528 \r
529         memset (allanims,0,sizeof(allanims));\r
530         numanimchains = 0;\r
531 \r
532         size = mapwidth*mapheight;\r
533 \r
534 //\r
535 // background plane\r
536 //\r
537         start = mapsegs[0];\r
538         info = mapsegs[2];\r
539         end = start+size;\r
540         do\r
541         {\r
542                 tile = *start++;\r
543                 if (tile>=0)                    // <0 is a tile that is never drawn\r
544                 {\r
545                         CA_MarkGrChunk(STARTTILE16+tile);\r
546                         if (tinf[ANIM+tile])\r
547                         {\r
548                                 // this tile will animated\r
549 \r
550                                 if (tinf[SPEED+tile])\r
551                                 {\r
552                                         if (!tinf[ANIM+tile])\r
553                                         {\r
554                                                 strcpy (str,"RF_MarkTileGraphics: Background anim of 0:");\r
555                                                 itoa (tile,str2,10);\r
556                                                 strcat (str,str2);\r
557                                                 Quit (str);\r
558                                         }\r
559                                         for (i=0;i<numanimchains;i++)\r
560                                                 if (allanims[i].current == tile)\r
561                                                 {\r
562                                                         *info = (unsigned)&allanims[i];\r
563                                                         goto nextback;\r
564                                                 }\r
565 \r
566                                         // new chain of animating tiles\r
567 \r
568                                         if (i>=MAXANIMTYPES)\r
569                                                 Quit ("RF_MarkTileGraphics: Too many unique animated tiles!");\r
570                                         allanims[i].current = tile;\r
571                                         allanims[i].count = tinf[SPEED+tile];\r
572 #ifdef KEEN6\r
573                                         allanims[i].visible = 0;\r
574                                         allanims[i].sound = -1;\r
575 #endif\r
576                                         *info = (unsigned)&allanims[i];\r
577                                         numanimchains++;\r
578                                 }\r
579 #ifdef KEEN6\r
580                                 RFL_CheckTileSound(&allanims[i], tile);\r
581 #endif\r
582 \r
583                                 anims = 0;\r
584                                 change = (signed char)(tinf[ANIM+tile]);\r
585                                 next = tile+change;\r
586                                 while (change && next != tile)\r
587                                 {\r
588 #ifdef KEEN6\r
589                                         RFL_CheckTileSound(&allanims[i], next);\r
590 #endif\r
591                                         CA_MarkGrChunk(STARTTILE16+next);\r
592                                         change = (signed char)(tinf[ANIM+next]);\r
593                                         next += change;\r
594                                         if (++anims > 20)\r
595                                         {\r
596                                                 strcpy (str,"RF_MarkTileGraphics: Unending background animation:");\r
597                                                 itoa (next,str2,10);\r
598                                                 strcat (str,str2);\r
599                                                 Quit (str);\r
600                                         }\r
601                                 }\r
602 \r
603                         }\r
604                 }\r
605 nextback:\r
606                 info++;\r
607         } while (start<end);\r
608 \r
609 //\r
610 // foreground plane\r
611 //\r
612         start = mapsegs[1];\r
613         info = mapsegs[2];\r
614         end = start+size;\r
615         do\r
616         {\r
617                 tile = *start++;\r
618                 if (tile>=0)                    // <0 is a tile that is never drawn\r
619                 {\r
620                         CA_MarkGrChunk(STARTTILE16M+tile);\r
621                         if (tinf[MANIM+tile])\r
622                         {\r
623                                 // this tile will animated\r
624 \r
625                                 if (tinf[MSPEED+tile])\r
626                                 {\r
627                                         if (!tinf[MANIM+tile])\r
628                                         {\r
629                                                 strcpy (str,"RF_MarkTileGraphics: Foreground anim of 0:");\r
630                                                 itoa (tile,str2,10);\r
631                                                 strcat (str,str2);\r
632                                                 Quit (str);\r
633                                         }\r
634                                         tilehigh = tile | 0x8000;       // foreground tiles have high bit\r
635                                         for (i=0;i<numanimchains;i++)\r
636                                                 if (allanims[i].current == tilehigh)\r
637                                                 {\r
638                                                         *info = (unsigned)&allanims[i];\r
639                                                         goto nextfront;\r
640                                                 }\r
641 \r
642                                         // new chain of animating tiles\r
643 \r
644                                         if (i>=MAXANIMTYPES)\r
645                                                 Quit ("RF_MarkTileGraphics: Too many unique animated tiles!");\r
646                                         allanims[i].current = tilehigh;\r
647                                         allanims[i].count = tinf[MSPEED+tile];\r
648 #ifdef KEEN6\r
649                                         allanims[i].visible = 0;\r
650                                         allanims[i].sound = -1;\r
651 #endif\r
652                                         *info = (unsigned)&allanims[i];\r
653                                         numanimchains++;\r
654                                 }\r
655 \r
656 #ifdef KEEN6\r
657                                 RFL_CheckTileSound(&allanims[i], tilehigh);\r
658 #endif\r
659                                 anims = 0;\r
660                                 change = (signed char)(tinf[MANIM+tile]);\r
661                                 next = tile+change;\r
662                                 while (change && next != tile)\r
663                                 {\r
664 #ifdef KEEN6\r
665                                         RFL_CheckTileSound(&allanims[i], next | 0x8000);        // foreground tiles have high bit\r
666 #endif\r
667                                         CA_MarkGrChunk(STARTTILE16M+next);\r
668                                         change = (signed char)(tinf[MANIM+next]);\r
669                                         next += change;\r
670                                         if (++anims > 20)\r
671                                         {\r
672                                                 strcpy (str,"RF_MarkTileGraphics: Unending foreground animation:");\r
673                                                 itoa (next,str2,10);\r
674                                                 strcat (str,str2);\r
675                                                 Quit (str);\r
676                                         }\r
677                                 }\r
678 \r
679                         }\r
680                 }\r
681 nextfront:\r
682                 info++;\r
683         } while (start<end);\r
684 }\r
685 \r
686 \r
687 //===========================================================================\r
688 \r
689 \r
690 /*\r
691 =========================\r
692 =\r
693 = RFL_InitAnimList\r
694 =\r
695 = Call to clear out the entire animating tile list and return all of them to\r
696 = the free list.\r
697 =\r
698 =========================\r
699 */\r
700 \r
701 void RFL_InitAnimList (void)\r
702 {\r
703         int     i;\r
704 \r
705         animfreeptr = &animarray[0];\r
706 \r
707         for (i=0;i<MAXANIMTILES-1;i++)\r
708                 animarray[i].nexttile = &animarray[i+1];\r
709 \r
710         animarray[i].nexttile = NULL;\r
711 \r
712         animhead = NULL;                        // nothing in list\r
713 \r
714 #ifdef KEEN6\r
715         {\r
716                 tiletype *anim;\r
717 \r
718                 for (anim = allanims; anim->current != 0; anim++)\r
719                         anim->visible = 0;\r
720         }\r
721 #endif\r
722 }\r
723 \r
724 \r
725 /*\r
726 ====================\r
727 =\r
728 = RFL_CheckForAnimTile\r
729 =\r
730 ====================\r
731 */\r
732 \r
733 void RFL_CheckForAnimTile (unsigned x, unsigned y)\r
734 {\r
735         unsigned        tile,offset,speed,lasttime,thistime,timemissed;\r
736         unsigned        far *map;\r
737         animtiletype    *anim,*next;\r
738 \r
739 // the info plane of each animating tile has a near pointer into allanims[]\r
740 // which gives the current state of all concurrently animating tiles\r
741 \r
742         offset = mapbwidthtable[y]/2+x;\r
743 \r
744 //\r
745 // background\r
746 //\r
747         map = mapsegs[0]+offset;\r
748         tile = *map;\r
749         if (tinf[ANIM+tile] && tinf[SPEED+tile])\r
750         {\r
751                 if (!animfreeptr)\r
752                         Quit ("RF_CheckForAnimTile: No free spots in tilearray!");\r
753                 anim = animfreeptr;\r
754                 animfreeptr = animfreeptr->nexttile;\r
755                 next = animhead;                                // stick it at the start of the list\r
756                 animhead = anim;\r
757                 if (next)\r
758                         next->prevptr = &anim->nexttile;\r
759                 anim->nexttile = next;\r
760                 anim->prevptr = &animhead;\r
761 \r
762                 anim->x = x;\r
763                 anim->y = y;\r
764                 anim->tile = tile;\r
765                 anim->mapplane = map;\r
766                 anim->chain = (tiletype *)*(mapsegs[2]+offset);\r
767 #ifdef KEEN6\r
768                 anim->chain->visible++;\r
769 #endif\r
770         }\r
771 \r
772 //\r
773 // foreground\r
774 //\r
775         map = mapsegs[1]+offset;\r
776         tile = *map;\r
777         if (tinf[MANIM+tile] && tinf[MSPEED+tile])\r
778         {\r
779                 if (!animfreeptr)\r
780                         Quit ("RF_CheckForAnimTile: No free spots in tilearray!");\r
781                 anim = animfreeptr;\r
782                 animfreeptr = animfreeptr->nexttile;\r
783                 next = animhead;                                // stick it at the start of the list\r
784                 animhead = anim;\r
785                 if (next)\r
786                         next->prevptr = &anim->nexttile;\r
787                 anim->nexttile = next;\r
788                 anim->prevptr = &animhead;\r
789 \r
790                 anim->x = x;\r
791                 anim->y = y;\r
792                 anim->tile = tile;\r
793                 anim->mapplane = map;\r
794                 anim->chain = (tiletype *)*(mapsegs[2]+offset);\r
795 #ifdef KEEN6\r
796                 anim->chain->visible++;\r
797 #endif\r
798         }\r
799 \r
800 }\r
801 \r
802 \r
803 /*\r
804 ====================\r
805 =\r
806 = RFL_RemoveAnimsOnX\r
807 =\r
808 ====================\r
809 */\r
810 \r
811 void RFL_RemoveAnimsOnX (unsigned x)\r
812 {\r
813         animtiletype *current,*next;\r
814 \r
815         current = animhead;\r
816         while (current)\r
817         {\r
818                 if (current->x == x)\r
819                 {\r
820 #ifdef KEEN6\r
821                         current->chain->visible--;\r
822 #endif\r
823                         *(void **)current->prevptr = current->nexttile;\r
824                         if (current->nexttile)\r
825                                 current->nexttile->prevptr = current->prevptr;\r
826                         next = current->nexttile;\r
827                         current->nexttile = animfreeptr;\r
828                         animfreeptr = current;\r
829                         current = next;\r
830                 }\r
831                 else\r
832                         current = current->nexttile;\r
833         }\r
834 }\r
835 \r
836 \r
837 /*\r
838 ====================\r
839 =\r
840 = RFL_RemoveAnimsOnY\r
841 =\r
842 ====================\r
843 */\r
844 \r
845 void RFL_RemoveAnimsOnY (unsigned y)\r
846 {\r
847         animtiletype *current,*next;\r
848 \r
849         current = animhead;\r
850         while (current)\r
851         {\r
852                 if (current->y == y)\r
853                 {\r
854 #ifdef KEEN6\r
855                         current->chain->visible--;\r
856 #endif\r
857                         *(void **)current->prevptr = current->nexttile;\r
858                         if (current->nexttile)\r
859                                 current->nexttile->prevptr = current->prevptr;\r
860                         next = current->nexttile;\r
861                         current->nexttile = animfreeptr;\r
862                         animfreeptr = current;\r
863                         current = next;\r
864                 }\r
865                 else\r
866                         current = current->nexttile;\r
867         }\r
868 }\r
869 \r
870 \r
871 /*\r
872 ====================\r
873 =\r
874 = RFL_RemoveAnimsInBlock\r
875 =\r
876 ====================\r
877 */\r
878 \r
879 void RFL_RemoveAnimsInBlock (unsigned x, unsigned y, unsigned width, unsigned height)\r
880 {\r
881         animtiletype *current,*next;\r
882 \r
883         current = animhead;\r
884         while (current)\r
885         {\r
886                 if (current->x - x < width && current->y - y < height)\r
887                 {\r
888 #ifdef KEEN6\r
889                         current->chain->visible--;\r
890 #endif\r
891                         *(void **)current->prevptr = current->nexttile;\r
892                         if (current->nexttile)\r
893                                 current->nexttile->prevptr = current->prevptr;\r
894                         next = current->nexttile;\r
895                         current->nexttile = animfreeptr;\r
896                         animfreeptr = current;\r
897                         current = next;\r
898                 }\r
899                 else\r
900                         current = current->nexttile;\r
901         }\r
902 }\r
903 \r
904 \r
905 /*\r
906 ====================\r
907 =\r
908 = RFL_AnimateTiles\r
909 =\r
910 ====================\r
911 */\r
912 \r
913 void RFL_AnimateTiles (void)\r
914 {\r
915         animtiletype *current;\r
916         unsigned        updateofs,tile,x,y;\r
917         tiletype        *anim;\r
918 \r
919 //\r
920 // animate the lists of tiles\r
921 //\r
922         anim = &allanims[0];\r
923         while (anim->current)\r
924         {\r
925                 anim->count-=tics;\r
926                 while ( anim->count < 1)\r
927                 {\r
928                         if (anim->current & 0x8000)\r
929                         {\r
930                                 tile = anim->current & 0x7fff;\r
931                                 tile += (signed char)tinf[MANIM+tile];\r
932                                 anim->count += tinf[MSPEED+tile];\r
933                                 tile |= 0x8000;\r
934                         }\r
935                         else\r
936                         {\r
937                                 tile = anim->current;\r
938                                 tile += (signed char)tinf[ANIM+tile];\r
939                                 anim->count += tinf[SPEED+tile];\r
940                         }\r
941                         anim->current = tile;\r
942 #ifdef KEEN6\r
943                         if (anim->visible && anim->current == anim->soundtile && anim->sound != -1)\r
944                         {\r
945                                 SD_PlaySound(anim->sound);\r
946                         }\r
947 #endif\r
948                 }\r
949                 anim++;\r
950         }\r
951 \r
952 \r
953 //\r
954 // traverse the list of animating tiles\r
955 //\r
956         current = animhead;\r
957         while (current)\r
958         {\r
959                 tile =current->chain->current;\r
960                 if ( tile != current->tile)\r
961                 {\r
962                 // tile has animated\r
963                 //\r
964                 // remove tile from master screen cache,\r
965                 // change a tile to its next state, set the structure up for\r
966                 // next animation, and post an update region to both update pages\r
967                 //\r
968                         current->tile = tile;\r
969 \r
970                         *(current->mapplane) = tile & 0x7fff;           // change in map\r
971 \r
972                         x = current->x-originxtile;\r
973                         y = current->y-originytile;\r
974 \r
975                         if (x>=PORTTILESWIDE || y>=PORTTILESHIGH)\r
976                                 Quit ("RFL_AnimateTiles: Out of bounds!");\r
977 \r
978                         updateofs = uwidthtable[y] + x;\r
979                         RFL_NewTile(updateofs);                         // puts "1"s in both pages\r
980                 }\r
981                 current = current->nexttile;\r
982         }\r
983 }\r
984 \r
985 \r
986 //===========================================================================\r
987 \r
988 /*\r
989 =========================\r
990 =\r
991 = RFL_InitSpriteList\r
992 =\r
993 = Call to clear out the entire sprite list and return all of them to\r
994 = the free list.\r
995 =\r
996 =========================\r
997 */\r
998 \r
999 void RFL_InitSpriteList (void)\r
1000 {\r
1001         int     i;\r
1002 \r
1003         spritefreeptr = &spritearray[0];\r
1004         for (i=0;i<MAXSPRITES-1;i++)\r
1005                 spritearray[i].nextsprite = &spritearray[i+1];\r
1006 \r
1007         spritearray[i].nextsprite = NULL;\r
1008 \r
1009 // NULL in all priority levels\r
1010 \r
1011         memset (prioritystart,0,sizeof(prioritystart));\r
1012 }\r
1013 \r
1014 //===========================================================================\r
1015 \r
1016 /*\r
1017 =================\r
1018 =\r
1019 = RFL_CalcOriginStuff\r
1020 =\r
1021 = Calculate all the global variables for a new position\r
1022 = Long parms so position can be clipped to a maximum near 64k\r
1023 =\r
1024 =================\r
1025 */\r
1026 \r
1027 void RFL_CalcOriginStuff (long x, long y)\r
1028 {\r
1029         originxglobal = x;\r
1030         originyglobal = y;\r
1031         originxtile = originxglobal>>G_T_SHIFT;\r
1032         originytile = originyglobal>>G_T_SHIFT;\r
1033         originxscreen = originxtile<<SX_T_SHIFT;\r
1034         originyscreen = originytile<<SY_T_SHIFT;\r
1035         originmap = mapbwidthtable[originytile] + originxtile*2;\r
1036 \r
1037 #if GRMODE == EGAGR\r
1038         panx = (originxglobal>>G_P_SHIFT) & 15;\r
1039         pansx = panx & 8;\r
1040         pany = pansy = (originyglobal>>G_P_SHIFT) & 15;\r
1041         panadjust = panx/8 + ylookup[pany];\r
1042 #endif\r
1043 \r
1044 #if GRMODE == CGAGR\r
1045         panx = (originxglobal>>G_P_SHIFT) & 15;\r
1046         pansx = panx & 12;\r
1047         pany = pansy = (originyglobal>>G_P_SHIFT) & 15;\r
1048         panadjust = pansx/4 + ylookup[pansy];\r
1049 #endif\r
1050 \r
1051 }\r
1052 \r
1053 \r
1054 /*\r
1055 =================\r
1056 =\r
1057 = RFL_ClearScrollBlocks\r
1058 =\r
1059 =================\r
1060 */\r
1061 \r
1062 void RFL_ClearScrollBlocks (void)\r
1063 {\r
1064         hscrollblocks = vscrollblocks = 0;\r
1065 }\r
1066 \r
1067 \r
1068 /*\r
1069 =================\r
1070 =\r
1071 = RF_SetScrollBlock\r
1072 =\r
1073 = Sets a horizontal or vertical scroll block\r
1074 = a horizontal block is ----, meaning it blocks up/down movement\r
1075 =\r
1076 =================\r
1077 */\r
1078 \r
1079 void RF_SetScrollBlock (int x, int y, boolean horizontal)\r
1080 {\r
1081         if (horizontal)\r
1082         {\r
1083                 hscrolledge[hscrollblocks] = y;\r
1084                 if (hscrollblocks++ == MAXSCROLLEDGES)\r
1085                         Quit ("RF_SetScrollBlock: Too many horizontal scroll blocks");\r
1086         }\r
1087         else\r
1088         {\r
1089                 vscrolledge[vscrollblocks] = x;\r
1090                 if (vscrollblocks++ == MAXSCROLLEDGES)\r
1091                         Quit ("RF_SetScrollBlock: Too many vertical scroll blocks");\r
1092         }\r
1093 }\r
1094 \r
1095 \r
1096 /*\r
1097 =================\r
1098 =\r
1099 = RFL_BoundScroll\r
1100 =\r
1101 = Bound a given x/y movement to scroll blocks\r
1102 =\r
1103 =================\r
1104 */\r
1105 \r
1106 void RFL_BoundScroll (int x, int y)\r
1107 {\r
1108         int     check,newxtile,newytile;\r
1109 \r
1110         originxglobal += x;\r
1111         originyglobal += y;\r
1112 \r
1113         newxtile= originxglobal >> G_T_SHIFT;\r
1114         newytile = originyglobal >> G_T_SHIFT;\r
1115 \r
1116         if (x>0)\r
1117         {\r
1118                 newxtile+=SCREENTILESWIDE;\r
1119                 for (check=0;check<vscrollblocks;check++)\r
1120                         if (vscrolledge[check] == newxtile)\r
1121                         {\r
1122                                 originxglobal = originxglobal&0xff00;\r
1123                                 break;\r
1124                         }\r
1125         }\r
1126         else if (x<0)\r
1127         {\r
1128                 for (check=0;check<vscrollblocks;check++)\r
1129                         if (vscrolledge[check] == newxtile)\r
1130                         {\r
1131                                 originxglobal = (originxglobal&0xff00)+0x100;\r
1132                                 break;\r
1133                         }\r
1134         }\r
1135 \r
1136 \r
1137         if (y>0)\r
1138         {\r
1139                 newytile+=SCREENTILESHIGH;\r
1140                 for (check=0;check<hscrollblocks;check++)\r
1141                         if (hscrolledge[check] == newytile)\r
1142                         {\r
1143                                 originyglobal = originyglobal&0xff00;\r
1144                                 break;\r
1145                         }\r
1146         }\r
1147         else if (y<0)\r
1148         {\r
1149                 for (check=0;check<hscrollblocks;check++)\r
1150                         if (hscrolledge[check] == newytile)\r
1151                         {\r
1152                                 originyglobal = (originyglobal&0xff00)+0x100;\r
1153                                 break;\r
1154                         }\r
1155         }\r
1156 \r
1157 \r
1158         RFL_CalcOriginStuff (originxglobal, originyglobal);\r
1159 }\r
1160 \r
1161 \r
1162 //===========================================================================\r
1163 \r
1164 /*\r
1165 =====================\r
1166 =\r
1167 = RF_SetRefreshHook\r
1168 =\r
1169 =====================\r
1170 */\r
1171 \r
1172 void RF_SetRefreshHook (void (*func) (void) )\r
1173 {\r
1174         refreshvector = func;\r
1175 }\r
1176 \r
1177 \r
1178 //===========================================================================\r
1179 \r
1180 /*\r
1181 =================\r
1182 =\r
1183 = RFL_NewRow\r
1184 =\r
1185 = Bring a new row of tiles onto the port, spawning animating tiles\r
1186 =\r
1187 =================\r
1188 */\r
1189 \r
1190 void    RFL_NewRow (int dir)\r
1191 {\r
1192         unsigned count,updatespot,updatestep;\r
1193         int             x,y,xstep,ystep;\r
1194 \r
1195         switch (dir)\r
1196         {\r
1197         case 0:         // top row\r
1198                 updatespot = 0;\r
1199                 updatestep = 1;\r
1200                 x = originxtile;\r
1201                 y = originytile;\r
1202                 xstep = 1;\r
1203                 ystep = 0;\r
1204                 count = PORTTILESWIDE;\r
1205                 break;\r
1206 \r
1207         case 1:         // right row\r
1208                 updatespot = PORTTILESWIDE-1;\r
1209                 updatestep = UPDATEWIDE;\r
1210                 x = originxtile + PORTTILESWIDE-1;\r
1211                 y = originytile;\r
1212                 xstep = 0;\r
1213                 ystep = 1;\r
1214                 count = PORTTILESHIGH;\r
1215                 break;\r
1216 \r
1217         case 2:         // bottom row\r
1218                 updatespot = UPDATEWIDE*(PORTTILESHIGH-1);\r
1219                 updatestep = 1;\r
1220                 x = originxtile;\r
1221                 y = originytile + PORTTILESHIGH-1;\r
1222                 xstep = 1;\r
1223                 ystep = 0;\r
1224                 count = PORTTILESWIDE;\r
1225                 break;\r
1226 \r
1227         case 3:         // left row\r
1228                 updatespot = 0;\r
1229                 updatestep = UPDATEWIDE;\r
1230                 x = originxtile;\r
1231                 y = originytile;\r
1232                 xstep = 0;\r
1233                 ystep = 1;\r
1234                 count = PORTTILESHIGH;\r
1235                 break;\r
1236         default:\r
1237                 Quit ("RFL_NewRow: Bad dir!");\r
1238         }\r
1239 \r
1240         while (count--)\r
1241         {\r
1242                 RFL_NewTile(updatespot);\r
1243                 RFL_CheckForAnimTile (x,y);\r
1244                 updatespot+=updatestep;\r
1245                 x+=xstep;\r
1246                 y+=ystep;\r
1247         }\r
1248 }\r
1249 \r
1250 //===========================================================================\r
1251 \r
1252 /*\r
1253 =====================\r
1254 =\r
1255 = RF_ForceRefresh\r
1256 =\r
1257 =====================\r
1258 */\r
1259 \r
1260 void RF_ForceRefresh (void)\r
1261 {\r
1262         RF_NewPosition (originxglobal,originyglobal);\r
1263         RF_Refresh ();\r
1264         RF_Refresh ();\r
1265 }\r
1266 \r
1267 //===========================================================================\r
1268 \r
1269 /*\r
1270 =====================\r
1271 =\r
1272 = RF_MapToMap\r
1273 =\r
1274 = Copies a block of tiles (all three planes) from one point\r
1275 = in the map to another, accounting for animating tiles\r
1276 =\r
1277 =====================\r
1278 */\r
1279 \r
1280 void RF_MapToMap (unsigned srcx, unsigned srcy,\r
1281                                   unsigned destx, unsigned desty,\r
1282                                   unsigned width, unsigned height)\r
1283 {\r
1284         int                     x,y;\r
1285         unsigned        source,destofs,xspot,yspot;\r
1286         unsigned        linedelta,p0,p1,p2,updatespot;\r
1287         unsigned        far *source0, far *source1, far *source2;\r
1288         unsigned        far *dest0, far *dest1, far *dest2;\r
1289         boolean         changed;\r
1290 \r
1291         RFL_RemoveAnimsInBlock (destx,desty,width,height);\r
1292 \r
1293         source = mapbwidthtable[srcy]/2 + srcx;\r
1294 \r
1295         source0 = mapsegs[0]+source;\r
1296         source1 = mapsegs[1]+source;\r
1297         source2 = mapsegs[2]+source;\r
1298 \r
1299         destofs = mapbwidthtable[desty]/2 + destx;\r
1300         destofs -= source;\r
1301 \r
1302         linedelta = mapwidth - width;\r
1303 \r
1304         for (y=0;y<height;y++,source0+=linedelta,source1+=linedelta,source2+=linedelta)\r
1305                 for (x=0;x<width;x++,source0++,source1++,source2++)\r
1306                 {\r
1307                         p0 = *source0;\r
1308                         p1 = *source1;\r
1309                         p2 = *source2;\r
1310 \r
1311                         dest0 = source0 + destofs;\r
1312                         dest1 = source1 + destofs;\r
1313                         dest2 = source2 + destofs;\r
1314 \r
1315 //\r
1316 // only make a new tile if it is different\r
1317 //\r
1318                         if (p0 != *dest0 || p1 != *dest1 || p2 != *dest2)\r
1319                         {\r
1320                                 *dest0 = p0;\r
1321                                 *dest1 = p1;\r
1322                                 *dest2 = p2;\r
1323                                 changed = true;\r
1324                         }\r
1325                         else\r
1326                                 changed = false;\r
1327 \r
1328 //\r
1329 // if tile is on the view port\r
1330 //\r
1331                         xspot = destx+x-originxtile;\r
1332                         yspot = desty+y-originytile;\r
1333                         if (yspot < PORTTILESHIGH && xspot < PORTTILESWIDE)\r
1334                         {\r
1335                                 if (changed)\r
1336                                 {\r
1337                                         updatespot = uwidthtable[yspot]+xspot;\r
1338                                         RFL_NewTile(updatespot);\r
1339                                 }\r
1340                                 RFL_CheckForAnimTile (destx+x,desty+y);\r
1341                         }\r
1342                 }\r
1343 }\r
1344 \r
1345 //===========================================================================\r
1346 \r
1347 \r
1348 /*\r
1349 =====================\r
1350 =\r
1351 = RF_MemToMap\r
1352 =\r
1353 = Copies a string of tiles from main memory to the map,\r
1354 = accounting for animating tiles\r
1355 =\r
1356 =====================\r
1357 */\r
1358 \r
1359 void RF_MemToMap (unsigned far *source, unsigned plane,\r
1360                                   unsigned destx, unsigned desty,\r
1361                                   unsigned width, unsigned height)\r
1362 {\r
1363         int                     x,y;\r
1364         unsigned        xspot,yspot;\r
1365         unsigned        linedelta,updatespot;\r
1366         unsigned        far *dest,old,new;\r
1367         boolean         changed;\r
1368 \r
1369         RFL_RemoveAnimsInBlock (destx,desty,width,height);\r
1370 \r
1371         dest = mapsegs[plane] + mapbwidthtable[desty]/2 + destx;\r
1372 \r
1373         linedelta = mapwidth - width;\r
1374 \r
1375         for (y=0;y<height;y++,dest+=linedelta)\r
1376                 for (x=0;x<width;x++)\r
1377                 {\r
1378                         old = *dest;\r
1379                         new = *source++;\r
1380                         if (old != new)\r
1381                         {\r
1382                                 *dest = new;\r
1383                                 changed = true;\r
1384                         }\r
1385                         else\r
1386                                 changed = false;\r
1387 \r
1388                         dest++;\r
1389                         xspot = destx+x-originxtile;\r
1390                         yspot = desty+y-originytile;\r
1391                         if (yspot < PORTTILESHIGH && xspot < PORTTILESWIDE)\r
1392                         {\r
1393                                 if (changed)\r
1394                                 {\r
1395                                         updatespot = uwidthtable[yspot]+xspot;\r
1396                                         RFL_NewTile(updatespot);\r
1397                                 }\r
1398                                 RFL_CheckForAnimTile (destx+x,desty+y);\r
1399                         }\r
1400                 }\r
1401 }\r
1402 \r
1403 //===========================================================================\r
1404 \r
1405 \r
1406 /*\r
1407 =====================\r
1408 =\r
1409 = RFL_BoundNewOrigin\r
1410 =\r
1411 = Copies a string of tiles from main memory to the map,\r
1412 = accounting for animating tiles\r
1413 =\r
1414 =====================\r
1415 */\r
1416 \r
1417 void RFL_BoundNewOrigin (unsigned orgx,unsigned orgy)\r
1418 {\r
1419         int     check,edge;\r
1420 \r
1421 //\r
1422 // calculate new origin related globals\r
1423 //\r
1424         if (orgx<originxmin)\r
1425           orgx=originxmin;\r
1426         else if (orgx>originxmax)\r
1427           orgx=originxmax;\r
1428 \r
1429         if (orgy<originymin)\r
1430           orgy=originymin;\r
1431         else if (orgy>originymax)\r
1432           orgy=originymax;\r
1433 \r
1434         originxtile = orgx>>G_T_SHIFT;\r
1435         originytile = orgy>>G_T_SHIFT;\r
1436 \r
1437         for (check=0;check<vscrollblocks;check++)\r
1438         {\r
1439                 edge = vscrolledge[check];\r
1440                 if (edge>=originxtile && edge <=originxtile+10)\r
1441                 {\r
1442                         orgx = (edge+1)*TILEGLOBAL;\r
1443                         break;\r
1444                 }\r
1445                 if (edge>=originxtile+11 && edge <=originxtile+20)\r
1446                 {\r
1447                         orgx = (edge-20)*TILEGLOBAL;\r
1448                         break;\r
1449                 }\r
1450         }\r
1451 \r
1452         for (check=0;check<hscrollblocks;check++)\r
1453         {\r
1454                 edge = hscrolledge[check];\r
1455                 if (edge>=originytile && edge <=originytile+6)\r
1456                 {\r
1457                         orgy = (edge+1)*TILEGLOBAL;\r
1458                         break;\r
1459                 }\r
1460                 if (edge>=originytile+7 && edge <=originytile+13)\r
1461                 {\r
1462                         orgy = (edge-13)*TILEGLOBAL;\r
1463                         break;\r
1464                 }\r
1465         }\r
1466 \r
1467 \r
1468         RFL_CalcOriginStuff (orgx,orgy);\r
1469 }\r
1470 \r
1471 \r
1472 //===========================================================================\r
1473 \r
1474 /*\r
1475 =====================\r
1476 =\r
1477 = RF_ClearBlock\r
1478 =\r
1479 = Posts erase blocks to clear a certain area of the screen to the master\r
1480 = screen, to erase text or something draw directly to the screen\r
1481 =\r
1482 = Parameters in pixels, but erasure is byte bounded\r
1483 =\r
1484 =====================\r
1485 */\r
1486 \r
1487 void RF_ClearBlock (int x, int y, int width, int height)\r
1488 {\r
1489         eraseblocktype block;\r
1490 \r
1491 #if GRMODE == EGAGR\r
1492         block.screenx = x/8+originxscreen;\r
1493         block.screeny = y+originyscreen;\r
1494         block.width = (width+(x&7)+7)/8;\r
1495         block.height = height;\r
1496         memcpy (eraselistptr[0]++,&block,sizeof(block));\r
1497         memcpy (eraselistptr[1]++,&block,sizeof(block));\r
1498 #endif\r
1499 \r
1500 #if GRMODE == CGAGR\r
1501         block.screenx = x/4+originxscreen;\r
1502         block.screeny = y+originyscreen;\r
1503         block.width = (width+(x&3)+3)/4;\r
1504         block.height = height;\r
1505         memcpy (eraselistptr[0]++,&block,sizeof(block));\r
1506 #endif\r
1507 \r
1508 }\r
1509 \r
1510 //===========================================================================\r
1511 \r
1512 /*\r
1513 =====================\r
1514 =\r
1515 = RF_RedrawBlock\r
1516 =\r
1517 = Causes a number of tiles to be redrawn to the master screen and updated\r
1518 =\r
1519 = Parameters in pixels, but erasure is tile bounded\r
1520 =\r
1521 =====================\r
1522 */\r
1523 \r
1524 void RF_RedrawBlock (int x, int y, int width, int height)\r
1525 {\r
1526         int     xx,yy,xl,xh,yl,yh;\r
1527 \r
1528         xl=(x+panx)/16;\r
1529         xh=(x+panx+width+15)/16;\r
1530         yl=(y+pany)/16;\r
1531         yh=(y+pany+height+15)/16;\r
1532         for (yy=yl;yy<=yh;yy++)\r
1533                 for (xx=xl;xx<=xh;xx++)\r
1534                         RFL_NewTile (yy*UPDATEWIDE+xx);\r
1535 }\r
1536 \r
1537 \r
1538 //===========================================================================\r
1539 \r
1540 /*\r
1541 =====================\r
1542 =\r
1543 = RF_CalcTics\r
1544 =\r
1545 =====================\r
1546 */\r
1547 \r
1548 void RF_CalcTics (void)\r
1549 {\r
1550         long    newtime,oldtimecount;\r
1551 \r
1552 //\r
1553 // calculate tics since last refresh for adaptive timing\r
1554 //\r
1555         if (lasttimecount > TimeCount)\r
1556                 TimeCount = lasttimecount;              // if the game was paused a LONG time\r
1557 \r
1558         if (DemoMode)                                   // demo recording and playback needs\r
1559         {                                                               // to be constant\r
1560 //\r
1561 // take DEMOTICS or more tics, and modify Timecount to reflect time taken\r
1562 //\r
1563                 oldtimecount = lasttimecount;\r
1564                 while (TimeCount<oldtimecount+DEMOTICS*2)\r
1565                 ;\r
1566                 lasttimecount = oldtimecount + DEMOTICS;\r
1567                 TimeCount = lasttimecount + DEMOTICS;\r
1568                 tics = DEMOTICS;\r
1569         }\r
1570         else\r
1571         {\r
1572 //\r
1573 // non demo, so report actual time\r
1574 //\r
1575                 do\r
1576                 {\r
1577                         newtime = TimeCount;\r
1578                         tics = newtime-lasttimecount;\r
1579                 } while (tics<MINTICS);\r
1580                 lasttimecount = newtime;\r
1581 \r
1582 #ifdef PROFILE\r
1583                         strcpy (scratch,"\tTics:");\r
1584                         itoa (tics,str,10);\r
1585                         strcat (scratch,str);\r
1586                         strcat (scratch,"\n");\r
1587                         write (profilehandle,scratch,strlen(scratch));\r
1588 #endif\r
1589 \r
1590                 if (tics>MAXTICS)\r
1591                 {\r
1592                         TimeCount -= (tics-MAXTICS);\r
1593                         tics = MAXTICS;\r
1594                 }\r
1595         }\r
1596 }\r
1597 \r
1598 //===========================================================================\r
1599 \r
1600 /*\r
1601 =====================\r
1602 =\r
1603 = RF_FindFreeBuffer\r
1604 =\r
1605 = Finds the start of unused, non visable buffer space\r
1606 =\r
1607 =====================\r
1608 */\r
1609 \r
1610 unsigned RF_FindFreeBuffer (void)\r
1611 {\r
1612         unsigned        spot,i,j;\r
1613         boolean         ok;\r
1614 \r
1615         for (i=0;i<3;i++)\r
1616         {\r
1617                 spot = screenstart[i]+SCREENSPACE;\r
1618                 ok = true;\r
1619                 for (j=0;j<3;j++)\r
1620                         if (spot == screenstart[j])\r
1621                         {\r
1622                                 ok = false;\r
1623                                 break;\r
1624                         }\r
1625                 if (ok)\r
1626                         return spot;\r
1627         }\r
1628 \r
1629         return 0;       // never get here...\r
1630 }\r
1631 \r
1632 /*\r
1633 =============================================================================\r
1634 \r
1635                                         EGA specific routines\r
1636 \r
1637 =============================================================================\r
1638 */\r
1639 \r
1640 #if GRMODE == EGAGR\r
1641 \r
1642 /*\r
1643 =====================\r
1644 =\r
1645 = RF_NewPosition EGA\r
1646 =\r
1647 =====================\r
1648 */\r
1649 \r
1650 void RF_NewPosition (unsigned x, unsigned y)\r
1651 {\r
1652         int mx,my;\r
1653         byte    *page0ptr,*page1ptr;\r
1654         unsigned        updatenum;\r
1655 \r
1656         RFL_BoundNewOrigin (x,y);\r
1657 //\r
1658 // clear out all animating tiles\r
1659 //\r
1660         RFL_InitAnimList ();\r
1661 \r
1662 //\r
1663 // set up the new update arrays at base position\r
1664 //\r
1665         updatestart[0] = baseupdatestart[0];\r
1666         updatestart[1] = baseupdatestart[1];\r
1667         updateptr = updatestart[otherpage];\r
1668 \r
1669         page0ptr = updatestart[0]+PORTTILESWIDE;        // used to stick "0"s after rows\r
1670         page1ptr = updatestart[1]+PORTTILESWIDE;\r
1671 \r
1672         updatenum = 0;                          // start at first visable tile\r
1673 \r
1674         for (my=0;my<PORTTILESHIGH;my++)\r
1675         {\r
1676                 for (mx=0;mx<PORTTILESWIDE;mx++)\r
1677                 {\r
1678                         RFL_NewTile(updatenum);                 // puts "1"s in both pages\r
1679                         RFL_CheckForAnimTile(mx+originxtile,my+originytile);\r
1680                         updatenum++;\r
1681                 }\r
1682                 updatenum++;\r
1683                 *page0ptr = *page1ptr = 0; // set a 0 at end of a line of tiles\r
1684                 page0ptr+=(PORTTILESWIDE+1);\r
1685                 page1ptr+=(PORTTILESWIDE+1);\r
1686         }\r
1687         *(word *)(page0ptr-PORTTILESWIDE)\r
1688                 = *(word *)(page1ptr-PORTTILESWIDE) = UPDATETERMINATE;\r
1689 }\r
1690 \r
1691 //===========================================================================\r
1692 \r
1693 \r
1694 /*\r
1695 =====================\r
1696 =\r
1697 = RF_Scroll  EGA\r
1698 =\r
1699 = Move the origin x/y global coordinates, readjust the screen panning, and\r
1700 = scroll if needed.  If the scroll distance is greater than one tile, the\r
1701 = entire screen will be redrawn (this could be generalized, but scrolling\r
1702 = more than one tile per refresh is a bad idea!).\r
1703 =\r
1704 =====================\r
1705 */\r
1706 \r
1707 void RF_Scroll (int x, int y)\r
1708 {\r
1709         long            neworgx,neworgy;\r
1710         int                     i,deltax,deltay,absdx,absdy;\r
1711         int                     oldxt,oldyt,move,yy;\r
1712         unsigned        updatespot;\r
1713         byte            *update0,*update1;\r
1714         unsigned        oldpanx,oldpanadjust,oldscreen,newscreen,screencopy;\r
1715         int                     screenmove;\r
1716 \r
1717         oldxt = originxtile;\r
1718         oldyt = originytile;\r
1719         oldpanadjust = panadjust;\r
1720         oldpanx = panx;\r
1721 \r
1722         RFL_BoundScroll (x,y);\r
1723 \r
1724         deltax = originxtile - oldxt;\r
1725         absdx = abs(deltax);\r
1726         deltay = originytile - oldyt;\r
1727         absdy = abs(deltay);\r
1728 \r
1729         if (absdx>1 || absdy>1)\r
1730         {\r
1731         //\r
1732         // scrolled more than one tile, so start from scratch\r
1733         //\r
1734                 RF_NewPosition(originxglobal,originyglobal);\r
1735                 return;\r
1736         }\r
1737 \r
1738         if (!absdx && !absdy)\r
1739                 return;                                 // the screen has not scrolled an entire tile\r
1740 \r
1741 \r
1742 //\r
1743 // adjust screens and handle SVGA crippled compatability mode\r
1744 //\r
1745         screenmove = deltay*16*SCREENWIDTH + deltax*TILEWIDTH;\r
1746         for (i=0;i<3;i++)\r
1747         {\r
1748                 screenstart[i]+= screenmove;\r
1749                 if (compatability && screenstart[i] > (0x10000l-SCREENSPACE) )\r
1750                 {\r
1751                         //\r
1752                         // move the screen to the opposite end of the buffer\r
1753                         //\r
1754                         screencopy = screenmove>0 ? FREEEGAMEM : -FREEEGAMEM;\r
1755                         oldscreen = screenstart[i] - screenmove;\r
1756                         newscreen = oldscreen + screencopy;\r
1757                         screenstart[i] = newscreen + screenmove;\r
1758                         VW_ScreenToScreen (oldscreen,newscreen,\r
1759                                 PORTTILESWIDE*2,PORTTILESHIGH*16);\r
1760 \r
1761                         if (i==screenpage)\r
1762                                 VW_SetScreen(newscreen+oldpanadjust,oldpanx & xpanmask);\r
1763                 }\r
1764         }\r
1765         bufferofs = screenstart[otherpage];\r
1766         displayofs = screenstart[screenpage];\r
1767         masterofs = screenstart[2];\r
1768 \r
1769 \r
1770 //\r
1771 // float the update regions\r
1772 //\r
1773         move = deltax;\r
1774         if (deltay==1)\r
1775           move += UPDATEWIDE;\r
1776         else if (deltay==-1)\r
1777           move -= UPDATEWIDE;\r
1778 \r
1779         updatestart[0]+=move;\r
1780         updatestart[1]+=move;\r
1781 \r
1782 //\r
1783 // draw the new tiles just scrolled on to the master screen, and\r
1784 // mark them as needing to be copied to each screen next refreshes\r
1785 // Make sure a zero is at the end of each row in update\r
1786 //\r
1787 \r
1788         if (deltax)\r
1789         {\r
1790                 if (deltax==1)\r
1791                 {\r
1792                         RFL_NewRow (1);                 // new right row\r
1793                         RFL_RemoveAnimsOnX (originxtile-1);\r
1794                 }\r
1795                 else\r
1796                 {\r
1797                         RFL_NewRow (3);                 // new left row\r
1798                         RFL_RemoveAnimsOnX (originxtile+PORTTILESWIDE);\r
1799                 }\r
1800 \r
1801                 update0 = updatestart[0]+PORTTILESWIDE;\r
1802                 update1 = updatestart[1]+PORTTILESWIDE;\r
1803                 for     (yy=0;yy<PORTTILESHIGH;yy++)\r
1804                 {\r
1805                         *update0 = *update1 = 0;        // drop a 0 at end of each row\r
1806                         update0+=UPDATEWIDE;\r
1807                         update1+=UPDATEWIDE;\r
1808                 }\r
1809         }\r
1810 \r
1811 //----------------\r
1812 \r
1813         if (deltay)\r
1814         {\r
1815                 if (deltay==1)\r
1816                 {\r
1817                         updatespot = UPDATEWIDE*(PORTTILESHIGH-1);\r
1818                         RFL_NewRow (2);                 // new bottom row\r
1819                         RFL_RemoveAnimsOnY (originytile-1);\r
1820                 }\r
1821                 else\r
1822                 {\r
1823                         updatespot = 0;\r
1824                         RFL_NewRow (0);                 // new top row\r
1825                         RFL_RemoveAnimsOnY (originytile+PORTTILESHIGH);\r
1826                 }\r
1827 \r
1828                 *(updatestart[0]+updatespot+PORTTILESWIDE) =\r
1829                         *(updatestart[1]+updatespot+PORTTILESWIDE) = 0;\r
1830         }\r
1831 \r
1832 //----------------\r
1833 \r
1834         //\r
1835         // place a new terminator\r
1836         //\r
1837         update0 = updatestart[0]+UPDATEWIDE*PORTTILESHIGH-1;\r
1838         update1 = updatestart[1]+UPDATEWIDE*PORTTILESHIGH-1;\r
1839         *update0++ = *update1++ = 0;\r
1840         *(unsigned *)update0 = *(unsigned *)update1 = UPDATETERMINATE;\r
1841 }\r
1842 \r
1843 //===========================================================================\r
1844 \r
1845 /*\r
1846 =====================\r
1847 =\r
1848 = RF_PlaceSprite   EGA\r
1849 =\r
1850 =====================\r
1851 */\r
1852 \r
1853 void RF_PlaceSprite (void **user,unsigned globalx,unsigned globaly,\r
1854         unsigned spritenumber, drawtype draw, int priority)\r
1855 {\r
1856         spritelisttype  register *sprite,*next;\r
1857         spritetabletype far *spr;\r
1858         spritetype _seg *block;\r
1859         unsigned        shift,pixx;\r
1860         char            str[80],str2[10];\r
1861 \r
1862         if (!spritenumber || spritenumber == (unsigned)-1)\r
1863         {\r
1864                 RF_RemoveSprite (user);\r
1865                 return;\r
1866         }\r
1867 \r
1868         sprite = (spritelisttype *)*user;\r
1869 \r
1870         if      (sprite)\r
1871         {\r
1872         // sprite allready exists in the list, so we can use it's block\r
1873 \r
1874         //\r
1875         // post an erase block to both pages by copying screenx,screeny,width,height\r
1876         // both pages may not need to be erased if the sprite just changed last frame\r
1877         //\r
1878                 if (sprite->updatecount<2)\r
1879                 {\r
1880                         if (!sprite->updatecount)\r
1881                                 memcpy (eraselistptr[otherpage]++,sprite,sizeof(eraseblocktype));\r
1882                         memcpy (eraselistptr[screenpage]++,sprite,sizeof(eraseblocktype));\r
1883                 }\r
1884 \r
1885                 if (priority != sprite->priority)\r
1886                 {\r
1887                 // sprite mvoed to another priority, so unlink the old one and\r
1888                 // relink it in the new priority\r
1889 \r
1890                         next = sprite->nextsprite;                      // cut old links\r
1891                         if (next)\r
1892                                 next->prevptr = sprite->prevptr;\r
1893                         *sprite->prevptr = next;\r
1894                         goto linknewspot;\r
1895                 }\r
1896         }\r
1897         else\r
1898         {\r
1899         // this is a brand new sprite, so allocate a block from the array\r
1900 \r
1901                 if (!spritefreeptr)\r
1902                         Quit ("RF_PlaceSprite: No free spots in spritearray!");\r
1903 \r
1904                 sprite = spritefreeptr;\r
1905                 spritefreeptr = spritefreeptr->nextsprite;\r
1906 \r
1907 linknewspot:\r
1908                 next = prioritystart[priority];         // stick it in new spot\r
1909                 if (next)\r
1910                         next->prevptr = &sprite->nextsprite;\r
1911                 sprite->nextsprite = next;\r
1912                 prioritystart[priority] = sprite;\r
1913                 sprite->prevptr = &prioritystart[priority];\r
1914         }\r
1915 \r
1916 //\r
1917 // write the new info to the sprite\r
1918 //\r
1919         spr = &spritetable[spritenumber-STARTSPRITES];\r
1920         block = (spritetype _seg *)grsegs[spritenumber];\r
1921 \r
1922         if (!block)\r
1923         {\r
1924                 strcpy (str,"RF_PlaceSprite: Placed an uncached sprite:");\r
1925                 itoa (spritenumber,str2,10);\r
1926                 strcat (str,str2);\r
1927                 Quit (str);\r
1928         }\r
1929 \r
1930         globaly+=spr->orgy;\r
1931         globalx+=spr->orgx;\r
1932 \r
1933         pixx = globalx >> G_SY_SHIFT;\r
1934         if (nopan)\r
1935                 shift = 0;\r
1936         else\r
1937                 shift = (pixx&7)/2;\r
1938 \r
1939         sprite->screenx = pixx >> (G_EGASX_SHIFT-G_SY_SHIFT);\r
1940         sprite->screeny = globaly >> G_SY_SHIFT;\r
1941         sprite->width = block->width[shift];\r
1942         sprite->height = spr->height;\r
1943         sprite->grseg = spritenumber;\r
1944         sprite->sourceofs = block->sourceoffset[shift];\r
1945         sprite->planesize = block->planesize[shift];\r
1946         sprite->draw = draw;\r
1947         sprite->priority = priority;\r
1948         sprite->tilex = sprite->screenx >> SX_T_SHIFT;\r
1949         sprite->tiley = sprite->screeny >> SY_T_SHIFT;\r
1950         sprite->tilewide = ( (sprite->screenx + sprite->width -1) >> SX_T_SHIFT )\r
1951                 - sprite->tilex + 1;\r
1952         sprite->tilehigh = ( (sprite->screeny + sprite->height -1) >> SY_T_SHIFT )\r
1953                 - sprite->tiley + 1;\r
1954 \r
1955         sprite->updatecount = 2;                // draw on next two refreshes\r
1956 \r
1957 // save the sprite pointer off in the user's pointer so it can be moved\r
1958 // again later\r
1959 \r
1960         *user = sprite;\r
1961 }\r
1962 \r
1963 //===========================================================================\r
1964 \r
1965 /*\r
1966 =====================\r
1967 =\r
1968 = RF_RemoveSprite  EGA\r
1969 =\r
1970 =====================\r
1971 */\r
1972 \r
1973 void RF_RemoveSprite (void **user)\r
1974 {\r
1975         spritelisttype  *sprite,*next;\r
1976 \r
1977         sprite = (spritelisttype *)*user;\r
1978         if (!sprite)\r
1979                 return;\r
1980 \r
1981 //\r
1982 // post an erase block to both pages by copying screenx,screeny,width,height\r
1983 // both pages may not need to be erased if the sprite just changed last frame\r
1984 //\r
1985         if (sprite->updatecount<2)\r
1986         {\r
1987                 if (!sprite->updatecount)\r
1988                         memcpy (eraselistptr[otherpage]++,sprite,sizeof(eraseblocktype));\r
1989                 memcpy (eraselistptr[screenpage]++,sprite,sizeof(eraseblocktype));\r
1990         }\r
1991 \r
1992 //\r
1993 // unlink the sprite node\r
1994 //\r
1995         next = sprite->nextsprite;\r
1996         if (next)                                               // if (!next), sprite is last in chain\r
1997                 next->prevptr = sprite->prevptr;\r
1998         *sprite->prevptr = next;\r
1999 \r
2000 //\r
2001 // add it back to the free list\r
2002 //\r
2003         sprite->nextsprite = spritefreeptr;\r
2004         spritefreeptr = sprite;\r
2005 \r
2006 //\r
2007 // null the users pointer, so next time that actor gets placed, it will\r
2008 // allocate a new block\r
2009 //\r
2010 \r
2011         *user = 0;\r
2012 }\r
2013 \r
2014 \r
2015 //===========================================================================\r
2016 \r
2017 \r
2018 /*\r
2019 ====================\r
2020 =\r
2021 = RFL_EraseBlocks  EGA\r
2022 =\r
2023 = Write mode 1 should be set\r
2024 =\r
2025 ====================\r
2026 */\r
2027 \r
2028 void RFL_EraseBlocks (void)\r
2029 {\r
2030         eraseblocktype  *block,*done;\r
2031         int                     screenxh,screenyh;\r
2032         unsigned        pos,xtl,ytl,xth,yth,x,y;\r
2033         byte            *updatespot;\r
2034         unsigned        updatedelta;\r
2035         unsigned        erasecount;\r
2036 \r
2037 #ifdef PROFILE\r
2038         erasecount = 0;\r
2039 #endif\r
2040 \r
2041         block = otherpage ? &eraselist[1][0] : &eraselist[0][0];\r
2042 \r
2043         done = eraselistptr[otherpage];\r
2044 \r
2045         while (block != done)\r
2046         {\r
2047 \r
2048         //\r
2049         // clip the block to the current screen view\r
2050         //\r
2051                 block->screenx -= originxscreen;\r
2052                 block->screeny -= originyscreen;\r
2053 \r
2054                 if (block->screenx < 0)\r
2055                 {\r
2056                         block->width += block->screenx;\r
2057                         if (block->width<1)\r
2058                                 goto next;\r
2059                         block->screenx = 0;\r
2060                 }\r
2061 \r
2062                 if (block->screeny < 0)\r
2063                 {\r
2064                         block->height += block->screeny;\r
2065                         if (block->height<1)\r
2066                                 goto next;\r
2067                         block->screeny = 0;\r
2068                 }\r
2069 \r
2070                 screenxh = block->screenx + block->width;\r
2071                 screenyh = block->screeny + block->height;\r
2072 \r
2073                 if (screenxh > EGAPORTSCREENWIDE)\r
2074                 {\r
2075                         block->width = EGAPORTSCREENWIDE-block->screenx;\r
2076                         screenxh = block->screenx + block->width;\r
2077                 }\r
2078 \r
2079                 if (screenyh > PORTSCREENHIGH)\r
2080                 {\r
2081                         block->height = PORTSCREENHIGH-block->screeny;\r
2082                         screenyh = block->screeny + block->height;\r
2083                 }\r
2084 \r
2085                 if (block->width<1 || block->height<1)\r
2086                         goto next;\r
2087 \r
2088         //\r
2089         // erase the block by copying from the master screen\r
2090         //\r
2091                 pos = ylookup[block->screeny]+block->screenx;\r
2092                 VW_ScreenToScreen (masterofs+pos,bufferofs+pos,\r
2093                         block->width,block->height);\r
2094 \r
2095         //\r
2096         // put 2s in update where the block was, to force sprites to update\r
2097         //\r
2098                 xtl = block->screenx >> SX_T_SHIFT;\r
2099                 xth = (block->screenx+block->width-1) >> SX_T_SHIFT;\r
2100                 ytl = block->screeny >> SY_T_SHIFT;\r
2101                 yth = (block->screeny+block->height-1) >> SY_T_SHIFT;\r
2102 \r
2103                 updatespot = updateptr + uwidthtable[ytl] + xtl;\r
2104                 updatedelta = UPDATEWIDE - (xth-xtl+1);\r
2105 \r
2106                 for (y=ytl;y<=yth;y++)\r
2107                 {\r
2108                         for (x=xtl;x<=xth;x++)\r
2109                                 *updatespot++ = 2;\r
2110                         updatespot += updatedelta;              // down to next line\r
2111                 }\r
2112 #ifdef PROFILE\r
2113                 erasecount++;\r
2114 #endif\r
2115 \r
2116 next:\r
2117                 block++;\r
2118         }\r
2119         eraselistptr[otherpage] = otherpage ? &eraselist[1][0] : &eraselist[0][0];\r
2120 #ifdef PROFILE\r
2121         strcpy (scratch,"\tErase:");\r
2122         itoa (erasecount,str,10);\r
2123         strcat (scratch,str);\r
2124         write (profilehandle,scratch,strlen(scratch));\r
2125 #endif\r
2126 \r
2127 }\r
2128 \r
2129 \r
2130 /*\r
2131 ====================\r
2132 =\r
2133 = RFL_UpdateSprites EGA\r
2134 =\r
2135 = NOTE: Implement vertical clipping!\r
2136 =\r
2137 ====================\r
2138 */\r
2139 \r
2140 void RFL_UpdateSprites (void)\r
2141 {\r
2142         spritelisttype  *sprite;\r
2143         int     portx,porty,x,y,xtl,xth,ytl,yth;\r
2144         int     priority;\r
2145         unsigned dest;\r
2146         byte            *updatespot,*baseupdatespot;\r
2147         unsigned        updatedelta;\r
2148         unsigned        updatecount;\r
2149         unsigned        height,sourceofs;\r
2150 \r
2151 #ifdef PROFILE\r
2152         updatecount = 0;\r
2153 #endif\r
2154 \r
2155         for (priority=0;priority<PRIORITIES;priority++)\r
2156         {\r
2157                 if (priority==MASKEDTILEPRIORITY)\r
2158                         RFL_MaskForegroundTiles ();\r
2159 \r
2160                 for (sprite = prioritystart[priority]; sprite ;\r
2161                         sprite = (spritelisttype *)sprite->nextsprite)\r
2162                 {\r
2163                 //\r
2164                 // see if the sprite has any visable area in the port\r
2165                 //\r
2166 \r
2167                         portx = sprite->screenx - originxscreen;\r
2168                         porty = sprite->screeny - originyscreen;\r
2169                         xtl = portx >> SX_T_SHIFT;\r
2170                         xth = (portx + sprite->width-1) >> SX_T_SHIFT;\r
2171                         ytl = porty >> SY_T_SHIFT;\r
2172                         yth = (porty + sprite->height-1) >> SY_T_SHIFT;\r
2173 \r
2174                         if (xtl<0)\r
2175                           xtl = 0;\r
2176                         if (xth>=PORTTILESWIDE)\r
2177                           xth = PORTTILESWIDE-1;\r
2178                         if (ytl<0)\r
2179                           ytl = 0;\r
2180                         if (yth>=PORTTILESHIGH)\r
2181                           yth = PORTTILESHIGH-1;\r
2182 \r
2183                         if (xtl>xth || ytl>yth)\r
2184                                 continue;\r
2185 \r
2186                 //\r
2187                 // see if it's visable area covers any non 0 update tiles\r
2188                 //\r
2189                         updatespot = baseupdatespot = updateptr + uwidthtable[ytl] + xtl;\r
2190                         updatedelta = UPDATEWIDE - (xth-xtl+1);\r
2191 \r
2192                         if (sprite->updatecount)\r
2193                         {\r
2194                                 sprite->updatecount--;                  // the sprite was just placed,\r
2195                                 goto redraw;                                    // so draw it for sure\r
2196                         }\r
2197 \r
2198                         for (y=ytl;y<=yth;y++)\r
2199                         {\r
2200                                 for (x=xtl;x<=xth;x++)\r
2201                                         if (*updatespot++)\r
2202                                                 goto redraw;\r
2203                                 updatespot += updatedelta;              // down to next line\r
2204                         }\r
2205                         continue;                                                       // no need to update\r
2206 \r
2207 redraw:\r
2208                 //\r
2209                 // set the tiles it covers to 3, because those tiles are being\r
2210                 // updated\r
2211                 //\r
2212                         updatespot = baseupdatespot;\r
2213                         for (y=ytl;y<=yth;y++)\r
2214                         {\r
2215                                 for (x=xtl;x<=xth;x++)\r
2216                                         *updatespot++ = 3;\r
2217                                 updatespot += updatedelta;              // down to next line\r
2218                         }\r
2219                 //\r
2220                 // draw it!\r
2221                 //\r
2222                         height = sprite->height;\r
2223                         sourceofs = sprite->sourceofs;\r
2224                         if (porty<0)\r
2225                         {\r
2226                                 height += porty;                                        // clip top off\r
2227                                 sourceofs -= porty*sprite->width;\r
2228                                 porty = 0;\r
2229                         }\r
2230                         else if (porty+height>PORTSCREENHIGH)\r
2231                         {\r
2232                                 height = PORTSCREENHIGH - porty;    // clip bottom off\r
2233                         }\r
2234 \r
2235                         dest = bufferofs + ylookup[porty] + portx;\r
2236 \r
2237                         switch (sprite->draw)\r
2238                         {\r
2239                         case spritedraw:\r
2240                                 VW_MaskBlock(grsegs[sprite->grseg], sourceofs,\r
2241                                         dest,sprite->width,height,sprite->planesize);\r
2242                                 break;\r
2243 \r
2244                         case maskdraw:\r
2245                                 VW_InverseMask(grsegs[sprite->grseg], sourceofs,\r
2246                                         dest,sprite->width,height);\r
2247                                 break;\r
2248 \r
2249                         }\r
2250 #ifdef PROFILE\r
2251                         updatecount++;\r
2252 #endif\r
2253 \r
2254 \r
2255                 }\r
2256         }\r
2257 #ifdef PROFILE\r
2258         strcpy (scratch,"\tSprites:");\r
2259         itoa (updatecount,str,10);\r
2260         strcat (scratch,str);\r
2261         write (profilehandle,scratch,strlen(scratch));\r
2262 #endif\r
2263 \r
2264 }\r
2265 \r
2266 \r
2267 /*\r
2268 =====================\r
2269 =\r
2270 = RF_Refresh   EGA\r
2271 =\r
2272 = All routines will draw at the port at bufferofs, possibly copying from\r
2273 = the port at masterofs.  The EGA version then page flips, while the\r
2274 = CGA version updates the screen from the buffer port.\r
2275 =\r
2276 = Screenpage is the currently displayed page, not the one being drawn\r
2277 = Otherpage is the page to be worked with now\r
2278 =\r
2279 =====================\r
2280 */\r
2281 \r
2282 void RF_Refresh (void)\r
2283 {\r
2284         byte    *newupdate;\r
2285 \r
2286         updateptr = updatestart[otherpage];\r
2287 \r
2288         RFL_AnimateTiles ();            // DEBUG\r
2289 \r
2290 //\r
2291 // update newly scrolled on tiles and animated tiles from the master screen\r
2292 //\r
2293         EGAWRITEMODE(1);\r
2294         EGAMAPMASK(15);\r
2295         RFL_UpdateTiles ();\r
2296         RFL_EraseBlocks ();\r
2297 \r
2298 //\r
2299 // Update is all 0 except where sprites have changed or new area has\r
2300 // been scrolled on.  Go through all sprites and update the ones that cover\r
2301 // a non 0 update tile\r
2302 //\r
2303         EGAWRITEMODE(0);\r
2304         RFL_UpdateSprites ();\r
2305 \r
2306 //\r
2307 // if the main program has a refresh hook set, call their function before\r
2308 // displaying the new page\r
2309 //\r
2310         if (refreshvector)\r
2311                 refreshvector();\r
2312 \r
2313 //\r
2314 // display the changed screen\r
2315 //\r
2316         VW_SetScreen(bufferofs+panadjust,panx & xpanmask);\r
2317 \r
2318 //\r
2319 // prepare for next refresh\r
2320 //\r
2321 // Set the update array to the middle position and clear it out to all "0"s\r
2322 // with an UPDATETERMINATE at the end\r
2323 //\r
2324         updatestart[otherpage] = newupdate = baseupdatestart[otherpage];\r
2325 asm     mov     ax,ds\r
2326 asm     mov     es,ax\r
2327 asm     xor     ax,ax\r
2328 asm     mov     cx,(UPDATESCREENSIZE-2)/2\r
2329 asm     mov     di,[newupdate]\r
2330 asm     rep     stosw\r
2331 asm     mov     [WORD PTR es:di],UPDATETERMINATE\r
2332 \r
2333         screenpage ^= 1;\r
2334         otherpage ^= 1;\r
2335         bufferofs = screenstart[otherpage];\r
2336         displayofs = screenstart[screenpage];\r
2337 \r
2338 //\r
2339 // calculate tics since last refresh for adaptive timing\r
2340 //\r
2341         RF_CalcTics ();\r
2342 }\r
2343 \r
2344 #endif          // GRMODE == EGAGR\r
2345 \r
2346 /*\r
2347 =============================================================================\r
2348 \r
2349                                         CGA specific routines\r
2350 \r
2351 =============================================================================\r
2352 */\r
2353 \r
2354 #if GRMODE == CGAGR\r
2355 \r
2356 \r
2357 /*\r
2358 =====================\r
2359 =\r
2360 = RF_NewPosition   CGA\r
2361 =\r
2362 =====================\r
2363 */\r
2364 \r
2365 void RF_NewPosition (unsigned x, unsigned y)\r
2366 {\r
2367         int mx,my;\r
2368         byte    *spotptr;\r
2369         unsigned        updatenum;\r
2370 \r
2371         RFL_BoundNewOrigin (x,y);\r
2372 \r
2373 //\r
2374 // clear out all animating tiles\r
2375 //\r
2376         RFL_InitAnimList ();\r
2377 \r
2378 //\r
2379 // set up the new update arrays at base position\r
2380 //\r
2381         updateptr = baseupdateptr;\r
2382 \r
2383         spotptr = updateptr + PORTTILESWIDE;    // used to stick "0"s after rows\r
2384 \r
2385         updatenum = 0;                          // start at first visable tile\r
2386 \r
2387         for (my=0;my<PORTTILESHIGH;my++)\r
2388         {\r
2389                 for (mx=0;mx<PORTTILESWIDE;mx++)\r
2390                 {\r
2391                         RFL_NewTile(updatenum);                 // puts "1"s in both pages\r
2392                         RFL_CheckForAnimTile(mx+originxtile,my+originytile);\r
2393                         updatenum++;\r
2394                 }\r
2395                 updatenum++;\r
2396                 *spotptr = 0; // set a 0 at end of a line of tiles\r
2397                 spotptr +=(PORTTILESWIDE+1);\r
2398         }\r
2399         *(word *)(spotptr-PORTTILESWIDE) = UPDATETERMINATE;\r
2400 }\r
2401 \r
2402 \r
2403 /*\r
2404 =====================\r
2405 =\r
2406 = RF_Scroll       CGA\r
2407 =\r
2408 = Move the origin x/y global coordinates, readjust the screen panning, and\r
2409 = scroll if needed.  If the scroll distance is greater than one tile, the\r
2410 = entire screen will be redrawn (this could be generalized, but scrolling\r
2411 = more than one tile per refresh is a bad idea!).\r
2412 =\r
2413 =====================\r
2414 */\r
2415 \r
2416 void RF_Scroll (int x, int y)\r
2417 {\r
2418         long            neworgx,neworgy;\r
2419         int                     i,deltax,deltay,absdx,absdy;\r
2420         int                     oldxt,oldyt,move,yy;\r
2421         unsigned        updatespot;\r
2422         byte            *spotptr;\r
2423         unsigned        oldoriginmap,oldscreen,newscreen,screencopy;\r
2424         int                     screenmove;\r
2425 \r
2426         oldxt = originxtile;\r
2427         oldyt = originytile;\r
2428 \r
2429         RFL_BoundScroll (x,y);\r
2430 \r
2431         deltax = originxtile - oldxt;\r
2432         absdx = abs(deltax);\r
2433         deltay = originytile - oldyt;\r
2434         absdy = abs(deltay);\r
2435 \r
2436         if (absdx>1 || absdy>1)\r
2437         {\r
2438         //\r
2439         // scrolled more than one tile, so start from scratch\r
2440         //\r
2441                 RF_NewPosition(originxglobal,originyglobal);\r
2442                 return;\r
2443         }\r
2444 \r
2445         if (!absdx && !absdy)\r
2446                 return;                                 // the screen has not scrolled an entire tile\r
2447 \r
2448 \r
2449 //\r
2450 // float screens\r
2451 //\r
2452         screenmove = deltay*16*SCREENWIDTH + deltax*TILEWIDTH;\r
2453         bufferofs += screenmove;\r
2454         masterofs += screenmove;\r
2455 \r
2456 \r
2457 //\r
2458 // float the update regions\r
2459 //\r
2460         move = deltax;\r
2461         if (deltay==1)\r
2462           move += UPDATEWIDE;\r
2463         else if (deltay==-1)\r
2464           move -= UPDATEWIDE;\r
2465 \r
2466         updateptr+=move;\r
2467 \r
2468 //\r
2469 // draw the new tiles just scrolled on to the master screen, and\r
2470 // mark them as needing to be copied to each screen next refreshes\r
2471 // Make sure a zero is at the end of each row in update\r
2472 //\r
2473 \r
2474         if (deltax)\r
2475         {\r
2476                 if (deltax==1)\r
2477                 {\r
2478                         RFL_NewRow (1);                 // new right row\r
2479                         RFL_RemoveAnimsOnX (originxtile-1);\r
2480                 }\r
2481                 else\r
2482                 {\r
2483                         RFL_NewRow (3);                 // new left row\r
2484                         RFL_RemoveAnimsOnX (originxtile+PORTTILESWIDE);\r
2485                 }\r
2486 \r
2487                 spotptr = updateptr+PORTTILESWIDE;\r
2488                 for     (yy=0;yy<PORTTILESHIGH;yy++)\r
2489                 {\r
2490                         *spotptr = 0;           // drop a 0 at end of each row\r
2491                         spotptr+=UPDATEWIDE;\r
2492                 }\r
2493         }\r
2494 \r
2495 //----------------\r
2496 \r
2497         if (deltay)\r
2498         {\r
2499                 if (deltay==1)\r
2500                 {\r
2501                         RFL_NewRow (2);                 // new bottom row\r
2502                         *(updateptr+UPDATEWIDE*(PORTTILESHIGH-1)+PORTTILESWIDE) = 0;\r
2503                         RFL_RemoveAnimsOnY (originytile-1);\r
2504                 }\r
2505                 else\r
2506                 {\r
2507                         RFL_NewRow (0);                 // new top row\r
2508                         *(updateptr+PORTTILESWIDE) = 0;\r
2509                         RFL_RemoveAnimsOnY (originytile+PORTTILESHIGH);\r
2510                 }\r
2511         }\r
2512 \r
2513 //----------------\r
2514 \r
2515         //\r
2516         // place a new terminator\r
2517         //\r
2518         spotptr = updateptr+UPDATEWIDE*PORTTILESHIGH-1;\r
2519         *spotptr++ = 0;\r
2520         *(unsigned *)spotptr = UPDATETERMINATE;\r
2521 }\r
2522 \r
2523 /*\r
2524 =====================\r
2525 =\r
2526 = RF_PlaceSprite  CGA\r
2527 =\r
2528 =====================\r
2529 */\r
2530 \r
2531 void RF_PlaceSprite (void **user,unsigned globalx,unsigned globaly,\r
2532         unsigned spritenumber, drawtype draw, int priority)\r
2533 {\r
2534         spritelisttype  register *sprite,*next;\r
2535         spritetabletype far *spr;\r
2536         spritetype _seg *block;\r
2537         unsigned        shift,pixx;\r
2538         char            str[80],str2[10];\r
2539 \r
2540         if (!spritenumber || spritenumber == (unsigned)-1)\r
2541         {\r
2542                 RF_RemoveSprite (user);\r
2543                 return;\r
2544         }\r
2545 \r
2546         sprite = (spritelisttype *)*user;\r
2547 \r
2548         if      (sprite)\r
2549         {\r
2550         // sprite allready exists in the list, so we can use it's block\r
2551 \r
2552         //\r
2553         // post an erase block to erase the old position by copying\r
2554         // screenx,screeny,width,height\r
2555         //\r
2556                 if (!sprite->updatecount)               // may not have been drawn at all yet\r
2557                         memcpy (eraselistptr[0]++,sprite,sizeof(eraseblocktype));\r
2558 \r
2559                 if (priority != sprite->priority)\r
2560                 {\r
2561                 // sprite moved to another priority, so unlink the old one and\r
2562                 // relink it in the new priority\r
2563 \r
2564                         next = sprite->nextsprite;                      // cut old links\r
2565                         if (next)\r
2566                                 next->prevptr = sprite->prevptr;\r
2567                         *sprite->prevptr = next;\r
2568                         goto linknewspot;\r
2569                 }\r
2570         }\r
2571         else\r
2572         {\r
2573         // this is a brand new sprite, so allocate a block from the array\r
2574 \r
2575                 if (!spritefreeptr)\r
2576                         Quit ("RF_PlaceSprite: No free spots in spritearray!");\r
2577 \r
2578                 sprite = spritefreeptr;\r
2579                 spritefreeptr = spritefreeptr->nextsprite;\r
2580 \r
2581 linknewspot:\r
2582                 next = prioritystart[priority];         // stick it in new spot\r
2583                 if (next)\r
2584                         next->prevptr = &sprite->nextsprite;\r
2585                 sprite->nextsprite = next;\r
2586                 prioritystart[priority] = sprite;\r
2587                 sprite->prevptr = &prioritystart[priority];\r
2588         }\r
2589 \r
2590 //\r
2591 // write the new info to the sprite\r
2592 //\r
2593         spr = &spritetable[spritenumber-STARTSPRITES];\r
2594         block = (spritetype _seg *)grsegs[spritenumber];\r
2595 \r
2596         if (!block)\r
2597         {\r
2598                 strcpy (str,"RF_PlaceSprite: Placed an uncached sprite!");\r
2599                 itoa (spritenumber,str2,10);\r
2600                 strcat (str,str2);\r
2601                 Quit (str);\r
2602         }\r
2603 \r
2604 \r
2605         globaly+=spr->orgy;\r
2606         globalx+=spr->orgx;\r
2607 \r
2608         sprite->screenx = globalx >> G_CGASX_SHIFT;\r
2609         sprite->screeny = globaly >> G_SY_SHIFT;\r
2610         sprite->width = block->width[0];\r
2611         sprite->height = spr->height;\r
2612         sprite->grseg = spritenumber;\r
2613         sprite->sourceofs = block->sourceoffset[0];\r
2614         sprite->planesize = block->planesize[0];\r
2615         sprite->draw = draw;\r
2616         sprite->priority = priority;\r
2617         sprite->tilex = sprite->screenx >> SX_T_SHIFT;\r
2618         sprite->tiley = sprite->screeny >> SY_T_SHIFT;\r
2619         sprite->tilewide = ( (sprite->screenx + sprite->width -1) >> SX_T_SHIFT )\r
2620                 - sprite->tilex + 1;\r
2621         sprite->tilehigh = ( (sprite->screeny + sprite->height -1) >> SY_T_SHIFT )\r
2622                 - sprite->tiley + 1;\r
2623 \r
2624         sprite->updatecount = 1;                // draw on next refresh\r
2625 \r
2626 // save the sprite pointer off in the user's pointer so it can be moved\r
2627 // again later\r
2628 \r
2629         *user = sprite;\r
2630 }\r
2631 \r
2632 //===========================================================================\r
2633 \r
2634 /*\r
2635 =====================\r
2636 =\r
2637 = RF_RemoveSprite CGA\r
2638 =\r
2639 =====================\r
2640 */\r
2641 \r
2642 void RF_RemoveSprite (void **user)\r
2643 {\r
2644         spritelisttype  *sprite,*next;\r
2645 \r
2646         sprite = (spritelisttype *)*user;\r
2647         if (!sprite)\r
2648                 return;\r
2649 \r
2650 //\r
2651 // post an erase block to erase the old position by copying\r
2652 // screenx,screeny,width,height\r
2653 //\r
2654         if (!sprite->updatecount)\r
2655         {\r
2656                 memcpy (eraselistptr[0]++,sprite,sizeof(eraseblocktype));\r
2657         }\r
2658 \r
2659 //\r
2660 // unlink the sprite node\r
2661 //\r
2662         next = sprite->nextsprite;\r
2663         if (next)                                               // if (!next), sprite is last in chain\r
2664                 next->prevptr = sprite->prevptr;\r
2665         *sprite->prevptr = next;\r
2666 \r
2667 //\r
2668 // add it back to the free list\r
2669 //\r
2670         sprite->nextsprite = spritefreeptr;\r
2671         spritefreeptr = sprite;\r
2672 \r
2673 //\r
2674 // null the users pointer, so next time that actor gets placed, it will\r
2675 // allocate a new block\r
2676 //\r
2677 \r
2678         *user = 0;\r
2679 }\r
2680 \r
2681 \r
2682 /*\r
2683 ====================\r
2684 =\r
2685 = RFL_EraseBlocks CGA\r
2686 =\r
2687 = Write mode 1 should be set\r
2688 =\r
2689 ====================\r
2690 */\r
2691 \r
2692 void RFL_EraseBlocks (void)\r
2693 {\r
2694         eraseblocktype  *block,*done;\r
2695         int                     screenxh,screenyh;\r
2696         unsigned        pos,xtl,ytl,xth,yth,x,y;\r
2697         byte            *updatespot;\r
2698         unsigned        updatedelta;\r
2699 \r
2700         block = &eraselist[0][0];\r
2701 \r
2702         done = eraselistptr[0];\r
2703 \r
2704         while (block != done)\r
2705         {\r
2706 \r
2707         //\r
2708         // clip the block to the current screen view\r
2709         //\r
2710                 block->screenx -= originxscreen;\r
2711                 block->screeny -= originyscreen;\r
2712 \r
2713                 if (block->screenx < 0)\r
2714                 {\r
2715                         block->width += block->screenx;\r
2716                         if (block->width<1)\r
2717                                 goto next;\r
2718                         block->screenx = 0;\r
2719                 }\r
2720 \r
2721                 if (block->screeny < 0)\r
2722                 {\r
2723                         block->height += block->screeny;\r
2724                         if (block->height<1)\r
2725                                 goto next;\r
2726                         block->screeny = 0;\r
2727                 }\r
2728 \r
2729                 screenxh = block->screenx + block->width;\r
2730                 screenyh = block->screeny + block->height;\r
2731 \r
2732                 if (screenxh > CGAPORTSCREENWIDE)\r
2733                 {\r
2734                         block->width = CGAPORTSCREENWIDE-block->screenx;\r
2735                         screenxh = block->screenx + block->width;\r
2736                 }\r
2737 \r
2738                 if (screenyh > PORTSCREENHIGH)\r
2739                 {\r
2740                         block->height = PORTSCREENHIGH-block->screeny;\r
2741                         screenyh = block->screeny + block->height;\r
2742                 }\r
2743 \r
2744                 if (block->width<1 || block->height<1)\r
2745                         goto next;\r
2746 \r
2747         //\r
2748         // erase the block by copying from the master screen\r
2749         //\r
2750                 pos = ylookup[block->screeny]+block->screenx;\r
2751                 block->width = (block->width + (pos&1) + 1)& ~1;\r
2752                 pos &= ~1;                              // make sure a word copy gets used\r
2753                 VW_ScreenToScreen (masterofs+pos,bufferofs+pos,\r
2754                         block->width,block->height);\r
2755 \r
2756         //\r
2757         // put 2s in update where the block was, to force sprites to update\r
2758         //\r
2759                 xtl = block->screenx >> SX_T_SHIFT;\r
2760                 xth = (block->screenx+block->width-1) >> SX_T_SHIFT;\r
2761                 ytl = block->screeny >> SY_T_SHIFT;\r
2762                 yth = (block->screeny+block->height-1) >> SY_T_SHIFT;\r
2763 \r
2764                 updatespot = updateptr + uwidthtable[ytl] + xtl;\r
2765                 updatedelta = UPDATEWIDE - (xth-xtl+1);\r
2766 \r
2767                 for (y=ytl;y<=yth;y++)\r
2768                 {\r
2769                         for (x=xtl;x<=xth;x++)\r
2770                                 *updatespot++ = 2;\r
2771                         updatespot += updatedelta;              // down to next line\r
2772                 }\r
2773 \r
2774 next:\r
2775                 block++;\r
2776         }\r
2777         eraselistptr[0] = &eraselist[0][0];\r
2778 }\r
2779 \r
2780 \r
2781 /*\r
2782 ====================\r
2783 =\r
2784 = RFL_UpdateSprites      CGA\r
2785 =\r
2786 = NOTE: Implement vertical clipping!\r
2787 =\r
2788 ====================\r
2789 */\r
2790 \r
2791 void RFL_UpdateSprites (void)\r
2792 {\r
2793         spritelisttype  *sprite;\r
2794         int     portx,porty,x,y,xtl,xth,ytl,yth;\r
2795         int     priority;\r
2796         unsigned dest;\r
2797         byte            *updatespot,*baseupdatespot;\r
2798         unsigned        updatedelta;\r
2799 \r
2800         unsigned        updatecount;\r
2801         unsigned        height,sourceofs;\r
2802 \r
2803 #ifdef PROFILE\r
2804         updatecount = 0;\r
2805 #endif\r
2806 \r
2807 \r
2808         for (priority=0;priority<PRIORITIES;priority++)\r
2809         {\r
2810                 if (priority==MASKEDTILEPRIORITY)\r
2811                         RFL_MaskForegroundTiles ();\r
2812 \r
2813                 for (sprite = prioritystart[priority]; sprite ;\r
2814                         sprite = (spritelisttype *)sprite->nextsprite)\r
2815                 {\r
2816                 //\r
2817                 // see if the sprite has any visable area in the port\r
2818                 //\r
2819 \r
2820                         portx = sprite->screenx - originxscreen;\r
2821                         porty = sprite->screeny - originyscreen;\r
2822                         xtl = portx >> SX_T_SHIFT;\r
2823                         xth = (portx + sprite->width-1) >> SX_T_SHIFT;\r
2824                         ytl = porty >> SY_T_SHIFT;\r
2825                         yth = (porty + sprite->height-1) >> SY_T_SHIFT;\r
2826 \r
2827                         if (xtl<0)\r
2828                           xtl = 0;\r
2829                         if (xth>=PORTTILESWIDE)\r
2830                           xth = PORTTILESWIDE-1;\r
2831                         if (ytl<0)\r
2832                           ytl = 0;\r
2833                         if (yth>=PORTTILESHIGH)\r
2834                           yth = PORTTILESHIGH-1;\r
2835 \r
2836                         if (xtl>xth || ytl>yth)\r
2837                                 continue;\r
2838 \r
2839                 //\r
2840                 // see if it's visable area covers any non 0 update tiles\r
2841                 //\r
2842                         updatespot = baseupdatespot = updateptr + uwidthtable[ytl] + xtl;\r
2843                         updatedelta = UPDATEWIDE - (xth-xtl+1);\r
2844 \r
2845                         if (sprite->updatecount)\r
2846                         {\r
2847                                 sprite->updatecount--;                  // the sprite was just placed,\r
2848                                 goto redraw;                                    // so draw it for sure\r
2849                         }\r
2850 \r
2851                         for (y=ytl;y<=yth;y++)\r
2852                         {\r
2853                                 for (x=xtl;x<=xth;x++)\r
2854                                         if (*updatespot++)\r
2855                                                 goto redraw;\r
2856                                 updatespot += updatedelta;              // down to next line\r
2857                         }\r
2858                         continue;                                                       // no need to update\r
2859 \r
2860 redraw:\r
2861                 //\r
2862                 // set the tiles it covers to 3, because those tiles are being\r
2863                 // updated\r
2864                 //\r
2865                         updatespot = baseupdatespot;\r
2866                         for (y=ytl;y<=yth;y++)\r
2867                         {\r
2868                                 for (x=xtl;x<=xth;x++)\r
2869                                         *updatespot++ = 3;\r
2870                                 updatespot += updatedelta;              // down to next line\r
2871                         }\r
2872                 //\r
2873                 // draw it!\r
2874                 //\r
2875                         height = sprite->height;\r
2876                         sourceofs = sprite->sourceofs;\r
2877                         if (porty<0)\r
2878                         {\r
2879                                 height += porty;                                        // clip top off\r
2880                                 sourceofs -= porty*sprite->width;\r
2881                                 porty = 0;\r
2882                         }\r
2883                         else if (porty+height>PORTSCREENHIGH)\r
2884                         {\r
2885                                 height = PORTSCREENHIGH - porty;    // clip bottom off\r
2886                         }\r
2887 \r
2888                         dest = bufferofs + ylookup[porty] + portx;\r
2889 \r
2890                         switch (sprite->draw)\r
2891                         {\r
2892                         case spritedraw:\r
2893                                 VW_MaskBlock(grsegs[sprite->grseg], sourceofs,\r
2894                                         dest,sprite->width,height,sprite->planesize);\r
2895                                 break;\r
2896 \r
2897                         case maskdraw:\r
2898                                 VW_InverseMask(grsegs[sprite->grseg], sourceofs,\r
2899                                         dest,sprite->width,height);\r
2900                                 break;\r
2901 \r
2902                         }\r
2903 #ifdef PROFILE\r
2904                         updatecount++;\r
2905 #endif\r
2906 \r
2907 \r
2908                 }\r
2909         }\r
2910 }\r
2911 \r
2912 \r
2913 /*\r
2914 =====================\r
2915 =\r
2916 = RF_Refresh        CGA\r
2917 =\r
2918 = All routines will draw at the port at bufferofs, possibly copying from\r
2919 = the port at masterofs.  The EGA version then page flips, while the\r
2920 = CGA version updates the screen from the buffer port.\r
2921 =\r
2922 = Screenpage is the currently displayed page, not the one being drawn\r
2923 = Otherpage is the page to be worked with now\r
2924 =\r
2925 =====================\r
2926 */\r
2927 \r
2928 void RF_Refresh (void)\r
2929 {\r
2930         long newtime,oldtimecount;\r
2931 \r
2932         RFL_AnimateTiles ();\r
2933 \r
2934 //\r
2935 // update newly scrolled on tiles and animated tiles from the master screen\r
2936 //\r
2937         RFL_UpdateTiles ();\r
2938         RFL_EraseBlocks ();\r
2939 \r
2940 //\r
2941 // Update is all 0 except where sprites have changed or new area has\r
2942 // been scrolled on.  Go through all sprites and update the ones that cover\r
2943 // a non 0 update tile\r
2944 //\r
2945         RFL_UpdateSprites ();\r
2946 \r
2947 //\r
2948 // if the main program has a refresh hook set, call their function before\r
2949 // displaying the new page\r
2950 //\r
2951         if (refreshvector)\r
2952                 refreshvector();\r
2953 \r
2954 //\r
2955 // update everything to the screen\r
2956 //\r
2957         VW_CGAFullUpdate ();\r
2958 \r
2959 //\r
2960 // calculate tics since last refresh for adaptive timing\r
2961 //\r
2962         RF_CalcTics ();\r
2963 }\r
2964 \r
2965 #endif          // GRMODE == CGAGR\r