Subversion Repositories eduke32

Rev

Rev 4495 | Rev 4559 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2542 helixhorne 1
//
2
// Common non-engine code/data for EDuke32 and Mapster32
3
//
4
 
5
#include "compat.h"
2726 hendricks2 6
#include "build.h"
2549 helixhorne 7
#include "scriptfile.h"
2554 helixhorne 8
#include "cache1d.h"
9
#include "kplib.h"
10
#include "baselayer.h"
3220 hendricks2 11
#include "names.h"
4557 hendricks2 12
#include "grpscan.h"
2542 helixhorne 13
 
3581 hendricks2 14
#ifdef _WIN32
15
# include "winbits.h"
3671 hendricks2 16
# include <shlwapi.h>
17
# include <winnt.h>
18
# ifndef KEY_WOW64_32KEY
19
#  define KEY_WOW64_32KEY 0x0200
20
# endif
3581 hendricks2 21
#endif
22
 
2542 helixhorne 23
#include "common.h"
2726 hendricks2 24
#include "common_game.h"
2542 helixhorne 25
 
4495 hendricks2 26
const char* s_buildInfo =
27
#ifdef BITNESS64
28
        "(64-bit)"
29
#else
30
        "(32-bit)"
31
#endif
32
#if defined (_MSC_VER) || defined(__cplusplus)
33
#ifdef _MSC_VER
34
        " MSVC"
35
#endif
36
#ifdef __cplusplus
37
        " C++"
38
#endif
39
        " build"
40
#endif
41
;
42
 
2789 hendricks2 43
int32_t g_gameType = GAMEFLAG_DUKE;
2542 helixhorne 44
 
4557 hendricks2 45
int32_t g_dependencyCRC = 0;
46
int32_t g_usingAddon = 0;
47
 
48
// g_gameNamePtr can point to one of: grpfiles[].name (string literal), string
49
// literal, malloc'd block (XXX: possible leak)
50
const char *g_gameNamePtr = NULL;
51
 
2726 hendricks2 52
// grp/con/def handling
53
 
2796 helixhorne 54
const char *defaultgamegrp[GAMECOUNT] = { "DUKE3D.GRP", "NAM.GRP", "NAPALM.GRP", "WW2GI.GRP" };
55
const char *defaultdeffilename[GAMECOUNT] = { "duke3d.def", "nam.def", "napalm.def", "ww2gi.def" };
56
const char *defaultconfilename = "GAME.CON";
57
const char *defaultgameconfilename[GAMECOUNT] = { "EDUKE.CON", "NAM.CON", "NAPALM.CON", "WW2GI.CON" };
2726 hendricks2 58
 
59
// g_grpNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
60
char *g_grpNamePtr = NULL;
61
// g_defNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
62
char *g_defNamePtr = NULL;
63
// g_scriptNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
64
char *g_scriptNamePtr = NULL;
65
 
66
void clearGrpNamePtr(void)
67
{
68
    if (g_grpNamePtr != NULL)
69
        Bfree(g_grpNamePtr);
70
    // g_grpNamePtr assumed to be assigned to right after
71
}
72
 
73
void clearDefNamePtr(void)
74
{
75
    if (g_defNamePtr != NULL)
76
        Bfree(g_defNamePtr);
77
    // g_defNamePtr assumed to be assigned to right after
78
}
79
 
80
void clearScriptNamePtr(void)
81
{
82
    if (g_scriptNamePtr != NULL)
83
        Bfree(g_scriptNamePtr);
84
    // g_scriptNamePtr assumed to be assigned to right after
85
}
86
 
