~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to terps/alan2/main.c

  • Committer: Package Import Robot
  • Author(s): Sylvain Beucler
  • Date: 2013-07-28 13:38:56 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20130728133856-4k6uc864wzsnrx04
Tags: 2011.1a-1
* New upstream release
* Alan 2 interpreter is now Free Software, include it
* Update fonts package names in dependencies (Closes: #715160)
* Bump Standards-Version to 3.9.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*----------------------------------------------------------------------*\
 
2
 
 
3
  MAIN.C
 
4
 
 
5
  Main module of interpreter for ALAN Adventure Language
 
6
 
 
7
\*----------------------------------------------------------------------*/
 
8
 
 
9
#define V27COMPATIBLE
 
10
 
 
11
#include "sysdep.h"
 
12
 
 
13
#include "types.h"
 
14
#include "main.h"
 
15
 
 
16
#include <time.h>
 
17
#ifdef USE_READLINE
 
18
#include "readline.h"
 
19
#endif
 
20
 
 
21
#ifdef HAVE_SHORT_FILENAMES
 
22
#include "av.h"
 
23
#else
 
24
#include "alan.version.h"
 
25
#endif
 
26
 
 
27
#include "args.h"
 
28
#include "parse.h"
 
29
#include "inter.h"
 
30
#include "rules.h"
 
31
#ifdef REVERSED
 
32
#include "reverse.h"
 
33
#endif
 
34
#include "debug.h"
 
35
#include "stack.h"
 
36
#include "exe.h"
 
37
#include "term.h"
 
38
 
 
39
#ifdef GLK
 
40
#include "glk.h"
 
41
#include "glkio.h"
 
42
#endif
 
43
 
 
44
/* PUBLIC DATA */
 
45
 
 
46
/* The Amachine memory */
 
47
Aword *memory;
 
48
static AcdHdr dummyHeader;      /* Dummy to use until memory allocated */
 
49
AcdHdr *header = &dummyHeader;
 
50
 
 
51
int memTop = 0;                 /* Top of load memory */
 
52
 
 
53
int conjWord;                   /* First conjunction in dictonary, for ',' */
 
54
 
 
55
 
 
56
/* Amachine variables */
 
57
CurVars cur;
 
58
 
 
59
/* Amachine structures */
 
60
WrdElem *dict;                  /* Dictionary pointer */
 
61
ActElem *acts;                  /* Actor table pointer */
 
62
LocElem *locs;                  /* Location table pointer */
 
63
VrbElem *vrbs;                  /* Verb table pointer */
 
64
StxElem *stxs;                  /* Syntax table pointer */
 
65
ObjElem *objs;                  /* Object table pointer */
 
66
CntElem *cnts;                  /* Container table pointer */
 
67
RulElem *ruls;                  /* Rule table pointer */
 
68
EvtElem *evts;                  /* Event table pointer */
 
69
MsgElem *msgs;                  /* Message table pointer */
 
70
Aword *scores;                  /* Score table pointer */
 
71
Aword *freq;                    /* Cumulative character frequencies */
 
72
 
 
73
int dictsize;
 
74
 
 
75
Boolean verbose = FALSE;
 
76
Boolean errflg = TRUE;
 
77
Boolean trcflg = FALSE;
 
78
Boolean dbgflg = FALSE;
 
79
Boolean stpflg = FALSE;
 
80
Boolean logflg = FALSE;
 
81
Boolean statusflg = TRUE;
 
82
Boolean fail = FALSE;
 
83
Boolean anyOutput = FALSE;
 
84
 
 
85
 
 
86
/* The files and filenames */
 
87
char *advnam;
 
88
FILE *txtfil;
 
89
FILE *logfil;
 
90
 
 
91
 
 
92
/* Screen formatting info */
 
93
int col, lin;
 
94
int paglen, pagwidth;
 
95
 
 
96
Boolean needsp = FALSE;
 
97
Boolean skipsp = FALSE;
 
98
 
 
99
/* Restart jump buffer */
 
100
jmp_buf restart_label;
 
101
 
 
102
 
 
103
/* PRIVATE DATA */
 
104
static jmp_buf jmpbuf;          /* Error return long jump buffer */
 
105
 
 
106
 
 
107
 
 
108
/*======================================================================
 
109
 
 
110
  terminate()
 
111
 
 
112
  Terminate the execution of the adventure, e.g. close windows,
 
113
  return buffers...
 
114
 
 
115
 */
 
116
#ifdef _PROTOTYPES_
 
117
void terminate(int code)
 
118
#else
 
119
void terminate(code)
 
120
     int code;
 
121
#endif
 
122
{
 
123
#ifdef __amiga__
 
124
#ifdef AZTEC_C
 
125
#include <fcntl.h>
 
126
  extern struct _dev *_devtab;
 
127
  char buf[85];
 
128
  
 
129
  if (con) { /* Running from WB, created a console so kill it */
 
130
    /* Running from WB, so we created a console and
 
131
       hacked the Aztec C device table to use it for all I/O
 
132
       so now we need to make it close it (once!) */
 
133
    _devtab[1].fd = _devtab[2].fd = 0;
 
134
  } else
 
135
#else
 
136
  /* Geek Gadgets GCC */
 
137
#include <workbench/startup.h>
 
138
#include <clib/dos_protos.h>
 
139
#include <clib/intuition_protos.h>
 
140
 
 
141
  if (_WBenchMsg != NULL) {
 
142
    Close(window);
 
143
    if (_WBenchMsg->sm_ArgList != NULL)
 
144
      UnLock(CurrentDir(cd));
 
145
  } else
 
146
#endif
 
147
#endif
 
148
    newline();
 
149
  free(memory);
 
150
  if (logflg)
 
151
    fclose(logfil);
 
152
 
 
153
#ifdef __MWERKS__
 
154
  printf("Command-Q to close window.");
 
155
#endif
 
156
 
 
157
#ifdef GLK
 
158
  glk_exit();
 
159
#else
 
160
  exit(code);
 
161
#endif
 
162
}
 
163
 
 
164
/*======================================================================
 
165
 
 
166
  usage()
 
167
 
 
168
  */
 
169
#ifdef _PROTOTYPES_
 
170
void usage(void)
 
171
#else
 
172
void usage()
 
173
#endif
 
174
{
 
175
  printf("Usage:\n\n");
 
176
  printf("    %s [<switches>] <adventure>\n\n", PROGNAME);
 
177
  printf("where the possible optional switches are:\n");
 
178
#ifdef GLK
 
179
  glk_set_style(style_Preformatted);
 
180
#endif
 
181
  printf("    -v    verbose mode\n");
 
182
  printf("    -l    log player commands and game output to a file\n");
 
183
  printf("    -i    ignore version and checksum errors\n");
 
184
  printf("    -n    no Status Line\n");
 
185
  printf("    -d    enter debug mode\n");
 
186
  printf("    -t    trace game execution\n");
 
187
  printf("    -s    single instruction trace\n");
 
188
#ifdef GLK
 
189
  glk_set_style(style_Normal);
 
190
#endif
 
191
}
 
192
 
 
193
 
 
194
/*======================================================================
 
195
 
 
196
  syserr()
 
197
 
 
198
  Print a little text blaming the user for the system error.
 
199
 
 
200
 */
 
201
#ifdef _PROTOTYPES_
 
202
void syserr(char *str)
 
203
#else
 
204
void syserr(str)
 
205
     char *str;
 
206
#endif
 
207
{
 
208
  output("$n$nAs you enter the twilight zone of Adventures, you stumble \
 
209
and fall to your knees. In front of you, you can vaguely see the outlines \
 
210
of an Adventure that never was.$n$nSYSTEM ERROR: ");
 
211
  output(str);
 
212
  output("$n$n");
 
213
 
 
214
  if (logflg)
 
215
    fclose(logfil);
 
216
  newline();
 
217
 
 
218
#ifdef __amiga__
 
219
#ifdef AZTEC_C
 
220
  {
 
221
    char buf[80];
 
222
 
 
223
    if (con) { /* Running from WB, wait for user ack. */
 
224
      printf("press RETURN to quit");
 
225
      gets(buf);
 
226
    }
 
227
  }
 
228
#endif
 
229
#endif
 
230
 
 
231
  terminate(0);
 
232
}
 
233
 
 
234
 
 
235
/*======================================================================
 
236
 
 
237
  error()
 
238
 
 
239
  Print an error message, force new player input and abort.
 
240
 
 
241
  */
 
242
#ifdef _PROTOTYPES_
 
243
void error(MsgKind msgno)       /* IN - The error message number */
 
244
#else
 
245
void error(msgno)
 
246
     MsgKind msgno;             /* IN - The error message number */
 
247
#endif
 
248
{
 
249
  if (msgno != MSGMAX)
 
250
    prmsg(msgno);
 
251
  wrds[wrdidx] = EOF;           /* Force new player input */
 
252
  dscrstkp = 0;                 /* Reset describe stack */
 
253
  longjmp(jmpbuf,TRUE);
 
254
}
 
255
 
 
256
 
 
257
/*======================================================================
 
258
 
 
259
  statusline()
 
260
 
 
261
  Print the the status line on the top of the screen.
 
262
 
 
263
  */
 
264
void statusline(void)
 
265
{
 
266
#ifdef GLK
 
267
  glui32 glkWidth;
 
268
  char line[100];
 
269
  int pcol = col;
 
270
  int i;
 
271
 
 
272
  if (NULL == glkStatusWin)
 
273
    return;
 
274
 
 
275
  glk_set_window(glkStatusWin);
 
276
  glk_window_clear(glkStatusWin);
 
277
  glk_window_get_size(glkStatusWin, &glkWidth, NULL);
 
278
 
 
279
  glk_set_style(style_User1);
 
280
  for (i = 0; i < glkWidth; i++)
 
281
    glk_put_char(' ');
 
282
 
 
283
  col = 1;
 
284
  glk_window_move_cursor(glkStatusWin, 1, 0);
 
285
needsp = FALSE;
 
286
  say(where(HERO));
 
287
  if (header->maxscore > 0)
 
288
    sprintf(line, "Score %d(%d)/%d moves", cur.score, (int)header->maxscore, cur.tick);
 
289
  else
 
290
    sprintf(line, "%d moves", cur.tick);
 
291
  glk_window_move_cursor(glkStatusWin, glkWidth - col - strlen(line), 0);
 
292
  printf(line);
 
293
  needsp = FALSE;
 
294
 
 
295
  col = pcol;
 
296
 
 
297
  glk_set_window(glkMainWin); 
 
298
#else
 
299
#ifdef HAVE_ANSI
 
300
  char line[100];
 
301
  int i;
 
302
  int pcol = col;
 
303
 
 
304
  if (!statusflg) return;
 
305
  /* ansi_position(1,1); ansi_bold_on(); */
 
306
  printf("\x1b[1;1H");
 
307
  printf("\x1b[7m");
 
308
  col = 1;
 
309
  say(where(HERO));
 
310
  if (header->maxscore > 0)
 
311
    sprintf(line, "Score %ld(%ld)/%ld moves", cur.score, (int)header->maxscore, cur.tick);
 
312
  else
 
313
    sprintf(line, "%ld moves", cur.tick);
 
314
  for (i=0; i < pagwidth - col - strlen(line); i++) putchar(' ');
 
315
  printf(line);
 
316
  printf("\x1b[m");
 
317
  printf("\x1b[%d;1H", paglen);
 
318
  needsp = FALSE;
 
319
 
 
320
  col = pcol;
 
321
#endif
 
322
#endif
 
323
}
 
324
 
 
325
 
 
326
/*======================================================================
 
327
 
 
328
  logprint()
 
329
 
 
330
  Print some text and log it if logging is on.
 
331
 
 
332
 */
 
333
void logprint(char str[])
 
334
{
 
335
  printf(str);
 
336
  if (logflg)
 
337
    fprintf(logfil, "%s", str);
 
338
}
 
339
 
 
340
 
 
341
 
 
342
/*======================================================================
 
343
 
 
344
  newline()
 
345
 
 
346
  Make a newline, but check for screen full.
 
347
 
 
348
 */
 
349
#ifdef _PROTOTYPES_
 
350
void newline(void)
 
351
#else
 
352
void newline()
 
353
#endif
 
354
{
 
355
#ifdef GLK
 
356
  glk_put_char('\n');
 
357
#else
 
358
  char buf[256];
 
359
  
 
360
  col = 1;
 
361
  if (lin >= paglen - 1) {
 
362
    logprint("\n");
 
363
    needsp = FALSE;
 
364
    prmsg(M_MORE);
 
365
#ifdef USE_READLINE
 
366
    (void) readline(buf);
 
367
#else
 
368
    fgets(buf, 256, stdin);
 
369
#endif
 
370
    getPageSize();
 
371
    lin = 0;
 
372
  } else
 
373
    logprint("\n");
 
374
  
 
375
  lin++;
 
376
  needsp = FALSE;
 
377
#endif
 
378
}
 
379
 
 
380
 
 
381
/*======================================================================
 
382
 
 
383
  para()
 
384
 
 
385
  Make a new paragraph, i.e one empty line (one or two newlines).
 
386
 
 
387
 */
 
388
#ifdef _PROTOTYPES_
 
389
void para(void)
 
390
#else
 
391
void para()
 
392
#endif
 
393
{
 
394
  if (col != 1)
 
395
    newline();
 
396
  newline();
 
397
}
 
398
 
 
399
 
 
400
/*======================================================================
 
401
 
 
402
  clear()
 
403
 
 
404
  Clear the screen.
 
405
 
 
406
 */
 
407
#ifdef _PROTOTYPES_
 
408
void clear(void)
 
409
#else
 
410
void clear()
 
411
#endif
 
412
{
 
413
#ifdef GLK
 
414
  glk_window_clear(glkMainWin);
 
415
#else
 
416
#ifdef HAVE_ANSI
 
417
  if (!statusflg) return;
 
418
  printf("\x1b[2J");
 
419
  printf("\x1b[%d;1H", paglen);
 
420
#endif
 
421
#endif
 
422
}
 
423
 
 
424
 
 
425
/*======================================================================
 
426
 
 
427
  allocate()
 
428
 
 
429
  Safely allocate new memory.
 
430
 
 
431
*/
 
432
#ifdef _PROTOTYPES_
 
433
void *allocate(unsigned long len)               /* IN - Length to allocate */
 
434
#else
 
435
void *allocate(len)
 
436
     unsigned long len;                 /* IN - Length to allocate */
 
437
#endif
 
438
{
 
439
  void *p = (void *)malloc((size_t)len);
 
440
 
 
441
  if (p == NULL)
 
442
    syserr("Out of memory.");
 
443
 
 
444
  return p;
 
445
}
 
446
 
 
447
 
 
448
/*----------------------------------------------------------------------
 
449
 
 
450
  just()
 
451
 
 
452
  Justify a string so that it wraps at end of screen.
 
453
 
 
454
 */
 
455
#ifdef _PROTOTYPES_
 
456
static void just(char str[])
 
457
#else
 
458
static void just(str)
 
459
     char str[];
 
460
#endif
 
461
{
 
462
#ifdef GLK
 
463
  logprint(str);
 
464
#else
 
465
  int i;
 
466
  char ch;
 
467
  
 
468
  if (col >= pagwidth && !skipsp)
 
469
    newline();
 
470
 
 
471
  while (strlen(str) > pagwidth - col) {
 
472
    i = pagwidth - col - 1;
 
473
    while (!isSpace(str[i]) && i > 0) /* First find wrap point */
 
474
      i--;
 
475
    if (i == 0 && col == 1)     /* If it doesn't fit at all */
 
476
      /* Wrap immediately after this word */
 
477
      while (!isSpace(str[i]) && str[i] != '\0')
 
478
        i++;
 
479
    if (i > 0) {                /* If it fits ... */
 
480
      ch = str[i];              /* Save space or NULL */
 
481
      str[i] = '\0';            /* Terminate string */
 
482
      logprint(str);            /* and print it */
 
483
      skipsp = FALSE;           /* If skipping, now we're done */
 
484
      str[i] = ch;              /* Restore character */
 
485
      /* Skip white after printed portion */
 
486
      for (str = &str[i]; isSpace(str[0]) && str[0] != '\0'; str++);
 
487
    }
 
488
    newline();                  /* Then start a new line */
 
489
  }
 
490
  logprint(str);                        /* Print tail */
 
491
  col = col + strlen(str);      /* Update column */
 
492
#endif
 
493
}
 
494
 
 
495
 
 
496
/*----------------------------------------------------------------------
 
497
 
 
498
  space()
 
499
 
 
500
  Output a space if needed.
 
501
 
 
502
 */
 
503
#ifdef _PROTOTYPES_
 
504
static void space(void)
 
505
#else
 
506
static void space()
 
507
#endif
 
508
{
 
509
  if (skipsp)
 
510
    skipsp = FALSE;
 
511
  else {
 
512
    if (needsp) {
 
513
      logprint(" ");
 
514
      col++;
 
515
    }
 
516
  }
 
517
  needsp = FALSE;
 
518
}
 
519
 
 
520
 
 
521
 
 
522
/*----------------------------------------------------------------------
 
523
 
 
524
  sayparam()
 
525
 
 
526
  A parameter needs to be said, check for words the player used and use
 
527
  them if possible.
 
528
 
 
529
*/
 
530
#ifdef _PROTOTYPES_
 
531
static void sayparam(int p)
 
532
#else
 
533
static void sayparam(p)
 
534
     int p;
 
535
#endif
 
536
{
 
537
  int i;
 
538
 
 
539
  for (i = 0; i <= p; i++)
 
540
    if (params[i].code == EOF)
 
541
      syserr("Nonexistent parameter referenced.");
 
542
 
 
543
  if (params[p].firstWord == EOF) /* Any words he used? */
 
544
    say(params[p].code);
 
545
  else                          /* Yes, so use them... */
 
546
    for (i = params[p].firstWord; i <= params[p].lastWord; i++) {
 
547
      just((char *)addrTo(dict[wrds[i]].wrd));
 
548
      if (i < params[p].lastWord)
 
549
        just(" ");
 
550
    }
 
551
}
 
552
 
 
553
 
 
554
/*----------------------------------------------------------------------
 
555
 
 
556
  prsym()
 
557
 
 
558
  Print an expanded symbolic reference.
 
559
 
 
560
  N = newline
 
561
  I = indent on a new line
 
562
  P = new paragraph
 
563
  L = current location name
 
564
  O = current object -> first parameter!
 
565
  V = current verb
 
566
  A = current actor
 
567
  T = tabulation
 
568
  $ = no space needed after this
 
569
 */
 
570
#ifdef _PROTOTYPES_
 
571
static void prsym(
 
572
                  char *str     /* IN - The string starting with '$' */
 
573
)
 
574
#else
 
575
static void prsym(str)
 
576
     char *str;                 /* IN - The string starting with '$' */
 
577
#endif
 
578
{
 
579
  switch (toLower(str[1])) {
 
580
  case 'n':
 
581
    newline();
 
582
    needsp = FALSE;
 
583
    break;
 
584
  case 'i':
 
585
    newline();
 
586
    logprint("    ");
 
587
    col = 5;
 
588
    needsp = FALSE;
 
589
    break;
 
590
  case 'o':
 
591
    sayparam(0);
 
592
    needsp = TRUE;              /* We did print something non-white */
 
593
    break;
 
594
  case '1':
 
595
  case '2':
 
596
  case '3':
 
597
  case '4':
 
598
  case '5':
 
599
  case '6':
 
600
  case '7':
 
601
  case '8':
 
602
  case '9':
 
603
    sayparam(str[1]-'1');
 
604
    needsp = TRUE;              /* We did print something non-white */
 
605
    break;
 
606
  case 'l':
 
607
    say(cur.loc);
 
608
    needsp = TRUE;              /* We did print something non-white */
 
609
    break;
 
610
  case 'a':
 
611
    say(cur.act);
 
612
    needsp = TRUE;              /* We did print something non-white */
 
613
    break;
 
614
  case 'v':
 
615
    just((char *)addrTo(dict[vrbwrd].wrd));
 
616
    needsp = TRUE;              /* We did print something non-white */
 
617
    break;
 
618
  case 'p':
 
619
    para();
 
620
    needsp = FALSE;
 
621
    break;
 
622
  case 't': {
 
623
    int i;
 
624
    int spaces = 4-(col-1)%4;
 
625
    
 
626
    for (i = 0; i<spaces; i++) logprint(" ");
 
627
    col = col + spaces;
 
628
    needsp = FALSE;
 
629
    break;
 
630
  }
 
631
  case '$':
 
632
    skipsp = TRUE;
 
633
    break;
 
634
  default:
 
635
    logprint("$");
 
636
    break;
 
637
  }
 
638
}
 
639
 
 
640
 
 
641
 
 
642
/*======================================================================
 
643
 
 
644
  output()
 
645
 
 
646
  Output a string to suit the screen. Any symbolic inserts ('$') are
 
647
  recogniced and performed.
 
648
 
 
649
 */
 
650
#ifdef _PROTOTYPES_
 
651
void output(char original[])
 
652
#else
 
653
void output(original)
 
654
     char original[];
 
655
#endif
 
656
{
 
657
  char ch;
 
658
  char *str, *copy;
 
659
  char *symptr;
 
660
 
 
661
  copy = strdup(original);
 
662
  str = copy;
 
663
 
 
664
  if (str[0] != '$' || str[1] != '$')
 
665
    space();                    /* Output space if needed (& not inhibited) */
 
666
 
 
667
  while ((symptr = strchr(str, '$')) != (char *) NULL) {
 
668
    ch = *symptr;               /* Terminate before symbol */
 
669
    *symptr = '\0';
 
670
    if (strlen(str) > 0) {
 
671
      just(str);                /* Output part before '$' */
 
672
      if (str[strlen(str)-1] == ' ')
 
673
        needsp = FALSE;
 
674
    }
 
675
    *symptr = ch;               /* restore '$' */
 
676
    prsym(symptr);              /* Print the symbolic reference */
 
677
    str = &symptr[2];           /* Advance to after symbol and continue */
 
678
  }
 
679
  if (str[0] != 0) {
 
680
    just(str);                  /* Output trailing part */
 
681
    skipsp = FALSE;
 
682
    if (str[strlen(str)-1] != ' ')
 
683
      needsp = TRUE;
 
684
  }
 
685
  anyOutput = TRUE;
 
686
  free(copy);
 
687
}
 
688
 
 
689
 
 
690
/*======================================================================
 
691
 
 
692
  prmsg()
 
693
 
 
694
  Print a message from the message table.
 
695
  
 
696
  */
 
697
#ifdef _PROTOTYPES_
 
698
void prmsg(MsgKind msg)         /* IN - message number */
 
699
#else
 
700
void prmsg(msg)
 
701
     MsgKind msg;               /* IN - message number */
 
702
#endif
 
703
{
 
704
  interpret(msgs[msg].stms);
 
705
}
 
706
 
 
707
 
 
708
/*----------------------------------------------------------------------*\
 
709
 
 
710
  Various check functions
 
711
 
 
712
  endOfTable()
 
713
  isObj, isLoc, isAct, IsCnt & isNum
 
714
 
 
715
\*----------------------------------------------------------------------*/
 
716
 
 
717
/* How to know we are at end of a table */
 
718
#ifdef _PROTOTYPES_
 
719
Boolean eot(Aword *adr)
 
720
#else
 
721
Boolean eot(adr)
 
722
     Aword *adr;
 
723
#endif
 
724
{
 
725
  return *adr == EOF;
 
726
}
 
727
 
 
728
 
 
729
#ifdef _PROTOTYPES_
 
730
Boolean isObj(Aword x)
 
731
#else
 
732
Boolean isObj(x)
 
733
     Aword x;
 
734
#endif
 
735
{
 
736
  return x >= OBJMIN && x <= OBJMAX;
 
737
}
 
738
 
 
739
#ifdef _PROTOTYPES_
 
740
Boolean isCnt(Aword x)
 
741
#else
 
742
Boolean isCnt(x)
 
743
     Aword x;
 
744
#endif
 
745
{
 
746
  return (x >= CNTMIN && x <= CNTMAX) ||
 
747
    (isObj(x) && objs[x-OBJMIN].cont != 0) ||
 
748
    (isAct(x) && acts[x-ACTMIN].cont != 0);
 
749
}
 
750
 
 
751
#ifdef _PROTOTYPES_
 
752
Boolean isAct(Aword x)
 
753
#else
 
754
Boolean isAct(x)
 
755
     Aword x;
 
756
#endif
 
757
{
 
758
  return x >= ACTMIN && x <= ACTMAX;
 
759
}
 
760
 
 
761
#ifdef _PROTOTYPES_
 
762
Boolean isLoc(Aword x)
 
763
#else
 
764
Boolean isLoc(x)
 
765
     Aword x;
 
766
#endif
 
767
{
 
768
  return x >= LOCMIN && x <= LOCMAX;
 
769
}
 
770
 
 
771
#ifdef _PROTOTYPES_
 
772
Boolean isNum(Aword x)
 
773
#else
 
774
Boolean isNum(x)
 
775
     Aword x;
 
776
#endif
 
777
{
 
778
  return x >= LITMIN && x <= LITMAX && litValues[x-LITMIN].type == TYPNUM;
 
779
}
 
780
 
 
781
#ifdef _PROTOTYPES_
 
782
Boolean isStr(Aword x)
 
783
#else
 
784
Boolean isStr(x)
 
785
     Aword x;
 
786
#endif
 
787
{
 
788
  return x >= LITMIN && x <= LITMAX && litValues[x-LITMIN].type == TYPSTR;
 
789
}
 
790
 
 
791
#ifdef _PROTOTYPES_
 
792
Boolean isLit(Aword x)
 
793
#else
 
794
Boolean isLit(x)
 
795
     Aword x;
 
796
#endif
 
797
{
 
798
  return x >= LITMIN && x <= LITMAX;
 
799
}
 
800
 
 
801
 
 
802
 
 
803
/*======================================================================
 
804
 
 
805
  exitto()
 
806
 
 
807
  Is there an exit from one location to another?
 
808
 
 
809
  */
 
810
#ifdef _PROTOTYPES_
 
811
Boolean exitto(int to, int from)
 
812
#else
 
813
Boolean exitto(to, from)
 
814
     int to, from;
 
815
#endif
 
816
{
 
817
  ExtElem *ext;
 
818
 
 
819
  if (locs[from-LOCMIN].exts == 0)
 
820
    return(FALSE); /* No exits */
 
821
 
 
822
  for (ext = (ExtElem *) addrTo(locs[from-LOCMIN].exts); !endOfTable(ext); ext++)
 
823
    if (ext->next == to)
 
824
      return(TRUE);
 
825
 
 
826
  return(FALSE);
 
827
}
 
828
    
 
829
      
 
830
 
 
831
#ifdef CHECKOBJ
 
832
/*======================================================================
 
833
 
 
834
  checkobj()
 
835
 
 
836
  Check that the object given is valid, else print an error message
 
837
  or find out what he wanted.
 
838
 
 
839
  This routine is not used any longer, kept for sentimental reasons ;-)
 
840
 
 
841
  */
 
842
void checkobj(obj)
 
843
     Aword *obj;
 
844
{
 
845
  Aword oldobj;
 
846
  
 
847
  if (*obj != EOF)
 
848
    return;
 
849
  
 
850
  oldobj = EOF;
 
851
  for (cur.obj = OBJMIN; cur.obj <= OBJMAX; cur.obj++) {
 
852
    /* If an object is present and it is possible to perform his action */
 
853
    if (isHere(cur.obj) && possible())
 
854
      if (oldobj == EOF)
 
855
        oldobj = cur.obj;
 
856
      else
 
857
        error(WANT);          /* And we didn't find multiple objects */
 
858
    }
 
859
  
 
860
  if (oldobj == EOF)
 
861
    error(WANT);              /* But we found ONE */
 
862
  
 
863
  *obj = cur.obj = oldobj;    
 
864
  output("($o)");             /* Then he surely meant this object */
 
865
}
 
866
#endif
 
867
 
 
868
 
 
869
 
 
870
 
 
871
/*----------------------------------------------------------------------
 
872
  count()
 
873
 
 
874
  Count the number of items in a container.
 
875
 
 
876
  */
 
877
#ifdef _PROTOTYPES_
 
878
static int count(int cnt)       /* IN - the container to count */
 
879
#else
 
880
static int count(cnt)
 
881
     int cnt;                   /* IN - the container to count */
 
882
#endif
 
883
{
 
884
  int i, j = 0;
 
885
  
 
886
  for (i = OBJMIN; i <= OBJMAX; i++)
 
887
    if (in(i, cnt))
 
888
      /* Then it's in this container also */
 
889
      j++;
 
890
  return(j);
 
891
}
 
892
 
 
893
 
 
894
 
 
895
/*----------------------------------------------------------------------
 
896
  sumatr()
 
897
 
 
898
  Sum the values of one attribute in a container. Recursively.
 
899
 
 
900
  */
 
901
#ifdef _PROTOTYPES_
 
902
static int sumatr(
 
903
     Aword atr,                 /* IN - the attribute to sum over */
 
904
     Aword cnt                  /* IN - the container to sum */
 
905
)
 
906
#else
 
907
static int sumatr(atr, cnt)
 
908
     Aword atr;                 /* IN - the attribute to sum over */
 
909
     Aword cnt;                 /* IN - the container to sum */
 
910
#endif
 
911
{
 
912
  int i;
 
913
  int sum = 0;
 
914
 
 
915
  for (i = OBJMIN; i <= OBJMAX; i++)
 
916
    if (objs[i-OBJMIN].loc == cnt) {    /* Then it's in this container */
 
917
      if (objs[i-OBJMIN].cont != 0)     /* This is also a container! */
 
918
        sum = sum + sumatr(atr, i);
 
919
      sum = sum + attribute(i, atr);
 
920
    }
 
921
  return(sum);
 
922
}
 
923
 
 
924
 
 
925
 
 
926
 
 
927
/*======================================================================
 
928
  checklim()
 
929
 
 
930
  Checks if a limit for a container is exceeded.
 
931
 
 
932
  */
 
933
#ifdef _PROTOTYPES_
 
934
Boolean checklim(
 
935
     Aword cnt,                 /* IN - Container code */
 
936
     Aword obj                  /* IN - The object to add */
 
937
)
 
938
#else
 
939
Boolean checklim(cnt, obj)
 
940
     Aword cnt;                 /* IN - Container code */
 
941
     Aword obj;                 /* IN - The object to add */
 
942
#endif
 
943
{
 
944
  LimElem *lim;
 
945
  Aword props;
 
946
 
 
947
  fail = TRUE;
 
948
  if (!isCnt(cnt))
 
949
    syserr("Checking limits for a non-container.");
 
950
 
 
951
  /* Find the container properties */
 
952
  if (isObj(cnt))
 
953
      props = objs[cnt-OBJMIN].cont;
 
954
  else if (isAct(cnt))
 
955
      props = acts[cnt-ACTMIN].cont;
 
956
  else
 
957
    props = cnt;
 
958
 
 
959
  if (cnts[props-CNTMIN].lims != 0) { /* Any limits at all? */
 
960
    for (lim = (LimElem *) addrTo(cnts[props-CNTMIN].lims); !endOfTable(lim); lim++)
 
961
      if (lim->atr == 0) {
 
962
        if (count(cnt) >= lim->val) {
 
963
          interpret(lim->stms);
 
964
          return(TRUE);         /* Limit check failed */
 
965
        }
 
966
      } else {
 
967
        if (sumatr(lim->atr, cnt) + attribute(obj, lim->atr) > lim->val) {
 
968
          interpret(lim->stms);
 
969
          return(TRUE);
 
970
        }
 
971
      }
 
972
  }
 
973
  fail = FALSE;
 
974
  return(FALSE);
 
975
}
 
976
 
 
977
 
 
978
 
 
979
 
 
980
 
 
981
/*----------------------------------------------------------------------*\
 
982
 
 
983
  Action routines
 
984
 
 
985
\*----------------------------------------------------------------------*/
 
986
 
 
987
 
 
988
 
 
989
/*----------------------------------------------------------------------
 
990
  trycheck()
 
991
 
 
992
  Tries a check, returns TRUE if it passed, FALSE else.
 
993
 
 
994
  */
 
995
#ifdef _PROTOTYPES_
 
996
static Boolean trycheck(
 
997
     Aaddr adr,                 /* IN - ACODE address to check table */
 
998
     Boolean act                /* IN - Act if it fails ? */
 
999
)
 
1000
#else
 
1001
static Boolean trycheck(adr, act)
 
1002
     Aaddr adr;                 /* IN - ACODE address to check table */
 
1003
     Boolean act;               /* IN - Act if it fails ? */
 
1004
#endif
 
1005
{
 
1006
  ChkElem *chk;
 
1007
 
 
1008
  chk = (ChkElem *) addrTo(adr);
 
1009
  if (chk->exp == 0) {
 
1010
    interpret(chk->stms);
 
1011
    return(FALSE);
 
1012
  } else {
 
1013
    while (!endOfTable(chk)) {
 
1014
      interpret(chk->exp);
 
1015
      if (!(Abool)pop()) {
 
1016
        if (act)
 
1017
          interpret(chk->stms);
 
1018
        return(FALSE);
 
1019
      }
 
1020
      chk++;
 
1021
    }
 
1022
    return(TRUE);
 
1023
  }
 
1024
}
 
1025
 
 
1026
 
 
1027
/*======================================================================
 
1028
  go()
 
1029
 
 
1030
  Move hero in a direction.
 
1031
 
 
1032
  */
 
1033
#ifdef _PROTOTYPES_
 
1034
void go(int dir)
 
1035
#else
 
1036
void go(dir)
 
1037
     int dir;
 
1038
#endif
 
1039
{
 
1040
  ExtElem *ext;
 
1041
  Boolean ok;
 
1042
  Aword oldloc;
 
1043
 
 
1044
  ext = (ExtElem *) addrTo(locs[cur.loc-LOCMIN].exts);
 
1045
  if (locs[cur.loc-LOCMIN].exts != 0)
 
1046
    while (!endOfTable(ext)) {
 
1047
      if (ext->code == dir) {
 
1048
        ok = TRUE;
 
1049
        if (ext->checks != 0) {
 
1050
          if (trcflg) {
 
1051
            printf("\n<EXIT %d (%s) from %d (", dir,
 
1052
                   (char *)addrTo(dict[wrds[wrdidx-1]].wrd), cur.loc);
 
1053
            debugsay(cur.loc);
 
1054
            printf("), Checking:>\n");
 
1055
          }
 
1056
          ok = trycheck(ext->checks, TRUE);
 
1057
        }
 
1058
        if (ok) {
 
1059
          oldloc = cur.loc;
 
1060
          if (ext->action != 0) {
 
1061
            if (trcflg) {
 
1062
              printf("\n<EXIT %d (%s) from %d (", dir, 
 
1063
                     (char *)addrTo(dict[wrds[wrdidx-1]].wrd), cur.loc);
 
1064
              debugsay(cur.loc);
 
1065
              printf("), Executing:>\n");
 
1066
            }       
 
1067
            interpret(ext->action);
 
1068
          }
 
1069
          /* Still at the same place? */
 
1070
          if (where(HERO) == oldloc) {
 
1071
            if (trcflg) {
 
1072
              printf("\n<EXIT %d (%s) from %d (", dir, 
 
1073
                     (char *)addrTo(dict[wrds[wrdidx-1]].wrd), cur.loc);
 
1074
              debugsay(cur.loc);
 
1075
              printf("), Moving:>\n");
 
1076
            }
 
1077
            locate(HERO, ext->next);
 
1078
          }
 
1079
        }
 
1080
        return;
 
1081
      }
 
1082
      ext++;
 
1083
    }
 
1084
  error(M_NO_WAY);
 
1085
}
 
1086
 
 
1087
 
 
1088
 
 
1089
/*----------------------------------------------------------------------
 
1090
 
 
1091
  findalt()
 
1092
 
 
1093
  Find the verb alternative wanted in a verb list and return
 
1094
  the address to it.
 
1095
 
 
1096
 */
 
1097
#ifdef _PROTOTYPES_
 
1098
static AltElem *findalt(
 
1099
     Aword vrbsadr,             /* IN - Address to start of list */
 
1100
     Aword param                /* IN - Which parameter to match */
 
1101
)
 
1102
#else
 
1103
static AltElem *findalt(vrbsadr, param)
 
1104
     Aword vrbsadr;             /* IN - Address to start of list */
 
1105
     Aword param;               /* IN - Which parameter to match */
 
1106
#endif
 
1107
{
 
1108
  VrbElem *vrb;
 
1109
  AltElem *alt;
 
1110
 
 
1111
  if (vrbsadr == 0)
 
1112
    return(NULL);
 
1113
 
 
1114
  for (vrb = (VrbElem *) addrTo(vrbsadr); !endOfTable(vrb); vrb++)
 
1115
    if (vrb->code == cur.vrb) {
 
1116
      for (alt = (AltElem *) addrTo(vrb->alts); !endOfTable(alt); alt++)
 
1117
        if (alt->param == param || alt->param == 0)
 
1118
          return alt;
 
1119
      return NULL;
 
1120
    }
 
1121
  return NULL;
 
1122
}
 
1123
 
 
1124
 
 
1125
 
 
1126
 
 
1127
/*======================================================================
 
1128
 
 
1129
  possible()
 
1130
 
 
1131
  Check if current action is possible according to the CHECKs.
 
1132
 
 
1133
  */
 
1134
#ifdef _PROTOTYPES_
 
1135
Boolean possible(void)
 
1136
#else
 
1137
Boolean possible()
 
1138
#endif
 
1139
{
 
1140
  AltElem *alt[MAXPARAMS+2];    /* List of alt-pointers, one for each param */
 
1141
  int i;                        /* Parameter index */
 
1142
  
 
1143
  fail = FALSE;
 
1144
  alt[0] = findalt(header->vrbs, 0);
 
1145
  /* Perform global checks */
 
1146
  if (alt[0] != 0 && alt[0]->checks != 0) {
 
1147
    if (!trycheck(alt[0]->checks, FALSE)) return FALSE;
 
1148
    if (fail) return FALSE;
 
1149
  }
 
1150
  
 
1151
  /* Now CHECKs in this location */
 
1152
  alt[1] = findalt(locs[cur.loc-LOCMIN].vrbs, 0);
 
1153
  if (alt[1] != 0 && alt[1]->checks != 0)
 
1154
    if (!trycheck(alt[1]->checks, FALSE))
 
1155
      return FALSE;
 
1156
  
 
1157
  for (i = 0; params[i].code != EOF; i++) {
 
1158
    alt[i+2] = findalt(objs[params[i].code-OBJMIN].vrbs, i+1);
 
1159
    /* CHECKs in a possible parameter */
 
1160
    if (alt[i+2] != 0 && alt[i+2]->checks != 0)
 
1161
      if (!trycheck(alt[i+2]->checks, FALSE))
 
1162
        return FALSE;
 
1163
  }
 
1164
 
 
1165
  for (i = 0; i < 2 || params[i-2].code != EOF; i++)
 
1166
    if (alt[i] != 0 && alt[i]->action != 0)
 
1167
      break;
 
1168
  if (i >= 2 && params[i-2].code == EOF)
 
1169
    /* Didn't find any code for this verb/object combination */
 
1170
    return FALSE;
 
1171
  else
 
1172
    return TRUE;
 
1173
}
 
1174
 
 
1175
 
 
1176
 
 
1177
/*----------------------------------------------------------------------
 
1178
 
 
1179
  do_it()
 
1180
 
 
1181
  Execute the action commanded by hero.
 
1182
 
 
1183
  */
 
1184
#ifdef _PROTOTYPES_
 
1185
static void do_it(void)
 
1186
#else
 
1187
static void do_it()
 
1188
#endif
 
1189
{
 
1190
  AltElem *alt[MAXPARAMS+2];    /* List of alt-pointers, one for each param */
 
1191
  Boolean done[MAXPARAMS+2];    /* Is it done */
 
1192
  int i;                        /* Parameter index */
 
1193
  char trace[80];               /* Trace string buffer */
 
1194
  
 
1195
  fail = FALSE;
 
1196
  alt[0] = findalt(header->vrbs, 0);
 
1197
  /* Perform global checks */
 
1198
  if (alt[0] != 0 && alt[0]->checks != 0) {
 
1199
    if (trcflg)
 
1200
      printf("\n<VERB %d, CHECK, GLOBAL:>\n", cur.vrb);
 
1201
    if (!trycheck(alt[0]->checks, TRUE)) return;
 
1202
    if (fail) return;
 
1203
  }
 
1204
  
 
1205
  /* Now CHECKs in this location */
 
1206
  alt[1] = findalt(locs[cur.loc-LOCMIN].vrbs, 0);
 
1207
  if (alt[1] != 0 && alt[1]->checks != 0) {
 
1208
    if (trcflg)
 
1209
      printf("\n<VERB %d, CHECK, in LOCATION:>\n", cur.vrb);
 
1210
    if (!trycheck(alt[1]->checks, TRUE)) return;
 
1211
    if (fail) return;
 
1212
  }
 
1213
  
 
1214
  for (i = 0; params[i].code != EOF; i++) {
 
1215
    if (isLit(params[i].code))
 
1216
      alt[i+2] = 0;
 
1217
    else {
 
1218
      if (isObj(params[i].code))
 
1219
        alt[i+2] = findalt(objs[params[i].code-OBJMIN].vrbs, i+1);
 
1220
      else if (isAct(params[i].code))
 
1221
        alt[i+2] = findalt(acts[params[i].code-ACTMIN].vrbs, i+1);
 
1222
      else
 
1223
        syserr("Illegal parameter type.");
 
1224
      /* CHECKs in the parameters */
 
1225
      if (alt[i+2] != 0 && alt[i+2]->checks != 0) {
 
1226
        if (trcflg)
 
1227
          printf("\n<VERB %d, CHECK, in Parameter #%d:>\n", cur.vrb, i);
 
1228
        if (!trycheck(alt[i+2]->checks, TRUE)) return;
 
1229
        if (fail) return;
 
1230
      }
 
1231
    }
 
1232
  }
 
1233
 
 
1234
  /* Check for anything to execute... */
 
1235
  for (i = 0; i < 2 || params[i-2].code != EOF; i++)
 
1236
    if (alt[i] != 0 && alt[i]->action != 0)
 
1237
      break;
 
1238
  if (i >= 2 && params[i-2].code == EOF)
 
1239
    /* Didn't find any code for this verb/object combination */
 
1240
    error(M_CANT0);
 
1241
  
 
1242
  /* Perform actions! */
 
1243
  
 
1244
  /* First try any BEFORE or ONLY from outside in */
 
1245
  done[0] = FALSE;
 
1246
  done[1] = FALSE;
 
1247
  for (i = 2; params[i-2].code != EOF; i++)
 
1248
    done[i] = FALSE;
 
1249
  i--;
 
1250
  while (i >= 0) {
 
1251
    if (alt[i] != 0)
 
1252
      if (alt[i]->qual == (Aword)Q_BEFORE || alt[i]->qual == (Aword)Q_ONLY) {
 
1253
        if (alt[i]->action != 0) {
 
1254
          if (trcflg) {
 
1255
            if (i == 0)
 
1256
              strcpy(trace, "GLOBAL");
 
1257
            else if (i == 1)
 
1258
              strcpy(trace, "in LOCATION");
 
1259
            else
 
1260
              sprintf(trace, "in PARAMETER %d", i-1);
 
1261
            if (alt[i]->qual == (Aword)Q_BEFORE)
 
1262
              printf("\n<VERB %d, %s (BEFORE), Body:>\n", cur.vrb, trace);
 
1263
            else
 
1264
              printf("\n<VERB %d, %s (ONLY), Body:>\n", cur.vrb, trace);
 
1265
          }
 
1266
          interpret(alt[i]->action);
 
1267
          if (fail) return;
 
1268
          if (alt[i]->qual == (Aword)Q_ONLY) return;
 
1269
        }
 
1270
        done[i] = TRUE;
 
1271
      }
 
1272
    i--;
 
1273
  }
 
1274
  
 
1275
  /* Then execute any not declared as AFTER, i.e. the default */
 
1276
  for (i = 0; i < 2 || params[i-2].code != EOF; i++) {
 
1277
    if (alt[i] != 0)
 
1278
      if (alt[i]->qual != (Aword)Q_AFTER) {
 
1279
        if (!done[i] && alt[i]->action != 0) {
 
1280
          if (trcflg) {
 
1281
            if (i == 0)
 
1282
              strcpy(trace, "GLOBAL");
 
1283
            else if (i == 1)
 
1284
              strcpy(trace, "in LOCATION");
 
1285
            else
 
1286
              sprintf(trace, "in PARAMETER %d", i-1);
 
1287
            printf("\n<VERB %d, %s, Body:>\n", cur.vrb, trace);
 
1288
          }
 
1289
          interpret(alt[i]->action);
 
1290
          if (fail) return;
 
1291
        }
 
1292
        done[i] = TRUE;
 
1293
      }
 
1294
  }
 
1295
 
 
1296
  /* Finally, the ones declared as after */
 
1297
  i--;
 
1298
  while (i >= 0) {
 
1299
    if (alt[i] != 0)
 
1300
      if (!done[i] && alt[i]->action != 0) {
 
1301
        if (trcflg) {
 
1302
          if (i == 0)
 
1303
            strcpy(trace, "GLOBAL");
 
1304
          else if (i == 1)
 
1305
            strcpy(trace, "in LOCATION");
 
1306
          else
 
1307
            sprintf(trace, "in PARAMETER %d", i-1);
 
1308
          printf("\n<VERB %d, %s (AFTER), Body:>\n", cur.vrb, trace);
 
1309
        }
 
1310
        interpret(alt[i]->action);
 
1311
        if (fail) return;
 
1312
      }
 
1313
    i--;
 
1314
  }
 
1315
}
 
1316
 
 
1317
 
 
1318
 
 
1319
/*======================================================================
 
1320
 
 
1321
  action()
 
1322
 
 
1323
  Execute all activities commanded. Handles possible multiple actions
 
1324
  such as THEM or lists of objects.
 
1325
 
 
1326
  */
 
1327
#ifdef _PROTOTYPES_
 
1328
void action(
 
1329
     ParamElem plst[]           /* IN - Plural parameter list */
 
1330
)
 
1331
#else
 
1332
void action(plst)
 
1333
     ParamElem plst[];
 
1334
#endif
 
1335
{
 
1336
  int i, mpos;
 
1337
  char marker[10];
 
1338
 
 
1339
  if (plural) {
 
1340
    /*
 
1341
       The code == 0 means this is a multiple position. We must loop
 
1342
       over this position (and replace it by each present in the plst)
 
1343
     */
 
1344
    for (mpos = 0; params[mpos].code != 0; mpos++); /* Find multiple position */
 
1345
    sprintf(marker, "($%d)", mpos+1); /* Prepare a printout with $1/2/3 */
 
1346
    for (i = 0; plst[i].code != EOF; i++) {
 
1347
      params[mpos] = plst[i];
 
1348
      output(marker);
 
1349
      do_it();
 
1350
      if (plst[i+1].code != EOF)
 
1351
        para();
 
1352
    }
 
1353
    params[mpos].code = 0;
 
1354
  } else
 
1355
    do_it();
 
1356
}
 
1357
 
 
1358
 
 
1359
 
 
1360
/*----------------------------------------------------------------------*\
 
1361
 
 
1362
  Event Handling
 
1363
 
 
1364
  eventchk()
 
1365
 
 
1366
\*----------------------------------------------------------------------*/
 
1367
 
 
1368
 
 
1369
/*----------------------------------------------------------------------
 
1370
  eventchk()
 
1371
 
 
1372
  Check if any events are pending. If so execute them.
 
1373
  */
 
1374
#ifdef _PROTOTYPES_
 
1375
static void eventchk(void)
 
1376
#else
 
1377
static void eventchk()
 
1378
#endif
 
1379
{
 
1380
  while (etop != 0 && eventq[etop-1].time == cur.tick) {
 
1381
    etop--;
 
1382
    if (isLoc(eventq[etop].where))
 
1383
      cur.loc = eventq[etop].where;
 
1384
    else
 
1385
      cur.loc = where(eventq[etop].where);
 
1386
    if (trcflg) {
 
1387
      printf("\n<EVENT %d (at ", eventq[etop].event);
 
1388
      debugsay(cur.loc);
 
1389
      printf("):>\n");
 
1390
    }
 
1391
    interpret(evts[eventq[etop].event-EVTMIN].code);
 
1392
  }
 
1393
}
 
1394
 
 
1395
 
 
1396
 
 
1397
 
 
1398
 
 
1399
/*----------------------------------------------------------------------*\
 
1400
 
 
1401
  Main program and initialisation
 
1402
 
 
1403
  codfil
 
1404
  filenames
 
1405
 
 
1406
  checkvers()
 
1407
  load()
 
1408
  checkdebug()
 
1409
  initheader()
 
1410
  initstrings()
 
1411
  start()
 
1412
  init()
 
1413
  main()
 
1414
 
 
1415
\*----------------------------------------------------------------------*/
 
1416
 
 
1417
 
 
1418
static FILE *codfil;
 
1419
static char codfnm[256] = "";
 
1420
static char txtfnm[256] = "";
 
1421
static char logfnm[256] = "";
 
1422
 
 
1423
 
 
1424
/*----------------------------------------------------------------------
 
1425
 
 
1426
  checkvers()
 
1427
 
 
1428
 */
 
1429
#ifdef _PROTOTYPES_
 
1430
static void checkvers(AcdHdr *header)
 
1431
#else
 
1432
static void checkvers(header)
 
1433
     AcdHdr *header;
 
1434
#endif
 
1435
{
 
1436
  char vers[4];
 
1437
  char state[2];
 
1438
 
 
1439
  /* Construct our own version */
 
1440
  vers[0] = alan.version.version;
 
1441
  vers[1] = alan.version.revision;
 
1442
 
 
1443
  /* Check version of .ACD file */
 
1444
  if (dbgflg) {
 
1445
    state[0] = header->vers[3];
 
1446
    state[1] = '\0';
 
1447
    printf("<Version of '%s' is %d.%d(%d)%s>",
 
1448
           advnam,
 
1449
           (int)(header->vers[0]),
 
1450
           (int)(header->vers[1]),
 
1451
           (int)(header->vers[2]),
 
1452
           (header->vers[3])==0? "": state);
 
1453
    newline();
 
1454
  }
 
1455
 
 
1456
  /* Compatible if version and revision match... */
 
1457
  if (strncmp(header->vers, vers, 2) != 0) {
 
1458
#ifdef V25COMPATIBLE
 
1459
    if (header->vers[0] == 2 && header->vers[1] == 5) /* Check for 2.5 version */
 
1460
      /* This we can convert later if needed... */;
 
1461
    else
 
1462
#endif
 
1463
#ifdef V27COMPATIBLE
 
1464
    if (header->vers[0] == 2 && header->vers[1] == 7) /* Check for 2.7 version */
 
1465
      /* This we can convert later if needed... */;
 
1466
    else
 
1467
#endif
 
1468
      if (errflg) {
 
1469
        char str[80];
 
1470
        sprintf(str, "Incompatible version of ACODE program. Game is %ld.%ld, interpreter %ld.%ld.",
 
1471
                (long) (header->vers[0]),
 
1472
                (long) (header->vers[1]),
 
1473
                (long) alan.version.version,
 
1474
                (long) alan.version.revision);
 
1475
        syserr(str);
 
1476
      } else
 
1477
        output("<WARNING! Incompatible version of ACODE program.>\n");
 
1478
  }
 
1479
}
 
1480
 
 
1481
 
 
1482
/*----------------------------------------------------------------------
 
1483
 
 
1484
  load()
 
1485
 
 
1486
 */
 
1487
#ifdef _PROTOTYPES_
 
1488
static void load(void)
 
1489
#else
 
1490
static void load()
 
1491
#endif
 
1492
{
 
1493
  AcdHdr tmphdr;
 
1494
  Aword crc = 0;
 
1495
  int i,tmp;
 
1496
  char err[100];
 
1497
 
 
1498
  rewind(codfil);
 
1499
  tmp = fread(&tmphdr, sizeof(tmphdr), 1, codfil);
 
1500
  rewind(codfil);
 
1501
  checkvers(&tmphdr);
 
1502
 
 
1503
  /* Allocate and load memory */
 
1504
 
 
1505
#ifdef REVERSED
 
1506
  reverseHdr(&tmphdr);
 
1507
#endif
 
1508
 
 
1509
  /* No memory allocated yet? */
 
1510
  if (memory == NULL) {
 
1511
#ifdef V25COMPATIBLE
 
1512
    if (tmphdr.vers[0] == 2 && tmphdr.vers[1] == 5)
 
1513
      /* We need some more memory to expand 2.5 format*/
 
1514
      memory = allocate((tmphdr.size+tmphdr.objmax-tmphdr.objmin+1+2)*sizeof(Aword));
 
1515
    else
 
1516
#endif
 
1517
      memory = allocate(tmphdr.size*sizeof(Aword));
 
1518
  }
 
1519
  header = (AcdHdr *) addrTo(0);
 
1520
 
 
1521
  memTop = fread(addrTo(0), sizeof(Aword), tmphdr.size, codfil);
 
1522
  if (memTop != tmphdr.size)
 
1523
    syserr("Could not read all ACD code.");
 
1524
 
 
1525
  /* Calculate checksum */
 
1526
  for (i = sizeof(tmphdr)/sizeof(Aword); i < memTop; i++) {
 
1527
    crc += memory[i]&0xff;
 
1528
    crc += (memory[i]>>8)&0xff;
 
1529
    crc += (memory[i]>>16)&0xff;
 
1530
    crc += (memory[i]>>24)&0xff;
 
1531
#ifdef CRCLOG
 
1532
    printf("%6x\t%6lx\t%6lx\n", i, crc, memory[i]);
 
1533
#endif
 
1534
  }
 
1535
  if (crc != tmphdr.acdcrc) {
 
1536
    sprintf(err, "Checksum error in .ACD file (0x%lx instead of 0x%lx).",
 
1537
            (unsigned long) crc, (unsigned long) tmphdr.acdcrc);
 
1538
    if (errflg)
 
1539
      syserr(err);
 
1540
    else {
 
1541
      output("<WARNING! $$");
 
1542
      output(err);
 
1543
      output("$$ Ignored, proceed at your own risk.>$n");
 
1544
    }
 
1545
  }
 
1546
 
 
1547
#ifdef REVERSED
 
1548
  if (dbgflg||trcflg||stpflg)
 
1549
    output("<Hmm, this is a little-endian machine, fixing byte ordering....");
 
1550
  reverseACD(tmphdr.vers[0] == 2 && tmphdr.vers[1] == 5); /* Reverse all words in the ACD file */
 
1551
  if (dbgflg||trcflg||stpflg)
 
1552
    output("OK.>$n");
 
1553
#endif
 
1554
 
 
1555
#ifdef V25COMPATIBLE
 
1556
  /* Check for 2.5 version */
 
1557
  if (tmphdr.vers[0] == 2 && tmphdr.vers[1] == 5) {
 
1558
    if (dbgflg||trcflg||stpflg)
 
1559
      output("<Hmm, this is a v2.5 game, please wait while I convert it...");
 
1560
    c25to26ACD();
 
1561
    if (dbgflg||trcflg||stpflg)
 
1562
      output("OK.>$n");
 
1563
  }
 
1564
#endif
 
1565
 
 
1566
}
 
1567
 
 
1568
 
 
1569
/*----------------------------------------------------------------------
 
1570
 
 
1571
  checkdebug()
 
1572
 
 
1573
 */
 
1574
#ifdef _PROTOTYPES_
 
1575
static void checkdebug(void)
 
1576
#else
 
1577
static void checkdebug()
 
1578
#endif
 
1579
{
 
1580
  /* Make sure he can't debug if not allowed! */
 
1581
  if (!header->debug) {
 
1582
    if (dbgflg|trcflg|stpflg)
 
1583
      printf("<Sorry, '%s' is not compiled for debug!>\n", advnam);
 
1584
    para();
 
1585
    dbgflg = FALSE;
 
1586
    trcflg = FALSE;
 
1587
    stpflg = FALSE;
 
1588
  }
 
1589
 
 
1590
  if (dbgflg)                   /* If debugging */
 
1591
    srand(0);                   /* use no randomization */
 
1592
  else
 
1593
    srand(time(0));             /* seed random generator */
 
1594
}
 
1595
 
 
1596
 
 
1597
/*----------------------------------------------------------------------
 
1598
 
 
1599
  initheader()
 
1600
 
 
1601
 */
 
1602
#ifdef _PROTOTYPES_
 
1603
static void initheader(void)
 
1604
#else
 
1605
static void initheader()
 
1606
#endif
 
1607
{
 
1608
  dict = (WrdElem *) addrTo(header->dict);
 
1609
  /* Find out number of entries in dictionary */
 
1610
  for (dictsize = 0; !endOfTable(&dict[dictsize]); dictsize++);
 
1611
  vrbs = (VrbElem *) addrTo(header->vrbs);
 
1612
  stxs = (StxElem *) addrTo(header->stxs);
 
1613
  locs = (LocElem *) addrTo(header->locs);
 
1614
  acts = (ActElem *) addrTo(header->acts);
 
1615
  objs = (ObjElem *) addrTo(header->objs);
 
1616
  evts = (EvtElem *) addrTo(header->evts);
 
1617
  cnts = (CntElem *) addrTo(header->cnts);
 
1618
  ruls = (RulElem *) addrTo(header->ruls);
 
1619
  msgs = (MsgElem *) addrTo(header->msgs);
 
1620
  scores = (Aword *) addrTo(header->scores);
 
1621
 
 
1622
  if (header->pack)
 
1623
    freq = (Aword *) addrTo(header->freq);
 
1624
}
 
1625
 
 
1626
 
 
1627
/*----------------------------------------------------------------------
 
1628
 
 
1629
  initstrings()
 
1630
 
 
1631
  */
 
1632
#ifdef _PROTOTYPES_
 
1633
static void initstrings(void)
 
1634
#else
 
1635
static void initstrings()
 
1636
#endif
 
1637
{
 
1638
  IniElem *init;
 
1639
 
 
1640
  for (init = (IniElem *) addrTo(header->init); !endOfTable(init); init++) {
 
1641
    getstr(init->fpos, init->len);
 
1642
    memory[init->adr] = pop();
 
1643
  }
 
1644
}
 
1645
 
 
1646
 
 
1647
/*----------------------------------------------------------------------
 
1648
 
 
1649
  start()
 
1650
 
 
1651
 */
 
1652
#ifdef _PROTOTYPES_
 
1653
static void start(void)
 
1654
#else
 
1655
static void start()
 
1656
#endif
 
1657
{
 
1658
  int startloc;
 
1659
 
 
1660
  cur.tick = -1;
 
1661
  cur.loc = startloc = where(HERO);
 
1662
  cur.act = HERO;
 
1663
  cur.score = 0;
 
1664
  if (trcflg)
 
1665
    printf("\n<START:>\n");
 
1666
  interpret(header->start);
 
1667
  para();
 
1668
 
 
1669
  acts[HERO-ACTMIN].loc = 0;
 
1670
  locate(HERO, startloc);
 
1671
}
 
1672
 
 
1673
 
 
1674
 
 
1675
/*----------------------------------------------------------------------
 
1676
  init()
 
1677
 
 
1678
  Initialization, program load etc.
 
1679
 
 
1680
  */
 
1681
#ifdef _PROTOTYPES_
 
1682
static void init(void)
 
1683
#else
 
1684
static void init()
 
1685
#endif
 
1686
{
 
1687
  int i;
 
1688
 
 
1689
  /* Initialise some status */
 
1690
  etop = 0;                     /* No pending events */
 
1691
  looking = FALSE;              /* Not looking now */
 
1692
  dscrstkp = 0;                 /* No describe in progress */
 
1693
 
 
1694
  load();
 
1695
 
 
1696
  initheader();
 
1697
  checkdebug();
 
1698
 
 
1699
  /* Initialise string attributes */
 
1700
  initstrings();
 
1701
 
 
1702
  getPageSize();
 
1703
 
 
1704
  /* Find first conjunction and use that for ',' handling */
 
1705
  for (i = 0; i < dictsize; i++)
 
1706
    if (isConj(i)) {
 
1707
      conjWord = i;
 
1708
      break;
 
1709
    }
 
1710
 
 
1711
  /* Start the adventure */
 
1712
  clear();
 
1713
  start();
 
1714
}
 
1715
 
 
1716
 
 
1717
 
 
1718
/*----------------------------------------------------------------------
 
1719
  movactor()
 
1720
 
 
1721
  Let the current actor move. If player, ask him.
 
1722
 
 
1723
 */
 
1724
#ifdef _PROTOTYPES_
 
1725
static void movactor(void)
 
1726
#else
 
1727
static void movactor()
 
1728
#endif
 
1729
{
 
1730
  ScrElem *scr;
 
1731
  StepElem *step;
 
1732
  ActElem *act = (ActElem *) &acts[cur.act-ACTMIN];
 
1733
 
 
1734
  cur.loc = where(cur.act);
 
1735
  if (cur.act == HERO) {
 
1736
    parse();
 
1737
    fail = FALSE;                       /* fail only aborts one actor */
 
1738
    rules();
 
1739
  } else if (act->script != 0) {
 
1740
    for (scr = (ScrElem *) addrTo(act->scradr); !endOfTable(scr); scr++)
 
1741
      if (scr->code == act->script) {
 
1742
        /* Find correct step in the list by indexing */
 
1743
        step = (StepElem *) addrTo(scr->steps);
 
1744
        step = (StepElem *) &step[act->step];
 
1745
        /* Now execute it, maybe. First check wait count */
 
1746
        if (step->after > act->count) {
 
1747
          /* Wait some more */
 
1748
          if (trcflg) {
 
1749
            printf("\n<ACTOR %d, ", cur.act);
 
1750
            debugsay(cur.act);
 
1751
            printf(" (at ");
 
1752
            debugsay(cur.loc);
 
1753
            printf("), SCRIPT %ld, STEP %ld, Waiting %ld more>\n",
 
1754
                   act->script, act->step+1, step->after-act->count);
 
1755
          }
 
1756
          act->count++;
 
1757
          rules();
 
1758
          return;
 
1759
        } else
 
1760
          act->count = 0;
 
1761
        /* Then check possible expression */
 
1762
        if (step->exp != 0) {
 
1763
          if (trcflg) {
 
1764
            printf("\n<ACTOR %d, ", cur.act);
 
1765
            debugsay(cur.act);
 
1766
            printf(" (at ");
 
1767
            debugsay(cur.loc);
 
1768
            printf("), SCRIPT %ld, STEP %ld, Evaluating:>\n",
 
1769
                   act->script, act->step+1);
 
1770
          }
 
1771
          interpret(step->exp);
 
1772
          if (!(Abool)pop()) {
 
1773
            rules();
 
1774
            return; /* Hadn't happened yet */
 
1775
          }
 
1776
        }
 
1777
        /* OK, so finally let him do his thing */
 
1778
        act->step++;            /* Increment step number before executing... */
 
1779
        if (trcflg) {
 
1780
          printf("\n<ACTOR %d, ", cur.act);
 
1781
          debugsay(cur.act);
 
1782
          printf(" (at ");
 
1783
          debugsay(cur.loc);
 
1784
          printf("), SCRIPT %ld, STEP %ld, Executing:>\n",
 
1785
                 act->script, act->step);
 
1786
        }
 
1787
        interpret(step->stm);
 
1788
        step++;
 
1789
        /* ... so that we can see if he is USEing another script now */
 
1790
        if (act->step != 0 && endOfTable(step))
 
1791
          /* No more steps in this script, so stop him */
 
1792
          act->script = 0;
 
1793
        fail = FALSE;                   /* fail only aborts one actor */
 
1794
        rules();
 
1795
        return;
 
1796
      }
 
1797
    syserr("Unknown actor script.");
 
1798
  } else if (trcflg) {
 
1799
    printf("\n<ACTOR %d, ", cur.act);
 
1800
    debugsay(cur.act);
 
1801
    printf(" (at ");
 
1802
    debugsay(cur.loc);
 
1803
    printf("), Idle>\n");
 
1804
    rules();
 
1805
    return;
 
1806
  }
 
1807
}
 
1808
 
 
1809
/*----------------------------------------------------------------------
 
1810
 
 
1811
  openFiles()
 
1812
 
 
1813
  Open the necessary files.
 
1814
 
 
1815
  */
 
1816
#ifdef _PROTOTYPES_
 
1817
static void openFiles(void)
 
1818
#else
 
1819
static void openFiles()
 
1820
#endif
 
1821
{
 
1822
  char str[256];
 
1823
  char *usr = "";
 
1824
  time_t tick;
 
1825
 
 
1826
  /* Open Acode file */
 
1827
  strcpy(codfnm, advnam);
 
1828
  strcat(codfnm, ".acd");
 
1829
  if ((codfil = fopen(codfnm, READ_MODE)) == NULL) {
 
1830
    strcpy(str, "Can't open adventure code file '");
 
1831
    strcat(str, codfnm);
 
1832
    strcat(str, "'.");
 
1833
    syserr(str);
 
1834
  }
 
1835
 
 
1836
#ifdef GARGLK
 
1837
        {
 
1838
                char *s = strrchr(codfnm, '\\');
 
1839
                if (!s) s = strrchr(codfnm, '/');
 
1840
                garglk_set_story_name(s ? s + 1 : codfnm);
 
1841
        }
 
1842
#endif
 
1843
 
 
1844
  /* Open Text file */
 
1845
  strcpy(txtfnm, advnam);
 
1846
  strcat(txtfnm, ".dat");
 
1847
  if ((txtfil = fopen(txtfnm, READ_MODE)) == NULL) {
 
1848
    strcpy(str, "Can't open adventure text data file '");
 
1849
    strcat(str, txtfnm);
 
1850
    strcat(str, "'.");
 
1851
    syserr(str);
 
1852
  }
 
1853
 
 
1854
  /* If logging open log file */
 
1855
  if (logflg) {
 
1856
    char *namstart;
 
1857
 
 
1858
    if((namstart = strrchr(advnam, ']')) == NULL
 
1859
       && (namstart = strrchr(advnam, '>')) == NULL
 
1860
       && (namstart = strrchr(advnam, '/')) == NULL
 
1861
       && (namstart = strrchr(advnam, '\\')) == NULL
 
1862
       && (namstart = strrchr(advnam, ':')) == NULL)
 
1863
      namstart = &advnam[0];
 
1864
    else
 
1865
      namstart++;
 
1866
 
 
1867
    time(&tick);
 
1868
    sprintf(logfnm, "%s%d%s.log", namstart, (int)tick, usr);
 
1869
    if ((logfil = fopen(logfnm, "w")) == NULL)
 
1870
      logflg = FALSE;
 
1871
  }
 
1872
}
 
1873
    
 
1874
 
 
1875
/*======================================================================
 
1876
 
 
1877
  run()
 
1878
 
 
1879
  Run the adventure
 
1880
 
 
1881
  */
 
1882
void run(void)
 
1883
{
 
1884
  openFiles();
 
1885
 
 
1886
  setjmp(restart_label);        /* Return here if he wanted to restart */
 
1887
 
 
1888
  init();                       /* Load, initialise and start the adventure */
 
1889
 
 
1890
  while (TRUE) {
 
1891
#ifdef MALLOC
 
1892
    if (malloc_verify() == 0) syserr("Error in heap.");
 
1893
#endif
 
1894
    if (dbgflg)
 
1895
      debug();
 
1896
 
 
1897
    eventchk();
 
1898
    cur.tick++;
 
1899
    (void) setjmp(jmpbuf);
 
1900
 
 
1901
    /* Move all characters */
 
1902
    for (cur.act = ACTMIN; cur.act <= ACTMAX; cur.act++)
 
1903
      movactor();
 
1904
  }
 
1905
}
 
1906