OSDN Git Service

going to start wolf3d core core (loop with input only) work soon. I was mostly brains...
[proj16/16.git] / src / core / wl_play.c
1 // WL_PLAY.C\r
2 \r
3 #include "WL_DEF.H"\r
4 #pragma hdrstop\r
5 \r
6 \r
7 /*\r
8 =============================================================================\r
9 \r
10                                                  LOCAL CONSTANTS\r
11 \r
12 =============================================================================\r
13 */\r
14 \r
15 #define sc_Question     0x35\r
16 \r
17 /*\r
18 =============================================================================\r
19 \r
20                                                  GLOBAL VARIABLES\r
21 \r
22 =============================================================================\r
23 */\r
24 \r
25 boolean         madenoise;                                      // true when shooting or screaming\r
26 \r
27 exit_t          playstate;\r
28 \r
29 int                     DebugOk;\r
30 \r
31 objtype         objlist[MAXACTORS],*new,*obj,*player,*lastobj,\r
32                         *objfreelist,*killerobj;\r
33 \r
34 unsigned        farmapylookup[MAPSIZE];\r
35 byte            *nearmapylookup[MAPSIZE];\r
36 \r
37 boolean         singlestep,godmode,noclip;\r
38 int                     extravbls;\r
39 \r
40 byte            tilemap[MAPSIZE][MAPSIZE];      // wall values only\r
41 byte            spotvis[MAPSIZE][MAPSIZE];\r
42 objtype         *actorat[MAPSIZE][MAPSIZE];\r
43 \r
44 //\r
45 // replacing refresh manager\r
46 //\r
47 unsigned        mapwidth,mapheight,tics;\r
48 boolean         compatability;\r
49 byte            *updateptr;\r
50 unsigned        mapwidthtable[64];\r
51 unsigned        uwidthtable[UPDATEHIGH];\r
52 unsigned        blockstarts[UPDATEWIDE*UPDATEHIGH];\r
53 //uso: replace: byte            update[UPDATESIZE];\r
54 //uso: is needed? byte    update[UPDATEHIGH][UPDATEWIDE];\r
55 \r
56 //\r
57 // control info\r
58 //\r
59 boolean         mouseenabled,joystickenabled,joypadenabled,joystickprogressive;\r
60 int                     joystickport;\r
61 int                     dirscan[4] = {sc_UpArrow,sc_RightArrow,sc_DownArrow,sc_LeftArrow};\r
62 int                     buttonscan[NUMBUTTONS] =\r
63                         {sc_Control,sc_Alt,sc_RShift,sc_Space,sc_1,sc_2,sc_3,sc_4};\r
64 int                     buttonmouse[4]={bt_attack,bt_strafe,bt_use,bt_nobutton};\r
65 int                     buttonjoy[4]={bt_attack,bt_strafe,bt_use,bt_run};\r
66 \r
67 int                     viewsize;\r
68 \r
69 boolean         buttonheld[NUMBUTTONS];\r
70 \r
71 boolean         demorecord,demoplayback;\r
72 char            far *demoptr, far *lastdemoptr;\r
73 memptr          demobuffer;\r
74 \r
75 //\r
76 // curent user input\r
77 //\r
78 int                     controlx,controly;              // range from -100 to 100 per tic\r
79 boolean         buttonstate[NUMBUTTONS];\r
80 \r
81 \r
82 \r
83 //===========================================================================\r
84 \r
85 \r
86 void    CenterWindow(word w,word h);\r
87 void    InitObjList (void);\r
88 void    RemoveObj (objtype *gone);\r
89 void    PollControls (void);\r
90 void    StopMusic(void);\r
91 void    StartMusic(void);\r
92 void    PlayLoop (void);\r
93 \r
94 /*\r
95 =============================================================================\r
96 \r
97                                                  LOCAL VARIABLES\r
98 \r
99 =============================================================================\r
100 */\r
101 \r
102 \r
103 objtype dummyobj;\r
104 \r
105 //\r
106 // LIST OF SONGS FOR EACH VERSION\r
107 //\r
108 int songs[]=\r
109 {\r
110 #ifndef SPEAR\r
111  //\r
112  // Episode One\r
113  //\r
114  GETTHEM_MUS,\r
115  SEARCHN_MUS,\r
116  POW_MUS,\r
117  SUSPENSE_MUS,\r
118  GETTHEM_MUS,\r
119  SEARCHN_MUS,\r
120  POW_MUS,\r
121  SUSPENSE_MUS,\r
122 \r
123  WARMARCH_MUS,  // Boss level\r
124  CORNER_MUS,    // Secret level\r
125 \r
126  //\r
127  // Episode Two\r
128  //\r
129  NAZI_OMI_MUS,\r
130  PREGNANT_MUS,\r
131  GOINGAFT_MUS,\r
132  HEADACHE_MUS,\r
133  NAZI_OMI_MUS,\r
134  PREGNANT_MUS,\r
135  HEADACHE_MUS,\r
136  GOINGAFT_MUS,\r
137 \r
138  WARMARCH_MUS,  // Boss level\r
139  DUNGEON_MUS,   // Secret level\r
140 \r
141  //\r
142  // Episode Three\r
143  //\r
144  INTROCW3_MUS,\r
145  NAZI_RAP_MUS,\r
146  TWELFTH_MUS,\r
147  ZEROHOUR_MUS,\r
148  INTROCW3_MUS,\r
149  NAZI_RAP_MUS,\r
150  TWELFTH_MUS,\r
151  ZEROHOUR_MUS,\r
152 \r
153  ULTIMATE_MUS,  // Boss level\r
154  PACMAN_MUS,    // Secret level\r
155 \r
156  //\r
157  // Episode Four\r
158  //\r
159  GETTHEM_MUS,\r
160  SEARCHN_MUS,\r
161  POW_MUS,\r
162  SUSPENSE_MUS,\r
163  GETTHEM_MUS,\r
164  SEARCHN_MUS,\r
165  POW_MUS,\r
166  SUSPENSE_MUS,\r
167 \r
168  WARMARCH_MUS,  // Boss level\r
169  CORNER_MUS,    // Secret level\r
170 \r
171  //\r
172  // Episode Five\r
173  //\r
174  NAZI_OMI_MUS,\r
175  PREGNANT_MUS,\r
176  GOINGAFT_MUS,\r
177  HEADACHE_MUS,\r
178  NAZI_OMI_MUS,\r
179  PREGNANT_MUS,\r
180  HEADACHE_MUS,\r
181  GOINGAFT_MUS,\r
182 \r
183  WARMARCH_MUS,  // Boss level\r
184  DUNGEON_MUS,   // Secret level\r
185 \r
186  //\r
187  // Episode Six\r
188  //\r
189  INTROCW3_MUS,\r
190  NAZI_RAP_MUS,\r
191  TWELFTH_MUS,\r
192  ZEROHOUR_MUS,\r
193  INTROCW3_MUS,\r
194  NAZI_RAP_MUS,\r
195  TWELFTH_MUS,\r
196  ZEROHOUR_MUS,\r
197 \r
198  ULTIMATE_MUS,  // Boss level\r
199  FUNKYOU_MUS            // Secret level\r
200 #else\r
201 \r
202  //////////////////////////////////////////////////////////////\r
203  //\r
204  // SPEAR OF DESTINY TRACKS\r
205  //\r
206  //////////////////////////////////////////////////////////////\r
207  XTIPTOE_MUS,\r
208  XFUNKIE_MUS,\r
209  XDEATH_MUS,\r
210  XGETYOU_MUS,           // DON'T KNOW\r
211  ULTIMATE_MUS,  // Trans Gr\94sse\r
212 \r
213  DUNGEON_MUS,\r
214  GOINGAFT_MUS,\r
215  POW_MUS,\r
216  TWELFTH_MUS,\r
217  ULTIMATE_MUS,  // Barnacle Wilhelm BOSS\r
218 \r
219  NAZI_OMI_MUS,\r
220  GETTHEM_MUS,\r
221  SUSPENSE_MUS,\r
222  SEARCHN_MUS,\r
223  ZEROHOUR_MUS,\r
224  ULTIMATE_MUS,  // Super Mutant BOSS\r
225 \r
226  XPUTIT_MUS,\r
227  ULTIMATE_MUS,  // Death Knight BOSS\r
228 \r
229  XJAZNAZI_MUS,  // Secret level\r
230  XFUNKIE_MUS,   // Secret level (DON'T KNOW)\r
231 \r
232  XEVIL_MUS              // Angel of Death BOSS\r
233 \r
234 #endif\r
235 };\r
236 \r
237 \r
238 /*\r
239 =============================================================================\r
240 \r
241                                                   USER CONTROL\r
242 \r
243 =============================================================================\r
244 */\r
245 \r
246 \r
247 #define BASEMOVE                35\r
248 #define RUNMOVE                 70\r
249 #define BASETURN                35\r
250 #define RUNTURN                 70\r
251 \r
252 #define JOYSCALE                2\r
253 \r
254 /*\r
255 ===================\r
256 =\r
257 = PollKeyboardButtons\r
258 =\r
259 ===================\r
260 */\r
261 \r
262 void PollKeyboardButtons (void)\r
263 {\r
264         int             i;\r
265 \r
266         for (i=0;i<NUMBUTTONS;i++)\r
267                 if (Keyboard[buttonscan[i]])\r
268                         buttonstate[i] = true;\r
269 }\r
270 \r
271 \r
272 /*\r
273 ===================\r
274 =\r
275 = PollMouseButtons\r
276 =\r
277 ===================\r
278 */\r
279 \r
280 void PollMouseButtons (void)\r
281 {\r
282         int     buttons;\r
283 \r
284         buttons = IN_MouseButtons ();\r
285 \r
286         if (buttons&1)\r
287                 buttonstate[buttonmouse[0]] = true;\r
288         if (buttons&2)\r
289                 buttonstate[buttonmouse[1]] = true;\r
290         if (buttons&4)\r
291                 buttonstate[buttonmouse[2]] = true;\r
292 }\r
293 \r
294 \r
295 \r
296 /*\r
297 ===================\r
298 =\r
299 = PollJoystickButtons\r
300 =\r
301 ===================\r
302 */\r
303 \r
304 void PollJoystickButtons (void)\r
305 {\r
306         int     buttons;\r
307 \r
308         buttons = IN_JoyButtons ();\r
309 \r
310         if (joystickport && !joypadenabled)\r
311         {\r
312                 if (buttons&4)\r
313                         buttonstate[buttonjoy[0]] = true;\r
314                 if (buttons&8)\r
315                         buttonstate[buttonjoy[1]] = true;\r
316         }\r
317         else\r
318         {\r
319                 if (buttons&1)\r
320                         buttonstate[buttonjoy[0]] = true;\r
321                 if (buttons&2)\r
322                         buttonstate[buttonjoy[1]] = true;\r
323                 if (joypadenabled)\r
324                 {\r
325                         if (buttons&4)\r
326                                 buttonstate[buttonjoy[2]] = true;\r
327                         if (buttons&8)\r
328                                 buttonstate[buttonjoy[3]] = true;\r
329                 }\r
330         }\r
331 }\r
332 \r
333 \r
334 /*\r
335 ===================\r
336 =\r
337 = PollKeyboardMove\r
338 =\r
339 ===================\r
340 */\r
341 \r
342 void PollKeyboardMove (void)\r
343 {\r
344         if (buttonstate[bt_run])\r
345         {\r
346                 if (Keyboard[dirscan[di_north]])\r
347                         controly -= RUNMOVE*tics;\r
348                 if (Keyboard[dirscan[di_south]])\r
349                         controly += RUNMOVE*tics;\r
350                 if (Keyboard[dirscan[di_west]])\r
351                         controlx -= RUNMOVE*tics;\r
352                 if (Keyboard[dirscan[di_east]])\r
353                         controlx += RUNMOVE*tics;\r
354         }\r
355         else\r
356         {\r
357                 if (Keyboard[dirscan[di_north]])\r
358                         controly -= BASEMOVE*tics;\r
359                 if (Keyboard[dirscan[di_south]])\r
360                         controly += BASEMOVE*tics;\r
361                 if (Keyboard[dirscan[di_west]])\r
362                         controlx -= BASEMOVE*tics;\r
363                 if (Keyboard[dirscan[di_east]])\r
364                         controlx += BASEMOVE*tics;\r
365         }\r
366 }\r
367 \r
368 \r
369 /*\r
370 ===================\r
371 =\r
372 = PollMouseMove\r
373 =\r
374 ===================\r
375 */\r
376 \r
377 void PollMouseMove (void)\r
378 {\r
379         int     mousexmove,mouseymove;\r
380 \r
381         Mouse(MDelta);\r
382         mousexmove = _CX;\r
383         mouseymove = _DX;\r
384 \r
385         controlx += mousexmove*10/(13-mouseadjustment);\r
386         controly += mouseymove*20/(13-mouseadjustment);\r
387 }\r
388 \r
389 \r
390 \r
391 /*\r
392 ===================\r
393 =\r
394 = PollJoystickMove\r
395 =\r
396 ===================\r
397 */\r
398 \r
399 void PollJoystickMove (void)\r
400 {\r
401         int     joyx,joyy;\r
402 \r
403         INL_GetJoyDelta(joystickport,&joyx,&joyy);\r
404 \r
405         if (joystickprogressive)\r
406         {\r
407                 if (joyx > 64)\r
408                         controlx += (joyx-64)*JOYSCALE*tics;\r
409                 else if (joyx < -64)\r
410                         controlx -= (-joyx-64)*JOYSCALE*tics;\r
411                 if (joyy > 64)\r
412                         controlx += (joyy-64)*JOYSCALE*tics;\r
413                 else if (joyy < -64)\r
414                         controly -= (-joyy-64)*JOYSCALE*tics;\r
415         }\r
416         else if (buttonstate[bt_run])\r
417         {\r
418                 if (joyx > 64)\r
419                         controlx += RUNMOVE*tics;\r
420                 else if (joyx < -64)\r
421                         controlx -= RUNMOVE*tics;\r
422                 if (joyy > 64)\r
423                         controly += RUNMOVE*tics;\r
424                 else if (joyy < -64)\r
425                         controly -= RUNMOVE*tics;\r
426         }\r
427         else\r
428         {\r
429                 if (joyx > 64)\r
430                         controlx += BASEMOVE*tics;\r
431                 else if (joyx < -64)\r
432                         controlx -= BASEMOVE*tics;\r
433                 if (joyy > 64)\r
434                         controly += BASEMOVE*tics;\r
435                 else if (joyy < -64)\r
436                         controly -= BASEMOVE*tics;\r
437         }\r
438 }\r
439 \r
440 \r
441 /*\r
442 ===================\r
443 =\r
444 = PollControls\r
445 =\r
446 = Gets user or demo input, call once each frame\r
447 =\r
448 = controlx              set between -100 and 100 per tic\r
449 = controly\r
450 = buttonheld[]  the state of the buttons LAST frame\r
451 = buttonstate[] the state of the buttons THIS frame\r
452 =\r
453 ===================\r
454 */\r
455 \r
456 void PollControls (void)\r
457 {\r
458         int             max,min,i;\r
459         byte    buttonbits;\r
460 \r
461 //\r
462 // get timing info for last frame\r
463 //\r
464         if (demoplayback)\r
465         {\r
466                 while (TimeCount<lasttimecount+DEMOTICS)\r
467                 ;\r
468                 TimeCount = lasttimecount + DEMOTICS;\r
469                 lasttimecount += DEMOTICS;\r
470                 tics = DEMOTICS;\r
471         }\r
472         else if (demorecord)                    // demo recording and playback needs\r
473         {                                                               // to be constant\r
474 //\r
475 // take DEMOTICS or more tics, and modify Timecount to reflect time taken\r
476 //\r
477                 while (TimeCount<lasttimecount+DEMOTICS)\r
478                 ;\r
479                 TimeCount = lasttimecount + DEMOTICS;\r
480                 lasttimecount += DEMOTICS;\r
481                 tics = DEMOTICS;\r
482         }\r
483         else\r
484                 CalcTics ();\r
485 \r
486         controlx = 0;\r
487         controly = 0;\r
488         memcpy (buttonheld,buttonstate,sizeof(buttonstate));\r
489         memset (buttonstate,0,sizeof(buttonstate));\r
490 \r
491         if (demoplayback)\r
492         {\r
493         //\r
494         // read commands from demo buffer\r
495         //\r
496                 buttonbits = *demoptr++;\r
497                 for (i=0;i<NUMBUTTONS;i++)\r
498                 {\r
499                         buttonstate[i] = buttonbits&1;\r
500                         buttonbits >>= 1;\r
501                 }\r
502 \r
503                 controlx = *demoptr++;\r
504                 controly = *demoptr++;\r
505 \r
506                 if (demoptr == lastdemoptr)\r
507                         playstate = ex_completed;               // demo is done\r
508 \r
509                 controlx *= (int)tics;\r
510                 controly *= (int)tics;\r
511 \r
512                 return;\r
513         }\r
514 \r
515 \r
516 //\r
517 // get button states\r
518 //\r
519         PollKeyboardButtons ();\r
520 \r
521         if (mouseenabled)\r
522                 PollMouseButtons ();\r
523 \r
524         if (joystickenabled)\r
525                 PollJoystickButtons ();\r
526 \r
527 //\r
528 // get movements\r
529 //\r
530         PollKeyboardMove ();\r
531 \r
532         if (mouseenabled)\r
533                 PollMouseMove ();\r
534 \r
535         if (joystickenabled)\r
536                 PollJoystickMove ();\r
537 \r
538 //\r
539 // bound movement to a maximum\r
540 //\r
541         max = 100*tics;\r
542         min = -max;\r
543         if (controlx > max)\r
544                 controlx = max;\r
545         else if (controlx < min)\r
546                 controlx = min;\r
547 \r
548         if (controly > max)\r
549                 controly = max;\r
550         else if (controly < min)\r
551                 controly = min;\r
552 \r
553         if (demorecord)\r
554         {\r
555         //\r
556         // save info out to demo buffer\r
557         //\r
558                 controlx /= (int)tics;\r
559                 controly /= (int)tics;\r
560 \r
561                 buttonbits = 0;\r
562 \r
563                 for (i=NUMBUTTONS-1;i>=0;i--)\r
564                 {\r
565                         buttonbits <<= 1;\r
566                         if (buttonstate[i])\r
567                                 buttonbits |= 1;\r
568                 }\r
569 \r
570                 *demoptr++ = buttonbits;\r
571                 *demoptr++ = controlx;\r
572                 *demoptr++ = controly;\r
573 \r
574                 if (demoptr >= lastdemoptr)\r
575                         Quit ("Demo buffer overflowed!");\r
576 \r
577                 controlx *= (int)tics;\r
578                 controly *= (int)tics;\r
579         }\r
580 }\r
581 \r
582 \r
583 \r
584 //==========================================================================\r
585 \r
586 \r
587 \r
588 ///////////////////////////////////////////////////////////////////////////\r
589 //\r
590 //      CenterWindow() - Generates a window of a given width & height in the\r
591 //              middle of the screen\r
592 //\r
593 ///////////////////////////////////////////////////////////////////////////\r
594 \r
595 #define MAXX    320\r
596 #define MAXY    160\r
597 \r
598 void    CenterWindow(word w,word h)\r
599 {\r
600         FixOfs ();\r
601         US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h);\r
602 }\r
603 \r
604 //===========================================================================\r
605 \r
606 \r
607 /*\r
608 =====================\r
609 =\r
610 = CheckKeys\r
611 =\r
612 =====================\r
613 */\r
614 \r
615 void CheckKeys (void)\r
616 {\r
617         int             i;\r
618         byte    scan;\r
619         unsigned        temp;\r
620 \r
621 \r
622         if (screenfaded || demoplayback)        // don't do anything with a faded screen\r
623                 return;\r
624 \r
625         scan = LastScan;\r
626 \r
627 \r
628         #ifdef SPEAR\r
629         //\r
630         // SECRET CHEAT CODE: TAB-G-F10\r
631         //\r
632         if (Keyboard[sc_Tab] &&\r
633                 Keyboard[sc_G] &&\r
634                 Keyboard[sc_F10])\r
635         {\r
636                 WindowH = 160;\r
637                 if (godmode)\r
638                 {\r
639                         Message ("God mode OFF");\r
640                         SD_PlaySound (NOBONUSSND);\r
641                 }\r
642                 else\r
643                 {\r
644                         Message ("God mode ON");\r
645                         SD_PlaySound (ENDBONUS2SND);\r
646                 }\r
647 \r
648                 IN_Ack();\r
649                 godmode ^= 1;\r
650                 DrawAllPlayBorderSides ();\r
651                 IN_ClearKeysDown();\r
652                 return;\r
653         }\r
654         #endif\r
655 \r
656 \r
657         //\r
658         // SECRET CHEAT CODE: 'MLI'\r
659         //\r
660         if (Keyboard[sc_M] &&\r
661                 Keyboard[sc_L] &&\r
662                 Keyboard[sc_I])\r
663         {\r
664                 gamestate.health = 100;\r
665                 gamestate.ammo = 99;\r
666                 gamestate.keys = 3;\r
667                 gamestate.score = 0;\r
668                 gamestate.TimeCount += 42000L;\r
669                 GiveWeapon (wp_chaingun);\r
670 \r
671                 DrawWeapon();\r
672                 DrawHealth();\r
673                 DrawKeys();\r
674                 DrawAmmo();\r
675                 DrawScore();\r
676 \r
677                 ClearMemory ();\r
678                 CA_CacheGrChunk (STARTFONT+1);\r
679                 ClearSplitVWB ();\r
680                 VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
681 \r
682                 Message(STR_CHEATER1"\n"\r
683                                 STR_CHEATER2"\n\n"\r
684                                 STR_CHEATER3"\n"\r
685                                 STR_CHEATER4"\n"\r
686                                 STR_CHEATER5);\r
687 \r
688                 UNCACHEGRCHUNK(STARTFONT+1);\r
689                 PM_CheckMainMem ();\r
690                 IN_ClearKeysDown();\r
691                 IN_Ack();\r
692 \r
693                 DrawAllPlayBorder ();\r
694         }\r
695 \r
696         //\r
697         // OPEN UP DEBUG KEYS\r
698         //\r
699 #ifndef SPEAR\r
700         if (Keyboard[sc_BackSpace] &&\r
701                 Keyboard[sc_LShift] &&\r
702                 Keyboard[sc_Alt] &&\r
703                 MS_CheckParm("goobers"))\r
704 #else\r
705         if (Keyboard[sc_BackSpace] &&\r
706                 Keyboard[sc_LShift] &&\r
707                 Keyboard[sc_Alt] &&\r
708                 MS_CheckParm("debugmode"))\r
709 #endif\r
710         {\r
711          ClearMemory ();\r
712          CA_CacheGrChunk (STARTFONT+1);\r
713          ClearSplitVWB ();\r
714          VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
715 \r
716          Message("Debugging keys are\nnow available!");\r
717          UNCACHEGRCHUNK(STARTFONT+1);\r
718          PM_CheckMainMem ();\r
719          IN_ClearKeysDown();\r
720          IN_Ack();\r
721 \r
722          DrawAllPlayBorderSides ();\r
723          DebugOk=1;\r
724         }\r
725 \r
726         //\r
727         // TRYING THE KEEN CHEAT CODE!\r
728         //\r
729         if (Keyboard[sc_B] &&\r
730                 Keyboard[sc_A] &&\r
731                 Keyboard[sc_T])\r
732         {\r
733          ClearMemory ();\r
734          CA_CacheGrChunk (STARTFONT+1);\r
735          ClearSplitVWB ();\r
736          VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
737 \r
738          Message("Commander Keen is also\n"\r
739                          "available from Apogee, but\n"\r
740                          "then, you already know\n"\r
741                          "that - right, Cheatmeister?!");\r
742 \r
743          UNCACHEGRCHUNK(STARTFONT+1);\r
744          PM_CheckMainMem ();\r
745          IN_ClearKeysDown();\r
746          IN_Ack();\r
747 \r
748          DrawAllPlayBorder ();\r
749         }\r
750 \r
751 //\r
752 // pause key weirdness can't be checked as a scan code\r
753 //\r
754         if (Paused)\r
755         {\r
756                 bufferofs = displayofs;\r
757                 LatchDrawPic (20-4,80-2*8,PAUSEDPIC);\r
758                 SD_MusicOff();\r
759                 IN_Ack();\r
760                 IN_ClearKeysDown ();\r
761                 SD_MusicOn();\r
762                 Paused = false;\r
763                 if (MousePresent)\r
764                         Mouse(MDelta);  // Clear accumulated mouse movement\r
765                 return;\r
766         }\r
767 \r
768 \r
769 //\r
770 // F1-F7/ESC to enter control panel\r
771 //\r
772         if (\r
773 #ifndef DEBCHECK\r
774                 scan == sc_F10 ||\r
775 #endif\r
776                 scan == sc_F9 ||\r
777                 scan == sc_F7 ||\r
778                 scan == sc_F8)                  // pop up quit dialog\r
779         {\r
780                 ClearMemory ();\r
781                 ClearSplitVWB ();\r
782                 VW_ScreenToScreen (displayofs,bufferofs,80,160);\r
783                 US_ControlPanel(scan);\r
784 \r
785                  DrawAllPlayBorderSides ();\r
786 \r
787                 if (scan == sc_F9)\r
788                   StartMusic ();\r
789 \r
790                 PM_CheckMainMem ();\r
791                 SETFONTCOLOR(0,15);\r
792                 IN_ClearKeysDown();\r
793                 return;\r
794         }\r
795 \r
796         if ( (scan >= sc_F1 && scan <= sc_F9) || scan == sc_Escape)\r
797         {\r
798                 StopMusic ();\r
799                 ClearMemory ();\r
800                 VW_FadeOut ();\r
801 \r
802                 US_ControlPanel(scan);\r
803 \r
804                 SETFONTCOLOR(0,15);\r
805                 IN_ClearKeysDown();\r
806                 DrawPlayScreen ();\r
807                 if (!startgame && !loadedgame)\r
808                 {\r
809                         VW_FadeIn ();\r
810                         StartMusic ();\r
811                 }\r
812                 if (loadedgame)\r
813                         playstate = ex_abort;\r
814                 lasttimecount = TimeCount;\r
815                 if (MousePresent)\r
816                         Mouse(MDelta);  // Clear accumulated mouse movement\r
817                 PM_CheckMainMem ();\r
818                 return;\r
819         }\r
820 \r
821 //\r
822 // TAB-? debug keys\r
823 //\r
824         if (Keyboard[sc_Tab] && DebugOk)\r
825         {\r
826                 CA_CacheGrChunk (STARTFONT);\r
827                 fontnumber=0;\r
828                 SETFONTCOLOR(0,15);\r
829                 DebugKeys();\r
830                 if (MousePresent)\r
831                         Mouse(MDelta);  // Clear accumulated mouse movement\r
832                 lasttimecount = TimeCount;\r
833                 return;\r
834         }\r
835 \r
836 }\r
837 \r
838 \r
839 //===========================================================================\r
840 \r
841 /*\r
842 #############################################################################\r
843 \r
844                                   The objlist data structure\r
845 \r
846 #############################################################################\r
847 \r
848 objlist containt structures for every actor currently playing.  The structure\r
849 is accessed as a linked list starting at *player, ending when ob->next ==\r
850 NULL.  GetNewObj inserts a new object at the end of the list, meaning that\r
851 if an actor spawn another actor, the new one WILL get to think and react the\r
852 same frame.  RemoveObj unlinks the given object and returns it to the free\r
853 list, but does not damage the objects ->next pointer, so if the current object\r
854 removes itself, a linked list following loop can still safely get to the\r
855 next element.\r
856 \r
857 <backwardly linked free list>\r
858 \r
859 #############################################################################\r
860 */\r
861 \r
862 \r
863 /*\r
864 =========================\r
865 =\r
866 = InitActorList\r
867 =\r
868 = Call to clear out the actor object lists returning them all to the free\r
869 = list.  Allocates a special spot for the player.\r
870 =\r
871 =========================\r
872 */\r
873 \r
874 int     objcount;\r
875 \r
876 void InitActorList (void)\r
877 {\r
878         int     i;\r
879 \r
880 //\r
881 // init the actor lists\r
882 //\r
883         for (i=0;i<MAXACTORS;i++)\r
884         {\r
885                 objlist[i].prev = &objlist[i+1];\r
886                 objlist[i].next = NULL;\r
887         }\r
888 \r
889         objlist[MAXACTORS-1].prev = NULL;\r
890 \r
891         objfreelist = &objlist[0];\r
892         lastobj = NULL;\r
893 \r
894         objcount = 0;\r
895 \r
896 //\r
897 // give the player the first free spots\r
898 //\r
899         GetNewActor ();\r
900         player = new;\r
901 \r
902 }\r
903 \r
904 //===========================================================================\r
905 \r
906 /*\r
907 =========================\r
908 =\r
909 = GetNewActor\r
910 =\r
911 = Sets the global variable new to point to a free spot in objlist.\r
912 = The free spot is inserted at the end of the liked list\r
913 =\r
914 = When the object list is full, the caller can either have it bomb out ot\r
915 = return a dummy object pointer that will never get used\r
916 =\r
917 =========================\r
918 */\r
919 \r
920 void GetNewActor (void)\r
921 {\r
922         if (!objfreelist)\r
923                 Quit ("GetNewActor: No free spots in objlist!");\r
924 \r
925         new = objfreelist;\r
926         objfreelist = new->prev;\r
927         memset (new,0,sizeof(*new));\r
928 \r
929         if (lastobj)\r
930                 lastobj->next = new;\r
931         new->prev = lastobj;    // new->next is allready NULL from memset\r
932 \r
933         new->active = false;\r
934         lastobj = new;\r
935 \r
936         objcount++;\r
937 }\r
938 \r
939 //===========================================================================\r
940 \r
941 /*\r
942 =========================\r
943 =\r
944 = RemoveObj\r
945 =\r
946 = Add the given object back into the free list, and unlink it from it's\r
947 = neighbors\r
948 =\r
949 =========================\r
950 */\r
951 \r
952 void RemoveObj (objtype *gone)\r
953 {\r
954         objtype **spotat;\r
955 \r
956         if (gone == player)\r
957                 Quit ("RemoveObj: Tried to remove the player!");\r
958 \r
959         gone->state = NULL;\r
960 \r
961 //\r
962 // fix the next object's back link\r
963 //\r
964         if (gone == lastobj)\r
965                 lastobj = (objtype *)gone->prev;\r
966         else\r
967                 gone->next->prev = gone->prev;\r
968 \r
969 //\r
970 // fix the previous object's forward link\r
971 //\r
972         gone->prev->next = gone->next;\r
973 \r
974 //\r
975 // add it back in to the free list\r
976 //\r
977         gone->prev = objfreelist;\r
978         objfreelist = gone;\r
979 \r
980         objcount--;\r
981 }\r
982 \r
983 /*\r
984 =============================================================================\r
985 \r
986                                                 MUSIC STUFF\r
987 \r
988 =============================================================================\r
989 */\r
990 \r
991 \r
992 /*\r
993 =================\r
994 =\r
995 = StopMusic\r
996 =\r
997 =================\r
998 */\r
999 \r
1000 void StopMusic(void)\r
1001 {\r
1002         int     i;\r
1003 \r
1004         SD_MusicOff();\r
1005         for (i = 0;i < LASTMUSIC;i++)\r
1006                 if (audiosegs[STARTMUSIC + i])\r
1007                 {\r
1008                         MM_SetPurge(&((memptr)audiosegs[STARTMUSIC + i]),3);\r
1009                         MM_SetLock(&((memptr)audiosegs[STARTMUSIC + i]),false);\r
1010                 }\r
1011 }\r
1012 \r
1013 //==========================================================================\r
1014 \r
1015 \r
1016 /*\r
1017 =================\r
1018 =\r
1019 = StartMusic\r
1020 =\r
1021 =================\r
1022 */\r
1023 \r
1024 void StartMusic(void)\r
1025 {\r
1026         musicnames      chunk;\r
1027 \r
1028         SD_MusicOff();\r
1029         chunk = songs[gamestate.mapon+gamestate.episode*10];\r
1030 \r
1031 //      if ((chunk == -1) || (MusicMode != smm_AdLib))\r
1032 //DEBUG control panel           return;\r
1033 \r
1034         MM_BombOnError (false);\r
1035         CA_CacheAudioChunk(STARTMUSIC + chunk);\r
1036         MM_BombOnError (true);\r
1037         if (mmerror)\r
1038                 mmerror = false;\r
1039         else\r
1040         {\r
1041                 MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true);\r
1042                 SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]);\r
1043         }\r
1044 }\r
1045 \r
1046 \r
1047 /*\r
1048 =============================================================================\r
1049 \r
1050                                         PALETTE SHIFTING STUFF\r
1051 \r
1052 =============================================================================\r
1053 */\r
1054 \r
1055 #define NUMREDSHIFTS    6\r
1056 #define REDSTEPS                8\r
1057 \r
1058 #define NUMWHITESHIFTS  3\r
1059 #define WHITESTEPS              20\r
1060 #define WHITETICS               6\r
1061 \r
1062 \r
1063 byte    far redshifts[NUMREDSHIFTS][768];\r
1064 byte    far whiteshifts[NUMREDSHIFTS][768];\r
1065 \r
1066 int             damagecount,bonuscount;\r
1067 boolean palshifted;\r
1068 \r
1069 extern  byte    far     gamepal;\r
1070 \r
1071 /*\r
1072 =====================\r
1073 =\r
1074 = InitRedShifts\r
1075 =\r
1076 =====================\r
1077 */\r
1078 \r
1079 void InitRedShifts (void)\r
1080 {\r
1081         byte    far *workptr, far *baseptr;\r
1082         int             i,j,delta;\r
1083 \r
1084 \r
1085 //\r
1086 // fade through intermediate frames\r
1087 //\r
1088         for (i=1;i<=NUMREDSHIFTS;i++)\r
1089         {\r
1090                 workptr = (byte far *)&redshifts[i-1][0];\r
1091                 baseptr = &gamepal;\r
1092 \r
1093                 for (j=0;j<=255;j++)\r
1094                 {\r
1095                         delta = 64-*baseptr;\r
1096                         *workptr++ = *baseptr++ + delta * i / REDSTEPS;\r
1097                         delta = -*baseptr;\r
1098                         *workptr++ = *baseptr++ + delta * i / REDSTEPS;\r
1099                         delta = -*baseptr;\r
1100                         *workptr++ = *baseptr++ + delta * i / REDSTEPS;\r
1101                 }\r
1102         }\r
1103 \r
1104         for (i=1;i<=NUMWHITESHIFTS;i++)\r
1105         {\r
1106                 workptr = (byte far *)&whiteshifts[i-1][0];\r
1107                 baseptr = &gamepal;\r
1108 \r
1109                 for (j=0;j<=255;j++)\r
1110                 {\r
1111                         delta = 64-*baseptr;\r
1112                         *workptr++ = *baseptr++ + delta * i / WHITESTEPS;\r
1113                         delta = 62-*baseptr;\r
1114                         *workptr++ = *baseptr++ + delta * i / WHITESTEPS;\r
1115                         delta = 0-*baseptr;\r
1116                         *workptr++ = *baseptr++ + delta * i / WHITESTEPS;\r
1117                 }\r
1118         }\r
1119 }\r
1120 \r
1121 \r
1122 /*\r
1123 =====================\r
1124 =\r
1125 = ClearPaletteShifts\r
1126 =\r
1127 =====================\r
1128 */\r
1129 \r
1130 void ClearPaletteShifts (void)\r
1131 {\r
1132         bonuscount = damagecount = 0;\r
1133 }\r
1134 \r
1135 \r
1136 /*\r
1137 =====================\r
1138 =\r
1139 = StartBonusFlash\r
1140 =\r
1141 =====================\r
1142 */\r
1143 \r
1144 void StartBonusFlash (void)\r
1145 {\r
1146         bonuscount = NUMWHITESHIFTS*WHITETICS;          // white shift palette\r
1147 }\r
1148 \r
1149 \r
1150 /*\r
1151 =====================\r
1152 =\r
1153 = StartDamageFlash\r
1154 =\r
1155 =====================\r
1156 */\r
1157 \r
1158 void StartDamageFlash (int damage)\r
1159 {\r
1160         damagecount += damage;\r
1161 }\r
1162 \r
1163 \r
1164 /*\r
1165 =====================\r
1166 =\r
1167 = UpdatePaletteShifts\r
1168 =\r
1169 =====================\r
1170 */\r
1171 \r
1172 void UpdatePaletteShifts (void)\r
1173 {\r
1174         int     red,white;\r
1175 \r
1176         if (bonuscount)\r
1177         {\r
1178                 white = bonuscount/WHITETICS +1;\r
1179                 if (white>NUMWHITESHIFTS)\r
1180                         white = NUMWHITESHIFTS;\r
1181                 bonuscount -= tics;\r
1182                 if (bonuscount < 0)\r
1183                         bonuscount = 0;\r
1184         }\r
1185         else\r
1186                 white = 0;\r
1187 \r
1188 \r
1189         if (damagecount)\r
1190         {\r
1191                 red = damagecount/10 +1;\r
1192                 if (red>NUMREDSHIFTS)\r
1193                         red = NUMREDSHIFTS;\r
1194 \r
1195                 damagecount -= tics;\r
1196                 if (damagecount < 0)\r
1197                         damagecount = 0;\r
1198         }\r
1199         else\r
1200                 red = 0;\r
1201 \r
1202         if (red)\r
1203         {\r
1204                 VW_WaitVBL(1);\r
1205                 VL_SetPalette (redshifts[red-1]);\r
1206                 palshifted = true;\r
1207         }\r
1208         else if (white)\r
1209         {\r
1210                 VW_WaitVBL(1);\r
1211                 VL_SetPalette (whiteshifts[white-1]);\r
1212                 palshifted = true;\r
1213         }\r
1214         else if (palshifted)\r
1215         {\r
1216                 VW_WaitVBL(1);\r
1217                 VL_SetPalette (&gamepal);               // back to normal\r
1218                 palshifted = false;\r
1219         }\r
1220 }\r
1221 \r
1222 \r
1223 /*\r
1224 =====================\r
1225 =\r
1226 = FinishPaletteShifts\r
1227 =\r
1228 = Resets palette to normal if needed\r
1229 =\r
1230 =====================\r
1231 */\r
1232 \r
1233 void FinishPaletteShifts (void)\r
1234 {\r
1235         if (palshifted)\r
1236         {\r
1237                 palshifted = 0;\r
1238                 VW_WaitVBL(1);\r
1239                 VL_SetPalette (&gamepal);\r
1240         }\r
1241 }\r
1242 \r
1243 \r
1244 /*\r
1245 =============================================================================\r
1246 \r
1247                                                 CORE PLAYLOOP\r
1248 \r
1249 =============================================================================\r
1250 */\r
1251 \r
1252 \r
1253 /*\r
1254 =====================\r
1255 =\r
1256 = DoActor\r
1257 =\r
1258 =====================\r
1259 */\r
1260 \r
1261 void DoActor (objtype *ob)\r
1262 {\r
1263         void (*think)(objtype *);\r
1264 \r
1265         if (!ob->active && !areabyplayer[ob->areanumber])\r
1266                 return;\r
1267 \r
1268         if (!(ob->flags&(FL_NONMARK|FL_NEVERMARK)) )\r
1269                 actorat[ob->tilex][ob->tiley] = NULL;\r
1270 \r
1271 //\r
1272 // non transitional object\r
1273 //\r
1274 \r
1275         if (!ob->ticcount)\r
1276         {\r
1277                 think = ob->state->think;\r
1278                 if (think)\r
1279                 {\r
1280                         think (ob);\r
1281                         if (!ob->state)\r
1282                         {\r
1283                                 RemoveObj (ob);\r
1284                                 return;\r
1285                         }\r
1286                 }\r
1287 \r
1288                 if (ob->flags&FL_NEVERMARK)\r
1289                         return;\r
1290 \r
1291                 if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley])\r
1292                         return;\r
1293 \r
1294                 actorat[ob->tilex][ob->tiley] = ob;\r
1295                 return;\r
1296         }\r
1297 \r
1298 //\r
1299 // transitional object\r
1300 //\r
1301         ob->ticcount-=tics;\r
1302         while ( ob->ticcount <= 0)\r
1303         {\r
1304                 think = ob->state->action;                      // end of state action\r
1305                 if (think)\r
1306                 {\r
1307                         think (ob);\r
1308                         if (!ob->state)\r
1309                         {\r
1310                                 RemoveObj (ob);\r
1311                                 return;\r
1312                         }\r
1313                 }\r
1314 \r
1315                 ob->state = ob->state->next;\r
1316 \r
1317                 if (!ob->state)\r
1318                 {\r
1319                         RemoveObj (ob);\r
1320                         return;\r
1321                 }\r
1322 \r
1323                 if (!ob->state->tictime)\r
1324                 {\r
1325                         ob->ticcount = 0;\r
1326                         goto think;\r
1327                 }\r
1328 \r
1329                 ob->ticcount += ob->state->tictime;\r
1330         }\r
1331 \r
1332 think:\r
1333         //\r
1334         // think\r
1335         //\r
1336         think = ob->state->think;\r
1337         if (think)\r
1338         {\r
1339                 think (ob);\r
1340                 if (!ob->state)\r
1341                 {\r
1342                         RemoveObj (ob);\r
1343                         return;\r
1344                 }\r
1345         }\r
1346 \r
1347         if (ob->flags&FL_NEVERMARK)\r
1348                 return;\r
1349 \r
1350         if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley])\r
1351                 return;\r
1352 \r
1353         actorat[ob->tilex][ob->tiley] = ob;\r
1354 }\r
1355 \r
1356 //==========================================================================\r
1357 \r
1358 \r
1359 /*\r
1360 ===================\r
1361 =\r
1362 = PlayLoop\r
1363 =\r
1364 ===================\r
1365 */\r
1366 long funnyticount;\r
1367 \r
1368 \r
1369 void PlayLoop (void)\r
1370 {\r
1371         int             give;\r
1372         int     helmetangle;\r
1373 \r
1374         playstate = TimeCount = lasttimecount = 0;\r
1375         frameon = 0;\r
1376         running = false;\r
1377         anglefrac = 0;\r
1378         facecount = 0;\r
1379         funnyticount = 0;\r
1380         memset (buttonstate,0,sizeof(buttonstate));\r
1381         ClearPaletteShifts ();\r
1382 \r
1383         if (MousePresent)\r
1384                 Mouse(MDelta);  // Clear accumulated mouse movement\r
1385 \r
1386         if (demoplayback)\r
1387                 IN_StartAck ();\r
1388 \r
1389         do\r
1390         {\r
1391                 if (virtualreality)\r
1392                 {\r
1393                         helmetangle = peek (0x40,0xf0);\r
1394                         player->angle += helmetangle;\r
1395                         if (player->angle >= ANGLES)\r
1396                                 player->angle -= ANGLES;\r
1397                 }\r
1398 \r
1399 \r
1400                 PollControls();\r
1401 \r
1402 //\r
1403 // actor thinking\r
1404 //\r
1405                 madenoise = false;\r
1406 \r
1407                 MoveDoors ();\r
1408                 MovePWalls ();\r
1409 \r
1410                 for (obj = player;obj;obj = obj->next)\r
1411                         DoActor (obj);\r
1412 \r
1413                 UpdatePaletteShifts ();\r
1414 \r
1415                 ThreeDRefresh ();\r
1416 \r
1417                 //\r
1418                 // MAKE FUNNY FACE IF BJ DOESN'T MOVE FOR AWHILE\r
1419                 //\r
1420                 #ifdef SPEAR\r
1421                 funnyticount += tics;\r
1422                 if (funnyticount > 30l*70)\r
1423                 {\r
1424                         funnyticount = 0;\r
1425                         StatusDrawPic (17,4,BJWAITING1PIC+(US_RndT()&1));\r
1426                         facecount = 0;\r
1427                 }\r
1428                 #endif\r
1429 \r
1430                 gamestate.TimeCount+=tics;\r
1431 \r
1432                 SD_Poll ();\r
1433                 UpdateSoundLoc();       // JAB\r
1434 \r
1435                 if (screenfaded)\r
1436                         VW_FadeIn ();\r
1437 \r
1438                 CheckKeys();\r
1439 \r
1440 //\r
1441 // debug aids\r
1442 //\r
1443                 if (singlestep)\r
1444                 {\r
1445                         VW_WaitVBL(14);\r
1446                         lasttimecount = TimeCount;\r
1447                 }\r
1448                 if (extravbls)\r
1449                         VW_WaitVBL(extravbls);\r
1450 \r
1451                 if (demoplayback)\r
1452                 {\r
1453                         if (IN_CheckAck ())\r
1454                         {\r
1455                                 IN_ClearKeysDown ();\r
1456                                 playstate = ex_abort;\r
1457                         }\r
1458                 }\r
1459 \r
1460 \r
1461                 if (virtualreality)\r
1462                 {\r
1463                         player->angle -= helmetangle;\r
1464                         if (player->angle < 0)\r
1465                                 player->angle += ANGLES;\r
1466                 }\r
1467 \r
1468         }while (!playstate && !startgame);\r
1469 \r
1470         if (playstate != ex_died)\r
1471                 FinishPaletteShifts ();\r
1472 }\r
1473 \r