2796 helixhorne 87
const char *G_DefaultGrpFile(void)
2726 hendricks2 88
{
89
    if (DUKE)
90
        return defaultgamegrp[GAME_DUKE];
91
    // order is important for the following three because GAMEFLAG_NAM overlaps all
92
    else if (NAPALM)
93
        return defaultgamegrp[GAME_NAPALM];
94
    else if (WW2GI)
95
        return defaultgamegrp[GAME_WW2GI];
96
    else if (NAM)
97
        return defaultgamegrp[GAME_NAM];
98
 
99
    return defaultgamegrp[0];
100
}
2796 helixhorne 101
const char *G_DefaultDefFile(void)
2726 hendricks2 102
{
103
    if (DUKE)
104
        return defaultdeffilename[GAME_DUKE];
105
    else if (WW2GI)
106
        return defaultdeffilename[GAME_WW2GI];
107
    else if (NAPALM)
108
    {
2752 helixhorne 109
        if (!testkopen(defaultdeffilename[GAME_NAPALM],0) && testkopen(defaultdeffilename[GAME_NAM],0))
3618 hendricks2 110
            return defaultdeffilename[GAME_NAM]; // NAM/NAPALM Sharing
2726 hendricks2 111
        else
112
            return defaultdeffilename[GAME_NAPALM];
113
    }
114
    else if (NAM)
115
    {
2752 helixhorne 116
        if (!testkopen(defaultdeffilename[GAME_NAM],0) && testkopen(defaultdeffilename[GAME_NAPALM],0))
3618 hendricks2 117
            return defaultdeffilename[GAME_NAPALM]; // NAM/NAPALM Sharing
2726 hendricks2 118
        else
119
            return defaultdeffilename[GAME_NAM];
120
    }
121
 
122
    return defaultdeffilename[0];
123
}
2796 helixhorne 124
const char *G_DefaultConFile(void)
2726 hendricks2 125
{
2752 helixhorne 126
    if (DUKE && testkopen(defaultgameconfilename[GAME_DUKE],0))
2726 hendricks2 127
        return defaultgameconfilename[GAME_DUKE];
2752 helixhorne 128
    else if (WW2GI && testkopen(defaultgameconfilename[GAME_WW2GI],0))
2726 hendricks2 129
        return defaultgameconfilename[GAME_WW2GI];
130
    else if (NAPALM)
131
    {
2752 helixhorne 132
        if (!testkopen(defaultgameconfilename[GAME_NAPALM],0))
2726 hendricks2 133
        {
2752 helixhorne 134
            if (testkopen(defaultgameconfilename[GAME_NAM],0))
3618 hendricks2 135
                return defaultgameconfilename[GAME_NAM]; // NAM/NAPALM Sharing
2726 hendricks2 136
        }
137
        else
138
            return defaultgameconfilename[GAME_NAPALM];
139
    }
140
    else if (NAM)
141
    {
2752 helixhorne 142
        if (!testkopen(defaultgameconfilename[GAME_NAM],0))
2726 hendricks2 143
        {
2752 helixhorne 144
            if (testkopen(defaultgameconfilename[GAME_NAPALM],0))
3618 hendricks2 145
                return defaultgameconfilename[GAME_NAPALM]; // NAM/NAPALM Sharing
2726 hendricks2 146
        }
147
        else
148
            return defaultgameconfilename[GAME_NAM];
149
    }
150
 
151
    return defaultconfilename;
152
}
153
 
2796 helixhorne 154
const char *G_GrpFile(void)
2726 hendricks2 155
{
156
    if (g_grpNamePtr == NULL)
157
        return G_DefaultGrpFile();
158
    else
159
        return g_grpNamePtr;
160
}
3654 terminx 161
 
2796 helixhorne 162
const char *G_DefFile(void)
2726 hendricks2 163
{
164
    if (g_defNamePtr == NULL)
165
        return G_DefaultDefFile();
166
    else
167
        return g_defNamePtr;
168
}
3654 terminx 169
 
2796 helixhorne 170
const char *G_ConFile(void)
2726 hendricks2 171
{
172
    if (g_scriptNamePtr == NULL)
173
        return G_DefaultConFile();
174
    else
175
        return g_scriptNamePtr;
176
}
177
 
178
//////////
179
 
3976 helixhorne 180
#define NUMPSKYMULTIS 5
181
EDUKE32_STATIC_ASSERT(NUMPSKYMULTIS <= MAXPSKYMULTIS);
182
EDUKE32_STATIC_ASSERT(PSKYOFF_MAX <= MAXPSKYTILES);
183
 
