]> 4ch.mooo.com Git - 16.git/blobdiff - src/lib/hb/c3_play.c
[16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / src / lib / hb / c3_play.c
diff --git a/src/lib/hb/c3_play.c b/src/lib/hb/c3_play.c
new file mode 100755 (executable)
index 0000000..112041f
--- /dev/null
@@ -0,0 +1,584 @@
+/* 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