1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1996, 2005 - 3D Realms Entertainment
4
5 This file is NOT part of Shadow Warrior version 1.2
6 However, it is either an older version of a file that is, or is
7 some test code written during the development of Shadow Warrior.
8 This file is provided purely for educational interest.
9
10 Shadow Warrior is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19 See the GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
25 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
26 */
27 //-------------------------------------------------------------------------
28
29 // scriplib.c
30 #include "build.h"
31 #include "editor.h"
32 #include "cache1d.h"
33
34 #include "names2.h"
35 #include "game.h"
36
37 #include "parse.h"
38
39 #define PATHSEPERATOR '\\'
40
41
42 //#define COMPUTE_TOTALS 1
43
44 /*
45 =============================================================================
46
47 ABNORMAL TERMINATION
48
49 =============================================================================
50 */
Error(const char * error,...)51 void Error(const char *error, ...)
52 {
53 va_list argptr;
54
55 va_start(argptr,error);
56 vprintf(error,argptr);
57 va_end(argptr);
58 printf("\n");
59 exit(1);
60 }
61
62
63
64 /*
65 =============================================================================
66
67 PARSING STUFF
68
69 =============================================================================
70 */
71
72 char token[MAXTOKEN];
73 char *scriptbuffer,*script_p,*scriptend_p;
74 int grabbed;
75 int scriptline;
76 SWBOOL endofscript;
77 SWBOOL tokenready; // only TRUE if UnGetToken was just called
78
79 /*
80 ==============
81 =
82 = LoadScriptFile
83 =
84 ==============
85 */
86
LoadScriptFile(const char * filename)87 SWBOOL LoadScriptFile(const char *filename)
88 {
89 int size, readsize;
90 int fp;
91
92
93 if ((fp=kopen4load(filename,0)) == -1)
94 {
95 // If there's no script file, forget it.
96 return FALSE;
97 }
98
99 size = kfilelength(fp);
100
101 scriptbuffer = (char *)Xmalloc(size);
102
103 ASSERT(scriptbuffer != NULL);
104
105 readsize = kread(fp, scriptbuffer, size);
106
107 kclose(fp);
108
109 ASSERT(readsize == size);
110
111
112 // Convert filebuffer to all upper case
113 //Bstrupr(scriptbuffer);
114
115 script_p = scriptbuffer;
116 scriptend_p = script_p + size;
117 scriptline = 1;
118 endofscript = FALSE;
119 tokenready = FALSE;
120 return TRUE;
121 }
122
123
124 /*
125 ==============
126 =
127 = UnGetToken
128 =
129 = Signals that the current token was not used, and should be reported
130 = for the next GetToken. Note that
131
132 GetToken (TRUE);
133 UnGetToken ();
134 GetToken (FALSE);
135
136 = could cross a line boundary.
137 =
138 ==============
139 */
140
UnGetToken(void)141 void UnGetToken(void)
142 {
143 tokenready = TRUE;
144 }
145
146
147 /*
148 ==============
149 =
150 = GetToken
151 =
152 ==============
153 */
154
GetToken(SWBOOL crossline)155 void GetToken(SWBOOL crossline)
156 {
157 char *token_p;
158
159 if (tokenready) // is a token already waiting?
160 {
161 tokenready = FALSE;
162 return;
163 }
164
165 if (script_p >= scriptend_p)
166 {
167 if (!crossline)
168 Error("Line %i is incomplete\n",scriptline);
169 endofscript = TRUE;
170 return;
171 }
172
173 //
174 // skip space
175 //
176 skipspace:
177 while (*script_p <= 32)
178 {
179 if (script_p >= scriptend_p)
180 {
181 if (!crossline)
182 Error("Line %i is incomplete\n",scriptline);
183 endofscript = TRUE;
184 return;
185 }
186 if (*script_p++ == '\n')
187 {
188 if (!crossline)
189 Error("Line %i is incomplete\n",scriptline);
190 scriptline++;
191 }
192 }
193
194 if (script_p >= scriptend_p)
195 {
196 if (!crossline)
197 Error("Line %i is incomplete\n",scriptline);
198 endofscript = TRUE;
199 return;
200 }
201
202 if (*script_p == '#') // # is comment field
203 {
204 if (!crossline)
205 Error("Line %i is incomplete\n",scriptline);
206 while (*script_p++ != '\n')
207 if (script_p >= scriptend_p)
208 {
209 endofscript = TRUE;
210 return;
211 }
212 goto skipspace;
213 }
214
215 //
216 // copy token
217 //
218 token_p = token;
219
220 while (*script_p > 32 && *script_p != '#')
221 {
222 *token_p++ = *script_p++;
223 if (script_p == scriptend_p)
224 break;
225 ASSERT(token_p != &token[MAXTOKEN]);
226 // Error ("Token too large on line %i\n",scriptline);
227 }
228
229 *token_p = 0;
230 }
231
232
233 /*
234 ==============
235 =
236 = TokenAvailable
237 =
238 = Returns true if there is another token on the line
239 =
240 ==============
241 */
242
TokenAvailable(void)243 SWBOOL TokenAvailable(void)
244 {
245 char *search_p;
246
247 search_p = script_p;
248
249 if (search_p >= scriptend_p)
250 return FALSE;
251
252 while (*search_p <= 32)
253 {
254 if (*search_p == '\n')
255 return FALSE;
256 search_p++;
257 if (search_p == scriptend_p)
258 return FALSE;
259
260 }
261
262 if (*search_p == '#')
263 return FALSE;
264
265 return TRUE;
266 }
267
DefaultExtension(char * path,char * extension)268 void DefaultExtension(char *path, char *extension)
269 {
270 char *src;
271 //
272 // if path doesn't have a .EXT, append extension
273 // (extension should include the .)
274 //
275 src = path + strlen(path) - 1;
276
277 while (*src != '\\' && src != path)
278 {
279 if (*src == '.')
280 return; // it has an extension
281 src--;
282 }
283
284 strcat(path, extension);
285 }
286
287
DefaultPath(char * path,char * basepath)288 void DefaultPath(char *path, char *basepath)
289 {
290 char temp[128];
291
292 if (path[0] == '\\')
293 return; // absolute path location
294 strcpy(temp,path);
295 strcpy(path,basepath);
296 strcat(path,temp);
297 }
298
299
StripFilename(char * path)300 void StripFilename(char *path)
301 {
302 int length;
303
304 length = strlen(path)-1;
305 while (length > 0 && path[length] != PATHSEPERATOR)
306 length--;
307 path[length] = 0;
308 }
309
310
ExtractFileBase(char * path,char * dest)311 void ExtractFileBase(char *path, char *dest)
312 {
313 char *src;
314 int length;
315
316 src = path + strlen(path) - 1;
317
318 //
319 // back up until a \ or the start
320 //
321 while (src != path && *(src-1) != '\\')
322 src--;
323
324 //
325 // copy up to eight characters
326 //
327 memset(dest,0,8);
328 length = 0;
329 while (*src && *src != '.')
330 {
331 if (++length == 9)
332 Error("Filename base of %s >8 chars",path);
333 *dest++ = toupper(*src++);
334 }
335 }
336
337
338 /*
339 ==============
340 =
341 = ParseNum / ParseHex
342 =
343 ==============
344 */
345
ParseHex(char * hex)346 int ParseHex(char *hex)
347 {
348 char *str;
349 int num;
350
351 num = 0;
352 str = hex;
353
354 while (*str)
355 {
356 num <<= 4;
357 if (*str >= '0' && *str <= '9')
358 num += *str-'0';
359 else if (*str >= 'a' && *str <= 'f')
360 num += 10 + *str-'a';
361 else if (*str >= 'A' && *str <= 'F')
362 num += 10 + *str-'A';
363 else
364 Error("Bad hex number: %s",hex);
365 str++;
366 }
367
368 return num;
369 }
370
371
ParseNum(char * str)372 int ParseNum(char *str)
373 {
374 if (str[0] == '$')
375 return ParseHex(str+1);
376 if (str[0] == '0' && str[1] == 'x')
377 return ParseHex(str+2);
378 return atol(str);
379 }
380
381
382
383
384 // voxelarray format is:
385 // spritenumber, voxelnumber
386 int aVoxelArray[MAXTILES];
387
388 // Load all the voxel files using swvoxfil.txt script file
389 // Script file format:
390
391 // # - Comment
392 // spritenumber (in artfile), voxel number, filename
393 // Ex. 1803 0 medkit2.kvx
394 // 1804 1 shotgun.kvx
395 // etc....
396
LoadKVXFromScript(const char * filename)397 void LoadKVXFromScript(const char *filename)
398 {
399 int lNumber=0,lTile=0; // lNumber is the voxel no. and lTile is the editart tile being
400 // replaced.
401 char *sName; // KVS file being loaded in.
402
403 int grabbed=0; // Number of lines parsed
404
405 sName = (char *)Xmalloc(256); // Up to 256 bytes for path
406 ASSERT(sName != NULL);
407
408 // zero out the array memory with -1's for pics not being voxelized
409 memset(aVoxelArray,-1,sizeof(aVoxelArray));
410
411 // Load the file
412 if (!LoadScriptFile(filename)) return;
413
414 do
415 {
416 GetToken(TRUE); // Crossing a line boundary on the end of line to first token
417 // of a new line is permitted (and expected)
418 if (endofscript)
419 break;
420
421 lTile = atol(token);
422
423 GetToken(FALSE);
424 lNumber = atol(token);
425
426 GetToken(FALSE);
427 strcpy(sName,token); // Copy the whole token as a file name and path
428
429 // Load the voxel file into memory
430 if (!qloadkvx(lNumber,sName))
431 {
432 // Store the sprite and voxel numbers for later use
433 aVoxelArray[lTile] = lNumber; // Voxel num
434 }
435
436 if (lNumber >= nextvoxid) // JBF: so voxels in the def file append to the list
437 nextvoxid = lNumber + 1;
438
439 grabbed++;
440 ASSERT(grabbed < MAXSPRITES);
441
442 }
443 while (script_p < scriptend_p);
444
445 Xfree(scriptbuffer);
446 script_p = NULL;
447 }
448
449
450 /// MISC ////////////////////////////////////////////////////////////////////
451
452 /*
453 extern int idleclock,slackerclock;
454
455 // Watch dog function. Tracks user's work times.
456 void LogUserTime( SWBOOL bIsLoggingIn )
457 {
458 int size, readsize;
459 time_t time_of_day;
460 char serialid[20],filename[100],fbase[20],buf[26],filetemp[100];
461 FILE *fp;
462 int tothours, totmins, totsecs, gtotalclock=0,gidleclock=0;
463 ldiv_t mins_secs;
464 ldiv_t hrs_mins;
465 int i;
466
467 char path[] = "o:\\user\\jimn\\logs\\";
468 // char path[] = "c:\\jim\\sw\\";
469
470 memset(filename,0,sizeof(filename));
471 memset(fbase,0,sizeof(fbase));
472 memset(serialid,0,sizeof(serialid));
473 memset(buf,0,sizeof(buf));
474 memset(filetemp,0,sizeof(filetemp));
475
476 // Get the time of day user logged in to build
477 time_of_day = time( NULL );
478
479 // Get the serial number from the user's disk drive "it's unique!"
480 system("dir > serid.bld");
481 LoadScriptFile("serid.bld");
482
483 // Go to the serial number
484 for (i=0; i<11; i++)
485 {
486 GetToken (TRUE);
487 if (endofscript)
488 return;
489 }
490
491 // Copy the token to serialid
492 strcpy(serialid,token);
493
494 // Free the script memory when done
495 Xfree(scriptbuffer);
496 script_p = NULL;
497
498 // Build a file name using serial id.
499 strcpy(filename,path);
500 strncpy(fbase,serialid,8);
501 strcat(fbase,".bld");
502 strcat(filename,fbase);
503
504 // Delete the temp file
505 system("erase serid.bld");
506
507 // Unhide the file so it can be opened
508 _dos_setfileattr(filename,_A_NORMAL);
509
510
511 // Open the file
512 fp = fopen( filename, "a+" );
513
514 // Opening on the network failed, try putting it on the current disk drive
515 if(fp == NULL)
516 {
517 // Unhide the file so it can be opened/this works if file was created before!
518 _dos_setfileattr(fbase,_A_NORMAL);
519 fp = fopen( fbase, "a+" );
520 strcpy(filetemp,fbase);
521 } else
522 strcpy(filetemp,filename);
523
524
525 if( fp == NULL)
526 return;
527 else
528 {
529 if(bIsLoggingIn)
530 {
531 fprintf(fp, "//////////////////////////////\n");
532 fprintf(fp, "User logged into build at: %s", _ctime( &time_of_day, buf ) );
533 }else
534 {
535 totsecs = totalclock/120; // Convert totalclock to seconds.
536
537 mins_secs = ldiv( totsecs, 60L );
538 totmins = mins_secs.quot;
539 totsecs = mins_secs.rem;
540
541 hrs_mins = ldiv( totmins, 60L);
542 tothours = hrs_mins.quot;
543 totmins = hrs_mins.rem;
544
545 fprintf(fp, "TotalClock: %ld\n",totalclock);
546 #ifdef COMPUTE_TOTALS
547 fprintf(fp, "IdleClock: %ld\n",slackerclock);
548 #endif
549 fprintf(fp, "Time this session: %ld Hours %ld Mins %ld Secs\n",tothours,totmins,totsecs);
550 #ifdef COMPUTE_TOTALS
551 totsecs = (totalclock-slackerclock)/120; // Convert totalclock to seconds.
552 if(totsecs<=0) totsecs = 0;
553
554 mins_secs = ldiv( totsecs, 60L );
555 totmins = mins_secs.quot;
556 totsecs = mins_secs.rem;
557
558 hrs_mins = ldiv( totmins, 60L);
559 tothours = hrs_mins.quot;
560 totmins = hrs_mins.rem;
561 fprintf(fp, "Time - idleclock : %ld Hours %ld Mins %ld Secs\n",tothours,totmins,totsecs);
562 #endif
563 }
564
565 fclose( fp );
566 }
567
568 #if 1
569 if(!bIsLoggingIn)
570 {
571 // Compute total time for file
572 LoadScriptFile(filetemp);
573
574 do {
575 GetToken (TRUE);
576
577 if (endofscript)
578 break;
579
580 if(!strcmpi(token,"totalclock:"))
581 {
582 GetToken(TRUE);
583 gtotalclock += atol(token);
584 }
585 #if 0
586 if(!strcmpi(token,"idleclock:"))
587 {
588 GetToken(TRUE);
589 gidleclock += atol(token);
590 }
591 #endif
592
593 } while (script_p < scriptend_p);
594
595 // Free the script memory when done
596 Xfree(scriptbuffer);
597 script_p = NULL;
598
599 // Open the file
600 fp = fopen( filetemp, "a+" );
601
602 // Now compute the grand total
603 if(fp != NULL)
604 {
605 totsecs = gtotalclock/120; // Convert totalclock to seconds.
606
607 mins_secs = ldiv( totsecs, 60L );
608 totmins = mins_secs.quot;
609 totsecs = mins_secs.rem;
610
611 hrs_mins = ldiv( totmins, 60L);
612 tothours = hrs_mins.quot;
613 totmins = hrs_mins.rem;
614
615 fprintf(fp, "\nTotal time so far : %ld Hours %ld Mins %ld Secs\n",tothours,totmins,totsecs);
616
617 #if 0
618 totsecs = (gtotalclock-gidleclock)/120; // Convert totalclock to seconds.
619 if(totsecs<=0) totsecs = 0;
620
621 mins_secs = ldiv( totsecs, 60L );
622 totmins = mins_secs.quot;
623 totsecs = mins_secs.rem;
624
625 hrs_mins = ldiv( totmins, 60L);
626 tothours = hrs_mins.quot;
627 totmins = hrs_mins.rem;
628
629 fprintf(fp, "\nTotal actual time : %ld Hours %ld Mins %ld Secs\n",tothours,totmins,totsecs);
630 #endif
631
632 fclose(fp);
633 }
634 }
635 #endif
636
637 _dos_setfileattr(filename,_A_HIDDEN);
638
639
640 }
641 */
642