3975 helixhorne 184
// Set up new-style multi-psky handling.
3976 helixhorne 185
void G_InitMultiPsky(int32_t CLOUDYOCEAN__DYN, int32_t MOONSKY1__DYN, int32_t BIGORBIT1__DYN, int32_t LA__DYN)
3220 hendricks2 186
{
187
    int32_t i;
188
 
3976 helixhorne 189
    psky_t *defaultsky = &multipsky[0];
190
    psky_t *oceansky = &multipsky[1];
191
    psky_t *moonsky = &multipsky[2];
192
    psky_t *spacesky = &multipsky[3];
193
    psky_t *citysky = &multipsky[4];
3220 hendricks2 194
 
3975 helixhorne 195
    static int32_t inited;
196
    if (inited)
197
        return;
198
    inited = 1;
3220 hendricks2 199
 
3976 helixhorne 200
    multipskytile[0] = -1;
201
    multipskytile[1] = CLOUDYOCEAN__DYN;
202
    multipskytile[2] = MOONSKY1__DYN;
203
    multipskytile[3] = BIGORBIT1__DYN;
204
    multipskytile[4] = LA__DYN;
3220 hendricks2 205
 
3976 helixhorne 206
    pskynummultis = NUMPSKYMULTIS;
3220 hendricks2 207
 
3975 helixhorne 208
    // When adding other multi-skies, take care that the tileofs[] values are
209
    // <= PSKYOFF_MAX. (It can be increased up to MAXPSKYTILES, but should be
210
    // set as tight as possible.)
211
 
3976 helixhorne 212
    // The default sky properties (all others are implicitly zero):
213
    defaultsky->lognumtiles = 3;
214
    defaultsky->horizfrac = 32768;
215
 
216
    // CLOUDYOCEAN
217
    // Aligns with the drawn scene horizon because it has one itself.
218
    oceansky->lognumtiles = 3;
219
    oceansky->horizfrac = 65536;
220
 
3220 hendricks2 221
    // MOONSKY1
222
    //        earth          mountain   mountain         sun
3975 helixhorne 223
    moonsky->lognumtiles = 3;
224
    moonsky->horizfrac = 32768;
225
    moonsky->tileofs[6] = 1;
226
    moonsky->tileofs[1] = 2;
227
    moonsky->tileofs[4] = 2;
228
    moonsky->tileofs[2] = 3;
3220 hendricks2 229
 
230
    // BIGORBIT1   // orbit
231
    //       earth1         2           3           moon/sun
3975 helixhorne 232
    spacesky->lognumtiles = 3;
233
    spacesky->horizfrac = 32768;
234
    spacesky->tileofs[5] = 1;
235
    spacesky->tileofs[6] = 2;
236
    spacesky->tileofs[7] = 3;
237
    spacesky->tileofs[2] = 4;
3220 hendricks2 238
 
239
    // LA // la city
240
    //       earth1         2           3           moon/sun
3975 helixhorne 241
    citysky->lognumtiles = 3;
242
    citysky->horizfrac = 16384+1024;
243
    citysky->tileofs[0] = 1;
244
    citysky->tileofs[1] = 2;
245
    citysky->tileofs[2] = 1;
246
    citysky->tileofs[3] = 3;
247
    citysky->tileofs[4] = 4;
248
    citysky->tileofs[5] = 0;
249
    citysky->tileofs[6] = 2;
250
    citysky->tileofs[7] = 3;
3220 hendricks2 251
 
3975 helixhorne 252
    for (i=0; i<pskynummultis; ++i)
253
    {
254
        int32_t j;
255
        for (j=0; j<(1<<multipsky[i].lognumtiles); ++j)
256
            Bassert(multipsky[i].tileofs[j] <= PSKYOFF_MAX);
257
    }
3976 helixhorne 258
}
3220 hendricks2 259
 
3976 helixhorne 260
void G_SetupGlobalPsky(void)
261
{
262
    int32_t i, mskyidx=0;
263
 
264
    // NOTE: Loop must be running backwards for the same behavior as the game
265
    // (greatest sector index with matching parallaxed sky takes precedence).
266
    for (i=numsectors-1; i>=0; i--)
267
    {
268
        if (sector[i].ceilingstat & 1)
269
        {
4006 helixhorne 270
            mskyidx = getpskyidx(sector[i].ceilingpicnum);
3976 helixhorne 271
            if (mskyidx > 0)
272
                break;
273
        }
274
    }
275
 
276
    g_pskyidx = mskyidx;
3220 hendricks2 277
}
278
 
279
//////////
280
 
4557 hendricks2 281
static char g_rootDir[BMAX_PATH];
282
char g_modDir[BMAX_PATH] = "/";
283
 
284
int32_t kopen4loadfrommod(const char *filename, char searchfirst)
285
{
286
    int32_t r=-1;
287
 
288
    if (g_modDir[0]!='/' || g_modDir[1]!=0)
289
    {
290
        static char fn[BMAX_PATH];
291
 
292
        Bsnprintf(fn, sizeof(fn), "%s/%s",g_modDir,filename);
293
        r = kopen4load(fn,searchfirst);
294
    }
295
 
296
    if (r < 0)
297
        r = kopen4load(filename,searchfirst);
298
 
299
    return r;
300
}
301
 
302
int32_t usecwd;
303
static void G_LoadAddon(void);
304
int32_t g_groupFileHandle;
305
 
306
void G_ExtPreInit(int32_t argc,const char **argv)
307
{
308
    usecwd = G_CheckCmdSwitch(argc, argv, "-usecwd");
309
 
310
#ifdef _WIN32
311
    GetModuleFileName(NULL,g_rootDir,BMAX_PATH);
312
    Bcorrectfilename(g_rootDir,1);
313
    //chdir(g_rootDir);
314
#else
315
    getcwd(g_rootDir,BMAX_PATH);
316
    strcat(g_rootDir,"/");
3582 hendricks2 317
#endif
4557 hendricks2 318
}
3582 hendricks2 319
 
