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] =
140 static execOpt_t ExecOptions[] =
142 { "-file", ExecOptionFILE, 1, 0 },
143 { "-scripts", ExecOptionSCRIPTS, 1, 0 },
144 { "-devmaps", ExecOptionDEVMAPS, 1, 0 },
145 { "-skill", ExecOptionSKILL, 1, 0 },
146 { "-playdemo", ExecOptionPLAYDEMO, 1, 0 },
147 { "-timedemo", ExecOptionPLAYDEMO, 1, 0 },
148 { "-maxzone", ExecOptionMAXZONE, 1, 0 },
149 { NULL, NULL, 0, 0 } // Terminator
152 // CODE --------------------------------------------------------------------
154 //==========================================================================
158 //==========================================================================
159 void InitMapMusicInfo(void);
165 M_FindResponseFile();
166 setbuf(stdout, NULL);
169 startskill = sk_medium;
175 shareware = false; // Always false for Hexen
182 // Initialize subsystems
184 ST_Message("V_Init: allocate screens.\n");
187 // Load defaults before initing other systems
188 ST_Message("M_LoadDefaults: Load system defaults.\n");
189 M_LoadDefaults(CONFIG_FILE_NAME);
191 // HEXEN MODIFICATION:
192 // There is a realloc() in W_AddFile() that might fail if the zone
193 // heap has been previously allocated, so we need to initialize the
194 // WAD files BEFORE the zone memory initialization.
195 ST_Message("W_Init: Init WADfiles.\n");
196 W_InitMultipleFiles(wadfiles);
200 W_CheckForOldFiles();
204 ST_Message("Z_Init: Init zone memory allocation daemon.\n");
208 ST_Message("MN_Init: Init menu system.\n");
211 ST_Message("CT_Init: Init chat mode data.\n");
214 InitMapMusicInfo(); // Init music fields in mapinfo
217 ST_Message("S_InitScript\n");
221 ST_Message("SN_InitSequenceScript: Registering sound sequences.\n");
222 SN_InitSequenceScript();
223 ST_Message("I_Init: Setting up machine state.\n");
226 ST_Message("ST_Init: Init startup screen.\n");
229 S_StartSongName("orb", true);
231 // Show version message now, so it's visible during R_Init()
232 ST_Message("Executable: "VERSIONTEXT".\n");
234 ST_Message("R_Init: Init Hexen refresh daemon");
238 if (M_CheckParm("-net")) ST_NetProgress(); // Console player found
240 ST_Message("P_Init: Init Playloop state.\n");
243 // Check for command line warping. Follows P_Init() because the
244 // MAPINFO.TXT script must be already processed.
249 ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n",
250 WarpMap, P_GetMapName(startmap), startmap, startskill+1);
253 ST_Message("D_CheckNetGame: Checking network game status.\n");
256 ST_Message("SB_Init: Loading patches.\n");
261 p = M_CheckParm("-record");
262 if(p && p < myargc-1)
264 G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p+1]);
265 H2_GameLoop(); // Never returns
268 p = M_CheckParm("-playdemo");
269 if(p && p < myargc-1)
271 singledemo = true; // Quit after one demo
272 G_DeferedPlayDemo(myargv[p+1]);
273 H2_GameLoop(); // Never returns
276 p = M_CheckParm("-timedemo");
277 if(p && p < myargc-1)
279 G_TimeDemo(myargv[p+1]);
280 H2_GameLoop(); // Never returns
283 p = M_CheckParm("-loadgame");
284 if(p && p < myargc-1)
286 G_LoadGame(atoi(myargv[p+1]));
289 if(gameaction != ga_loadgame)
291 UpdateState |= I_FULLSCRN;
292 BorderNeedRefresh = true;
293 if(autostart || netgame)
296 G_InitNew(startskill, startepisode, startmap);
303 H2_GameLoop(); // Never returns
306 //==========================================================================
310 //==========================================================================
312 static void HandleArgs(void)
317 nomonsters = M_ParmExists("-nomonsters");
318 respawnparm = M_ParmExists("-respawn");
319 randomclass = M_ParmExists("-randclass");
320 ravpic = M_ParmExists("-ravpic");
321 artiskip = M_ParmExists("-artiskip");
322 debugmode = M_ParmExists("-debug");
323 deathmatch = M_ParmExists("-deathmatch");
324 cdrom = M_ParmExists("-cdrom");
325 cmdfrag = M_ParmExists("-cmdfrag");
327 // Process command line options
328 for(opt = ExecOptions; opt->name != NULL; opt++)
330 p = M_CheckParm(opt->name);
331 if(p && p < myargc-opt->requiredArgs)
333 opt->func(&myargv[p], opt->tag);
337 // Look for an external device driver
338 I_CheckExternDriver();
341 //==========================================================================
345 //==========================================================================
347 static void WarpCheck(void)
352 p = M_CheckParm("-warp");
353 if(p && p < myargc-1)
355 WarpMap = atoi(myargv[p+1]);
356 map = P_TranslateMap(WarpMap);
358 { // Couldn't find real map number
360 ST_Message("-WARP: Invalid map number.\n");
363 { // Found a valid startmap
371 startmap = P_TranslateMap(1);
379 //==========================================================================
383 //==========================================================================
385 static void ExecOptionSKILL(char **args, int tag)
387 startskill = args[1][0]-'1';
391 //==========================================================================
395 //==========================================================================
397 static void ExecOptionFILE(char **args, int tag)
401 p = M_CheckParm("-file");
402 while(++p != myargc && myargv[p][0] != '-')
404 AddWADFile(myargv[p]);
409 //==========================================================================
411 // ExecOptionPLAYDEMO
413 //==========================================================================
415 static void ExecOptionPLAYDEMO(char **args, int tag)
419 sprintf(file, "%s.lmp", args[1]);
421 ST_Message("Playing demo %s.lmp.\n", args[1]);
424 //==========================================================================
428 //==========================================================================
430 static void ExecOptionSCRIPTS(char **args, int tag)
432 sc_FileScripts = true;
433 sc_ScriptsDir = args[1];
436 //==========================================================================
440 //==========================================================================
442 static void ExecOptionDEVMAPS(char **args, int tag)
445 ST_Message("Map development mode enabled:\n");
446 ST_Message("[config ] = %s\n", args[1]);
447 SC_OpenFileCLib(args[1]);
448 SC_MustGetStringName("mapsdir");
450 ST_Message("[mapsdir ] = %s\n", sc_String);
451 DevMapsDir = malloc(strlen(sc_String)+1);
452 strcpy(DevMapsDir, sc_String);
453 SC_MustGetStringName("scriptsdir");
455 ST_Message("[scriptsdir] = %s\n", sc_String);
456 sc_FileScripts = true;
457 sc_ScriptsDir = malloc(strlen(sc_String)+1);
458 strcpy(sc_ScriptsDir, sc_String);
459 while(SC_GetString())
461 if(SC_Compare("file"))
464 AddWADFile(sc_String);
468 SC_ScriptError(NULL);
475 long superatol(char *s)
477 long int n=0, r=10, x, mul=1;
488 else if (x == 72 && r == 10)
492 if (r<2 || r>36) return -1;
497 if (x >= r) return -1;
505 static void ExecOptionMAXZONE(char **args, int tag)
509 size = superatol(args[1]);
510 if (size < MINIMUM_HEAP_SIZE) size = MINIMUM_HEAP_SIZE;
511 if (size > MAXIMUM_HEAP_SIZE) size = MAXIMUM_HEAP_SIZE;
515 //==========================================================================
519 //==========================================================================
521 void H2_GameLoop(void)
523 if(M_CheckParm("-debugfile"))
526 sprintf(filename, "debug%i.txt", consoleplayer);
527 debugfile = fopen(filename,"w");
532 // Frame syncronous IO operations
535 // Process one or more tics
540 G_BuildTiccmd(&netcmds[consoleplayer][maketic%BACKUPTICS]);
551 // Will run at least one tic
555 // Move positional sounds
556 S_UpdateSounds(players[displayplayer].mo);
562 //==========================================================================
566 // Send all the events of the given timestamp down the responder chain.
568 //==========================================================================
570 void H2_ProcessEvents(void)
574 for(; eventtail != eventhead; eventtail = (++eventtail)&(MAXEVENTS-1))
576 ev = &events[eventtail];
589 //==========================================================================
593 // Called by the I/O functions when input is detected.
595 //==========================================================================
597 void H2_PostEvent(event_t *ev)
599 events[eventhead] = *ev;
601 eventhead &= (MAXEVENTS-1);
604 //==========================================================================
608 //==========================================================================
610 static void DrawAndBlit(void)
612 // Change the view size if needed
615 R_ExecuteSetViewSize();
618 // Do buffered drawing
632 R_RenderPlayerView(&players[displayplayer]);
635 UpdateState |= I_FULLVIEW;
638 case GS_INTERMISSION:
649 if(paused && !MenuActive && !askforquit)
653 V_DrawPatch(160, viewwindowy+5, W_CacheLumpName("PAUSED",
658 V_DrawPatch(160, 70, W_CacheLumpName("PAUSED",
664 if( OGL_DrawFilter() )
665 BorderNeedRefresh = true;
668 // Draw current message
674 // Send out any new accumulation
677 // Flush buffered stuff to screen
681 //==========================================================================
685 //==========================================================================
687 static void DrawMessage(void)
691 player = &players[consoleplayer];
692 if(player->messageTics <= 0 || !player->message)
696 if(player->yellowMessage)
698 MN_DrTextAYellow(player->message,
699 160-MN_TextAWidth(player->message)/2, 1);
703 MN_DrTextA(player->message, 160-MN_TextAWidth(player->message)/2, 1);
707 //==========================================================================
711 //==========================================================================
713 void H2_PageTicker(void)
721 //==========================================================================
725 //==========================================================================
727 static void PageDrawer(void)
729 V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE));
730 if(demosequence == 1)
732 V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE));
734 UpdateState |= I_FULLSCRN;
737 //==========================================================================
741 // Called after each demo or intro demosequence finishes.
743 //==========================================================================
745 void H2_AdvanceDemo(void)
750 //==========================================================================
754 //==========================================================================
756 void H2_DoAdvanceDemo(void)
758 players[consoleplayer].playerstate = PST_LIVE; // don't reborn
760 usergame = false; // can't save/end game here
762 gameaction = ga_nothing;
763 demosequence = (demosequence+1)%7;
768 gamestate = GS_DEMOSCREEN;
770 S_StartSongName("hexen", true);
774 gamestate = GS_DEMOSCREEN;
778 BorderNeedRefresh = true;
779 UpdateState |= I_FULLSCRN;
780 G_DeferedPlayDemo("demo1");
784 gamestate = GS_DEMOSCREEN;
788 BorderNeedRefresh = true;
789 UpdateState |= I_FULLSCRN;
790 G_DeferedPlayDemo("demo2");
794 gamestate = GS_DEMOSCREEN;
798 BorderNeedRefresh = true;
799 UpdateState |= I_FULLSCRN;
800 G_DeferedPlayDemo("demo3");
805 //==========================================================================
809 //==========================================================================
811 void H2_StartTitle(void)
813 gameaction = ga_nothing;
818 //==========================================================================
822 // -recordfrom <savegame num> <demoname>
824 //==========================================================================
826 static void CheckRecordFrom(void)
830 p = M_CheckParm("-recordfrom");
831 if(!p || p > myargc-2)
835 G_LoadGame(atoi(myargv[p+1]));
836 G_DoLoadGame(); // Load the gameskill etc info from savegame
837 G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p+2]);
838 H2_GameLoop(); // Never returns
841 //==========================================================================
845 //==========================================================================
847 static void AddWADFile(char *file)
852 ST_Message("Adding external file: %s\n", file);
858 new = malloc(strlen(file)+1);
865 // Use these for non-i386 systems. Lifted from the Doom code.
867 fixed_t FixedMul (fixed_t a, fixed_t b)
869 return ((long long) a * (long long) b) >> 16;
872 fixed_t FixedDiv2 (fixed_t a, fixed_t b)
876 c = ((long long)a<<16) / ((long long)b);
882 c = ((double)a) / ((double)b) * FRACUNIT;
884 if (c >= 2147483648.0 || c < -2147483648.0)
885 I_Error("FixedDiv: divide by zero");
890 //==========================================================================
894 //==========================================================================
896 fixed_t FixedDiv(fixed_t a, fixed_t b)
898 if((abs(a)>>14) >= abs(b))
900 return((a^b)<0 ? MININT : MAXINT);
902 return(FixedDiv2(a, b));
906 //==========================================================================
910 //==========================================================================
912 static void CreateBasePath(void)
914 sprintf(base,"%s/.hhexen/",getenv("HOME"));
916 mkdir( base, S_IRWXU|S_IRWXG|S_IRWXO );