]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/h2_main.c
osezer patch 003
[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         for(; eventtail != eventhead; eventtail = (++eventtail)&(MAXEVENTS-1))
575         {
576                 ev = &events[eventtail];
577                 if(F_Responder(ev))
578                 {
579                         continue;
580                 }
581                 if(MN_Responder(ev))
582                 {
583                         continue;
584                 }
585                 G_Responder(ev);
586         }
587 }
588
589 //==========================================================================
590 //
591 // H2_PostEvent
592 //
593 // Called by the I/O functions when input is detected.
594 //
595 //==========================================================================
596
597 void H2_PostEvent(event_t *ev)
598 {
599         events[eventhead] = *ev;
600         eventhead++;
601         eventhead &= (MAXEVENTS-1);
602 }
603
604 //==========================================================================
605 //
606 // DrawAndBlit
607 //
608 //==========================================================================
609
610 static void DrawAndBlit(void)
611 {
612         // Change the view size if needed
613         if(setsizeneeded)
614         {
615                 R_ExecuteSetViewSize();
616         }
617
618         // Do buffered drawing
619         switch(gamestate)
620         {
621                 case GS_LEVEL:
622                         if(!gametic)
623                         {
624                                 break;
625                         }
626                         if(automapactive)
627                         {
628                                 AM_Drawer();
629                         }
630                         else
631                         {
632                                 R_RenderPlayerView(&players[displayplayer]);
633                         }
634                         CT_Drawer();
635                         UpdateState |= I_FULLVIEW;
636                         SB_Drawer();
637                         break;
638                 case GS_INTERMISSION:
639                         IN_Drawer();
640                         break;
641                 case GS_FINALE:
642                         F_Drawer();
643                         break;
644                 case GS_DEMOSCREEN:
645                         PageDrawer();
646                         break;
647         }
648
649         if(paused && !MenuActive && !askforquit)
650         {
651                 if(!netgame)
652                 {
653                         V_DrawPatch(160, viewwindowy+5, W_CacheLumpName("PAUSED",
654                                 PU_CACHE));
655                 }
656                 else
657                 {
658                         V_DrawPatch(160, 70, W_CacheLumpName("PAUSED",
659                                 PU_CACHE));
660                 }
661         }
662
663 #ifdef RENDER3D
664     if( OGL_DrawFilter() )
665         BorderNeedRefresh = true;
666 #endif
667
668         // Draw current message
669         DrawMessage();
670
671         // Draw Menu
672         MN_Drawer();
673
674         // Send out any new accumulation
675         NetUpdate();
676
677         // Flush buffered stuff to screen
678         I_Update();
679 }
680
681 //==========================================================================
682 //
683 // DrawMessage
684 //
685 //==========================================================================
686
687 static void DrawMessage(void)
688 {
689         player_t *player;
690
691         player = &players[consoleplayer];
692         if(player->messageTics <= 0 || !player->message)
693         { // No message
694                 return;
695         }
696         if(player->yellowMessage)
697         {
698                 MN_DrTextAYellow(player->message, 
699                         160-MN_TextAWidth(player->message)/2, 1);
700         }
701         else
702         {
703                 MN_DrTextA(player->message, 160-MN_TextAWidth(player->message)/2, 1);
704         }
705 }
706
707 //==========================================================================
708 //
709 // H2_PageTicker
710 //
711 //==========================================================================
712
713 void H2_PageTicker(void)
714 {
715         if(--pagetic < 0)
716         {
717                 H2_AdvanceDemo();
718         }
719 }
720
721 //==========================================================================
722 //
723 // PageDrawer
724 //
725 //==========================================================================
726
727 static void PageDrawer(void)
728 {
729         V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE));
730         if(demosequence == 1)
731         {
732                 V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE));
733         }
734         UpdateState |= I_FULLSCRN;
735 }
736
737 //==========================================================================
738 //
739 // H2_AdvanceDemo
740 //
741 // Called after each demo or intro demosequence finishes.
742 //
743 //==========================================================================
744
745 void H2_AdvanceDemo(void)
746 {
747         advancedemo = true;
748 }
749
750 //==========================================================================
751 //
752 // H2_DoAdvanceDemo
753 //
754 //==========================================================================
755
756 void H2_DoAdvanceDemo(void)
757 {
758         players[consoleplayer].playerstate = PST_LIVE; // don't reborn
759         advancedemo = false;
760         usergame = false; // can't save/end game here
761         paused = false;
762         gameaction = ga_nothing;
763         demosequence = (demosequence+1)%7;
764         switch(demosequence)
765         {
766                 case 0:
767                         pagetic = 280;
768                         gamestate = GS_DEMOSCREEN;
769                         pagename = "TITLE";
770                         S_StartSongName("hexen", true);
771                         break;
772                 case 1:
773                         pagetic = 210;
774                         gamestate = GS_DEMOSCREEN;
775                         pagename = "TITLE";
776                         break;
777                 case 2:
778                         BorderNeedRefresh = true;
779                         UpdateState |= I_FULLSCRN;
780                         G_DeferedPlayDemo("demo1");
781                         break;
782                 case 3:
783                         pagetic = 200;
784                         gamestate = GS_DEMOSCREEN;
785                         pagename = "CREDIT";
786                         break;
787                 case 4:
788                         BorderNeedRefresh = true;
789                         UpdateState |= I_FULLSCRN;
790                         G_DeferedPlayDemo("demo2");
791                         break;
792                 case 5:
793                         pagetic = 200;
794                         gamestate = GS_DEMOSCREEN;
795                         pagename = "CREDIT";
796                         break;
797                 case 6:
798                         BorderNeedRefresh = true;
799                         UpdateState |= I_FULLSCRN;
800                         G_DeferedPlayDemo("demo3");
801                         break;
802         }
803 }
804
805 //==========================================================================
806 //
807 // H2_StartTitle
808 //
809 //==========================================================================
810
811 void H2_StartTitle(void)
812 {
813         gameaction = ga_nothing;
814         demosequence = -1;
815         H2_AdvanceDemo();
816 }
817
818 //==========================================================================
819 //
820 // CheckRecordFrom
821 //
822 // -recordfrom <savegame num> <demoname>
823 //
824 //==========================================================================
825
826 static void CheckRecordFrom(void)
827 {
828         int p;
829
830         p = M_CheckParm("-recordfrom");
831         if(!p || p > myargc-2)
832         { // Bad args
833                 return;
834         }
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
839 }
840
841 //==========================================================================
842 //
843 // AddWADFile
844 //
845 //==========================================================================
846
847 static void AddWADFile(char *file)
848 {
849         int i;
850         char *new;
851
852         ST_Message("Adding external file: %s\n", file);
853         i = 0;
854         while(wadfiles[i])
855         {
856                 i++;
857         }
858         new = malloc(strlen(file)+1);
859         strcpy(new, file);
860         wadfiles[i] = new;
861 }
862
863
864 #if 0
865 // Use these for non-i386 systems.  Lifted from the Doom code.
866
867 fixed_t FixedMul (fixed_t a, fixed_t b)
868 {
869     return ((long long) a * (long long) b) >> 16;
870 }
871
872 fixed_t FixedDiv2 (fixed_t a, fixed_t b)
873 {
874 #if 0
875     long long c;
876     c = ((long long)a<<16) / ((long long)b);
877         return (fixed_t) c;
878 #endif
879
880     double c;
881         
882     c = ((double)a) / ((double)b) * FRACUNIT;
883             
884     if (c >= 2147483648.0 || c < -2147483648.0)
885         I_Error("FixedDiv: divide by zero");
886     return (fixed_t) c;
887 }
888 #endif
889
890 //==========================================================================
891 //
892 // FixedDiv
893 //
894 //==========================================================================
895
896 fixed_t FixedDiv(fixed_t a, fixed_t b)
897 {
898         if((abs(a)>>14) >= abs(b))
899         {
900                 return((a^b)<0 ? MININT : MAXINT);
901         }
902         return(FixedDiv2(a, b));
903 }
904
905
906 //==========================================================================
907 //
908 // CreateBasePath
909 //
910 //==========================================================================
911
912 static void CreateBasePath(void)
913 {
914         sprintf(base,"%s/.hhexen/",getenv("HOME"));
915         basePath = base;
916         mkdir( base, S_IRWXU|S_IRWXG|S_IRWXO );
917
918