4557 hendricks2 320
void G_ExtInit(void)
3582 hendricks2 321
{
4557 hendricks2 322
    char cwd[BMAX_PATH];
323
 
324
    if (getcwd(cwd,BMAX_PATH))
325
    {
326
#if defined(__APPLE__)
327
        /* Dirty hack on OS X to also look for gamedata inside the application bundle - rhoenie 08/08 */
328
        char seekinappcontainer[BMAX_PATH];
329
        Bsnprintf(seekinappcontainer,sizeof(seekinappcontainer),"%s/EDuke32.app/", cwd);
330
        addsearchpath(seekinappcontainer);
3582 hendricks2 331
#endif
4557 hendricks2 332
        addsearchpath(cwd);
333
    }
334
 
335
    if (CommandPaths)
336
    {
337
        int32_t i;
338
        struct strllist *s;
339
        while (CommandPaths)
340
        {
341
            s = CommandPaths->next;
342
            i = addsearchpath(CommandPaths->str);
343
            if (i < 0)
344
            {
345
                initprintf("Failed adding %s for game data: %s\n", CommandPaths->str,
346
                           i==-1 ? "not a directory" : "no such directory");
347
            }
348
 
349
            Bfree(CommandPaths->str);
350
            Bfree(CommandPaths);
351
            CommandPaths = s;
352
        }
353
    }
354
 
355
#if defined(_WIN32)
356
    if (!access("user_profiles_enabled", F_OK))
357
#else
358
    if (usecwd == 0 && access("user_profiles_disabled", F_OK))
359
#endif
360
    {
361
        char *homedir;
362
        int32_t asperr;
363
 
364
        if ((homedir = Bgethomedir()))
365
        {
366
            Bsnprintf(cwd,sizeof(cwd),"%s/"
367
#if defined(_WIN32)
368
                      "EDuke32 Settings"
369
#elif defined(__APPLE__)
370
                      "Library/Application Support/EDuke32"
371
#elif defined(GEKKO)
372
                      "apps/eduke32"
373
#else
374
                      ".eduke32"
375
#endif
376
                      ,homedir);
377
            asperr = addsearchpath(cwd);
378
            if (asperr == -2)
379
            {
380
                if (Bmkdir(cwd,S_IRWXU) == 0) asperr = addsearchpath(cwd);
381
                else asperr = -1;
382
            }
383
            if (asperr == 0)
384
                chdir(cwd);
385
            Bfree(homedir);
386
        }
387
    }
388
 
389
    // JBF 20031220: Because it's annoying renaming GRP files whenever I want to test different game data
390
    if (g_grpNamePtr == NULL)
391
    {
392
        const char *cp = getenv("DUKE3DGRP");
393
        if (cp)
394
        {
395
            clearGrpNamePtr();
396
            g_grpNamePtr = dup_filename(cp);
397
            initprintf("Using \"%s\" as main GRP file\n", g_grpNamePtr);
398
        }
399
    }
3582 hendricks2 400
}
401
 
4557 hendricks2 402
void G_ExtPreStartupWindow(void)
403
{
404
    ScanGroups();
405
    {
406
        // try and identify the 'defaultgamegrp' in the set of GRPs.
407
        // if it is found, set up the environment accordingly for the game it represents.
408
        // if it is not found, choose the first GRP from the list
409
        struct grpfile *fg, *first = NULL;
410
 
411
        for (fg = foundgrps; fg; fg=fg->next)
412
        {
413
            struct grpfile *grp;
414
            for (grp = listgrps; grp; grp=grp->next)
415
                if (fg->crcval == grp->crcval) break;
416
 
417
            if (grp == NULL)
418
                continue;
419
 
420
            fg->game = grp->game;
421
            if (!first) first = fg;
422
            if (!Bstrcasecmp(fg->name, G_DefaultGrpFile()))
423
            {
424
                g_gameType = grp->game;
425
                g_gameNamePtr = grp->name;
426
                break;
427
            }
428
        }
429
        if (!fg && first)
430
        {
431
            if (g_grpNamePtr == NULL)
432
            {
433
                clearGrpNamePtr();
434
                g_grpNamePtr = dup_filename(first->name);
435
            }
436
            g_gameType = first->game;
437
            g_gameNamePtr = listgrps->name;
438
        }
439
        else if (!fg) g_gameNamePtr = NULL;
440
    }
441
}
442
 
