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 CreateSavePath(void);
83 static void WarpCheck(void);
86 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
88 extern boolean automapactive;
89 extern boolean MenuActive;
90 extern boolean askforquit;
91 extern char *SavePath;
93 // PUBLIC DATA DEFINITIONS -------------------------------------------------
95 boolean DevMaps; // true = Map development mode
96 char *DevMapsDir = ""; // development maps directory
97 boolean shareware; // true if only episode 1 present
98 boolean nomonsters; // checkparm of -nomonsters
99 boolean respawnparm; // checkparm of -respawn
100 boolean randomclass; // checkparm of -randclass
101 boolean debugmode; // checkparm of -debug
102 boolean ravpic; // checkparm of -ravpic
103 boolean cdrom; // true if cd-rom mode active
104 boolean cmdfrag; // true if a CMD_FRAG packet should be sent out
105 boolean singletics; // debug flag to cancel adaptiveness
106 boolean artiskip; // whether shift-enter skips an artifact
107 int maxzone = 0x800000; // Maximum allocated for zone heap (8meg default)
114 event_t events[MAXEVENTS];
118 // PRIVATE DATA DEFINITIONS ------------------------------------------------
121 static int demosequence;
123 static char *pagename;
125 static char *wadfiles[MAXWADFILES] =
127 "/Novell/H2/source/hexen.wad"
130 static char *wadfiles[MAXWADFILES] =
137 static execOpt_t ExecOptions[] =
139 { "-file", ExecOptionFILE, 1, 0 },
140 { "-scripts", ExecOptionSCRIPTS, 1, 0 },
141 { "-devmaps", ExecOptionDEVMAPS, 1, 0 },
142 { "-skill", ExecOptionSKILL, 1, 0 },
143 { "-playdemo", ExecOptionPLAYDEMO, 1, 0 },
144 { "-timedemo", ExecOptionPLAYDEMO, 1, 0 },
145 { "-maxzone", ExecOptionMAXZONE, 1, 0 },
146 { NULL, NULL, 0, 0 } // Terminator
149 // CODE --------------------------------------------------------------------
151 //==========================================================================
155 //==========================================================================
156 void InitMapMusicInfo(void);
162 M_FindResponseFile();
163 setbuf(stdout, NULL);
166 startskill = sk_medium;
172 shareware = false; // Always false for Hexen
177 // Initialize subsystems
179 ST_Message("V_Init: allocate screens.\n");
182 // Load defaults before initing other systems
183 ST_Message("M_LoadDefaults: Load system defaults.\n");
184 M_LoadDefaults(CONFIG_FILE_NAME);
186 // Now that the savedir is loaded from .CFG, make sure it exists
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);
197 ST_Message("Z_Init: Init zone memory allocation daemon.\n");
201 ST_Message("MN_Init: Init menu system.\n");
204 ST_Message("CT_Init: Init chat mode data.\n");
207 InitMapMusicInfo(); // Init music fields in mapinfo
210 ST_Message("S_InitScript\n");
214 ST_Message("SN_InitSequenceScript: Registering sound sequences.\n");
215 SN_InitSequenceScript();
216 ST_Message("I_Init: Setting up machine state.\n");
219 ST_Message("ST_Init: Init startup screen.\n");
222 S_StartSongName("orb", true);
224 // Show version message now, so it's visible during R_Init()
225 ST_Message("Executable: "VERSIONTEXT".\n");
227 ST_Message("R_Init: Init Hexen refresh daemon");
231 if (M_CheckParm("-net")) ST_NetProgress(); // Console player found
233 ST_Message("P_Init: Init Playloop state.\n");
236 // Check for command line warping. Follows P_Init() because the
237 // MAPINFO.TXT script must be already processed.
242 ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n",
243 WarpMap, P_GetMapName(startmap), startmap, startskill+1);
246 ST_Message("D_CheckNetGame: Checking network game status.\n");
249 ST_Message("SB_Init: Loading patches.\n");
254 p = M_CheckParm("-record");
255 if(p && p < myargc-1)
257 G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p+1]);
258 H2_GameLoop(); // Never returns
261 p = M_CheckParm("-playdemo");
262 if(p && p < myargc-1)
264 singledemo = true; // Quit after one demo
265 G_DeferedPlayDemo(myargv[p+1]);
266 H2_GameLoop(); // Never returns
269 p = M_CheckParm("-timedemo");
270 if(p && p < myargc-1)
272 G_TimeDemo(myargv[p+1]);
273 H2_GameLoop(); // Never returns
276 p = M_CheckParm("-loadgame");
277 if(p && p < myargc-1)
279 G_LoadGame(atoi(myargv[p+1]));
282 if(gameaction != ga_loadgame)
284 UpdateState |= I_FULLSCRN;
285 BorderNeedRefresh = true;
286 if(autostart || netgame)
289 G_InitNew(startskill, startepisode, startmap);
296 H2_GameLoop(); // Never returns
299 //==========================================================================
303 //==========================================================================
305 static void HandleArgs(void)
310 nomonsters = M_ParmExists("-nomonsters");
311 respawnparm = M_ParmExists("-respawn");
312 randomclass = M_ParmExists("-randclass");
313 ravpic = M_ParmExists("-ravpic");
314 artiskip = M_ParmExists("-artiskip");
315 debugmode = M_ParmExists("-debug");
316 deathmatch = M_ParmExists("-deathmatch");
317 cdrom = M_ParmExists("-cdrom");
318 cmdfrag = M_ParmExists("-cmdfrag");
320 // Process command line options
321 for(opt = ExecOptions; opt->name != NULL; opt++)
323 p = M_CheckParm(opt->name);
324 if(p && p < myargc-opt->requiredArgs)
326 opt->func(&myargv[p], opt->tag);
330 // Look for an external device driver
331 I_CheckExternDriver();
334 //==========================================================================
338 //==========================================================================
340 static void WarpCheck(void)
345 p = M_CheckParm("-warp");
346 if(p && p < myargc-1)
348 WarpMap = atoi(myargv[p+1]);
349 map = P_TranslateMap(WarpMap);
351 { // Couldn't find real map number
353 ST_Message("-WARP: Invalid map number.\n");
356 { // Found a valid startmap
364 startmap = P_TranslateMap(1);
372 //==========================================================================
376 //==========================================================================
378 static void ExecOptionSKILL(char **args, int tag)
380 startskill = args[1][0]-'1';
384 //==========================================================================
388 //==========================================================================
390 static void ExecOptionFILE(char **args, int tag)
394 p = M_CheckParm("-file");
395 while(++p != myargc && myargv[p][0] != '-')
397 AddWADFile(myargv[p]);
402 //==========================================================================
404 // ExecOptionPLAYDEMO
406 //==========================================================================
408 static void ExecOptionPLAYDEMO(char **args, int tag)
412 sprintf(file, "%s.lmp", args[1]);
414 ST_Message("Playing demo %s.lmp.\n", args[1]);
417 //==========================================================================
421 //==========================================================================
423 static void ExecOptionSCRIPTS(char **args, int tag)
425 sc_FileScripts = true;
426 sc_ScriptsDir = args[1];
429 //==========================================================================
433 //==========================================================================
435 static void ExecOptionDEVMAPS(char **args, int tag)
438 ST_Message("Map development mode enabled:\n");
439 ST_Message("[config ] = %s\n", args[1]);
440 SC_OpenFileCLib(args[1]);
441 SC_MustGetStringName("mapsdir");
443 ST_Message("[mapsdir ] = %s\n", sc_String);
444 DevMapsDir = malloc(strlen(sc_String)+1);
445 strcpy(DevMapsDir, sc_String);
446 SC_MustGetStringName("scriptsdir");
448 ST_Message("[scriptsdir] = %s\n", sc_String);
449 sc_FileScripts = true;
450 sc_ScriptsDir = malloc(strlen(sc_String)+1);
451 strcpy(sc_ScriptsDir, sc_String);
452 while(SC_GetString())
454 if(SC_Compare("file"))
457 AddWADFile(sc_String);
461 SC_ScriptError(NULL);
468 long superatol(char *s)
470 long int n=0, r=10, x, mul=1;
481 else if (x == 72 && r == 10)
485 if (r<2 || r>36) return -1;
490 if (x >= r) return -1;
498 static void ExecOptionMAXZONE(char **args, int tag)
502 size = superatol(args[1]);
503 if (size < MINIMUM_HEAP_SIZE) size = MINIMUM_HEAP_SIZE;
504 if (size > MAXIMUM_HEAP_SIZE) size = MAXIMUM_HEAP_SIZE;
508 //==========================================================================
512 //==========================================================================
514 void H2_GameLoop(void)
516 if(M_CheckParm("-debugfile"))
519 sprintf(filename, "debug%i.txt", consoleplayer);
520 debugfile = fopen(filename,"w");
525 // Frame syncronous IO operations
528 // Process one or more tics
533 G_BuildTiccmd(&netcmds[consoleplayer][maketic%BACKUPTICS]);
544 // Will run at least one tic
548 // Move positional sounds
549 S_UpdateSounds(players[displayplayer].mo);
555 //==========================================================================
559 // Send all the events of the given timestamp down the responder chain.
561 //==========================================================================
563 void H2_ProcessEvents(void)
567 for(; eventtail != eventhead; eventtail = (++eventtail)&(MAXEVENTS-1))
569 ev = &events[eventtail];
582 //==========================================================================
586 // Called by the I/O functions when input is detected.
588 //==========================================================================
590 void H2_PostEvent(event_t *ev)
592 events[eventhead] = *ev;
593 eventhead = (++eventhead)&(MAXEVENTS-1);
596 //==========================================================================
600 //==========================================================================
602 static void DrawAndBlit(void)
604 // Change the view size if needed
607 R_ExecuteSetViewSize();
610 // Do buffered drawing
624 R_RenderPlayerView(&players[displayplayer]);
627 UpdateState |= I_FULLVIEW;
630 case GS_INTERMISSION:
641 if(paused && !MenuActive && !askforquit)
645 V_DrawPatch(160, viewwindowy+5, W_CacheLumpName("PAUSED",
650 V_DrawPatch(160, 70, W_CacheLumpName("PAUSED",
656 if( OGL_DrawFilter() )
657 BorderNeedRefresh = true;
660 // Draw current message
666 // Send out any new accumulation
669 // Flush buffered stuff to screen
673 //==========================================================================
677 //==========================================================================
679 static void DrawMessage(void)
683 player = &players[consoleplayer];
684 if(player->messageTics <= 0 || !player->message)
688 if(player->yellowMessage)
690 MN_DrTextAYellow(player->message,
691 160-MN_TextAWidth(player->message)/2, 1);
695 MN_DrTextA(player->message, 160-MN_TextAWidth(player->message)/2, 1);
699 //==========================================================================
703 //==========================================================================
705 void H2_PageTicker(void)
713 //==========================================================================
717 //==========================================================================
719 static void PageDrawer(void)
721 V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE));
722 if(demosequence == 1)
724 V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE));
726 UpdateState |= I_FULLSCRN;
729 //==========================================================================
733 // Called after each demo or intro demosequence finishes.
735 //==========================================================================
737 void H2_AdvanceDemo(void)
742 //==========================================================================
746 //==========================================================================
748 void H2_DoAdvanceDemo(void)
750 players[consoleplayer].playerstate = PST_LIVE; // don't reborn
752 usergame = false; // can't save/end game here
754 gameaction = ga_nothing;
755 demosequence = (demosequence+1)%7;
760 gamestate = GS_DEMOSCREEN;
762 S_StartSongName("hexen", true);
766 gamestate = GS_DEMOSCREEN;
770 BorderNeedRefresh = true;
771 UpdateState |= I_FULLSCRN;
772 G_DeferedPlayDemo("demo1");
776 gamestate = GS_DEMOSCREEN;
780 BorderNeedRefresh = true;
781 UpdateState |= I_FULLSCRN;
782 G_DeferedPlayDemo("demo2");
786 gamestate = GS_DEMOSCREEN;
790 BorderNeedRefresh = true;
791 UpdateState |= I_FULLSCRN;
792 G_DeferedPlayDemo("demo3");
797 //==========================================================================
801 //==========================================================================
803 void H2_StartTitle(void)
805 gameaction = ga_nothing;
810 //==========================================================================
814 // -recordfrom <savegame num> <demoname>
816 //==========================================================================
818 static void CheckRecordFrom(void)
822 p = M_CheckParm("-recordfrom");
823 if(!p || p > myargc-2)
827 G_LoadGame(atoi(myargv[p+1]));
828 G_DoLoadGame(); // Load the gameskill etc info from savegame
829 G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p+2]);
830 H2_GameLoop(); // Never returns
833 //==========================================================================
837 //==========================================================================
839 static void AddWADFile(char *file)
844 ST_Message("Adding external file: %s\n", file);
850 new = malloc(strlen(file)+1);
857 // Use these for non-i386 systems. Lifted from the Doom code.
859 fixed_t FixedMul (fixed_t a, fixed_t b)
861 return ((long long) a * (long long) b) >> 16;
864 fixed_t FixedDiv2 (fixed_t a, fixed_t b)
868 c = ((long long)a<<16) / ((long long)b);
874 c = ((double)a) / ((double)b) * FRACUNIT;
876 if (c >= 2147483648.0 || c < -2147483648.0)
877 I_Error("FixedDiv: divide by zero");
882 //==========================================================================
886 //==========================================================================
888 fixed_t FixedDiv(fixed_t a, fixed_t b)
890 if((abs(a)>>14) >= abs(b))
892 return((a^b)<0 ? MININT : MAXINT);
894 return(FixedDiv2(a, b));
898 //==========================================================================
902 //==========================================================================
904 static void CreateSavePath(void)
906 char creationPath[121];
911 SavePath = "c:\\hexndata\\";
913 len = strlen(SavePath);
914 if (len >= 120) I_Error("Save path too long\n");
915 strcpy(creationPath, SavePath);
917 creationPath[len-1] = 0;
918 mkdir( creationPath, S_IRWXU|S_IRWXG|S_IRWXO );