+++ /dev/null
-/* 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
-// C3_PLAY.C\r
-\r
-#include "C3_DEF.H"\r
-#pragma hdrstop\r
-\r
-/*\r
-=============================================================================\r
-\r
- LOCAL CONSTANTS\r
-\r
-=============================================================================\r
-*/\r
-\r
-#define POINTTICS 6\r
-\r
-\r
-/*\r
-=============================================================================\r
-\r
- GLOBAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-ControlInfo c;\r
-boolean running,slowturn;\r
-\r
-int bordertime;\r
-objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj,*objfreelist;\r
-\r
-unsigned farmapylookup[MAPSIZE];\r
-byte *nearmapylookup[MAPSIZE];\r
-\r
-boolean singlestep,godmode;\r
-int extravbls;\r
-\r
-//\r
-// replacing refresh manager\r
-//\r
-unsigned mapwidth,mapheight,tics;\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
-/*\r
-=============================================================================\r
-\r
- LOCAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-void CalcBounds (objtype *ob);\r
-void DrawPlayScreen (void);\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
-\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 264\r
-#define MAXY 146\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
- if (screenfaded) // don't do anything with a faded screen\r
- return;\r
-\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
-\r
-//\r
-// F1-F7/ESC to enter control panel\r
-//\r
- if ( (LastScan >= sc_F1 && LastScan <= sc_F7) || LastScan == sc_Escape)\r
- {\r
- StopMusic ();\r
- NormalScreen ();\r
- FreeUpMemory ();\r
- US_CenterWindow (20,8);\r
- US_CPrint ("Loading");\r
- VW_UpdateScreen ();\r
- US_ControlPanel();\r
- if (abortgame)\r
- {\r
- playstate = ex_abort;\r
- return;\r
- }\r
- StartMusic ();\r
- IN_ClearKeysDown();\r
- if (restartgame)\r
- playstate = ex_resetgame;\r
- if (loadedgame)\r
- playstate = ex_loadedgame;\r
- DrawPlayScreen ();\r
- CacheScaleds ();\r
- lasttimecount = TimeCount;\r
- if (MousePresent) Mouse(MDelta); // Clear accumulated mouse movement\r
- }\r
-\r
-//\r
-// F10-? debug keys\r
-//\r
- if (Keyboard[sc_F10])\r
- {\r
- DebugKeys();\r
- if (MousePresent) Mouse(MDelta); // Clear accumulated mouse movement\r
- lasttimecount = TimeCount;\r
- }\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
-\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
-\r
-//==========================================================================\r
-\r
-/*\r
-===================\r
-=\r
-= PollControls\r
-=\r
-===================\r
-*/\r
-\r
-void PollControls (void)\r
-{\r
- unsigned buttons;\r
-\r
- IN_ReadControl(0,&c);\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
- c.button0 = 1;\r
- if (buttons&2)\r
- c.button1 = 1;\r
-\r
- }\r
-\r
- if (Controls[0]==ctrl_Joystick)\r
- {\r
- if (c.x>120 || c.x <-120 || c.y>120 || c.y<-120)\r
- running = true;\r
- else\r
- running = false;\r
- if (c.x>-48 && c.x<48)\r
- slowturn = true;\r
- else\r
- slowturn = false;\r
- }\r
- else\r
- {\r
- if (Keyboard[sc_RShift])\r
- running = true;\r
- else\r
- running = false;\r
- if (c.button0)\r
- slowturn = true;\r
- else\r
- slowturn = false;\r
- }\r
-}\r
-\r
-//==========================================================================\r
-\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
-\r
-//==========================================================================\r
-\r
-\r
-/*\r
-===================\r
-=\r
-= PlayLoop\r
-=\r
-===================\r
-*/\r
-\r
-void PlayLoop (void)\r
-{\r
- int give;\r
-\r
- void (*think)();\r
-\r
- ingame = true;\r
- playstate = TimeCount = 0;\r
- gamestate.shotpower = handheight = 0;\r
- pointcount = pointsleft = 0;\r
-\r
- DrawLevelNumber (gamestate.mapon);\r
- DrawBars ();\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
- c.xaxis = 1;\r
- if (++TimeCount == 300)\r
- return;\r
-#endif\r
-\r
- for (obj = player;obj;obj = obj->next)\r
- if (obj->active)\r
- {\r
- if (obj->ticcount)\r
- {\r
- obj->ticcount-=tics;\r
- while ( obj->ticcount <= 0)\r
- {\r
- think = obj->state->think;\r
- if (think)\r
- {\r
- think (obj);\r
- if (!obj->state)\r
- {\r
- RemoveObj (obj);\r
- goto nextactor;\r
- }\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
- think = obj->state->think;\r
- if (think)\r
- {\r
- think (obj);\r
- if (!obj->state)\r
- RemoveObj (obj);\r
- }\r
-nextactor:;\r
- }\r
-\r
-\r
- if (bordertime)\r
- {\r
- bordertime -= tics;\r
- if (bordertime<=0)\r
- {\r
- bordertime = 0;\r
- VW_ColorBorder (3);\r
- }\r
- }\r
-\r
- if (pointcount)\r
- {\r
- pointcount -= tics;\r
- if (pointcount <= 0)\r
- {\r
- pointcount += POINTTICS;\r
- give = (pointsleft > 1000)? 1000 :\r
- (\r
- (pointsleft > 100)? 100 :\r
- ((pointsleft < 20)? pointsleft : 20)\r
- );\r
- SD_PlaySound (GETPOINTSSND);\r
- AddPoints (give);\r
- pointsleft -= give;\r
- if (!pointsleft)\r
- pointcount = 0;\r
- }\r
- }\r
-\r
- ThreeDRefresh ();\r
-\r
- CheckKeys();\r
- if (singlestep)\r
- {\r
- VW_WaitVBL(14);\r
- lasttimecount = TimeCount;\r
- }\r
- if (extravbls)\r
- VW_WaitVBL(extravbls);\r
-\r
- }while (!playstate);\r
- StopMusic ();\r
-\r
- ingame = false;\r
- if (bordertime)\r
- {\r
- bordertime = 0;\r
- VW_ColorBorder (3);\r
- }\r
-\r
- if (!abortgame)\r
- AddPoints (pointsleft);\r
- else\r
- abortgame = false;\r
-}\r
-\r