Subversion Repositories eduke32

Rev

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

Rev Author Line No. Line
5196 hendricks2 1
//-------------------------------------------------------------------------
2
/*
3
Copyright (C) 1997, 2005 - 3D Realms Entertainment
4
 
5
This file is part of Shadow Warrior version 1.2
6
 
7
Shadow Warrior is free software; you can redistribute it and/or
8
modify it under the terms of the GNU General Public License
9
as published by the Free Software Foundation; either version 2
10
of the License, or (at your option) any later version.
11
 
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
 
16
See the GNU General Public License for more details.
17
 
18
You should have received a copy of the GNU General Public License
19
along with this program; if not, write to the Free Software
20
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21
 
22
Original Source: 1997 - Frank Maddin and Jim Norwood
23
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24
*/
25
//-------------------------------------------------------------------------
26
 
27
// scriplib.c
28
#include "build.h"
29
#include "cache1d.h"
30
 
31
#include "keys.h"
32
#include "names2.h"
33
#include "panel.h"
34
#include "game.h"
35
 
36
#include "parse.h"
37
#include "sprite.h"
38
#include "jsector.h"
39
#include "parent.h"
40
 
41
#define PATHSEPERATOR   '\\'
42
 
43
//#define COMPUTE_TOTALS    1
44
 
45
ParentalStruct aVoxelArray[MAXTILES];
46
 
47
 
48
/*
49
=============================================================================
50
 
51
                        PARSING STUFF
52
 
53
=============================================================================
54
*/
55
 
56
char    token[MAXTOKEN];
57
char    *scriptbuffer,*script_p,*scriptend_p;
58
int     grabbed;
59
int     scriptline;
5198 hendricks2 60
SWBOOL    endofscript;
61
SWBOOL    tokenready;                     // only TRUE if UnGetToken was just called
5196 hendricks2 62
 
63
/*
64
==============
65
=
66
= LoadScriptFile
67
=
68
==============
69
*/
70
 
7499 hendricks2 71
SWBOOL LoadScriptFile(const char *filename)
5196 hendricks2 72
{
73
    int size, readsize;
74
    int fp;
75
 
76
 
77
    if ((fp=kopen4load(filename,0)) == -1)
78
    {
79
        // If there's no script file, forget it.
80
        return FALSE;
81
    }
82
 
83
    size = kfilelength(fp);
84
 
8347 hendricks2 85
    scriptbuffer = (char *)AllocMem(size+1);
5196 hendricks2 86
 
87
    ASSERT(scriptbuffer != NULL);
88
 
89
    readsize = kread(fp, scriptbuffer, size);
90
 
91
    kclose(fp);
92
 
93
    ASSERT(readsize == size);
94
 
8347 hendricks2 95
    scriptbuffer[readsize] = '\0';
5196 hendricks2 96
 
97
    // Convert filebuffer to all upper case
8283 hendricks2 98
    //Bstrupr(scriptbuffer);
5196 hendricks2 99
 
100
    script_p = scriptbuffer;
101
    scriptend_p = script_p + size;
102
    scriptline = 1;
103
    endofscript = FALSE;
104
    tokenready = FALSE;
105
    return TRUE;
106
}
107
 
108
 
109
/*
110
==============
111
=
112
= UnGetToken
113
=
114
= Signals that the current token was not used, and should be reported
115
= for the next GetToken.  Note that
116
 
117
GetToken (TRUE);
118
UnGetToken ();
119
GetToken (FALSE);
120
 
121
= could cross a line boundary.
122
=
123
==============
124
*/
125
 
126
void UnGetToken(void)
127
{
128
    tokenready = TRUE;
129
}
130
 
131
 
132
/*
133
==============
134
=
135
= GetToken
136
=
137
==============
138
*/
139
 
