+++ /dev/null
-/* Reconstructed Commander Keen 4-6 Source Code\r
- * Copyright (C) 2021 K1n9_Duk3\r
- *\r
- * This file is primarily based on:\r
- * Catacomb 3-D Source Code\r
- * Copyright (C) 1993-2014 Flat Rock Software\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License along\r
- * with this program; if not, write to the Free Software Foundation, Inc.,\r
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
- */\r
-\r
-// ID_RF.C\r
-\r
-/*\r
-=============================================================================\r
-\r
-notes\r
------\r
-\r
-scrolling more than one tile / refresh forces a total redraw\r
-\r
-two overlapping sprites of equal priority can change drawing order when\r
-updated\r
-\r
-=============================================================================\r
-*/\r
-\r
-#include "ID_HEADS.H"\r
-#pragma hdrstop\r
-\r
-/*\r
-=============================================================================\r
-\r
- LOCAL CONSTANTS\r
-\r
-=============================================================================\r
-*/\r
-\r
-#define SCREENTILESWIDE 20\r
-#define SCREENTILESHIGH 13\r
-\r
-#define SCREENSPACE (SCREENWIDTH*240)\r
-#define FREEEGAMEM (0x10000l-3l*SCREENSPACE)\r
-\r
-//\r
-// the update array must have enough space for two screens that can float\r
-// up two two tiles each way\r
-//\r
-// (PORTTILESWIDE+1)*PORTTILESHIGH must be even so the arrays can be cleared\r
-// by word width instructions\r
-\r
-#define UPDATESCREENSIZE (UPDATEWIDE*PORTTILESHIGH+2)\r
-#define UPDATESPARESIZE (UPDATEWIDE*2+4)\r
-#define UPDATESIZE (UPDATESCREENSIZE+2*UPDATESPARESIZE)\r
-\r
-#define G_EGASX_SHIFT 7 // global >> ?? = screen x\r
-#define G_CGASX_SHIFT 6 // global >> ?? = screen x\r
-#define G_SY_SHIFT 4 // global >> ?? = screen y\r
-\r
-unsigned SX_T_SHIFT; // screen x >> ?? = tile EGA = 1, CGA = 2;\r
-#define SY_T_SHIFT 4 // screen y >> ?? = tile\r
-\r
-\r
-#define EGAPORTSCREENWIDE 42\r
-#define CGAPORTSCREENWIDE 84\r
-#define PORTSCREENHIGH 224\r
-\r
-#define UPDATESCREENSIZE (UPDATEWIDE*PORTTILESHIGH+2)\r
-#define UPDATESPARESIZE (UPDATEWIDE*2+4)\r
-#define UPDATESIZE (UPDATESCREENSIZE+2*UPDATESPARESIZE)\r
-\r
-#define MAXSCROLLEDGES 6\r
-\r
-/*\r
-=============================================================================\r
-\r
- LOCAL TYPES\r
-\r
-=============================================================================\r
-*/\r
-\r
-typedef struct spriteliststruct\r
-{\r
- int screenx,screeny;\r
- int width,height;\r
-\r
- unsigned grseg,sourceofs,planesize;\r
- drawtype draw;\r
- unsigned tilex,tiley,tilewide,tilehigh;\r
- int priority,updatecount;\r
- struct spriteliststruct **prevptr,*nextsprite;\r
-} spritelisttype;\r
-\r
-\r
-typedef struct\r
-{\r
- int screenx,screeny;\r
- int width,height;\r
-} eraseblocktype;\r
-\r
-\r
-typedef struct\r
-{\r
- unsigned current; // foreground tiles have high bit set\r
- int count;\r
-#ifdef KEEN6\r
- unsigned soundtile;\r
- unsigned visible;\r
- int sound;\r
-#endif\r
-} tiletype;\r
-\r
-\r
-typedef struct animtilestruct\r
-{\r
- unsigned x,y,tile;\r
- tiletype *chain;\r
- unsigned far *mapplane;\r
- struct animtilestruct **prevptr,*nexttile;\r
-} animtiletype;\r
-\r
-/*\r
-=============================================================================\r
-\r
- GLOBAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-unsigned tics;\r
-long lasttimecount;\r
-\r
-boolean compatability; // crippled refresh for wierdo SVGAs\r
-\r
-unsigned mapwidth,mapheight,mapbyteswide,mapwordswide\r
- ,mapbytesextra,mapwordsextra;\r
-unsigned mapbwidthtable[MAXMAPHEIGHT];\r
-\r
-//\r
-// Global : Actor coordinates are in this, at 1/16 th of a pixel, to allow\r
-// for fractional movement and acceleration.\r
-//\r
-// Tiles : Tile offsets from the upper left corner of the current map.\r
-//\r
-// Screen : Graphics level offsets from map origin, x in bytes, y in pixels.\r
-// originxscreen is the same spot as originxtile, just with extra precision\r
-// so graphics don't need to be done in tile boundaries.\r
-//\r
-\r
-unsigned originxglobal,originyglobal;\r
-unsigned originxtile,originytile;\r
-unsigned originxscreen,originyscreen;\r
-unsigned originmap;\r
-unsigned originxmin,originxmax,originymin,originymax;\r
-\r
-unsigned masterofs;\r
-\r
-//\r
-// Table of the offsets from bufferofs of each tile spot in the\r
-// view port. The extra wide tile should never be drawn, but the space\r
-// is needed to account for the extra 0 in the update arrays. Built by\r
-// RF_Startup\r
-//\r
-\r
-unsigned blockstarts[UPDATEWIDE*UPDATEHIGH];\r
-unsigned updatemapofs[UPDATEWIDE*UPDATEHIGH];\r
-\r
-unsigned uwidthtable[PORTTILESHIGH]; // lookup instead of multiply\r
-\r
-byte update[2][UPDATESIZE];\r
-byte *updateptr,*baseupdateptr, // current start of update window\r
- *updatestart[2],\r
- *baseupdatestart[2];\r
-\r
-/*\r
-=============================================================================\r
-\r
- LOCAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-static char scratch[20],str[80];\r
-\r
-tiletype allanims[MAXANIMTYPES];\r
-unsigned numanimchains;\r
-\r
-void (*refreshvector) (void);\r
-\r
-unsigned screenstart[3] =\r
- {0,SCREENSPACE,SCREENSPACE*2};\r
-\r
-unsigned xpanmask; // prevent panning to odd pixels\r
-\r
-unsigned screenpage; // screen currently being displayed\r
-unsigned otherpage;\r
-\r
-\r
-spritelisttype spritearray[MAXSPRITES],*prioritystart[PRIORITIES],\r
- *spritefreeptr;\r
-\r
-animtiletype animarray[MAXANIMTILES],*animhead,*animfreeptr;\r
-\r
-int animfreespot;\r
-\r
-eraseblocktype eraselist[2][MAXSPRITES],*eraselistptr[2];\r
-\r
-int hscrollblocks,vscrollblocks;\r
-int hscrolledge[MAXSCROLLEDGES],vscrolledge[MAXSCROLLEDGES];\r
-\r
-/*\r
-=============================================================================\r
-\r
- LOCAL PROTOTYPES\r
-\r
-=============================================================================\r
-*/\r
-\r
-void RFL_NewTile (unsigned updateoffset);\r
-void RFL_MaskForegroundTiles (void);\r
-void RFL_UpdateTiles (void);\r
-\r
-void RFL_BoundScroll (int x, int y);\r
-void RFL_CalcOriginStuff (long x, long y);\r
-void RFL_ClearScrollBlocks (void);\r
-void RFL_InitSpriteList (void);\r
-void RFL_InitAnimList (void);\r
-void RFL_CheckForAnimTile (unsigned x, unsigned y);\r
-void RFL_AnimateTiles (void);\r
-void RFL_RemoveAnimsOnX (unsigned x);\r
-void RFL_RemoveAnimsOnY (unsigned y);\r
-void RFL_EraseBlocks (void);\r
-void RFL_UpdateSprites (void);\r
-\r
-\r
-/*\r
-=============================================================================\r
-\r
- GRMODE INDEPENDANT ROUTINES\r
-\r
-=============================================================================\r
-*/\r
-\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_Startup\r
-=\r
-=====================\r
-*/\r
-\r
-static char *ParmStrings[] = {"comp",""};\r
-\r
-void RF_Startup (void)\r
-{\r
- int i,x,y;\r
- unsigned *blockstart;\r
-\r
-#ifndef KEEN\r
- //\r
- // Keen 4-6 store the compatability setting in the game's config file.\r
- // The setting is loaded from that file AFTER RF_Startup is executed,\r
- // making this check useless (unless the config file doesn't exist).\r
- // Instead, US_Startup now checks for that parameter after the config\r
- // file has been read.\r
- //\r
- if (grmode == EGAGR)\r
- for (i = 1;i < _argc;i++)\r
- if (US_CheckParm(_argv[i],ParmStrings) == 0)\r
- {\r
- compatability = true;\r
- break;\r
- }\r
-#endif\r
-\r
- for (i=0;i<PORTTILESHIGH;i++)\r
- uwidthtable[i] = UPDATEWIDE*i;\r
-\r
- originxmin = originymin = MAPBORDER*TILEGLOBAL;\r
-\r
- eraselistptr[0] = &eraselist[0][0];\r
- eraselistptr[1] = &eraselist[1][0];\r
-\r
-\r
-\r
- if (grmode == EGAGR)\r
- {\r
- SX_T_SHIFT = 1;\r
-\r
- baseupdatestart[0] = &update[0][UPDATESPARESIZE];\r
- baseupdatestart[1] = &update[1][UPDATESPARESIZE];\r
-\r
- screenpage = 0;\r
- otherpage = 1;\r
- displayofs = screenstart[screenpage];\r
- bufferofs = screenstart[otherpage];\r
- masterofs = screenstart[2];\r
-\r
- updateptr = baseupdatestart[otherpage];\r
-\r
- blockstart = &blockstarts[0];\r
- for (y=0;y<UPDATEHIGH;y++)\r
- for (x=0;x<UPDATEWIDE;x++)\r
- *blockstart++ = SCREENWIDTH*16*y+x*TILEWIDTH;\r
-\r
- xpanmask = 6; // dont pan to odd pixels\r
- }\r
-\r
- else if (grmode == CGAGR)\r
- {\r
- SX_T_SHIFT = 2;\r
-\r
- updateptr = baseupdateptr = &update[0][UPDATESPARESIZE];\r
-\r
- bufferofs = 0;\r
- masterofs = 0x8000;\r
-\r
- blockstart = &blockstarts[0];\r
- for (y=0;y<UPDATEHIGH;y++)\r
- for (x=0;x<UPDATEWIDE;x++)\r
- *blockstart++ = SCREENWIDTH*16*y+x*TILEWIDTH;\r
- }\r
-}\r
-\r
-\r
-\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_Shutdown\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_Shutdown (void)\r
-{\r
-\r
-}\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_FixOfs\r
-=\r
-= Sets bufferofs,displayofs, and masterofs to regular values, for the\r
-= occasions when you have moved them around manually\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_FixOfs (void)\r
-{\r
- screenstart[0] = 0;\r
- screenstart[1] = SCREENSPACE;\r
- screenstart[2] = SCREENSPACE*2;\r
-\r
- if (grmode == EGAGR)\r
- {\r
- screenpage = 0;\r
- otherpage = 1;\r
- panx = pany = pansx = pansy = panadjust = 0;\r
- displayofs = screenstart[screenpage];\r
- bufferofs = screenstart[otherpage];\r
- masterofs = screenstart[2];\r
- VW_SetScreen (displayofs,0);\r
- }\r
- else\r
- {\r
- panx = pany = pansx = pansy = panadjust = 0;\r
- bufferofs = 0;\r
- masterofs = 0x8000;\r
- }\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_NewMap\r
-=\r
-= Makes some convienient calculations based on maphead->\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_NewMap (void)\r
-{\r
- int i,x,y;\r
- unsigned spot,*table;\r
-\r
- mapwidth = mapheaderseg[mapon]->width;\r
- mapbyteswide = 2*mapwidth;\r
- mapheight = mapheaderseg[mapon]->height;\r
- mapwordsextra = mapwidth-PORTTILESWIDE;\r
- mapbytesextra = 2*mapwordsextra;\r
-\r
-//\r
-// make a lookup table for the maps left edge\r
-//\r
- if (mapheight > MAXMAPHEIGHT)\r
- Quit ("RF_NewMap: Map too tall!");\r
- spot = 0;\r
- for (i=0;i<mapheight;i++)\r
- {\r
- mapbwidthtable[i] = spot;\r
- spot += mapbyteswide;\r
- }\r
-\r
-//\r
-// fill in updatemapofs with the new width info\r
-//\r
- table = &updatemapofs[0];\r
- for (y=0;y<PORTTILESHIGH;y++)\r
- for (x=0;x<UPDATEWIDE;x++)\r
- *table++ = mapbwidthtable[y]+x*2;\r
-\r
-//\r
-// the y max value clips off the bottom half of a tile so a map that is\r
-// 13 + MAPBORDER*2 tile high will not scroll at all vertically\r
-//\r
- originxmax = (mapwidth-MAPBORDER-SCREENTILESWIDE)*TILEGLOBAL;\r
- originymax = (mapheight-MAPBORDER-SCREENTILESHIGH)*TILEGLOBAL;\r
- if (originxmax<originxmin) // for very small maps\r
- originxmax=originxmin;\r
- if (originymax<originymin)\r
- originymax=originymin;\r
-\r
-//\r
-// clear out the lists\r
-//\r
- RFL_InitSpriteList ();\r
- RFL_InitAnimList ();\r
- RFL_ClearScrollBlocks ();\r
- RF_SetScrollBlock (0,MAPBORDER-1,true);\r
- RF_SetScrollBlock (0,mapheight-MAPBORDER,true);\r
- RF_SetScrollBlock (MAPBORDER-1,0,false);\r
- RF_SetScrollBlock (mapwidth-MAPBORDER,0,false);\r
-\r
-\r
- lasttimecount = TimeCount; // setup for adaptive timing\r
- tics = 1;\r
-}\r
-\r
-//===========================================================================\r
-\r
-#ifdef KEEN6\r
-/*\r
-==========================\r
-=\r
-= RFL_CheckTileSound\r
-=\r
-= Checks if the tile plays a sound and if so adds that info to the animation\r
-=\r
-==========================\r
-*/\r
-\r
-#define NUMSOUNDTILES 2\r
-typedef struct {\r
- unsigned tilenums[NUMSOUNDTILES];\r
- int sounds[NUMSOUNDTILES];\r
-} tilesoundtype;\r
-\r
-tilesoundtype far soundtiles = {\r
- {2152|0x8000, 2208|0x8000},\r
- {SND_STOMP, SND_FLAME}\r
-};\r
-\r
-void RFL_CheckTileSound(tiletype *anim, unsigned tile)\r
-{\r
- int i;\r
-\r
- for (i=0; i<NUMSOUNDTILES; i++)\r
- {\r
- if (soundtiles.tilenums[i] == tile)\r
- {\r
- anim->soundtile = tile;\r
- anim->sound = soundtiles.sounds[i];\r
- break;\r
- }\r
- }\r
-}\r
-\r
-#endif\r
-\r
-//===========================================================================\r
-\r
-/*\r
-==========================\r
-=\r
-= RF_MarkTileGraphics\r
-=\r
-= Goes through mapplane[0/1] and marks all background/foreground tiles\r
-= needed, then follows all animation sequences to make sure animated\r
-= tiles get all the stages. Every unique animating tile is given an\r
-= entry in allanims[], so every instance of that tile will animate at the\r
-= same rate. The info plane for each animating tile will hold a pointer\r
-= into allanims[], therefore you can't have both an animating foreground\r
-= and background tile in the same spot!\r
-=\r
-==========================\r
-*/\r
-\r
-void RF_MarkTileGraphics (void)\r
-{\r
- unsigned size;\r
- int tile,next,anims,change;\r
- unsigned far *start,far *end,far *info;\r
- unsigned i,tilehigh;\r
- char str[80],str2[10];\r
-\r
- memset (allanims,0,sizeof(allanims));\r
- numanimchains = 0;\r
-\r
- size = mapwidth*mapheight;\r
-\r
-//\r
-// background plane\r
-//\r
- start = mapsegs[0];\r
- info = mapsegs[2];\r
- end = start+size;\r
- do\r
- {\r
- tile = *start++;\r
- if (tile>=0) // <0 is a tile that is never drawn\r
- {\r
- CA_MarkGrChunk(STARTTILE16+tile);\r
- if (tinf[ANIM+tile])\r
- {\r
- // this tile will animated\r
-\r
- if (tinf[SPEED+tile])\r
- {\r
- if (!tinf[ANIM+tile])\r
- {\r
- strcpy (str,"RF_MarkTileGraphics: Background anim of 0:");\r
- itoa (tile,str2,10);\r
- strcat (str,str2);\r
- Quit (str);\r
- }\r
- for (i=0;i<numanimchains;i++)\r
- if (allanims[i].current == tile)\r
- {\r
- *info = (unsigned)&allanims[i];\r
- goto nextback;\r
- }\r
-\r
- // new chain of animating tiles\r
-\r
- if (i>=MAXANIMTYPES)\r
- Quit ("RF_MarkTileGraphics: Too many unique animated tiles!");\r
- allanims[i].current = tile;\r
- allanims[i].count = tinf[SPEED+tile];\r
-#ifdef KEEN6\r
- allanims[i].visible = 0;\r
- allanims[i].sound = -1;\r
-#endif\r
- *info = (unsigned)&allanims[i];\r
- numanimchains++;\r
- }\r
-#ifdef KEEN6\r
- RFL_CheckTileSound(&allanims[i], tile);\r
-#endif\r
-\r
- anims = 0;\r
- change = (signed char)(tinf[ANIM+tile]);\r
- next = tile+change;\r
- while (change && next != tile)\r
- {\r
-#ifdef KEEN6\r
- RFL_CheckTileSound(&allanims[i], next);\r
-#endif\r
- CA_MarkGrChunk(STARTTILE16+next);\r
- change = (signed char)(tinf[ANIM+next]);\r
- next += change;\r
- if (++anims > 20)\r
- {\r
- strcpy (str,"RF_MarkTileGraphics: Unending background animation:");\r
- itoa (next,str2,10);\r
- strcat (str,str2);\r
- Quit (str);\r
- }\r
- }\r
-\r
- }\r
- }\r
-nextback:\r
- info++;\r
- } while (start<end);\r
-\r
-//\r
-// foreground plane\r
-//\r
- start = mapsegs[1];\r
- info = mapsegs[2];\r
- end = start+size;\r
- do\r
- {\r
- tile = *start++;\r
- if (tile>=0) // <0 is a tile that is never drawn\r
- {\r
- CA_MarkGrChunk(STARTTILE16M+tile);\r
- if (tinf[MANIM+tile])\r
- {\r
- // this tile will animated\r
-\r
- if (tinf[MSPEED+tile])\r
- {\r
- if (!tinf[MANIM+tile])\r
- {\r
- strcpy (str,"RF_MarkTileGraphics: Foreground anim of 0:");\r
- itoa (tile,str2,10);\r
- strcat (str,str2);\r
- Quit (str);\r
- }\r
- tilehigh = tile | 0x8000; // foreground tiles have high bit\r
- for (i=0;i<numanimchains;i++)\r
- if (allanims[i].current == tilehigh)\r
- {\r
- *info = (unsigned)&allanims[i];\r
- goto nextfront;\r
- }\r
-\r
- // new chain of animating tiles\r
-\r
- if (i>=MAXANIMTYPES)\r
- Quit ("RF_MarkTileGraphics: Too many unique animated tiles!");\r
- allanims[i].current = tilehigh;\r
- allanims[i].count = tinf[MSPEED+tile];\r
-#ifdef KEEN6\r
- allanims[i].visible = 0;\r
- allanims[i].sound = -1;\r
-#endif\r
- *info = (unsigned)&allanims[i];\r
- numanimchains++;\r
- }\r
-\r
-#ifdef KEEN6\r
- RFL_CheckTileSound(&allanims[i], tilehigh);\r
-#endif\r
- anims = 0;\r
- change = (signed char)(tinf[MANIM+tile]);\r
- next = tile+change;\r
- while (change && next != tile)\r
- {\r
-#ifdef KEEN6\r
- RFL_CheckTileSound(&allanims[i], next | 0x8000); // foreground tiles have high bit\r
-#endif\r
- CA_MarkGrChunk(STARTTILE16M+next);\r
- change = (signed char)(tinf[MANIM+next]);\r
- next += change;\r
- if (++anims > 20)\r
- {\r
- strcpy (str,"RF_MarkTileGraphics: Unending foreground animation:");\r
- itoa (next,str2,10);\r
- strcat (str,str2);\r
- Quit (str);\r
- }\r
- }\r
-\r
- }\r
- }\r
-nextfront:\r
- info++;\r
- } while (start<end);\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=========================\r
-=\r
-= RFL_InitAnimList\r
-=\r
-= Call to clear out the entire animating tile list and return all of them to\r
-= the free list.\r
-=\r
-=========================\r
-*/\r
-\r
-void RFL_InitAnimList (void)\r
-{\r
- int i;\r
-\r
- animfreeptr = &animarray[0];\r
-\r
- for (i=0;i<MAXANIMTILES-1;i++)\r
- animarray[i].nexttile = &animarray[i+1];\r
-\r
- animarray[i].nexttile = NULL;\r
-\r
- animhead = NULL; // nothing in list\r
-\r
-#ifdef KEEN6\r
- {\r
- tiletype *anim;\r
-\r
- for (anim = allanims; anim->current != 0; anim++)\r
- anim->visible = 0;\r
- }\r
-#endif\r
-}\r
-\r
-\r
-/*\r
-====================\r
-=\r
-= RFL_CheckForAnimTile\r
-=\r
-====================\r
-*/\r
-\r
-void RFL_CheckForAnimTile (unsigned x, unsigned y)\r
-{\r
- unsigned tile,offset,speed,lasttime,thistime,timemissed;\r
- unsigned far *map;\r
- animtiletype *anim,*next;\r
-\r
-// the info plane of each animating tile has a near pointer into allanims[]\r
-// which gives the current state of all concurrently animating tiles\r
-\r
- offset = mapbwidthtable[y]/2+x;\r
-\r
-//\r
-// background\r
-//\r
- map = mapsegs[0]+offset;\r
- tile = *map;\r
- if (tinf[ANIM+tile] && tinf[SPEED+tile])\r
- {\r
- if (!animfreeptr)\r
- Quit ("RF_CheckForAnimTile: No free spots in tilearray!");\r
- anim = animfreeptr;\r
- animfreeptr = animfreeptr->nexttile;\r
- next = animhead; // stick it at the start of the list\r
- animhead = anim;\r
- if (next)\r
- next->prevptr = &anim->nexttile;\r
- anim->nexttile = next;\r
- anim->prevptr = &animhead;\r
-\r
- anim->x = x;\r
- anim->y = y;\r
- anim->tile = tile;\r
- anim->mapplane = map;\r
- anim->chain = (tiletype *)*(mapsegs[2]+offset);\r
-#ifdef KEEN6\r
- anim->chain->visible++;\r
-#endif\r
- }\r
-\r
-//\r
-// foreground\r
-//\r
- map = mapsegs[1]+offset;\r
- tile = *map;\r
- if (tinf[MANIM+tile] && tinf[MSPEED+tile])\r
- {\r
- if (!animfreeptr)\r
- Quit ("RF_CheckForAnimTile: No free spots in tilearray!");\r
- anim = animfreeptr;\r
- animfreeptr = animfreeptr->nexttile;\r
- next = animhead; // stick it at the start of the list\r
- animhead = anim;\r
- if (next)\r
- next->prevptr = &anim->nexttile;\r
- anim->nexttile = next;\r
- anim->prevptr = &animhead;\r
-\r
- anim->x = x;\r
- anim->y = y;\r
- anim->tile = tile;\r
- anim->mapplane = map;\r
- anim->chain = (tiletype *)*(mapsegs[2]+offset);\r
-#ifdef KEEN6\r
- anim->chain->visible++;\r
-#endif\r
- }\r
-\r
-}\r
-\r
-\r
-/*\r
-====================\r
-=\r
-= RFL_RemoveAnimsOnX\r
-=\r
-====================\r
-*/\r
-\r
-void RFL_RemoveAnimsOnX (unsigned x)\r
-{\r
- animtiletype *current,*next;\r
-\r
- current = animhead;\r
- while (current)\r
- {\r
- if (current->x == x)\r
- {\r
-#ifdef KEEN6\r
- current->chain->visible--;\r
-#endif\r
- *(void **)current->prevptr = current->nexttile;\r
- if (current->nexttile)\r
- current->nexttile->prevptr = current->prevptr;\r
- next = current->nexttile;\r
- current->nexttile = animfreeptr;\r
- animfreeptr = current;\r
- current = next;\r
- }\r
- else\r
- current = current->nexttile;\r
- }\r
-}\r
-\r
-\r
-/*\r
-====================\r
-=\r
-= RFL_RemoveAnimsOnY\r
-=\r
-====================\r
-*/\r
-\r
-void RFL_RemoveAnimsOnY (unsigned y)\r
-{\r
- animtiletype *current,*next;\r
-\r
- current = animhead;\r
- while (current)\r
- {\r
- if (current->y == y)\r
- {\r
-#ifdef KEEN6\r
- current->chain->visible--;\r
-#endif\r
- *(void **)current->prevptr = current->nexttile;\r
- if (current->nexttile)\r
- current->nexttile->prevptr = current->prevptr;\r
- next = current->nexttile;\r
- current->nexttile = animfreeptr;\r
- animfreeptr = current;\r
- current = next;\r
- }\r
- else\r
- current = current->nexttile;\r
- }\r
-}\r
-\r
-\r
-/*\r
-====================\r
-=\r
-= RFL_RemoveAnimsInBlock\r
-=\r
-====================\r
-*/\r
-\r
-void RFL_RemoveAnimsInBlock (unsigned x, unsigned y, unsigned width, unsigned height)\r
-{\r
- animtiletype *current,*next;\r
-\r
- current = animhead;\r
- while (current)\r
- {\r
- if (current->x - x < width && current->y - y < height)\r
- {\r
-#ifdef KEEN6\r
- current->chain->visible--;\r
-#endif\r
- *(void **)current->prevptr = current->nexttile;\r
- if (current->nexttile)\r
- current->nexttile->prevptr = current->prevptr;\r
- next = current->nexttile;\r
- current->nexttile = animfreeptr;\r
- animfreeptr = current;\r
- current = next;\r
- }\r
- else\r
- current = current->nexttile;\r
- }\r
-}\r
-\r
-\r
-/*\r
-====================\r
-=\r
-= RFL_AnimateTiles\r
-=\r
-====================\r
-*/\r
-\r
-void RFL_AnimateTiles (void)\r
-{\r
- animtiletype *current;\r
- unsigned updateofs,tile,x,y;\r
- tiletype *anim;\r
-\r
-//\r
-// animate the lists of tiles\r
-//\r
- anim = &allanims[0];\r
- while (anim->current)\r
- {\r
- anim->count-=tics;\r
- while ( anim->count < 1)\r
- {\r
- if (anim->current & 0x8000)\r
- {\r
- tile = anim->current & 0x7fff;\r
- tile += (signed char)tinf[MANIM+tile];\r
- anim->count += tinf[MSPEED+tile];\r
- tile |= 0x8000;\r
- }\r
- else\r
- {\r
- tile = anim->current;\r
- tile += (signed char)tinf[ANIM+tile];\r
- anim->count += tinf[SPEED+tile];\r
- }\r
- anim->current = tile;\r
-#ifdef KEEN6\r
- if (anim->visible && anim->current == anim->soundtile && anim->sound != -1)\r
- {\r
- SD_PlaySound(anim->sound);\r
- }\r
-#endif\r
- }\r
- anim++;\r
- }\r
-\r
-\r
-//\r
-// traverse the list of animating tiles\r
-//\r
- current = animhead;\r
- while (current)\r
- {\r
- tile =current->chain->current;\r
- if ( tile != current->tile)\r
- {\r
- // tile has animated\r
- //\r
- // remove tile from master screen cache,\r
- // change a tile to its next state, set the structure up for\r
- // next animation, and post an update region to both update pages\r
- //\r
- current->tile = tile;\r
-\r
- *(current->mapplane) = tile & 0x7fff; // change in map\r
-\r
- x = current->x-originxtile;\r
- y = current->y-originytile;\r
-\r
- if (x>=PORTTILESWIDE || y>=PORTTILESHIGH)\r
- Quit ("RFL_AnimateTiles: Out of bounds!");\r
-\r
- updateofs = uwidthtable[y] + x;\r
- RFL_NewTile(updateofs); // puts "1"s in both pages\r
- }\r
- current = current->nexttile;\r
- }\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=========================\r
-=\r
-= RFL_InitSpriteList\r
-=\r
-= Call to clear out the entire sprite list and return all of them to\r
-= the free list.\r
-=\r
-=========================\r
-*/\r
-\r
-void RFL_InitSpriteList (void)\r
-{\r
- int i;\r
-\r
- spritefreeptr = &spritearray[0];\r
- for (i=0;i<MAXSPRITES-1;i++)\r
- spritearray[i].nextsprite = &spritearray[i+1];\r
-\r
- spritearray[i].nextsprite = NULL;\r
-\r
-// NULL in all priority levels\r
-\r
- memset (prioritystart,0,sizeof(prioritystart));\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=================\r
-=\r
-= RFL_CalcOriginStuff\r
-=\r
-= Calculate all the global variables for a new position\r
-= Long parms so position can be clipped to a maximum near 64k\r
-=\r
-=================\r
-*/\r
-\r
-void RFL_CalcOriginStuff (long x, long y)\r
-{\r
- originxglobal = x;\r
- originyglobal = y;\r
- originxtile = originxglobal>>G_T_SHIFT;\r
- originytile = originyglobal>>G_T_SHIFT;\r
- originxscreen = originxtile<<SX_T_SHIFT;\r
- originyscreen = originytile<<SY_T_SHIFT;\r
- originmap = mapbwidthtable[originytile] + originxtile*2;\r
-\r
-#if GRMODE == EGAGR\r
- panx = (originxglobal>>G_P_SHIFT) & 15;\r
- pansx = panx & 8;\r
- pany = pansy = (originyglobal>>G_P_SHIFT) & 15;\r
- panadjust = panx/8 + ylookup[pany];\r
-#endif\r
-\r
-#if GRMODE == CGAGR\r
- panx = (originxglobal>>G_P_SHIFT) & 15;\r
- pansx = panx & 12;\r
- pany = pansy = (originyglobal>>G_P_SHIFT) & 15;\r
- panadjust = pansx/4 + ylookup[pansy];\r
-#endif\r
-\r
-}\r
-\r
-\r
-/*\r
-=================\r
-=\r
-= RFL_ClearScrollBlocks\r
-=\r
-=================\r
-*/\r
-\r
-void RFL_ClearScrollBlocks (void)\r
-{\r
- hscrollblocks = vscrollblocks = 0;\r
-}\r
-\r
-\r
-/*\r
-=================\r
-=\r
-= RF_SetScrollBlock\r
-=\r
-= Sets a horizontal or vertical scroll block\r
-= a horizontal block is ----, meaning it blocks up/down movement\r
-=\r
-=================\r
-*/\r
-\r
-void RF_SetScrollBlock (int x, int y, boolean horizontal)\r
-{\r
- if (horizontal)\r
- {\r
- hscrolledge[hscrollblocks] = y;\r
- if (hscrollblocks++ == MAXSCROLLEDGES)\r
- Quit ("RF_SetScrollBlock: Too many horizontal scroll blocks");\r
- }\r
- else\r
- {\r
- vscrolledge[vscrollblocks] = x;\r
- if (vscrollblocks++ == MAXSCROLLEDGES)\r
- Quit ("RF_SetScrollBlock: Too many vertical scroll blocks");\r
- }\r
-}\r
-\r
-\r
-/*\r
-=================\r
-=\r
-= RFL_BoundScroll\r
-=\r
-= Bound a given x/y movement to scroll blocks\r
-=\r
-=================\r
-*/\r
-\r
-void RFL_BoundScroll (int x, int y)\r
-{\r
- int check,newxtile,newytile;\r
-\r
- originxglobal += x;\r
- originyglobal += y;\r
-\r
- newxtile= originxglobal >> G_T_SHIFT;\r
- newytile = originyglobal >> G_T_SHIFT;\r
-\r
- if (x>0)\r
- {\r
- newxtile+=SCREENTILESWIDE;\r
- for (check=0;check<vscrollblocks;check++)\r
- if (vscrolledge[check] == newxtile)\r
- {\r
- originxglobal = originxglobal&0xff00;\r
- break;\r
- }\r
- }\r
- else if (x<0)\r
- {\r
- for (check=0;check<vscrollblocks;check++)\r
- if (vscrolledge[check] == newxtile)\r
- {\r
- originxglobal = (originxglobal&0xff00)+0x100;\r
- break;\r
- }\r
- }\r
-\r
-\r
- if (y>0)\r
- {\r
- newytile+=SCREENTILESHIGH;\r
- for (check=0;check<hscrollblocks;check++)\r
- if (hscrolledge[check] == newytile)\r
- {\r
- originyglobal = originyglobal&0xff00;\r
- break;\r
- }\r
- }\r
- else if (y<0)\r
- {\r
- for (check=0;check<hscrollblocks;check++)\r
- if (hscrolledge[check] == newytile)\r
- {\r
- originyglobal = (originyglobal&0xff00)+0x100;\r
- break;\r
- }\r
- }\r
-\r
-\r
- RFL_CalcOriginStuff (originxglobal, originyglobal);\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_SetRefreshHook\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_SetRefreshHook (void (*func) (void) )\r
-{\r
- refreshvector = func;\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=================\r
-=\r
-= RFL_NewRow\r
-=\r
-= Bring a new row of tiles onto the port, spawning animating tiles\r
-=\r
-=================\r
-*/\r
-\r
-void RFL_NewRow (int dir)\r
-{\r
- unsigned count,updatespot,updatestep;\r
- int x,y,xstep,ystep;\r
-\r
- switch (dir)\r
- {\r
- case 0: // top row\r
- updatespot = 0;\r
- updatestep = 1;\r
- x = originxtile;\r
- y = originytile;\r
- xstep = 1;\r
- ystep = 0;\r
- count = PORTTILESWIDE;\r
- break;\r
-\r
- case 1: // right row\r
- updatespot = PORTTILESWIDE-1;\r
- updatestep = UPDATEWIDE;\r
- x = originxtile + PORTTILESWIDE-1;\r
- y = originytile;\r
- xstep = 0;\r
- ystep = 1;\r
- count = PORTTILESHIGH;\r
- break;\r
-\r
- case 2: // bottom row\r
- updatespot = UPDATEWIDE*(PORTTILESHIGH-1);\r
- updatestep = 1;\r
- x = originxtile;\r
- y = originytile + PORTTILESHIGH-1;\r
- xstep = 1;\r
- ystep = 0;\r
- count = PORTTILESWIDE;\r
- break;\r
-\r
- case 3: // left row\r
- updatespot = 0;\r
- updatestep = UPDATEWIDE;\r
- x = originxtile;\r
- y = originytile;\r
- xstep = 0;\r
- ystep = 1;\r
- count = PORTTILESHIGH;\r
- break;\r
- default:\r
- Quit ("RFL_NewRow: Bad dir!");\r
- }\r
-\r
- while (count--)\r
- {\r
- RFL_NewTile(updatespot);\r
- RFL_CheckForAnimTile (x,y);\r
- updatespot+=updatestep;\r
- x+=xstep;\r
- y+=ystep;\r
- }\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_ForceRefresh\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_ForceRefresh (void)\r
-{\r
- RF_NewPosition (originxglobal,originyglobal);\r
- RF_Refresh ();\r
- RF_Refresh ();\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_MapToMap\r
-=\r
-= Copies a block of tiles (all three planes) from one point\r
-= in the map to another, accounting for animating tiles\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_MapToMap (unsigned srcx, unsigned srcy,\r
- unsigned destx, unsigned desty,\r
- unsigned width, unsigned height)\r
-{\r
- int x,y;\r
- unsigned source,destofs,xspot,yspot;\r
- unsigned linedelta,p0,p1,p2,updatespot;\r
- unsigned far *source0, far *source1, far *source2;\r
- unsigned far *dest0, far *dest1, far *dest2;\r
- boolean changed;\r
-\r
- RFL_RemoveAnimsInBlock (destx,desty,width,height);\r
-\r
- source = mapbwidthtable[srcy]/2 + srcx;\r
-\r
- source0 = mapsegs[0]+source;\r
- source1 = mapsegs[1]+source;\r
- source2 = mapsegs[2]+source;\r
-\r
- destofs = mapbwidthtable[desty]/2 + destx;\r
- destofs -= source;\r
-\r
- linedelta = mapwidth - width;\r
-\r
- for (y=0;y<height;y++,source0+=linedelta,source1+=linedelta,source2+=linedelta)\r
- for (x=0;x<width;x++,source0++,source1++,source2++)\r
- {\r
- p0 = *source0;\r
- p1 = *source1;\r
- p2 = *source2;\r
-\r
- dest0 = source0 + destofs;\r
- dest1 = source1 + destofs;\r
- dest2 = source2 + destofs;\r
-\r
-//\r
-// only make a new tile if it is different\r
-//\r
- if (p0 != *dest0 || p1 != *dest1 || p2 != *dest2)\r
- {\r
- *dest0 = p0;\r
- *dest1 = p1;\r
- *dest2 = p2;\r
- changed = true;\r
- }\r
- else\r
- changed = false;\r
-\r
-//\r
-// if tile is on the view port\r
-//\r
- xspot = destx+x-originxtile;\r
- yspot = desty+y-originytile;\r
- if (yspot < PORTTILESHIGH && xspot < PORTTILESWIDE)\r
- {\r
- if (changed)\r
- {\r
- updatespot = uwidthtable[yspot]+xspot;\r
- RFL_NewTile(updatespot);\r
- }\r
- RFL_CheckForAnimTile (destx+x,desty+y);\r
- }\r
- }\r
-}\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_MemToMap\r
-=\r
-= Copies a string of tiles from main memory to the map,\r
-= accounting for animating tiles\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_MemToMap (unsigned far *source, unsigned plane,\r
- unsigned destx, unsigned desty,\r
- unsigned width, unsigned height)\r
-{\r
- int x,y;\r
- unsigned xspot,yspot;\r
- unsigned linedelta,updatespot;\r
- unsigned far *dest,old,new;\r
- boolean changed;\r
-\r
- RFL_RemoveAnimsInBlock (destx,desty,width,height);\r
-\r
- dest = mapsegs[plane] + mapbwidthtable[desty]/2 + destx;\r
-\r
- linedelta = mapwidth - width;\r
-\r
- for (y=0;y<height;y++,dest+=linedelta)\r
- for (x=0;x<width;x++)\r
- {\r
- old = *dest;\r
- new = *source++;\r
- if (old != new)\r
- {\r
- *dest = new;\r
- changed = true;\r
- }\r
- else\r
- changed = false;\r
-\r
- dest++;\r
- xspot = destx+x-originxtile;\r
- yspot = desty+y-originytile;\r
- if (yspot < PORTTILESHIGH && xspot < PORTTILESWIDE)\r
- {\r
- if (changed)\r
- {\r
- updatespot = uwidthtable[yspot]+xspot;\r
- RFL_NewTile(updatespot);\r
- }\r
- RFL_CheckForAnimTile (destx+x,desty+y);\r
- }\r
- }\r
-}\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=====================\r
-=\r
-= RFL_BoundNewOrigin\r
-=\r
-= Copies a string of tiles from main memory to the map,\r
-= accounting for animating tiles\r
-=\r
-=====================\r
-*/\r
-\r
-void RFL_BoundNewOrigin (unsigned orgx,unsigned orgy)\r
-{\r
- int check,edge;\r
-\r
-//\r
-// calculate new origin related globals\r
-//\r
- if (orgx<originxmin)\r
- orgx=originxmin;\r
- else if (orgx>originxmax)\r
- orgx=originxmax;\r
-\r
- if (orgy<originymin)\r
- orgy=originymin;\r
- else if (orgy>originymax)\r
- orgy=originymax;\r
-\r
- originxtile = orgx>>G_T_SHIFT;\r
- originytile = orgy>>G_T_SHIFT;\r
-\r
- for (check=0;check<vscrollblocks;check++)\r
- {\r
- edge = vscrolledge[check];\r
- if (edge>=originxtile && edge <=originxtile+10)\r
- {\r
- orgx = (edge+1)*TILEGLOBAL;\r
- break;\r
- }\r
- if (edge>=originxtile+11 && edge <=originxtile+20)\r
- {\r
- orgx = (edge-20)*TILEGLOBAL;\r
- break;\r
- }\r
- }\r
-\r
- for (check=0;check<hscrollblocks;check++)\r
- {\r
- edge = hscrolledge[check];\r
- if (edge>=originytile && edge <=originytile+6)\r
- {\r
- orgy = (edge+1)*TILEGLOBAL;\r
- break;\r
- }\r
- if (edge>=originytile+7 && edge <=originytile+13)\r
- {\r
- orgy = (edge-13)*TILEGLOBAL;\r
- break;\r
- }\r
- }\r
-\r
-\r
- RFL_CalcOriginStuff (orgx,orgy);\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_ClearBlock\r
-=\r
-= Posts erase blocks to clear a certain area of the screen to the master\r
-= screen, to erase text or something draw directly to the screen\r
-=\r
-= Parameters in pixels, but erasure is byte bounded\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_ClearBlock (int x, int y, int width, int height)\r
-{\r
- eraseblocktype block;\r
-\r
-#if GRMODE == EGAGR\r
- block.screenx = x/8+originxscreen;\r
- block.screeny = y+originyscreen;\r
- block.width = (width+(x&7)+7)/8;\r
- block.height = height;\r
- memcpy (eraselistptr[0]++,&block,sizeof(block));\r
- memcpy (eraselistptr[1]++,&block,sizeof(block));\r
-#endif\r
-\r
-#if GRMODE == CGAGR\r
- block.screenx = x/4+originxscreen;\r
- block.screeny = y+originyscreen;\r
- block.width = (width+(x&3)+3)/4;\r
- block.height = height;\r
- memcpy (eraselistptr[0]++,&block,sizeof(block));\r
-#endif\r
-\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_RedrawBlock\r
-=\r
-= Causes a number of tiles to be redrawn to the master screen and updated\r
-=\r
-= Parameters in pixels, but erasure is tile bounded\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_RedrawBlock (int x, int y, int width, int height)\r
-{\r
- int xx,yy,xl,xh,yl,yh;\r
-\r
- xl=(x+panx)/16;\r
- xh=(x+panx+width+15)/16;\r
- yl=(y+pany)/16;\r
- yh=(y+pany+height+15)/16;\r
- for (yy=yl;yy<=yh;yy++)\r
- for (xx=xl;xx<=xh;xx++)\r
- RFL_NewTile (yy*UPDATEWIDE+xx);\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_CalcTics\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_CalcTics (void)\r
-{\r
- long newtime,oldtimecount;\r
-\r
-//\r
-// calculate tics since last refresh for adaptive timing\r
-//\r
- if (lasttimecount > TimeCount)\r
- TimeCount = lasttimecount; // if the game was paused a LONG time\r
-\r
- if (DemoMode) // demo recording and playback needs\r
- { // to be constant\r
-//\r
-// take DEMOTICS or more tics, and modify Timecount to reflect time taken\r
-//\r
- oldtimecount = lasttimecount;\r
- while (TimeCount<oldtimecount+DEMOTICS*2)\r
- ;\r
- lasttimecount = oldtimecount + DEMOTICS;\r
- TimeCount = lasttimecount + DEMOTICS;\r
- tics = DEMOTICS;\r
- }\r
- else\r
- {\r
-//\r
-// non demo, so report actual time\r
-//\r
- do\r
- {\r
- newtime = TimeCount;\r
- tics = newtime-lasttimecount;\r
- } while (tics<MINTICS);\r
- lasttimecount = newtime;\r
-\r
-#ifdef PROFILE\r
- strcpy (scratch,"\tTics:");\r
- itoa (tics,str,10);\r
- strcat (scratch,str);\r
- strcat (scratch,"\n");\r
- write (profilehandle,scratch,strlen(scratch));\r
-#endif\r
-\r
- if (tics>MAXTICS)\r
- {\r
- TimeCount -= (tics-MAXTICS);\r
- tics = MAXTICS;\r
- }\r
- }\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_FindFreeBuffer\r
-=\r
-= Finds the start of unused, non visable buffer space\r
-=\r
-=====================\r
-*/\r
-\r
-unsigned RF_FindFreeBuffer (void)\r
-{\r
- unsigned spot,i,j;\r
- boolean ok;\r
-\r
- for (i=0;i<3;i++)\r
- {\r
- spot = screenstart[i]+SCREENSPACE;\r
- ok = true;\r
- for (j=0;j<3;j++)\r
- if (spot == screenstart[j])\r
- {\r
- ok = false;\r
- break;\r
- }\r
- if (ok)\r
- return spot;\r
- }\r
-\r
- return 0; // never get here...\r
-}\r
-\r
-/*\r
-=============================================================================\r
-\r
- EGA specific routines\r
-\r
-=============================================================================\r
-*/\r
-\r
-#if GRMODE == EGAGR\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_NewPosition EGA\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_NewPosition (unsigned x, unsigned y)\r
-{\r
- int mx,my;\r
- byte *page0ptr,*page1ptr;\r
- unsigned updatenum;\r
-\r
- RFL_BoundNewOrigin (x,y);\r
-//\r
-// clear out all animating tiles\r
-//\r
- RFL_InitAnimList ();\r
-\r
-//\r
-// set up the new update arrays at base position\r
-//\r
- updatestart[0] = baseupdatestart[0];\r
- updatestart[1] = baseupdatestart[1];\r
- updateptr = updatestart[otherpage];\r
-\r
- page0ptr = updatestart[0]+PORTTILESWIDE; // used to stick "0"s after rows\r
- page1ptr = updatestart[1]+PORTTILESWIDE;\r
-\r
- updatenum = 0; // start at first visable tile\r
-\r
- for (my=0;my<PORTTILESHIGH;my++)\r
- {\r
- for (mx=0;mx<PORTTILESWIDE;mx++)\r
- {\r
- RFL_NewTile(updatenum); // puts "1"s in both pages\r
- RFL_CheckForAnimTile(mx+originxtile,my+originytile);\r
- updatenum++;\r
- }\r
- updatenum++;\r
- *page0ptr = *page1ptr = 0; // set a 0 at end of a line of tiles\r
- page0ptr+=(PORTTILESWIDE+1);\r
- page1ptr+=(PORTTILESWIDE+1);\r
- }\r
- *(word *)(page0ptr-PORTTILESWIDE)\r
- = *(word *)(page1ptr-PORTTILESWIDE) = UPDATETERMINATE;\r
-}\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_Scroll EGA\r
-=\r
-= Move the origin x/y global coordinates, readjust the screen panning, and\r
-= scroll if needed. If the scroll distance is greater than one tile, the\r
-= entire screen will be redrawn (this could be generalized, but scrolling\r
-= more than one tile per refresh is a bad idea!).\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_Scroll (int x, int y)\r
-{\r
- long neworgx,neworgy;\r
- int i,deltax,deltay,absdx,absdy;\r
- int oldxt,oldyt,move,yy;\r
- unsigned updatespot;\r
- byte *update0,*update1;\r
- unsigned oldpanx,oldpanadjust,oldscreen,newscreen,screencopy;\r
- int screenmove;\r
-\r
- oldxt = originxtile;\r
- oldyt = originytile;\r
- oldpanadjust = panadjust;\r
- oldpanx = panx;\r
-\r
- RFL_BoundScroll (x,y);\r
-\r
- deltax = originxtile - oldxt;\r
- absdx = abs(deltax);\r
- deltay = originytile - oldyt;\r
- absdy = abs(deltay);\r
-\r
- if (absdx>1 || absdy>1)\r
- {\r
- //\r
- // scrolled more than one tile, so start from scratch\r
- //\r
- RF_NewPosition(originxglobal,originyglobal);\r
- return;\r
- }\r
-\r
- if (!absdx && !absdy)\r
- return; // the screen has not scrolled an entire tile\r
-\r
-\r
-//\r
-// adjust screens and handle SVGA crippled compatability mode\r
-//\r
- screenmove = deltay*16*SCREENWIDTH + deltax*TILEWIDTH;\r
- for (i=0;i<3;i++)\r
- {\r
- screenstart[i]+= screenmove;\r
- if (compatability && screenstart[i] > (0x10000l-SCREENSPACE) )\r
- {\r
- //\r
- // move the screen to the opposite end of the buffer\r
- //\r
- screencopy = screenmove>0 ? FREEEGAMEM : -FREEEGAMEM;\r
- oldscreen = screenstart[i] - screenmove;\r
- newscreen = oldscreen + screencopy;\r
- screenstart[i] = newscreen + screenmove;\r
- VW_ScreenToScreen (oldscreen,newscreen,\r
- PORTTILESWIDE*2,PORTTILESHIGH*16);\r
-\r
- if (i==screenpage)\r
- VW_SetScreen(newscreen+oldpanadjust,oldpanx & xpanmask);\r
- }\r
- }\r
- bufferofs = screenstart[otherpage];\r
- displayofs = screenstart[screenpage];\r
- masterofs = screenstart[2];\r
-\r
-\r
-//\r
-// float the update regions\r
-//\r
- move = deltax;\r
- if (deltay==1)\r
- move += UPDATEWIDE;\r
- else if (deltay==-1)\r
- move -= UPDATEWIDE;\r
-\r
- updatestart[0]+=move;\r
- updatestart[1]+=move;\r
-\r
-//\r
-// draw the new tiles just scrolled on to the master screen, and\r
-// mark them as needing to be copied to each screen next refreshes\r
-// Make sure a zero is at the end of each row in update\r
-//\r
-\r
- if (deltax)\r
- {\r
- if (deltax==1)\r
- {\r
- RFL_NewRow (1); // new right row\r
- RFL_RemoveAnimsOnX (originxtile-1);\r
- }\r
- else\r
- {\r
- RFL_NewRow (3); // new left row\r
- RFL_RemoveAnimsOnX (originxtile+PORTTILESWIDE);\r
- }\r
-\r
- update0 = updatestart[0]+PORTTILESWIDE;\r
- update1 = updatestart[1]+PORTTILESWIDE;\r
- for (yy=0;yy<PORTTILESHIGH;yy++)\r
- {\r
- *update0 = *update1 = 0; // drop a 0 at end of each row\r
- update0+=UPDATEWIDE;\r
- update1+=UPDATEWIDE;\r
- }\r
- }\r
-\r
-//----------------\r
-\r
- if (deltay)\r
- {\r
- if (deltay==1)\r
- {\r
- updatespot = UPDATEWIDE*(PORTTILESHIGH-1);\r
- RFL_NewRow (2); // new bottom row\r
- RFL_RemoveAnimsOnY (originytile-1);\r
- }\r
- else\r
- {\r
- updatespot = 0;\r
- RFL_NewRow (0); // new top row\r
- RFL_RemoveAnimsOnY (originytile+PORTTILESHIGH);\r
- }\r
-\r
- *(updatestart[0]+updatespot+PORTTILESWIDE) =\r
- *(updatestart[1]+updatespot+PORTTILESWIDE) = 0;\r
- }\r
-\r
-//----------------\r
-\r
- //\r
- // place a new terminator\r
- //\r
- update0 = updatestart[0]+UPDATEWIDE*PORTTILESHIGH-1;\r
- update1 = updatestart[1]+UPDATEWIDE*PORTTILESHIGH-1;\r
- *update0++ = *update1++ = 0;\r
- *(unsigned *)update0 = *(unsigned *)update1 = UPDATETERMINATE;\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_PlaceSprite EGA\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_PlaceSprite (void **user,unsigned globalx,unsigned globaly,\r
- unsigned spritenumber, drawtype draw, int priority)\r
-{\r
- spritelisttype register *sprite,*next;\r
- spritetabletype far *spr;\r
- spritetype _seg *block;\r
- unsigned shift,pixx;\r
- char str[80],str2[10];\r
-\r
- if (!spritenumber || spritenumber == (unsigned)-1)\r
- {\r
- RF_RemoveSprite (user);\r
- return;\r
- }\r
-\r
- sprite = (spritelisttype *)*user;\r
-\r
- if (sprite)\r
- {\r
- // sprite allready exists in the list, so we can use it's block\r
-\r
- //\r
- // post an erase block to both pages by copying screenx,screeny,width,height\r
- // both pages may not need to be erased if the sprite just changed last frame\r
- //\r
- if (sprite->updatecount<2)\r
- {\r
- if (!sprite->updatecount)\r
- memcpy (eraselistptr[otherpage]++,sprite,sizeof(eraseblocktype));\r
- memcpy (eraselistptr[screenpage]++,sprite,sizeof(eraseblocktype));\r
- }\r
-\r
- if (priority != sprite->priority)\r
- {\r
- // sprite mvoed to another priority, so unlink the old one and\r
- // relink it in the new priority\r
-\r
- next = sprite->nextsprite; // cut old links\r
- if (next)\r
- next->prevptr = sprite->prevptr;\r
- *sprite->prevptr = next;\r
- goto linknewspot;\r
- }\r
- }\r
- else\r
- {\r
- // this is a brand new sprite, so allocate a block from the array\r
-\r
- if (!spritefreeptr)\r
- Quit ("RF_PlaceSprite: No free spots in spritearray!");\r
-\r
- sprite = spritefreeptr;\r
- spritefreeptr = spritefreeptr->nextsprite;\r
-\r
-linknewspot:\r
- next = prioritystart[priority]; // stick it in new spot\r
- if (next)\r
- next->prevptr = &sprite->nextsprite;\r
- sprite->nextsprite = next;\r
- prioritystart[priority] = sprite;\r
- sprite->prevptr = &prioritystart[priority];\r
- }\r
-\r
-//\r
-// write the new info to the sprite\r
-//\r
- spr = &spritetable[spritenumber-STARTSPRITES];\r
- block = (spritetype _seg *)grsegs[spritenumber];\r
-\r
- if (!block)\r
- {\r
- strcpy (str,"RF_PlaceSprite: Placed an uncached sprite:");\r
- itoa (spritenumber,str2,10);\r
- strcat (str,str2);\r
- Quit (str);\r
- }\r
-\r
- globaly+=spr->orgy;\r
- globalx+=spr->orgx;\r
-\r
- pixx = globalx >> G_SY_SHIFT;\r
- if (nopan)\r
- shift = 0;\r
- else\r
- shift = (pixx&7)/2;\r
-\r
- sprite->screenx = pixx >> (G_EGASX_SHIFT-G_SY_SHIFT);\r
- sprite->screeny = globaly >> G_SY_SHIFT;\r
- sprite->width = block->width[shift];\r
- sprite->height = spr->height;\r
- sprite->grseg = spritenumber;\r
- sprite->sourceofs = block->sourceoffset[shift];\r
- sprite->planesize = block->planesize[shift];\r
- sprite->draw = draw;\r
- sprite->priority = priority;\r
- sprite->tilex = sprite->screenx >> SX_T_SHIFT;\r
- sprite->tiley = sprite->screeny >> SY_T_SHIFT;\r
- sprite->tilewide = ( (sprite->screenx + sprite->width -1) >> SX_T_SHIFT )\r
- - sprite->tilex + 1;\r
- sprite->tilehigh = ( (sprite->screeny + sprite->height -1) >> SY_T_SHIFT )\r
- - sprite->tiley + 1;\r
-\r
- sprite->updatecount = 2; // draw on next two refreshes\r
-\r
-// save the sprite pointer off in the user's pointer so it can be moved\r
-// again later\r
-\r
- *user = sprite;\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_RemoveSprite EGA\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_RemoveSprite (void **user)\r
-{\r
- spritelisttype *sprite,*next;\r
-\r
- sprite = (spritelisttype *)*user;\r
- if (!sprite)\r
- return;\r
-\r
-//\r
-// post an erase block to both pages by copying screenx,screeny,width,height\r
-// both pages may not need to be erased if the sprite just changed last frame\r
-//\r
- if (sprite->updatecount<2)\r
- {\r
- if (!sprite->updatecount)\r
- memcpy (eraselistptr[otherpage]++,sprite,sizeof(eraseblocktype));\r
- memcpy (eraselistptr[screenpage]++,sprite,sizeof(eraseblocktype));\r
- }\r
-\r
-//\r
-// unlink the sprite node\r
-//\r
- next = sprite->nextsprite;\r
- if (next) // if (!next), sprite is last in chain\r
- next->prevptr = sprite->prevptr;\r
- *sprite->prevptr = next;\r
-\r
-//\r
-// add it back to the free list\r
-//\r
- sprite->nextsprite = spritefreeptr;\r
- spritefreeptr = sprite;\r
-\r
-//\r
-// null the users pointer, so next time that actor gets placed, it will\r
-// allocate a new block\r
-//\r
-\r
- *user = 0;\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-====================\r
-=\r
-= RFL_EraseBlocks EGA\r
-=\r
-= Write mode 1 should be set\r
-=\r
-====================\r
-*/\r
-\r
-void RFL_EraseBlocks (void)\r
-{\r
- eraseblocktype *block,*done;\r
- int screenxh,screenyh;\r
- unsigned pos,xtl,ytl,xth,yth,x,y;\r
- byte *updatespot;\r
- unsigned updatedelta;\r
- unsigned erasecount;\r
-\r
-#ifdef PROFILE\r
- erasecount = 0;\r
-#endif\r
-\r
- block = otherpage ? &eraselist[1][0] : &eraselist[0][0];\r
-\r
- done = eraselistptr[otherpage];\r
-\r
- while (block != done)\r
- {\r
-\r
- //\r
- // clip the block to the current screen view\r
- //\r
- block->screenx -= originxscreen;\r
- block->screeny -= originyscreen;\r
-\r
- if (block->screenx < 0)\r
- {\r
- block->width += block->screenx;\r
- if (block->width<1)\r
- goto next;\r
- block->screenx = 0;\r
- }\r
-\r
- if (block->screeny < 0)\r
- {\r
- block->height += block->screeny;\r
- if (block->height<1)\r
- goto next;\r
- block->screeny = 0;\r
- }\r
-\r
- screenxh = block->screenx + block->width;\r
- screenyh = block->screeny + block->height;\r
-\r
- if (screenxh > EGAPORTSCREENWIDE)\r
- {\r
- block->width = EGAPORTSCREENWIDE-block->screenx;\r
- screenxh = block->screenx + block->width;\r
- }\r
-\r
- if (screenyh > PORTSCREENHIGH)\r
- {\r
- block->height = PORTSCREENHIGH-block->screeny;\r
- screenyh = block->screeny + block->height;\r
- }\r
-\r
- if (block->width<1 || block->height<1)\r
- goto next;\r
-\r
- //\r
- // erase the block by copying from the master screen\r
- //\r
- pos = ylookup[block->screeny]+block->screenx;\r
- VW_ScreenToScreen (masterofs+pos,bufferofs+pos,\r
- block->width,block->height);\r
-\r
- //\r
- // put 2s in update where the block was, to force sprites to update\r
- //\r
- xtl = block->screenx >> SX_T_SHIFT;\r
- xth = (block->screenx+block->width-1) >> SX_T_SHIFT;\r
- ytl = block->screeny >> SY_T_SHIFT;\r
- yth = (block->screeny+block->height-1) >> SY_T_SHIFT;\r
-\r
- updatespot = updateptr + uwidthtable[ytl] + xtl;\r
- updatedelta = UPDATEWIDE - (xth-xtl+1);\r
-\r
- for (y=ytl;y<=yth;y++)\r
- {\r
- for (x=xtl;x<=xth;x++)\r
- *updatespot++ = 2;\r
- updatespot += updatedelta; // down to next line\r
- }\r
-#ifdef PROFILE\r
- erasecount++;\r
-#endif\r
-\r
-next:\r
- block++;\r
- }\r
- eraselistptr[otherpage] = otherpage ? &eraselist[1][0] : &eraselist[0][0];\r
-#ifdef PROFILE\r
- strcpy (scratch,"\tErase:");\r
- itoa (erasecount,str,10);\r
- strcat (scratch,str);\r
- write (profilehandle,scratch,strlen(scratch));\r
-#endif\r
-\r
-}\r
-\r
-\r
-/*\r
-====================\r
-=\r
-= RFL_UpdateSprites EGA\r
-=\r
-= NOTE: Implement vertical clipping!\r
-=\r
-====================\r
-*/\r
-\r
-void RFL_UpdateSprites (void)\r
-{\r
- spritelisttype *sprite;\r
- int portx,porty,x,y,xtl,xth,ytl,yth;\r
- int priority;\r
- unsigned dest;\r
- byte *updatespot,*baseupdatespot;\r
- unsigned updatedelta;\r
- unsigned updatecount;\r
- unsigned height,sourceofs;\r
-\r
-#ifdef PROFILE\r
- updatecount = 0;\r
-#endif\r
-\r
- for (priority=0;priority<PRIORITIES;priority++)\r
- {\r
- if (priority==MASKEDTILEPRIORITY)\r
- RFL_MaskForegroundTiles ();\r
-\r
- for (sprite = prioritystart[priority]; sprite ;\r
- sprite = (spritelisttype *)sprite->nextsprite)\r
- {\r
- //\r
- // see if the sprite has any visable area in the port\r
- //\r
-\r
- portx = sprite->screenx - originxscreen;\r
- porty = sprite->screeny - originyscreen;\r
- xtl = portx >> SX_T_SHIFT;\r
- xth = (portx + sprite->width-1) >> SX_T_SHIFT;\r
- ytl = porty >> SY_T_SHIFT;\r
- yth = (porty + sprite->height-1) >> SY_T_SHIFT;\r
-\r
- if (xtl<0)\r
- xtl = 0;\r
- if (xth>=PORTTILESWIDE)\r
- xth = PORTTILESWIDE-1;\r
- if (ytl<0)\r
- ytl = 0;\r
- if (yth>=PORTTILESHIGH)\r
- yth = PORTTILESHIGH-1;\r
-\r
- if (xtl>xth || ytl>yth)\r
- continue;\r
-\r
- //\r
- // see if it's visable area covers any non 0 update tiles\r
- //\r
- updatespot = baseupdatespot = updateptr + uwidthtable[ytl] + xtl;\r
- updatedelta = UPDATEWIDE - (xth-xtl+1);\r
-\r
- if (sprite->updatecount)\r
- {\r
- sprite->updatecount--; // the sprite was just placed,\r
- goto redraw; // so draw it for sure\r
- }\r
-\r
- for (y=ytl;y<=yth;y++)\r
- {\r
- for (x=xtl;x<=xth;x++)\r
- if (*updatespot++)\r
- goto redraw;\r
- updatespot += updatedelta; // down to next line\r
- }\r
- continue; // no need to update\r
-\r
-redraw:\r
- //\r
- // set the tiles it covers to 3, because those tiles are being\r
- // updated\r
- //\r
- updatespot = baseupdatespot;\r
- for (y=ytl;y<=yth;y++)\r
- {\r
- for (x=xtl;x<=xth;x++)\r
- *updatespot++ = 3;\r
- updatespot += updatedelta; // down to next line\r
- }\r
- //\r
- // draw it!\r
- //\r
- height = sprite->height;\r
- sourceofs = sprite->sourceofs;\r
- if (porty<0)\r
- {\r
- height += porty; // clip top off\r
- sourceofs -= porty*sprite->width;\r
- porty = 0;\r
- }\r
- else if (porty+height>PORTSCREENHIGH)\r
- {\r
- height = PORTSCREENHIGH - porty; // clip bottom off\r
- }\r
-\r
- dest = bufferofs + ylookup[porty] + portx;\r
-\r
- switch (sprite->draw)\r
- {\r
- case spritedraw:\r
- VW_MaskBlock(grsegs[sprite->grseg], sourceofs,\r
- dest,sprite->width,height,sprite->planesize);\r
- break;\r
-\r
- case maskdraw:\r
- VW_InverseMask(grsegs[sprite->grseg], sourceofs,\r
- dest,sprite->width,height);\r
- break;\r
-\r
- }\r
-#ifdef PROFILE\r
- updatecount++;\r
-#endif\r
-\r
-\r
- }\r
- }\r
-#ifdef PROFILE\r
- strcpy (scratch,"\tSprites:");\r
- itoa (updatecount,str,10);\r
- strcat (scratch,str);\r
- write (profilehandle,scratch,strlen(scratch));\r
-#endif\r
-\r
-}\r
-\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_Refresh EGA\r
-=\r
-= All routines will draw at the port at bufferofs, possibly copying from\r
-= the port at masterofs. The EGA version then page flips, while the\r
-= CGA version updates the screen from the buffer port.\r
-=\r
-= Screenpage is the currently displayed page, not the one being drawn\r
-= Otherpage is the page to be worked with now\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_Refresh (void)\r
-{\r
- byte *newupdate;\r
-\r
- updateptr = updatestart[otherpage];\r
-\r
- RFL_AnimateTiles (); // DEBUG\r
-\r
-//\r
-// update newly scrolled on tiles and animated tiles from the master screen\r
-//\r
- EGAWRITEMODE(1);\r
- EGAMAPMASK(15);\r
- RFL_UpdateTiles ();\r
- RFL_EraseBlocks ();\r
-\r
-//\r
-// Update is all 0 except where sprites have changed or new area has\r
-// been scrolled on. Go through all sprites and update the ones that cover\r
-// a non 0 update tile\r
-//\r
- EGAWRITEMODE(0);\r
- RFL_UpdateSprites ();\r
-\r
-//\r
-// if the main program has a refresh hook set, call their function before\r
-// displaying the new page\r
-//\r
- if (refreshvector)\r
- refreshvector();\r
-\r
-//\r
-// display the changed screen\r
-//\r
- VW_SetScreen(bufferofs+panadjust,panx & xpanmask);\r
-\r
-//\r
-// prepare for next refresh\r
-//\r
-// Set the update array to the middle position and clear it out to all "0"s\r
-// with an UPDATETERMINATE at the end\r
-//\r
- updatestart[otherpage] = newupdate = baseupdatestart[otherpage];\r
-asm mov ax,ds\r
-asm mov es,ax\r
-asm xor ax,ax\r
-asm mov cx,(UPDATESCREENSIZE-2)/2\r
-asm mov di,[newupdate]\r
-asm rep stosw\r
-asm mov [WORD PTR es:di],UPDATETERMINATE\r
-\r
- screenpage ^= 1;\r
- otherpage ^= 1;\r
- bufferofs = screenstart[otherpage];\r
- displayofs = screenstart[screenpage];\r
-\r
-//\r
-// calculate tics since last refresh for adaptive timing\r
-//\r
- RF_CalcTics ();\r
-}\r
-\r
-#endif // GRMODE == EGAGR\r
-\r
-/*\r
-=============================================================================\r
-\r
- CGA specific routines\r
-\r
-=============================================================================\r
-*/\r
-\r
-#if GRMODE == CGAGR\r
-\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_NewPosition CGA\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_NewPosition (unsigned x, unsigned y)\r
-{\r
- int mx,my;\r
- byte *spotptr;\r
- unsigned updatenum;\r
-\r
- RFL_BoundNewOrigin (x,y);\r
-\r
-//\r
-// clear out all animating tiles\r
-//\r
- RFL_InitAnimList ();\r
-\r
-//\r
-// set up the new update arrays at base position\r
-//\r
- updateptr = baseupdateptr;\r
-\r
- spotptr = updateptr + PORTTILESWIDE; // used to stick "0"s after rows\r
-\r
- updatenum = 0; // start at first visable tile\r
-\r
- for (my=0;my<PORTTILESHIGH;my++)\r
- {\r
- for (mx=0;mx<PORTTILESWIDE;mx++)\r
- {\r
- RFL_NewTile(updatenum); // puts "1"s in both pages\r
- RFL_CheckForAnimTile(mx+originxtile,my+originytile);\r
- updatenum++;\r
- }\r
- updatenum++;\r
- *spotptr = 0; // set a 0 at end of a line of tiles\r
- spotptr +=(PORTTILESWIDE+1);\r
- }\r
- *(word *)(spotptr-PORTTILESWIDE) = UPDATETERMINATE;\r
-}\r
-\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_Scroll CGA\r
-=\r
-= Move the origin x/y global coordinates, readjust the screen panning, and\r
-= scroll if needed. If the scroll distance is greater than one tile, the\r
-= entire screen will be redrawn (this could be generalized, but scrolling\r
-= more than one tile per refresh is a bad idea!).\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_Scroll (int x, int y)\r
-{\r
- long neworgx,neworgy;\r
- int i,deltax,deltay,absdx,absdy;\r
- int oldxt,oldyt,move,yy;\r
- unsigned updatespot;\r
- byte *spotptr;\r
- unsigned oldoriginmap,oldscreen,newscreen,screencopy;\r
- int screenmove;\r
-\r
- oldxt = originxtile;\r
- oldyt = originytile;\r
-\r
- RFL_BoundScroll (x,y);\r
-\r
- deltax = originxtile - oldxt;\r
- absdx = abs(deltax);\r
- deltay = originytile - oldyt;\r
- absdy = abs(deltay);\r
-\r
- if (absdx>1 || absdy>1)\r
- {\r
- //\r
- // scrolled more than one tile, so start from scratch\r
- //\r
- RF_NewPosition(originxglobal,originyglobal);\r
- return;\r
- }\r
-\r
- if (!absdx && !absdy)\r
- return; // the screen has not scrolled an entire tile\r
-\r
-\r
-//\r
-// float screens\r
-//\r
- screenmove = deltay*16*SCREENWIDTH + deltax*TILEWIDTH;\r
- bufferofs += screenmove;\r
- masterofs += screenmove;\r
-\r
-\r
-//\r
-// float the update regions\r
-//\r
- move = deltax;\r
- if (deltay==1)\r
- move += UPDATEWIDE;\r
- else if (deltay==-1)\r
- move -= UPDATEWIDE;\r
-\r
- updateptr+=move;\r
-\r
-//\r
-// draw the new tiles just scrolled on to the master screen, and\r
-// mark them as needing to be copied to each screen next refreshes\r
-// Make sure a zero is at the end of each row in update\r
-//\r
-\r
- if (deltax)\r
- {\r
- if (deltax==1)\r
- {\r
- RFL_NewRow (1); // new right row\r
- RFL_RemoveAnimsOnX (originxtile-1);\r
- }\r
- else\r
- {\r
- RFL_NewRow (3); // new left row\r
- RFL_RemoveAnimsOnX (originxtile+PORTTILESWIDE);\r
- }\r
-\r
- spotptr = updateptr+PORTTILESWIDE;\r
- for (yy=0;yy<PORTTILESHIGH;yy++)\r
- {\r
- *spotptr = 0; // drop a 0 at end of each row\r
- spotptr+=UPDATEWIDE;\r
- }\r
- }\r
-\r
-//----------------\r
-\r
- if (deltay)\r
- {\r
- if (deltay==1)\r
- {\r
- RFL_NewRow (2); // new bottom row\r
- *(updateptr+UPDATEWIDE*(PORTTILESHIGH-1)+PORTTILESWIDE) = 0;\r
- RFL_RemoveAnimsOnY (originytile-1);\r
- }\r
- else\r
- {\r
- RFL_NewRow (0); // new top row\r
- *(updateptr+PORTTILESWIDE) = 0;\r
- RFL_RemoveAnimsOnY (originytile+PORTTILESHIGH);\r
- }\r
- }\r
-\r
-//----------------\r
-\r
- //\r
- // place a new terminator\r
- //\r
- spotptr = updateptr+UPDATEWIDE*PORTTILESHIGH-1;\r
- *spotptr++ = 0;\r
- *(unsigned *)spotptr = UPDATETERMINATE;\r
-}\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_PlaceSprite CGA\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_PlaceSprite (void **user,unsigned globalx,unsigned globaly,\r
- unsigned spritenumber, drawtype draw, int priority)\r
-{\r
- spritelisttype register *sprite,*next;\r
- spritetabletype far *spr;\r
- spritetype _seg *block;\r
- unsigned shift,pixx;\r
- char str[80],str2[10];\r
-\r
- if (!spritenumber || spritenumber == (unsigned)-1)\r
- {\r
- RF_RemoveSprite (user);\r
- return;\r
- }\r
-\r
- sprite = (spritelisttype *)*user;\r
-\r
- if (sprite)\r
- {\r
- // sprite allready exists in the list, so we can use it's block\r
-\r
- //\r
- // post an erase block to erase the old position by copying\r
- // screenx,screeny,width,height\r
- //\r
- if (!sprite->updatecount) // may not have been drawn at all yet\r
- memcpy (eraselistptr[0]++,sprite,sizeof(eraseblocktype));\r
-\r
- if (priority != sprite->priority)\r
- {\r
- // sprite moved to another priority, so unlink the old one and\r
- // relink it in the new priority\r
-\r
- next = sprite->nextsprite; // cut old links\r
- if (next)\r
- next->prevptr = sprite->prevptr;\r
- *sprite->prevptr = next;\r
- goto linknewspot;\r
- }\r
- }\r
- else\r
- {\r
- // this is a brand new sprite, so allocate a block from the array\r
-\r
- if (!spritefreeptr)\r
- Quit ("RF_PlaceSprite: No free spots in spritearray!");\r
-\r
- sprite = spritefreeptr;\r
- spritefreeptr = spritefreeptr->nextsprite;\r
-\r
-linknewspot:\r
- next = prioritystart[priority]; // stick it in new spot\r
- if (next)\r
- next->prevptr = &sprite->nextsprite;\r
- sprite->nextsprite = next;\r
- prioritystart[priority] = sprite;\r
- sprite->prevptr = &prioritystart[priority];\r
- }\r
-\r
-//\r
-// write the new info to the sprite\r
-//\r
- spr = &spritetable[spritenumber-STARTSPRITES];\r
- block = (spritetype _seg *)grsegs[spritenumber];\r
-\r
- if (!block)\r
- {\r
- strcpy (str,"RF_PlaceSprite: Placed an uncached sprite!");\r
- itoa (spritenumber,str2,10);\r
- strcat (str,str2);\r
- Quit (str);\r
- }\r
-\r
-\r
- globaly+=spr->orgy;\r
- globalx+=spr->orgx;\r
-\r
- sprite->screenx = globalx >> G_CGASX_SHIFT;\r
- sprite->screeny = globaly >> G_SY_SHIFT;\r
- sprite->width = block->width[0];\r
- sprite->height = spr->height;\r
- sprite->grseg = spritenumber;\r
- sprite->sourceofs = block->sourceoffset[0];\r
- sprite->planesize = block->planesize[0];\r
- sprite->draw = draw;\r
- sprite->priority = priority;\r
- sprite->tilex = sprite->screenx >> SX_T_SHIFT;\r
- sprite->tiley = sprite->screeny >> SY_T_SHIFT;\r
- sprite->tilewide = ( (sprite->screenx + sprite->width -1) >> SX_T_SHIFT )\r
- - sprite->tilex + 1;\r
- sprite->tilehigh = ( (sprite->screeny + sprite->height -1) >> SY_T_SHIFT )\r
- - sprite->tiley + 1;\r
-\r
- sprite->updatecount = 1; // draw on next refresh\r
-\r
-// save the sprite pointer off in the user's pointer so it can be moved\r
-// again later\r
-\r
- *user = sprite;\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_RemoveSprite CGA\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_RemoveSprite (void **user)\r
-{\r
- spritelisttype *sprite,*next;\r
-\r
- sprite = (spritelisttype *)*user;\r
- if (!sprite)\r
- return;\r
-\r
-//\r
-// post an erase block to erase the old position by copying\r
-// screenx,screeny,width,height\r
-//\r
- if (!sprite->updatecount)\r
- {\r
- memcpy (eraselistptr[0]++,sprite,sizeof(eraseblocktype));\r
- }\r
-\r
-//\r
-// unlink the sprite node\r
-//\r
- next = sprite->nextsprite;\r
- if (next) // if (!next), sprite is last in chain\r
- next->prevptr = sprite->prevptr;\r
- *sprite->prevptr = next;\r
-\r
-//\r
-// add it back to the free list\r
-//\r
- sprite->nextsprite = spritefreeptr;\r
- spritefreeptr = sprite;\r
-\r
-//\r
-// null the users pointer, so next time that actor gets placed, it will\r
-// allocate a new block\r
-//\r
-\r
- *user = 0;\r
-}\r
-\r
-\r
-/*\r
-====================\r
-=\r
-= RFL_EraseBlocks CGA\r
-=\r
-= Write mode 1 should be set\r
-=\r
-====================\r
-*/\r
-\r
-void RFL_EraseBlocks (void)\r
-{\r
- eraseblocktype *block,*done;\r
- int screenxh,screenyh;\r
- unsigned pos,xtl,ytl,xth,yth,x,y;\r
- byte *updatespot;\r
- unsigned updatedelta;\r
-\r
- block = &eraselist[0][0];\r
-\r
- done = eraselistptr[0];\r
-\r
- while (block != done)\r
- {\r
-\r
- //\r
- // clip the block to the current screen view\r
- //\r
- block->screenx -= originxscreen;\r
- block->screeny -= originyscreen;\r
-\r
- if (block->screenx < 0)\r
- {\r
- block->width += block->screenx;\r
- if (block->width<1)\r
- goto next;\r
- block->screenx = 0;\r
- }\r
-\r
- if (block->screeny < 0)\r
- {\r
- block->height += block->screeny;\r
- if (block->height<1)\r
- goto next;\r
- block->screeny = 0;\r
- }\r
-\r
- screenxh = block->screenx + block->width;\r
- screenyh = block->screeny + block->height;\r
-\r
- if (screenxh > CGAPORTSCREENWIDE)\r
- {\r
- block->width = CGAPORTSCREENWIDE-block->screenx;\r
- screenxh = block->screenx + block->width;\r
- }\r
-\r
- if (screenyh > PORTSCREENHIGH)\r
- {\r
- block->height = PORTSCREENHIGH-block->screeny;\r
- screenyh = block->screeny + block->height;\r
- }\r
-\r
- if (block->width<1 || block->height<1)\r
- goto next;\r
-\r
- //\r
- // erase the block by copying from the master screen\r
- //\r
- pos = ylookup[block->screeny]+block->screenx;\r
- block->width = (block->width + (pos&1) + 1)& ~1;\r
- pos &= ~1; // make sure a word copy gets used\r
- VW_ScreenToScreen (masterofs+pos,bufferofs+pos,\r
- block->width,block->height);\r
-\r
- //\r
- // put 2s in update where the block was, to force sprites to update\r
- //\r
- xtl = block->screenx >> SX_T_SHIFT;\r
- xth = (block->screenx+block->width-1) >> SX_T_SHIFT;\r
- ytl = block->screeny >> SY_T_SHIFT;\r
- yth = (block->screeny+block->height-1) >> SY_T_SHIFT;\r
-\r
- updatespot = updateptr + uwidthtable[ytl] + xtl;\r
- updatedelta = UPDATEWIDE - (xth-xtl+1);\r
-\r
- for (y=ytl;y<=yth;y++)\r
- {\r
- for (x=xtl;x<=xth;x++)\r
- *updatespot++ = 2;\r
- updatespot += updatedelta; // down to next line\r
- }\r
-\r
-next:\r
- block++;\r
- }\r
- eraselistptr[0] = &eraselist[0][0];\r
-}\r
-\r
-\r
-/*\r
-====================\r
-=\r
-= RFL_UpdateSprites CGA\r
-=\r
-= NOTE: Implement vertical clipping!\r
-=\r
-====================\r
-*/\r
-\r
-void RFL_UpdateSprites (void)\r
-{\r
- spritelisttype *sprite;\r
- int portx,porty,x,y,xtl,xth,ytl,yth;\r
- int priority;\r
- unsigned dest;\r
- byte *updatespot,*baseupdatespot;\r
- unsigned updatedelta;\r
-\r
- unsigned updatecount;\r
- unsigned height,sourceofs;\r
-\r
-#ifdef PROFILE\r
- updatecount = 0;\r
-#endif\r
-\r
-\r
- for (priority=0;priority<PRIORITIES;priority++)\r
- {\r
- if (priority==MASKEDTILEPRIORITY)\r
- RFL_MaskForegroundTiles ();\r
-\r
- for (sprite = prioritystart[priority]; sprite ;\r
- sprite = (spritelisttype *)sprite->nextsprite)\r
- {\r
- //\r
- // see if the sprite has any visable area in the port\r
- //\r
-\r
- portx = sprite->screenx - originxscreen;\r
- porty = sprite->screeny - originyscreen;\r
- xtl = portx >> SX_T_SHIFT;\r
- xth = (portx + sprite->width-1) >> SX_T_SHIFT;\r
- ytl = porty >> SY_T_SHIFT;\r
- yth = (porty + sprite->height-1) >> SY_T_SHIFT;\r
-\r
- if (xtl<0)\r
- xtl = 0;\r
- if (xth>=PORTTILESWIDE)\r
- xth = PORTTILESWIDE-1;\r
- if (ytl<0)\r
- ytl = 0;\r
- if (yth>=PORTTILESHIGH)\r
- yth = PORTTILESHIGH-1;\r
-\r
- if (xtl>xth || ytl>yth)\r
- continue;\r
-\r
- //\r
- // see if it's visable area covers any non 0 update tiles\r
- //\r
- updatespot = baseupdatespot = updateptr + uwidthtable[ytl] + xtl;\r
- updatedelta = UPDATEWIDE - (xth-xtl+1);\r
-\r
- if (sprite->updatecount)\r
- {\r
- sprite->updatecount--; // the sprite was just placed,\r
- goto redraw; // so draw it for sure\r
- }\r
-\r
- for (y=ytl;y<=yth;y++)\r
- {\r
- for (x=xtl;x<=xth;x++)\r
- if (*updatespot++)\r
- goto redraw;\r
- updatespot += updatedelta; // down to next line\r
- }\r
- continue; // no need to update\r
-\r
-redraw:\r
- //\r
- // set the tiles it covers to 3, because those tiles are being\r
- // updated\r
- //\r
- updatespot = baseupdatespot;\r
- for (y=ytl;y<=yth;y++)\r
- {\r
- for (x=xtl;x<=xth;x++)\r
- *updatespot++ = 3;\r
- updatespot += updatedelta; // down to next line\r
- }\r
- //\r
- // draw it!\r
- //\r
- height = sprite->height;\r
- sourceofs = sprite->sourceofs;\r
- if (porty<0)\r
- {\r
- height += porty; // clip top off\r
- sourceofs -= porty*sprite->width;\r
- porty = 0;\r
- }\r
- else if (porty+height>PORTSCREENHIGH)\r
- {\r
- height = PORTSCREENHIGH - porty; // clip bottom off\r
- }\r
-\r
- dest = bufferofs + ylookup[porty] + portx;\r
-\r
- switch (sprite->draw)\r
- {\r
- case spritedraw:\r
- VW_MaskBlock(grsegs[sprite->grseg], sourceofs,\r
- dest,sprite->width,height,sprite->planesize);\r
- break;\r
-\r
- case maskdraw:\r
- VW_InverseMask(grsegs[sprite->grseg], sourceofs,\r
- dest,sprite->width,height);\r
- break;\r
-\r
- }\r
-#ifdef PROFILE\r
- updatecount++;\r
-#endif\r
-\r
-\r
- }\r
- }\r
-}\r
-\r
-\r
-/*\r
-=====================\r
-=\r
-= RF_Refresh CGA\r
-=\r
-= All routines will draw at the port at bufferofs, possibly copying from\r
-= the port at masterofs. The EGA version then page flips, while the\r
-= CGA version updates the screen from the buffer port.\r
-=\r
-= Screenpage is the currently displayed page, not the one being drawn\r
-= Otherpage is the page to be worked with now\r
-=\r
-=====================\r
-*/\r
-\r
-void RF_Refresh (void)\r
-{\r
- long newtime,oldtimecount;\r
-\r
- RFL_AnimateTiles ();\r
-\r
-//\r
-// update newly scrolled on tiles and animated tiles from the master screen\r
-//\r
- RFL_UpdateTiles ();\r
- RFL_EraseBlocks ();\r
-\r
-//\r
-// Update is all 0 except where sprites have changed or new area has\r
-// been scrolled on. Go through all sprites and update the ones that cover\r
-// a non 0 update tile\r
-//\r
- RFL_UpdateSprites ();\r
-\r
-//\r
-// if the main program has a refresh hook set, call their function before\r
-// displaying the new page\r
-//\r
- if (refreshvector)\r
- refreshvector();\r
-\r
-//\r
-// update everything to the screen\r
-//\r
- VW_CGAFullUpdate ();\r
-\r
-//\r
-// calculate tics since last refresh for adaptive timing\r
-//\r
- RF_CalcTics ();\r
-}\r
-\r
-#endif // GRMODE == CGAGR\r