443
void G_ExtPostStartupWindow(int32_t autoload)
444
{
445
    if (g_modDir[0] != '/')
446
    {
447
        char cwd[BMAX_PATH];
448
 
449
        Bstrcat(g_rootDir,g_modDir);
450
        addsearchpath(g_rootDir);
451
//        addsearchpath(mod_dir);
452
 
453
        if (getcwd(cwd,BMAX_PATH))
454
        {
455
            Bsprintf(cwd,"%s/%s",cwd,g_modDir);
456
            if (!Bstrcmp(g_rootDir, cwd))
457
            {
458
                if (addsearchpath(cwd) == -2)
459
                    if (Bmkdir(cwd,S_IRWXU) == 0) addsearchpath(cwd);
460
            }
461
        }
462
 
463
#ifdef USE_OPENGL
464
        Bsprintf(cwd,"%s/%s",g_modDir,TEXCACHEFILE);
465
        Bstrcpy(TEXCACHEFILE,cwd);
466
#endif
467
    }
468
 
469
    if (g_usingAddon)
470
        G_LoadAddon();
471
 
472
    {
473
        int32_t i;
474
        const char *grpfile = G_GrpFile();
475
 
476
        if (g_dependencyCRC)
477
        {
478
            struct grpfile * grp = FindGroup(g_dependencyCRC);
479
            if (grp)
480
            {
481
                if ((i = initgroupfile(grp->name)) == -1)
482
                    initprintf("Warning: could not find main data file \"%s\"!\n",grp->name);
483
                else
484
                    initprintf("Using \"%s\" as main game data file.\n", grp->name);
485
            }
486
        }
487
 
488
        if ((i = initgroupfile(grpfile)) == -1)
489
            initprintf("Warning: could not find main data file \"%s\"!\n",grpfile);
490
        else
491
            initprintf("Using \"%s\" as main game data file.\n", grpfile);
492
 
493
        if (autoload)
494
        {
495
            G_LoadGroupsInDir("autoload");
496
 
497
            if (i != -1)
498
                G_DoAutoload(grpfile);
499
        }
500
    }
501
 
502
    if (g_modDir[0] != '/')
503
        G_LoadGroupsInDir(g_modDir);
504
 
505
    if (g_defNamePtr == NULL)
506
    {
507
        const char *tmpptr = getenv("DUKE3DDEF");
508
        if (tmpptr)
509
        {
510
            clearDefNamePtr();
511
            g_defNamePtr = dup_filename(tmpptr);
512
            initprintf("Using \"%s\" as definitions file\n", g_defNamePtr);
513
        }
514
    }
515
 
516
    loaddefinitions_game(G_DefFile(), TRUE);
517
 
518
    {
519
        struct strllist *s;
520
 
521
        pathsearchmode = 1;
522
        while (CommandGrps)
523
        {
524
            int32_t j;
525
 
526
            s = CommandGrps->next;
527
 
528
            if ((j = initgroupfile(CommandGrps->str)) == -1)
529
                initprintf("Could not find file \"%s\".\n",CommandGrps->str);
530
            else
531
            {
532
                g_groupFileHandle = j;
533
                initprintf("Using file \"%s\" as game data.\n",CommandGrps->str);
534
                if (autoload)
535
                    G_DoAutoload(CommandGrps->str);
536
            }
537
 
538
            Bfree(CommandGrps->str);
539
            Bfree(CommandGrps);
540
            CommandGrps = s;
541
        }
542
        pathsearchmode = 0;
543
    }
544
}
545
 
3622 terminx 546
#ifdef _WIN32
3637 terminx 547
const char * G_GetInstallPath(int32_t insttype)
3622 terminx 548
{
3637 terminx 549
    static char spath[NUMINSTPATHS][BMAX_PATH];
550
    static int32_t success[NUMINSTPATHS] = { -1, -1 };
3622 terminx 551
    int32_t siz = BMAX_PATH;
552
 
3637 terminx 553
    if (success[insttype] == -1)
554
    {
3671 hendricks2 555
        HKEY HKLM32;
556
        LONG keygood = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NULL, 0, KEY_READ | KEY_WOW64_32KEY, &HKLM32);
557
        // KEY_WOW64_32KEY gets us around Wow6432Node on 64-bit builds
558
 
559
        if (keygood == ERROR_SUCCESS)
4127 hendricks2 560
        {
3671 hendricks2 561
            switch (insttype)
562
            {
563
            case INSTPATH_STEAM:
564
                success[insttype] = SHGetValueA(HKLM32, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App 225140", "InstallLocation", NULL, spath[insttype], (LPDWORD)&siz);
565
                break;
566
            case INSTPATH_GOG:
567
                success[insttype] = SHGetValueA(HKLM32, "SOFTWARE\\GOG.com\\GOGDUKE3D", "PATH", NULL, spath[insttype], (LPDWORD)&siz);
568
                break;
569
            }
4127 hendricks2 570
 
571
            RegCloseKey(HKLM32);
572
        }
3637 terminx 573
    }
3622 terminx 574
 
3637 terminx 575
    if (success[insttype] == ERROR_SUCCESS)
576
        return spath[insttype];
3622 terminx 577
 
578
    return NULL;
579
}
580
#endif
581
 
4557 hendricks2 582
static void G_LoadAddon(void)
583
{
584
    struct grpfile * grp;
585
    int32_t crc = 0;  // compiler-happy
586
 
587
    switch (g_usingAddon)
588
    {
589
    case ADDON_DUKEDC:
590
        crc = DUKEDC_CRC;
591
        break;
592
    case ADDON_NWINTER:
593
        crc = DUKENW_CRC;
594
        break;
595
    case ADDON_CARIBBEAN:
596
        crc = DUKECB_CRC;
597
        break;
598
    }
599
 
600
    if (!crc) return;
601
 
602
    grp = FindGroup(crc);
603
 
604
    if (grp && FindGroup(DUKE15_CRC))
605
    {
606
        clearGrpNamePtr();
607
        g_grpNamePtr = dup_filename(FindGroup(DUKE15_CRC)->name);
608
 
609
        G_AddGroup(grp->name);
610
 
611
        for (grp = listgrps; grp; grp=grp->next)
612
            if (crc == grp->crcval) break;
613
 
614
        if (grp != NULL && grp->scriptname)
615
        {
616
            clearScriptNamePtr();
617
            g_scriptNamePtr = dup_filename(grp->scriptname);
618
        }
619
 
620
        if (grp != NULL && grp->defname)
621
        {
622
            clearDefNamePtr();
623
            g_defNamePtr = dup_filename(grp->defname);
624
        }
625
    }
626
}
627
 