5198 hendricks2 140
void GetToken(SWBOOL crossline)
5196 hendricks2 141
{
142
    char    *token_p;
143
 
144
    if (tokenready)                         // is a token already waiting?
145
    {
146
        tokenready = FALSE;
147
        return;
148
    }
149
 
150
    if (script_p >= scriptend_p)
151
    {
152
        if (!crossline)
5225 hendricks2 153
            buildprintf("Error: Line %i is incomplete\n",scriptline);
5196 hendricks2 154
        endofscript = TRUE;
155
        return;
156
    }
157
 
158
//
159
// skip space
160
//
161
skipspace:
162
    while (*script_p <= 32)
163
    {
164
        if (script_p >= scriptend_p)
165
        {
166
            if (!crossline)
5225 hendricks2 167
                buildprintf("Error: Line %i is incomplete\n",scriptline);
5196 hendricks2 168
            endofscript = TRUE;
169
            return;
170
        }
171
        if (*script_p++ == '\n')
172
        {
173
            if (!crossline)
5225 hendricks2 174
                buildprintf("Error: Line %i is incomplete\n",scriptline);
5196 hendricks2 175
            scriptline++;
176
        }
177
    }
178
 
179
    if (script_p >= scriptend_p)
180
    {
181
        if (!crossline)
5225 hendricks2 182
            buildprintf("Error: Line %i is incomplete\n",scriptline);
5196 hendricks2 183
        endofscript = TRUE;
184
        return;
185
    }
186
 
187
    if (*script_p == '#')   // # is comment field
188
    {
189
        if (!crossline)
5225 hendricks2 190
            buildprintf("Error: Line %i is incomplete\n",scriptline);
5196 hendricks2 191
        while (*script_p++ != '\n')
192
            if (script_p >= scriptend_p)
193
            {
194
                endofscript = TRUE;
195
                return;
196
            }
197
        goto skipspace;
198
    }
199
 
200
//
201
// copy token
202
//
203
    token_p = token;
204
 
205
    while (*script_p > 32 && *script_p != '#')
206
    {
207
        *token_p++ = *script_p++;
208
        if (script_p == scriptend_p)
209
            break;
210
        ASSERT(token_p != &token[MAXTOKEN]);
5225 hendricks2 211
//          buildprintf("Error: Token too large on line %i\n",scriptline);
5196 hendricks2 212
    }
213
 
214
    *token_p = 0;
215
}
216
 
217
 
218
/*
219
==============
220
=
221
= TokenAvailable
222
=
223
= Returns true if there is another token on the line
224
=
225
==============
226
*/
227
 
5198 hendricks2 228
SWBOOL TokenAvailable(void)
5196 hendricks2 229
{
230
    char    *search_p;
231
 
232
    search_p = script_p;
233
 
234
    if (search_p >= scriptend_p)
235
        return FALSE;
236
 
237
    while (*search_p <= 32)
238
    {
239
        if (*search_p == '\n')
240
            return FALSE;
241
        search_p++;
242
        if (search_p == scriptend_p)
243
            return FALSE;
244
 
245
    }
246
 
247
    if (*search_p == '#')
248
        return FALSE;
249
 
250
    return TRUE;
251
}
252
 
253
 
254
// Load all the voxel files using swvoxfil.txt script file
255
// Script file format:
256
 
257
//          # - Comment
258
//          spritenumber (in artfile), voxel number, filename
259
//          Ex. 1803 0 medkit2.kvx
260
//              1804 1 shotgun.kvx
261
//              etc....
262
 
7499 hendricks2 263
void LoadKVXFromScript(const char *filename)
5196 hendricks2 264
{
265
    int lNumber=0,lTile=0; // lNumber is the voxel no. and lTile is the editart tile being
266
    // replaced.
267
    char *sName;            // KVS file being loaded in.
268
 
269
    int grabbed=0;          // Number of lines parsed
270
 
271
    sName = (char *)AllocMem(256);    // Up to 256 bytes for path
272
    ASSERT(sName != NULL);
273
 
274
    // zero out the array memory with -1's for pics not being voxelized
275
    memset(&aVoxelArray[0],-1,sizeof(struct TILE_INFO_TYPE)*MAXTILES);
276
    for (grabbed = 0; grabbed < MAXTILES; grabbed++)
277
    {
278
        aVoxelArray[grabbed].Voxel = -1;
279
        aVoxelArray[grabbed].Parental = -1;
280
    }
281
 
282
    grabbed = 0;
283
 
284
    // Load the file
285
    if (!LoadScriptFile(filename))
286
        ASSERT(TRUE==FALSE);
287
 
288
    do
289
    {
290
        GetToken(TRUE);     // Crossing a line boundary on the end of line to first token
291
        // of a new line is permitted (and expected)
292
        if (endofscript)
293
            break;
294
 
295
        lTile = atol(token);
296
 
297
        GetToken(FALSE);
298
        lNumber = atol(token);
299
 
300
        GetToken(FALSE);
301
        strcpy(sName,token);            // Copy the whole token as a file name and path
302
 
303
        // Load the voxel file into memory
304
        if (!qloadkvx(lNumber,sName))
305
        {
306
            // Store the sprite and voxel numbers for later use
307
            aVoxelArray[lTile].Voxel = lNumber; // Voxel num
308
        }
309
 
310
        if (lNumber >= nextvoxid)   // JBF: so voxels in the def file append to the list
311
            nextvoxid = lNumber + 1;
312
 
313
        grabbed++;
314
        ASSERT(grabbed < MAXSPRITES);
315
 
316
    }
317
    while (script_p < scriptend_p);
318
 
319
    FreeMem(scriptbuffer);
320
    FreeMem(sName);
321
    script_p = NULL;
322
}
323
 
