+/* Reconstructed Commander Keen 4-6 Source Code\r
+ * Copyright (C) 2021 K1n9_Duk3\r
+ *\r
+ * This file is loosely based on:\r
+ * Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\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
+// CK_MAIN.C\r
+/*\r
+=============================================================================\r
+\r
+ COMMANDER KEEN\r
+\r
+ An Id Software production\r
+\r
+=============================================================================\r
+*/\r
+\r
+#include "CK_DEF.H"\r
+\r
+/*\r
+=============================================================================\r
+\r
+ GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+boolean tedlevel;\r
+Uint16 tedlevelnum;\r
+\r
+char str[80], str2[20];\r
+boolean storedemo, jerk;\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= SizeText\r
+=\r
+= Calculates width and height of a string that contains line breaks\r
+= (Note: only the height is ever used, width is NOT calculated correctly)\r
+=\r
+=====================\r
+*/\r
+\r
+void SizeText(char *text, Uint16 *width, Uint16 *height)\r
+{\r
+ register char *ptr;\r
+ char c;\r
+ Uint16 w, h;\r
+ char strbuf[80];\r
+\r
+ *width = *height = 0;\r
+ ptr = &strbuf[0];\r
+ while ((c=*(text++)) != '\0')\r
+ {\r
+ *(ptr++) = c;\r
+ if (c == '\n' || !*text)\r
+ {\r
+ USL_MeasureString(strbuf, &w, &h); // BUG: strbuf may not have a terminating '\0' at the end!\r
+ *height += h;\r
+ if (*width < w)\r
+ {\r
+ *width = w;\r
+ }\r
+ ptr = &strbuf[0];\r
+ }\r
+ }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= ShutdownId\r
+=\r
+= Shuts down all ID_?? managers\r
+=\r
+==========================\r
+*/\r
+\r
+void ShutdownId(void)\r
+{\r
+ US_Shutdown();\r
+ SD_Shutdown();\r
+ IN_Shutdown();\r
+ RF_Shutdown();\r
+ VW_Shutdown();\r
+ CA_Shutdown();\r
+ MM_Shutdown();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= InitGame\r
+=\r
+= Load a few things right away\r
+=\r
+==========================\r
+*/\r
+\r
+void InitGame(void)\r
+{\r
+ static char *ParmStrings[] = {"JERK", ""};\r
+ void MML_UseSpace (Uint16 segstart, Uint16 seglength);\r
+\r
+ Uint16 segstart,seglength;\r
+ Sint16 i;\r
+\r
+ // Note: The value of the jerk variable is replaced with the value\r
+ // read from the config file during US_Startup, which means the\r
+ // JERK parameter has absolutely no effect if a valid config file\r
+ // exists. The parameter check should be moved to some place after\r
+ // US_Startup to make it work reliably.\r
+ \r
+ for (i=1; i < _argc; i++)\r
+ {\r
+ if (US_CheckParm(_argv[i], ParmStrings) == 0)\r
+ {\r
+ jerk = true;\r
+ }\r
+ }\r
+\r
+ US_TextScreen();\r
+\r
+ MM_Startup();\r
+ VW_Startup();\r
+ RF_Startup();\r
+ IN_Startup();\r
+ SD_Startup();\r
+ US_Startup();\r
+\r
+ US_UpdateTextScreen();\r
+\r
+ CA_Startup();\r
+ US_Setup();\r
+\r
+ US_SetLoadSaveHooks(&LoadTheGame, &SaveTheGame, &ResetGame);\r
+ drawcachebox = DialogDraw;\r
+ updatecachebox = DialogUpdate;\r
+ finishcachebox = DialogFinish;\r
+\r
+//\r
+// load in and lock down some basic chunks\r
+//\r
+\r
+ CA_ClearMarks();\r
+\r
+ CA_MarkGrChunk(STARTFONT);\r
+ CA_MarkGrChunk(STARTTILE8);\r
+ CA_MarkGrChunk(STARTTILE8M);\r
+#if GRMODE == EGAGR\r
+ CA_MarkGrChunk(CORDPICM);\r
+ CA_MarkGrChunk(METALPOLEPICM);\r
+#endif\r
+\r
+ CA_CacheMarks(NULL);\r
+\r
+ MM_SetLock(&grsegs[STARTFONT], true);\r
+ MM_SetLock(&grsegs[STARTTILE8], true);\r
+ MM_SetLock(&grsegs[STARTTILE8M], true);\r
+#if GRMODE == EGAGR\r
+ MM_SetLock(&grsegs[CORDPICM], true);\r
+ MM_SetLock(&grsegs[METALPOLEPICM], true);\r
+#endif\r
+\r
+ fontcolor = WHITE;\r
+\r
+ US_FinishTextScreen();\r
+\r
+//\r
+// reclaim the memory from the linked in text screen\r
+//\r
+ segstart = FP_SEG(&introscn);\r
+ seglength = 4000/16;\r
+ if (FP_OFF(&introscn))\r
+ {\r
+ segstart++;\r
+ seglength--;\r
+ }\r
+ MML_UseSpace (segstart,seglength);\r
+\r
+ VW_SetScreenMode(GRMODE);\r
+#if GRMODE == CGAGR\r
+ VW_ColorBorder(BROWN);\r
+#else\r
+ VW_ColorBorder(CYAN);\r
+#endif\r
+ VW_ClearVideo(BLACK);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==========================\r
+=\r
+= Quit\r
+=\r
+==========================\r
+*/\r
+\r
+void Quit(char *error)\r
+{\r
+ Uint16 finscreen;\r
+\r
+ if (!error)\r
+ {\r
+ CA_SetAllPurge();\r
+ CA_CacheGrChunk(ORDERSCREEN);\r
+ finscreen = (Uint16)grsegs[ORDERSCREEN];\r
+ }\r
+\r
+ // BUG: VW_ClearVideo may brick the system if screenseg is 0\r
+ // (i.e. VW_SetScreenMode has not been executed) - this may\r
+ // happen if the code runs into an error during InitGame\r
+ // (EMS/XMS errors, files not found etc.)\r
+ VW_ClearVideo(BLACK);\r
+ VW_SetLineWidth(40);\r
+\r
+ ShutdownId();\r
+ if (error && *error)\r
+ {\r
+ puts(error);\r
+ if (tedlevel)\r
+ {\r
+ getch();\r
+ execlp("TED5.EXE", "TED5.EXE", "/LAUNCH", NULL);\r
+ }\r
+ else if (US_ParmPresent("windows"))\r
+ {\r
+ bioskey(0);\r
+ }\r
+ exit(1);\r
+ }\r
+\r
+ if (!NoWait)\r
+ {\r
+ movedata(finscreen, 7, 0xB800, 0, 4000);\r
+ gotoxy(1, 24);\r
+ if (US_ParmPresent("windows"))\r
+ {\r
+ bioskey(0);\r
+ }\r
+ }\r
+\r
+ exit(0);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= TEDDeath\r
+=\r
+==================\r
+*/\r
+\r
+void TEDDeath(void)\r
+{\r
+ ShutdownId();\r
+ execlp("TED5.EXE", "TED5.EXE", "/LAUNCH", NULL);\r
+ // BUG: should call exit(1); here in case starting TED5 fails\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= CheckMemory\r
+=\r
+==================\r
+*/\r
+\r
+void CheckMemory(void)\r
+{\r
+ Uint16 finscreen;\r
+\r
+ if (mminfo.nearheap+mminfo.farheap+mminfo.EMSmem+mminfo.XMSmem >= MINMEMORY)\r
+ return;\r
+\r
+ CA_CacheGrChunk (OUTOFMEM);\r
+ finscreen = (Uint16)grsegs[OUTOFMEM];\r
+ ShutdownId();\r
+ movedata (finscreen,7,0xb800,0,4000);\r
+ gotoxy (1,24);\r
+ exit(1);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= DemoLoop\r
+=\r
+=====================\r
+*/\r
+\r
+void DemoLoop(void)\r
+{\r
+ static char *ParmStrings[] = {"easy", "normal", "hard", ""};\r
+\r
+ register Sint16 i, state;\r
+ Sint16 level;\r
+\r
+//\r
+// check for launch from ted\r
+//\r
+ if (tedlevel)\r
+ {\r
+ NewGame();\r
+ CA_LoadAllSounds();\r
+ gamestate.mapon = tedlevelnum;\r
+ restartgame = gd_Normal;\r
+ for (i = 1;i < _argc;i++)\r
+ {\r
+ if ( (level = US_CheckParm(_argv[i],ParmStrings)) == -1)\r
+ continue;\r
+\r
+ restartgame = level+gd_Easy;\r
+ break;\r
+ }\r
+ GameLoop();\r
+ TEDDeath();\r
+ }\r
+\r
+//\r
+// demo loop\r
+//\r
+ state = 0;\r
+ playstate = ex_stillplaying;\r
+ while (1)\r
+ {\r
+ switch (state++)\r
+ {\r
+ case 0:\r
+#if GRMODE == CGAGR\r
+ ShowTitle();\r
+#else\r
+ if (nopan)\r
+ {\r
+ ShowTitle();\r
+ }\r
+ else\r
+ {\r
+ Terminator();\r
+ }\r
+#endif\r
+ break;\r
+\r
+ case 1:\r
+ RunDemo(0);\r
+ break;\r
+\r
+ case 2:\r
+#if GRMODE == CGAGR\r
+ ShowCredits();\r
+#else\r
+ StarWars();\r
+#endif\r
+ break;\r
+\r
+ case 3:\r
+ RunDemo(1);\r
+ break;\r
+\r
+ case 4:\r
+ ShowHighScores();\r
+ break;\r
+\r
+ case 5:\r
+ RunDemo(2);\r
+ break;\r
+\r
+ case 6:\r
+ state = 0;\r
+ RunDemo(3);\r
+ break;\r
+ }\r
+\r
+ while (playstate == ex_resetgame || playstate == ex_loadedgame)\r
+ {\r
+ GameLoop();\r
+ ShowHighScores();\r
+ if (playstate == ex_resetgame || playstate == ex_loadedgame)\r
+ {\r
+ continue; // don't show title screen, go directly to GameLoop();\r
+ }\r
+ ShowTitle();\r
+ ///////////////\r
+ // this is completely useless:\r
+ if (playstate == ex_resetgame || playstate == ex_loadedgame)\r
+ {\r
+ continue;\r
+ }\r
+ ///////////////\r
+ }\r
+ }\r
+}\r
+\r
+//===========================================================================\r
+\r
+#if (GRMODE == EGAGR) && !(defined KEEN6)\r
+/*\r
+=====================\r
+=\r
+= CheckCutFile\r
+=\r
+=====================\r
+*/\r
+\r
+#define FILE_GR1 GREXT"1."EXTENSION\r
+#define FILE_GR2 GREXT"2."EXTENSION\r
+#define FILE_GRAPH GREXT"GRAPH."EXTENSION\r
+\r
+static void CheckCutFile(void)\r
+{\r
+ register Sint16 ohandle, ihandle;\r
+ Sint16 handle;\r
+ Sint32 size;\r
+ void far *buffer;\r
+\r
+ if ( (handle = open(FILE_GRAPH, O_BINARY|O_RDONLY)) != -1)\r
+ {\r
+ close(handle);\r
+ return;\r
+ }\r
+ puts("Combining "FILE_GR1" and "FILE_GR2" into "FILE_GRAPH"...");\r
+ if (rename(FILE_GR1, FILE_GRAPH) == -1)\r
+ {\r
+ puts("Can't rename "FILE_GR1"!");\r
+ exit(1);\r
+ }\r
+ if ( (ohandle = open(FILE_GRAPH, O_BINARY|O_APPEND|O_WRONLY)) == -1)\r
+ {\r
+ puts("Can't open "FILE_GRAPH"!");\r
+ exit(1);\r
+ }\r
+ lseek(ohandle, 0, SEEK_END);\r
+ if ( (ihandle = open(FILE_GR2, O_BINARY|O_RDONLY)) == -1)\r
+ {\r
+ puts("Can't find "FILE_GR2"!");\r
+ exit(1);\r
+ }\r
+ size = filelength(ihandle);\r
+ buffer = farmalloc(32000);\r
+ while (size)\r
+ {\r
+ if (size > 32000)\r
+ {\r
+ CA_FarRead(ihandle, buffer, 32000);\r
+ CA_FarWrite(ohandle, buffer, 32000);\r
+ size -= 32000;\r
+ }\r
+ else\r
+ {\r
+ CA_FarRead(ihandle, buffer, size);\r
+ CA_FarWrite(ohandle, buffer, size);\r
+ size = 0;\r
+ }\r
+ }\r
+ farfree(buffer);\r
+ close(ohandle);\r
+ close(ihandle);\r
+ unlink(FILE_GR2);\r
+}\r
+#endif\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= main\r
+=\r
+==========================\r
+*/\r
+\r
+void main(void)\r
+{\r
+#if (GRMODE == EGAGR) && !(defined KEEN6)\r
+ CheckCutFile();\r
+#endif\r
+\r
+ if (US_ParmPresent("DEMO"))\r
+ storedemo = true;\r
+\r
+ if (US_ParmPresent("JOYPAD"))\r
+ joypad = true; // Note: the joypad variable is never used\r
+ \r
+ InitGame();\r
+ CheckMemory();\r
+ if (NoWait || tedlevel)\r
+ debugok = true;\r
+\r
+ DemoLoop();\r
+ Quit("Demo loop exited???");\r
+}
\ No newline at end of file