Round 5: Warn those using 1.0 wadfiles to quit it.
[theoddone33/hhexen.git] / base / h2_main.c
1
2 //**************************************************************************
3 //**
4 //** h2_main.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile$
7 //** $Revision$
8 //** $Date$
9 //** $Author$
10 //**
11 //**************************************************************************
12
13 // HEADER FILES ------------------------------------------------------------
14
15 #ifdef __linux
16 #include <sys/stat.h>
17 #endif 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <time.h>
21 #include "h2def.h"
22 #include "p_local.h"
23 #include "soundst.h"
24
25 #ifdef RENDER3D
26 #include "ogl_def.h"
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)
30 #endif
31
32
33 // MACROS ------------------------------------------------------------------
34
35 #define CONFIG_FILE_NAME "hhexen.cfg"
36 #define MAXWADFILES 20
37
38 // TYPES -------------------------------------------------------------------
39
40 typedef struct
41 {
42         char *name;
43         void (*func)(char **args, int tag);
44         int requiredArgs;
45         int tag;
46 } execOpt_t;
47
48 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
49
50 void R_ExecuteSetViewSize(void);
51 void D_CheckNetGame(void);
52 void G_BuildTiccmd(ticcmd_t *cmd);
53 void F_Drawer(void);
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);
59
60 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
61
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);
67
68 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
69
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);
84
85
86 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
87
88 extern boolean automapactive;
89 extern boolean MenuActive;
90 extern boolean askforquit;
91
92 // PUBLIC DATA DEFINITIONS -------------------------------------------------
93
94 char *basePath;
95 char base[121];
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)
109 skill_t startskill;
110 int startepisode;
111 int startmap;
112 boolean autostart;
113 boolean advancedemo;
114 FILE *debugfile;
115 event_t events[MAXEVENTS];
116 int eventhead;
117 int eventtail;
118
119 // PRIVATE DATA DEFINITIONS ------------------------------------------------
120
121 static int WarpMap;
122 static int demosequence;
123 static int pagetic;
124 static char *pagename;
125 #ifdef __NeXT__
126 static char *wadfiles[MAXWADFILES] =
127 {
128         "/Novell/H2/source/hexen.wad"
129 };
130 #else
131 static char *wadfiles[MAXWADFILES] =
132 {
133         "hexen.wad"
134         ,"assassin.wad"
135         ,NULL
136 };
137 #endif
138 static execOpt_t ExecOptions[] =
139 {
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
148 };
149
150 // CODE --------------------------------------------------------------------
151
152 //==========================================================================
153 //
154 // H2_Main
155 //
156 //==========================================================================
157 void InitMapMusicInfo(void);
158
159 void H2_Main(void)
160 {
161         int p;
162
163         M_FindResponseFile();
164         setbuf(stdout, NULL);
165         startepisode = 1;
166         autostart = false;
167         startskill = sk_medium;
168         startmap = 1;
169
170 #ifdef DEMO_WAD
171         shareware = true;
172 #else
173         shareware = false; // Always false for Hexen
174 #endif
175
176         HandleArgs();
177
178         CreateBasePath();
179
180         // Initialize subsystems
181
182         ST_Message("V_Init: allocate screens.\n");
183         V_Init();
184
185         // Load defaults before initing other systems
186         ST_Message("M_LoadDefaults: Load system defaults.\n");
187         M_LoadDefaults(CONFIG_FILE_NAME);
188
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);
195
196
197 #ifndef DEMO_WAD
198         W_CheckForOldFiles();
199 #endif
200         
201
202         ST_Message("Z_Init: Init zone memory allocation daemon.\n");
203         Z_Init();
204
205
206         ST_Message("MN_Init: Init menu system.\n");
207         MN_Init();
208
209         ST_Message("CT_Init: Init chat mode data.\n");
210         CT_Init();
211
212         InitMapMusicInfo();             // Init music fields in mapinfo
213
214 #if defined(__linux)
215         ST_Message("S_InitScript\n");
216         S_InitScript();
217 #endif
218
219         ST_Message("SN_InitSequenceScript: Registering sound sequences.\n");
220         SN_InitSequenceScript();
221         ST_Message("I_Init: Setting up machine state.\n");
222         I_Init();
223
224         ST_Message("ST_Init: Init startup screen.\n");
225         ST_Init();
226
227         S_StartSongName("orb", true);
228
229         // Show version message now, so it's visible during R_Init()
230         ST_Message("Executable: "VERSIONTEXT".\n");
231
232         ST_Message("R_Init: Init Hexen refresh daemon");
233         R_Init();
234         ST_Message("\n");
235
236         if (M_CheckParm("-net")) ST_NetProgress();      // Console player found
237
238         ST_Message("P_Init: Init Playloop state.\n");
239         P_Init();
240
241         // Check for command line warping. Follows P_Init() because the
242         // MAPINFO.TXT script must be already processed.
243         WarpCheck();
244
245         if(autostart)
246         {
247                 ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n",
248                         WarpMap, P_GetMapName(startmap), startmap, startskill+1);
249         }
250
251         ST_Message("D_CheckNetGame: Checking network game status.\n");
252         D_CheckNetGame();
253
254         ST_Message("SB_Init: Loading patches.\n");
255         SB_Init();
256         
257         CheckRecordFrom();
258
259         p = M_CheckParm("-record");
260         if(p && p < myargc-1)
261         {
262                 G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p+1]);
263                 H2_GameLoop(); // Never returns
264         }
265
266         p = M_CheckParm("-playdemo");
267         if(p && p < myargc-1)
268         {
269                 singledemo = true; // Quit after one demo
270                 G_DeferedPlayDemo(myargv[p+1]);
271                 H2_GameLoop(); // Never returns
272         }
273
274         p = M_CheckParm("-timedemo");
275         if(p && p < myargc-1)
276         {
277                 G_TimeDemo(myargv[p+1]);
278                 H2_GameLoop(); // Never returns
279         }
280
281         p = M_CheckParm("-loadgame");
282         if(p && p < myargc-1)
283         {
284                 G_LoadGame(atoi(myargv[p+1]));
285         }
286
287         if(gameaction != ga_loadgame)
288         {
289                 UpdateState |= I_FULLSCRN;
290                 BorderNeedRefresh = true;
291                 if(autostart || netgame)
292                 {
293                         G_StartNewInit();
294                         G_InitNew(startskill, startepisode, startmap);
295                 }
296                 else
297                 {
298                         H2_StartTitle();
299                 }
300         }
301         H2_GameLoop(); // Never returns
302 }
303
304 //==========================================================================
305 //
306 // HandleArgs
307 //
308 //==========================================================================
309
310 static void HandleArgs(void)
311 {
312         int p;
313         execOpt_t *opt;
314
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");
324
325         // Process command line options
326         for(opt = ExecOptions; opt->name != NULL; opt++)
327         {
328                 p = M_CheckParm(opt->name);
329                 if(p && p < myargc-opt->requiredArgs)
330                 {
331                         opt->func(&myargv[p], opt->tag);
332                 }
333         }
334
335         // Look for an external device driver
336         I_CheckExternDriver();
337 }
338
339 //==========================================================================
340 //
341 // WarpCheck
342 //
343 //==========================================================================
344
345 static void WarpCheck(void)
346 {
347         int p;
348         int map;
349
350         p = M_CheckParm("-warp");
351         if(p && p < myargc-1)
352         {
353                 WarpMap = atoi(myargv[p+1]);
354                 map = P_TranslateMap(WarpMap);
355                 if(map == -1)
356                 { // Couldn't find real map number
357                         startmap = 1;
358                         ST_Message("-WARP: Invalid map number.\n");
359                 }
360                 else
361                 { // Found a valid startmap
362                         startmap = map;
363                         autostart = true;
364                 }
365         }
366         else
367         {
368                 WarpMap = 1;
369                 startmap = P_TranslateMap(1);
370                 if(startmap == -1)
371                 {
372                         startmap = 1;
373                 }
374         }
375 }
376
377 //==========================================================================
378 //
379 // ExecOptionSKILL
380 //
381 //==========================================================================
382
383 static void ExecOptionSKILL(char **args, int tag)
384 {
385         startskill = args[1][0]-'1';
386         autostart = true;
387 }
388
389 //==========================================================================
390 //
391 // ExecOptionFILE
392 //
393 //==========================================================================
394
395 static void ExecOptionFILE(char **args, int tag)
396 {
397         int p;
398
399         p = M_CheckParm("-file");
400         while(++p != myargc && myargv[p][0] != '-')
401         {
402                 AddWADFile(myargv[p]);
403         }
404 }
405
406
407 //==========================================================================
408 //
409 // ExecOptionPLAYDEMO
410 //
411 //==========================================================================
412
413 static void ExecOptionPLAYDEMO(char **args, int tag)
414 {
415         char file[256];
416
417         sprintf(file, "%s.lmp", args[1]);
418         AddWADFile(file);
419         ST_Message("Playing demo %s.lmp.\n", args[1]);
420 }
421
422 //==========================================================================
423 //
424 // ExecOptionSCRIPTS
425 //
426 //==========================================================================
427
428 static void ExecOptionSCRIPTS(char **args, int tag)
429 {
430         sc_FileScripts = true;
431         sc_ScriptsDir = args[1];
432 }
433
434 //==========================================================================
435 //
436 // ExecOptionDEVMAPS
437 //
438 //==========================================================================
439
440 static void ExecOptionDEVMAPS(char **args, int tag)
441 {
442         DevMaps = true;
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");
447         SC_MustGetString();
448         ST_Message("[mapsdir   ] = %s\n", sc_String);
449         DevMapsDir = malloc(strlen(sc_String)+1);
450         strcpy(DevMapsDir, sc_String);
451         SC_MustGetStringName("scriptsdir");
452         SC_MustGetString();
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())
458         {
459                 if(SC_Compare("file"))
460                 {
461                         SC_MustGetString();
462                         AddWADFile(sc_String);
463                 }
464                 else
465                 {
466                         SC_ScriptError(NULL);
467                 }
468         }
469         SC_Close();
470 }
471
472
473 long superatol(char *s)
474 {
475         long int n=0, r=10, x, mul=1;
476         char *c=s;
477
478         for (; *c; c++)
479         {
480                 x = (*c & 223) - 16;
481
482                 if (x == -3)
483                 {
484                         mul = -mul;
485                 }
486                 else if (x == 72 && r == 10)
487                 {
488                         n -= (r=n);
489                         if (!r) r=16;
490                         if (r<2 || r>36) return -1;
491                 }
492                 else
493                 {
494                         if (x>10) x-=39;
495                         if (x >= r) return -1;
496                         n = (n*r) + x;
497                 }
498         }
499         return(mul*n);
500 }
501
502
503 static void ExecOptionMAXZONE(char **args, int tag)
504 {
505         int size;
506         
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;
510         maxzone = size;
511 }
512
513 //==========================================================================
514 //
515 // H2_GameLoop
516 //
517 //==========================================================================
518
519 void H2_GameLoop(void)
520 {
521         if(M_CheckParm("-debugfile"))
522         {
523                 char filename[20];
524                 sprintf(filename, "debug%i.txt", consoleplayer);
525                 debugfile = fopen(filename,"w");
526         }
527         I_InitGraphics();
528         while(1)
529         {
530                 // Frame syncronous IO operations
531                 I_StartFrame();
532
533                 // Process one or more tics
534                 if(singletics)
535                 {
536                         I_StartTic();
537                         H2_ProcessEvents();
538                         G_BuildTiccmd(&netcmds[consoleplayer][maketic%BACKUPTICS]);
539                         if(advancedemo)
540                         {
541                                 H2_DoAdvanceDemo();
542                         }
543                         G_Ticker();
544                         gametic++;
545                         maketic++;
546                 }
547                 else
548                 {
549                         // Will run at least one tic
550                         TryRunTics();
551                 }
552
553                 // Move positional sounds
554                 S_UpdateSounds(players[displayplayer].mo);
555
556                 DrawAndBlit();
557         }
558 }
559
560 //==========================================================================
561 //
562 // H2_ProcessEvents
563 //
564 // Send all the events of the given timestamp down the responder chain.
565 //
566 //==========================================================================
567
568 void H2_ProcessEvents(void)
569 {
570         event_t *ev;
571
572         for(; eventtail != eventhead; eventtail = (++eventtail)&(MAXEVENTS-1))
573         {
574                 ev = &events[eventtail];
575                 if(F_Responder(ev))
576                 {
577                         continue;
578                 }
579                 if(MN_Responder(ev))
580                 {
581                         continue;
582                 }
583                 G_Responder(ev);
584         }
585 }
586
587 //==========================================================================
588 //
589 // H2_PostEvent
590 //
591 // Called by the I/O functions when input is detected.
592 //
593 //==========================================================================
594
595 void H2_PostEvent(event_t *ev)
596 {
597         events[eventhead] = *ev;
598         eventhead = (++eventhead)&(MAXEVENTS-1);
599 }
600
601 //==========================================================================
602 //
603 // DrawAndBlit
604 //
605 //==========================================================================
606
607 static void DrawAndBlit(void)
608 {
609         // Change the view size if needed
610         if(setsizeneeded)
611         {
612                 R_ExecuteSetViewSize();
613         }
614
615         // Do buffered drawing
616         switch(gamestate)
617         {
618                 case GS_LEVEL:
619                         if(!gametic)
620                         {
621                                 break;
622                         }
623                         if(automapactive)
624                         {
625                                 AM_Drawer();
626                         }
627                         else
628                         {
629                                 R_RenderPlayerView(&players[displayplayer]);
630                         }
631                         CT_Drawer();
632                         UpdateState |= I_FULLVIEW;
633                         SB_Drawer();
634                         break;
635                 case GS_INTERMISSION:
636                         IN_Drawer();
637                         break;
638                 case GS_FINALE:
639                         F_Drawer();
640                         break;
641                 case GS_DEMOSCREEN:
642                         PageDrawer();
643                         break;
644         }
645
646         if(paused && !MenuActive && !askforquit)
647         {
648                 if(!netgame)
649                 {
650                         V_DrawPatch(160, viewwindowy+5, W_CacheLumpName("PAUSED",
651                                 PU_CACHE));
652                 }
653                 else
654                 {
655                         V_DrawPatch(160, 70, W_CacheLumpName("PAUSED",
656                                 PU_CACHE));
657                 }
658         }
659
660 #ifdef RENDER3D
661     if( OGL_DrawFilter() )
662         BorderNeedRefresh = true;
663 #endif
664
665         // Draw current message
666         DrawMessage();
667
668         // Draw Menu
669         MN_Drawer();
670
671         // Send out any new accumulation
672         NetUpdate();
673
674         // Flush buffered stuff to screen
675         I_Update();
676 }
677
678 //==========================================================================
679 //
680 // DrawMessage
681 //
682 //==========================================================================
683
684 static void DrawMessage(void)
685 {
686         player_t *player;
687
688         player = &players[consoleplayer];
689         if(player->messageTics <= 0 || !player->message)
690         { // No message
691                 return;
692         }
693         if(player->yellowMessage)
694         {
695                 MN_DrTextAYellow(player->message, 
696                         160-MN_TextAWidth(player->message)/2, 1);
697         }
698         else
699         {
700                 MN_DrTextA(player->message, 160-MN_TextAWidth(player->message)/2, 1);
701         }
702 }
703
704 //==========================================================================
705 //
706 // H2_PageTicker
707 //
708 //==========================================================================
709
710 void H2_PageTicker(void)
711 {
712         if(--pagetic < 0)
713         {
714                 H2_AdvanceDemo();
715         }
716 }
717
718 //==========================================================================
719 //
720 // PageDrawer
721 //
722 //==========================================================================
723
724 static void PageDrawer(void)
725 {
726         V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE));
727         if(demosequence == 1)
728         {
729                 V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE));
730         }
731         UpdateState |= I_FULLSCRN;
732 }
733
734 //==========================================================================
735 //
736 // H2_AdvanceDemo
737 //
738 // Called after each demo or intro demosequence finishes.
739 //
740 //==========================================================================
741
742 void H2_AdvanceDemo(void)
743 {
744         advancedemo = true;
745 }
746
747 //==========================================================================
748 //
749 // H2_DoAdvanceDemo
750 //
751 //==========================================================================
752
753 void H2_DoAdvanceDemo(void)
754 {
755         players[consoleplayer].playerstate = PST_LIVE; // don't reborn
756         advancedemo = false;
757         usergame = false; // can't save/end game here
758         paused = false;
759         gameaction = ga_nothing;
760         demosequence = (demosequence+1)%7;
761         switch(demosequence)
762         {
763                 case 0:
764                         pagetic = 280;
765                         gamestate = GS_DEMOSCREEN;
766                         pagename = "TITLE";
767                         S_StartSongName("hexen", true);
768                         break;
769                 case 1:
770                         pagetic = 210;
771                         gamestate = GS_DEMOSCREEN;
772                         pagename = "TITLE";
773                         break;
774                 case 2:
775                         BorderNeedRefresh = true;
776                         UpdateState |= I_FULLSCRN;
777                         G_DeferedPlayDemo("demo1");
778                         break;
779                 case 3:
780                         pagetic = 200;
781                         gamestate = GS_DEMOSCREEN;
782                         pagename = "CREDIT";
783                         break;
784                 case 4:
785                         BorderNeedRefresh = true;
786                         UpdateState |= I_FULLSCRN;
787                         G_DeferedPlayDemo("demo2");
788                         break;
789                 case 5:
790                         pagetic = 200;
791                         gamestate = GS_DEMOSCREEN;
792                         pagename = "CREDIT";
793                         break;
794                 case 6:
795                         BorderNeedRefresh = true;
796                         UpdateState |= I_FULLSCRN;
797                         G_DeferedPlayDemo("demo3");
798                         break;
799         }
800 }
801
802 //==========================================================================
803 //
804 // H2_StartTitle
805 //
806 //==========================================================================
807
808 void H2_StartTitle(void)
809 {
810         gameaction = ga_nothing;
811         demosequence = -1;
812         H2_AdvanceDemo();
813 }
814
815 //==========================================================================
816 //
817 // CheckRecordFrom
818 //
819 // -recordfrom <savegame num> <demoname>
820 //
821 //==========================================================================
822
823 static void CheckRecordFrom(void)
824 {
825         int p;
826
827         p = M_CheckParm("-recordfrom");
828         if(!p || p > myargc-2)
829         { // Bad args
830                 return;
831         }
832         G_LoadGame(atoi(myargv[p+1]));
833         G_DoLoadGame(); // Load the gameskill etc info from savegame
834         G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p+2]);
835         H2_GameLoop(); // Never returns
836 }
837
838 //==========================================================================
839 //
840 // AddWADFile
841 //
842 //==========================================================================
843
844 static void AddWADFile(char *file)
845 {
846         int i;
847         char *new;
848
849         ST_Message("Adding external file: %s\n", file);
850         i = 0;
851         while(wadfiles[i])
852         {
853                 i++;
854         }
855         new = malloc(strlen(file)+1);
856         strcpy(new, file);
857         wadfiles[i] = new;
858 }
859
860
861 #if 0
862 // Use these for non-i386 systems.  Lifted from the Doom code.
863
864 fixed_t FixedMul (fixed_t a, fixed_t b)
865 {
866     return ((long long) a * (long long) b) >> 16;
867 }
868
869 fixed_t FixedDiv2 (fixed_t a, fixed_t b)
870 {
871 #if 0
872     long long c;
873     c = ((long long)a<<16) / ((long long)b);
874         return (fixed_t) c;
875 #endif
876
877     double c;
878         
879     c = ((double)a) / ((double)b) * FRACUNIT;
880             
881     if (c >= 2147483648.0 || c < -2147483648.0)
882         I_Error("FixedDiv: divide by zero");
883     return (fixed_t) c;
884 }
885 #endif
886
887 //==========================================================================
888 //
889 // FixedDiv
890 //
891 //==========================================================================
892
893 fixed_t FixedDiv(fixed_t a, fixed_t b)
894 {
895         if((abs(a)>>14) >= abs(b))
896         {
897                 return((a^b)<0 ? MININT : MAXINT);
898         }
899         return(FixedDiv2(a, b));
900 }
901
902
903 //==========================================================================
904 //
905 // CreateBasePath
906 //
907 //==========================================================================
908
909 static void CreateBasePath(void)
910 {
911         sprintf(base,"%s/.hhexen/",getenv("HOME"));
912         basePath = base;
913         mkdir( base, S_IRWXU|S_IRWXG|S_IRWXO );
914