324
// Load in info for all Parental lock tile targets
325
//          # - Comment
326
//          tilenumber (in artfile), replacement tile offset (if any)
327
//          Ex. 1803 -1       -1 = No tile replacement
328
//              1804 2000
329
//              etc....
7499 hendricks2 330
void LoadPLockFromScript(const char *filename)
5196 hendricks2 331
{
332
    int lNumber=0,lTile=0; // lNumber is the voxel no. and lTile is the editart tile being
333
    // replaced.
334
    char *sName;            // KVS file being loaded in.
335
 
336
    int grabbed=0;          // Number of lines parsed
337
 
338
    sName = (char *)AllocMem(256);    // Up to 256 bytes for path
339
    ASSERT(sName != NULL);
340
 
341
    // Load the file
342
    if (!LoadScriptFile(filename))
343
        ASSERT(TRUE==FALSE);
344
 
345
    do
346
    {
347
        GetToken(TRUE);     // Crossing a line boundary on the end of line to first token
348
        // of a new line is permitted (and expected)
349
        if (endofscript)
350
            break;
351
 
352
        lTile = atoi(token);
353
 
354
        GetToken(FALSE);
355
        lNumber = atoi(token);
356
 
357
        // Store the sprite and voxel numbers for later use
358
        aVoxelArray[lTile].Parental = lNumber;  // Replacement to tile, -1 for none
359
 
360
        grabbed++;
361
        ASSERT(grabbed < MAXSPRITES);
362
 
363
    }
364
    while (script_p < scriptend_p);
365
 
366
    FreeMem(scriptbuffer);
367
    FreeMem(sName);
368
    script_p = NULL;
369
}
370
 
371
 
372
/*
373
 * Here begins JonoF's modding enhancement stuff
374
 */
375
 
376
#include "scriptfile.h"
377
 
378
enum
379
{
380
    CM_MAP,
381
    CM_EPISODE,
382
    CM_TITLE,
383
    CM_FILENAME,
384
    CM_SONG,
385
    CM_CDATRACK,
386
    CM_BESTTIME,
387
    CM_PARTIME,
388
    CM_SUBTITLE,
389
    CM_SKILL,
390
    CM_TEXT,
391
    CM_COOKIE,
392
    CM_GOTKEY,
393
    CM_NEEDKEY,
394
    CM_INVENTORY,
395
    CM_AMOUNT,
396
    CM_WEAPON,
397
    CM_AMMONAME,
398
    CM_MAXAMMO,
399
    CM_DAMAGEMIN,
400
    CM_DAMAGEMAX,
401
    CM_SECRET,
402
    CM_QUIT,
403
};
404
 
405
static const struct _tokset
406
{
7499 hendricks2 407
    const char *str;
5196 hendricks2 408
    int tokn;
409
} cm_tokens[] =
410
{
411
    { "map",         CM_MAP       },
412
    { "level",       CM_MAP       },
413
    { "episode",     CM_EPISODE   },
414
    { "skill",       CM_SKILL     },
415
    { "cookie",      CM_COOKIE    },
416
    { "fortune",     CM_COOKIE    },
417
    { "gotkey",      CM_GOTKEY    },
418
    { "inventory",   CM_INVENTORY },
419
    { "weapon",      CM_WEAPON    },
420
    { "needkey",     CM_NEEDKEY   },
421
    { "secret",      CM_SECRET    },
422
    { "quit",        CM_QUIT      },
423
},
424
  cm_map_tokens[] =
425
{
426
    { "title",       CM_TITLE     },
427
    { "name",        CM_TITLE     },
428
    { "description", CM_TITLE     },
429
    { "filename",    CM_FILENAME  },
430
    { "file",        CM_FILENAME  },
431
    { "fn",          CM_FILENAME  },
432
    { "levelname",   CM_FILENAME  },
433
    { "song",        CM_SONG      },
434
    { "music",       CM_SONG      },
435
    { "songname",    CM_SONG      },
436
    { "cdatrack",    CM_CDATRACK  },
437
    { "cdtrack",     CM_CDATRACK  },
438
    { "besttime",    CM_BESTTIME  },
439
    { "partime",     CM_PARTIME   },
440
},
441
  cm_episode_tokens[] =
442
{
443
    { "title",       CM_TITLE     },
444
    { "name",        CM_TITLE     },
445
    { "description", CM_TITLE     },
446
    { "subtitle",    CM_SUBTITLE  },
447
},
448
  cm_skill_tokens[] =
