]> 4ch.mooo.com Git - 16.git/blob - 16/keen456/KEEN4-6/CK_MAIN.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / CK_MAIN.C
1 /* Reconstructed Commander Keen 4-6 Source Code\r
2  * Copyright (C) 2021 K1n9_Duk3\r
3  *\r
4  * This file is loosely based on:\r
5  * Keen Dreams Source Code\r
6  * Copyright (C) 2014 Javier M. Chavez\r
7  *\r
8  * This program is free software; you can redistribute it and/or modify\r
9  * it under the terms of the GNU General Public License as published by\r
10  * the Free Software Foundation; either version 2 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU General Public License along\r
19  * with this program; if not, write to the Free Software Foundation, Inc.,\r
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
21  */\r
22 \r
23 // CK_MAIN.C\r
24 /*\r
25 =============================================================================\r
26 \r
27                                                         COMMANDER KEEN\r
28 \r
29                                         An Id Software production\r
30 \r
31 =============================================================================\r
32 */\r
33 \r
34 #include "CK_DEF.H"\r
35 \r
36 /*\r
37 =============================================================================\r
38 \r
39                                                  GLOBAL VARIABLES\r
40 \r
41 =============================================================================\r
42 */\r
43 \r
44 boolean tedlevel;\r
45 Uint16 tedlevelnum;\r
46 \r
47 char str[80], str2[20];\r
48 boolean storedemo, jerk;\r
49 \r
50 /*\r
51 =============================================================================\r
52 \r
53                                                  LOCAL VARIABLES\r
54 \r
55 =============================================================================\r
56 */\r
57 \r
58 //===========================================================================\r
59 \r
60 /*\r
61 =====================\r
62 =\r
63 = SizeText\r
64 =\r
65 = Calculates width and height of a string that contains line breaks\r
66 = (Note: only the height is ever used, width is NOT calculated correctly)\r
67 =\r
68 =====================\r
69 */\r
70 \r
71 void SizeText(char *text, Uint16 *width, Uint16 *height)\r
72 {\r
73         register char *ptr;\r
74         char c;\r
75         Uint16 w, h;\r
76         char strbuf[80];\r
77 \r
78         *width = *height = 0;\r
79         ptr = &strbuf[0];\r
80         while ((c=*(text++)) != '\0')\r
81         {\r
82                 *(ptr++) = c;\r
83                 if (c == '\n' || !*text)\r
84                 {\r
85                         USL_MeasureString(strbuf, &w, &h);      // BUG: strbuf may not have a terminating '\0' at the end!\r
86                         *height += h;\r
87                         if (*width < w)\r
88                         {\r
89                                 *width = w;\r
90                         }\r
91                         ptr = &strbuf[0];\r
92                 }\r
93         }\r
94 }\r
95 \r
96 //===========================================================================\r
97 \r
98 /*\r
99 ==========================\r
100 =\r
101 = ShutdownId\r
102 =\r
103 = Shuts down all ID_?? managers\r
104 =\r
105 ==========================\r
106 */\r
107 \r
108 void ShutdownId(void)\r
109 {\r
110         US_Shutdown();\r
111         SD_Shutdown();\r
112         IN_Shutdown();\r
113         RF_Shutdown();\r
114         VW_Shutdown();\r
115         CA_Shutdown();\r
116         MM_Shutdown();\r
117 }\r
118 \r
119 \r
120 //===========================================================================\r
121 \r
122 /*\r
123 ==========================\r
124 =\r
125 = InitGame\r
126 =\r
127 = Load a few things right away\r
128 =\r
129 ==========================\r
130 */\r
131 \r
132 void InitGame(void)\r
133 {\r
134         static char *ParmStrings[] = {"JERK", ""};\r
135         void MML_UseSpace (Uint16 segstart, Uint16 seglength);\r
136 \r
137         Uint16 segstart,seglength;\r
138         Sint16 i;\r
139 \r
140         // Note: The value of the jerk variable is replaced with the value\r
141         // read from the config file during US_Startup, which means the\r
142         // JERK parameter has absolutely no effect if a valid config file\r
143         // exists. The parameter check should be moved to some place after\r
144         // US_Startup to make it work reliably.\r
145         \r
146         for (i=1; i < _argc; i++)\r
147         {\r
148                 if (US_CheckParm(_argv[i], ParmStrings) == 0)\r
149                 {\r
150                         jerk = true;\r
151                 }\r
152         }\r
153 \r
154         US_TextScreen();\r
155 \r
156         MM_Startup();\r
157         VW_Startup();\r
158         RF_Startup();\r
159         IN_Startup();\r
160         SD_Startup();\r
161         US_Startup();\r
162 \r
163         US_UpdateTextScreen();\r
164 \r
165         CA_Startup();\r
166         US_Setup();\r
167 \r
168         US_SetLoadSaveHooks(&LoadTheGame, &SaveTheGame, &ResetGame);\r
169         drawcachebox = DialogDraw;\r
170         updatecachebox = DialogUpdate;\r
171         finishcachebox = DialogFinish;\r
172 \r
173 //\r
174 // load in and lock down some basic chunks\r
175 //\r
176 \r
177         CA_ClearMarks();\r
178 \r
179         CA_MarkGrChunk(STARTFONT);\r
180         CA_MarkGrChunk(STARTTILE8);\r
181         CA_MarkGrChunk(STARTTILE8M);\r
182 #if GRMODE == EGAGR\r
183         CA_MarkGrChunk(CORDPICM);\r
184         CA_MarkGrChunk(METALPOLEPICM);\r
185 #endif\r
186 \r
187         CA_CacheMarks(NULL);\r
188 \r
189         MM_SetLock(&grsegs[STARTFONT], true);\r
190         MM_SetLock(&grsegs[STARTTILE8], true);\r
191         MM_SetLock(&grsegs[STARTTILE8M], true);\r
192 #if GRMODE == EGAGR\r
193         MM_SetLock(&grsegs[CORDPICM], true);\r
194         MM_SetLock(&grsegs[METALPOLEPICM], true);\r
195 #endif\r
196 \r
197         fontcolor = WHITE;\r
198 \r
199         US_FinishTextScreen();\r
200 \r
201 //\r
202 // reclaim the memory from the linked in text screen\r
203 //\r
204         segstart = FP_SEG(&introscn);\r
205         seglength = 4000/16;\r
206         if (FP_OFF(&introscn))\r
207         {\r
208                 segstart++;\r
209                 seglength--;\r
210         }\r
211         MML_UseSpace (segstart,seglength);\r
212 \r
213         VW_SetScreenMode(GRMODE);\r
214 #if GRMODE == CGAGR\r
215         VW_ColorBorder(BROWN);\r
216 #else\r
217         VW_ColorBorder(CYAN);\r
218 #endif\r
219         VW_ClearVideo(BLACK);\r
220 }\r
221 \r
222 //===========================================================================\r
223 \r
224 /*\r
225 ==========================\r
226 =\r
227 = Quit\r
228 =\r
229 ==========================\r
230 */\r
231 \r
232 void Quit(char *error)\r
233 {\r
234         Uint16 finscreen;\r
235 \r
236         if (!error)\r
237         {\r
238                 CA_SetAllPurge();\r
239                 CA_CacheGrChunk(ORDERSCREEN);\r
240                 finscreen = (Uint16)grsegs[ORDERSCREEN];\r
241         }\r
242 \r
243         // BUG: VW_ClearVideo may brick the system if screenseg is 0\r
244         // (i.e. VW_SetScreenMode has not been executed) - this may\r
245         // happen if the code runs into an error during InitGame\r
246         // (EMS/XMS errors, files not found etc.)\r
247         VW_ClearVideo(BLACK);\r
248         VW_SetLineWidth(40);\r
249 \r
250         ShutdownId();\r
251         if (error && *error)\r
252         {\r
253                 puts(error);\r
254                 if (tedlevel)\r
255                 {\r
256                         getch();\r
257                         execlp("TED5.EXE", "TED5.EXE", "/LAUNCH", NULL);\r
258                 }\r
259                 else if (US_ParmPresent("windows"))\r
260                 {\r
261                         bioskey(0);\r
262                 }\r
263                 exit(1);\r
264         }\r
265 \r
266         if (!NoWait)\r
267         {\r
268                 movedata(finscreen, 7, 0xB800, 0, 4000);\r
269                 gotoxy(1, 24);\r
270                 if (US_ParmPresent("windows"))\r
271                 {\r
272                         bioskey(0);\r
273                 }\r
274         }\r
275 \r
276         exit(0);\r
277 }\r
278 \r
279 //===========================================================================\r
280 \r
281 /*\r
282 ==================\r
283 =\r
284 = TEDDeath\r
285 =\r
286 ==================\r
287 */\r
288 \r
289 void TEDDeath(void)\r
290 {\r
291         ShutdownId();\r
292         execlp("TED5.EXE", "TED5.EXE", "/LAUNCH", NULL);\r
293         // BUG: should call exit(1); here in case starting TED5 fails\r
294 }\r
295 \r
296 //===========================================================================\r
297 \r
298 /*\r
299 ==================\r
300 =\r
301 = CheckMemory\r
302 =\r
303 ==================\r
304 */\r
305 \r
306 void CheckMemory(void)\r
307 {\r
308         Uint16 finscreen;\r
309 \r
310         if (mminfo.nearheap+mminfo.farheap+mminfo.EMSmem+mminfo.XMSmem >= MINMEMORY)\r
311                 return;\r
312 \r
313         CA_CacheGrChunk (OUTOFMEM);\r
314         finscreen = (Uint16)grsegs[OUTOFMEM];\r
315         ShutdownId();\r
316         movedata (finscreen,7,0xb800,0,4000);\r
317         gotoxy (1,24);\r
318         exit(1);\r
319 }\r
320 \r
321 //===========================================================================\r
322 \r
323 /*\r
324 =====================\r
325 =\r
326 = DemoLoop\r
327 =\r
328 =====================\r
329 */\r
330 \r
331 void DemoLoop(void)\r
332 {\r
333         static char *ParmStrings[] = {"easy", "normal", "hard", ""};\r
334 \r
335         register Sint16 i, state;\r
336         Sint16 level;\r
337 \r
338 //\r
339 // check for launch from ted\r
340 //\r
341         if (tedlevel)\r
342         {\r
343                 NewGame();\r
344                 CA_LoadAllSounds();\r
345                 gamestate.mapon = tedlevelnum;\r
346                 restartgame = gd_Normal;\r
347                 for (i = 1;i < _argc;i++)\r
348                 {\r
349                         if ( (level = US_CheckParm(_argv[i],ParmStrings)) == -1)\r
350                                 continue;\r
351 \r
352                         restartgame = level+gd_Easy;\r
353                         break;\r
354                 }\r
355                 GameLoop();\r
356                 TEDDeath();\r
357         }\r
358 \r
359 //\r
360 // demo loop\r
361 //\r
362         state = 0;\r
363         playstate = ex_stillplaying;\r
364         while (1)\r
365         {\r
366                 switch (state++)\r
367                 {\r
368                 case 0:\r
369 #if GRMODE == CGAGR\r
370                         ShowTitle();\r
371 #else\r
372                         if (nopan)\r
373                         {\r
374                                 ShowTitle();\r
375                         }\r
376                         else\r
377                         {\r
378                                 Terminator();\r
379                         }\r
380 #endif\r
381                         break;\r
382 \r
383                 case 1:\r
384                         RunDemo(0);\r
385                         break;\r
386 \r
387                 case 2:\r
388 #if GRMODE == CGAGR\r
389                         ShowCredits();\r
390 #else\r
391                         StarWars();\r
392 #endif\r
393                         break;\r
394 \r
395                 case 3:\r
396                         RunDemo(1);\r
397                         break;\r
398 \r
399                 case 4:\r
400                         ShowHighScores();\r
401                         break;\r
402 \r
403                 case 5:\r
404                         RunDemo(2);\r
405                         break;\r
406 \r
407                 case 6:\r
408                         state = 0;\r
409                         RunDemo(3);\r
410                         break;\r
411                 }\r
412 \r
413                 while (playstate == ex_resetgame || playstate == ex_loadedgame)\r
414                 {\r
415                         GameLoop();\r
416                         ShowHighScores();\r
417                         if (playstate == ex_resetgame || playstate == ex_loadedgame)\r
418                         {\r
419                                 continue;       // don't show title screen, go directly to GameLoop();\r
420                         }\r
421                         ShowTitle();\r
422                         ///////////////\r
423                         // this is completely useless:\r
424                         if (playstate == ex_resetgame || playstate == ex_loadedgame)\r
425                         {\r
426                                 continue;\r
427                         }\r
428                         ///////////////\r
429                 }\r
430         }\r
431 }\r
432 \r
433 //===========================================================================\r
434 \r
435 #if (GRMODE == EGAGR) && !(defined KEEN6)\r
436 /*\r
437 =====================\r
438 =\r
439 = CheckCutFile\r
440 =\r
441 =====================\r
442 */\r
443 \r
444 #define FILE_GR1 GREXT"1."EXTENSION\r
445 #define FILE_GR2 GREXT"2."EXTENSION\r
446 #define FILE_GRAPH GREXT"GRAPH."EXTENSION\r
447 \r
448 static void CheckCutFile(void)\r
449 {\r
450         register Sint16 ohandle, ihandle;\r
451         Sint16 handle;\r
452         Sint32 size;\r
453         void far *buffer;\r
454 \r
455         if ( (handle = open(FILE_GRAPH, O_BINARY|O_RDONLY)) != -1)\r
456         {\r
457                 close(handle);\r
458                 return;\r
459         }\r
460         puts("Combining "FILE_GR1" and "FILE_GR2" into "FILE_GRAPH"...");\r
461         if (rename(FILE_GR1, FILE_GRAPH) == -1)\r
462         {\r
463                 puts("Can't rename "FILE_GR1"!");\r
464                 exit(1);\r
465         }\r
466         if ( (ohandle = open(FILE_GRAPH, O_BINARY|O_APPEND|O_WRONLY)) == -1)\r
467         {\r
468                 puts("Can't open "FILE_GRAPH"!");\r
469                 exit(1);\r
470         }\r
471         lseek(ohandle, 0, SEEK_END);\r
472         if ( (ihandle = open(FILE_GR2, O_BINARY|O_RDONLY)) == -1)\r
473         {\r
474                 puts("Can't find "FILE_GR2"!");\r
475                 exit(1);\r
476         }\r
477         size = filelength(ihandle);\r
478         buffer = farmalloc(32000);\r
479         while (size)\r
480         {\r
481                 if (size > 32000)\r
482                 {\r
483                         CA_FarRead(ihandle, buffer, 32000);\r
484                         CA_FarWrite(ohandle, buffer, 32000);\r
485                         size -= 32000;\r
486                 }\r
487                 else\r
488                 {\r
489                         CA_FarRead(ihandle, buffer, size);\r
490                         CA_FarWrite(ohandle, buffer, size);\r
491                         size = 0;\r
492                 }\r
493         }\r
494         farfree(buffer);\r
495         close(ohandle);\r
496         close(ihandle);\r
497         unlink(FILE_GR2);\r
498 }\r
499 #endif\r
500 \r
501 //===========================================================================\r
502 \r
503 \r
504 /*\r
505 ==========================\r
506 =\r
507 = main\r
508 =\r
509 ==========================\r
510 */\r
511 \r
512 void main(void)\r
513 {\r
514 #if (GRMODE == EGAGR) && !(defined KEEN6)\r
515         CheckCutFile();\r
516 #endif\r
517 \r
518         if (US_ParmPresent("DEMO"))\r
519                 storedemo = true;\r
520 \r
521         if (US_ParmPresent("JOYPAD"))\r
522                 joypad = true;  // Note: the joypad variable is never used\r
523         \r
524         InitGame();\r
525         CheckMemory();\r
526         if (NoWait || tedlevel)\r
527                 debugok = true;\r
528 \r
529         DemoLoop();\r
530         Quit("Demo loop exited???");\r
531 }