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