449
{
450
    { "title",       CM_TITLE     },
451
    { "name",        CM_TITLE     },
452
    { "description", CM_TITLE     },
453
},
454
  cm_inventory_tokens[] =
455
{
456
    { "title",       CM_TITLE     },
457
    { "name",        CM_TITLE     },
458
    { "description", CM_TITLE     },
459
    { "amount",      CM_AMOUNT    },
460
},
461
  cm_weapons_tokens[] =
462
{
463
    { "title",       CM_TITLE     },
464
    { "name",        CM_TITLE     },
465
    { "description", CM_TITLE     },
466
    { "ammoname",    CM_AMMONAME  },
467
    { "maxammo",     CM_MAXAMMO   },
468
    { "mindamage",   CM_DAMAGEMIN },
469
    { "maxdamage",   CM_DAMAGEMAX },
470
    { "pickup",      CM_AMOUNT    },
471
    { "weaponpickup",CM_WEAPON    },
472
}
473
;
474
#define cm_numtokens           (sizeof(cm_tokens)/sizeof(cm_tokens[0]))
475
#define cm_map_numtokens       (sizeof(cm_map_tokens)/sizeof(cm_map_tokens[0]))
476
#define cm_episode_numtokens   (sizeof(cm_episode_tokens)/sizeof(cm_episode_tokens[0]))
477
#define cm_skill_numtokens     (sizeof(cm_skill_tokens)/sizeof(cm_skill_tokens[0]))
478
#define cm_inventory_numtokens (sizeof(cm_inventory_tokens)/sizeof(cm_inventory_tokens[0]))
479
#define cm_weapons_numtokens   (sizeof(cm_weapons_tokens)/sizeof(cm_weapons_tokens[0]))
480
 
481
 
482
static int cm_transtok(const char *tok, const struct _tokset *set, const unsigned num)
483
{
484
    unsigned i;
485
 
486
    for (i=0; i<num; i++)
487
    {
488
        if (!Bstrcasecmp(tok, set[i].str))
489
            return set[i].tokn;
490
    }
491
 
492
    return -1;
493
}
494
 
495
// Load custom map and episode information
496
//   level # {
497
//      title    "Map Name"
498
//      filename "filename.map"
499
//      song     "filename.mid"
500
//      cdatrack n
501
//      besttime secs
502
//      partime  secs
503
//   }
504
//
505
//   episode # {
506
//      title    "Episode Name"
507
//      subtitle "Caption text"
508
//   }
509
//
510
//   skill # {
511
//      name "Tiny grasshopper"
512
//   }
513
//
514
//   fortune {
515
//      "You never going to score."
516
//      "26-31-43-82-16-29"
517
//      "Sorry, you no win this time, try again."
518
//   }
519
//   gotkey {
520
//      "Got the RED key!"
521
//      "Got the BLUE key!"
522
//      "Got the GREEN key!"
523
//      ...
524
//   }
525
//   needkey {
526
//      "You need a RED key for this door."
527
//      "You need a BLUE key for this door."
528
//      "You need a GREEN key for this door."
529
//      ...
530
//   }
531
//   inventory # { name "Armour" amount 50 }
532
//   weapon # { name "Uzi Submachine Gun" ammoname "Uzi Clip" maxammo 200 mindamage 5 maxdamage 7 pickup 50 }
533
//   secret  "You found a secret area!"
534
//   quit    "PRESS (Y) TO QUIT, (N) TO FIGHT ON."
535
 
536
static LEVEL_INFO custommaps[MAX_LEVELS_REG];
537
static char *customfortune[MAX_FORTUNES];
538
static char *customkeymsg[MAX_KEYS];
539
static char *customkeydoormsg[MAX_KEYS];
540
static char *custominventoryname[InvDecl_TOTAL];
541
static char *customweaponname[2][MAX_WEAPONS];  // weapon, ammo
542
 
