2 //**************************************************************************
4 //** h2_main.c : Heretic 2 : Raven Software, Corp.
11 //**************************************************************************
13 // HEADER FILES ------------------------------------------------------------
27 #define W_CacheLumpName(a,b) W_GetNumForName(a)
28 #define V_DrawPatch(x,y,p) OGL_DrawPatch(x,y,p)
29 #define V_DrawRawScreen(a) OGL_DrawRawScreen(a)
33 // MACROS ------------------------------------------------------------------
35 #define CONFIG_FILE_NAME "hhexen.cfg"
36 #define MAXWADFILES 20
38 // TYPES -------------------------------------------------------------------
43 void (*func)(char **args, int tag);
48 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
50 void R_ExecuteSetViewSize(void);
51 void D_CheckNetGame(void);
52 void G_BuildTiccmd(ticcmd_t *cmd);
54 boolean F_Responder(event_t *ev);
55 void I_StartupKeyboard(void);
56 void I_StartupJoystick(void);
57 void I_ShutdownKeyboard(void);
58 void S_InitScript(void);
60 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
62 void H2_ProcessEvents(void);
63 void H2_DoAdvanceDemo(void);
64 void H2_AdvanceDemo(void);
65 void H2_StartTitle(void);
66 void H2_PageTicker(void);
68 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
70 static void DrawMessage(void);
71 static void PageDrawer(void);
72 static void HandleArgs(void);
73 static void CheckRecordFrom(void);
74 static void AddWADFile(char *file);
75 static void DrawAndBlit(void);
76 static void ExecOptionFILE(char **args, int tag);
77 static void ExecOptionSCRIPTS(char **args, int tag);
78 static void ExecOptionDEVMAPS(char **args, int tag);
79 static void ExecOptionSKILL(char **args, int tag);
80 static void ExecOptionPLAYDEMO(char **args, int tag);
81 static void ExecOptionMAXZONE(char **args, int tag);
82 static void CreateBasePath(void);
83 static void WarpCheck(void);
86 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
88 extern boolean automapactive;
89 extern boolean MenuActive;
90 extern boolean askforquit;
92 // PUBLIC DATA DEFINITIONS -------------------------------------------------
96 boolean DevMaps; // true = Map development mode
97 char *DevMapsDir = ""; // development maps directory
98 boolean shareware; // true if only episode 1 present
99 boolean nomonsters; // checkparm of -nomonsters
100 boolean respawnparm; // checkparm of -respawn
101 boolean randomclass; // checkparm of -randclass
102 boolean debugmode; // checkparm of -debug
103 boolean ravpic; // checkparm of -ravpic
104 boolean cdrom; // true if cd-rom mode active
105 boolean cmdfrag; // true if a CMD_FRAG packet should be sent out
106 boolean singletics; // debug flag to cancel adaptiveness
107 boolean artiskip; // whether shift-enter skips an artifact
108 int maxzone = 0x800000; // Maximum allocated for zone heap (8meg default)
115 event_t events[MAXEVENTS];
119 // PRIVATE DATA DEFINITIONS ------------------------------------------------
122 static int demosequence;
124 static char *pagename;
126 static char *wadfiles[MAXWADFILES] =
128 "/Novell/H2/source/hexen.wad"
131 static char *wadfiles[MAXWADFILES] =
138 static execOpt_t ExecOptions[] =
140 { "-file", ExecOptionFILE, 1, 0 },
141 { "-scripts", ExecOptionSCRIPTS, 1, 0 },
142 { "-devmaps", ExecOptionDEVMAPS, 1, 0 },
143 { "-skill", ExecOptionSKILL, 1, 0 },
144 { "-playdemo", ExecOptionPLAYDEMO, 1, 0 },
145 { "-timedemo", ExecOptionPLAYDEMO, 1, 0 },
146 { "-maxzone", ExecOptionMAXZONE, 1, 0 },
147 { NULL, NULL, 0, 0 } // Terminator
150 // CODE --------------------------------------------------------------------
152 //==========================================================================
156 //==========================================================================
157 void InitMapMusicInfo(void);
163 M_FindResponseFile();
164 setbuf(stdout, NULL);
167 startskill = sk_medium;
173 shareware = false; // Always false for Hexen
180 // Initialize subsystems
182 ST_Message("V_Init: allocate screens.\n");
185 // Load defaults before initing other systems
186 ST_Message("M_LoadDefaults: Load system defaults.\n");
187 M_LoadDefaults(CONFIG_FILE_NAME);
189 // HEXEN MODIFICATION:
190 // There is a realloc() in W_AddFile() that might fail if the zone
191 // heap has been previously allocated, so we need to initialize the
192 // WAD files BEFORE the zone memory initialization.
193 ST_Message("W_Init: Init WADfiles.\n");
194 W_InitMultipleFiles(wadfiles);
198 W_CheckForOldFiles();
202 ST_Message("Z_Init: Init zone memory allocation daemon.\n");
206 ST_Message("MN_Init: Init menu system.\n");
209 ST_Message("CT_Init: Init chat mode data.\n");
212 InitMapMusicInfo(); // Init music fields in mapinfo
215 ST_Message("S_InitScript\n");
219 ST_Message("SN_InitSequenceScript: Registering sound sequences.\n");
220 SN_InitSequenceScript();
221 ST_Message("I_Init: Setting up machine state.\n");
224 ST_Message("ST_Init: Init startup screen.\n");
227 S_StartSongName("orb", true);
229 // Show version message now, so it's visible during R_Init()
230 ST_Message("Executable: "VERSIONTEXT".\n");
232 ST_Message("R_Init: Init Hexen refresh daemon");
236 if (M_CheckParm("-net")) ST_NetProgress(); // Console player found
238 ST_Message("P_Init: Init Playloop state.\n");
241 // Check for command line warping. Follows P_Init() because the
242 // MAPINFO.TXT script must be already processed.
247 ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n",
248 WarpMap, P_GetMapName(startmap), startmap, startskill+1);
251 ST_Message("D_CheckNetGame: Checking network game status.\n");
254 ST_Message("SB_Init: Loading patches.\n");
259 p = M_CheckParm("-record");
260 if(p && p < myargc-1)
262 G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p+1]);
263 H2_GameLoop(); // Never returns
266 p = M_CheckParm("-playdemo");
267 if(p && p < myargc-1)
269 singledemo = true; // Quit after one demo
270 G_DeferedPlayDemo(myargv[p+1]);
271 H2_GameLoop(); // Never returns
274 p = M_CheckParm("-timedemo");
275 if(p && p < myargc-1)
277 G_TimeDemo(myargv[p+1]);
278 H2_GameLoop(); // Never returns
281 p = M_CheckParm("-loadgame");
282 if(p && p < myargc-1)
284 G_LoadGame(atoi(myargv[p+1]));
287 if(gameaction != ga_loadgame)
289 UpdateState |= I_FULLSCRN;
290 BorderNeedRefresh = true;
291 if(autostart || netgame)
294 G_InitNew(startskill, startepisode, startmap);
301 H2_GameLoop(); // Never returns
304 //==========================================================================
308 //==========================================================================
310 static void HandleArgs(void)
315 nomonsters = M_ParmExists("-nomonsters");
316 respawnparm = M_ParmExists("-respawn");
317 randomclass = M_ParmExists("-randclass");
318 ravpic = M_ParmExists("-ravpic");
319 artiskip = M_ParmExists("-artiskip");
320 debugmode = M_ParmExists("-debug");
321 deathmatch = M_ParmExists("-deathmatch");
322 cdrom = M_ParmExists("-cdrom");
323 cmdfrag = M_ParmExists("-cmdfrag");
325 // Process command line options
326 for(opt = ExecOptions; opt->name != NULL; opt++)
328 p = M_CheckParm(opt->name);
329 if(p && p < myargc-opt->requiredArgs)
331 opt->func(&myargv[p], opt->tag);
335 // Look for an external device driver
336 I_CheckExternDriver();
339 //==========================================================================
343 //==========================================================================
345 static void WarpCheck(void)
350 p = M_CheckParm("-warp");
351 if(p && p < myargc-1)
353 WarpMap = atoi(myargv[p+1]);
354 map = P_TranslateMap(WarpMap);
356 { // Couldn't find real map number
358 ST_Message("-WARP: Invalid map number.\n");
361 { // Found a valid startmap
369 startmap = P_TranslateMap(1);
377 //==========================================================================
381 //==========================================================================
383 static void ExecOptionSKILL(char **args, int tag)
385 startskill = args[1][0]-'1';
389 //==========================================================================
393 //==========================================================================
395 static void ExecOptionFILE(char **args, int tag)
399 p = M_CheckParm("-file");
400 while(++p != myargc && myargv[p][0] != '-')
402 AddWADFile(myargv[p]);
407 //==========================================================================
409 // ExecOptionPLAYDEMO
411 //==========================================================================
413 static void ExecOptionPLAYDEMO(char **args, int tag)
417 sprintf(file, "%s.lmp", args[1]);
419 ST_Message("Playing demo %s.lmp.\n", args[1]);
422 //==========================================================================
426 //==========================================================================
428 static void ExecOptionSCRIPTS(char **args, int tag)
430 sc_FileScripts = true;
431 sc_ScriptsDir = args[1];
434 //==========================================================================
438 //==========================================================================
440 static void ExecOptionDEVMAPS(char **args, int tag)
443 ST_Message("Map development mode enabled:\n");
444 ST_Message("[config ] = %s\n", args[1]);
445 SC_OpenFileCLib(args[1]);
446 SC_MustGetStringName("mapsdir");
448 ST_Message("[mapsdir ] = %s\n", sc_String);
449 DevMapsDir = malloc(strlen(sc_String)+1);
450 strcpy(DevMapsDir, sc_String);
451 SC_MustGetStringName("scriptsdir");
453 ST_Message("[scriptsdir] = %s\n", sc_String);
454 sc_FileScripts = true;
455 sc_ScriptsDir = malloc(strlen(sc_String)+1);
456 strcpy(sc_ScriptsDir, sc_String);
457 while(SC_GetString())
459 if(SC_Compare("file"))
462 AddWADFile(sc_String);
466 SC_ScriptError(NULL);
473 long superatol(char *s)
475 long int n=0, r=10, x, mul=1;
486 else if (x == 72 && r == 10)
490 if (r<2 || r>36) return -1;
495 if (x >= r) return -1;
503 static void ExecOptionMAXZONE(char **args, int tag)
507 size = superatol(args[1]);
508 if (size < MINIMUM_HEAP_SIZE) size = MINIMUM_HEAP_SIZE;
509 if (size > MAXIMUM_HEAP_SIZE) size = MAXIMUM_HEAP_SIZE;
513 //==========================================================================
517 //==========================================================================
519 void H2_GameLoop(void)
521 if(M_CheckParm("-debugfile"))
524 sprintf(filename, "debug%i.txt", consoleplayer);
525 debugfile = fopen(filename,"w");
530 // Frame syncronous IO operations
533 // Process one or more tics
538 G_BuildTiccmd(&netcmds[consoleplayer][maketic%BACKUPTICS]);
549 // Will run at least one tic
553 // Move positional sounds
554 S_UpdateSounds(players[displayplayer].mo);
560 //==========================================================================
564 // Send all the events of the given timestamp down the responder chain.
566 //==========================================================================
568 void H2_ProcessEvents(void)
572 for(; eventtail != eventhead; eventtail = (++eventtail)&(MAXEVENTS-1))
574 ev = &events[eventtail];
587 //==========================================================================
591 // Called by the I/O functions when input is detected.
593 //==========================================================================
595 void H2_PostEvent(event_t *ev)
597 events[eventhead] = *ev;
599 eventhead &= (MAXEVENTS-1);
602 //==========================================================================
606 //==========================================================================
608 static void DrawAndBlit(void)
610 // Change the view size if needed
613 R_ExecuteSetViewSize();
616 // Do buffered drawing
630 R_RenderPlayerView(&players[displayplayer]);
633 UpdateState |= I_FULLVIEW;
636 case GS_INTERMISSION:
647 if(paused && !MenuActive && !askforquit)
651 V_DrawPatch(160, viewwindowy+5, W_CacheLumpName("PAUSED",
656 V_DrawPatch(160, 70, W_CacheLumpName("PAUSED",
662 if( OGL_DrawFilter() )
663 BorderNeedRefresh = true;
666 // Draw current message
672 // Send out any new accumulation
675 // Flush buffered stuff to screen
679 //==========================================================================
683 //==========================================================================
685 static void DrawMessage(void)
689 player = &players[consoleplayer];
690 if(player->messageTics <= 0 || !player->message)
694 if(player->yellowMessage)
696 MN_DrTextAYellow(player->message,
697 160-MN_TextAWidth(player->message)/2, 1);
701 MN_DrTextA(player->message, 160-MN_TextAWidth(player->message)/2, 1);
705 //==========================================================================
709 //==========================================================================
711 void H2_PageTicker(void)
719 //==========================================================================
723 //==========================================================================
725 static void PageDrawer(void)
727 V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE));
728 if(demosequence == 1)
730 V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE));
732 UpdateState |= I_FULLSCRN;
735 //==========================================================================
739 // Called after each demo or intro demosequence finishes.
741 //==========================================================================
743 void H2_AdvanceDemo(void)
748 //==========================================================================
752 //==========================================================================
754 void H2_DoAdvanceDemo(void)
756 players[consoleplayer].playerstate = PST_LIVE; // don't reborn
758 usergame = false; // can't save/end game here
760 gameaction = ga_nothing;
761 demosequence = (demosequence+1)%7;
766 gamestate = GS_DEMOSCREEN;
768 S_StartSongName("hexen", true);
772 gamestate = GS_DEMOSCREEN;
776 BorderNeedRefresh = true;
777 UpdateState |= I_FULLSCRN;
778 G_DeferedPlayDemo("demo1");
782 gamestate = GS_DEMOSCREEN;
786 BorderNeedRefresh = true;
787 UpdateState |= I_FULLSCRN;
788 G_DeferedPlayDemo("demo2");
792 gamestate = GS_DEMOSCREEN;
796 BorderNeedRefresh = true;
797 UpdateState |= I_FULLSCRN;
798 G_DeferedPlayDemo("demo3");
803 //==========================================================================
807 //==========================================================================
809 void H2_StartTitle(void)
811 gameaction = ga_nothing;
816 //==========================================================================
820 // -recordfrom <savegame num> <demoname>
822 //==========================================================================
824 static void CheckRecordFrom(void)
828 p = M_CheckParm("-recordfrom");
829 if(!p || p > myargc-2)
833 G_LoadGame(atoi(myargv[p+1]));
834 G_DoLoadGame(); // Load the gameskill etc info from savegame
835 G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p+2]);
836 H2_GameLoop(); // Never returns
839 //==========================================================================
843 //==========================================================================
845 static void AddWADFile(char *file)
850 ST_Message("Adding external file: %s\n", file);
856 new = malloc(strlen(file)+1);
863 // Use these for non-i386 systems. Lifted from the Doom code.
865 fixed_t FixedMul (fixed_t a, fixed_t b)
867 return ((long long) a * (long long) b) >> 16;
870 fixed_t FixedDiv2 (fixed_t a, fixed_t b)
874 c = ((long long)a<<16) / ((long long)b);
880 c = ((double)a) / ((double)b) * FRACUNIT;
882 if (c >= 2147483648.0 || c < -2147483648.0)
883 I_Error("FixedDiv: divide by zero");
888 //==========================================================================
892 //==========================================================================
894 fixed_t FixedDiv(fixed_t a, fixed_t b)
896 if((abs(a)>>14) >= abs(b))
898 return((a^b)<0 ? MININT : MAXINT);
900 return(FixedDiv2(a, b));
904 //==========================================================================
908 //==========================================================================
910 static void CreateBasePath(void)
912 sprintf(base,"%s/.hhexen/",getenv("HOME"));
914 mkdir( base, S_IRWXU|S_IRWXG|S_IRWXO );