1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program 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. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "glk/alan2/alan2.h"
24 #include "glk/alan2/types.h"
25 #include "glk/alan2/exe.h"
26 #include "glk/alan2/glkio.h"
27 #include "glk/alan2/inter.h"
28 #include "glk/alan2/main.h"
29 #include "glk/alan2/parse.h"
30 #include "glk/alan2/stack.h"
31 #include "glk/alan2/decode.h"
32
33 namespace Glk {
34 namespace Alan2 {
35
36 #define WIDTH 80
37
38 #define N_EVTS 100
39
40
41 /* PUBLIC DATA */
42
43 /* The event queue */
44 EvtqElem eventq[N_EVTS]; /* Event queue */
45 int etop = 0; /* Event queue top pointer */
46
47 Boolean looking = FALSE; /* LOOKING? flag */
48
49 int dscrstkp = 0; /* Describe-stack pointer */
50
51
52 void dscrobjs();
53 void dscracts();
54
55
print(Aword fpos,Aword len)56 void print(Aword fpos, Aword len) {
57 char str[2 * WIDTH]; // String buffer
58 int outlen = 0; // Current output length
59 int ch = 0;
60 int i;
61 long savfp = 0; // Temporary saved text file position
62 static Boolean printFlag = FALSE; // Printing already?
63 Boolean savedPrintFlag = printFlag;
64 void *info = nullptr; // Saved decoding info
65
66
67 if (len == 0) return;
68
69 if (isHere(HERO)) { /* Check if the player will see it */
70 if (printFlag) { /* Already printing? */
71 /* Save current text file position and/or decoding info */
72 if (header->pack)
73 info = pushDecode();
74 else
75 savfp = ftell(txtfil);
76 }
77 printFlag = TRUE; /* We're printing now! */
78 fseek(txtfil, fpos, 0); /* Position to start of text */
79 if (header->pack)
80 startDecoding();
81 for (outlen = 0; outlen != (int)len; outlen = outlen + strlen(str)) {
82 /* Fill the buffer from the beginning */
83 for (i = 0; i <= WIDTH || (i > WIDTH && ch != ' '); i++) {
84 if (outlen + i == (int)len) /* No more characters? */
85 break;
86 if (header->pack)
87 ch = decodeChar();
88 else
89 ch = getc(txtfil);
90 if (ch == EOFChar) /* Or end of text? */
91 break;
92 str[i] = ch;
93 }
94 str[i] = '\0';
95 output(str);
96 }
97 /* And restore */
98 printFlag = savedPrintFlag;
99 if (printFlag) {
100 if (header->pack)
101 popDecode(info);
102 else
103 fseek(txtfil, savfp, 0);
104 }
105 }
106 }
107
sys(Aword fpos,Aword len)108 void sys(Aword fpos, Aword len) {
109 #ifdef GLK
110 ::error("system calls aren't supported");
111 #else
112 char *command;
113
114 getstr(fpos, len); /* Returns address to string on stack */
115 command = (char *)pop();
116 int tmp = system(command);
117 free(command);
118 #endif
119 }
120
getstr(Aword fpos,Aword len)121 void getstr(Aword fpos, Aword len) {
122 char *buf = (char *)allocate(len + 1);
123
124 push((Aptr) buf); /* Push the address to the string */
125 fseek(txtfil, fpos, 0); /* Position to start of text */
126 if (header->pack)
127 startDecoding();
128 while (len--)
129 if (header->pack)
130 *(buf++) = decodeChar();
131 else
132 *(buf++) = getc(txtfil);
133 *buf = '\0';
134 }
135
score(Aword sc)136 void score(Aword sc) {
137 char buf[80];
138
139 if (sc == 0) {
140 prmsg(M_SCORE1);
141 sprintf(buf, "%d", cur.score);
142 output(buf);
143 prmsg(M_SCORE2);
144 sprintf(buf, "%ld.", (unsigned long) header->maxscore);
145 output(buf);
146 } else {
147 cur.score += scores[sc - 1];
148 scores[sc - 1] = 0;
149 }
150 }
151
visits(Aword v)152 void visits(Aword v) {
153 cur.visits = v;
154 }
155
confirm(MsgKind msgno)156 Boolean confirm(MsgKind msgno) {
157 char buf[80];
158
159 /* This is a bit of a hack since we really want to compare the input,
160 it could be affirmative, but for now any input is NOT! */
161 prmsg(msgno);
162
163 if (!readline(buf)) return TRUE;
164 col = 1;
165
166 return (buf[0] == '\0');
167 }
168
quit(CONTEXT)169 void quit(CONTEXT) {
170 char buf[80];
171
172 para();
173 while (!g_vm->shouldQuit()) {
174 col = 1;
175 statusline();
176 prmsg(M_QUITACTION);
177 if (!readline(buf)) {
178 CALL1(terminate, 0)
179 }
180
181 if (scumm_stricmp(buf, "restart") == 0) {
182 g_vm->setRestart(true);
183 LONG_JUMP
184 } else if (scumm_stricmp(buf, "restore") == 0) {
185 restore();
186 LONG_JUMP
187 } else if (scumm_stricmp(buf, "quit") == 0) {
188 CALL1(terminate, 0)
189 }
190 }
191 }
192
restart()193 void restart() {
194 para();
195 if (confirm(M_REALLY)) {
196 //longjmp(restart_label, TRUE);
197 ::error("TODO: restart");
198 } else
199 return;
200 syserr("Fallthrough in RESTART");
201 }
202
cancl(Aword evt)203 void cancl(Aword evt) {
204 int i;
205
206 for (i = etop - 1; i >= 0; i--)
207 if (eventq[i].event == (int)evt) {
208 while (i < etop - 1) {
209 eventq[i].event = eventq[i + 1].event;
210 eventq[i].time = eventq[i + 1].time;
211 eventq[i].where = eventq[i + 1].where;
212 i++;
213 }
214 etop--;
215 return;
216 }
217 }
218
schedule(Aword evt,Aword whr,Aword aft)219 void schedule(Aword evt, Aword whr, Aword aft) {
220 int i;
221 int time;
222
223 cancl(evt);
224 /* Check for overflow */
225 if (etop == N_EVTS) syserr("Out of event space.");
226
227 time = cur.tick + aft;
228
229 /* Bubble this event down */
230 for (i = etop; i >= 1 && eventq[i - 1].time <= time; i--) {
231 eventq[i].event = eventq[i - 1].event;
232 eventq[i].time = eventq[i - 1].time;
233 eventq[i].where = eventq[i - 1].where;
234 }
235
236 eventq[i].time = time;
237 eventq[i].where = whr;
238 eventq[i].event = evt;
239 etop++;
240 }
241
242
243 /*----------------------------------------------------------------------
244
245 getatr()
246
247 Get an attribute value from an attribute list
248
249 */
getatr(Aaddr atradr,Aaddr atr)250 static Aptr getatr(
251 Aaddr atradr, /* IN - ACODE address to attribute table */
252 Aaddr atr /* IN - The attribute to read */
253 ) {
254 AtrElem *at;
255
256 at = (AtrElem *) addrTo(atradr);
257 return at[atr - 1].val;
258 }
259
260
261 /*----------------------------------------------------------------------
262
263 setatr()
264
265 Set a particular attribute to a value.
266
267 */
setatr(Aaddr atradr,Aword atr,Aword val)268 static void setatr(
269 Aaddr atradr, /* IN - ACODE address to attribute table */
270 Aword atr, /* IN - attribute code */
271 Aword val /* IN - new value */
272 ) {
273 AtrElem *at;
274
275 at = (AtrElem *) addrTo(atradr);
276 at[atr - 1].val = val;
277 }
278
279
280 /*----------------------------------------------------------------------
281
282 make()
283
284 */
285
makloc(Aword loc,Aword atr,Aword val)286 static void makloc(Aword loc, Aword atr, Aword val) {
287 setatr(locs[loc - LOCMIN].atrs, atr, val);
288 }
289
makobj(Aword obj,Aword atr,Aword val)290 static void makobj(Aword obj, Aword atr, Aword val) {
291 setatr(objs[obj - OBJMIN].atrs, atr, val);
292 }
293
makact(Aword act,Aword atr,Aword val)294 static void makact(Aword act, Aword atr, Aword val) {
295 setatr(acts[act - ACTMIN].atrs, atr, val);
296 }
297
make(Aword id,Aword atr,Aword val)298 void make(Aword id, Aword atr, Aword val) {
299 char str[80];
300
301 if (isObj(id))
302 makobj(id, atr, val);
303 else if (isLoc(id))
304 makloc(id, atr, val);
305 else if (isAct(id))
306 makact(id, atr, val);
307 else {
308 sprintf(str, "Can't MAKE item (%ld).", (unsigned long) id);
309 syserr(str);
310 }
311 }
312
313
314 /*----------------------------------------------------------------------------
315
316 set()
317
318 */
319
setloc(Aword loc,Aword atr,Aword val)320 static void setloc(Aword loc, Aword atr, Aword val) {
321 setatr(locs[loc - LOCMIN].atrs, atr, val);
322 locs[loc - LOCMIN].describe = 0;
323 }
324
setobj(Aword obj,Aword atr,Aword val)325 static void setobj(Aword obj, Aword atr, Aword val) {
326 setatr(objs[obj - OBJMIN].atrs, atr, val);
327 }
328
setact(Aword act,Aword atr,Aword val)329 static void setact(Aword act, Aword atr, Aword val) {
330 setatr(acts[act - ACTMIN].atrs, atr, val);
331 }
332
set(Aword id,Aword atr,Aword val)333 void set(Aword id, Aword atr, Aword val) {
334 char str[80];
335
336 if (isObj(id))
337 setobj(id, atr, val);
338 else if (isLoc(id))
339 setloc(id, atr, val);
340 else if (isAct(id))
341 setact(id, atr, val);
342 else {
343 sprintf(str, "Can't SET item (%ld).", (unsigned long) id);
344 syserr(str);
345 }
346 }
347
setstr(Aword id,Aword atr,Aword str)348 void setstr(Aword id, Aword atr, Aword str) {
349 free((char *)attribute(id, atr));
350 set(id, atr, str);
351 }
352
353
354
355 /*-----------------------------------------------------------------------------
356
357 incr/decr
358
359 */
360
361 /*----------------------------------------------------------------------
362
363 incratr()
364
365 Increment a particular attribute by a value.
366
367 */
incratr(Aaddr atradr,Aword atr,Aword step)368 static void incratr(
369 Aaddr atradr, /* IN - ACODE address to attribute table */
370 Aword atr, /* IN - attribute code */
371 Aword step /* IN - step to increment by */
372 ) {
373 AtrElem *at;
374
375 at = (AtrElem *) addrTo(atradr);
376 at[atr - 1].val += step;
377 }
378
incrloc(Aword loc,Aword atr,Aword step)379 static void incrloc(Aword loc, Aword atr, Aword step) {
380 incratr(locs[loc - LOCMIN].atrs, atr, step);
381 locs[loc - LOCMIN].describe = 0;
382 }
383
incrobj(Aword obj,Aword atr,Aword step)384 static void incrobj(Aword obj, Aword atr, Aword step) {
385 incratr(objs[obj - OBJMIN].atrs, atr, step);
386 }
387
incract(Aword act,Aword atr,Aword step)388 static void incract(Aword act, Aword atr, Aword step) {
389 incratr(acts[act - ACTMIN].atrs, atr, step);
390 }
391
incr(Aword id,Aword atr,Aword step)392 void incr(Aword id, Aword atr, Aword step) {
393 char str[80];
394
395 if (isObj(id))
396 incrobj(id, atr, step);
397 else if (isLoc(id))
398 incrloc(id, atr, step);
399 else if (isAct(id))
400 incract(id, atr, step);
401 else {
402 sprintf(str, "Can't INCR item (%ld).", (unsigned long) id);
403 syserr(str);
404 }
405 }
406
decr(Aword id,Aword atr,Aword step)407 void decr(Aword id, Aword atr, Aword step) {
408 char str[80];
409
410 // TODO: Original did explicit negation on an unsigned value. Make sure that the
411 // casts added to ignore the warnings are okay
412 if (isObj(id))
413 incrobj(id, atr, static_cast<uint>(-(int)step));
414 else if (isLoc(id))
415 incrloc(id, atr, static_cast<uint>(-(int)step));
416 else if (isAct(id))
417 incract(id, atr, static_cast<uint>(-(int)step));
418 else {
419 sprintf(str, "Can't DECR item (%ld).", (unsigned long) id);
420 syserr(str);
421 }
422 }
423
424
425 /*----------------------------------------------------------------------
426
427 attribute()
428
429 */
430
locatr(Aword loc,Aword atr)431 static Aptr locatr(Aword loc, Aword atr) {
432 return getatr(locs[loc - LOCMIN].atrs, atr);
433 }
434
objatr(Aword obj,Aword atr)435 static Aptr objatr(Aword obj, Aword atr) {
436 return getatr(objs[obj - OBJMIN].atrs, atr);
437 }
438
actatr(Aword act,Aword atr)439 static Aptr actatr(Aword act, Aword atr) {
440 return getatr(acts[act - ACTMIN].atrs, atr);
441 }
442
litatr(Aword lit,Aword atr)443 static Aptr litatr(Aword lit, Aword atr) {
444 char str[80];
445
446 if (atr == 1)
447 return litValues[lit - LITMIN].value;
448 else {
449 sprintf(str, "Unknown attribute for literal (%ld).", (unsigned long) atr);
450 syserr(str);
451 }
452 return (Aptr)EOD;
453 }
454
attribute(Aword id,Aword atr)455 Aptr attribute(Aword id, Aword atr) {
456 char str[80];
457
458 if (isObj(id))
459 return objatr(id, atr);
460 else if (isLoc(id))
461 return locatr(id, atr);
462 else if (isAct(id))
463 return actatr(id, atr);
464 else if (isLit(id))
465 return litatr(id, atr);
466 else {
467 sprintf(str, "Can't ATTRIBUTE item (%ld).", (unsigned long) id);
468 syserr(str);
469 }
470 return (Aptr)EOD;
471 }
472
strattr(Aword id,Aword atr)473 Aptr strattr(Aword id, Aword atr) {
474 return (Aptr) strdup((char *)attribute(id, atr));
475 }
476
477
478 /*----------------------------------------------------------------------
479
480 where()
481
482 */
483
objloc(Aword obj)484 static Aword objloc(Aword obj) {
485 if (isCnt(objs[obj - OBJMIN].loc)) /* In something ? */
486 if (isObj(objs[obj - OBJMIN].loc) || isAct(objs[obj - OBJMIN].loc))
487 return (where(objs[obj - OBJMIN].loc));
488 else /* Containers not anywhere is where the hero is! */
489 return (where(HERO));
490 else
491 return (objs[obj - OBJMIN].loc);
492 }
493
actloc(Aword act)494 static Aword actloc(Aword act) {
495 return (acts[act - ACTMIN].loc);
496 }
497
where(Aword id)498 Aword where(Aword id) {
499 char str[80];
500
501 if (isObj(id))
502 return objloc(id);
503 else if (isAct(id))
504 return actloc(id);
505 else {
506 sprintf(str, "Can't WHERE item (%ld).", (unsigned long) id);
507 syserr(str);
508 }
509 return (Aptr)EOD;
510 }
511
512
513 /*----------------------------------------------------------------------
514
515 aggregates
516
517 */
518
agrmax(Aword atr,Aword whr)519 Aint agrmax(Aword atr, Aword whr) {
520 Aword i;
521 Aint max = 0;
522
523 for (i = OBJMIN; i <= OBJMAX; i++) {
524 if (isLoc(whr)) {
525 if (where(i) == whr && (int)attribute(i, atr) > max)
526 max = attribute(i, atr);
527 } else if (objs[i - OBJMIN].loc == whr && (int)attribute(i, atr) > max)
528 max = attribute(i, atr);
529 }
530 return (max);
531 }
532
agrsum(Aword atr,Aword whr)533 Aint agrsum(Aword atr, Aword whr) {
534 Aword i;
535 Aint sum = 0;
536
537 for (i = OBJMIN; i <= OBJMAX; i++) {
538 if (isLoc(whr)) {
539 if (where(i) == whr)
540 sum += attribute(i, atr);
541 } else if (objs[i - OBJMIN].loc == whr)
542 sum += attribute(i, atr);
543 }
544 return (sum);
545 }
546
agrcount(Aword whr)547 Aint agrcount(Aword whr) {
548 Aword i;
549 Aword count = 0;
550
551 for (i = OBJMIN; i <= OBJMAX; i++) {
552 if (isLoc(whr)) {
553 if (where(i) == whr)
554 count++;
555 } else if (objs[i - OBJMIN].loc == whr)
556 count++;
557 }
558 return (count);
559 }
560
561
562 /*----------------------------------------------------------------------
563
564 locate()
565
566 */
567
locobj(Aword obj,Aword whr)568 static void locobj(Aword obj, Aword whr) {
569 if (isCnt(whr)) { /* Into a container */
570 if (whr == obj)
571 syserr("Locating something inside itself.");
572 if (checklim(whr, obj))
573 return;
574 else
575 objs[obj - OBJMIN].loc = whr;
576 } else {
577 objs[obj - OBJMIN].loc = whr;
578 /* Make sure the location is described since it's changed */
579 locs[whr - LOCMIN].describe = 0;
580 }
581 }
582
locact(Aword act,Aword whr)583 static void locact(Aword act, Aword whr) {
584 Aword prevact = cur.act;
585 Aword prevloc = cur.loc;
586
587 cur.loc = whr;
588 acts[act - ACTMIN].loc = whr;
589 if (act == HERO) {
590 if (locs[acts[act - ACTMIN].loc - LOCMIN].describe % (cur.visits + 1) == 0)
591 look();
592 else {
593 if (anyOutput)
594 para();
595 say(where(HERO));
596 prmsg(M_AGAIN);
597 newline();
598 dscrobjs();
599 dscracts();
600 }
601 locs[where(HERO) - LOCMIN].describe++;
602 locs[where(HERO) - LOCMIN].describe %= (cur.visits + 1);
603 } else
604 locs[whr - LOCMIN].describe = 0;
605 if (locs[cur.loc - LOCMIN].does != 0) {
606 cur.act = act;
607 interpret(locs[cur.loc - LOCMIN].does);
608 cur.act = prevact;
609 }
610
611 if (cur.act != (int)act)
612 cur.loc = prevloc;
613 }
614
locate(Aword id,Aword whr)615 void locate(Aword id, Aword whr) {
616 char str[80];
617
618 if (isObj(id))
619 locobj(id, whr);
620 else if (isAct(id))
621 locact(id, whr);
622 else {
623 sprintf(str, "Can't LOCATE item (%ld).", (unsigned long) id);
624 syserr(str);
625 }
626 }
627
628
629 /*----------------------------------------------------------------------
630
631 isHere()
632
633 */
634
objhere(Aword obj)635 static Abool objhere(Aword obj) {
636 if (isCnt(objs[obj - OBJMIN].loc)) { /* In something? */
637 if (isObj(objs[obj - OBJMIN].loc) || isAct(objs[obj - OBJMIN].loc))
638 return (isHere(objs[obj - OBJMIN].loc));
639 else /* If the container wasn't anywhere, assume where HERO is! */
640 return ((int)where(HERO) == cur.loc);
641 } else {
642 return (int)(objs[obj - OBJMIN].loc) == cur.loc;
643 }
644 }
645
acthere(Aword act)646 static Aword acthere(Aword act) {
647 return (int)(acts[act - ACTMIN].loc) == cur.loc;
648 }
649
isHere(Aword id)650 Abool isHere(Aword id) {
651 char str[80];
652
653 if (isObj(id))
654 return objhere(id);
655 else if (isAct(id))
656 return acthere(id);
657 else {
658 sprintf(str, "Can't HERE item (%ld).", (unsigned long) id);
659 syserr(str);
660 }
661 return (Abool)EOD;
662 }
663
664 /*----------------------------------------------------------------------
665
666 isNear()
667
668 */
669
objnear(Aword obj)670 static Aword objnear(Aword obj) {
671 if (isCnt(objs[obj - OBJMIN].loc)) { /* In something? */
672 if (isObj(objs[obj - OBJMIN].loc) || isAct(objs[obj - OBJMIN].loc))
673 return (isNear(objs[obj - OBJMIN].loc));
674 else /* If the container wasn't anywhere, assume here, so not nearby! */
675 return (FALSE);
676 } else
677 return (exitto(where(obj), cur.loc));
678 }
679
actnear(Aword act)680 static Aword actnear(Aword act) {
681 return (exitto(where(act), cur.loc));
682 }
683
isNear(Aword id)684 Abool isNear(Aword id) {
685 char str[80];
686
687 if (isObj(id))
688 return objnear(id);
689 else if (isAct(id))
690 return actnear(id);
691 else {
692 sprintf(str, "Can't NEAR item (%ld).", (unsigned long) id);
693 syserr(str);
694 }
695 return (Abool)EOD;
696 }
697
698
699 /*----------------------------------------------------------------------
700
701 in()
702
703 */
704
in(Aword obj,Aword cnt)705 Abool in(Aword obj, Aword cnt) {
706 if (!isObj(obj))
707 return (FALSE);
708 if (!isCnt(cnt))
709 syserr("IN in a non-container.");
710
711 return (objs[obj - OBJMIN].loc == cnt);
712 }
713
714
715 /*----------------------------------------------------------------------
716
717 say()
718
719 */
720
sayloc(Aword loc)721 static void sayloc(Aword loc) {
722 interpret(locs[loc - LOCMIN].nams);
723 }
724
sayobj(Aword obj)725 static void sayobj(Aword obj) {
726 interpret(objs[obj - OBJMIN].dscr2);
727 }
728
sayact(Aword act)729 static void sayact(Aword act) {
730 interpret(acts[act - ACTMIN].nam);
731 }
732
sayint(Aword val)733 void sayint(Aword val) {
734 char buf[25];
735
736 if (isHere(HERO)) {
737 sprintf(buf, "%ld", (unsigned long) val);
738 output(buf);
739 }
740 }
741
saystr(char * str)742 void saystr(char *str) {
743 if (isHere(HERO))
744 output(str);
745 free(str);
746 }
747
saylit(Aword lit)748 static void saylit(Aword lit) {
749 char *str;
750
751 if (isNum(lit))
752 sayint(litValues[lit - LITMIN].value);
753 else {
754 str = (char *)strdup((char *)litValues[lit - LITMIN].value);
755 saystr(str);
756 }
757 }
758
sayarticle(Aword id)759 void sayarticle(Aword id) {
760 if (!isObj(id))
761 syserr("Trying to say article of something *not* an object.");
762 if (objs[id - OBJMIN].art != 0)
763 interpret(objs[id - OBJMIN].art);
764 else
765 prmsg(M_ARTICLE);
766 }
767
say(Aword id)768 void say(Aword id) {
769 char str[80];
770
771 if (isHere(HERO)) {
772 if (isObj(id))
773 sayobj(id);
774 else if (isLoc(id))
775 sayloc(id);
776 else if (isAct(id))
777 sayact(id);
778 else if (isLit(id))
779 saylit(id);
780 else {
781 sprintf(str, "Can't SAY item (%ld).", (unsigned long) id);
782 syserr(str);
783 }
784 }
785 }
786
787
788 /*----------------------------------------------------------------------
789
790 describe()
791
792 */
793
dscrloc(Aword loc)794 static void dscrloc(Aword loc) {
795 if (locs[loc - LOCMIN].dscr != 0)
796 interpret(locs[loc - LOCMIN].dscr);
797 }
798
dscrobj(Aword obj)799 static void dscrobj(Aword obj) {
800 objs[obj - OBJMIN].describe = FALSE;
801 if (objs[obj - OBJMIN].dscr1 != 0)
802 interpret(objs[obj - OBJMIN].dscr1);
803 else {
804 prmsg(M_SEEOBJ1);
805 sayarticle(obj);
806 say(obj);
807 prmsg(M_SEEOBJ4);
808 if (objs[obj - OBJMIN].cont != 0)
809 list(obj);
810 }
811 }
812
dscract(Aword act)813 static void dscract(Aword act) {
814 ScrElem *scr = NULL;
815
816 if (acts[act - ACTMIN].script != 0) {
817 for (scr = (ScrElem *) addrTo(acts[act - ACTMIN].scradr); !endOfTable(scr); scr++)
818 if (scr->code == acts[act - ACTMIN].script)
819 break;
820 if (endOfTable(scr)) scr = NULL;
821 }
822 if (scr != NULL && scr->dscr != 0)
823 interpret(scr->dscr);
824 else if (acts[act - ACTMIN].dscr != 0)
825 interpret(acts[act - ACTMIN].dscr);
826 else {
827 interpret(acts[act - ACTMIN].nam);
828 prmsg(M_SEEACT);
829 }
830 acts[act - ACTMIN].describe = FALSE;
831 }
832
833
834 static Aword dscrstk[255];
835
describe(Aword id)836 void describe(Aword id) {
837 int i;
838 char str[80];
839
840 for (i = 0; i < dscrstkp; i++)
841 if (dscrstk[i] == id)
842 syserr("Recursive DESCRIBE.");
843 dscrstk[dscrstkp++] = id;
844
845 if (isObj(id))
846 dscrobj(id);
847 else if (isLoc(id))
848 dscrloc(id);
849 else if (isAct(id))
850 dscract(id);
851 else {
852 sprintf(str, "Can't DESCRIBE item (%ld).", (unsigned long) id);
853 syserr(str);
854 }
855
856 dscrstkp--;
857 }
858
859
860 /*----------------------------------------------------------------------
861
862 use()
863
864 */
865
use(Aword act,Aword scr)866 void use(Aword act, Aword scr) {
867 char str[80];
868
869 if (!isAct(act)) {
870 sprintf(str, "Item is not an Actor (%ld).", (unsigned long) act);
871 syserr(str);
872 }
873
874 acts[act - ACTMIN].script = scr;
875 acts[act - ACTMIN].step = 0;
876 }
877
878
879 /*----------------------------------------------------------------------
880
881 list()
882
883 */
884
list(Aword cnt)885 void list(Aword cnt) {
886 uint i;
887 Aword props;
888 Aword prevobj = 0;
889 Boolean found = FALSE;
890 Boolean multiple = FALSE;
891
892 /* Find container properties */
893 if (isObj(cnt))
894 props = objs[cnt - OBJMIN].cont;
895 else if (isAct(cnt))
896 props = acts[cnt - ACTMIN].cont;
897 else
898 props = cnt;
899
900 for (i = OBJMIN; i <= OBJMAX; i++) {
901 if (in(i, cnt)) { /* Yes, it's in this container */
902 if (!found) {
903 found = TRUE;
904 if (cnts[props - CNTMIN].header != 0)
905 interpret(cnts[props - CNTMIN].header);
906 else {
907 prmsg(M_CONTAINS1);
908 if (cnts[props - CNTMIN].nam != 0) /* It has it's own name */
909 interpret(cnts[props - CNTMIN].nam);
910 else
911 say(cnts[props - CNTMIN].parent); /* It is actually an object or actor */
912 prmsg(M_CONTAINS2);
913 }
914 } else {
915 if (multiple) {
916 needsp = FALSE;
917 prmsg(M_CONTAINS3);
918 }
919 multiple = TRUE;
920 sayarticle(prevobj);
921 say(prevobj);
922 }
923 prevobj = i;
924 }
925 }
926
927 if (found) {
928 if (multiple)
929 prmsg(M_CONTAINS4);
930 sayarticle(prevobj);
931 say(prevobj);
932 prmsg(M_CONTAINS5);
933 } else {
934 if (cnts[props - CNTMIN].empty != 0)
935 interpret(cnts[props - CNTMIN].empty);
936 else {
937 prmsg(M_EMPTY1);
938 if (cnts[props - CNTMIN].nam != 0) /* It has it's own name */
939 interpret(cnts[props - CNTMIN].nam);
940 else
941 say(cnts[props - CNTMIN].parent); /* It is actually an actor or object */
942 prmsg(M_EMPTY2);
943 }
944 }
945 needsp = TRUE;
946 }
947
948
949 /*----------------------------------------------------------------------
950
951 empty()
952
953 */
954
empty(Aword cnt,Aword whr)955 void empty(Aword cnt, Aword whr) {
956 for (uint i = OBJMIN; i <= OBJMAX; i++)
957 if (in(i, cnt))
958 locate(i, whr);
959 }
960
961
962 /*----------------------------------------------------------------------*\
963
964 Description of current location
965
966 dscrobjs()
967 dscracts()
968 look()
969
970 \*----------------------------------------------------------------------*/
971
dscrobjs()972 void dscrobjs() {
973 uint i;
974 int prevobj = 0;
975 Boolean found = FALSE;
976 Boolean multiple = FALSE;
977
978 /* First describe everything here with its own description */
979 for (i = OBJMIN; i <= OBJMAX; i++)
980 if ((int)objs[i - OBJMIN].loc == cur.loc &&
981 objs[i - OBJMIN].describe &&
982 objs[i - OBJMIN].dscr1)
983 describe(i);
984
985 /* Then list everything else here */
986 for (i = OBJMIN; i <= OBJMAX; i++)
987 if ((int)objs[i - OBJMIN].loc == cur.loc && objs[i - OBJMIN].describe) {
988 if (!found) {
989 prmsg(M_SEEOBJ1);
990 sayarticle(i);
991 say(i);
992 found = TRUE;
993 } else {
994 if (multiple) {
995 needsp = FALSE;
996 prmsg(M_SEEOBJ2);
997 sayarticle(prevobj);
998 say(prevobj);
999 }
1000 multiple = TRUE;
1001 }
1002 prevobj = i;
1003 }
1004
1005 if (found) {
1006 if (multiple) {
1007 prmsg(M_SEEOBJ3);
1008 sayarticle(prevobj);
1009 say(prevobj);
1010 }
1011 prmsg(M_SEEOBJ4);
1012 }
1013
1014 /* Set describe flag for all objects */
1015 for (i = OBJMIN; i <= OBJMAX; i++)
1016 objs[i - OBJMIN].describe = TRUE;
1017 }
1018
dscracts()1019 void dscracts() {
1020 uint i;
1021
1022 for (i = HERO + 1; i <= ACTMAX; i++)
1023 if ((int)acts[i - ACTMIN].loc == cur.loc && acts[i - ACTMIN].describe)
1024 describe(i);
1025
1026 /* Set describe flag for all actors */
1027 for (i = HERO; i <= ACTMAX; i++)
1028 acts[i - ACTMIN].describe = TRUE;
1029 }
1030
look()1031 void look() {
1032 uint i;
1033
1034 if (looking)
1035 syserr("Recursive LOOK.");
1036
1037 looking = TRUE;
1038 /* Set describe flag for all objects and actors */
1039 for (i = OBJMIN; i <= OBJMAX; i++)
1040 objs[i - OBJMIN].describe = TRUE;
1041 for (i = ACTMIN; i <= ACTMAX; i++)
1042 acts[i - ACTMIN].describe = TRUE;
1043
1044 if (anyOutput)
1045 para();
1046
1047 g_vm->glk_set_style(style_Subheader);
1048 needsp = FALSE;
1049 say(cur.loc);
1050 needsp = FALSE;
1051 output(".");
1052 g_vm->glk_set_style(style_Normal);
1053 newline();
1054 needsp = FALSE;
1055 describe(cur.loc);
1056 dscrobjs();
1057 dscracts();
1058 looking = FALSE;
1059 }
1060
1061
1062 /*----------------------------------------------------------------------
1063
1064 save()
1065
1066 */
1067
save()1068 void save() {
1069 (void)g_vm->saveGame();
1070 }
1071
1072
1073 /*----------------------------------------------------------------------
1074
1075 restore()
1076
1077 */
1078
restore()1079 void restore() {
1080 (void)g_vm->loadGame();
1081 }
1082
1083
1084 /*----------------------------------------------------------------------
1085
1086 rnd()
1087
1088 */
1089
rnd(Aword from,Aword to)1090 Aword rnd(Aword from, Aword to) {
1091 if (to == from)
1092 return to;
1093 else if (to > from)
1094 return (rand() / 10) % (to - from + 1) + from;
1095 else
1096 return (rand() / 10) % (from - to + 1) + to;
1097 }
1098
1099 /*----------------------------------------------------------------------
1100
1101 btw()
1102
1103 BETWEEN
1104
1105 */
1106
btw(Aint val,Aint low,Aint high)1107 Abool btw(Aint val, Aint low, Aint high) {
1108 if (high > low)
1109 return low <= val && val <= high;
1110 else
1111 return high <= val && val <= low;
1112 }
1113
1114
1115
1116 /*----------------------------------------------------------------------
1117
1118 contains()
1119
1120 */
1121
contains(Aptr string,Aptr substring)1122 Aword contains(Aptr string, Aptr substring) {
1123 Abool found;
1124
1125 strlow((char *)string);
1126 strlow((char *)substring);
1127
1128 found = (strstr((char *)string, (char *)substring) != 0);
1129
1130 free((char *)string);
1131 free((char *)substring);
1132
1133 return (found);
1134 }
1135
1136
1137 /*----------------------------------------------------------------------
1138
1139 streq()
1140
1141 Compare two strings approximately, ignore case
1142
1143 */
streq(char a[],char b[])1144 Abool streq(char a[], char b[]) {
1145 Boolean eq;
1146
1147 strlow(a);
1148 strlow(b);
1149
1150 eq = (strcmp(a, b) == 0);
1151
1152 free(a);
1153 free(b);
1154
1155 return (eq);
1156 }
1157
1158 } // End of namespace Alan2
1159 } // End of namespace Glk
1160