543
#define WM_DAMAGE  1
544
#define WM_WEAP   2
545
#define WM_AMMO   4
546
static struct
547
{
7499 hendricks2 548
    const char *sym;
5196 hendricks2 549
    int dmgid;
550
    int editable;
551
} weaponmap[] =
552
{
553
    { "WPN_FIST",       WPN_FIST,        WM_DAMAGE },
554
    { "WPN_SWORD",      WPN_SWORD,       WM_DAMAGE },
555
    { "WPN_SHURIKEN",   WPN_STAR,        WM_DAMAGE|WM_WEAP },
556
    { "WPN_STICKYBOMB", WPN_MINE,        WM_DAMAGE|WM_WEAP },
557
    { "WPN_UZI",        WPN_UZI,         WM_DAMAGE|WM_WEAP|WM_AMMO },
558
    { "WPN_MISSILE",    WPN_MICRO,       WM_DAMAGE|WM_WEAP|WM_AMMO },
559
    { "WPN_NUKE",       DMG_NUCLEAR_EXP, WM_DAMAGE|WM_WEAP|WM_AMMO },
560
    { "WPN_GRENADE",    WPN_GRENADE,     WM_DAMAGE|WM_WEAP|WM_AMMO },
561
    { "WPN_RAILGUN",    WPN_RAIL,        WM_DAMAGE|WM_WEAP|WM_AMMO },
562
    { "WPN_SHOTGUN",    WPN_SHOTGUN,     WM_DAMAGE|WM_WEAP|WM_AMMO },
563
    { "WPN_HOTHEAD",    WPN_HOTHEAD,     WM_DAMAGE|WM_WEAP },
564
    { "WPN_HEART",      WPN_HEART,       WM_DAMAGE|WM_WEAP },
565
    { "WPN_HOTHEAD_NAPALM", WPN_NAPALM,  WM_DAMAGE },
566
    { "WPN_HOTHEAD_RING",   WPN_RING,    WM_DAMAGE },
567
};
568
 