3581 hendricks2 628
void G_AddSearchPaths(void)
629
{
630
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
631
    addsearchpath("/usr/share/games/jfduke3d");
632
    addsearchpath("/usr/local/share/games/jfduke3d");
633
    addsearchpath("/usr/share/games/eduke32");
634
    addsearchpath("/usr/local/share/games/eduke32");
635
#elif defined(__APPLE__)
636
    addsearchpath("/Library/Application Support/JFDuke3D");
637
    addsearchpath("/Library/Application Support/EDuke32");
638
#elif defined (_WIN32)
3615 terminx 639
    // detect Steam and GOG versions of Duke3D
640
    char buf[BMAX_PATH];
3671 hendricks2 641
    const char* instpath;
3615 terminx 642
 
3671 hendricks2 643
    if ((instpath = G_GetInstallPath(INSTPATH_STEAM)))
3622 terminx 644
    {
4557 hendricks2 645
        Bsnprintf(buf, sizeof(buf), "%s/gameroot", instpath);
3622 terminx 646
        addsearchpath(buf);
3615 terminx 647
 
4557 hendricks2 648
        Bsnprintf(buf, sizeof(buf), "%s/gameroot/addons", instpath);
3622 terminx 649
        addsearchpath(buf);
3615 terminx 650
    }
651
 
3671 hendricks2 652
    if ((instpath = G_GetInstallPath(INSTPATH_GOG)))
653
        addsearchpath(instpath);
3581 hendricks2 654
#endif
655
}
656
 
3654 terminx 657
void G_CleanupSearchPaths(void)
658
{
659
#ifdef _WIN32
660
    char buf[BMAX_PATH];
3671 hendricks2 661
    const char* instpath;
3654 terminx 662
 
3671 hendricks2 663
    if ((instpath = G_GetInstallPath(INSTPATH_STEAM)))
3654 terminx 664
    {
4557 hendricks2 665
        Bsnprintf(buf, sizeof(buf), "%s/gameroot", instpath);
3654 terminx 666
        removesearchpath(buf);
667
 
4557 hendricks2 668
        Bsnprintf(buf, sizeof(buf), "%s/gameroot/addons", instpath);
3654 terminx 669
        removesearchpath(buf);
670
    }
671
 
3671 hendricks2 672
    if ((instpath = G_GetInstallPath(INSTPATH_GOG)))
673
        removesearchpath(instpath);
3654 terminx 674
#endif
675
}
676
 
3581 hendricks2 677
//////////
678
 
2542 helixhorne 679
struct strllist *CommandPaths, *CommandGrps;
680
 
4128 hendricks2 681
char **g_scriptModules = NULL;
682
int32_t g_scriptModulesNum = 0;
683
char **g_defModules = NULL;
684
int32_t g_defModulesNum = 0;
685
 
686
#ifdef HAVE_CLIPSHAPE_FEATURE
687
char **g_clipMapFiles = NULL;
688
int32_t g_clipMapFilesNum = 0;
689
#endif
690
 
2542 helixhorne 691
void G_AddGroup(const char *buffer)
692
{
693
    char buf[BMAX_PATH];
694
 
4491 helixhorne 695
    struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
2542 helixhorne 696
 
697
    Bstrcpy(buf, buffer);
698
 
699
    if (Bstrchr(buf,'.') == 0)
700
        Bstrcat(buf,".grp");
701
 
4491 helixhorne 702
    s->str = Xstrdup(buf);
2542 helixhorne 703
 
704
    if (CommandGrps)
705
    {
706
        struct strllist *t;
707
        for (t = CommandGrps; t->next; t=t->next) ;
708
        t->next = s;
709
        return;
710
    }
711
    CommandGrps = s;
712
}
713
 
714
void G_AddPath(const char *buffer)
715
{
4491 helixhorne 716
    struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
717
    s->str = Xstrdup(buffer);
2542 helixhorne 718
 
719
    if (CommandPaths)
720
    {
721
        struct strllist *t;
722
        for (t = CommandPaths; t->next; t=t->next) ;
723
        t->next = s;
724
        return;
725
    }
726
    CommandPaths = s;
727
}
2549 helixhorne 728
 
4128 hendricks2 729
void G_AddDef(const char *buffer)
730
{
731
    clearDefNamePtr();
732
    g_defNamePtr = dup_filename(buffer);
733
    initprintf("Using DEF file \"%s\".\n",g_defNamePtr);
734
}
735
 
736
void G_AddDefModule(const char *buffer)
737
{
4491 helixhorne 738
    g_defModules = (char **) Xrealloc (g_defModules, (g_defModulesNum+1) * sizeof(char *));
739
    g_defModules[g_defModulesNum] = Xstrdup(buffer);
4128 hendricks2 740
    ++g_defModulesNum;
741
}
742
 
