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