569
// FIXME: yes, we are leaking memory here at the end of the program by not freeing anything
7499 hendricks2 570
void LoadCustomInfoFromScript(const char *filename)
5196 hendricks2 571
{
572
    scriptfile *script;
573
    char *token;
574
    char *braceend;
575
    int curmap = -1;
576
 
577
    script = scriptfile_fromfile(filename);
578
    if (!script) return;
579
 
580
    // predefine constants for some stuff to give convenience and eliminate the need for a 'define' directive
581
    scriptfile_addsymbolvalue("INV_ARMOR",      1+InvDecl_Armor);
582
    scriptfile_addsymbolvalue("INV_KEVLAR",     1+InvDecl_Kevlar);
583
    scriptfile_addsymbolvalue("INV_SM_MEDKIT",  1+InvDecl_SmMedkit);
584
    scriptfile_addsymbolvalue("INV_FORTUNE",    1+InvDecl_Booster);
585
    scriptfile_addsymbolvalue("INV_MEDKIT",     1+InvDecl_Medkit);
586
    scriptfile_addsymbolvalue("INV_GAS_BOMB",   1+InvDecl_ChemBomb);
587
    scriptfile_addsymbolvalue("INV_FLASH_BOMB", 1+InvDecl_FlashBomb);
588
    scriptfile_addsymbolvalue("INV_CALTROPS",   1+InvDecl_Caltrops);
589
    scriptfile_addsymbolvalue("INV_NIGHT_VIS",  1+InvDecl_NightVision);
590
    scriptfile_addsymbolvalue("INV_REPAIR_KIT", 1+InvDecl_RepairKit);
591
    scriptfile_addsymbolvalue("INV_SMOKE_BOMB", 1+InvDecl_Cloak);
592
 
593
    {
594
        unsigned i;
595
        for (i=0; i<SIZ(weaponmap); i++)
596
            scriptfile_addsymbolvalue(weaponmap[i].sym, 1+i);
597
    }
598
 
599
    while ((token = scriptfile_gettoken(script)))
600
    {
601
        switch (cm_transtok(token, cm_tokens, cm_numtokens))
602
        {
603
        case CM_MAP:
604
        {
605
            char *mapnumptr;
7532 hendricks2 606
            if (scriptfile_getnumber(script, &curmap)) break;
607
            mapnumptr = script->ltextptr;
5196 hendricks2 608
            if (scriptfile_getbraces(script, &braceend)) break;
609
 
610
            // first map file in LevelInfo[] is bogus, last map file is NULL
611
            if (curmap < 1 || curmap > MAX_LEVELS_REG)
612
            {
613
                buildprintf("Error: map number %d not in range 1-%d on line %s:%d\n",
614
                            curmap, MAX_LEVELS_REG, script->filename,
615
                            scriptfile_getlinum(script,mapnumptr));
616
                script->textptr = braceend;
617
                break;
618
            }
619
 
620
            while (script->textptr < braceend)
621
            {
622
                if (!(token = scriptfile_gettoken(script))) break;
623
                if (token == braceend) break;
624
                switch (cm_transtok(token, cm_map_tokens, cm_map_numtokens))
625
                {
626
                case CM_FILENAME:
627
                {
628
                    char *t;
629
                    if (scriptfile_getstring(script, &t)) break;
630
 
7508 hendricks2 631
                    //Bfree(custommaps[curmap].LevelName);
5196 hendricks2 632
                    custommaps[curmap].LevelName = strdup(t);
633
                    LevelInfo[curmap].LevelName = custommaps[curmap].LevelName;
634
                    break;
635
                }
636
                case CM_SONG:
637
                {
638
                    char *t;
639
                    if (scriptfile_getstring(script, &t)) break;
640
 
7508 hendricks2 641
                    //Bfree(custommaps[curmap].SongName);
5196 hendricks2 642
                    custommaps[curmap].SongName = strdup(t);
643
                    LevelInfo[curmap].SongName = custommaps[curmap].SongName;
644
                    break;
645
                }
646
                case CM_TITLE:
647
                {
648
                    char *t;
649
                    if (scriptfile_getstring(script, &t)) break;
650
 
7508 hendricks2 651
                    //Bfree(custommaps[curmap].Description);
5196 hendricks2 652
                    custommaps[curmap].Description = strdup(t);
653
                    LevelInfo[curmap].Description = custommaps[curmap].Description;
654
                    break;
655
                }
656
                case CM_BESTTIME:
657
                {
658
                    int n;
659
                    char s[10];
660
                    if (scriptfile_getnumber(script, &n)) break;
661
 
662
                    Bsnprintf(s, 10, "%d : %02d", n/60, n%60);
7508 hendricks2 663
                    //Bfree(custommaps[curmap].BestTime);
5196 hendricks2 664
                    custommaps[curmap].BestTime = strdup(s);
665
                    LevelInfo[curmap].BestTime = custommaps[curmap].BestTime;
666
                    break;
667
                }
668
                case CM_PARTIME:
669
                {
670
                    int n;
671
                    char s[10];
672
                    if (scriptfile_getnumber(script, &n)) break;
673
 
674
                    Bsnprintf(s, 10, "%d : %02d", n/60, n%60);
7508 hendricks2 675
                    //Bfree(custommaps[curmap].ParTime);
5196 hendricks2 676
                    custommaps[curmap].ParTime = strdup(s);
677
                    LevelInfo[curmap].ParTime = custommaps[curmap].ParTime;
678
                    break;
679
                }
680
                case CM_CDATRACK:
681
                {
682
                    int n;
683
                    if (scriptfile_getnumber(script, &n)) break;
684
                    break;
685
                }
686
                default:
687
                    buildprintf("Error on line %s:%d\n",
688
                                script->filename,
689
                                scriptfile_getlinum(script,script->ltextptr));
690
                    break;
691
                }
692
            }
693
            break;
694
        }
695
 
696
        case CM_EPISODE:
697
        {
698
            char *epnumptr;
7532 hendricks2 699
            if (scriptfile_getnumber(script, &curmap)) break;
700
            epnumptr = script->ltextptr;
5196 hendricks2 701
            if (scriptfile_getbraces(script, &braceend)) break;
702
 
703
            // first map file in LevelInfo[] is bogus, last map file is NULL
704
            if ((unsigned)--curmap >= 2u)
705
            {
706
                buildprintf("Error: episode number %d not in range 1-2 on line %s:%d\n",
707
                            curmap, script->filename,
708
                            scriptfile_getlinum(script,epnumptr));
709
                script->textptr = braceend;
710
                break;
711
            }
712
 
713
            while (script->textptr < braceend)
714
            {
715
                if (!(token = scriptfile_gettoken(script))) break;
716
                if (token == braceend) break;
717
                switch (cm_transtok(token, cm_episode_tokens, cm_episode_numtokens))
718
                {
719
                case CM_TITLE:
720
                {
721
                    char *t;
722
                    if (scriptfile_getstring(script, &t)) break;
723
 
724
                    strncpy(&EpisodeNames[curmap][1], t, MAX_EPISODE_NAME_LEN);
725
                    EpisodeNames[curmap][MAX_EPISODE_NAME_LEN+1] = 0;
726
                    break;
727
                }
728
                case CM_SUBTITLE:
729
                {
730
                    char *t;
731
                    if (scriptfile_getstring(script, &t)) break;
732
 
733
                    strncpy(EpisodeSubtitles[curmap], t, MAX_EPISODE_SUBTITLE_LEN);
734
                    EpisodeSubtitles[curmap][MAX_EPISODE_SUBTITLE_LEN] = 0;
735
                    break;
736
                }
737
                default:
738
                    buildprintf("Error on line %s:%d\n",
739
                                script->filename,
740
                                scriptfile_getlinum(script,script->ltextptr));
741
                    break;
742
                }
743
            }
744
            break;
745
        }
746
 
747
        case CM_SKILL:
748
        {
749
            char *epnumptr;
7532 hendricks2 750
            if (scriptfile_getnumber(script, &curmap)) break;
751
            epnumptr = script->ltextptr;
5196 hendricks2 752
            if (scriptfile_getbraces(script, &braceend)) break;
753
 
754
            // first map file in LevelInfo[] is bogus, last map file is NULL
755
            if ((unsigned)--curmap >= 4u)
756
            {
757
                buildprintf("Error: skill number %d not in range 1-4 on line %s:%d\n",
758
                            curmap, script->filename,
759
                            scriptfile_getlinum(script,epnumptr));
760
                script->textptr = braceend;
761
                break;
762
            }
763
 
764
            while (script->textptr < braceend)
765
            {
766
                if (!(token = scriptfile_gettoken(script))) break;
767
                if (token == braceend) break;
768
                switch (cm_transtok(token, cm_skill_tokens, cm_skill_numtokens))
769
                {
770
                case CM_TITLE:
771
                {
772
                    char *t;
773
                    if (scriptfile_getstring(script, &t)) break;
774
 
775
                    strncpy(&SkillNames[curmap][1], t, MAX_SKILL_NAME_LEN);
776
                    SkillNames[curmap][MAX_SKILL_NAME_LEN+1] = 0;
777
                    break;
778
                }
779
                default:
780
                    buildprintf("Error on line %s:%d\n",
781
                                script->filename,
782
                                scriptfile_getlinum(script,script->ltextptr));
783
                    break;
784
                }
785
            }
786
            break;
787
        }
788
 
789
        case CM_COOKIE:
790
        {
791
            char *t;
792
            int fc = 0;
793
 
794
            if (scriptfile_getbraces(script, &braceend)) break;
795
 
796
            while (script->textptr < braceend)
797
            {
798
                if (scriptfile_getstring(script, &t)) break;
799
 
800
                if (fc == MAX_FORTUNES) continue;
801
 
802
                customfortune[fc] = strdup(t);
803
                if (customfortune[fc]) ReadFortune[fc] = customfortune[fc];
804
                fc++;
805
            }
806
            break;
807
        }
808
        case CM_GOTKEY:
809
        {
810
            char *t;
811
            int fc = 0;
812
 
813
            if (scriptfile_getbraces(script, &braceend)) break;
814
 
815
            while (script->textptr < braceend)
816
            {
817
                if (scriptfile_getstring(script, &t)) break;
818
 
819
                if (fc == MAX_KEYS) continue;
820
 
821
                customkeymsg[fc] = strdup(t);
822
                if (customkeymsg[fc]) KeyMsg[fc] = customkeymsg[fc];
823
                fc++;
824
            }
825
            break;
826
        }
827
        case CM_NEEDKEY:
828
        {
829
            char *t;
830
            int fc = 0;
831
 
832
            if (scriptfile_getbraces(script, &braceend)) break;
833
 
834
            while (script->textptr < braceend)
835
            {
836
                if (scriptfile_getstring(script, &t)) break;
837
 
838
                if (fc == MAX_KEYS) continue;
839
 
840
                customkeydoormsg[fc] = strdup(t);
841
                if (customkeydoormsg[fc]) KeyDoorMessage[fc] = customkeydoormsg[fc];
842
                fc++;
843
            }
844
            break;
845
        }
846
        case CM_INVENTORY:
847
        {
848
            char *invtokptr = script->ltextptr, *invnumptr;
849
            int in;
850
            char *name = NULL;
851
            int amt = -1;
852
 
7532 hendricks2 853
            if (scriptfile_getsymbol(script, &in)) break;
854
            invnumptr = script->ltextptr;
5196 hendricks2 855
            if (scriptfile_getbraces(script, &braceend)) break;
856
 
857
            if ((unsigned)--in >= (unsigned)InvDecl_TOTAL)
858
            {
859
                buildprintf("Error: inventory item number not in range 1-%d on line %s:%d\n",
860
                            InvDecl_TOTAL, script->filename,
861
                            scriptfile_getlinum(script,invnumptr));
862
                script->textptr = braceend;
863
                break;
864
            }
865
 
866
            while (script->textptr < braceend)
867
            {
868
                if (!(token = scriptfile_gettoken(script))) break;
869
                if (token == braceend) break;
870
                switch (cm_transtok(token, cm_inventory_tokens, cm_inventory_numtokens))
871
                {
872
                case CM_TITLE:
873
                    if (scriptfile_getstring(script, &name)) break;
874
                    break;
875
                case CM_AMOUNT:
876
                    if (scriptfile_getnumber(script, &amt)) break;
877
                    break;
878
                default:
879
                    buildprintf("Error on line %s:%d\n",
880
                                script->filename,
881
                                scriptfile_getlinum(script,script->ltextptr));
882
                    break;
883
                }
884
            }
885
 
886
            if (name)
887
            {
5352 hendricks2 888
                Bfree(custominventoryname[in]);
5196 hendricks2 889
                custominventoryname[in] = strdup(name);
890
                InventoryDecls[in].name = custominventoryname[in];
891
            }
892
            if (amt >= 0)
893
            {
894
                InventoryDecls[in].amount = amt;
895
            }
896
            break;
897
        }
898
        case CM_WEAPON:
899
        {
900
            char *wpntokptr = script->ltextptr, *wpnnumptr;
901
            char *name = NULL, *ammo = NULL;
902
            int maxammo = -1, damagemin = -1, damagemax = -1, pickup = -1, wpickup = -1;
903
            int in,id;
904
 
7532 hendricks2 905
            if (scriptfile_getsymbol(script, &in)) break;
906
            wpnnumptr = script->ltextptr;
5196 hendricks2 907
            if (scriptfile_getbraces(script, &braceend)) break;
908
 
909
            if ((unsigned)--in >= (unsigned)SIZ(weaponmap))
910
            {
911
                buildprintf("Error: weapon number not in range 1-%d on line %s:%d\n",
912
                            (int)SIZ(weaponmap), script->filename,
913
                            scriptfile_getlinum(script,wpnnumptr));
914
                script->textptr = braceend;
915
                break;
916
            }
917
 
918
            while (script->textptr < braceend)
919
            {
920
                if (!(token = scriptfile_gettoken(script))) break;
921
                if (token == braceend) break;
922
                switch (cm_transtok(token, cm_weapons_tokens, cm_weapons_numtokens))
923
                {
924
                case CM_TITLE:
925
                    if (scriptfile_getstring(script, &name)) break;
926
                    break;
927
                case CM_AMMONAME:
928
                    if (scriptfile_getstring(script, &ammo)) break;
929
                    break;
930
                case CM_MAXAMMO:
931
                    if (scriptfile_getnumber(script, &maxammo)) break;
932
                    break;
933
                case CM_DAMAGEMIN:
934
                    if (scriptfile_getnumber(script, &damagemin)) break;
935
                    break;
936
                case CM_DAMAGEMAX:
937
                    if (scriptfile_getnumber(script, &damagemax)) break;
938
                    break;
939
                case CM_AMOUNT:
940
                    if (scriptfile_getnumber(script, &pickup)) break;
941
                    break;
942
                case CM_WEAPON:
943
                    if (scriptfile_getnumber(script, &wpickup)) break;
944
                    break;
945
                default:
946
                    buildprintf("Error on line %s:%d\n",
947
                                script->filename,
948
                                scriptfile_getlinum(script,script->ltextptr));
949
                    break;
950
                }
951
            }
952
            id = weaponmap[in].dmgid;
953
            if (weaponmap[in].editable & WM_DAMAGE)
954
            {
955
                if (damagemin >= 0) DamageData[id].damage_lo = damagemin;
956
                if (damagemax >= 0) DamageData[id].damage_hi = damagemax;
957
            }
958
            if (weaponmap[in].editable & WM_WEAP)
959
            {
960
                if (maxammo >= 0) DamageData[id].max_ammo = maxammo;
961
                if (name)
962
                {
5352 hendricks2 963
                    Bfree(customweaponname[0][id]);
5196 hendricks2 964
                    customweaponname[0][id] = strdup(name);
965
                    DamageData[id].weapon_name = customweaponname[0][id];
966
                }
967
                if (wpickup >= 0) DamageData[id].weapon_pickup = wpickup;
968
            }
969
            if (weaponmap[in].editable & WM_AMMO)
970
            {
971
                if (ammo)
972
                {
5352 hendricks2 973
                    Bfree(customweaponname[1][id]);
5196 hendricks2 974
                    customweaponname[1][id] = strdup(ammo);
975
                    DamageData[id].ammo_name = customweaponname[1][id];
976
                }
977
                if (pickup >= 0) DamageData[id].ammo_pickup = pickup;
978
            }
979
            break;
980
        }
981
        case CM_SECRET:
982
        case CM_QUIT:
983
        default:
984
            buildprintf("Error on line %s:%d\n",
985
                        script->filename,
986
                        scriptfile_getlinum(script,script->ltextptr));
987
            break;
988
        }
989
    }
990
 
991
    scriptfile_close(script);
992
    scriptfile_clearsymbols();
993
}
994