743
#ifdef HAVE_CLIPSHAPE_FEATURE
744
void G_AddClipMap(const char *buffer)
745
{
4491 helixhorne 746
    g_clipMapFiles = (char **) Xrealloc (g_clipMapFiles, (g_clipMapFilesNum+1) * sizeof(char *));
747
    g_clipMapFiles[g_clipMapFilesNum] = Xstrdup(buffer);
4128 hendricks2 748
    ++g_clipMapFilesNum;
749
}
750
#endif
751
 
752
void G_AddCon(const char *buffer)
753
{
754
    clearScriptNamePtr();
755
    g_scriptNamePtr = dup_filename(buffer);
756
    initprintf("Using CON file \"%s\".\n",g_scriptNamePtr);
757
}
758
 
759
void G_AddConModule(const char *buffer)
760
{
4491 helixhorne 761
    g_scriptModules = (char **) Xrealloc (g_scriptModules, (g_scriptModulesNum+1) * sizeof(char *));
762
    g_scriptModules[g_scriptModulesNum] = Xstrdup(buffer);
4128 hendricks2 763
    ++g_scriptModulesNum;
764
}
765
 
2549 helixhorne 766
//////////
767
 
768
int32_t getatoken(scriptfile *sf, const tokenlist *tl, int32_t ntokens)
769
{
770
    char *tok;
771
    int32_t i;
772
 
773
    if (!sf) return T_ERROR;
774
    tok = scriptfile_gettoken(sf);
775
    if (!tok) return T_EOF;
776
 
777
    for (i=ntokens-1; i>=0; i--)
778
    {
779
        if (!Bstrcasecmp(tok, tl[i].text))
780
            return tl[i].tokenid;
781
    }
782
    return T_ERROR;
783
}
2554 helixhorne 784
 
785
//////////
786
 
4557 hendricks2 787
int32_t G_CheckCmdSwitch(int32_t argc, const char **argv, const char *str)
788
{
789
    int32_t i;
790
    for (i=0; i<argc; i++)
791
    {
792
        if (str && !Bstrcasecmp(argv[i], str))
793
            return 1;
794
    }
795
 
796
    return 0;
797
}
798
 
2752 helixhorne 799
// returns: 1 if file could be opened, 0 else
800
int32_t testkopen(const char *filename, char searchfirst)
801
{
802
    int32_t fd = kopen4load(filename, searchfirst);
803
    if (fd >= 0)
804
        kclose(fd);
805
    return (fd >= 0);
806
}
807
 
2554 helixhorne 808
// checks from path and in ZIPs, returns 1 if NOT found
809
int32_t check_file_exist(const char *fn)
810
{
811
    int32_t opsm = pathsearchmode;
812
    char *tfn;
813
 
814
    pathsearchmode = 1;
815
    if (findfrompath(fn,&tfn) < 0)
816
    {
817
        char buf[BMAX_PATH];
818
 
819
        Bstrcpy(buf,fn);
820
        kzfindfilestart(buf);
821
        if (!kzfindfile(buf))
822
        {
823
            initprintf("Error: file \"%s\" does not exist\n",fn);
824
            pathsearchmode = opsm;
825
            return 1;
826
        }
827
    }
828
    else Bfree(tfn);
829
    pathsearchmode = opsm;
830
 
831
    return 0;
832
}
2555 helixhorne 833
 
834
 
835
//// FILE NAME / DIRECTORY LISTS ////
836
void fnlist_clearnames(fnlist_t *fnl)
837
{
838
    klistfree(fnl->finddirs);
839
    klistfree(fnl->findfiles);
840
 
841
    fnl->finddirs = fnl->findfiles = NULL;
842
    fnl->numfiles = fnl->numdirs = 0;
843
}
844
 
845
// dirflags, fileflags:
846
//  -1 means "don't get dirs/files",
847
//  otherwise ORed to flags for respective klistpath
848
int32_t fnlist_getnames(fnlist_t *fnl, const char *dirname, const char *pattern,
849
                        int32_t dirflags, int32_t fileflags)
850
{
851
    CACHE1D_FIND_REC *r;
852
 
853
    fnlist_clearnames(fnl);
854
 
855
    if (dirflags != -1)
856
        fnl->finddirs = klistpath(dirname, "*", CACHE1D_FIND_DIR|dirflags);
857
    if (fileflags != -1)
858
        fnl->findfiles = klistpath(dirname, pattern, CACHE1D_FIND_FILE|fileflags);
859
 
860
    for (r=fnl->finddirs; r; r=r->next)
861
        fnl->numdirs++;
862
    for (r=fnl->findfiles; r; r=r->next)
863
        fnl->numfiles++;
864
 
865
    return(0);
866
}
867
 
868
 
