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