--- /dev/null
+/* Catacomb Apocalypse 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
+// C3_PLAY.C\r
+\r
+#include "DEF.H"\r
+#include "gelib.h"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define POINTTICS 6\r
+#define PAUSE 300\r
+\r
+/*\r
+=============================================================================\r
+\r
+ GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+byte bcolor;\r
+short skytimer=-1,skytimer_reset;\r
+short groundtimer=-1,groundtimer_reset;\r
+\r
+unsigned scolor,gcolor;\r
+unsigned *skycolor,*groundcolor,debug_sky,debug_gnd;\r
+\r
+unsigned nocolorchange=0xFFFF;\r
+byte BGFLAGS, // global that holds all current flags\r
+ bgflag; // used by BG changer, this flag is set when done\r
+\r
+\r
+unsigned sky_daytonight[]={0x0909,0x0101,0x0808,0x0000,0xFFFF};\r
+//unsigned gnd_daytonight[]={0x0202,0xFFFF};\r
+\r
+unsigned sky_lightning[]={0x0101,0x0909,0x0f0f,0x0808,0x0000,0xFFFF};\r
+\r
+unsigned sky_colors[NUMLEVELS]={0x0000,0x0000,0x0000,0x0000,0x0808,\r
+ 0x0404,0x0000,0x0000,0x0000,0x0000,\r
+ 0x0000,0x0000,0x0000,0x0000,0x0606,\r
+ 0x0000,0x0000,0x0000,0x0000,0x0000,\r
+ 0x0000};\r
+unsigned gnd_colors[NUMLEVELS]={0x0202,0x0202,0x0606,0x0202,0x0707,\r
+ 0x0505,0x0808,0x0606,0x0101,0x0808,\r
+ 0x0606,0x0404,0x0808,0x0c0c,0x0e0e,\r
+ 0x0808,0x0808,0x0c0c,0x0000,0x0707,\r
+ 0x0808};\r
+\r
+\r
+ControlInfo control;\r
+boolean running=false; //,slowturn;\r
+\r
+int bordertime;\r
+objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj,*objfreelist;\r
+\r
+#if USE_INERT_LIST\r
+inertobjtype inertobjlist[MAXINERTOBJ],*inert;\r
+#endif\r
+\r
+unsigned farmapylookup[MAPSIZE];\r
+byte *nearmapylookup[MAPSIZE];\r
+\r
+boolean singlestep,godmode;\r
+int extravbls;\r
+status_flags status_flag;\r
+int status_delay;\r
+\r
+//\r
+// replacing refresh manager\r
+//\r
+unsigned mapwidth,mapheight,tics,realtics;\r
+boolean compatability;\r
+byte *updateptr;\r
+unsigned mapwidthtable[64];\r
+unsigned uwidthtable[UPDATEHIGH];\r
+unsigned blockstarts[UPDATEWIDE*UPDATEHIGH];\r
+#define UPDATESCREENSIZE (UPDATEWIDE*PORTTILESHIGH+2)\r
+#define UPDATESPARESIZE (UPDATEWIDE*2+4)\r
+#define UPDATESIZE (UPDATESCREENSIZE+2*UPDATESPARESIZE)\r
+byte update[UPDATESIZE];\r
+\r
+int mousexmove,mouseymove;\r
+int pointcount,pointsleft;\r
+\r
+short BeepTime = 0;\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+void CalcBounds (objtype *ob);\r
+void DrawPlayScreen (void);\r
+void PreFullDisplay(void);\r
+void PostFullDisplay(boolean draw_view);\r
+\r
+\r
+//\r
+// near data map array (wall values only, get text number from far data)\r
+//\r
+byte tilemap[MAPSIZE][MAPSIZE];\r
+byte spotvis[MAPSIZE][MAPSIZE];\r
+objtype *actorat[MAPSIZE][MAPSIZE];\r
+\r
+objtype dummyobj;\r
+\r
+int bordertime;\r
+int objectcount;\r
+\r
+void StopMusic(void);\r
+void StartMusic(void);\r
+\r
+void CalibrateJoystick(short joynum);\r
+\r
+//==========================================================================\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// CenterWindow() - Generates a window of a given width & height in the\r
+// middle of the screen\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+\r
+#define MAXX 320\r
+#define MAXY 120\r
+\r
+void CenterWindow(word w,word h)\r
+{\r
+ US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= CheckKeys\r
+=\r
+=====================\r
+*/\r
+\r
+void CheckKeys (void)\r
+{\r
+ extern boolean autofire;\r
+\r
+ if (screenfaded) // don't do anything with a faded screen\r
+ return;\r
+\r
+#if 0\r
+//\r
+// pause key wierdness can't be checked as a scan code\r
+//\r
+ if (Paused)\r
+ {\r
+ CenterWindow (8,3);\r
+ US_PrintCentered ("PAUSED");\r
+ VW_UpdateScreen ();\r
+// SD_MusicOff();\r
+ IN_Ack();\r
+// SD_MusicOn();\r
+ Paused = false;\r
+ if (MousePresent) Mouse(MDelta); // Clear accumulated mouse movement\r
+ }\r
+ else\r
+ if (Keyboard[sc_Enter]) // P = pause with no screen disruptioon\r
+ {\r
+// SD_MusicOff();\r
+ DisplaySMsg("PAUSED",NULL);\r
+ IN_Ack();\r
+// SD_MusicOn();\r
+ if (MousePresent) Mouse(MDelta); // Clear accumulated mouse movement\r
+ }\r
+ else\r
+ if (Keyboard[sc_S])\r
+ {\r
+ char *Text[] = {{"Slow Mode ON"},{"Slow Mode OFF"}};\r
+\r
+ SlowMode ^= 1;\r
+ extravbls = SlowMode << 3;\r
+ CenterWindow (8,3);\r
+ US_PrintCentered (Text[SlowMode]);\r
+ VW_UpdateScreen ();\r
+// SD_MusicOff();\r
+ IN_Ack();\r
+// SD_MusicOn();\r
+ if (MousePresent) Mouse(MDelta); // Clear accumulated mouse movement\r
+ }\r
+#endif\r
+\r
+\r
+// F2 - SOUND OPTIONS\r
+//\r
+ if (Keyboard[sc_F2])\r
+ {\r
+ int height=7;\r
+ boolean ChoiceMade = false;\r
+\r
+ if (AdLibPresent)\r
+ height++;\r
+\r
+ VW_FixRefreshBuffer();\r
+ CenterWindow(22,height);\r
+ US_Print( "\n 1 ) NO SOUND \n");\r
+ US_Print( " 2 ) PC AUDIO \n");\r
+\r
+ if (AdLibPresent)\r
+ US_Print(" 3 ) ADLIB AUDIO\n");\r
+\r
+ US_Print( "\n ESC) EXIT ");\r
+ VW_UpdateScreen();\r
+\r
+ // Switch audio device ON/OFF & load sounds if there\r
+ // was a change in the device.\r
+\r
+ do {\r
+\r
+ if (Keyboard[1]) // ESC - Exit\r
+ ChoiceMade = true;\r
+ else\r
+ if (Keyboard[2]) // 1 - No Sound\r
+ {\r
+ SD_SetSoundMode(sdm_Off);\r
+ ChoiceMade = true;\r
+ }\r
+ else\r
+ if (Keyboard[3]) // 2 - PC Audio\r
+ {\r
+ SD_SetSoundMode(sdm_PC);\r
+// if (oldsoundmode != sdm_PC)\r
+ CA_LoadAllSounds();\r
+ ChoiceMade = true;\r
+ }\r
+ else\r
+ if ((Keyboard[4]) && AdLibPresent) // 3 - AdLib Audio\r
+ {\r
+ SD_SetSoundMode(sdm_AdLib);\r
+// if (oldsoundmode != sdm_AdLib)\r
+ CA_LoadAllSounds();\r
+ ChoiceMade = true;\r
+ }\r
+\r
+ } while (!ChoiceMade);\r
+ tics = realtics = 1;\r
+ IN_ClearKeysDown();\r
+ }\r
+\r
+// F5 - CALIBRATE JOYSTICK\r
+//\r
+ if (Keyboard[sc_F5])\r
+ {\r
+ CalibrateJoystick(0);\r
+ tics = realtics = 1;\r
+ IN_ClearKeysDown();\r
+ }\r
+\r
+deadloop:;\r
+// ESCAPE - quits game\r
+//\r
+ if ((Keyboard[sc_Escape]) || (Flags & FL_DEAD))\r
+ {\r
+ char ch;\r
+\r
+ DisplaySMsg("Options", NULL);\r
+ status_flag = S_NONE;\r
+\r
+\r
+ if (Flags & FL_DEAD)\r
+ {\r
+ char choices[] = {sc_Escape,sc_R,sc_N,sc_Q,0};\r
+ ch = DisplayMsg("Restore New Quit",choices);\r
+ DisplayMsg(" ", NULL);\r
+ }\r
+ else\r
+ {\r
+ char choices[] = {sc_Escape,sc_S,sc_R,sc_N,sc_Q,0};\r
+ ch = DisplayMsg("Save Restore New Quit",choices);\r
+ }\r
+ DrawText(true);\r
+\r
+ switch (ch)\r
+ {\r
+ case sc_S:\r
+ if (!(Flags & FL_DEAD))\r
+ Keyboard[sc_F3] = true;\r
+ break;\r
+\r
+ case sc_R:\r
+ Keyboard[sc_F4] = true;\r
+ break;\r
+\r
+ case sc_N:\r
+ DisplaySMsg("Starting anew", NULL);\r
+ VW_WaitVBL(60);\r
+ playstate = ex_resetgame;\r
+ Flags &= ~FL_DEAD;\r
+ break;\r
+\r
+ case sc_Q:\r
+ DisplaySMsg("FARE THEE WELL!", NULL);\r
+ VW_WaitVBL(120);\r
+ if (!Flags & FL_QUICK)\r
+ VW_FadeOut();\r
+ NormalScreen();\r
+ FreeUpMemory();\r
+ Quit(NULL);\r
+ break;\r
+ }\r
+ tics = realtics = 1;\r
+ }\r
+\r
+// F1 - DISPLAY HELP\r
+//\r
+ if (Keyboard[sc_F1])\r
+ {\r
+ PrintHelp();\r
+\r
+#ifdef TEXT_PRESENTER\r
+\r
+ extern PresenterInfo MainHelpText;\r
+\r
+ VW_FadeOut();\r
+\r
+ FreeUpMemory();\r
+ if (!LoadPresenterScript("HELP.TXT",&MainHelpText))\r
+ {\r
+ VW_FadeIn();\r
+ CenterWindow(30,5);\r
+ US_CPrint("\nError loading HELP file.\n");\r
+ US_CPrint("Press any key.");\r
+ IN_Ack();\r
+ VW_FadeOut();\r
+ }\r
+ else\r
+ {\r
+ VW_SetSplitScreen(200);\r
+ bufferofs = displayofs = screenloc[0];\r
+ VW_Bar(0,0,320,200,0);\r
+\r
+ Display640();\r
+ Presenter(&MainHelpText);\r
+ Display320();\r
+ }\r
+ FreePresenterScript(&MainHelpText);\r
+#endif\r
+ VW_SetSplitScreen(120);\r
+ VW_SetScreen(screenloc[0],0);\r
+ screenpage = 0;\r
+ CacheScaleds();\r
+\r
+ bufferofs = 0;\r
+ RedrawStatusWindow();\r
+ ThreeDRefresh();\r
+ VW_FadeIn();\r
+ Keyboard[sc_F1] = false;\r
+ tics = realtics = 1;\r
+ IN_ClearKeysDown();\r
+ }\r
+\r
+// F3 - SAVE GAME\r
+//\r
+ if ((Keyboard[sc_F3]) && (!(Flags & FL_DEAD)))\r
+ {\r
+ PreFullDisplay();\r
+ GE_SaveGame();\r
+ PostFullDisplay(true);\r
+ tics = realtics = 1;\r
+ IN_ClearKeysDown();\r
+ }\r
+\r
+// F4 - LOAD GAME\r
+//\r
+ if (Keyboard[sc_F4])\r
+ {\r
+ PreFullDisplay();\r
+ if (GE_LoadGame())\r
+ {\r
+ loadedgame = true;\r
+ playstate = ex_loadedgame;\r
+ Flags &= ~FL_DEAD;\r
+ lasttext = -1;\r
+ PostFullDisplay(false);\r
+ }\r
+ else\r
+ if (playstate == ex_victorious)\r
+ {\r
+ PostFullDisplay(false);\r
+ Victory(false);\r
+ IN_Ack();\r
+ Quit(NULL);\r
+ }\r
+ else\r
+ PostFullDisplay(true);\r
+ Keyboard[sc_F5] = false;\r
+ tics = realtics = 1;\r
+ IN_ClearKeysDown();\r
+ }\r
+\r
+ if (Flags & FL_DEAD)\r
+ goto deadloop;\r
+\r
+//\r
+// F10-? debug keys\r
+//\r
+ if (Keyboard[sc_BackSpace])\r
+ {\r
+ DebugKeys();\r
+ if (MousePresent) Mouse(MDelta); // Clear accumulated mouse movement\r
+ lasttimecount = TimeCount;\r
+ }\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// PreFullDisplay()\r
+//-------------------------------------------------------------------------\r
+void PreFullDisplay()\r
+{\r
+ VW_FadeOut();\r
+ VW_SetSplitScreen(200);\r
+ bufferofs = displayofs = screenloc[0];\r
+ VW_Bar(0,0,320,200,0);\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// PostFullDisplay()\r
+//-------------------------------------------------------------------------\r
+void PostFullDisplay(boolean draw_view)\r
+{\r
+ VW_SetSplitScreen(120);\r
+ bufferofs = 0;\r
+ RedrawStatusWindow();\r
+ if (draw_view)\r
+ {\r
+ ThreeDRefresh();\r
+ VW_FadeIn();\r
+ }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+#############################################################################\r
+\r
+ The objlist data structure\r
+\r
+#############################################################################\r
+\r
+objlist containt structures for every actor currently playing. The structure\r
+is accessed as a linked list starting at *player, ending when ob->next ==\r
+NULL. GetNewObj inserts a new object at the end of the list, meaning that\r
+if an actor spawn another actor, the new one WILL get to think and react the\r
+same frame. RemoveObj unlinks the given object and returns it to the free\r
+list, but does not damage the objects ->next pointer, so if the current object\r
+removes itself, a linked list following loop can still safely get to the\r
+next element.\r
+\r
+<backwardly linked free list>\r
+\r
+#############################################################################\r
+*/\r
+\r
+\r
+/*\r
+=========================\r
+=\r
+= InitObjList\r
+=\r
+= Call to clear out the entire object list, returning them all to the free\r
+= list. Allocates a special spot for the player.\r
+=\r
+=========================\r
+*/\r
+\r
+void InitObjList (void)\r
+{\r
+ int i;\r
+\r
+ for (i=0;i<MAXACTORS;i++)\r
+ {\r
+ objlist[i].prev = &objlist[i+1];\r
+ objlist[i].next = NULL;\r
+ }\r
+\r
+ objlist[MAXACTORS-1].prev = NULL;\r
+\r
+ objfreelist = &objlist[0];\r
+ lastobj = NULL;\r
+\r
+ objectcount = 0;\r
+\r
+//\r
+// give the player and score the first free spots\r
+//\r
+ GetNewObj (false);\r
+ player = new;\r
+\r
+#if USE_INERT_LIST\r
+ inert = inertobjlist;\r
+#endif\r
+\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=========================\r
+=\r
+= GetNewObj\r
+=\r
+= Sets the global variable new to point to a free spot in objlist.\r
+= The free spot is inserted at the end of the liked list\r
+=\r
+= When the object list is full, the caller can either have it bomb out ot\r
+= return a dummy object pointer that will never get used\r
+=\r
+=========================\r
+*/\r
+\r
+void GetNewObj (boolean usedummy)\r
+{\r
+ if (!objfreelist)\r
+ {\r
+ if (usedummy)\r
+ {\r
+ new = &dummyobj;\r
+ return;\r
+ }\r
+ Quit ("GetNewObj: No free spots in objlist!");\r
+ }\r
+\r
+ new = objfreelist;\r
+ objfreelist = new->prev;\r
+ memset (new,0,sizeof(*new));\r
+\r
+ if (lastobj)\r
+ lastobj->next = new;\r
+ new->prev = lastobj; // new->next is allready NULL from memset\r
+\r
+ new->active = false;\r
+ lastobj = new;\r
+\r
+ objectcount++;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=========================\r
+=\r
+= RemoveObj\r
+=\r
+= Add the given object back into the free list, and unlink it from it's\r
+= neighbors\r
+=\r
+=========================\r
+*/\r
+\r
+void RemoveObj (objtype *gone)\r
+{\r
+ objtype **spotat;\r
+\r
+ if (gone == player)\r
+ Quit ("RemoveObj: Tried to remove the player!");\r
+\r
+//\r
+// fix the next object's back link\r
+//\r
+ if (gone == lastobj)\r
+ lastobj = (objtype *)gone->prev;\r
+ else\r
+ gone->next->prev = gone->prev;\r
+\r
+//\r
+// fix the previous object's forward link\r
+//\r
+ gone->prev->next = gone->next;\r
+\r
+//\r
+// add it back in to the free list\r
+//\r
+ gone->prev = objfreelist;\r
+ objfreelist = gone;\r
+\r
+ objectcount--;\r
+}\r
+\r
+#if USE_INERT_LIST\r
+\r
+//--------------------------------------------------------------------------\r
+// MoveObjToInert()\r
+//--------------------------------------------------------------------------\r
+void MoveObjToInert(objtype *obj)\r
+{\r
+\r
+ if (inert == &inertobjlist[MAXINERTOBJ])\r
+ return;\r
+\r
+// Transfer info needed by inert objtype\r
+//\r
+ inert->x = obj->x;\r
+ inert->y = obj->y;\r
+ inert->size = obj->size;\r
+ inert->viewx = obj->viewx;\r
+ inert->tilex = obj->tilex;\r
+ inert->tiley = obj->tiley;\r
+ inert->state = obj->state;\r
+ inert->ticcount = obj->ticcount;\r
+\r
+// Setup links between inert objects\r
+//\r
+ if (inert != inertobjlist)\r
+ (inert-1)->next = inert;\r
+ inert->next = NULL;\r
+ inert++;\r
+\r
+// Free 'real' object from list.\r
+//\r
+ RemoveObj(obj);\r
+}\r
+\r
+#endif\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= PollControls\r
+=\r
+===================\r
+*/\r
+\r
+void PollControls (void)\r
+{\r
+ unsigned buttons;\r
+\r
+ IN_ReadControl(0,&control);\r
+\r
+ if (MousePresent)\r
+ {\r
+ Mouse(MButtons);\r
+ buttons = _BX;\r
+ Mouse(MDelta);\r
+ mousexmove = _CX;\r
+ mouseymove = _DX;\r
+\r
+ if (buttons&1)\r
+ control.button0 = 1;\r
+ if (buttons&2)\r
+ control.button1 = 1;\r
+\r
+ }\r
+\r
+ if (Keyboard[sc_V] || Keyboard[sc_Tab])\r
+ running = true;\r
+ else\r
+ running = false;\r
+}\r
+\r
+//==========================================================================\r
+\r
+#if 0\r
+/*\r
+=================\r
+=\r
+= StopMusic\r
+=\r
+=================\r
+*/\r
+\r
+void StopMusic(void)\r
+{\r
+ int i;\r
+\r
+ SD_MusicOff();\r
+ for (i = 0;i < LASTMUSIC;i++)\r
+ if (audiosegs[STARTMUSIC + i])\r
+ {\r
+ MM_SetPurge(&((memptr)audiosegs[STARTMUSIC + i]),3);\r
+ MM_SetLock(&((memptr)audiosegs[STARTMUSIC + i]),false);\r
+ }\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= StartMusic\r
+=\r
+=================\r
+*/\r
+\r
+// JAB - Cache & start the appropriate music for this level\r
+void StartMusic(void)\r
+{\r
+ musicnames chunk;\r
+\r
+ SD_MusicOff();\r
+ chunk = TOOHOT_MUS;\r
+// if ((chunk == -1) || (MusicMode != smm_AdLib))\r
+//DEBUG control panel return;\r
+\r
+ MM_BombOnError (false);\r
+ CA_CacheAudioChunk(STARTMUSIC + chunk);\r
+ MM_BombOnError (true);\r
+ if (mmerror)\r
+ mmerror = false;\r
+ else\r
+ {\r
+ MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true);\r
+ SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]);\r
+ }\r
+}\r
+#endif\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= PlayLoop\r
+=\r
+===================\r
+*/\r
+\r
+void PlayLoop (void)\r
+{\r
+ char shot_color[3] = {4,9,14};\r
+\r
+ int allgems[5]={GEM_DELAY_TIME, // used for Q & D comparison\r
+ GEM_DELAY_TIME, // for having all gems...\r
+ GEM_DELAY_TIME, // the "allgems" declaration MUST\r
+ GEM_DELAY_TIME, // match the "gems" declaration in\r
+ GEM_DELAY_TIME // the gametype structure!\r
+ };\r
+\r
+// int originx=0;\r
+// int i=100;\r
+ signed long dx,dy,radius,psin,pcos,newx,newy;\r
+ int give;\r
+ short objnum;\r
+ signed long ox,oy,xl,xh,yl,yh,px,py,norm_dx,norm_dy;\r
+ short o_radius;\r
+\r
+ void (*think)();\r
+\r
+ ingame = true;\r
+ playstate = TimeCount = 0;\r
+ gamestate.shotpower = handheight = 0;\r
+ pointcount = pointsleft = 0;\r
+\r
+ status_flag = S_NONE;\r
+\r
+#if 0\r
+ // setup sky/ground colors and effects (based on level)\r
+ //\r
+ switch (gamestate.mapon)\r
+ {\r
+ case 255:\r
+ if (!(BGFLAGS & BGF_NIGHT))\r
+ {\r
+ InitBgChange(3*60,sky_daytonight,-1,NULL,BGF_NIGHT);\r
+ groundcolor = &gnd_colors[0];\r
+ }\r
+ else\r
+ {\r
+ skycolor = &sky_colors[0];\r
+ groundcolor = &gnd_colors[0];\r
+ }\r
+ break;\r
+\r
+ default:\r
+ skycolor = &sky_colors[gamestate.mapon];\r
+ groundcolor = &gnd_colors[gamestate.mapon];\r
+ skytimer = groundtimer = -1;\r
+ break;\r
+ }\r
+#endif\r
+\r
+ BGFLAGS |= BGF_NOT_LIGHTNING;\r
+ skytimer = groundtimer = -1;\r
+\r
+ debug_gnd = *groundcolor;\r
+ debug_sky = *skycolor;\r
+ RedrawStatusWindow();\r
+ ThreeDRefresh();\r
+ if (screenfaded)\r
+ VW_FadeIn();\r
+\r
+#ifndef PROFILE\r
+ fizzlein = true; // fizzle fade in the first refresh\r
+#endif\r
+ TimeCount = lasttimecount = lastnuke = 0;\r
+\r
+ PollControls (); // center mouse\r
+// StartMusic ();\r
+ do\r
+ {\r
+#ifndef PROFILE\r
+ PollControls();\r
+#else\r
+ control.xaxis = 1;\r
+ if (++TimeCount == 300)\r
+ return;\r
+#endif\r
+ DisplayStatus(&status_flag);\r
+\r
+ objnum=0;\r
+ for (obj = player;obj;obj = obj->next)\r
+ {\r
+ if ((obj->active >= yes) && (!(FreezeTime && (obj!=player))))\r
+ {\r
+ if (obj->ticcount)\r
+ {\r
+ obj->ticcount-=realtics;\r
+ while ( obj->ticcount <= 0)\r
+ {\r
+ think = obj->state->think;\r
+ if (think)\r
+ {\r
+ statetype *oldstate=obj->state;\r
+\r
+ think (obj);\r
+ if (!obj->state)\r
+ {\r
+ RemoveObj (obj);\r
+ goto nextactor;\r
+ }\r
+ if (obj->state != oldstate)\r
+ break;\r
+ }\r
+\r
+ obj->state = obj->state->next;\r
+ if (!obj->state)\r
+ {\r
+ RemoveObj (obj);\r
+ goto nextactor;\r
+ }\r
+ if (!obj->state->tictime)\r
+ {\r
+ obj->ticcount = 0;\r
+ goto nextactor;\r
+ }\r
+ if (obj->state->tictime>0)\r
+ obj->ticcount += obj->state->tictime;\r
+ }\r
+ }\r
+\r
+ think = obj->state->think;\r
+ if (think)\r
+ {\r
+ think (obj);\r
+ if (!obj->state)\r
+ RemoveObj (obj);\r
+ }\r
+nextactor:;\r
+ }\r
+\r
+ // keep a list of objects around the player for radar updates\r
+ //\r
+ if (obj == player)\r
+ {\r
+ px = player->x;\r
+ py = player->y;\r
+ psin = sintable[player->angle];\r
+ pcos = costable[player->angle];\r
+ xl = px-((long)RADAR_WIDTH<<TILESHIFT)/2;\r
+ xh = px+((long)RADAR_WIDTH<<TILESHIFT)/2-1;\r
+ yl = py-((long)RADAR_HEIGHT<<TILESHIFT)/2;\r
+ yh = py+((long)RADAR_HEIGHT<<TILESHIFT)/2;\r
+ }\r
+\r
+ if (objnum > MAX_RADAR_BLIPS-2)\r
+ objnum = MAX_RADAR_BLIPS-2;\r
+\r
+ ox = obj->x;\r
+ oy = obj->y;\r
+\r
+\r
+ if ((ox >= xl) && (ox <= xh) && (oy >= yl) && (oy <= yh))\r
+ {\r
+ norm_dx = (dx = px-ox)>>TILESHIFT;\r
+ norm_dy = (dy = oy-py)>>TILESHIFT;\r
+\r
+ o_radius = IntSqrt((norm_dx * norm_dx) + (norm_dy * norm_dy));\r
+\r
+ if (o_radius < RADAR_RADIUS)\r
+ {\r
+ newx = FixedByFrac(dy,pcos)-FixedByFrac(dx,psin);\r
+ newy = FixedByFrac(dy,psin)+FixedByFrac(dx,pcos);\r
+\r
+ RadarXY[objnum][0]=newx>>TILESHIFT;\r
+ RadarXY[objnum][1]=newy>>TILESHIFT;\r
+\r
+ // Define color to use for this object...\r
+ //\r
+\r
+ switch (obj->obclass)\r
+ {\r
+ // NO GEM NEEDED\r
+ //\r
+ // THE WIZARD! (YOU)\r
+ //\r
+ case playerobj:\r
+ RadarXY[objnum++][2]=15;\r
+ break;\r
+\r
+ // WIZARD'S SHOTS\r
+ //\r
+ case bounceobj:\r
+ case pshotobj:\r
+ case bigpshotobj:\r
+ RadarXY[objnum++][2]=shot_color[screenpage];\r
+ break;\r
+\r
+ // RED GEM\r
+ //\r
+ // STOMPY (DK RED)\r
+ //\r
+ case invisdudeobj:\r
+ case stompyobj:\r
+ if (gamestate.gems[B_RGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=4;\r
+ break;\r
+\r
+ // BLOB (LT RED)\r
+ //\r
+ case blobobj:\r
+ if (gamestate.gems[B_RGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=12;\r
+ break;\r
+\r
+ // BLUE GEM\r
+ //\r
+ // ROBOTANK (LT BLUE)\r
+ //\r
+ case robotankobj:\r
+ case fmageobj:\r
+ if (gamestate.gems[B_BGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=9;\r
+ break;\r
+\r
+#if 1\r
+ // BLUE DEMON (DK BLUE)\r
+ //\r
+ case demonobj:\r
+ if (gamestate.gems[B_GGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=1;\r
+ break;\r
+#endif\r
+\r
+ // GREEN GEM\r
+ //\r
+ // WIZARD (LT GREEN)\r
+ //\r
+ case wizardobj:\r
+ if (gamestate.gems[B_GGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=10;\r
+ break;\r
+\r
+ // AQUA MAN (DK GREEN)\r
+ //\r
+ case aquamanobj:\r
+ if (gamestate.gems[B_GGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=2;\r
+ break;\r
+\r
+ // YELLOW GEM\r
+ //\r
+ // EQYPTIAN HEAD (BROWN)\r
+ //\r
+ case headobj:\r
+ if (gamestate.gems[B_YGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=6;\r
+ break;\r
+\r
+ // RAMBONE (YELLOW)\r
+ // TROLL\r
+ case ramboneobj:\r
+ case trollobj:\r
+ if (gamestate.gems[B_YGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=14;\r
+ break;\r
+\r
+ // BUG (LIGHT GRAY)\r
+ case bugobj:\r
+ if (gamestate.gems[B_YGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=7;\r
+ break;\r
+\r
+ // RAY (DARK GRAY)\r
+ case rayobj:\r
+ if (gamestate.gems[B_YGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=8;\r
+ break;\r
+\r
+ // PURPLE GEM\r
+ //\r
+ // MEC DEMON (PURPLE)\r
+ //\r
+ case cyborgdemonobj:\r
+ if (gamestate.gems[B_PGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=5;\r
+ break;\r
+\r
+ // EYE (LT PURPLE)\r
+ //\r
+ case eyeobj:\r
+ case reyeobj:\r
+ if (gamestate.gems[B_PGEM-B_RGEM])\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=13;\r
+ break;\r
+\r
+ // ALL GEMS NEEDED\r
+ //\r
+ // NEMESIS\r
+ //\r
+ case grelmobj:\r
+ if (!memcmp(gamestate.gems,allgems,sizeof(gamestate.gems)))\r
+ if (obj->active == always)\r
+ RadarXY[objnum++][2]=15;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ RadarXY[objnum][2]=-1; // Signals end of RadarXY list...\r
+\r
+#if USE_INERT_LIST\r
+ if (inert != inertobjlist)\r
+ for (obj=(objtype *)inertobjlist;obj;obj=obj->next)\r
+ if (obj->ticcount)\r
+ {\r
+ obj->ticcount-=realtics;\r
+ while ( obj->ticcount <= 0)\r
+ {\r
+ obj->state = obj->state->next;\r
+ if (!obj->state)\r
+ Quit("Removable object in INERT list.");\r
+\r
+ if (!obj->state->tictime)\r
+ {\r
+ obj->ticcount = 0;\r
+ goto nextactor;\r
+ }\r
+\r
+ if (obj->state->tictime>0)\r
+ obj->ticcount += obj->state->tictime;\r
+ }\r
+ }\r
+#endif\r
+\r
+ if (bordertime)\r
+ {\r
+ bordertime -= realtics;\r
+ if (bordertime<=0)\r
+ {\r
+ bordertime = 0;\r
+ VW_ColorBorder(0);\r
+ }\r
+ }\r
+\r
+#if 1\r
+// random lightning?\r
+//\r
+ if (BGFLAGS & (BGF_NOT_LIGHTNING))\r
+ {\r
+ if ((scolor & 0xe0) && (!(random(20-realtics))))\r
+ {\r
+ BGFLAGS &= ~BGF_NOT_LIGHTNING;\r
+ InitBgChange(1,sky_lightning,-1,NULL,BGF_NOT_LIGHTNING);\r
+ }\r
+ }\r
+\r
+// handle sky/ground color changes\r
+//\r
+ if (skytimer != -1)\r
+ {\r
+ skytimer -= realtics;\r
+ if (skytimer < 0)\r
+ {\r
+ skycolor++;\r
+ if (*skycolor == 0xffff)\r
+ {\r
+ skytimer = -1;\r
+// skycolor--;\r
+ skycolor = &scolor;\r
+ if (groundtimer == -1)\r
+ BGFLAGS |= bgflag;\r
+ }\r
+ else\r
+ skytimer = skytimer_reset;\r
+ }\r
+ }\r
+\r
+ if (groundtimer != -1)\r
+ {\r
+ groundtimer -= realtics;\r
+ if (groundtimer < 0)\r
+ {\r
+ groundcolor++;\r
+ if (*groundcolor == 0xffff)\r
+ {\r
+ groundtimer = -1;\r
+// groundcolor--;\r
+ groundcolor = &gcolor;\r
+ if (skytimer == -1)\r
+ BGFLAGS |= bgflag;\r
+ }\r
+ else\r
+ groundtimer = groundtimer_reset;\r
+ }\r
+ }\r
+#endif\r
+\r
+\r
+//\r
+// Handle FreezeTime counter..\r
+//\r
+ if (FreezeTime)\r
+ {\r
+ if (FreezeTime<20*30)\r
+ if ((BeepTime+=realtics)>=60)\r
+ {\r
+ BeepTime -= 60;\r
+ SD_PlaySound(TICKSND);\r
+ }\r
+\r
+ if ((FreezeTime-=realtics)<=0)\r
+ {\r
+ FreezeTime=0;\r
+ SD_PlaySound(TIMERETURNSND);\r
+ DisplaySMsg(NULL,NULL);\r
+ status_flag = S_NONE;\r
+ }\r
+ }\r
+\r
+\r
+// refresh all\r
+//\r
+ ThreeDRefresh ();\r
+\r
+ if (Flags & FL_DEAD)\r
+ {\r
+ SD_PlaySound (GAMEOVERSND);\r
+ DisplaySMsg("DEAD",NULL);\r
+ DrawHealth();\r
+ }\r
+\r
+// check for win\r
+//\r
+ if (playstate == ex_victorious)\r
+ {\r
+ Victory(true);\r
+ IN_Ack();\r
+ Quit(NULL);\r
+ }\r
+\r
+ CheckKeys();\r
+\r
+ }while (!playstate);\r
+// StopMusic ();\r
+\r
+ ingame = false;\r
+ if (bordertime)\r
+ {\r
+ bordertime = 0;\r
+ VW_ColorBorder(0);\r
+ }\r
+\r
+ if (abortgame)\r
+ abortgame = false;\r
+}\r
+\r
+//--------------------------------------------------------------------------\r
+// IntSqrt() - by Master Programmer, George Leritte!\r
+//--------------------------------------------------------------------------\r
+int IntSqrt(long va)\r
+{\r
+asm mov AX, word ptr va\r
+asm mov DX, word ptr va+2\r
+asm mov bx,dx // {bx = integer square root of dx:ax}\r
+asm or bx,ax // {if dx:ax=0 then return}\r
+asm jz isq01\r
+asm mov bx,dx\r
+asm shl bx,1\r
+asm or bl,ah\r
+asm or bl,al\r
+asm dec bx\r
+asm add bx,dx // { initial guess}\r
+asm jg isq10\r
+asm inc bx // { don't return zero}\r
+asm jg isq10\r
+asm mov bx,7fffh\r
+isq01:;\r
+ goto exitrout;\r
+\r
+isq10:;\r
+asm push ax\r
+asm push dx\r
+asm div bx\r
+asm sub ax,bx\r
+asm cmp ax,1\r
+asm jbe isq90\r
+asm cmp ax,-1\r
+asm jae isq90\r
+asm sar ax,1\r
+asm add bx,ax\r
+asm pop dx\r
+asm pop ax\r
+asm jmp isq10\r
+isq90:;\r
+asm pop dx\r
+asm pop ax\r
+exitrout:;\r
+asm mov ax,bx\r
+}\r
+\r
+//-------------------------------------------------------------------------\r
+// InitBgChange()\r
+//-------------------------------------------------------------------------\r
+void InitBgChange(short stimer, unsigned *scolors, short gtimer, unsigned *gcolors, byte flag)\r
+{\r
+ skytimer_reset = skytimer = stimer;\r
+ if (scolors)\r
+ skycolor = scolors;\r
+\r
+ groundtimer_reset = groundtimer = gtimer;\r
+ if (gcolors)\r
+ groundcolor = gcolors;\r
+\r
+ bgflag = flag;\r
+}\r
+\r
+////////////////////////////////////////////////////////\r
+//\r
+// DisplayStatus\r
+//\r
+// Stat_Flag - contains the type of status displayed\r
+// -- also uses status_delay (global variable) will not\r
+// change display until this variable is zero.\r
+// -- heirarchy is determined by the series of if statements,\r
+// to change it, rearrange th if statements.\r
+//\r
+////////////////////////////////////////////////////////\r
+\r
+#define MESSAGEDELAY 25\r
+void DisplayStatus (status_flags *stat_flag)\r
+{\r
+ status_flags temp_status;\r
+\r
+\r
+ if (*stat_flag == S_TIMESTOP)\r
+ return;\r
+\r
+ if (status_delay > 0)\r
+ {\r
+ status_delay -= realtics;\r
+ return;\r
+ }\r
+ else\r
+ status_delay = 0;\r
+\r
+ // check for a change in status from previous call\r
+\r
+ temp_status = S_VIEWING; //precaution\r
+\r
+ if (Keyboard[sc_Control] || control.button0)\r
+ temp_status = S_MISSLE;\r
+\r
+ if (Keyboard[sc_Z] && !Keyboard[sc_F10])\r
+ temp_status = S_ZAPPER;\r
+\r
+ if ((Keyboard[sc_X] && !Keyboard[sc_F10]) || Keyboard[sc_Enter])\r
+ temp_status = S_XTER;\r
+\r
+ if (control.x)\r
+ temp_status = S_TURN;\r
+\r
+ if ((Keyboard[sc_V] || Keyboard[sc_Tab]) && control.x)\r
+ temp_status = S_QTURN;\r
+\r
+ if (Keyboard[sc_Alt] && control.x)\r
+ temp_status = S_SIDESTEP;\r
+\r
+ if (control.y < 0)\r
+ temp_status = S_ADVANCE;\r
+\r
+ if (control.y > 0)\r
+ temp_status = S_RETREAT;\r
+\r
+ if (Keyboard[sc_F5])\r
+ temp_status = S_JOYSTICK;\r
+\r
+ if (Keyboard[sc_F4])\r
+ temp_status = S_RESTORING;\r
+\r
+ if (Keyboard[sc_F3])\r
+ temp_status = S_SAVING;\r
+\r
+ if (Keyboard[sc_F2])\r
+ temp_status = S_SND;\r
+\r
+ if (Keyboard[sc_F1])\r
+ temp_status = S_HELP;\r
+\r
+ if (temp_status != *stat_flag)\r
+ {\r
+ *stat_flag = temp_status;\r
+\r
+\r
+ switch (*stat_flag)\r
+ {\r
+ case S_MISSLE:\r
+ DisplaySMsg("Magick Missile", NULL);\r
+ status_delay = MESSAGEDELAY;\r
+ break;\r
+\r
+ case S_ZAPPER:\r
+ if (gamestate.bolts)\r
+ {\r
+ DisplaySMsg("Zapper", NULL);\r
+ status_delay = MESSAGEDELAY+10;\r
+ }\r
+ break;\r
+\r
+ case S_XTER:\r
+ if (gamestate.nukes)\r
+ {\r
+ DisplaySMsg("Xterminator", NULL);\r
+ status_delay = MESSAGEDELAY+5;\r
+ }\r
+ break;\r
+\r
+ case S_TURN:\r
+ DisplaySMsg("Turning", NULL);\r
+ status_delay = MESSAGEDELAY;\r
+ break;\r
+\r
+ case S_QTURN:\r
+ DisplaySMsg("Quick Turning", NULL);\r
+ status_delay = MESSAGEDELAY;\r
+ break;\r
+\r
+ case S_SIDESTEP:\r
+ DisplaySMsg("Sidestepping", NULL);\r
+ status_delay = MESSAGEDELAY;\r
+ break;\r
+\r
+ case S_ADVANCE:\r
+ DisplaySMsg("Advancing", NULL);\r
+ status_delay = MESSAGEDELAY;\r
+ break;\r
+\r
+ case S_RETREAT:\r
+ DisplaySMsg("Retreating", NULL);\r
+ status_delay = MESSAGEDELAY;\r
+ break;\r
+\r
+ case S_JOYSTICK:\r
+ DisplaySMsg("Adjusting Joystick", NULL);\r
+ break;\r
+\r
+ case S_RESTORING:\r
+ DisplaySMsg("Restoring", NULL);\r
+ break;\r
+\r
+ case S_SAVING:\r
+ DisplaySMsg("Saving", NULL);\r
+ break;\r
+\r
+ case S_SND:\r
+ DisplaySMsg("Select Sound", NULL);\r
+ break;\r
+\r
+ case S_HELP:\r
+ DisplaySMsg("Getting Help", NULL);\r
+ break;\r
+\r
+ case S_VIEWING:\r
+ DisplaySMsg("Viewing", NULL);\r
+ break;\r
+ }\r
+ bufferofs = displayofs = screenloc[screenpage];\r
+\r
+ }\r
+}\r