3269 terminx 869
// loads all group (grp, zip, pk3/4) files in the given directory
2555 helixhorne 870
void G_LoadGroupsInDir(const char *dirname)
871
{
3269 terminx 872
    static const char *extensions[4] = { "*.grp", "*.zip", "*.pk3", "*.pk4" };
2555 helixhorne 873
 
874
    char buf[BMAX_PATH];
875
    int32_t i;
876
 
877
    fnlist_t fnlist = FNLIST_INITIALIZER;
878
 
3269 terminx 879
    for (i=0; i<4; i++)
2555 helixhorne 880
    {
881
        CACHE1D_FIND_REC *rec;
882
 
883
        fnlist_getnames(&fnlist, dirname, extensions[i], -1, 0);
884
 
885
        for (rec=fnlist.findfiles; rec; rec=rec->next)
886
        {
887
            Bsnprintf(buf, sizeof(buf), "%s/%s", dirname, rec->name);
888
            initprintf("Using group file \"%s\".\n", buf);
889
            initgroupfile(buf);
890
        }
891
 
892
        fnlist_clearnames(&fnlist);
893
    }
894
}
895
 
896
void G_DoAutoload(const char *dirname)
897
{
898
    char buf[BMAX_PATH];
899
 
900
    Bsnprintf(buf, sizeof(buf), "autoload/%s", dirname);
901
    G_LoadGroupsInDir(buf);
902
}
2560 helixhorne 903
 
904
////
905
 
906
// returns a buffer of size BMAX_PATH
907
char *dup_filename(const char *fn)
908
{
4491 helixhorne 909
    char *buf = (char *)Xmalloc(BMAX_PATH);
2560 helixhorne 910
 
911
    return Bstrncpyz(buf, fn, BMAX_PATH);
912
}
3004 helixhorne 913
 
914
 
915
// Copy FN to WBUF and append an extension if it's not there, which is checked
916
// case-insensitively.
917
// Returns: 1 if not all characters could be written to WBUF, 0 else.
918
int32_t maybe_append_ext(char *wbuf, int32_t wbufsiz, const char *fn, const char *ext)
919
{
920
    const int32_t slen=Bstrlen(fn), extslen=Bstrlen(ext);
921
    const int32_t haveext = (slen>=extslen && Bstrcasecmp(&fn[slen-extslen], ext)==0);
922
 
923
    Bassert((intptr_t)wbuf != (intptr_t)fn);  // no aliasing
924
 
925
    // If 'fn' has no extension suffixed, append one.
926
    return (Bsnprintf(wbuf, wbufsiz, "%s%s", fn, haveext ? "" : ext) >= wbufsiz);
927
}
3243 helixhorne 928
 
929
 
3489 helixhorne 930
// Approximations to 2D and 3D Euclidean distances. Initial EDuke32 SVN import says
3243 helixhorne 931
// in jmact/mathutil.c: "Ken's reverse-engineering job".
932
// Note that jmact/mathutil.c contains practically the same code, but where the
933
// individual x/y(/z) distances are passed instead.
934
int32_t ldist(const spritetype *s1, const spritetype *s2)
935
{
936
    int32_t x = klabs(s1->x-s2->x);
937
    int32_t y = klabs(s1->y-s2->y);
938
 
939
    if (x<y) swaplong(&x,&y);
940
 
941
    {
942
        int32_t t = y + (y>>1);
943
        return (x - (x>>5) - (x>>7)  + (t>>2) + (t>>6));
944
    }
945
}
946
 
947
int32_t dist(const spritetype *s1, const spritetype *s2)
948
{
949
    int32_t x = klabs(s1->x-s2->x);
950
    int32_t y = klabs(s1->y-s2->y);
951
    int32_t z = klabs((s1->z-s2->z)>>4);
952
 
953
    if (x<y) swaplong(&x,&y);
954
    if (x<z) swaplong(&x,&z);
955
 
956
    {
957
        int32_t t = y + z;
958
        return (x - (x>>4) + (t>>2) + (t>>3));
959
    }
960
}
3321 helixhorne 961
 
962
 
963
// Clear OSD background
964
void COMMON_clearbackground(int32_t numcols, int32_t numrows)
965
{
966
    UNREFERENCED_PARAMETER(numcols);
967
 
968
# ifdef USE_OPENGL
3784 terminx 969
    if (getrendermode() >= REND_POLYMOST && qsetmode==200)
3321 helixhorne 970
    {
4408 helixhorne 971
        bglPushAttrib(GL_FOG_BIT);
972
        bglDisable(GL_FOG);
973
 
3321 helixhorne 974
        setpolymost2dview();
975
        bglColor4f(0,0,0,0.67f);
976
        bglEnable(GL_BLEND);
977
        bglRectd(0,0, xdim,8*numrows+8);
978
        bglColor4f(0,0,0,1);
979
        bglRectd(0,8*numrows+4, xdim,8*numrows+8);
4408 helixhorne 980
 
981
        bglPopAttrib();
982
 
3321 helixhorne 983
        return;
984
    }
985
# endif
986
 
987
    CLEARLINES2D(0, min(ydim, numrows*8+8), editorcolors[16]);
988
}