]> 4ch.mooo.com Git - 16.git/blob - 16/cawat/C5_PLAY.C
96f777576891b290648c887ef93d48e91433ad03
[16.git] / 16 / cawat / C5_PLAY.C
1 /* Catacomb Armageddon Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // C3_PLAY.C\r
20 \r
21 #include "DEF.H"\r
22 #include "gelib.h"\r
23 #pragma hdrstop\r
24 \r
25 /*\r
26 =============================================================================\r
27 \r
28                                                  LOCAL CONSTANTS\r
29 \r
30 =============================================================================\r
31 */\r
32 \r
33 #define POINTTICS       6\r
34 #define PAUSE 300\r
35 \r
36 /*\r
37 =============================================================================\r
38 \r
39                                                  GLOBAL VARIABLES\r
40 \r
41 =============================================================================\r
42 */\r
43 \r
44 byte bcolor;\r
45 short skytimer=-1,skytimer_reset;\r
46 short groundtimer=-1,groundtimer_reset;\r
47 \r
48 unsigned scolor,gcolor;\r
49 unsigned *skycolor,*groundcolor,debug_sky,debug_gnd;\r
50 \r
51 unsigned nocolorchange=0xFFFF;\r
52 byte BGFLAGS,                           // global that holds all current flags\r
53           bgflag;                               // used by BG changer, this flag is set when done\r
54 \r
55 \r
56 unsigned sky_daytonight[]={0x0909,0x0101,0x0808,0x0000,0xFFFF};\r
57 //unsigned gnd_daytonight[]={0x0202,0xFFFF};\r
58 \r
59 unsigned sky_lightning[]={0x0101,0x0909,0x0f0f,0x0808,0x0000,0xFFFF};\r
60 \r
61 unsigned sky_colors[NUMLEVELS]={0x0000,0x0000,0x0000,0x0000,0x0808,\r
62                                                                                   0x0404,0x0000,0x0000,0x0000,0x0000,\r
63                                                                                   0x0000,0x0000,0x0000,0x0000,0x0606,\r
64                                                                                   0x0000,0x0000,0x0000,0x0000,0x0000,\r
65                                                                                   0x0000};\r
66 unsigned gnd_colors[NUMLEVELS]={0x0202,0x0202,0x0606,0x0202,0x0707,\r
67                                                                                   0x0505,0x0808,0x0606,0x0101,0x0808,\r
68                                                                                   0x0606,0x0404,0x0808,0x0c0c,0x0e0e,\r
69                                                                                   0x0808,0x0808,0x0c0c,0x0000,0x0707,\r
70                                                                                   0x0808};\r
71 \r
72 \r
73 ControlInfo     control;\r
74 boolean         running=false; //,slowturn;\r
75 \r
76 int                     bordertime;\r
77 objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj,*objfreelist;\r
78 \r
79 #if USE_INERT_LIST\r
80 inertobjtype inertobjlist[MAXINERTOBJ],*inert;\r
81 #endif\r
82 \r
83 unsigned        farmapylookup[MAPSIZE];\r
84 byte            *nearmapylookup[MAPSIZE];\r
85 \r
86 boolean         singlestep,godmode;\r
87 int                     extravbls;\r
88 status_flags    status_flag;\r
89 int             status_delay;\r
90 \r
91 //\r
92 // replacing refresh manager\r
93 //\r
94 unsigned        mapwidth,mapheight,tics,realtics;\r
95 boolean         compatability;\r
96 byte            *updateptr;\r
97 unsigned        mapwidthtable[64];\r
98 unsigned        uwidthtable[UPDATEHIGH];\r
99 unsigned        blockstarts[UPDATEWIDE*UPDATEHIGH];\r
100 #define UPDATESCREENSIZE        (UPDATEWIDE*PORTTILESHIGH+2)\r
101 #define UPDATESPARESIZE         (UPDATEWIDE*2+4)\r
102 #define UPDATESIZE                      (UPDATESCREENSIZE+2*UPDATESPARESIZE)\r
103 byte            update[UPDATESIZE];\r
104 \r
105 int             mousexmove,mouseymove;\r
106 int             pointcount,pointsleft;\r
107 \r
108 short BeepTime = 0;\r
109 \r
110 /*\r
111 =============================================================================\r
112 \r
113                                                  LOCAL VARIABLES\r
114 \r
115 =============================================================================\r
116 */\r
117 \r
118 void CalcBounds (objtype *ob);\r
119 void DrawPlayScreen (void);\r
120 void PreFullDisplay(void);\r
121 void PostFullDisplay(boolean draw_view);\r
122 \r
123 \r
124 //\r
125 // near data map array (wall values only, get text number from far data)\r
126 //\r
127 byte            tilemap[MAPSIZE][MAPSIZE];\r
128 byte            spotvis[MAPSIZE][MAPSIZE];\r
129 objtype         *actorat[MAPSIZE][MAPSIZE];\r
130 \r
131 objtype dummyobj;\r
132 \r
133 int bordertime;\r
134 int     objectcount;\r
135 \r
136 void StopMusic(void);\r
137 void StartMusic(void);\r
138 \r
139 void CalibrateJoystick(short joynum);\r
140 \r
141 //==========================================================================\r
142 \r
143 ///////////////////////////////////////////////////////////////////////////\r
144 //\r
145 //      CenterWindow() - Generates a window of a given width & height in the\r
146 //              middle of the screen\r
147 //\r
148 ///////////////////////////////////////////////////////////////////////////\r
149 \r
150 #define MAXX    320\r
151 #define MAXY    120\r
152 \r
153 void    CenterWindow(word w,word h)\r
154 {\r
155         US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h);\r
156 }\r
157 \r
158 //===========================================================================\r
159 \r
160 \r
161 /*\r
162 =====================\r
163 =\r
164 = CheckKeys\r
165 =\r
166 =====================\r
167 */\r
168 \r
169 void CheckKeys (void)\r
170 {\r
171         extern boolean autofire;\r
172 \r
173         if (screenfaded)                        // don't do anything with a faded screen\r
174                 return;\r
175 \r
176 #if 0\r
177 //\r
178 // pause key wierdness can't be checked as a scan code\r
179 //\r
180         if (Paused)\r
181         {\r
182                 CenterWindow (8,3);\r
183                 US_PrintCentered ("PAUSED");\r
184                 VW_UpdateScreen ();\r
185 //              SD_MusicOff();\r
186                 IN_Ack();\r
187 //              SD_MusicOn();\r
188                 Paused = false;\r
189                 if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
190         }\r
191         else\r
192         if (Keyboard[sc_Enter])                 // P = pause with no screen disruptioon\r
193         {\r
194 //              SD_MusicOff();\r
195                 DisplaySMsg("PAUSED",NULL);\r
196                 IN_Ack();\r
197 //              SD_MusicOn();\r
198                 if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
199         }\r
200         else\r
201         if (Keyboard[sc_S])\r
202         {\r
203                 char *Text[] = {{"Slow Mode ON"},{"Slow Mode OFF"}};\r
204 \r
205                 SlowMode ^= 1;\r
206                 extravbls = SlowMode << 3;\r
207                 CenterWindow (8,3);\r
208                 US_PrintCentered (Text[SlowMode]);\r
209                 VW_UpdateScreen ();\r
210 //              SD_MusicOff();\r
211                 IN_Ack();\r
212 //              SD_MusicOn();\r
213                 if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
214         }\r
215 #endif\r
216 \r
217 \r
218 // F2 - SOUND OPTIONS\r
219 //\r
220         if (Keyboard[sc_F2])\r
221         {\r
222                 int height=7;\r
223                 boolean ChoiceMade = false;\r
224 \r
225                 if (AdLibPresent)\r
226                         height++;\r
227 \r
228                 VW_FixRefreshBuffer();\r
229                 CenterWindow(22,height);\r
230                 US_Print( "\n        1 )  NO SOUND \n");\r
231                 US_Print(   "        2 )  PC  AUDIO \n");\r
232 \r
233                 if (AdLibPresent)\r
234                         US_Print("        3 ) ADLIB AUDIO\n");\r
235 \r
236                 US_Print( "\n       ESC)    EXIT    ");\r
237                 VW_UpdateScreen();\r
238 \r
239                 // Switch audio device ON/OFF & load sounds if there\r
240                 // was a change in the device.\r
241 \r
242                 do {\r
243 \r
244                         if (Keyboard[1])                                                                // ESC - Exit\r
245                                 ChoiceMade = true;\r
246                         else\r
247                         if (Keyboard[2])                                                                // 1 - No Sound\r
248                         {\r
249                                 SD_SetSoundMode(sdm_Off);\r
250                                 ChoiceMade = true;\r
251                         }\r
252                         else\r
253                         if (Keyboard[3])                                                        // 2 - PC Audio\r
254                         {\r
255                                 SD_SetSoundMode(sdm_PC);\r
256 //                              if (oldsoundmode != sdm_PC)\r
257                                         CA_LoadAllSounds();\r
258                                 ChoiceMade = true;\r
259                         }\r
260                         else\r
261                         if ((Keyboard[4]) &&    AdLibPresent)           // 3 - AdLib Audio\r
262                         {\r
263                                 SD_SetSoundMode(sdm_AdLib);\r
264 //                              if (oldsoundmode != sdm_AdLib)\r
265                                         CA_LoadAllSounds();\r
266                                 ChoiceMade = true;\r
267                         }\r
268 \r
269                 } while (!ChoiceMade);\r
270                 tics = realtics = 1;\r
271                 IN_ClearKeysDown();\r
272         }\r
273 \r
274 // F5 - CALIBRATE JOYSTICK\r
275 //\r
276         if (Keyboard[sc_F5])\r
277         {\r
278                 CalibrateJoystick(0);\r
279                 tics = realtics = 1;\r
280                 IN_ClearKeysDown();\r
281         }\r
282 \r
283 deadloop:;\r
284 // ESCAPE - quits game\r
285 //\r
286         if ((Keyboard[sc_Escape]) || (Flags & FL_DEAD))\r
287         {\r
288                 char ch;\r
289 \r
290                 DisplaySMsg("Options", NULL);\r
291                 status_flag = S_NONE;\r
292 \r
293 \r
294                 if (Flags & FL_DEAD)\r
295                 {\r
296                         char choices[] = {sc_Escape,sc_R,sc_N,sc_Q,0};\r
297                         ch = DisplayMsg("Restore          New          Quit",choices);\r
298                 }\r
299                 else\r
300                 {\r
301                         char choices[] = {sc_Escape,sc_S,sc_R,sc_N,sc_Q,0};\r
302                         ch = DisplayMsg("Save       Restore       New       Quit",choices);\r
303                 }\r
304                 DrawText(true);\r
305 \r
306                 switch (ch)\r
307                 {\r
308                         case sc_S:\r
309                                 if (!(Flags & FL_DEAD))\r
310                                         Keyboard[sc_F3] = true;\r
311                         break;\r
312 \r
313                         case sc_R:\r
314                                 Keyboard[sc_F4] = true;\r
315                         break;\r
316 \r
317                         case sc_N:\r
318                                 DisplaySMsg("Starting anew", NULL);\r
319                                 VW_WaitVBL(60);\r
320                                 playstate = ex_resetgame;\r
321                                 Flags &= ~FL_DEAD;\r
322                         break;\r
323 \r
324                         case sc_Q:\r
325                                 DisplaySMsg("FARE THEE WELL!", NULL);\r
326                                 VW_WaitVBL(120);\r
327                                 if (!Flags & FL_QUICK)\r
328                                         VW_FadeOut();\r
329                                 NormalScreen();\r
330                                 FreeUpMemory();\r
331                                 Quit(NULL);\r
332                         break;\r
333                 }\r
334                 tics = realtics = 1;\r
335         }\r
336 \r
337 // F1 - DISPLAY HELP\r
338 //\r
339         if (Keyboard[sc_F1])\r
340         {\r
341                 PrintHelp();\r
342 \r
343 #ifdef TEXT_PRESENTER\r
344 \r
345                 extern PresenterInfo MainHelpText;\r
346 \r
347                 VW_FadeOut();\r
348 \r
349                 FreeUpMemory();\r
350                 if (!LoadPresenterScript("HELP.TXT",&MainHelpText))\r
351                 {\r
352                         VW_FadeIn();\r
353                         CenterWindow(30,5);\r
354                         US_CPrint("\nError loading HELP file.\n");\r
355                         US_CPrint("Press any key.");\r
356                         IN_Ack();\r
357                         VW_FadeOut();\r
358                 }\r
359                 else\r
360                 {\r
361                         VW_SetSplitScreen(200);\r
362                         bufferofs = displayofs = screenloc[0];\r
363                         VW_Bar(0,0,320,200,0);\r
364 \r
365                         Display640();\r
366                         Presenter(&MainHelpText);\r
367                         Display320();\r
368                 }\r
369                 FreePresenterScript(&MainHelpText);\r
370 #endif\r
371                 VW_SetSplitScreen(120);\r
372                 VW_SetScreen(screenloc[0],0);\r
373                 screenpage = 0;\r
374                 CacheScaleds();\r
375 \r
376                 bufferofs = 0;\r
377                 RedrawStatusWindow();\r
378                 ThreeDRefresh();\r
379                 VW_FadeIn();\r
380                 Keyboard[sc_F1] = false;\r
381                 tics = realtics = 1;\r
382                 IN_ClearKeysDown();\r
383         }\r
384 \r
385 // F3 - SAVE GAME\r
386 //\r
387         if ((Keyboard[sc_F3]) && (!(Flags & FL_DEAD)))\r
388         {\r
389                 PreFullDisplay();\r
390                 GE_SaveGame();\r
391                 PostFullDisplay(true);\r
392                 tics = realtics = 1;\r
393                 IN_ClearKeysDown();\r
394         }\r
395 \r
396 // F4 - LOAD GAME\r
397 //\r
398         if (Keyboard[sc_F4])\r
399         {\r
400                 PreFullDisplay();\r
401                 if (GE_LoadGame())\r
402                 {\r
403                         loadedgame = true;\r
404                         playstate = ex_loadedgame;\r
405                         Flags &= ~FL_DEAD;\r
406                         lasttext = -1;\r
407                         PostFullDisplay(false);\r
408                 }\r
409                 else\r
410                 if (playstate == ex_victorious)\r
411                 {\r
412                         PostFullDisplay(false);\r
413                         Victory(false);\r
414                         IN_Ack();\r
415 //                      gamestate.mapon++;\r
416                 }\r
417                 else\r
418                         PostFullDisplay(true);\r
419                 Keyboard[sc_F5] = false;\r
420                 tics = realtics = 1;\r
421                 IN_ClearKeysDown();\r
422         }\r
423 \r
424         if (Flags & FL_DEAD)\r
425                 goto deadloop;\r
426 \r
427 //\r
428 // F10-? debug keys\r
429 //\r
430         if (Keyboard[sc_BackSpace])\r
431         {\r
432                 DebugKeys();\r
433                 if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
434                 lasttimecount = TimeCount;\r
435         }\r
436 }\r
437 \r
438 //-------------------------------------------------------------------------\r
439 // PreFullDisplay()\r
440 //-------------------------------------------------------------------------\r
441 void PreFullDisplay()\r
442 {\r
443         VW_FadeOut();\r
444         VW_SetSplitScreen(200);\r
445         bufferofs = displayofs = screenloc[0];\r
446         VW_Bar(0,0,320,200,0);\r
447 }\r
448 \r
449 //-------------------------------------------------------------------------\r
450 // PostFullDisplay()\r
451 //-------------------------------------------------------------------------\r
452 void PostFullDisplay(boolean draw_view)\r
453 {\r
454         VW_SetSplitScreen(120);\r
455         bufferofs = 0;\r
456         RedrawStatusWindow();\r
457         if (draw_view)\r
458         {\r
459                 ThreeDRefresh();\r
460                 VW_FadeIn();\r
461         }\r
462 }\r
463 \r
464 \r
465 //===========================================================================\r
466 \r
467 /*\r
468 #############################################################################\r
469 \r
470                                   The objlist data structure\r
471 \r
472 #############################################################################\r
473 \r
474 objlist containt structures for every actor currently playing.  The structure\r
475 is accessed as a linked list starting at *player, ending when ob->next ==\r
476 NULL.  GetNewObj inserts a new object at the end of the list, meaning that\r
477 if an actor spawn another actor, the new one WILL get to think and react the\r
478 same frame.  RemoveObj unlinks the given object and returns it to the free\r
479 list, but does not damage the objects ->next pointer, so if the current object\r
480 removes itself, a linked list following loop can still safely get to the\r
481 next element.\r
482 \r
483 <backwardly linked free list>\r
484 \r
485 #############################################################################\r
486 */\r
487 \r
488 \r
489 /*\r
490 =========================\r
491 =\r
492 = InitObjList\r
493 =\r
494 = Call to clear out the entire object list, returning them all to the free\r
495 = list.  Allocates a special spot for the player.\r
496 =\r
497 =========================\r
498 */\r
499 \r
500 void InitObjList (void)\r
501 {\r
502         int     i;\r
503 \r
504         for (i=0;i<MAXACTORS;i++)\r
505         {\r
506                 objlist[i].prev = &objlist[i+1];\r
507                 objlist[i].next = NULL;\r
508         }\r
509 \r
510         objlist[MAXACTORS-1].prev = NULL;\r
511 \r
512         objfreelist = &objlist[0];\r
513         lastobj = NULL;\r
514 \r
515         objectcount = 0;\r
516 \r
517 //\r
518 // give the player and score the first free spots\r
519 //\r
520         GetNewObj (false);\r
521         player = new;\r
522 \r
523 #if USE_INERT_LIST\r
524         inert = inertobjlist;\r
525 #endif\r
526 \r
527 }\r
528 \r
529 //===========================================================================\r
530 \r
531 /*\r
532 =========================\r
533 =\r
534 = GetNewObj\r
535 =\r
536 = Sets the global variable new to point to a free spot in objlist.\r
537 = The free spot is inserted at the end of the liked list\r
538 =\r
539 = When the object list is full, the caller can either have it bomb out ot\r
540 = return a dummy object pointer that will never get used\r
541 =\r
542 =========================\r
543 */\r
544 \r
545 void GetNewObj (boolean usedummy)\r
546 {\r
547         if (!objfreelist)\r
548         {\r
549                 if (usedummy)\r
550                 {\r
551                         new = &dummyobj;\r
552                         return;\r
553                 }\r
554                 Quit ("GetNewObj: No free spots in objlist!");\r
555         }\r
556 \r
557         new = objfreelist;\r
558         objfreelist = new->prev;\r
559         memset (new,0,sizeof(*new));\r
560 \r
561         if (lastobj)\r
562                 lastobj->next = new;\r
563         new->prev = lastobj;    // new->next is allready NULL from memset\r
564 \r
565         new->active = false;\r
566         lastobj = new;\r
567 \r
568         objectcount++;\r
569 }\r
570 \r
571 //===========================================================================\r
572 \r
573 /*\r
574 =========================\r
575 =\r
576 = RemoveObj\r
577 =\r
578 = Add the given object back into the free list, and unlink it from it's\r
579 = neighbors\r
580 =\r
581 =========================\r
582 */\r
583 \r
584 void RemoveObj (objtype *gone)\r
585 {\r
586         objtype **spotat;\r
587 \r
588         if (gone == player)\r
589                 Quit ("RemoveObj: Tried to remove the player!");\r
590 \r
591 //\r
592 // fix the next object's back link\r
593 //\r
594         if (gone == lastobj)\r
595                 lastobj = (objtype *)gone->prev;\r
596         else\r
597                 gone->next->prev = gone->prev;\r
598 \r
599 //\r
600 // fix the previous object's forward link\r
601 //\r
602         gone->prev->next = gone->next;\r
603 \r
604 //\r
605 // add it back in to the free list\r
606 //\r
607         gone->prev = objfreelist;\r
608         objfreelist = gone;\r
609 \r
610         objectcount--;\r
611 }\r
612 \r
613 #if USE_INERT_LIST\r
614 \r
615 //--------------------------------------------------------------------------\r
616 // MoveObjToInert()\r
617 //--------------------------------------------------------------------------\r
618 void MoveObjToInert(objtype *obj)\r
619 {\r
620 \r
621         if (inert == &inertobjlist[MAXINERTOBJ])\r
622                 return;\r
623 \r
624 // Transfer info needed by inert objtype\r
625 //\r
626         inert->x = obj->x;\r
627         inert->y = obj->y;\r
628         inert->size = obj->size;\r
629         inert->viewx = obj->viewx;\r
630         inert->tilex = obj->tilex;\r
631         inert->tiley = obj->tiley;\r
632         inert->state = obj->state;\r
633         inert->ticcount = obj->ticcount;\r
634 \r
635 // Setup links between inert objects\r
636 //\r
637         if (inert != inertobjlist)\r
638                 (inert-1)->next = inert;\r
639         inert->next = NULL;\r
640         inert++;\r
641 \r
642 // Free 'real' object from list.\r
643 //\r
644         RemoveObj(obj);\r
645 }\r
646 \r
647 #endif\r
648 \r
649 //==========================================================================\r
650 \r
651 /*\r
652 ===================\r
653 =\r
654 = PollControls\r
655 =\r
656 ===================\r
657 */\r
658 \r
659 void PollControls (void)\r
660 {\r
661         unsigned buttons;\r
662 \r
663         IN_ReadControl(0,&control);\r
664 \r
665         if (MousePresent)\r
666         {\r
667                 Mouse(MButtons);\r
668                 buttons = _BX;\r
669                 Mouse(MDelta);\r
670                 mousexmove = _CX;\r
671                 mouseymove = _DX;\r
672 \r
673                 if (buttons&1)\r
674                         control.button0 = 1;\r
675                 if (buttons&2)\r
676                         control.button1 = 1;\r
677 \r
678         }\r
679 \r
680         if (Keyboard[sc_V] || Keyboard[sc_Tab])\r
681                 running = true;\r
682         else\r
683                 running = false;\r
684 }\r
685 \r
686 //==========================================================================\r
687 \r
688 #if 0\r
689 /*\r
690 =================\r
691 =\r
692 = StopMusic\r
693 =\r
694 =================\r
695 */\r
696 \r
697 void StopMusic(void)\r
698 {\r
699         int     i;\r
700 \r
701         SD_MusicOff();\r
702         for (i = 0;i < LASTMUSIC;i++)\r
703                 if (audiosegs[STARTMUSIC + i])\r
704                 {\r
705                         MM_SetPurge(&((memptr)audiosegs[STARTMUSIC + i]),3);\r
706                         MM_SetLock(&((memptr)audiosegs[STARTMUSIC + i]),false);\r
707                 }\r
708 }\r
709 \r
710 //==========================================================================\r
711 \r
712 \r
713 /*\r
714 =================\r
715 =\r
716 = StartMusic\r
717 =\r
718 =================\r
719 */\r
720 \r
721 // JAB - Cache & start the appropriate music for this level\r
722 void StartMusic(void)\r
723 {\r
724         musicnames      chunk;\r
725 \r
726         SD_MusicOff();\r
727         chunk = TOOHOT_MUS;\r
728 //      if ((chunk == -1) || (MusicMode != smm_AdLib))\r
729 //DEBUG control panel           return;\r
730 \r
731         MM_BombOnError (false);\r
732         CA_CacheAudioChunk(STARTMUSIC + chunk);\r
733         MM_BombOnError (true);\r
734         if (mmerror)\r
735                 mmerror = false;\r
736         else\r
737         {\r
738                 MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true);\r
739                 SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]);\r
740         }\r
741 }\r
742 #endif\r
743 \r
744 //==========================================================================\r
745 \r
746 \r
747 /*\r
748 ===================\r
749 =\r
750 = PlayLoop\r
751 =\r
752 ===================\r
753 */\r
754 \r
755 void PlayLoop (void)\r
756 {\r
757         char shot_color[3] = {4,9,14};\r
758 \r
759         int allgems[5]={GEM_DELAY_TIME,         // used for Q & D comparison\r
760                                                  GEM_DELAY_TIME,                // for having all gems...\r
761                                                  GEM_DELAY_TIME,                // the "allgems" declaration MUST\r
762                                                  GEM_DELAY_TIME,                // match the "gems" declaration in\r
763                                                  GEM_DELAY_TIME         // the gametype structure!\r
764                                                 };\r
765 \r
766 //      int originx=0;\r
767 //      int i=100;\r
768         signed long dx,dy,radius,psin,pcos,newx,newy;\r
769         int             give;\r
770         short objnum;\r
771         signed long ox,oy,xl,xh,yl,yh,px,py,norm_dx,norm_dy;\r
772         short o_radius;\r
773 \r
774         void (*think)();\r
775 \r
776         ingame = true;\r
777         playstate = TimeCount = 0;\r
778         gamestate.shotpower = handheight = 0;\r
779         pointcount = pointsleft = 0;\r
780 \r
781         status_flag = S_NONE;\r
782 \r
783 #if 0\r
784         // setup sky/ground colors and effects (based on level)\r
785         //\r
786         switch (gamestate.mapon)\r
787         {\r
788                 case 255:\r
789                         if (!(BGFLAGS & BGF_NIGHT))\r
790                         {\r
791                                 InitBgChange(3*60,sky_daytonight,-1,NULL,BGF_NIGHT);\r
792                                 groundcolor = &gnd_colors[0];\r
793                         }\r
794                         else\r
795                         {\r
796                                 skycolor = &sky_colors[0];\r
797                                 groundcolor = &gnd_colors[0];\r
798                         }\r
799                 break;\r
800 \r
801                 default:\r
802                         skycolor = &sky_colors[gamestate.mapon];\r
803                         groundcolor = &gnd_colors[gamestate.mapon];\r
804                         skytimer = groundtimer = -1;\r
805                 break;\r
806         }\r
807 #endif\r
808 \r
809         BGFLAGS |= BGF_NOT_LIGHTNING;\r
810         skytimer = groundtimer = -1;\r
811 \r
812         debug_gnd = *groundcolor;\r
813         debug_sky = *skycolor;\r
814         RedrawStatusWindow();\r
815         ThreeDRefresh();\r
816         if (screenfaded)\r
817                 VW_FadeIn();\r
818 \r
819 #ifndef PROFILE\r
820         fizzlein = true;                                // fizzle fade in the first refresh\r
821 #endif\r
822         TimeCount = lasttimecount = lastnuke = 0;\r
823 \r
824         PollControls ();                                // center mouse\r
825 //      StartMusic ();\r
826         do\r
827         {\r
828 #ifndef PROFILE\r
829                 PollControls();\r
830 #else\r
831                 control.xaxis = 1;\r
832                 if (++TimeCount == 300)\r
833                         return;\r
834 #endif\r
835                 DisplayStatus(&status_flag);\r
836 \r
837                 objnum=0;\r
838                 for (obj = player;obj;obj = obj->next)\r
839                 {\r
840                         if ((obj->active >= yes) && (!(FreezeTime && (obj!=player))))\r
841                         {\r
842                                 if (obj->ticcount)\r
843                                 {\r
844                                         obj->ticcount-=realtics;\r
845                                         while ( obj->ticcount <= 0)\r
846                                         {\r
847                                                 think = obj->state->think;\r
848                                                 if (think)\r
849                                                 {\r
850                                                         statetype *oldstate=obj->state;\r
851 \r
852                                                         think (obj);\r
853                                                         if (!obj->state)\r
854                                                         {\r
855                                                                 RemoveObj (obj);\r
856                                                                 goto nextactor;\r
857                                                         }\r
858                                                         if (obj->state != oldstate)\r
859                                                                 break;\r
860                                                 }\r
861 \r
862                                                 obj->state = obj->state->next;\r
863                                                 if (!obj->state)\r
864                                                 {\r
865                                                         RemoveObj (obj);\r
866                                                         goto nextactor;\r
867                                                 }\r
868                                                 if (!obj->state->tictime)\r
869                                                 {\r
870                                                         obj->ticcount = 0;\r
871                                                         goto nextactor;\r
872                                                 }\r
873                                                 if (obj->state->tictime>0)\r
874                                                         obj->ticcount += obj->state->tictime;\r
875                                         }\r
876                                 }\r
877 \r
878                                 think = obj->state->think;\r
879                                 if (think)\r
880                                 {\r
881                                         think (obj);\r
882                                         if (!obj->state)\r
883                                                 RemoveObj (obj);\r
884                                 }\r
885 nextactor:;\r
886                         }\r
887 \r
888                         // keep a list of objects around the player for radar updates\r
889                         //\r
890                                 if (obj == player)\r
891                                 {\r
892                                         px = player->x;\r
893                                         py = player->y;\r
894                                         psin = sintable[player->angle];\r
895                                         pcos = costable[player->angle];\r
896                                         xl = px-((long)RADAR_WIDTH<<TILESHIFT)/2;\r
897                                         xh = px+((long)RADAR_WIDTH<<TILESHIFT)/2-1;\r
898                                         yl = py-((long)RADAR_HEIGHT<<TILESHIFT)/2;\r
899                                         yh = py+((long)RADAR_HEIGHT<<TILESHIFT)/2;\r
900                                 }\r
901 \r
902                                 if (objnum > MAX_RADAR_BLIPS-2)\r
903                                         objnum = MAX_RADAR_BLIPS-2;\r
904 \r
905                                 ox = obj->x;\r
906                                 oy = obj->y;\r
907 \r
908 \r
909                                 if ((ox >= xl) && (ox <= xh) && (oy >= yl) && (oy <= yh))\r
910                                 {\r
911                                         norm_dx = (dx = px-ox)>>TILESHIFT;\r
912                                         norm_dy = (dy = oy-py)>>TILESHIFT;\r
913 \r
914                                         o_radius = IntSqrt((norm_dx * norm_dx) + (norm_dy * norm_dy));\r
915 \r
916                                         if (o_radius < RADAR_RADIUS)\r
917                                         {\r
918                                                 newx = FixedByFrac(dy,pcos)-FixedByFrac(dx,psin);\r
919                                                 newy = FixedByFrac(dy,psin)+FixedByFrac(dx,pcos);\r
920 \r
921                                                 RadarXY[objnum][0]=newx>>TILESHIFT;\r
922                                                 RadarXY[objnum][1]=newy>>TILESHIFT;\r
923 \r
924                                                 // Define color to use for this object...\r
925                                                 //\r
926 \r
927                                                 switch (obj->obclass)\r
928                                                 {\r
929                         // NO GEM NEEDED\r
930                         //\r
931                                         // THE WIZARD! (YOU)\r
932                                         //\r
933                                                         case playerobj:\r
934                                                                 RadarXY[objnum++][2]=15;\r
935                                                         break;\r
936 \r
937                                         // WIZARD'S SHOTS\r
938                                         //\r
939                                                         case pshotobj:\r
940                                                         case bigpshotobj:\r
941                                                                 RadarXY[objnum++][2]=shot_color[screenpage];\r
942                                                         break;\r
943 \r
944                                         // BATS                                                         (DK GRAY)\r
945                                         //\r
946                                                         case batobj:\r
947                                                                 if (obj->active == always)\r
948                                                                         RadarXY[objnum++][2]=8;\r
949                                                         break;\r
950 \r
951                                         // RABBITS                                                      (LT GRAY)\r
952                                         //\r
953                                                         case bunnyobj:\r
954                                                                 if (obj->active == always)\r
955                                                                         RadarXY[objnum++][2]=7;\r
956                                                         break;\r
957 \r
958                         // RED GEM\r
959                         //\r
960                                         // EYE, RED DEMON                                               (DK RED)\r
961                                         //\r
962                                                         case eyeobj:\r
963                                                         case reddemonobj:\r
964                                                                 if (gamestate.gems[B_RGEM-B_RGEM])\r
965                                                                         if (obj->active == always)\r
966                                                                                 RadarXY[objnum++][2]=4;\r
967                                                         break;\r
968 \r
969                                         // RED MAGE                                                     (LT RED)\r
970                                         //\r
971                                                         case mageobj:\r
972                                                                 if (gamestate.gems[B_RGEM-B_RGEM])\r
973                                                                         if (obj->active == always)\r
974                                                                                 RadarXY[objnum++][2]=12;\r
975                                                         break;\r
976 \r
977                         // BLUE GEM\r
978                         //\r
979                                         // SUCCUBUS                                                     (LT BLUE)\r
980                                         //\r
981                                                         case succubusobj:\r
982                                                                 if (gamestate.gems[B_BGEM-B_RGEM])\r
983                                                                         if (obj->active == always)\r
984                                                                                 RadarXY[objnum++][2]=9;\r
985                                                         break;\r
986 \r
987                                         // WATER DRAGON                                                 (DK BLUE)\r
988                                         //\r
989                                                         case wetobj:\r
990                                                                 if (gamestate.gems[B_GGEM-B_RGEM])\r
991                                                                         if (obj->active == always)\r
992                                                                                 RadarXY[objnum++][2]=1;\r
993                                                         break;\r
994 \r
995 \r
996 \r
997                         // GREEN GEM\r
998                         //\r
999                                         // GREEN TROLL                                                  (LT GREEN)\r
1000                                         //\r
1001                                                         case fatdemonobj:\r
1002                                                                 if (gamestate.gems[B_GGEM-B_RGEM])\r
1003                                                                         if (obj->active == always)\r
1004                                                                                 RadarXY[objnum++][2]=10;\r
1005                                                         break;\r
1006 \r
1007                                         // GODESS                                                       (DK GREEN)\r
1008                                         //\r
1009                                                         case godessobj:\r
1010                                                                 if (gamestate.gems[B_GGEM-B_RGEM])\r
1011                                                                         if (obj->active == always)\r
1012                                                                                 RadarXY[objnum++][2]=2;\r
1013                                                         break;\r
1014 \r
1015                         // YELLOW GEM\r
1016                         //\r
1017                                         // ANT                                                          (BROWN)\r
1018                                         //\r
1019                                                         case antobj:\r
1020                                                         case treeobj:\r
1021                                                                 if (gamestate.gems[B_YGEM-B_RGEM])\r
1022                                                                         if (obj->active == always)\r
1023                                                                                 RadarXY[objnum++][2]=6;\r
1024                                                         break;\r
1025 \r
1026                                         // SKELETON                                                     (YELLOW)\r
1027                                         //\r
1028                                                         case skeletonobj:\r
1029                                                                 if (gamestate.gems[B_YGEM-B_RGEM])\r
1030                                                                         if (obj->active == always)\r
1031                                                                                 RadarXY[objnum++][2]=14;\r
1032                                                         break;\r
1033 \r
1034                         // PURPLE GEM\r
1035                         //\r
1036                                         // ZOMBIE\r
1037                                         //\r
1038                                                         case zombieobj:\r
1039                                                                 if (gamestate.gems[B_PGEM-B_RGEM])\r
1040                                                                         if (obj->active == always)\r
1041                                                                                 RadarXY[objnum++][2]=13;\r
1042                                                         break;\r
1043 \r
1044                         // ALL GEMS NEEDED\r
1045                         //\r
1046                                         // NEMESIS\r
1047                                         //\r
1048                                                         case grelmobj:\r
1049                                                                 if (!memcmp(gamestate.gems,allgems,sizeof(gamestate.gems)))\r
1050                                                                         if (obj->active == always)\r
1051                                                                                 RadarXY[objnum++][2]=15;\r
1052                                                         break;\r
1053                                                 }\r
1054                                         }\r
1055                                 }\r
1056                 }\r
1057                 RadarXY[objnum][2]=-1;          // Signals end of RadarXY list...\r
1058 \r
1059 #if USE_INERT_LIST\r
1060                 if (inert != inertobjlist)\r
1061                         for (obj=(objtype *)inertobjlist;obj;obj=obj->next)\r
1062                                 if (obj->ticcount)\r
1063                                 {\r
1064                                         obj->ticcount-=realtics;\r
1065                                         while ( obj->ticcount <= 0)\r
1066                                         {\r
1067                                                 obj->state = obj->state->next;\r
1068                                                 if (!obj->state)\r
1069                                                         Quit("Removable object in INERT list.");\r
1070 \r
1071                                                 if (!obj->state->tictime)\r
1072                                                 {\r
1073                                                         obj->ticcount = 0;\r
1074                                                         goto nextactor;\r
1075                                                 }\r
1076 \r
1077                                                 if (obj->state->tictime>0)\r
1078                                                         obj->ticcount += obj->state->tictime;\r
1079                                         }\r
1080                                 }\r
1081 #endif\r
1082 \r
1083                 if (bordertime)\r
1084                 {\r
1085                         bordertime -= realtics;\r
1086                         if (bordertime<=0)\r
1087                         {\r
1088                                 bordertime = 0;\r
1089                                 VW_ColorBorder(0);\r
1090                         }\r
1091                 }\r
1092 \r
1093 #if 1\r
1094 // random lightning?\r
1095 //\r
1096         if (BGFLAGS & (BGF_NOT_LIGHTNING))\r
1097         {\r
1098                 if ((scolor & 0xe0) && (!(random(20-realtics))))\r
1099                 {\r
1100                         BGFLAGS &= ~BGF_NOT_LIGHTNING;\r
1101                         InitBgChange(1,sky_lightning,-1,NULL,BGF_NOT_LIGHTNING);\r
1102                 }\r
1103         }\r
1104 \r
1105 // handle sky/ground color changes\r
1106 //\r
1107                 if (skytimer != -1)\r
1108                 {\r
1109                         skytimer -= realtics;\r
1110                         if (skytimer < 0)\r
1111                         {\r
1112                                 skycolor++;\r
1113                                 if (*skycolor == 0xffff)\r
1114                                 {\r
1115                                         skytimer = -1;\r
1116 //                                      skycolor--;\r
1117                                         skycolor = &scolor;\r
1118                                         if (groundtimer == -1)\r
1119                                                 BGFLAGS |= bgflag;\r
1120                                 }\r
1121                                 else\r
1122                                         skytimer = skytimer_reset;\r
1123                         }\r
1124                 }\r
1125 \r
1126                 if (groundtimer != -1)\r
1127                 {\r
1128                         groundtimer -= realtics;\r
1129                         if (groundtimer < 0)\r
1130                         {\r
1131                                 groundcolor++;\r
1132                                 if (*groundcolor == 0xffff)\r
1133                                 {\r
1134                                         groundtimer = -1;\r
1135 //                                      groundcolor--;\r
1136                                         groundcolor = &gcolor;\r
1137                                         if (skytimer == -1)\r
1138                                                 BGFLAGS |= bgflag;\r
1139                                 }\r
1140                                 else\r
1141                                         groundtimer = groundtimer_reset;\r
1142                         }\r
1143                 }\r
1144 #endif\r
1145 \r
1146 \r
1147 //\r
1148 //              Handle FreezeTime counter..\r
1149 //\r
1150                 if (FreezeTime)\r
1151                 {\r
1152                         if (FreezeTime<20*30)\r
1153                                 if ((BeepTime+=realtics)>=60)\r
1154                                 {\r
1155                                         BeepTime -= 60;\r
1156                                         SD_PlaySound(TICKSND);\r
1157                                 }\r
1158 \r
1159                         if ((FreezeTime-=realtics)<=0)\r
1160                         {\r
1161                                 FreezeTime=0;\r
1162                                 SD_PlaySound(TIMERETURNSND);\r
1163                                 DisplaySMsg(NULL,NULL);\r
1164                                 status_flag = S_NONE;\r
1165                         }\r
1166                 }\r
1167 \r
1168 \r
1169 // refresh all\r
1170 //\r
1171                 ThreeDRefresh ();\r
1172 \r
1173                 if (Flags & FL_DEAD)\r
1174                 {\r
1175                         SD_PlaySound (GAMEOVERSND);\r
1176                         DisplaySMsg("DEAD",NULL);\r
1177                         DrawHealth();\r
1178                         if (gamestate.potions)\r
1179                         {\r
1180                                  bufferofs = displayofs = screenloc[screenpage];\r
1181                                  CenterWindow(35,3);\r
1182                                  US_CPrint("\nYou should use your Cure Potions wisely\n");\r
1183                                  IN_Ack();\r
1184                         }\r
1185                 }\r
1186 \r
1187 // check for win\r
1188 //\r
1189                 if (playstate == ex_victorious)\r
1190                 {\r
1191                         Victory(true);\r
1192 //                      Flags |= FL_DEAD;\r
1193                         IN_Ack();\r
1194 //                      gamestate.mapon++;\r
1195                 }\r
1196 \r
1197                 CheckKeys();\r
1198 \r
1199         }while (!playstate);\r
1200 //      StopMusic ();\r
1201 \r
1202         ingame = false;\r
1203         if (bordertime)\r
1204         {\r
1205                 bordertime = 0;\r
1206                 VW_ColorBorder(0);\r
1207         }\r
1208 \r
1209         if (abortgame)\r
1210                 abortgame = false;\r
1211 }\r
1212 \r
1213 //--------------------------------------------------------------------------\r
1214 // IntSqrt() - by Master Programmer, George Leritte!\r
1215 //--------------------------------------------------------------------------\r
1216 int IntSqrt(long va)\r
1217 {\r
1218 asm     mov     AX, word ptr va\r
1219 asm     mov     DX, word ptr va+2\r
1220 asm     mov     bx,dx           // {bx = integer square root of dx:ax}\r
1221 asm     or      bx,ax           // {if dx:ax=0 then return}\r
1222 asm     jz      isq01\r
1223 asm     mov     bx,dx\r
1224 asm     shl     bx,1\r
1225 asm     or      bl,ah\r
1226 asm     or      bl,al\r
1227 asm     dec     bx\r
1228 asm     add     bx,dx           // { initial guess}\r
1229 asm     jg      isq10\r
1230 asm     inc     bx              // { don't return zero}\r
1231 asm     jg      isq10\r
1232 asm     mov     bx,7fffh\r
1233 isq01:;\r
1234                   goto    exitrout;\r
1235 \r
1236 isq10:;\r
1237 asm     push    ax\r
1238 asm     push    dx\r
1239 asm     div     bx\r
1240 asm     sub     ax,bx\r
1241 asm     cmp     ax,1\r
1242 asm     jbe     isq90\r
1243 asm     cmp     ax,-1\r
1244 asm     jae     isq90\r
1245 asm     sar     ax,1\r
1246 asm     add     bx,ax\r
1247 asm     pop     dx\r
1248 asm     pop     ax\r
1249 asm     jmp     isq10\r
1250 isq90:;\r
1251 asm     pop     dx\r
1252 asm     pop     ax\r
1253 exitrout:;\r
1254 asm     mov     ax,bx\r
1255 }\r
1256 \r
1257 //-------------------------------------------------------------------------\r
1258 // InitBgChange()\r
1259 //-------------------------------------------------------------------------\r
1260 void InitBgChange(short stimer, unsigned *scolors, short gtimer, unsigned *gcolors, byte flag)\r
1261 {\r
1262         skytimer_reset = skytimer = stimer;\r
1263         if (scolors)\r
1264                 skycolor = scolors;\r
1265 \r
1266         groundtimer_reset = groundtimer = gtimer;\r
1267         if (gcolors)\r
1268                 groundcolor = gcolors;\r
1269 \r
1270         bgflag = flag;\r
1271 }\r
1272 \r
1273 ////////////////////////////////////////////////////////\r
1274 //\r
1275 // DisplayStatus\r
1276 //\r
1277 //  Stat_Flag -  contains the type of status displayed\r
1278 //  -- also uses status_delay (global variable) will not\r
1279 //     change display until this variable is zero.\r
1280 //  -- heirarchy is determined by the series of if statements,\r
1281 //        to change it, rearrange th if statements.\r
1282 //\r
1283 ////////////////////////////////////////////////////////\r
1284 \r
1285 #define MESSAGEDELAY  25\r
1286 void DisplayStatus (status_flags *stat_flag)\r
1287 {\r
1288         status_flags temp_status;\r
1289 \r
1290 \r
1291         if (*stat_flag == S_TIMESTOP)\r
1292           return;\r
1293 \r
1294         if (status_delay > 0)\r
1295         {\r
1296                 status_delay -= realtics;\r
1297                 return;\r
1298         }\r
1299         else\r
1300                 status_delay = 0;\r
1301 \r
1302         // check for a change in status from previous call\r
1303 \r
1304         temp_status = S_VIEWING;                             //precaution\r
1305 \r
1306         if (Keyboard[sc_Control] || control.button0)\r
1307                 temp_status = S_MISSLE;\r
1308 \r
1309         if (Keyboard[sc_Z] && !Keyboard[sc_F10])\r
1310                 temp_status = S_ZAPPER;\r
1311 \r
1312         if ((Keyboard[sc_X] && !Keyboard[sc_F10]) || Keyboard[sc_Enter])\r
1313                 temp_status = S_XTER;\r
1314 \r
1315         if (control.x)\r
1316                 temp_status = S_TURN;\r
1317 \r
1318         if ((Keyboard[sc_V] || Keyboard[sc_Tab]) && control.x)\r
1319                 temp_status = S_QTURN;\r
1320 \r
1321         if (Keyboard[sc_Alt] && control.x)\r
1322                 temp_status = S_SIDESTEP;\r
1323 \r
1324         if (control.y < 0)\r
1325                 temp_status = S_ADVANCE;\r
1326 \r
1327         if (control.y > 0)\r
1328                 temp_status = S_RETREAT;\r
1329 \r
1330         if (Keyboard[sc_F5])\r
1331                 temp_status = S_JOYSTICK;\r
1332 \r
1333         if (Keyboard[sc_F4])\r
1334                 temp_status = S_RESTORING;\r
1335 \r
1336         if (Keyboard[sc_F3])\r
1337                 temp_status = S_SAVING;\r
1338 \r
1339         if (Keyboard[sc_F2])\r
1340                 temp_status = S_SND;\r
1341 \r
1342         if (Keyboard[sc_F1])\r
1343                 temp_status = S_HELP;\r
1344 \r
1345         if (temp_status != *stat_flag)\r
1346         {\r
1347                 *stat_flag = temp_status;\r
1348 \r
1349 \r
1350                 switch (*stat_flag)\r
1351                 {\r
1352                         case S_MISSLE:\r
1353                                 DisplaySMsg("Magick Missile", NULL);\r
1354                                 status_delay = MESSAGEDELAY;\r
1355                         break;\r
1356 \r
1357                         case S_ZAPPER:\r
1358                                 if (gamestate.bolts)\r
1359                                 {\r
1360                                         DisplaySMsg("Zapper", NULL);\r
1361                                         status_delay = MESSAGEDELAY+10;\r
1362                                 }\r
1363                         break;\r
1364 \r
1365                         case S_XTER:\r
1366                                 if (gamestate.nukes)\r
1367                                 {\r
1368                                         DisplaySMsg("Xterminator", NULL);\r
1369                                         status_delay = MESSAGEDELAY+5;\r
1370                                 }\r
1371                         break;\r
1372 \r
1373                         case S_TURN:\r
1374                                 DisplaySMsg("Turning", NULL);\r
1375                                 status_delay = MESSAGEDELAY;\r
1376                         break;\r
1377 \r
1378                         case S_QTURN:\r
1379                                 DisplaySMsg("Quick Turning", NULL);\r
1380                                 status_delay = MESSAGEDELAY;\r
1381                         break;\r
1382 \r
1383                         case S_SIDESTEP:\r
1384                                 DisplaySMsg("Sidestepping", NULL);\r
1385                                 status_delay = MESSAGEDELAY;\r
1386                         break;\r
1387 \r
1388                         case S_ADVANCE:\r
1389                                 DisplaySMsg("Advancing", NULL);\r
1390                                 status_delay = MESSAGEDELAY;\r
1391                         break;\r
1392 \r
1393                         case S_RETREAT:\r
1394                                 DisplaySMsg("Retreating", NULL);\r
1395                                 status_delay = MESSAGEDELAY;\r
1396                         break;\r
1397 \r
1398                         case S_JOYSTICK:\r
1399                                 DisplaySMsg("Adjusting Joystick", NULL);\r
1400                         break;\r
1401 \r
1402                         case S_RESTORING:\r
1403                                 DisplaySMsg("Restoring", NULL);\r
1404                         break;\r
1405 \r
1406                         case S_SAVING:\r
1407                                 DisplaySMsg("Saving", NULL);\r
1408                         break;\r
1409 \r
1410                         case S_SND:\r
1411                                 DisplaySMsg("Select Sound", NULL);\r
1412                         break;\r
1413 \r
1414                         case S_HELP:\r
1415                                 DisplaySMsg("Getting Help", NULL);\r
1416                         break;\r
1417 \r
1418                         case S_VIEWING:\r
1419                                 DisplaySMsg("Viewing", NULL);\r
1420                         break;\r
1421                 }\r
1422                 bufferofs = displayofs = screenloc[screenpage];\r
1423 \r
1424         }\r
1425 }\r