1 /*
2 Copyright (C) 1994-1995 Apogee Software, Ltd.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 #include "rt_def.h"
21 #include "lumpy.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stddef.h>
25 #include <fcntl.h>
26 #include <string.h>
27 
28 #ifdef DOS
29 #include <malloc.h>
30 #include <dos.h>
31 #include <io.h>
32 #include <conio.h>
33 #include <graph.h>
34 #include <process.h>
35 #include <direct.h>
36 #include <bios.h>
37 #else
38 #include <signal.h>
39 #endif
40 
41 #if USE_SDL
42 /* Need to redefine main to SDL_main on some platforms... */
43 #include "SDL.h"
44 #endif
45 
46 #include "rt_actor.h"
47 #include "rt_stat.h"
48 #include "rt_vid.h"
49 #include "rt_menu.h"
50 #include "rt_sound.h"
51 #include "watcom.h"
52 #include "scriplib.h"
53 #include "rt_main.h"
54 #include "_rt_main.h"
55 #include "rt_com.h"
56 #include "rt_util.h"
57 #include "z_zone.h"
58 #include "w_wad.h"
59 #include "rt_game.h"
60 #include "rt_floor.h"
61 #include "rt_playr.h"
62 #include "rt_draw.h"
63 #include "rt_str.h"
64 #include "rt_view.h"
65 #include "rt_door.h"
66 #include "rt_ted.h"
67 #include "rt_in.h"
68 #include "rt_map.h"
69 #include "rt_rand.h"
70 #include "rt_debug.h"
71 #include "isr.h"
72 #include "rt_cfg.h"
73 #include "develop.h"
74 #include "version.h"
75 #include "rt_menu.h"
76 #include "rt_dr_a.h"
77 #include "rt_msg.h"
78 #include "rt_build.h"
79 #include "rt_error.h"
80 #include "modexlib.h"
81 #include "rt_net.h"
82 #include "cin_main.h"
83 #include "rottnet.h"
84 #include "rt_scale.h"
85 
86 #include "music.h"
87 #include "fx_man.h"
88 //MED
89 #include "memcheck.h"
90 
91 volatile int    oldtime;
92 volatile int    gametime;
93 
94 boolean         tedlevel;
95 int             tedlevelnum;
96 int             tedx=0;
97 int             tedy=0;
98 boolean         warp;
99 int             warpx=0;
100 int             warpy=0;
101 int             warpa=0;
102 int             NoSound;
103 int             polltime;
104 int             oldpolltime;
105 boolean         fizzlein = false;
106 int             pheight;
107 
108 boolean SCREENSHOTS             = false;
109 boolean MONOPRESENT             = false;
110 boolean MAPSTATS                = false;
111 boolean TILESTATS               = false;
112 boolean HUD                     = false;
113 boolean IS8250                  = false;
114 
115 boolean dopefish;
116 
117 boolean newlevel = false;
118 boolean infopause;
119 boolean SOUNDSETUP=false;
120 boolean quiet = false;
121 
122 #if (DEVELOPMENT == 1)
123 boolean DebugOk = true;
124 #else
125 boolean DebugOk = false;
126 #endif
127 
128 #if (WHEREAMI==1)
129 int programlocation=-1;
130 #endif
131 
132 #if SAVE_SCREEN
133 static char savename[13] = "ROTT0000.LBM";
134 static int totalbytes;
135 static byte *bptr;
136 #endif
137 static boolean turbo;
138 
139 static int NoWait;
140 static int startlevel=0;
141 static int demonumber=-1;
142 
143 char CWD[40];                          // curent working directory
144 static boolean quitactive = false;
145 
146 int timelimit;
147 int maxtimelimit;
148 boolean timelimitenabled;
149 boolean demoexit;
150 boolean noecho;
151 
152 void CheckCommandLineParameters( void );
153 void PlayTurboGame( void );
154 void Init_Tables (void);
155 void CheckRemoteRidicule ( int scancode );
156 
157 #ifndef DOS
158 extern void crash_print (int);
159 extern int setup_homedir (void);
160 #endif
161 
main(int argc,char * argv[])162 int main (int argc, char *argv[])
163 {
164     char *macwd;
165 #ifndef DOS
166 	_argc = argc;
167 	_argv = argv;
168 #endif
169 
170 #if defined(PLATFORM_MACOSX)
171     {
172         /* OS X will give us a path in the form '/Applications/Rise of the Triad.app/Contents/MacOS/Rise of the Triad'.
173            Our data is in Contents/Resources. */
174         char *path;
175         const char suffix[] = "/Resources/";
176         int end;
177         path = (char *)malloc(strlen(argv[0]) + strlen(suffix) + 1);
178         if (path == NULL) return 1;
179         strcpy(path, argv[0]);
180         /* Back up two '/'s. */
181         for (end = strlen(path)-1; end >= 0 && path[end] != '/'; end--);
182         if (end >= 0) for (--end; end >= 0 && path[end] != '/'; end--);
183         strcpy(&path[end], suffix);
184         printf("Changing to working directory: %s\n", path);
185         chdir(path);
186         free(path);
187     }
188 #endif
189 
190 #ifdef DC
191 	platform_init();
192 #elif !defined(DOS)
193    signal (11, crash_print);
194 
195    if (setup_homedir() == -1) return 1;
196 #endif
197 
198    // Set which release version we're on
199    gamestate.Version = ROTTVERSION;
200 
201 #if ( SHAREWARE == 1 )
202    gamestate.Product = ROTT_SHAREWARE;
203 #else
204    {
205 	struct {
206 		const char *file;
207 		version_type ver;
208 	} const list[] = {
209 		{"ROTTSITE.RTC",ROTT_SITELICENSE},
210 		{"ROTTCD.RTC",ROTT_SUPERCD},
211 		{"DARKWAR.RTC",ROTT_REGISTERED},
212 		{"HUNTBGIN.RTC",ROTT_SHAREWARE},
213 	};
214 extern char * ROTTMAPS;
215 extern char * BATTMAPS;
216 
217 	int i;
218 	for(i=0;i<sizeof(list)/sizeof(list[0])-1;i++) {
219 		if (access(list[i].file,F_OK)==0) break;
220 	}
221 	gamestate.Product = list[i].ver;
222 	BATTMAPS = list[i].file;
223 	ROTTMAPS = list[i].ver==ROTT_SHAREWARE?"HUNTBGIN.RTL":"DARKWAR.RTL";
224    }
225 #endif
226 
227    DrawRottTitle ();
228    gamestate.randomseed=-1;
229 
230    gamestate.autorun = 0;
231    StartupSoftError();
232 //   UL_ErrorStartup ();
233 
234    CheckCommandLineParameters();
235 
236    // Start up Memory manager with a certain amount of reserved memory
237 
238    Z_Init(50000,1000000);
239 
240    IN_Startup ();
241 
242    InitializeGameCommands();
243    if (standalone==false)
244       {
245       ReadConfig ();
246       ReadSETUPFiles ();
247       doublestep=0;
248       SetupWads();
249       BuildTables ();
250       GetMenuInfo ();
251       }
252 
253 //   if (modemgame==true)
254 //      {
255 //      SCREENSHOTS=true;
256 //      if (standalone==false)
257 //         {
258 //         MenuFixup ();
259 //         }
260 //      MAPSTATS=true;
261 //      }
262    if (standalone==false)
263       {
264       int status1 = 0;
265       int status2 = 0;
266       int status3 = 0;
267 
268       if ( !NoSound && !IS8250 )
269          {
270          if (!quiet)
271             printf( "MU_Startup: " );
272          status1 = MU_Startup(false);
273          if (!quiet)
274             printf( "%s\n", MUSIC_ErrorString( MUSIC_Error ) );
275          }
276       else if ( IS8250 )
277          {
278          printf( "==============================================================================\n");
279          printf( "WARNING: 8250 detected.\n" );
280          printf( "Music has been disabled.  This is necessary to maintain high interrupt\n" );
281          printf( "rates with the 8250 UART which will improve overall game performance.\n");
282          printf( "                      < Press any key to continue >\n");
283          printf( "==============================================================================\n");
284          getch();
285          }
286 
287       if (!NoSound)
288          {
289          int nv, nb, nc;
290 
291          if (!quiet)
292             printf( "SD_SetupFXCard: " );
293          status2 = SD_SetupFXCard (&nv, &nb, &nc);
294          if (!quiet)
295             printf( "%s\n", FX_ErrorString( FX_Error ) );
296 
297          if ( !status2 )
298             {
299             if (!quiet)
300                printf( "SD_Startup: " );
301             status3 = SD_Startup(false);
302             if (!quiet)
303                printf( "%s\n", FX_ErrorString( FX_Error ) );
304             }
305          }
306       else
307          {
308          if (!quiet)
309             printf( "Sound FX disabled.\n" );
310          }
311 
312       if ( status1 || status2 || status3 )
313          {
314          printf( "\n\nROTT was unable to initialize your " );
315          if ( status1 )
316             {
317             printf( "music " );
318             MusicMode = 0;
319             }
320          if ( status2 || status3 )
321             {
322             if ( status1 )
323                {
324                printf( "or " );
325                }
326             printf( "sound fx " );
327 
328             FXMode = 0;
329             }
330 
331          printf( "hardware.\n"
332                  "Now entering sound setup.\n" );
333          SOUNDSETUP = true;
334          }
335 
336       Init_Tables ();
337       InitializeRNG ();
338       InitializeMessages();
339       LoadColorMap();
340       }
341    if (infopause==true)
342       {
343       printf("\n< Press any key to continue >\n");
344       getch();
345       }
346    I_StartupTimer();
347    I_StartupKeyboard();
348 #if 0
349 #if (SHAREWARE == 1)
350    if ((!SOUNDSETUP) && (standalone==false))
351       {
352       byte * txtscn;
353       int i;
354 
355       for (i=0;i<20;i++)
356          printf("\n");
357       txtscn = (byte *) W_CacheLumpNum (W_GetNumForName ("rotts10"), PU_CACHE);
358       memcpy ((byte *)0xB8000, txtscn, 4000);
359       I_Delay (600);
360       }
361 #endif
362 #endif
363    locplayerstate = &PLAYERSTATE[consoleplayer];
364 
365    if (standalone==true)
366       ServerLoop();
367 
368    VL_SetVGAPlaneMode();
369    VL_SetPalette(origpal);
370 
371 //   SetTextMode();
372 //   GraphicsMode();
373 //   SetTextMode();
374 //   VL_SetVGAPlaneMode();
375 //   VL_SetPalette(origpal);
376 //   SetBorderColor(155);
377    SetViewSize(8);
378 
379    if ( SOUNDSETUP )
380       {
381       SwitchPalette( origpal, 35 );
382       CP_SoundSetup();
383       }
384 
385    playstate = ex_titles;
386 
387 //   I_SetKeyboardLEDs( caps_lock, 0 );
388 
389    gamestate.battlemode = battle_StandAloneGame;
390 
391    BATTLE_SetOptions( &BATTLE_Options[ battle_StandAloneGame ] );
392 
393    if (turbo || tedlevel)
394 		{
395       if (modemgame == true)
396          {
397          turbo = false;
398          NoWait = true;
399          }
400       else
401          {
402          PlayTurboGame();
403          }
404       }
405    else
406       {
407 #if (SHAREWARE == 0)
408       if ( dopefish == true )
409          {
410          DopefishTitle();
411          }
412       else if ( NoWait == false )
413          {
414          ApogeeTitle();
415          }
416 #else
417       if ( NoWait == false )
418          {
419          if (W_CheckNumForName("svendor") != -1)
420             {
421             lbm_t * LBM;
422 
423             LBM = (lbm_t *) W_CacheLumpName( "svendor", PU_CACHE, Cvt_lbm_t, 1);
424             VL_DecompressLBM (LBM,true);
425             I_Delay(40);
426             MenuFadeOut();
427             }
428 //         ParticleIntro ();
429          ApogeeTitle();
430          }
431 #endif
432       }
433 
434    GameLoop();
435 
436 
437    QuitGame();
438 
439    return 0;
440 }
441 
DrawRottTitle(void)442 void DrawRottTitle ( void )
443 {
444    char title[80];
445    char buf[5];
446 
447    SetTextMode();
448    TurnOffTextCursor ();
449 
450    if (CheckParm("QUIET") == 0)
451       {
452       SetTextMode();
453       TurnOffTextCursor ();
454       if (CheckParm ("SOUNDSETUP") == 0)
455          {
456 #ifdef ANSIESC
457          printf("\n\n\n");
458 #endif
459          strcpy (title,"Rise of the Triad Startup  Version ");
460          strcat (title,itoa(ROTTMAJORVERSION,&buf[0],10));
461          strcat (title,".");
462 //MED
463 #if (SHAREWARE==1)||(DOPEFISH==0)
464          strcat (title,itoa(ROTTMINORVERSION,&buf[0],10));
465 #else
466          strcat (title,"DFISH");
467 #endif
468 #ifndef ANSIESC
469          strcat (title,"\n");
470 #endif
471 
472          px=(80-strlen(title))>>1;
473          py=0;
474 
475          UL_printf(title);
476 
477          memset (title,0,sizeof(title));
478 
479          if (gamestate.Product == ROTT_SHAREWARE)
480             {
481 #if (DELUXE==1)
482             strcpy(title,"Lasersoft Deluxe Version");
483 #elif (LOWCOST==1)
484             strcpy(title,"Episode One");
485 #else
486             strcpy(title,"Shareware Version");
487 #endif
488             }
489          else if (gamestate.Product == ROTT_SUPERCD)
490              strcpy(title,"CD Version");
491          else if (gamestate.Product == ROTT_SITELICENSE)
492              strcpy(title,"Site License CD Version");
493          else
494              strcpy(title,"Commercial Version");
495 
496          px=(80-strlen(title))>>1;
497          py=1;
498 
499          UL_printf(title);
500 #ifndef ANSIESC
501 	 printf ("\n");
502 #endif
503 
504          UL_ColorBox (0, 0, 80, 2, 0x1e);
505          }
506       else
507          {
508          printf("\n\n");
509          strcpy (title,"Rise of the Triad Sound Setup  Version ");
510          strcat (title,itoa(ROTTMAJORVERSION,&buf[0],10));
511          strcat (title,".");
512          strcat (title,itoa(ROTTMINORVERSION,&buf[0],10));
513 
514          px=(80-strlen(title))>>1;
515          py=0;
516 
517          UL_printf(title);
518 
519          UL_ColorBox (0, 0, 80, 1, 0x1e);
520          }
521       }
522    else
523       {
524       TurnOffTextCursor ();
525       }
526 
527 }
528 
CheckCommandLineParameters(void)529 void CheckCommandLineParameters( void )
530 {
531    char *PStrings[] = {"TEDLEVEL","NOWAIT","NOSOUND","NOW",
532                        "TRANSPORT","DOPEFISH","SCREENSHOTS",
533                        "MONO","MAPSTATS","TILESTATS","VER","net",
534                        "PAUSE","SOUNDSETUP","WARP","IS8250","ENABLEVR",
535                        "TIMELIMIT","MAXTIMELIMIT","NOECHO","DEMOEXIT","QUIET",NULL};
536    int i,n;
537 
538    infopause=false;
539    SOUNDSETUP = false;
540    tedlevel=false;
541    NoWait=false;
542    NoSound=false;
543    turbo=false;
544    warp=false;
545    dopefish=false;
546    modemgame=false;
547    SCREENSHOTS=false;
548    MONOPRESENT=false;
549    MAPSTATS=false;
550    TILESTATS=false;
551    IS8250 = false;
552    vrenabled = false;
553    demoexit = false;
554 
555    modemgame=false;
556    networkgame=false;
557 	consoleplayer=0;
558 	numplayers = 1;
559    timelimit=-1;
560    timelimitenabled=false;
561    noecho = false;
562    quiet = false;
563 
564    if (
565         (CheckParm("?\0")) ||
566         (CheckParm("HELP")) ||
567         (
568          (_argc>1) &&
569          (_argv[1][0]=='?')
570         )
571       )
572       {
573       SetTextMode ();
574       printf ("Rise of the Triad  (c) 1995 Apogee Software\n\n");
575       printf ("COMMAND LINE PARAMETERS\n");
576       printf ("   SPACEBALL  - Enable check for Spaceball.\n");
577       printf ("   NOJOYS     - Disable check for joystick.\n");
578       printf ("   NOMOUSE    - Disable check for mouse.\n");
579       printf ("   CYBERMAN   - Enable check for Cyberman.\n");
580       printf ("   ASSASSIN   - Enable check for Wingman Assassin.\n");
581       printf ("   VER        - Version number.\n");
582       printf ("   MAPSTATS   - Dump Map statistics to ERROR.\n");
583       printf ("   TILESTATS  - Dump Tile statistics to ERROR.\n");
584       printf ("   MONO       - Enable mono-monitor support.\n");
585       printf ("   SCREENSHOTS- Clean screen capture for shots.\n");
586       printf ("   PAUSE      - Pauses startup screen information.\n");
587       printf ("   SOUNDSETUP - Setup sound for ROTT\n");
588       printf ("   ENABLEVR   - Enable VR helmet input devices\n");
589       printf ("   NOECHO     - Turn off sound reverb\n");
590       printf ("   DEMOEXIT   - Exit program when demo is terminated\n");
591       printf ("   WARP       - Warp to specific ROTT level\n");
592       printf ("                next paramater is level to start on\n");
593       printf ("   TIMELIMIT  - Play ROTT in time limit mode\n");
594       printf ("                next paramater is time in seconds\n");
595       printf ("   MAXTIMELIMIT - Maximimum time to count down from\n");
596       printf ("                next paramater is time in seconds\n");
597       printf ("   DOPEFISH   - ?\n");
598       exit (0);
599       }
600 
601    // Check For command line parameters
602 
603    for (i = 1;i < _argc;i++)
604    {
605       n = US_CheckParm(_argv[i],PStrings);
606       switch(n)
607       {
608 #if (TEDLAUNCH==1)
609        case 0:
610          tedlevelnum = ParseNum(_argv[i + 1]);
611          tedlevel=true;
612          if (i+3>=_argc)
613             {
614             tedx=0;
615             tedy=0;
616             }
617          else
618             {
619             tedx=ParseNum(_argv[i + 2]);
620             tedy=ParseNum(_argv[i + 3]);
621             }
622          MenuFixup ();
623          break;
624 #endif
625        case 1:
626          NoWait = true;
627          break;
628 		 case 2:
629          NoSound = true;
630          break;
631        case 3:
632          turbo = true;
633          break;
634        case 4:
635          warp = true;
636          warpx=ParseNum(_argv[i + 1]);
637          warpy=ParseNum(_argv[i + 2]);
638          warpa=ParseNum(_argv[i + 3]);
639          break;
640        case 5:
641          dopefish=true;
642          break;
643        case 6:
644          SCREENSHOTS = true;
645          break;
646        case 7:
647          MONOPRESENT = true;
648          break;
649        case 8:
650          MAPSTATS = true;
651          break;
652        case 9:
653          TILESTATS = true;
654          break;
655        case 10:
656          SetTextMode ();
657          printf ("Rise of the Triad  (c) 1995 Apogee Software\n");
658 //MED
659          if (gamestate.Product == ROTT_SHAREWARE)
660             {
661 #if (DELUXE==1)
662             printf("Lasersoft Deluxe ");
663 #elif (LOWCOST==1)
664             printf("Episode One ");
665 #else
666             printf("Shareware ");
667 #endif
668             }
669          else if (gamestate.Product == ROTT_SUPERCD)
670             printf("CD ");
671          else if (gamestate.Product == ROTT_SITELICENSE)
672             printf("Site License ");
673          else
674             printf("Commercial ");
675          printf ("Version %d.%d\n", ROTTMAJORVERSION,ROTTMINORVERSION);
676          exit (0);
677          break;
678        case 11:
679          InitROTTNET();
680 		   numplayers = rottcom->numplayers;
681          if (numplayers>MAXPLAYERS)
682             Error("Too many players.\n");
683          if (!quiet)
684 	     printf("Playing %ld player ROTT\n",(long int)numplayers);
685          modemgame=true;
686          if (rottcom->gametype==NETWORK_GAME)
687             {
688             if (!quiet)
689                printf("NETWORK GAME\n");
690             networkgame=true;
691             }
692          else
693             {
694             if (!quiet)
695                printf("MODEM GAME\n");
696             }
697          break;
698        case 12:
699          infopause=true;
700          break;
701        case 13:
702           SOUNDSETUP = true;
703           break;
704        case 14:
705           startlevel = (ParseNum(_argv[i + 1])-1);
706           break;
707        case 15:
708           IS8250 = true;
709           break;
710        case 16:
711           vrenabled = true;
712           if (!quiet)
713              printf("Virtual Reality Mode enabled\n");
714           break;
715        case 17:
716           timelimitenabled = true;
717           timelimit = ParseNum(_argv[i + 1]);
718           if (!quiet)
719              printf("Time Limit = %ld Seconds\n",(long int)timelimit);
720           timelimit *= VBLCOUNTER;
721           break;
722 
723        case 18:
724           maxtimelimit = ParseNum(_argv[i + 1]);
725           maxtimelimit *= VBLCOUNTER;
726           break;
727        case 19:
728           noecho = true;
729           break;
730        case 20:
731           demoexit = true;
732           break;
733        case 21:
734           quiet = true;
735           break;
736       }
737    }
738 }
739 
SetupWads(void)740 void SetupWads( void )
741 {
742    char  *newargs[99];
743 	int argnum = 0;
744 #if (SHAREWARE==0)
745    int arg;
746 #endif
747    char tempstr[129];
748 
749 #if (SHAREWARE==0)
750 
751    // Check for User wads
752 
753    arg = CheckParm ("file");
754    if (arg!=0)
755       {
756       newargs [argnum++] = _argv[arg+1];
757       }
758 
759    arg = CheckParm ("file1");
760    if (arg!=0)
761       {
762       newargs [argnum++] = _argv[arg+1];
763       }
764 
765    arg = CheckParm ("file2");
766    if (arg!=0)
767       {
768       newargs [argnum++] = _argv[arg+1];
769       }
770 
771 #else
772    if (
773        (CheckParm ("file") > 0) ||
774        (CheckParm ("file1") > 0) ||
775        (CheckParm ("file2") > 0)
776       )
777       printf("External wads ignored.\n");
778 
779 #endif
780 
781    // Normal ROTT wads
782 
783 if (isSHAREWARE)
784    newargs [argnum++] = "huntbgin.wad";
785 else
786    newargs [argnum++] = "darkwar.wad";
787 
788 //   newargs [argnum++] = "credits.wad";
789 
790    // Check for Remote Ridicule WAD
791 
792    if (RemoteSounds.avail == true)
793       {
794       char  *src;
795 
796       strcpy (tempstr,RemoteSounds.path);
797       src = RemoteSounds.path + strlen(RemoteSounds.path) - 1;
798       if (*src != '\\')
799          strcat (tempstr,"\\\0");
800       strcat (tempstr,RemoteSounds.file);
801       newargs [argnum++] = tempstr;
802       }
803    else
804       {
805       newargs [argnum++] = "remote1.rts";
806       }
807 
808    newargs [argnum++] = NULL;
809 
810    W_InitMultipleFiles(newargs);
811 }
812 
PlayTurboGame(void)813 void PlayTurboGame
814    (
815    void
816    )
817 
818    {
819    NewGame = true;
820    locplayerstate->player = DefaultPlayerCharacter;
821    playstate = ex_resetgame;
822    GameLoop();
823    }
824 
825 
826 //***************************************************************************
827 //
828 // Init_Tables () - Init tables needed for double buffering
829 //
830 //***************************************************************************
831 
Init_Tables(void)832 void Init_Tables (void)
833 {
834 	int i;
835 	int x,
836 		 y;
837 	unsigned *blockstart;
838 	byte * shape;
839 
840    memset (&CWD[0], 0, 40);
841    getcwd (CWD, 40);                      // get the current directory
842 
843    origpal=SafeMalloc(768);
844    memcpy (origpal, W_CacheLumpName("pal",PU_CACHE, CvtNull, 1), 768);
845 
846    FindEGAColors();
847 
848 	for (i=0;i<PORTTILESHIGH;i++)
849 		uwidthtable[i] = UPDATEWIDE*i;
850 
851 	updateptr = &update[0];
852 
853 	blockstart = &blockstarts[0];
854 	for (y=0;y<UPDATEHIGH;y++)
855 		for (x=0;x<UPDATEWIDE;x++)
856 			*blockstart++ = SCREENWIDTH*16*y+x*TILEWIDTH;
857 
858 	for (i = 0; i < 0x300; i++)
859 		*(origpal+(unsigned int)i) = (*(origpal+(unsigned int)i))>>2;
860 
861 	// Cache in fonts
862 	shape = W_CacheLumpNum (W_GetNumForName ("smallfont"), PU_STATIC, Cvt_font_t, 1);
863 	smallfont = (font_t *)shape;
864 	CurrentFont = smallfont;
865 
866 	// Cache in tiny font
867 	shape = W_CacheLumpNum (W_GetNumForName ("tinyfont"), PU_STATIC, Cvt_font_t, 1);
868 	tinyfont = (font_t *)shape;
869 
870    intensitytable=W_CacheLumpNum(W_GetNumForName("menucmap"),PU_STATIC, CvtNull, 1);
871    fontcolor = egacolor[4];
872 
873    if (!quiet)
874       printf("RT_MAIN: Fonts Initialized\n");
875 }
876 
877 
878 
879 
NumberOfTeams(void)880 int NumberOfTeams
881    (
882    void
883    )
884 
885    {
886    int index;
887    int team[ MAXPLAYERCOLORS ];
888    int count;
889    int color;
890 
891    memset( team, 0, sizeof( team ) );
892 
893    count = 0;
894    for( index = 0; index < numplayers; index++ )
895       {
896       color = PLAYERSTATE[ index ].uniformcolor;
897       if ( !team[ color ] )
898          {
899          team[ color ] = true;
900          count++;
901          }
902       }
903 
904    return( count );
905    }
906 
GameLoop(void)907 void GameLoop (void)
908 {
909    boolean done   = false;
910    boolean loadit = false;
911    int NextLevel;
912 
913    wami(1);
914 
915 	while (1)
916 	   {
917       if ( playstate == ex_battledone )
918          {
919          while( damagecount > 0 )
920             {
921             DoBorderShifts();
922             }
923          damagecount = 0;
924          SetBorderColor (0);
925 
926          StopWind();
927 
928          ShutdownClientControls();
929 
930          SD_Play (SD_LEVELDONESND);
931 
932          if ( ( player->flags & FL_DOGMODE ) ||
933             ( gamestate.battlemode == battle_Eluder ) )
934             MU_StartSong(song_dogend);
935          else
936             MU_StartSong(song_endlevel);
937 
938 
939          VL_FillPalette(255,255,255);
940          VL_FadeIn(0,255,origpal,10);
941 
942          BattleLevelCompleted( consoleplayer );
943 
944          BATTLE_Shutdown();
945 
946          Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
947 
948          ingame = false;
949 
950          if ( networkgame == true )
951             {
952             AddGameEndCommand ();
953             }
954 
955          AdjustMenuStruct ();
956 
957          CalcTics();
958          CalcTics();
959 
960          playstate = ex_titles;
961          }
962 
963 		switch (playstate)
964 		   {
965          case ex_titles:
966             BATTLE_Shutdown();
967             MU_StartSong(song_title);
968             if ((NoWait==false)&&(!modemgame))
969                {
970                byte dimpal[768];
971                int i;
972 
973                for (i = 0; i < 0x300; i++)
974                   dimpal[i] = origpal[i]>>2;
975                CalcTics();
976                CalcTics();
977                IN_ClearKeysDown ();
978                while (IN_GetMouseButtons()) {}
979                while ((!LastScan) && (!IN_GetMouseButtons()))
980                   {
981                   int i;
982                   unsigned tempbuf;
983                   MenuFadeOut();
984                   ClearGraphicsScreen();
985                   SetPalette(&dimpal[0]);
986                   PlayMovie ("shartitl", true);
987                   if ( ( LastScan ) || ( IN_GetMouseButtons() ) )
988                      {
989                      break;
990                      }
991 
992                   PlayMovie ("shartit2", true);
993 
994                   if ( ( LastScan ) || ( IN_GetMouseButtons() ) )
995                      {
996                      break;
997                      }
998                   SD_Play (SD_LIGHTNINGSND);
999                   MenuFadeIn();
1000                   I_Delay(30);
1001                   SD_Play (SD_ACTORSQUISHSND);
1002                   tempbuf=bufferofs;
1003                   bufferofs=displayofs;
1004                   DrawNormalSprite(320-94,200-41,W_GetNumForName("rsac"));
1005                   bufferofs=tempbuf;
1006                   I_Delay(30);
1007 
1008                   if ( ( LastScan ) || ( IN_GetMouseButtons() ) )
1009                      {
1010                      break;
1011                      }
1012 
1013                   DoCreditScreen ();
1014                   if ((!LastScan) && (!IN_GetMouseButtons()))
1015                      CheckHighScore (0, 0, false);
1016 #if (SHAREWARE==0)
1017                   if ((!LastScan) && (!IN_GetMouseButtons()))
1018                      {
1019                      DoMicroStoryScreen ();
1020                      }
1021 #endif
1022                   if (
1023                       (!LastScan) &&
1024                       (!IN_GetMouseButtons()) &&
1025                       (lowmemory==0) &&
1026                       (GameLevels.avail==false)
1027                      )
1028                      {
1029                      if (demonumber==-1)
1030                         demonumber=RandomNumber("GameLoop",0);
1031                      for (i=0;i<4;i++)
1032                         {
1033                         demonumber=(demonumber+1)%4;
1034                         if (DemoExists (demonumber+1) == true)
1035                            break;
1036                         }
1037                      if (DemoExists (demonumber+1) == true)
1038                         {
1039                         ingame=true;
1040                         LoadDemo (demonumber+1);
1041                         break;
1042                         }
1043                      }
1044                   }
1045                }
1046 
1047             if (playstate != ex_demoplayback)
1048                {
1049                if (demoexit == true)
1050                   {
1051                   QuitGame();
1052                   }
1053                NoWait = false;
1054                SwitchPalette(origpal,35);
1055                CP_MainMenu();
1056                }
1057          break;
1058 
1059          case ex_resetgame:
1060             InitCharacter();
1061 
1062             InitializeMessages();
1063 
1064             fizzlein = true;
1065             BATTLE_GetSpecials();
1066             BATTLE_SetOptions( &BATTLE_Options[ gamestate.battlemode ] );
1067 
1068             if ( modemgame == true )
1069                {
1070                fizzlein = false;
1071 
1072                if ( consoleplayer == 0 )
1073                   {
1074                   // Setup Master
1075                   SetupGameMaster();
1076                   }
1077                else
1078                   {
1079                   // Setup slave
1080                   SetupGamePlayer();
1081                   }
1082 
1083                if ( gamestate.Version < ROTTVERSION )
1084                   {
1085                   Error( "This version of Rise of the Triad (%d.%d) is incompatible with\n"
1086                      "version %d.%d.", ROTTMAJORVERSION, ROTTMINORVERSION,
1087                      gamestate.Version / 10, gamestate.Version % 10 );
1088                   }
1089                if ( gamestate.teamplay )
1090                   {
1091                   int teams;
1092 
1093                   teams = NumberOfTeams();
1094                   if ( gamestate.battlemode == battle_CaptureTheTriad )
1095                      {
1096                      if ( teams != 2 )
1097                         {
1098                         CP_CaptureTheTriadError();
1099                         playstate = ex_titles;
1100                         continue;
1101                         }
1102                      }
1103                   else if ( teams < 2 )
1104                      {
1105                      CP_TeamPlayErrorMessage();
1106                      playstate = ex_titles;
1107                      continue;
1108                      }
1109                   }
1110                }
1111 
1112             InitCharacter();
1113 
1114             BATTLE_Init( gamestate.battlemode, numplayers );
1115 
1116             NewGame = true;
1117 
1118             if ( ( BATTLEMODE ) && ( BATTLE_ShowKillCount ) )
1119                {
1120                StatusBar |= STATUS_KILLS;
1121                }
1122             else
1123                {
1124                StatusBar &= ~STATUS_KILLS;
1125                }
1126 
1127             if (loadedgame == false)
1128                {
1129                if ( !BATTLEMODE )
1130                   {
1131                   PlayCinematic();
1132                   }
1133 
1134                SetupGameLevel();
1135                }
1136 
1137             IN_ClearKeyboardQueue();
1138 
1139 				SetupScreen (true);
1140 
1141             MenuFixup ();
1142             playstate=ex_stillplaying;
1143          break;
1144 
1145          case ex_stillplaying:
1146             InitializeMessages();
1147 
1148             SHAKETICS = 0xFFFF;
1149             if (modemgame==true)
1150                {
1151                ComSetTime();
1152                turbo = false;
1153                }
1154             else if (turbo==true)
1155                turbo=false;
1156             else
1157                newlevel=true;
1158             PlayLoop ();
1159          break;
1160 
1161          case ex_died:
1162             loadit = done = false;
1163 
1164             Died ();
1165             StopWind();
1166 
1167             while (damagecount>0)
1168                DoBorderShifts();
1169 
1170             damagecount = 0;
1171             SetBorderColor (0);
1172             if (demorecord)
1173                {
1174                FreeDemo ();
1175                }
1176             if (demoplayback)
1177                {
1178                FreeDemo ();
1179                playstate=ex_demodone;
1180                }
1181             else
1182                {
1183                ShutdownClientControls();
1184 
1185                Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
1186 
1187                if (CheckForQuickLoad()==false)
1188                   {
1189                   if (locplayerstate->lives < 0)
1190                      {
1191                      if (timelimitenabled == false)
1192                         {
1193                         CheckHighScore (gamestate.score, gamestate.mapon+1, false);
1194                         playstate = ex_titles;
1195                         AdjustMenuStruct ();
1196                         ingame = false;
1197                         locplayerstate->health     = MaxHitpointsForCharacter(locplayerstate);
1198                         gamestate.score            = 0;
1199                         locplayerstate->lives      = 3;
1200                         locplayerstate->weapon     = wp_pistol;
1201                         locplayerstate->triads     = 0;
1202                         UpdateLives (locplayerstate->lives);
1203                         UpdateScore (gamestate.score);
1204                         }
1205                      else
1206                         {
1207                         QuitGame();
1208                         }
1209                      }
1210                   else
1211                      {
1212                      fizzlein = true;
1213                      SetupGameLevel ();
1214                      UpdateTriads(player,0);
1215                      playstate = ex_stillplaying;
1216                      }
1217                   }
1218                }
1219             break;
1220 
1221          case ex_warped:
1222             StopWind();
1223             TurnShakeOff();
1224             SHAKETICS = 0xffff;
1225             gamestate.TimeCount = 0;
1226 	         gamestate.frame=0;
1227 
1228             Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
1229 
1230             fizzlein = true;
1231             SetupGameLevel ();
1232 
1233             playstate = ex_stillplaying;
1234          break;
1235 
1236          case ex_skiplevel:
1237          case ex_secretdone:
1238          case ex_secretlevel:
1239          case ex_completed:
1240          case ex_bossdied:
1241 
1242             ShutdownClientControls();
1243             TurnShakeOff();
1244             SHAKETICS = 0xffff;
1245             if (timelimitenabled == false)
1246                {
1247                gamestate.TimeCount = 0;
1248                gamestate.frame=0;
1249                }
1250             StopWind();
1251 #if (SHAREWARE==0)
1252             if ((playstate==ex_bossdied) && (gamestate.mapon!=30))
1253                {
1254                int shape;
1255                lbm_t * LBM;
1256                byte *s;
1257                patch_t *p;
1258                char str[50];
1259                int width, height;
1260 
1261                LBM = (lbm_t *) W_CacheLumpName( "deadboss", PU_CACHE, Cvt_lbm_t, 1);
1262                VL_DecompressLBM (LBM,false);
1263                MenuFadeOut();
1264                switch (gamestate.mapon)
1265                   {
1266                   case 6:
1267                      shape = W_GetNumForName("deadstev");
1268                      break;
1269                   case 14:
1270                      shape = W_GetNumForName("deadjoe");
1271                      break;
1272                   case 22:
1273                      shape = W_GetNumForName("deadrobo");
1274                      break;
1275                   case 33:
1276                      shape = W_GetNumForName("deadtom");
1277                      break;
1278 //                  default:
1279 //                     Error("Boss died on an illegal level\n");
1280 //                     break;
1281                   }
1282                s = W_CacheLumpNum (shape, PU_CACHE, Cvt_patch_t, 1);
1283                p = (patch_t *)s;
1284                DrawNormalSprite ((320-p->origsize)>>1, (230-(p->height-p->topoffset))>>1, shape);
1285                switch (gamestate.mapon)
1286                   {
1287                   case 6:
1288                      strcpy(&str[0],"\"General\" John Darian");
1289                      break;
1290                   case 14:
1291                      strcpy(&str[0],"Sebastian \"Doyle\" Krist");
1292                      break;
1293                   case 22:
1294                      strcpy(&str[0],"the NME");
1295                      break;
1296                   case 33:
1297                      strcpy(&str[0],"El Oscuro");
1298                      break;
1299 //                  default:
1300 //                     Error("Boss died on an illegal level\n");
1301 //                     break;
1302                   }
1303                CurrentFont=smallfont;
1304                US_MeasureStr (&width, &height, str);
1305                US_ClippedPrint ((320-width)>>1, 180, str);
1306                VW_UpdateScreen();
1307                MenuFadeIn();
1308 
1309                WaitKeyUp();
1310                LastScan = 0;
1311                while (!LastScan)
1312                   ;
1313                LastScan=0;
1314                }
1315 #endif
1316             LevelCompleted ( playstate );
1317 
1318             NextLevel = GetNextMap(player->tilex,player->tiley);
1319 
1320             demoplayback = false;
1321 
1322             Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
1323             if (NextLevel != -1 )
1324                {
1325                gamestate.mapon = NextLevel;
1326                PlayCinematic();
1327                fizzlein = true;
1328                SetupGameLevel ();
1329                playstate = ex_stillplaying;
1330                }
1331             else
1332                {
1333                playstate = ex_gameover;
1334                }
1335          break;
1336 
1337          case ex_demodone:
1338             ingame=false;
1339             ShutdownClientControls();
1340             TurnShakeOff();
1341             SHAKETICS = 0xffff;
1342             gamestate.TimeCount = 0;
1343 	         gamestate.frame=0;
1344 
1345             demoplayback = false;
1346 
1347             Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
1348             playstate=ex_titles;
1349          break;
1350 
1351          case ex_gameover:
1352             StopWind();
1353             DoEndCinematic();
1354             if (playstate==ex_gameover)
1355                {
1356                CheckHighScore (gamestate.score, gamestate.mapon+1, false);
1357 
1358                ingame = false;
1359                AdjustMenuStruct ();
1360                playstate = ex_titles;
1361                }
1362          break;
1363 
1364          case ex_demorecord:
1365             ShutdownClientControls();
1366             Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
1367 
1368             RecordDemo();
1369             SetupGameLevel ();
1370 
1371             fizzlein = true;
1372             playstate = ex_stillplaying;
1373          break;
1374 
1375          case ex_demoplayback:
1376             ShutdownClientControls();
1377             Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
1378 
1379             SetupDemo();
1380             SetupGameLevel ();
1381 
1382             fizzlein = true;
1383             playstate = ex_stillplaying;
1384          break;
1385 	 default:
1386 	     ;
1387          }
1388       }
1389    waminot();
1390    }
1391 
CheckForQuickLoad(void)1392 boolean CheckForQuickLoad
1393    (
1394    void
1395    )
1396 
1397    {
1398    if ( pickquick )
1399       {
1400       SetupMenuBuf();
1401 
1402       pickquick = CP_DisplayMsg( "\nQuick load saved game?\n", 12 );
1403       if ( pickquick )
1404          {
1405          AllocateSavedScreenPtr();
1406          CP_LoadGame( 1, 1 );
1407          FreeSavedScreenPtr();
1408          }
1409       else
1410          {
1411          // Erase the quick load message
1412          VL_FadeOut( 0, 255, 0, 0, 0, 20 );
1413          }
1414 
1415       ShutdownMenuBuf();
1416       }
1417 
1418    return( pickquick );
1419    }
1420 
1421 //===========================================================================
1422 
ShutDown(void)1423 void ShutDown ( void )
1424 {
1425    if ( ( standalone == false ) || ( SOUNDSETUP ) )
1426       {
1427       WriteConfig ();
1428       }
1429 
1430 //   if (
1431 //       (networkgame==false) &&
1432 //       (modemgame==true)
1433 //      )
1434 //      {
1435 //      ShutdownModemGame ();
1436 //      }
1437 
1438    ShutdownClientControls();
1439    I_ShutdownKeyboard();
1440 #ifdef DOS /* the UL_ErrorStartup() call is commented out... */
1441    UL_ErrorShutdown ();
1442 #endif
1443    ShutdownGameCommands();
1444    MU_Shutdown();
1445    I_ShutdownTimer();
1446    SD_Shutdown();
1447    IN_Shutdown ();
1448    ShutdownSoftError ();
1449    Z_ShutDown();
1450 //   _settextcursor (0x0607);
1451 }
1452 
1453 //===========================================================================
1454 
1455 #if (DEVELOPMENT == 1)
1456    extern int totallevelsize;
1457 #endif
1458 
QuitGame(void)1459 void QuitGame ( void )
1460 {
1461 #if (DEBUG == 1)
1462    char buf[5];
1463 #endif
1464 
1465 #if (DEVELOPMENT == 1)
1466    int temp;
1467 #else
1468    byte *txtscn;
1469 #endif
1470    int k;
1471 
1472    MU_FadeOut(200);
1473    while (MU_FadeActive())
1474       {
1475       int time=GetTicCount();
1476       while (GetTicCount()==time) {}
1477       }
1478 
1479    PrintMapStats();
1480    PrintTileStats();
1481    SetTextMode();
1482 
1483 #if (DEVELOPMENT == 1)
1484    printf("Clean Exit\n");
1485    if (gamestate.TimeCount)
1486       {
1487       temp=(gamestate.frame*VBLCOUNTER*100)/gamestate.TimeCount;
1488       printf("fps  = %2ld.%2ld\n",temp/100,temp%100);
1489       }
1490    printf("argc=%ld\n",_argc);
1491    for (k=0;k<_argc;k++) printf("%s\n",_argv[k]);
1492    switch( _heapchk() )
1493    {
1494    case _HEAPOK:
1495      printf( "OK - heap is good\n" );
1496      break;
1497    case _HEAPEMPTY:
1498      printf( "OK - heap is empty\n" );
1499      break;
1500    case _HEAPBADBEGIN:
1501      printf( "ERROR - heap is damaged\n" );
1502      break;
1503    case _HEAPBADNODE:
1504      printf( "ERROR - bad node in heap\n" );
1505      break;
1506    }
1507    printf("\nLight Characteristics\n");
1508    printf("---------------------\n");
1509    if (fog)
1510       printf("FOG is ON\n");
1511    else
1512       printf("FOG is OFF\n");
1513    printf("LIGHTLEVEL=%ld\n",GetLightLevelTile());
1514    printf("LIGHTRATE =%ld\n",GetLightRateTile());
1515    printf("\nCENTERY=%ld\n",centery);
1516 #else
1517    if ( !SOUNDSETUP )
1518       {
1519 #if (SHAREWARE==0)
1520       txtscn = (byte *) W_CacheLumpNum (W_GetNumForName ("regend"), PU_CACHE, CvtNull, 1);
1521 #else
1522       txtscn = (byte *) W_CacheLumpNum (W_GetNumForName ("shareend"), PU_CACHE, CvtNull, 1);
1523 #endif
1524 #if DOS
1525       for (k = 0; k < 23; k++)
1526          printf ("\n");
1527       memcpy ((byte *)0xB8000, txtscn, 4000);
1528 #elif defined (ANSIESC)
1529       DisplayTextSplash (txtscn, 25);
1530 #endif
1531 
1532 #if (DEBUG == 1)
1533       px = ERRORVERSIONCOL;
1534       py = ERRORVERSIONROW;
1535 #if (BETA == 1)
1536       UL_printf ("�");
1537 #else
1538       UL_printf (itoa(ROTTMAJORVERSION,&buf[0],10));
1539 #endif
1540       // Skip the dot
1541       px++;
1542 
1543       UL_printf (itoa(ROTTMINORVERSION,&buf[0],10));
1544 #endif
1545       }
1546 #endif
1547 
1548    if ( SOUNDSETUP )
1549       {
1550       printf( "\nSound setup complete.\n"
1551               "Type ROTT to run the game.\n" );
1552       }
1553    ShutDown();
1554 #ifdef DC
1555 	platform_exit(); // save ramdisk to vmu
1556 #endif
1557 
1558    exit(0);
1559 }
1560 
InitCharacter(void)1561 void InitCharacter
1562    (
1563    void
1564    )
1565 
1566    {
1567    locplayerstate->health = MaxHitpointsForCharacter( locplayerstate );
1568    if (timelimitenabled == true)
1569       {
1570       locplayerstate->lives  = 1;
1571       }
1572    else
1573       {
1574       locplayerstate->lives  = 3;
1575       }
1576 
1577    ClearTriads (locplayerstate);
1578    locplayerstate->playerheight = characters[ locplayerstate->player ].height;
1579 //   locplayerstate->stepwhich = 0;
1580 //   locplayerstate->steptime = 0;
1581 
1582    gamestate.score = 0;
1583 
1584    if ( gamestate.battlemode == battle_StandAloneGame )
1585       {
1586       gamestate.mapon = startlevel;
1587       gamestate.difficulty = DefaultDifficulty;
1588       }
1589    else
1590       {
1591       gamestate.difficulty = gd_hard;
1592       }
1593 
1594    gamestate.dipballs = 0;
1595    gamestate.TimeCount = 0;
1596 
1597 	godmode = 0;
1598    damagecount = 0;
1599 
1600    UpdateScore( gamestate.score );
1601    }
1602 
1603 
1604 
1605 
UpdateGameObjects(void)1606 void UpdateGameObjects ( void )
1607 {
1608 	int j;
1609 	volatile int atime;
1610 	objtype * ob,*temp;
1611    battle_status BattleStatus;
1612 
1613    wami(2);
1614 
1615    if (controlupdatestarted==0)
1616       {
1617       return;
1618       waminot();
1619       }
1620 
1621 	atime=GetFastTics();
1622 
1623    UpdateClientControls ();
1624 
1625    if (demoplayback == false)
1626        PollControls ();
1627 
1628    CalcTics ();
1629 
1630    UpdateClientControls ();
1631 
1632 
1633    while (oldpolltime<oldtime)
1634 	   {
1635       UpdateClientControls ();
1636 	   MoveDoors();
1637       ProcessElevators();
1638 	   MovePWalls();
1639       UpdateLightning ();
1640 	   TriggerStuff();
1641 		CheckCriticalStatics();
1642 		for(j=0;j<numclocks;j++)
1643 		   if (Clocks[j].time1 &&
1644 			   ((gamestate.TimeCount == Clocks[j].time1) ||
1645 			   (gamestate.TimeCount == Clocks[j].time2)))
1646 				TRIGGER[Clocks[j].linkindex]=1;
1647 		for (ob = firstactive; ob;)
1648 			{
1649 			 temp = ob->nextactive;
1650 			 DoActor (ob);
1651 #if (DEVELOPMENT == 1)
1652 			 if ((ob->x<=0) || (ob->y<=0))
1653 				Error("object xy below zero obj->x=%ld obj->y=%ld obj->obclass=%ld\n",ob->x,ob->y,ob->obclass);
1654 			 if ((ob->angle<0) || (ob->angle>=FINEANGLES))
1655 				Error("object angle below zero obj->angle=%ld obj->obclass=%ld\n",ob->angle,ob->obclass);
1656 #endif
1657 			 ob = temp;
1658 			}
1659 
1660       BattleStatus = BATTLE_CheckGameStatus( battle_refresh, 0 );
1661       if ( BattleStatus != battle_no_event )
1662          {
1663          switch( BattleStatus )
1664             {
1665             case battle_end_game :
1666             case battle_out_of_time :
1667                playstate = ex_battledone;
1668                break;
1669 
1670             case battle_end_round :
1671                SetWhoHaveWeapons();
1672                break;
1673 	    default:
1674 		;
1675             }
1676          if ( playstate == ex_battledone )
1677             {
1678             break;
1679             }
1680          }
1681 #if (SYNCCHECK == 1)
1682       CheckForSyncCheck();
1683 #endif
1684       if (timelimitenabled == true)
1685          {
1686          if (timelimit-gamestate.TimeCount>maxtimelimit)
1687             timelimit = maxtimelimit+gamestate.TimeCount;
1688          if (gamestate.TimeCount == timelimit)
1689             {
1690             locplayerstate->lives=-1;
1691             playstate=ex_died;
1692             }
1693          }
1694 
1695       gamestate.TimeCount ++;
1696 
1697       ResetCurrentCommand();
1698 
1699       oldpolltime++;
1700       if (GamePaused==true)
1701          break;
1702 		}
1703    actortime=GetFastTics()-atime;
1704 
1705    UpdateClientControls ();
1706 
1707    if (noecho == false)
1708       {
1709       if ( player->flags & FL_SHROOMS )
1710          {
1711          FX_SetReverb( 230 );
1712          }
1713       else if (sky == 0)
1714          {
1715          FX_SetReverb( min( numareatiles[ player->areanumber ] >> 1, 90 ) );
1716          }
1717       }
1718 
1719    waminot();
1720 
1721 }
1722 
1723 
PauseLoop(void)1724 void PauseLoop ( void )
1725 {
1726    StopWind();
1727 
1728    UpdateClientControls ();
1729 
1730    while (oldpolltime<oldtime)
1731 	   {
1732       CheckUnPause();
1733 #if (SYNCCHECK == 1)
1734       CheckForSyncCheck();
1735 #endif
1736       oldpolltime++;
1737       if (GamePaused==false)
1738          {
1739          break;
1740          }
1741 		}
1742 
1743    CalcTics ();
1744    if (demoplayback==false)
1745       PollControls ();
1746 
1747    if ((RefreshPause == true) &&
1748        (GamePaused == true) &&
1749        ((GetTicCount() - pausedstartedticcount) >= blanktime))
1750       {
1751       RefreshPause = false;
1752       StartupScreenSaver();
1753       }
1754 }
1755 
1756 
1757 
PlayLoop(void)1758 void PlayLoop
1759    (
1760    void
1761    )
1762 
1763    {
1764    volatile int atime;
1765 
1766    boolean canquit = true;
1767    int     quittime = 0;
1768 
1769    wami(3);
1770 
1771 
1772    if ( (loadedgame == false) && (timelimitenabled == false) )
1773       {
1774       gamestate.TimeCount = 0;
1775       gamestate.frame = 0;
1776       }
1777 
1778 fromloadedgame:
1779 
1780    GamePaused = false;
1781 
1782 	if ( loadedgame == false )
1783       {
1784     	DrawPlayScreen( true );
1785 		missobj = NULL;
1786 		}
1787 	else
1788 		{
1789 		loadedgame = false;
1790       DoLoadGameSequence();
1791 		}
1792 
1793    drawtime  = 0;
1794    actortime = 0;
1795 	tics      = 0;
1796 	SetFastTics(0);
1797 
1798    if ( fizzlein == false )
1799       {
1800       StartupClientControls();
1801       }
1802    else
1803       {
1804       ShutdownClientControls();
1805       }
1806 
1807    // set detail level
1808    doublestep = 2 - DetailLevel;
1809 
1810    ResetMessageTime();
1811    DeletePriorityMessage( MSG_SYSTEM );
1812 
1813    if ( ( gamestate.battlemode == battle_Normal ) &&
1814       ( numplayers == 1 ) )
1815       {
1816       AddMessage( "Comm-bat is for Modem and Network games.", MSG_GAME );
1817       AddMessage( "You will not be facing any", MSG_GAME );
1818       AddMessage( "opponents.  Have fun and explore.", MSG_GAME );
1819       }
1820 
1821 
1822 	while( playstate == ex_stillplaying )
1823       {
1824       UpdateClientControls();
1825 
1826       if ( GamePaused )
1827          {
1828          PauseLoop();
1829 
1830          atime = GetFastTics();
1831 
1832          if ( RefreshPause )
1833             {
1834             ThreeDRefresh();
1835             }
1836          else
1837             {
1838             UpdateScreenSaver();
1839             }
1840          }
1841       else
1842          {
1843          if (controlupdatestarted == 1)
1844             UpdateGameObjects();
1845 
1846          atime = GetFastTics();
1847 
1848          ThreeDRefresh();
1849          }
1850 
1851       SyncToServer();
1852 
1853 		drawtime = GetFastTics() - atime;
1854 
1855       // Don't allow player to quit if entering message
1856       canquit = !MSG.messageon;
1857 
1858       PollKeyboard();
1859 
1860       MISCVARS->madenoise = false;
1861 
1862       AnimateWalls();
1863 
1864       UpdateClientControls();
1865 
1866       #if (DEVELOPMENT == 1)
1867          Z_CheckHeap();
1868       #endif
1869 
1870       if ( AutoDetailOn == true )
1871          {
1872    		AdaptDetail();
1873          }
1874 
1875       UpdateClientControls();
1876 
1877       DoSprites();
1878       DoAnimatedMaskedWalls();
1879 
1880       UpdatePlayers();
1881 
1882       DrawTime( false );
1883 
1884       UpdateClientControls();
1885 
1886       if ( ( !BATTLEMODE ) && ( CP_CheckQuick( LastScan ) ) )
1887 			{
1888          boolean escaped=false;
1889 
1890          if (LastScan == sc_Escape)
1891             {
1892             MU_StoreSongPosition();
1893             MU_StartSong(song_menu);
1894             escaped = true;
1895             }
1896          TurnShakeOff();
1897          StopWind();
1898          SetBorderColor( 0 );
1899          ShutdownClientControls();
1900          if (demoplayback==true)
1901             {
1902             FreeDemo();
1903             playstate = ex_demodone;
1904             if (demoexit==true)
1905                {
1906                QuitGame();
1907                }
1908             return;
1909             }
1910 
1911          ControlPanel( LastScan );
1912 
1913          // set detail level
1914          doublestep = 2 - DetailLevel;
1915 
1916          inmenu = false;
1917 
1918          if ( playstate == ex_titles )
1919             {
1920             return;
1921             }
1922 
1923          if ( playstate == ex_stillplaying )
1924             {
1925             SetupScreen( false );
1926             }
1927 
1928          if ( loadedgame == true )
1929             {
1930             goto fromloadedgame;
1931             }
1932 
1933          if (
1934               ( playstate == ex_stillplaying ) &&
1935               ( ( fizzlein == false ) ||
1936                 ( GamePaused )
1937               )
1938             )
1939             {
1940             StartupClientControls();
1941             }
1942 
1943          if (
1944               (playstate == ex_stillplaying) &&
1945               (GamePaused == false) &&
1946               (escaped == true)
1947             )
1948             {
1949             MU_StartSong(song_level);
1950             MU_RestoreSongPosition();
1951             }
1952          }
1953 
1954       if ( BATTLEMODE )
1955          {
1956          if ( MSG.messageon == false )
1957             {
1958             CheckRemoteRidicule( LastScan );
1959             }
1960          if ( quitactive == false )
1961             {
1962             if ( ( LastScan == sc_Escape ) && ( canquit ) )
1963                {
1964                quitactive = true;
1965                quittime   = GetTicCount() + QUITTIMEINTERVAL;
1966 
1967                if ( (consoleplayer == 0) || (networkgame == false) )
1968                   {
1969                   AddMessage( "Do you want to end this game? "
1970                      "(\\FY\\O/\\FN\\O)", MSG_QUIT );
1971                   }
1972                else
1973                   {
1974                   AddMessage( "Do you want to exit to DOS? "
1975                      "(\\FY\\O/\\EN\\O)", MSG_QUIT );
1976                   }
1977                }
1978             }
1979          else
1980             {
1981             if ( GetTicCount() > quittime )
1982                {
1983                quitactive = false;
1984                }
1985             else if ( LastScan == sc_N )
1986                {
1987                DeletePriorityMessage( MSG_QUIT );
1988                quitactive = false;
1989                }
1990             else if ( LastScan == sc_Y )
1991                {
1992                DeletePriorityMessage( MSG_QUIT );
1993                if ( (consoleplayer == 0) || (networkgame==false) )
1994                   {
1995                   AddEndGameCommand();
1996                   }
1997                else
1998                   {
1999                   AddQuitCommand();
2000                   }
2001                }
2002             }
2003          }
2004       }
2005    waminot();
2006    }
2007 
2008 //******************************************************************************
2009 //
2010 // CheckRemoteRidicule ()
2011 //
2012 //******************************************************************************
2013 
CheckRemoteRidicule(int scancode)2014 void CheckRemoteRidicule ( int scancode )
2015 {
2016    int num=-1;
2017 
2018    wami(4);
2019    switch (scancode)
2020    {
2021       case sc_F1:
2022          num=0;
2023          break;
2024       case sc_F2:
2025          num=1;
2026          break;
2027       case sc_F3:
2028          num=2;
2029          break;
2030       case sc_F4:
2031          num=3;
2032          break;
2033       case sc_F5:
2034          if ( !Keyboard[ sc_RShift ] )
2035             {
2036             num=4;
2037             }
2038          break;
2039       case sc_F6:
2040          num=5;
2041          break;
2042       case sc_F7:
2043          if ( !Keyboard[ sc_RShift ] )
2044             {
2045             num=6;
2046             }
2047          break;
2048       case sc_F8:
2049          num=7;
2050          break;
2051       case sc_F9:
2052          num=8;
2053          break;
2054       case sc_F10:
2055          num=9;
2056          break;
2057    }
2058    if (num>=0)
2059       {
2060       AddRemoteRidiculeCommand ( consoleplayer, MSG_DIRECTED_TO_ALL, num );
2061       LastScan=0;
2062       }
2063    waminot();
2064 }
2065 
2066 //******************************************************************************
2067 //
2068 // DoBossKey ()
2069 //
2070 //******************************************************************************
2071 
DoBossKey(void)2072 void DoBossKey ( void )
2073 {
2074 #ifdef DOS
2075    union REGS regs;
2076    ShutdownClientControls();
2077 
2078    SetTextMode();
2079 
2080    // move cursor to the row 0 column 4
2081    regs.w.ax = 0x0200;
2082    regs.w.bx = 0;
2083    regs.w.dx = 0x0004;
2084    int386(0x10,&regs,&regs);
2085    px=0;
2086    py=0;
2087    UL_printf("C:\\>\n");
2088 
2089    LastScan = 0;
2090    IN_WaitForKey ();
2091    VL_SetVGAPlaneMode();
2092    VL_SetPalette(origpal);
2093    SetBorderColor(0);
2094    TurnShakeOff();
2095    SetupScreen(true);
2096    ThreeDRefresh();
2097 
2098    StartupClientControls();
2099 #else
2100 	STUB_FUNCTION;
2101 #endif
2102 }
2103 
2104 
2105 //******************************************************************************
2106 //
2107 // PollKeyboard ()
2108 //
2109 //******************************************************************************
2110 
PollKeyboard(void)2111 void PollKeyboard
2112    (
2113    void
2114    )
2115 
2116    {
2117    static char autopressed = false;
2118 
2119    wami(5);
2120 
2121    if (demoplayback==true)
2122       {
2123       IN_UpdateKeyboard();
2124       }
2125 
2126    if ( !BATTLEMODE )
2127       {
2128       CheckDebug ();
2129       if (
2130          ( Keyboard[ sc_CapsLock ] ) &&
2131          ( DebugOk )
2132          )
2133          {
2134          DebugKeys ();
2135          }
2136       }
2137 
2138    if ( locplayerstate->buttonstate[ bt_autorun ] )
2139       {
2140       if ( !autopressed )
2141          {
2142          autopressed = true;
2143          gamestate.autorun ^= 1;
2144          if ( gamestate.autorun == 0 )
2145             {
2146             AddMessage( "AutoRun is \\cOFF", MSG_SYSTEM );
2147             }
2148          else
2149             {
2150             AddMessage( "AutoRun is \\cON", MSG_SYSTEM );
2151             }
2152          }
2153       }
2154    else
2155       {
2156       autopressed = false;
2157       }
2158 
2159 #if 0
2160    if ( modemgame == false )
2161       {
2162       CheckDevelopmentKeys();
2163       }
2164 #endif
2165 
2166    if ( ( MSG.messageon == false ) && ( !quitactive ) )
2167       {
2168       if ( ( Keyboard[ buttonscan[ bt_message ] ] ) && ( BATTLEMODE ) )
2169          {
2170          // Send message to all
2171          MSG.messageon = true;
2172          MSG.directed  = false;
2173          MSG.inmenu    = false;
2174          MSG.remoteridicule = -1;
2175          MSG.towho     = MSG_DIRECTED_TO_ALL;
2176          MSG.textnum   = AddMessage( "_", MSG_MODEM );
2177          MSG.length    = 1;
2178          DeletePriorityMessage( MSG_MACRO );
2179          }
2180       else if ( ( Keyboard[ buttonscan[ bt_directmsg ] ] ) && ( BATTLEMODE ) )
2181          {
2182          // Send directed message
2183          MSG.messageon = true;
2184          MSG.directed  = true;
2185          MSG.inmenu    = false;
2186          MSG.remoteridicule = -1;
2187          MSG.towho     = 0;
2188          MSG.textnum   = AddMessage( "_", MSG_MODEM );
2189          MSG.length    = 1;
2190          DeletePriorityMessage( MSG_MACRO );
2191          }
2192       if ( buttonpoll[ bt_map ] )
2193          {
2194          if ( !BATTLEMODE )
2195             {
2196             // Automap
2197             StopWind();
2198             DoMap( player->tilex, player->tiley );
2199             }
2200          else
2201             {
2202             // Show kill counts
2203             if ( SHOW_KILLS() )
2204                {
2205                BATTLE_ShowKillCount = false;
2206                StatusBar &= ~STATUS_KILLS;
2207                }
2208             else
2209                {
2210                StatusBar |= STATUS_KILLS;
2211                BATTLE_ShowKillCount = true;
2212                }
2213 
2214             SetupScreen( true );
2215             }
2216          }
2217 
2218       // Shrink screen
2219       if ( Keyboard[ sc_Minus ] )
2220          {
2221          if ( viewsize > 0 )
2222             {
2223             viewsize--;
2224             SetupScreen( true );
2225             }
2226          }
2227 
2228       // Expand screen
2229       if ( Keyboard[ sc_Plus ] )
2230          {
2231          if ( viewsize < MAXVIEWSIZES - 1 )
2232             {
2233             viewsize++;
2234             SetupScreen( true );
2235             }
2236          }
2237 
2238       // Set detail
2239       if ( ( Keyboard[ sc_F5 ] ) && ( ( !BATTLEMODE ) ||
2240          ( Keyboard[ sc_RShift ] ) ) )
2241          {
2242          Keyboard[ sc_F5 ] = false;
2243          LastScan = 0;
2244          DetailLevel++;
2245          if ( DetailLevel > 2 )
2246             {
2247             DetailLevel = 0;
2248             }
2249 
2250          switch( DetailLevel )
2251             {
2252             case 0 :
2253                AddMessage( "Low detail", MSG_SYSTEM );
2254                break;
2255 
2256             case 1 :
2257                AddMessage( "Medium detail", MSG_SYSTEM );
2258                break;
2259 
2260             case 2 :
2261                AddMessage( "High detail", MSG_SYSTEM );
2262                break;
2263             }
2264          doublestep = 2 - DetailLevel;
2265          }
2266 
2267       // Turn messages on/off
2268 
2269       if ( ( Keyboard[ sc_F7 ] ) && ( ( !BATTLEMODE ) ||
2270          ( Keyboard[ sc_RShift ] ) ) )
2271          {
2272          Keyboard[ sc_F7 ] = false;
2273          LastScan = 0;
2274          MessagesEnabled = !MessagesEnabled;
2275          if ( !MessagesEnabled )
2276             {
2277             AddMessage( "Messages disabled.", MSG_MSGSYSTEM );
2278             }
2279          else
2280             {
2281             AddMessage( "Messages enabled.", MSG_MSGSYSTEM );
2282             }
2283          }
2284 
2285       if ( ( Keyboard[ sc_F6 ] ) && ( !BATTLEMODE ) )
2286          {
2287          Keyboard[ sc_F6 ] = false;
2288          if (Keyboard[sc_RShift])
2289             {
2290             ShutdownClientControls();
2291             UndoQuickSaveGame();
2292             StartupClientControls();
2293             }
2294          else if (quicksaveslot==-1)
2295             {
2296             ShutdownClientControls();
2297             LastScan=sc_F2;
2298             inmenu = true;
2299             ControlPanel( LastScan );
2300             StartupClientControls();
2301             }
2302          else
2303             {
2304             LastScan = 0;
2305             ShutdownClientControls();
2306             ThreeDRefresh();
2307             QuickSaveGame();
2308             StartupClientControls();
2309             }
2310          }
2311 
2312 //#if 0
2313       if ( ( Keyboard[ sc_F12 ] ) && ( !BATTLEMODE ) )
2314          {
2315          Keyboard[ sc_F12 ] = false;
2316          LastScan = 0;
2317          DoBossKey();
2318          }
2319 //#endif
2320 
2321       // Gamma correction
2322       if ( Keyboard[ sc_F11 ] )
2323          {
2324          char str[ 50 ] = "Gamma Correction Level ";
2325          char str2[ 10 ];
2326 
2327          gammaindex++;
2328          if ( gammaindex == NUMGAMMALEVELS )
2329             {
2330             gammaindex = 0;
2331             }
2332          VL_SetPalette( origpal );
2333          itoa( gammaindex, str2, 10 );
2334          strcat( str, str2 );
2335          AddMessage( str, MSG_SYSTEM );
2336 
2337          while( Keyboard[ sc_F11 ] )
2338             {
2339             IN_UpdateKeyboard();
2340             }
2341          }
2342     #if 0
2343       if ( Keyboard[ sc_M ] )
2344          {
2345          char str[ 50 ] = "Mouse Y-Rotation Input Scale ";
2346          char str2[ 10 ];
2347 
2348          if ( Keyboard[ sc_RShift ] )
2349             mouse_ry_input_scale += 50;
2350          else
2351             mouse_ry_input_scale -= 50;
2352 
2353          itoa(mouse_ry_input_scale,str2,10);
2354          strcat( str, str2 );
2355          AddMessage( str, MSG_SYSTEM );
2356 
2357          }
2358     #endif
2359       // Increase volume
2360       if ( Keyboard[ sc_CloseBracket ] )
2361          {
2362          if ( Keyboard[ sc_RShift ] )
2363             {
2364             char str[ 50 ] = "Music Volume Level ";
2365             char str2[ 10 ];
2366 
2367             if ( MUvolume < 255 )
2368                {
2369                MUvolume++;
2370                }
2371             MU_SetVolume( MUvolume );
2372 
2373             itoa( MUvolume, str2, 10 );
2374             strcat( str, str2 );
2375             AddMessage( str, MSG_SYSTEM );
2376             }
2377          else
2378             {
2379             char str[ 50 ] = "Sound FX Volume Level ";
2380             char str2[ 10 ];
2381 
2382             if ( FXvolume < 255 )
2383                {
2384                FXvolume++;
2385                }
2386             FX_SetVolume( FXvolume );
2387 
2388             itoa( FXvolume, str2, 10 );
2389             strcat( str, str2 );
2390             AddMessage( str, MSG_SYSTEM );
2391             }
2392          }
2393 
2394       // Decrease volume
2395       if ( Keyboard[ sc_OpenBracket ] )
2396          {
2397          if ( Keyboard[ sc_RShift ] )
2398             {
2399             char str[ 50 ] = "Music Volume Level ";
2400             char str2[ 10 ];
2401 
2402             if ( MUvolume > 0 )
2403                {
2404                MUvolume--;
2405                }
2406             MU_SetVolume( MUvolume );
2407 
2408             itoa( MUvolume, str2, 10 );
2409             strcat( str, str2 );
2410             AddMessage( str, MSG_SYSTEM );
2411             }
2412          else
2413             {
2414             char str[ 50 ] = "Sound FX Volume Level ";
2415             char str2[ 10 ];
2416 
2417             if ( FXvolume > 0 )
2418                {
2419                FXvolume--;
2420                }
2421             FX_SetVolume( FXvolume );
2422 
2423             itoa( FXvolume, str2, 10 );
2424             strcat( str, str2 );
2425             AddMessage( str, MSG_SYSTEM );
2426             }
2427          }
2428 
2429       #if SAVE_SCREEN
2430 #if (DEVELOPMENT == 1)
2431          if ( Keyboard[ sc_CapsLock ] && Keyboard[ sc_C ] )
2432             {
2433             SaveScreen( true );
2434             }
2435          else if ( Keyboard[ sc_CapsLock ] && Keyboard[ sc_X ] )
2436             {
2437             SaveScreen( false );
2438             }
2439 #endif
2440          else if ( Keyboard[ sc_Alt] && Keyboard[ sc_C ] )
2441             {
2442             SaveScreen( false );
2443             }
2444          else if ( Keyboard[ sc_Alt] && Keyboard[ sc_V ] )
2445             {
2446             SaveScreen( true );
2447             }
2448       #endif
2449       }
2450    waminot();
2451    }
2452 
2453 
2454 //******************************************************************************
2455 //
2456 // CheckDevelopmentKeys ()
2457 //
2458 //******************************************************************************
2459 #if 0
2460 void CheckDevelopmentKeys
2461    (
2462    void
2463    )
2464 
2465    {
2466    #if (DEBUG == 1)
2467    if ( Keyboard[ sc_CapsLock ] && Keyboard[ sc_T ] )
2468       {
2469       if ( warp == true )
2470          {
2471          player->x     = warpx;
2472          player->y     = warpy;
2473          player->angle = warpa;
2474          locplayerstate->anglefrac = warpa << ANGLEBITS;
2475          player->momentumx = 0;
2476          player->momentumy = 0;
2477          player->momentumz = 0;
2478          }
2479       return;
2480       }
2481    #endif
2482 
2483    // Lower wall height
2484    if ( Keyboard[ sc_5 ] )
2485       {
2486       if ( levelheight > 1 )
2487          {
2488          levelheight--;
2489          }
2490 
2491       while( Keyboard[ sc_5 ] )
2492          {
2493          IN_UpdateKeyboard ();
2494          }
2495 
2496       maxheight = ( levelheight << 6 ) - 32;
2497       nominalheight = maxheight - 32;
2498       }
2499 
2500    // Raise wall height
2501    if ( Keyboard[ sc_6 ] )
2502       {
2503       levelheight++;
2504 
2505       while( Keyboard[ sc_6 ] )
2506          {
2507          IN_UpdateKeyboard();
2508          }
2509 
2510       maxheight = ( levelheight << 6 ) - 32;
2511       nominalheight = maxheight - 32;
2512       }
2513 
2514    if ( Keyboard[ sc_8 ] )
2515       {
2516       char str[ 50 ] = "You are now player ";
2517       char str2[ 10 ];
2518 
2519       locplayerstate->player++;
2520       if ( locplayerstate->player == 5 )
2521          {
2522          locplayerstate->player = 0;
2523          }
2524 
2525       while( Keyboard[ sc_8 ] )
2526          {
2527          IN_UpdateKeyboard ();
2528          }
2529 
2530       itoa( locplayerstate->player, str2, 10 );
2531       strcat( str, str2 );
2532       AddMessage( str, MSG_SYSTEM );
2533       }
2534 
2535 #if 0
2536    // Cycle forward through wall textures
2537       if (Keyboard[sc_W] && (modemgame==false))
2538          {int i,j;
2539 
2540           for(i=0;i<128;i++)
2541             for(j=0;j<128;j++)
2542               {if (IsWall(i,j))
2543                  {if (tilemap[i][j] ==
2544                       (W_GetNumForName("WALLSTOP")-W_GetNumForName("WALLSTRT")-1))
2545                     tilemap[i][j] = 1;
2546                   else
2547                     tilemap[i][j] ++;
2548                  }
2549               }
2550           while(Keyboard[sc_W])
2551             IN_UpdateKeyboard ();
2552 
2553          }
2554 
2555 
2556 
2557       if (Keyboard[sc_Q] && (modemgame==false))
2558          {int i,j;
2559 
2560           for(i=0;i<128;i++)
2561             for(j=0;j<128;j++)
2562               {if (IsWall(i,j))
2563                  {if (tilemap[i][j] == 1)
2564                     tilemap[i][j] = 74;
2565                   else
2566                     tilemap[i][j] --;
2567                  }
2568               }
2569           while(Keyboard[sc_Q])
2570             IN_UpdateKeyboard ();
2571 
2572          }
2573 
2574 #endif
2575    // Step through cieling/skies
2576    if ( Keyboard[ sc_K ] )
2577        {
2578        if ( sky > 0 )
2579           {
2580           MAPSPOT( 1, 0, 0 )++;
2581           if ( MAPSPOT( 1, 0, 0 ) > 239 )
2582              {
2583              MAPSPOT( 1, 0, 0 ) = 234;
2584              }
2585           }
2586        else
2587           {
2588           MAPSPOT( 1, 0, 0 )++;
2589           if ( MAPSPOT( 1, 0, 0 ) > 198 + 15 )
2590              {
2591              MAPSPOT( 1, 0, 0 ) = 198;
2592              }
2593           }
2594 
2595        SetPlaneViewSize();
2596 
2597        while( Keyboard[ sc_K ] )
2598           {
2599           IN_UpdateKeyboard();
2600           }
2601        }
2602 
2603    // Step through floors
2604    if ( Keyboard[ sc_L ] )
2605       {
2606       MAPSPOT( 0, 0, 0 )++;
2607       if ( MAPSPOT( 0, 0, 0 ) > 180 + 15 )
2608          {
2609          MAPSPOT( 0, 0, 0 ) = 180;
2610          SetPlaneViewSize();
2611 
2612          while( Keyboard[ sc_L ] )
2613             {
2614             IN_UpdateKeyboard();
2615             }
2616          }
2617       }
2618 
2619    // Increase darkness level
2620    if ( Keyboard[ sc_M ] )
2621       {
2622       if ( darknesslevel < 7 )
2623          {
2624          darknesslevel++;
2625          }
2626 
2627       SetLightLevels( darknesslevel );
2628 
2629       while( Keyboard[ sc_M ] )
2630          {
2631          IN_UpdateKeyboard();
2632          }
2633       }
2634 
2635    // Decrease darkness level
2636    if ( Keyboard[ sc_N ] )
2637       {
2638       if ( darknesslevel > 0 )
2639          {
2640          darknesslevel--;
2641          }
2642 
2643       SetLightLevels( darknesslevel );
2644 
2645       while( Keyboard[ sc_N ] )
2646          {
2647          IN_UpdateKeyboard();
2648          }
2649       }
2650 
2651    // Increase light rate
2652    if ( Keyboard[ sc_B ] )
2653       {
2654       SetLightRate( GetLightRate() + 1 );
2655       myprintf( "normalshade = %ld\n", normalshade );
2656 
2657       while( Keyboard[ sc_B ] )
2658          {
2659          IN_UpdateKeyboard();
2660          }
2661       }
2662 
2663    // Decrease light rate
2664    if ( Keyboard[ sc_V ] )
2665       {
2666       SetLightRate( GetLightRate() - 1 );
2667       myprintf( "normalshade = %ld\n", normalshade );
2668 
2669       while( Keyboard[ sc_V ] )
2670          {
2671          IN_UpdateKeyboard();
2672          }
2673       }
2674 
2675    // Toggle light diminishing on/off
2676    if ( Keyboard[ sc_T ] )
2677       {
2678       fulllight ^= 1;
2679 
2680       while( Keyboard[ sc_T ] )
2681          {
2682          IN_UpdateKeyboard();
2683          }
2684       }
2685    }
2686 #endif
2687 
2688 
2689 #if SAVE_SCREEN
2690 
2691 
BigShort(short l)2692 short   BigShort (short l)
2693 {
2694    byte    b1,b2;
2695 
2696    b1 = l&255;
2697    b2 = (l>>8)&255;
2698 
2699    return (b1<<8) + b2;
2700 }
2701 
BigLong(long l)2702 long    BigLong (long l)
2703 {
2704    byte    b1,b2,b3,b4;
2705 
2706    b1 = l&255;
2707    b2 = (l>>8)&255;
2708    b3 = (l>>16)&255;
2709    b4 = (l>>24)&255;
2710 
2711    return ((long)b1<<24) + ((long)b2<<16) + ((long)b3<<8) + b4;
2712 }
2713 
2714 /*
2715 ==============
2716 =
2717 = WriteLBMfile
2718 =
2719 ==============
2720 */
2721 
WriteLBMfile(char * filename,byte * data,int width,int height)2722 void WriteLBMfile (char *filename, byte *data, int width, int height)
2723 {
2724    byte    *lbm, *lbmptr;
2725    long    *formlength, *bmhdlength, *cmaplength, *bodylength;
2726    long    length;
2727    bmhd_t  basebmhd;
2728    int     handle;
2729    int     i;
2730 
2731    lbm = lbmptr = (byte *) SafeMalloc (65000);
2732 
2733 //
2734 // start FORM
2735 //
2736    *lbmptr++ = 'F';
2737    *lbmptr++ = 'O';
2738    *lbmptr++ = 'R';
2739    *lbmptr++ = 'M';
2740 
2741    formlength = (long*)lbmptr;
2742    lbmptr+=4;                      // leave space for length
2743 
2744    *lbmptr++ = 'P';
2745    *lbmptr++ = 'B';
2746    *lbmptr++ = 'M';
2747    *lbmptr++ = ' ';
2748 
2749 //
2750 // write BMHD
2751 //
2752    *lbmptr++ = 'B';
2753    *lbmptr++ = 'M';
2754    *lbmptr++ = 'H';
2755    *lbmptr++ = 'D';
2756 
2757    bmhdlength = (long *)lbmptr;
2758    lbmptr+=4;                      // leave space for length
2759 
2760    memset (&basebmhd,0,sizeof(basebmhd));
2761    basebmhd.w = BigShort(width);
2762    basebmhd.h = BigShort(height);
2763    basebmhd.nPlanes = BigShort(8);
2764    basebmhd.xAspect = BigShort(5);
2765    basebmhd.yAspect = BigShort(6);
2766    basebmhd.pageWidth = BigShort(width);
2767    basebmhd.pageHeight = BigShort(height);
2768 
2769    memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
2770    lbmptr += sizeof(basebmhd);
2771 
2772    length = lbmptr-(byte *)bmhdlength-4;
2773    *bmhdlength = BigLong(length);
2774    if (length&1)
2775       *lbmptr++ = 0;          // pad chunk to even offset
2776 
2777 //
2778 // write CMAP
2779 //
2780    *lbmptr++ = 'C';
2781    *lbmptr++ = 'M';
2782    *lbmptr++ = 'A';
2783    *lbmptr++ = 'P';
2784 
2785    cmaplength = (long *)lbmptr;
2786    lbmptr+=4;                      // leave space for length
2787 
2788    for (i = 0; i < 0x300; i++)
2789       *lbmptr++ = (*(origpal+i))<<2;
2790 
2791 // memcpy (lbmptr,&origpal[0],768);
2792 // lbmptr += 768;
2793 
2794    length = lbmptr-(byte *)cmaplength-4;
2795    *cmaplength = BigLong(length);
2796    if (length&1)
2797       *lbmptr++ = 0;          // pad chunk to even offset
2798 
2799 //
2800 // write BODY
2801 //
2802    *lbmptr++ = 'B';
2803    *lbmptr++ = 'O';
2804    *lbmptr++ = 'D';
2805    *lbmptr++ = 'Y';
2806 
2807    bodylength = (long *)lbmptr;
2808    lbmptr+=4;                      // leave space for length
2809 
2810    memcpy (lbmptr,data,width*height);
2811    lbmptr += width*height;
2812 
2813    length = lbmptr-(byte *)bodylength-4;
2814    *bodylength = BigLong(length);
2815    if (length&1)
2816       *lbmptr++ = 0;          // pad chunk to even offset
2817 
2818 //
2819 // done
2820 //
2821    length = lbmptr-(byte *)formlength-4;
2822    *formlength = BigLong(length);
2823    if (length&1)
2824       *lbmptr++ = 0;          // pad chunk to even offset
2825 
2826 //
2827 // write output file
2828 //
2829    handle = SafeOpenWrite (filename);
2830 
2831    SafeWrite (handle, lbm, lbmptr-lbm);
2832 
2833    close (handle);
2834    SafeFree(lbm);
2835 }
2836 
2837 
2838 //****************************************************************************
2839 //
2840 // GetFileName ()
2841 //
2842 //****************************************************************************
2843 
GetFileName(boolean saveLBM)2844 void GetFileName (boolean saveLBM)
2845 {
2846 #ifdef DOS
2847    char num[4];
2848    int cnt = 0;
2849    struct find_t fblock;
2850 
2851    if (saveLBM)
2852       memcpy (savename, "ROTT0000.LBM\0", 13);
2853    else
2854       memcpy (savename, "ROTT0000.PCX\0", 13);
2855 
2856    if (_dos_findfirst (savename, 0, &fblock) != 0)
2857       return;
2858 
2859    do
2860    {
2861       cnt++;
2862       memset (&num[0], 0, 4);
2863       itoa (cnt, num, 10);
2864 
2865       if (cnt > 99)
2866       {
2867          savename[5] = num[0];
2868          savename[6] = num[1];
2869          savename[7] = num[2];
2870       }
2871       else
2872       if (cnt > 9)
2873       {
2874          savename[6] = num[0];
2875          savename[7] = num[1];
2876       }
2877       else
2878          savename[7] = num[0];
2879    }
2880    while (_dos_findfirst (savename, 0, &fblock) == 0);
2881 #else
2882 	int i;
2883 
2884 	for (i = 0; i < 9999; i++) {
2885 		char filename[128];
2886 
2887 		if (saveLBM) {
2888 	   		sprintf(savename, "rott%04d.lbm", i);
2889 	   	} else {
2890 	   		sprintf(savename, "rott%04d.pcx", i);
2891 	   	}
2892 
2893 		GetPathFromEnvironment( filename, ApogeePath, savename );
2894 
2895 		if (access(filename, F_OK) != 0) {
2896 			return;
2897 		}
2898 	}
2899 #endif
2900 }
2901 
2902 //****************************************************************************
2903 //
2904 // SaveScreen ()
2905 //
2906 //****************************************************************************
2907 
2908 boolean inhmenu;
2909 
2910 #if (BETA == 1)
2911 #define SSX (160-(46*2))
2912 #define SSY (17)
2913 #endif
SaveScreen(boolean saveLBM)2914 void SaveScreen (boolean saveLBM)
2915 {
2916    byte *buffer;
2917    byte * screen;
2918    boolean oldHUD;
2919    char filename[ 128 ];
2920 
2921 #if (BETA == 1)
2922    unsigned tmp;
2923    char buf[30];
2924    int i;
2925 #endif
2926 
2927 
2928    oldHUD=HUD;
2929    HUD=false;
2930    doublestep=0;
2931    if (inhmenu==false)
2932       screen = (byte *) bufferofs;
2933    else
2934       screen = (byte *) displayofs;
2935 
2936    if (inhmenu==false)
2937       ThreeDRefresh ();
2938    doublestep = 2 - DetailLevel;
2939 
2940    buffer = (byte *) SafeMalloc (65000);
2941 
2942 #if (BETA == 1)
2943    if (SCREENSHOTS == false)
2944    {
2945       if (screen!=(byte *)bufferofs)
2946          {
2947          tmp=bufferofs;
2948          bufferofs=displayofs;
2949          }
2950       CurrentFont=tinyfont;
2951 
2952       VGAMAPMASK(15);
2953       for (i=-1;i<6;i++)
2954          memset((byte *)bufferofs+(ylookup[i+SSY])+(SSX>>2),0,46);
2955       px=SSX;
2956       py=SSY;
2957       VW_DrawPropString(" Rise of the Triad (c) 1995 Apogee  Version ");
2958       VW_DrawPropString(itoa(ROTTMAJORVERSION,&buf[0],10));
2959       VW_DrawPropString(".");
2960       VW_DrawPropString(itoa(ROTTMINORVERSION,&buf[0],10));
2961       px=SSX+13;
2962       py=SSY+8;
2963       VW_DrawPropString(" Episode ");
2964       VW_DrawPropString(itoa(gamestate.episode,&buf[0],10));
2965       VW_DrawPropString(" Area ");
2966       VW_DrawPropString(itoa(GetLevel(gamestate.episode, gamestate.mapon),&buf[0],10));
2967 
2968       if (screen!=(byte *)bufferofs)
2969          bufferofs=tmp;
2970    }
2971 #endif
2972 
2973    VL_CopyPlanarPageToMemory(screen,buffer);
2974 
2975    GetFileName (saveLBM);
2976    GetPathFromEnvironment( filename, ApogeePath, savename );
2977 
2978    if (saveLBM)
2979    {
2980       WriteLBMfile (filename, buffer, 320, 200);
2981       while (Keyboard[sc_CapsLock] && Keyboard[sc_C])
2982            IN_UpdateKeyboard ();
2983    }
2984    else
2985    {
2986       WritePCX (filename, buffer);
2987       while (Keyboard[sc_CapsLock] && Keyboard[sc_X])
2988            IN_UpdateKeyboard ();
2989    }
2990 
2991    SafeFree(buffer);
2992    HUD=oldHUD;
2993 }
2994 
2995 //****************************************************************************
2996 //
2997 // WritePCX ()
2998 //
2999 //****************************************************************************
3000 
WritePCX(char * file,byte * source)3001 void WritePCX (char * file, byte * source)
3002 {
3003    PCX_HEADER pcxHDR;
3004    byte *tempbuffer;
3005    byte pal[0x300];
3006    int pcxhandle;
3007    int i, j, y;
3008    unsigned char c;
3009    unsigned char buffer1[GAP_SIZE];
3010 
3011    pcxhandle = SafeOpenWrite (file);
3012 
3013       /* --- init the header that we'll write.
3014        *    Note: since DPaint never reads & writes at the same time,
3015        *    it is okay to share the same read & write structure,
3016        *    unlike in CONVERT.EXE.
3017        */
3018 
3019    memset (&pcxHDR, sizeof(PCX_HEADER), 0);
3020 
3021    pcxHDR.manufacturer  = 10;
3022    pcxHDR.version       = 5;
3023    pcxHDR.encoding      = 1;
3024 
3025    pcxHDR.bitsperpixel  = 8;           //bpp;
3026    pcxHDR.xmin          = pcxHDR.ymin = 0;
3027    pcxHDR.xmax          = 319;         //bitmap->box.w - 1;
3028    pcxHDR.ymax          = 199;         //bitmap->box.h - 1;
3029    pcxHDR.hres          = 320;         //N_COLUMNS;
3030    pcxHDR.vres          = 200;         //N_LINES;
3031 
3032   // bytesperline doesn't take into account multiple planes.
3033   // Output in same format as bitmap (planar vs packed).
3034   //
3035    pcxHDR.bytesperline  = 320;         //bitmap->width;
3036 
3037    pcxHDR.nplanes       = 1;           //bitmap->planes;
3038    pcxHDR.reserved      = 0;
3039 
3040   // First 16 colors of our palette info.
3041    for (i = 0, j = 0; i < 16; ++i, j += 3) {
3042       pcxHDR.colormap[i][0] = (unsigned char)(origpal[j]);
3043       pcxHDR.colormap[i][1] = (unsigned char)(origpal[j]+2);
3044       pcxHDR.colormap[i][2] = (unsigned char)(origpal[j]+3);
3045    }
3046 
3047   //
3048   // Write the 128-byte header
3049   //
3050    SafeWrite(pcxhandle,&pcxHDR, sizeof (PCX_HEADER));
3051 
3052    memset (buffer1, GAP_SIZE, 0);
3053 
3054    SafeWrite (pcxhandle, &buffer1, GAP_SIZE);
3055 
3056    tempbuffer = (byte *) SafeMalloc (65000);
3057    bptr = tempbuffer;
3058    totalbytes = 0;
3059 
3060   //
3061   // Write to a bit-packed file.
3062   //
3063 	for (y = 0;  y < 200;  ++y) 		// for each line in band
3064 		if (PutBytes (((unsigned char *) (source+(y*320))),
3065 						  pcxHDR.bytesperline))
3066          Error ("Error writing PCX bit-packed line!\n");
3067 
3068    SafeWrite (pcxhandle, tempbuffer, totalbytes);
3069 
3070   //
3071   // Write out PCX palette
3072   //
3073    c = 0x0C;
3074 
3075    for (i = 0; i < 0x300; i++)
3076       pal[i] = (*(origpal+i))<<2;
3077 
3078    SafeWrite (pcxhandle, &c, 1);
3079    SafeWrite (pcxhandle, &pal[0], 768);
3080 
3081    close (pcxhandle);
3082    SafeFree (tempbuffer);
3083 }
3084 
3085 
3086 //****************************************************************************
3087 //
3088 // PutBytes ()
3089 //
3090 // Write bytes to a file, handling packing as it goes.
3091 // Returns :  0 == SUCCESS
3092 //            1 == FAIL.
3093 //
3094 //****************************************************************************
3095 
PutBytes(unsigned char * ptr,unsigned int bytes)3096 int PutBytes (unsigned char *ptr, unsigned int bytes)
3097 {
3098 	unsigned int startbyte, count;
3099 	char b;
3100 
3101 	while (bytes > 0) {
3102 	  // check for a repeating byte value
3103 		startbyte = *ptr;
3104 		*ptr++ = 0;
3105 		--bytes;
3106 		count = 1;
3107 		while (*ptr == startbyte && bytes > 0 && count < 63)
3108 		{
3109 			*ptr = 0;
3110 			++ptr;
3111 			--bytes;
3112 			++count;
3113 		}
3114 	  // If we can pack the sequence, or if we have to add a
3115 	  //	byte before it because the top 2 bits of the value
3116 	  //	are 1's, write a packed sequence of 2 bytes.
3117 	  //	Otherwise, just write the byte value.
3118 	  //
3119 		if (count > 1  ||  (startbyte & 0xc0) == 0xc0)
3120 		{
3121 			b = 0xc0 | count;
3122 
3123 			*bptr++ = b;
3124 			totalbytes++;
3125 		}
3126 		b = startbyte;
3127 
3128 		*bptr++ = b;
3129 		totalbytes++;
3130 	}
3131 	return (0);
3132 }
3133 
3134 
3135 #endif
3136 
3137 
3138 //****************************************************************************
3139 //
3140 // PlayCinematic () - Play intro cinematics
3141 //
3142 //****************************************************************************
3143 
PlayCinematic(void)3144 void PlayCinematic (void)
3145 {
3146 
3147    if ((tedlevel == true) || (turbo == true))
3148       return;
3149 
3150    switch (gamestate.mapon)
3151    {
3152 #if (SHAREWARE == 0)
3153       byte pal[768];
3154       case 0:        // Start of EPISODE 1
3155 
3156          MU_StartSong ( song_cinematic1 );
3157          VL_FadeOut (0, 255, 0, 0, 0, 20);
3158          VL_ClearBuffer (bufferofs, 0);
3159          DrawNormalSprite(0,30,W_GetNumForName("nicolas"));
3160          DrawNormalSprite(0,168,W_GetNumForName("oneyear"));
3161          FlipPage();
3162          memcpy(&pal[0],W_CacheLumpName("nicpal",PU_CACHE, CvtNull, 1),768);
3163          VL_NormalizePalette(&pal[0]);
3164          VL_FadeIn(0,255,pal,20);
3165          I_Delay (60);
3166          VL_FadeOut (0, 255, 0, 0, 0, 20);
3167          IN_UpdateKeyboard();
3168          if (LastScan!=0)
3169             {
3170             LastScan=0;
3171             return;
3172             }
3173          SD_PlayPitchedSound(SD_LIGHTNINGSND,255,-1500);
3174          DoInBetweenCinematic (20, W_GetNumForName("binoculr"), 80,
3175                                "The HUNT cases an\n"
3176                                "ancient monastery."
3177                               );
3178          IN_UpdateKeyboard();
3179          if (LastScan!=0)
3180             {
3181             LastScan=0;
3182             return;
3183             }
3184          SD_Play(SD_NMESEESND);
3185          DoInBetweenCinematic (20, W_GetNumForName("binosee"), 80,
3186                                "\"There they are,\" says\n"
3187                                "Cassatt. \"Let's get back\n"
3188                                "to the boat and inform HQ.\""
3189                               );
3190          IN_UpdateKeyboard();
3191          if (LastScan!=0)
3192             {
3193             LastScan=0;
3194             return;
3195             }
3196          SD_Play(SD_HIGHGUARD1SEESND);
3197          DoInBetweenCinematic (20, W_GetNumForName("boatgard"), 80,
3198                                "\"The intruders, on that hill!\""
3199                               );
3200          IN_UpdateKeyboard();
3201          if (LastScan!=0)
3202             {
3203             LastScan=0;
3204             return;
3205             }
3206          SD_Play(SD_EXPLODESND);
3207          DoInBetweenCinematic (20, W_GetNumForName("boatblow"), 80,
3208                                "\"There goes our ride home,\"\n"
3209                                "says Barrett.  \"Looks like\n"
3210                                "the only way out is in....\""
3211                               );
3212          IN_UpdateKeyboard();
3213          LastScan=0;
3214       break;
3215 
3216       case 8:        // Start of EPISODE 2
3217          MU_StartSong ( song_cinematic2 );
3218          DoInBetweenCinematic (0, W_GetNumForName("epi12"), 1200,
3219                                "The HUNT makes their way\n"
3220                                "into the main keep."
3221                               );
3222          IN_UpdateKeyboard();
3223          LastScan=0;
3224       break;
3225 
3226       case 16:       // Start of EPISODE 3
3227          MU_StartSong ( song_cinematic1 );
3228          DoInBetweenCinematic (20, W_GetNumForName("epi23"), 1200,
3229                                "The HUNT stands before a pair\n"
3230                                "of ominous wooden doors.\n"
3231                                "The sounds of machinery and\n"
3232                                "servomotors fill the air.\n"
3233                               );
3234          IN_UpdateKeyboard();
3235          LastScan=0;
3236       break;
3237 
3238       case 24:       // Start of EPISODE 4
3239          MU_StartSong ( song_cinematic2 );
3240          DoInBetweenCinematic (0, W_GetNumForName("epi34"), 1200,
3241                                "Stairs lead down beneath the\n"
3242                                "keep.  From behind the doors\n"
3243                                "come the moans of the undead."
3244                               );
3245          IN_UpdateKeyboard();
3246          LastScan=0;
3247       break;
3248 #endif
3249    }
3250 }
3251