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/agt/agility.h"
24 #include "glk/agt/interp.h"
25 #include "glk/agt/exec.h"
26
27 namespace Glk {
28 namespace AGT {
29
30 /*
31
32 This file contains several things:
33 i) The code for each of the built-in verbs, all prefixed with 'v_'
34 (so, for example, the code for DROP is in v_drop()).
35 ii) The main routine for checking and running player commands.
36 iii) The main routine for doing intelligent disambiguation.
37
38 */
39
40
41 /* ------------------------------------------------------------------- */
42 /* VERBS: Functions that implement the predefined verbs. */
43 /* ------------------------------------------------------------------- */
44
v_look()45 void v_look() {
46 do_look = 1;
47 }
48
49
50 /* 1=N, etc. */
v_go(int dir)51 static void v_go(int dir) {
52 int newloc, tmploc;
53 int i;
54 /* rbool has_seen;*/
55
56 dir--;
57
58 tmploc = loc;
59 newloc = room[loc].path[dir];
60 if (newloc > exitmsg_base) { /* Customized error messages */
61 msgout(newloc - exitmsg_base, 1);
62 return;
63 }
64 if (newloc < 0) { /* Run autoverb */
65 int v0;
66
67 v0 = verb_code(-newloc);
68 if (v0 == 0) {
69 if (!PURE_ERROR)
70 writeln("GAME ERROR: Invalid verb.");
71 return;
72 }
73 clear_stack();
74 (void)scan_metacommand(0, v0, 0, 0, 0, NULL);
75 return;
76 }
77 if (newloc < first_room) {
78 if (dir == 12) /* Special */
79 sysmsg(182, "Nothing happens.");
80 else if (dir == 10) /* ENTER */
81 sysmsg(197, "$You$ can't enter anything here.");
82 else if (dir == 11) /* EXIT */
83 sysmsg(198, "$You're$ not inside anything that $you$ can exit.");
84 else
85 sysmsg(13, "$You$ can't go that way.");
86 return;
87 }
88 if (newloc > maxroom) {
89 if (!PURE_ERROR)
90 writeln("GAME ERROR: Invalid room number.");
91 return;
92 }
93
94 /* Then need to check for hostile creatures */
95 /* (If we are going back to the room we came from and not PURE_HOSTILE
96 is set, then we don't need to check this) */
97
98 if (dir != 12 && (PURE_HOSTILE || newloc != oldloc + first_room))
99 creatloop(i)
100 if (creature[i].location == loc + first_room &&
101 creature[i].hostile) {
102 parse_rec tmpcreat;
103 curr_creat_rec = &tmpcreat;
104 make_parserec(i + first_creat, &tmpcreat);
105 sysmsg(14, "$The_c$$c_name$ blocks $your$ way.");
106 curr_creat_rec = NULL;
107 return;
108 }
109
110 /* has_seen=room[newloc-first_room].has_seen;*/
111 goto_room(newloc - first_room);
112 if (dir != 12 && newloc != tmploc + first_room) /* SPECIAL */
113 oldloc = tmploc; /* Can backtrack as long as not from special */
114 if (dir == 12 && special_ptr[loc].size > 0)
115 /* need to print special of NEW room */
116 runptr(loc, special_ptr, "INTERNAL ERROR: Invalid special ptr", 0, NULL, NULL);
117
118 if (tmploc == loc && dir == 12) /* SPECIAL that sends us nowhere */
119 do_look = 0;
120 }
121
122
123 /* PUSH, PULL, TURN, PLAY, CHANGE_LOCATIONS */
v_noun(int vc,parse_rec * nounrec)124 static void v_noun(int vc, parse_rec *nounrec) {
125 int dobj_;
126
127 dobj_ = p_obj(nounrec);
128
129 if (vc == 0 && !it_pushable(dobj_)) {
130 int msgnum;
131 if (!tcreat(dobj_)) msgnum = 172;
132 else if (creature[dobj_ - first_creat].gender == 0)
133 if (creature[dobj_ - first_creat].hostile) msgnum = 167;
134 else msgnum = 168;
135 else if (creature[dobj_ - first_creat].hostile) msgnum = 169;
136 else msgnum = 170;
137 sysmsgd(msgnum, "$You$ can't $verb$ $the_n$$noun$.", nounrec); /* Push */
138 return;
139 }
140 if (vc == 1 && !it_pullable(dobj_)) { /* Pull */
141 sysmsgd(tcreat(dobj_) ? 173 : 175, "$You$ can't $verb$ $the_n$$noun$.",
142 nounrec);
143 return;
144 }
145 if (vc == 2 && !it_turnable(dobj_)) { /* Turn */
146 sysmsgd(tcreat(dobj_) ? 164 : 166, "$You$ can't $verb$ $the_n$$noun$.",
147 nounrec);
148 return;
149 }
150 if (vc == 3 && !it_playable(dobj_)) { /* Play */
151 sysmsgd(tcreat(dobj_) ? 176 : 178, "$You$ can't $verb$ $the_n$$noun$.",
152 nounrec);
153 return;
154 }
155 if (matchclass(dobj_, room[loc].key)) { /* SPECIAL triggered */
156 v_go(13);
157 return;
158 }
159 if (vc == 4) {
160 sysmsgd(tcreat(dobj_) ? 180 : 181, "Nothing happens.", nounrec);
161 return;
162 }
163 /* otherwise, print out relevent description. */
164 if (vc == 0) /* Push */
165 runptr(dobj_ - first_noun, push_ptr,
166 "$You$ $verb$ $the_n$$noun$ for a while, but nothing happens.",
167 171, nounrec, NULL);
168 if (vc == 1) /* Pull */
169 runptr(dobj_ - first_noun, pull_ptr,
170 "$You$ $verb$ $the_n$$noun$ a bit, but nothing happens.", 174,
171 nounrec, NULL);
172 if (vc == 2) /* Turn */
173 runptr(dobj_ - first_noun, turn_ptr,
174 "$You$ $verb$ $the_n$$noun$, but nothing happens.", 165,
175 nounrec, NULL);
176 if (vc == 3) /* Play */
177 runptr(dobj_ - first_noun, play_ptr,
178 "$You$ $verb$ $the_n$$noun$ for a bit, but nothing happens.", 177,
179 nounrec, NULL);
180 }
181
182 /* vc==1 if ASK, 0 if TALK TO */
v_talk(int vc,parse_rec * nounrec,parse_rec * objrec)183 static void v_talk(int vc, parse_rec *nounrec, parse_rec *objrec) {
184 int dobj_, iobj_;
185
186 dobj_ = p_obj(nounrec);
187 iobj_ = p_obj(objrec);
188
189 if (nounrec->info == D_END || nounrec->info == D_AND) {
190 alt_sysmsg(211, "Who $are$ $you$ addressing?", nounrec, objrec);
191 return;
192 }
193 if (!genvisible(nounrec)) {
194 alt_sysmsg(212, "Who $are$ $you$ addressing?", nounrec, objrec);
195 return;
196 }
197 if (!tcreat(dobj_)) {
198 alt_sysmsg(vc ? 161 : 156, "That isn't animate.", nounrec, objrec);
199 return;
200 }
201 if (vc == 0)
202 runptr(dobj_ - first_creat,
203 talk_ptr, "$Your$ conversational gambit is ignored.",
204 creature[dobj_ - first_creat].gender == 0 ? 157 : (iobj_ == 0 ? 159 : 158),
205 nounrec, objrec);
206 if (vc == 1)
207 runptr(dobj_ - first_creat, ask_ptr, "$You$ get no answer.",
208 iobj_ == 0 ? 162 : 163, nounrec, objrec);
209 }
210
v_examine(parse_rec * nounrec)211 static void v_examine(parse_rec *nounrec) {
212 if (!islit()) {
213 sysmsgd(room[loc].light == 1 ? 19 : 20, "It's too dark to see anything.",
214 nounrec);
215 }
216 it_describe(nounrec->obj);
217 }
218
v_view(parse_rec * nounrec)219 static void v_view(parse_rec *nounrec) { /* VIEW a picture */
220 int i;
221 int dobj_;
222 dobj_ = p_obj(nounrec);
223
224 if (tnoun(dobj_) && noun[dobj_ - first_noun].pict != 0)
225 pictcmd(1, pictable[noun[dobj_ - first_noun].pict - 1]);
226 else if (tcreat(dobj_) && creature[dobj_ - first_creat].pict != 0)
227 pictcmd(1, pictable[creature[dobj_ - first_creat].pict - 1]);
228 else if (dobj_ == -ext_code[wscene] && room[loc].pict != 0)
229 /* View the room picture */
230 pictcmd(1, pictable[room[loc].pict - 1]);
231 else { /* room.PIX_bits */
232 if (dobj_ < 0)
233 for (i = 0; i < maxpix; i++) /* Check them all */
234 if (dobj_ == -pix_name[i] &&
235 (room[loc].PIX_bits & (1L << i))) {
236 pictcmd(2, i);
237 return;
238 }
239 sysmsgd(217, "That can't be VIEWed here.", nounrec);
240 }
241 }
242
243
v_read(parse_rec * nounrec)244 static void v_read(parse_rec *nounrec) {
245 int dobj_;
246 dobj_ = p_obj(nounrec);
247
248 if (!tnoun(dobj_) || !noun[dobj_ - first_noun].readable) {
249 sysmsg(134,
250 "$You$ can't read $the_n$$noun$, "
251 "so instead $you$ just examine $n_indir$.");
252 it_describe(dobj_);
253 return;
254 }
255 if (text_ptr[dobj_ - first_noun].size > 0)
256 runptr(dobj_ - first_noun, text_ptr,
257 "INTERNAL ERROR: Invalid read pointer", 0, NULL, NULL);
258 else
259 runptr(dobj_ - first_noun, noun_ptr, "$You$ learn nothing new.",
260 193, nounrec, NULL);
261 }
262
263
v_eat(int vc,parse_rec * nounrec)264 static void v_eat(int vc, parse_rec *nounrec) {
265 int dobj_;
266 dobj_ = p_obj(nounrec);
267
268 if (!tnoun(dobj_)) {
269 sysmsgd(124, "That can't be consumed.", nounrec);
270 return;
271 }
272 if (vc == 0 && !noun[dobj_ - first_noun].edible) {
273 sysmsgd(124, "$You$ can't eat that.", nounrec);
274 return;
275 }
276 if (vc == 1 && !noun[dobj_ - first_noun].drinkable) {
277 sysmsgd(127, "$You$ can't drink that.", nounrec);
278 return;
279 }
280
281 sysmsgd(128, "$You$ $verb$ $the_n$$adjective$ $noun$.", nounrec);
282
283 if (noun[dobj_ - first_noun].movable) it_destroy(dobj_);
284 if (noun[dobj_ - first_noun].poisonous) {
285 sysmsgd(129, "Unfortunatly, $n_pro$ $n_was$ poisonous.", nounrec);
286 deadflag = 1;
287 }
288 }
289
290
291 /* assumes objrec is in the noun range */
can_wear(parse_rec * objrec)292 static int can_wear(parse_rec *objrec) {
293 static const char *errs[] = {
294 "$The_n$$noun$ $n_is$ far too heavy to wear.",
295 "$You're$ already loaded down with too much weight as it is.",
296 "$The_n$$noun$ $n_is$ too big and bulky to wear.",
297 "$You're$ wearing too much to also wear $the_n$$noun$."
298 };
299 int n;
300
301 if (!it_canmove(objrec->obj)) {
302 sysmsgd(202, "$You$ can't move $the_n$$noun$.", objrec);
303 }
304 n = check_fit(objrec->obj, 1000);
305 if (n == FIT_OK /* || n>=FIT_SIZE */) return 1;
306 sysmsgd(37 + n, errs[n - 1], objrec);
307 return 0;
308 }
309
310
311 /* assumes objrec is in the noun range */
can_carry(parse_rec * objrec)312 static int can_carry(parse_rec *objrec) {
313 static const char *errs[] = {
314 "$The_n$$noun$ $n_is$ far too heavy to carry.",
315 "$You're$ already carrying too much weight as it is.",
316 "$The_n$$noun$ $n_is$ too big and bulky to pick up.",
317 "$You're$ carrying too much to also carry $the_n$$noun$."
318 };
319 int n;
320
321 n = check_fit(objrec->obj, 1);
322 if (n == FIT_OK) return 1;
323 sysmsgd(30 + n - 1, errs[n - 1], objrec);
324 return 0;
325 }
326
v_get(parse_rec * objrec)327 static int v_get(parse_rec *objrec) {
328 int cnt, i;
329 int obj;
330
331 obj = objrec->obj;
332
333 /* If there is a hostile creature in the room and PURE_GETHOSTILE isn't
334 set, then don't let the player pick up anything */
335 if (!PURE_GETHOSTILE)
336 creatloop(i)
337 if (creature[i].location == loc + first_room &&
338 creature[i].hostile) {
339 parse_rec tmpcreat;
340 make_parserec(i + first_creat, &tmpcreat);
341 curr_creat_rec = &tmpcreat;
342 sysmsgd(14, "$The_c$$c_name$ blocks $your$ way.", objrec);
343 return 0;
344 }
345
346 if (objrec->info == D_ALL) {
347 cnt = 0;
348 nounloop(i)
349 if (noun[i].location == loc + first_room && noun[i].movable) {
350 /* Need to add weight/size check */
351 parse_rec tmpnoun;
352 make_parserec(i + first_noun, &tmpnoun);
353 if (can_carry(&tmpnoun)) {
354 get_obj(i + first_noun);
355 sysmsgd(8, "$You$ pick up $the_n$$adjective$ $noun$.", &tmpnoun);
356 }
357 cnt++;
358 }
359 if (cnt == 0) {
360 sysmsgd(24, "There doesn't seem to be anything here to take.", objrec);
361 return 0;
362 } else return 1;
363 }
364 if (it_door(obj, objrec->noun)) {
365 if (room[loc].locked_door)
366 sysmsgd(25, "You can't pick up the door.", objrec);
367 else
368 sysmsgd(26, "You can't pick up the doorway.", objrec);
369 return 0;
370 }
371 if (!tnoun(obj) || !noun[obj - first_noun].movable) {
372 sysmsgd(tcreat(obj) ? (creature[obj - first_creat].hostile ? 34 : 35) : 29,
373 "$You$ can't pick $the_n$$noun$ up.", objrec);
374 return 0;
375 }
376 if (it_loc(obj) == 1) {
377 sysmsgd(27, "$You$ already have $the_n$$noun$.", objrec);
378 return 1;
379 }
380 if (!can_carry(objrec)) return 0;
381 get_obj(obj);
382 sysmsgd(8, "$You$ pick up $the_n$$adjective$ $noun$.", objrec);
383 return 1;
384 }
385
v_remove(parse_rec * objrec)386 static int v_remove(parse_rec *objrec) {
387 int i, j;
388 integer obj;
389
390 obj = objrec->obj;
391 if (objrec->info == D_ALL) {
392 if (player_worn == 0) {
393 sysmsgd(46, "$You're$ not wearing anything.", objrec);
394 return 0;
395 }
396 safecontloop(i, j, 1000)
397 if (it_canmove(i)) {
398 parse_rec tmp;
399 if (PURE_WEAR) drop_obj(i);
400 else it_move(i, 1); /* Really need to check to make sure
401 we haven't exceeded weight requirement
402 here */
403 make_parserec(i, &tmp);
404 sysmsgd(9, "$You$ take off $the_n$$noun$.", &tmp);
405 }
406 return 1;
407 }
408 if (it_loc(obj) != 1000) {
409 sysmsgd(213, "$You're$ not wearing that.", objrec);
410 return 0;
411 }
412 if (!it_canmove(obj)) {
413 sysmsgd(201, "$You're$ not able to remove $the_n$$noun$.", objrec);
414 return 0;
415 }
416 sysmsgd(9, "$You$ take off $the_n$$noun$.", objrec);
417 if (PURE_WEAR) drop_obj(obj); /* Required to be consistent w/ AGT */
418 else v_get(objrec); /* (trap can_carry problems) */
419 return 1;
420 }
421
v_drop(parse_rec * objrec)422 static void v_drop(parse_rec *objrec) {
423 int i, j;
424 int obj;
425 obj = objrec->obj;
426
427 if (obj == ALL_MARK) {
428 if (player_contents == 0)
429 sysmsgd(45, "$You$ don't have anything to drop.", objrec);
430 else safecontloop(i, j, 1) {
431 parse_rec tmp;
432 make_parserec(i, &tmp);
433 drop_obj(i);
434 sysmsgd(9, "$You$ $verb$ $the_n$$noun$.", &tmp);
435 }
436 return;
437 }
438 if (!it_possess(obj)) {
439 sysmsgd(47, "$You$ don't have that.", objrec);
440 return;
441 }
442 if (!it_canmove(obj)) {
443 sysmsgd(200, "$You're$ not able to $verb$ $the_n$$noun$.", objrec);
444 return;
445 }
446 if (it_loc(obj) == 1000) {
447 sysmsgd(216, "(Taking it off first)", objrec);
448 }
449 sysmsgd(9, "$You$ $verb$ $the_n$$noun$.", objrec);
450 drop_obj(obj);
451 }
452
v_wear(parse_rec * objrec)453 static void v_wear(parse_rec *objrec) {
454 int i, cnt;
455 int obj;
456
457 obj = objrec->obj;
458 if (objrec->info == D_ALL) {
459 cnt = 0;
460 nounloop(i)
461 if (noun[i].location != 1000 && visible(i + first_noun) &&
462 noun[i].wearable) {
463 parse_rec tmp;
464 make_parserec(i + first_noun, &tmp);
465 if (can_wear(&tmp)) {
466 it_move(i + first_noun, 1000);
467 sysmsgd(42, "$You$ put on $the_n$$adjective$ $noun$.", &tmp);
468 }
469 cnt++;
470 }
471 if (cnt == 0)
472 sysmsgd(36, "There doesn't seem to be anything $you$ can wear here.",
473 objrec);
474 return;
475 }
476 if (!tnoun(obj) || !noun[obj - first_noun].wearable) {
477 sysmsgd(tcreat(obj) ? (creature[obj - first_creat].hostile ? 43 : 44) : 203,
478 "$You$ can't wear that.", objrec);
479 return;
480 }
481 if (it_loc(obj) == 1000) {
482 sysmsgd(37, "$You$ $are$ already wearing $the_n$$noun$.", objrec);
483 return;
484 }
485 if (!can_wear(objrec)) return;
486 sysmsgd(42, "$You$ put on $the_n$$noun$.", objrec);
487 it_move(obj, 1000);
488 }
489
490 /* l_or_u: 0=lock, 1=unlock */
do_lock(uchar l_or_u,parse_rec * nounrec,parse_rec * objrec)491 static int do_lock(uchar l_or_u, parse_rec *nounrec, parse_rec *objrec) {
492 int dnoun;
493 int dobj_, iobj_;
494 word dobj_word;
495
496 dobj_ = p_obj(nounrec);
497 iobj_ = p_obj(objrec);
498 dobj_word = nounrec->noun;
499
500 if (it_door(dobj_, dobj_word) && l_or_u != room[loc].locked_door) {
501 /* That is, trying to unlock an unlocked door, or lock a locked one. */
502 if (l_or_u == 0)
503 alt_sysmsg(114, "The door is already locked.", nounrec, objrec);
504 else
505 alt_sysmsg(105,
506 "There doesn't seem to be any door here that need unlocking.",
507 nounrec, objrec);
508 return 0;
509 }
510 if (!it_lockable(dobj_, dobj_word)) {
511 alt_sysmsg((l_or_u ? 108 : 118), "$The_n$$noun$ can't be $verb$ed.",
512 nounrec, objrec);
513 return 0;
514 }
515 if (tnoun(dobj_) && noun[dobj_ - first_noun].closable && it_open(dobj_)) {
516 if (l_or_u == 0) {
517 alt_sysmsg(120, "$You$ will need to close $the_n$$noun$ first.",
518 nounrec, objrec);
519 return 0;
520 } else { /* l_or_u==1 */
521 alt_sysmsg(110, "$The_n$$noun$ $n_is$ already open!",
522 nounrec, objrec);
523 return 0;
524 }
525 }
526 if (it_locked(dobj_, dobj_word) != l_or_u) {
527 alt_sysmsg((l_or_u ? 109 : 119), "$The_n$$noun$ $n_is$ already $verb$ed",
528 nounrec, objrec);
529 return 0;
530 }
531 if (it_door(dobj_, dobj_word) || dobj_ < 0) { /* i.e. a door */
532 alt_sysmsg((l_or_u ? 104 : 115),
533 "$You$ try to $verb$ $the_n$$noun$, but fail.",
534 nounrec, objrec);
535 return 0;
536 }
537 dnoun = dobj_ - first_noun;
538 if (iobj_ == 0) {
539 alt_sysmsg((l_or_u ? 106 : 208),
540 "$You$ will need to use something to do that.",
541 nounrec, objrec);
542 return 0;
543 }
544 if (!player_has(iobj_)) {
545 alt_sysmsg((l_or_u ? 107 : 117), "$You$ don't have $the_o$$object$.",
546 nounrec, objrec);
547 return 0;
548 }
549 if (!matchclass(iobj_, noun[dnoun].key)) {
550 alt_sysmsg(l_or_u ? (vb == 15 ? 80 : 111) : 121, /* vb 15 is OPEN */
551 "$The_o$$object$ doesn't fit.", nounrec, objrec);
552 return 0;
553 }
554 noun[dnoun].locked = !l_or_u;
555 return 1;
556 }
557
558 /* First argument indicates lock or unlock-- 0=lock, 1=unlock */
v_lock(uchar l_or_u,parse_rec * nounrec,parse_rec * objrec)559 static void v_lock(uchar l_or_u, parse_rec *nounrec, parse_rec *objrec) {
560 if (!do_lock(l_or_u, nounrec, objrec)) return;
561 /* Need to fix these messages: */
562 alt_sysmsg((l_or_u ? 112 : 122),
563 "$You$ $verb$ $the_n$$noun$ with $the_o$$object$.",
564 nounrec, objrec);
565 }
566
567 /* OPEN ... WITH ... */
v_open(parse_rec * nounrec,parse_rec * objrec)568 static void v_open(parse_rec *nounrec, parse_rec *objrec) {
569 int dnoun;
570 int dobj_, iobj_;
571
572 dobj_ = p_obj(nounrec);
573 iobj_ = p_obj(objrec);
574
575 dnoun = dobj_ - first_noun;
576 if (it_door(dobj_, nounrec->noun)) {
577 if (room[loc].locked_door)
578 alt_sysmsg(71, "$The_n$$noun$ $n_is$ locked.",
579 nounrec, objrec);
580 else
581 alt_sysmsg(72, "$The_n$$noun$ $n_is$ already open.",
582 nounrec, objrec);
583 return;
584 }
585 if (it_open(dobj_)) {
586 alt_sysmsg(78, "$The_n$$noun$ $n_is$ already open.", nounrec, objrec);
587 return;
588 }
589 if (!tnoun(dobj_) || !noun[dnoun].closable) {
590 alt_sysmsg(77, "$You$ can't open $the_n$$noun$.", nounrec, objrec);
591 return;
592 }
593 if (iobj_ != 0) { /* Need to do unlock action */
594 if (!do_lock(1, nounrec, objrec)) return;
595 /* If something goes wrong, return */
596 }
597 if (noun[dnoun].lockable && noun[dnoun].locked) {
598 alt_sysmsg(79, "It is locked.", nounrec, objrec);
599 return;
600 }
601 noun[dnoun].open = 1;
602 if (iobj_ != 0) /* Obviously these messages need improvement */
603 alt_sysmsg(81, "$You$ have opened $the_n$$noun$ with $the_o$$object$.",
604 nounrec, objrec);
605 else alt_sysmsg(82, "$You$ have opened $the_n$$noun$.", nounrec, objrec);
606 if (noun[dnoun].contents != 0)
607 alt_sysmsg(187, "Inside, $you$ see the following:", nounrec, objrec);
608 print_contents(dobj_, 1);
609 }
610
v_close(parse_rec * nounrec)611 static void v_close(parse_rec *nounrec) {
612 int dobj_;
613 dobj_ = nounrec->obj;
614
615 if (it_door(dobj_, nounrec->noun)) {
616 if (room[loc].locked_door)
617 sysmsgd(84, "The door is already closed.", nounrec);
618 else
619 sysmsgd(85, "That apparently can't be closed.", nounrec);
620 return;
621 }
622 if (!it_open(dobj_)) {
623 sysmsgd(88, "$The_n$$noun$ $n_is$ already closed.", nounrec);
624 return;
625 }
626 if (!tnoun(dobj_) || !noun[dobj_ - first_noun].closable) {
627 sysmsgd(87, "$You$ can't close $the_n$$noun$.", nounrec);
628 return;
629 }
630 noun[dobj_ - first_noun].open = 0;
631 sysmsgd(89, "$You$ have closed $the_n$$noun$.", nounrec);
632 }
633
634
v_light(int newstate,parse_rec * nounrec)635 static void v_light(int newstate, parse_rec *nounrec) {
636 int dobj_;
637 dobj_ = p_obj(nounrec);
638
639 if (!tnoun(dobj_) || !noun[dobj_ - first_noun].light) {
640 sysmsgd(newstate ? 135 : 140, "$You$ can't $verb$ $the_n$$noun$.", nounrec);
641 return;
642 }
643 dobj_ -= first_noun;
644 if (noun[dobj_].on == newstate) {
645 if (newstate)
646 sysmsgd(136, "$The_n$$noun$ $n_is$ already lit.", nounrec);
647 else sysmsgd(141,
648 "$The_n$$noun$ $n_is$n't lit, so $you$ can't extinguish $n_indir$",
649 nounrec);
650 return;
651 }
652 noun[dobj_].on = newstate;
653 if (newstate) sysmsgd(138, "$The_n$$noun$ $n_is$ now lit.", nounrec);
654 else sysmsgd(143, "$The_n$$noun$ $n_is$ no longer lit.", nounrec);
655 }
656
v_turn(word prep_,parse_rec * nounrec)657 static void v_turn(word prep_, parse_rec *nounrec) {
658 int newstate; /* 1=on, 0=off */
659 int dobj_;
660 dobj_ = p_obj(nounrec);
661
662 newstate = (prep_ == ext_code[won]); /* ON or OFF ? */
663 if (!it_turnable(dobj_) && !nounattr(dobj_, light)) {
664 sysmsgd(newstate ? 209 : 210,
665 "$You$ can't turn $the_n$$noun$ $prep_$.", nounrec);
666 return;
667 }
668 if (matchclass(dobj_, room[loc].key)) { /* SPECIAL triggered */
669 v_go(13);
670 return;
671 }
672 if (!tnoun(dobj_)) { /* This should be redundant */
673 writeln("INTERNAL ERROR: Non-noun turn on/off not supported");
674 return;
675 }
676 dobj_ -= first_noun;
677 if (noun[dobj_].on == newstate) {
678 sysmsgd(newstate ? 137 : 142, "$The_n$$noun$ $n_is$ already $prep_$.",
679 nounrec);
680 return;
681 }
682 noun[dobj_].on = newstate;
683 sysmsgd(newstate ? 139 : 144, "$The_n$$noun$ $n_is$ now $prep_$.", nounrec);
684 }
685
686
687
688 /* Missile=1 if actually firing a weapon. */
v_attack(uchar missile,parse_rec * targrec,parse_rec * weprec)689 static void v_attack(uchar missile, parse_rec *targrec, parse_rec *weprec) {
690 int targ, wep;
691 targ = targrec->obj;
692 wep = weprec->obj;
693
694 /* The following fix really belongs in the parser, but it might
695 break some games to do this translation before running metacommands */
696 if (missile && targ == 0) /* SHOOT <target> */
697 if (!tnoun(wep) || !noun[wep - first_noun].shootable) {
698 targ = wep;
699 targrec = weprec;
700 wep = 0;
701 }
702
703 curr_creat_rec = targrec; /* So error messages will print properly */
704 if (wep > 0 && !player_has(wep)) {
705 alt_sysmsg(98, "(Getting $the_o$$object$ first)", targrec, weprec);
706 if (!v_get(weprec)) return;
707 }
708 if ((targ > 0 && !tcreat(targ)) || targ < 0) {
709 alt_sysmsg(missile ? 90 : 93,
710 "It only makes sense to attack living things.",
711 targrec, weprec);
712 return;
713 }
714 if (missile) {
715 if (wep == 0) {
716 sysmsgd(94, "It's not clear what $you$ want to $verb$ with.", targrec);
717 return;
718 } else if (!tnoun(wep) || !noun[wep - first_noun].shootable) {
719 alt_sysmsg(it_isweapon(wep) ? 96 : 95,
720 "$The_o$$object$ doesn't seem to be able to fire.",
721 targrec, weprec);
722 return;
723 } else if (noun[wep - first_noun].num_shots <= 0) {
724 alt_sysmsg(97, "$The_o$$object$ $o_is$ out of ammunition.",
725 targrec, weprec);
726 return;
727 } else noun[wep - first_noun].num_shots--;
728 }
729
730 if (targ == 0) {
731 if (!missile) {
732 alt_sysmsg(206, "Attack what???", NULL, weprec);
733 return;
734 } else {
735 alt_sysmsg(188, "$You$ fire a shot into the air.", NULL, weprec);
736 return;
737 }
738 }
739
740 if (wep == 0) { /* and !missile, but that's taken care of above */
741 sysmsgd(creature[targ - first_creat].hostile ? 91 : 92,
742 "$You$ attack $the_n$$noun$ with $your$ bare hands, but $n_pro$ "
743 "evades $your$ attack.", targrec);
744 return;
745 }
746
747 if (matchclass(wep, creature[targ - first_creat].weapon)) {
748 if (missile)
749 alt_sysmsg(creature[targ - first_creat].hostile ? 99 : 101,
750 "$You$ shoot $the_n$$noun$; "
751 "$n_pro$ vanishes in a cloud of red smoke."
752 , targrec, weprec);
753 else
754 alt_sysmsg(creature[targ - first_creat].hostile ? 49 : 53,
755 "$You$ kill $the_o$$object$; "
756 "$o_pro$ vanishes in a cloud of red smoke.",
757 weprec, targrec);
758 it_destroy(targ);
759 if (!missile) drop_obj(wep);
760 return;
761 } else {
762 if (!missile) {
763 int msgnum;
764 if (creature[targ - first_creat].hostile) {
765 alt_sysmsg(50, NULL, weprec, targrec); /* Preliminary message */
766 msgnum = 51;
767 } else msgnum = 54;
768 if (noun[wep - first_noun].drinkable) { /* i.e. a liquid */
769 alt_sysmsg(msgnum + 1, "$You$ splash $the_o$$object$ with "
770 "$the_n$$noun$, but the liquid quickly evaporates "
771 "without noticable effect.", weprec, targrec);
772 it_destroy(wep);
773 } else {
774 alt_sysmsg(msgnum,
775 "$You$ strike at $the_o$$object$ with $the_n$$noun$, "
776 "but $your$ weapon bounces off of $o_indir$ harmlessly",
777 weprec, targrec);
778 drop_obj(wep);
779 }
780 } else
781 alt_sysmsg(creature[targ - first_creat].hostile ? 100 : 102 ,
782 "$You$ fire at $the_n$$noun$ with $the_o$$object$, but $your$ "
783 "shots don't seem to have any effect.", targrec, weprec);
784
785 if (creature[targ - first_creat].hostile &&
786 ++creature[targ - first_creat].counter >=
787 creature[targ - first_creat].threshold) {
788 alt_sysmsg(204, "$The_n$$noun$ counterattacks! $N_pro$ fights "
789 "viciously and $you$ $are$ unable to defend $your$self "
790 "against $n_indir$.", targrec, weprec);
791 deadflag = 1;
792 }
793 }
794 }
795
796 /* child_proc is true if v_put is being called by v_put, and so
797 shouldn't print success messages */
v_put(parse_rec * nounrec,word prep_,parse_rec * objrec,rbool child_proc)798 static rbool v_put(parse_rec *nounrec, word prep_,
799 parse_rec *objrec, rbool child_proc) {
800 rbool in_prep;
801 int dobj_, iobj_;
802
803 dobj_ = p_obj(nounrec);
804 iobj_ = p_obj(objrec);
805
806 in_prep = (prep_ == ext_code[win] || prep_ == ext_code[winto]
807 || prep_ == ext_code[winside]);
808
809 if (prep_ == 0 || iobj_ == 0) {
810 v_drop(nounrec);
811 return 1;
812 }
813 if (!tnoun(dobj_)) {
814 alt_sysmsg(tcreat(dobj_) ? 11 : 10,
815 "$You$ can't do that with $the_n$$noun$.",
816 nounrec, objrec);
817 return 0;
818 }
819 if (!noun[dobj_ - first_noun].movable) {
820 alt_sysmsg(61, "$You$ can't move $the_n$$adjective$ $noun$.",
821 nounrec, objrec);
822 return 0;
823 }
824 if (tcreat(iobj_)) {
825 alt_sysmsg(189, "$The_o$$object$ doesn't want $n_indir$.",
826 nounrec, objrec);
827 return 0;
828 }
829 if (!tnoun(iobj_)) {
830 alt_sysmsg(tcreat(iobj_) ? 12 : 64,
831 "$You$ can't put something $prep_$ $the_o$$object$.",
832 nounrec, objrec);
833 return 0;
834 }
835 if (dobj_ == iobj_) {
836 alt_sysmsg(62, "$You$ can't put something $prep_$ $n_indir$self.",
837 nounrec, objrec);
838 return 0;
839 }
840 if (!it_open(iobj_) && in_prep) {
841 alt_sysmsg(65, "$The_o$$object$ $o_is$n't open.", nounrec, objrec);
842 return 0;
843 }
844 if (player_has(iobj_) && !in_prep) {
845 alt_sysmsg(is_within(iobj_, 1, 0) ? 68 : 69,
846 "$You$ can't put $the_n$$noun$ $prep_$ something that $you$ "
847 "$are$ carrying.", nounrec, objrec);
848 return 0;
849 }
850
851 if (in_prep) { /* PUT IN */
852 if (check_fit(dobj_, iobj_) != FIT_OK) {
853 alt_sysmsg(66, "$You$ can't fit $the_n$$noun$ into $the_o$$object$.",
854 nounrec, objrec);
855 return 0;
856 }
857 if (it_loc(dobj_) == 1000)
858 alt_sysmsg(216, "(Taking $n_indir$ off first)", nounrec, objrec);
859 it_move(dobj_, iobj_);
860 } else { /* PUT <prep_> with a preposition other than IN */
861 int parent;
862
863 parent = it_loc(iobj_);
864 if (!troom(parent)) {
865 parse_rec parent_rec;
866 make_parserec(parent, &parent_rec);
867 if (!v_put(nounrec, ext_code[win], &parent_rec, 1)) return 0;
868 } else {
869 if (it_loc(dobj_) == 1000)
870 alt_sysmsg(216, "(Taking $n_indir$ off first)", nounrec, objrec);
871 drop_obj(dobj_);
872 }
873 dobj_ -= first_noun;
874 assert(noun[dobj_].pos_prep == 0); /* v_put should have ensured this */
875 noun[dobj_].pos_prep = prep_;
876 noun[dobj_].pos_name = it_name(iobj_);
877 if (iobj_ > 0) noun[dobj_].nearby_noun = iobj_;
878 }
879 if (!child_proc)
880 alt_sysmsg(67, "$You$ place $the_n$$noun$ $prep_$ $the_o$$object$.",
881 nounrec, objrec);
882 return 1;
883 }
884
885
886 /* at, to, in, into, across, inside */
v_throw(parse_rec * nounrec,word prep_,parse_rec * objrec)887 static void v_throw(parse_rec *nounrec, word prep_, parse_rec *objrec) {
888 int dobj_, iobj_;
889 dobj_ = p_obj(nounrec);
890 iobj_ = p_obj(objrec);
891
892 /* Need to check to see what the preposition is-- if it is AT
893 then we should send it to attack routine. */
894 if (!player_has(nounrec->obj)) {
895 alt_sysmsg(47, "$You$ don't have $the_n$$noun$.", nounrec, objrec);
896 return;
897 }
898 if (prep_ == 0) {
899 v_drop(nounrec);
900 return;
901 }
902 if (prep_ != ext_code[wat])
903 v_put(nounrec, prep_, objrec, 0);
904 else /* prep_ is AT */
905 if (!noun[dobj_ - first_noun].movable) {
906 alt_sysmsg(215, "$You$ can't move $the_n$$adjective$ $noun$.",
907 nounrec, objrec);
908 return;
909 }
910 if (tcreat(iobj_)) /* If a creature, treat as an attack */
911 v_attack(0, objrec, nounrec);
912 else { /* THROW AT somethin inanimate */
913 if (dobj_ == iobj_) {
914 alt_sysmsg(56, "$You$ can't $verb$ $the_n$$noun$ $prep_$ $n_indir$self.",
915 nounrec, objrec);
916 return;
917 }
918 if (it_loc(dobj_) == 1000)
919 alt_sysmsg(216, "(Taking it off first)", nounrec, objrec);
920
921 if (tnoun(dobj_) && noun[dobj_ - first_noun].drinkable) {
922 /* A liquid */
923 if (tnoun(iobj_) && noun[iobj_ - first_noun].open)
924 alt_sysmsg(58, "$You$ throw $the_n$$noun$ into $the_o$$object$, "
925 "but $n_pro$ quickly evaporates.",
926 nounrec, objrec);
927 else
928 alt_sysmsg(57, "$The_n$$noun$ splashes on $the_o$$object$ but "
929 "quickly evaporates.", nounrec, objrec);
930 it_destroy(dobj_);
931 } else { /* _Not_ a liquid: */
932 if (tnoun(iobj_) && noun[iobj_ - first_noun].open)
933 if (check_fit(dobj_, iobj_)) {
934 alt_sysmsg(60, "$The_n$$noun$ lands inside $the_o$$object$.",
935 nounrec, objrec);
936 it_move(dobj_, iobj_);
937 return;
938 } else {
939 alt_sysmsg(205, "You $verb$ $the_n$$noun$ into $the_o$$object$, "
940 "but there isn't enough room and $n_pro$ falls out.",
941 nounrec, objrec);
942 }
943 else
944 alt_sysmsg(59, "$The_n$$noun$ bounces off $the_o$$object$.",
945 nounrec, objrec);
946 /* At this point, either the object is closed or doesn't have enough
947 room */
948 it_move(dobj_, first_room + loc);
949 }
950 }
951 }
952
953
954
v_inventory(void)955 void v_inventory(void) {
956 if (player_contents != 0) {
957 sysmsg(130, "$You're$ carrying:");
958 print_contents(1, 1); /* obj=1=self, ind_lev=1 */
959 } else sysmsg(131, "$You$ $are$ empty-handed.");
960 if (player_worn != 0) {
961 sysmsg(132, "$You're$ wearing:");
962 print_contents(1000, 1);
963 }
964 }
965
966
967
968
969
v_quit(void)970 static void v_quit(void) {
971 sysmsg(145, "Are you sure you want to quit?");
972 if (yesno("")) {
973 sysmsg(146, NULL);
974 quitflag = 1;
975 }
976 }
977
978 const char dirname[12][10] = {"north", "south", "east", "west",
979 "northeast", "northwest", "southeast", "southwest",
980 "up", "down", "in", "out"
981 };
982
v_listexit(void)983 void v_listexit(void) {
984 int i, j, k;
985
986 if (!islit()) {
987 sysmsg(23, "It is too dark to see anything.");
988 return;
989 }
990 j = k = 0;
991 for (i = 0; i < 12; i++)
992 if (room[loc].path[i] != 0) k++;
993 if (k == 0)
994 sysmsg(224, "There are no immediately visible exits.");
995 else {
996 sysmsg(225, "There are exits to");
997 for (i = 0; i < 12; i++)
998 if (room[loc].path[i] != 0) {
999 j++;
1000 if (j > 1) writestr(", ");
1001 if (j > 1 && j == k) writestr("or ");
1002 if (i < 8) writestr("the ");
1003 writestr(dirname[i]);
1004 }
1005 writeln(".");
1006 }
1007 }
1008
1009
v_yell(void)1010 static void v_yell(void) {
1011 sysmsg(150, "YAAAAEEEEEEEEOOOOOOUUUUUAAAAHHHHHH!!!!!");
1012 }
1013
1014
1015
1016 /* ------------------------------------------------------------------- */
1017 /* VERB EXECUTION AND GRAMMER CHECKING */
1018
1019
checkgram(int vb_,int dobj_,word prep_,int iobj_,rbool redir_flag)1020 static int checkgram(int vb_, int dobj_, word prep_, int iobj_, rbool redir_flag) {
1021 int i;
1022 int msgnum;
1023
1024 /* We turn off certain sorts of grammar checking if either PURE_GRAMMAR
1025 is set or there has been signicant redirection. */
1026 if (redir_flag < 2) redir_flag = 0;
1027 if (PURE_GRAMMAR) redir_flag = 1;
1028
1029 /* First of all, no constraints on dummy_verb grammer */
1030 if (vb_ >= BASE_VERB && vb_ < TOTAL_VERB) return 0;
1031
1032 if (!(verbflag[vb_]&VERB_TAKEOBJ)
1033 && (dobj_ != 0 || iobj_ != 0 || prep_ > 0)
1034 && vb_ != OLD_VERB + 11) {
1035 if (redir_flag) return 0; /* Original AGT doesn't check this. */
1036 sysmsg(190, "$Verb$ doesn't take an object.");
1037 return -1;
1038 }
1039
1040 /* Now verify prepositons. If PURE_GRAMMAR is set, we don't
1041 check prepositions unless the verb actually accepts at least one.
1042 (this reflects the behavior of the original AGT interpreters). */
1043 if (prep_ > 0 && !(redir_flag && syntbl[preplist[vb_]] == 0)) {
1044 for (i = preplist[vb_]; syntbl[i] != 0 && syntbl[i] != prep_; i++);
1045 if (syntbl[i] != prep_) {
1046 msgnum = 191;
1047 if (vb_ == 15) msgnum = 74; /* Open */
1048 if (vb_ == 17) msgnum = 116; /* Lock */
1049 if (vb_ == 14) msgnum = 48; /* Throw */
1050 sysmsg(msgnum, "$Verb$ doesn't take $prep_$ as a preposition.");
1051 return -1;
1052 }
1053 }
1054 if (iobj_ == ALL_MARK) {
1055 sysmsg(199, "You can't use ALL as an indirect object");
1056 return -1;
1057 }
1058 if (dobj_ == ALL_MARK && vb_ != 33 && vb_ != 41 && vb_ != 51 && vb_ != 52) {
1059 /* i.e. verb is not GET,DROP,WEAR,REMOVE */
1060 msgnum = 5;
1061 if (vb_ == 31) msgnum = 155; /* Talk */
1062 if (vb_ == 34) msgnum = 160; /* Ask */
1063 sysmsg(5, "You can't use ALL with '$verb$'.");
1064 return -1;
1065 }
1066 return 0;
1067 }
1068
1069
1070 /* This checks to make sure that all of the objects are present */
verify_scope(int vb_,parse_rec * nounrec,word prep_,parse_rec * objrec)1071 static rbool verify_scope(int vb_, parse_rec *nounrec,
1072 word prep_, parse_rec *objrec) {
1073 int msgnum;
1074 int dobj_, iobj_;
1075 dobj_ = nounrec->obj;
1076 iobj_ = objrec->obj;
1077
1078 if (!(verbflag[vb_]&VERB_TAKEOBJ)) return 1;
1079 /* No objects (and we've already checked the grammar in
1080 a previous routine) */
1081
1082 if (vb_ == 31 || vb_ == 34) /* TELL, ASK */
1083 return 1; /* These verbs handle this themselves */
1084
1085 if (dobj_ == 0) {
1086 sysmsg(184, "What do $you$ want to $verb$?");
1087 return 0;
1088 }
1089 if (dobj_ != ALL_MARK && !genvisible(nounrec)
1090 && !(it_door(dobj_, nounrec->noun) && /* DOOR object handling */
1091 (vb_ == 33 || vb_ == 15 || vb_ == 16 || vb_ == 17 || vb_ == 18
1092 || vb_ == 29 || vb_ == 24 || vb_ == 22 || vb_ == 21))) {
1093 msgnum = 3;
1094 if (vb_ == 33) msgnum = 28; /* Get */
1095 if (vb_ == 29) msgnum = 63; /* Put */
1096 if (vb_ == 15) msgnum = 75; /* Open */
1097 if (vb_ == 16) msgnum = 86; /* Close */
1098 if (vb_ == 24) msgnum = 126; /* Drink */
1099 if (vb_ == 22) msgnum = 133; /* Read */
1100 if (vb_ == 21) msgnum = 179; /* Change_Locations */
1101 sysmsg(msgnum, "$You$ don't see any $noun$ here.");
1102 return 0;
1103 }
1104
1105 if (prep_ != 0 && vb_ != 35) { /* verb 35 is TURN e.g. ON|OFF */
1106 if (iobj_ == 0) {
1107 msgnum = 214;
1108 if (vb_ == 29) msgnum = 70; /* Put */
1109 sysmsg(msgnum, "What do $you$ want to $verb$ $the_n$$noun$ $prep_$?");
1110 return 0;
1111 }
1112 if (iobj_ == -ext_code[wdoor]) {
1113 sysmsg(183, "You can't $verb$ $prep_$ $the_o$$object$.");
1114 return 0;
1115 }
1116 if (iobj_ != ALL_MARK && !genvisible(objrec)) {
1117 msgnum = 4;
1118 if (vb_ == 15) msgnum = 76; /* Open */
1119 if (vb_ == 18) msgnum = 207; /* Unlock */
1120 sysmsg(msgnum, "$You$ don't see any $object$ here.");
1121 return 0;
1122 }
1123 }
1124 return 1;
1125 }
1126
1127
exec_verb_info(void)1128 static void exec_verb_info(void) {
1129 char *a, *b, *c;
1130 char buff[200];
1131
1132 a = objname(dobj);
1133 b = objname(iobj);
1134 c = objname(actor);
1135 sprintf(buff, "\t\t]]%s, %s %s(%ld) %s %s(%ld)", c, dict[ syntbl[auxsyn[vb]] ],
1136 a, dobj_rec->num, prep == 0 ? "->" : dict[prep], b, iobj_rec->num);
1137 writeln(buff);
1138 rfree(a);
1139 rfree(b);
1140 rfree(c);
1141 }
1142
1143
1144 /* Returns true if the turn is done. */
metacommand_cycle(int save_vb,int * p_redir_flag)1145 rbool metacommand_cycle(int save_vb, int *p_redir_flag) {
1146 if (!have_meta) return 0;
1147
1148
1149 /* Now check metacommands */
1150 if (DEBUG_AGT_CMD)
1151 debugout("*** Scanning: ANY metacommands ****\n");
1152 /* ANY metacommands: */
1153 supress_debug = !debug_any;
1154 clear_stack();
1155 if ((PURE_METAVERB || !was_metaverb)
1156 && 2 == scan_metacommand(0, 0, 0, 0, 0, NULL))
1157 return 1;
1158
1159 supress_debug = 0;
1160
1161 vb = save_vb;
1162 actor_in_scope |= visible(actor); /* Set up for ActorWasPresent */
1163
1164 clear_stack();
1165 if (actor != 0 && aver < AGX00) {
1166 if (DEBUG_AGT_CMD)
1167 debugout("*** Scanning: ANYBODY metacommands ****\n");
1168 if (2 == scan_metacommand(2, vb, dobj, prep, iobj, NULL))
1169 return 1;
1170 }
1171
1172 clear_stack();
1173 if (DEBUG_AGT_CMD)
1174 debugout("*** Scanning: VERB metacommands ****\n");
1175 /* Normal treatment */
1176 if (2 == scan_metacommand(actor, vb, dobj, prep, iobj, p_redir_flag))
1177 return 1;
1178 /* Note that scan_metacommand will change the -global- copy of vb if a
1179 RedirectTo occurs. */
1180
1181 return 0;
1182 }
1183
1184
1185
1186 /* Execute both meta-commands and more normal commands */
1187 /* May need tweaking for AGAIN and UNDO */
exec_verb(void)1188 void exec_verb(void) {
1189 int objswap; /* 1=if iobj has been moved to dobj */
1190 /* (Done for metacommands when there is an iobj but no dobj) */
1191 rbool turndone;
1192 int save_vb;
1193 int redir_flag;
1194
1195 if (DEBUG_EXEC_VERB) exec_verb_info();
1196
1197 do_disambig = 0; /* We're doing this for real */
1198
1199 save_vb = vb;
1200 cmd_saveable = 1;
1201 redir_flag = 0;
1202
1203 was_metaverb = (verbflag[vb] & VERB_META)
1204 && actor == 0 && dobj == 0 && prep == 0 && iobj == 0;
1205
1206 /* The following is purely for metacommands */
1207 if (dobj == 0 && dobj_rec->info != D_NUM && iobj != 0) {
1208 dobj = iobj;
1209 rfree(dobj_rec);
1210 dobj_rec = copy_parserec(iobj_rec);
1211 objswap = 1;
1212 } else objswap = 0;
1213
1214 beforecmd = 1; /* This is for 1.8x support */
1215
1216 turndone = metacommand_cycle(save_vb, &redir_flag) || deadflag;
1217
1218 if (!turndone && DEBUG_AGT_CMD)
1219 debugout("*** Executing Built-in Verbs ****\n");
1220
1221 if (actor > 0 && !turndone) {
1222 if (!actor_in_scope)
1223 sysmsg(196, "I don't see whom $you$ $are$ trying to address here.");
1224 else
1225 sysmsg(192, "$The_name$$name$ doesn't want to.");
1226 } else if (vb == 19 && dobj == 0 && prep == 0 && iobj == 0)
1227 /* LOOK: Doesn't matter if turn is done. */
1228 v_look();
1229 else if (!turndone) {
1230 /* Execute normal verbs: check grammer and then call */
1231 if (!objswap) {
1232 if (checkgram(vb, dobj, prep, iobj, redir_flag) == -1) return;
1233 } else if (checkgram(vb, 0, prep, iobj, redir_flag) == -1) return;
1234
1235 if (!verify_scope(vb, dobj_rec, prep, iobj_rec)) return;
1236
1237 if (vb < 13 && vb > 0) v_go(vb);
1238 else switch (vb) {
1239
1240 case 14:
1241 v_throw(dobj_rec, prep, iobj_rec);
1242 break;
1243 case 29:
1244 v_put(dobj_rec, prep, iobj_rec, 0);
1245 break;
1246
1247 /* _with_ verbs */
1248 case 15:
1249 v_open(dobj_rec, iobj_rec);
1250 break;
1251 case 16:
1252 v_close(dobj_rec);
1253 break;
1254 case 17:
1255 v_lock(0, dobj_rec, iobj_rec);
1256 break; /* LOCK */
1257 case 18:
1258 v_lock(1, dobj_rec, iobj_rec);
1259 break; /* UNLOCK */
1260 case 36:
1261 v_noun(0, dobj_rec);
1262 break; /* PUSH (WITH);Ignore indir object*/
1263
1264 case 26:
1265 v_attack(0, dobj_rec, iobj_rec);
1266 break;
1267 case 49:
1268 if (prep == ext_code[wwith])
1269 v_attack(1, dobj_rec, iobj_rec); /* SHOOT WITH */
1270 else
1271 v_attack(1, iobj_rec, dobj_rec); /* SHOOT AT */
1272 break;
1273
1274 /* _about_ verbs */
1275 case 31:
1276 v_talk(0, dobj_rec, iobj_rec);
1277 break; /* TELL */
1278 case 34:
1279 v_talk(1, dobj_rec, iobj_rec);
1280 break; /* ASK */
1281
1282 case 28:
1283 v_yell();
1284 break;
1285 case 27:
1286 sysmsg(149, "Time passes...");
1287 break; /* wait */
1288 case 55:
1289 v_go(13);
1290 break; /* magic_word */
1291
1292 /* case 19: v_look();break; -- this is moved up above */
1293
1294 case 50:
1295 runptr(loc, help_ptr, "Sorry, you're on your own here.",
1296 2, NULL, NULL);
1297 break; /* HELP */
1298 case 32:
1299 v_inventory();
1300 break;
1301 case 56:
1302 v_view(dobj_rec);
1303 break; /* VIEW */
1304 case 35:
1305 if (prep > 0)
1306 v_turn(prep, dobj_rec); /* TURN ON|OFF */
1307 else
1308 v_noun(2, dobj_rec); /* TURN */
1309 break;
1310 case 20:
1311 v_examine(dobj_rec);
1312 break;
1313 case 22:
1314 v_read(dobj_rec);
1315 break;
1316 case 23:
1317 v_eat(0, dobj_rec);
1318 break; /* EAT */
1319 case 24:
1320 v_eat(1, dobj_rec);
1321 break; /* DRINK */
1322 case 37:
1323 v_noun(1, dobj_rec);
1324 break; /* PULL */
1325 case 38:
1326 v_noun(3, dobj_rec);
1327 break; /* PLAY */
1328 case 47:
1329 v_light(1, dobj_rec);
1330 break; /* LIGHT */
1331 case 48:
1332 v_light(0, dobj_rec);
1333 break; /* EXTINGUISH */
1334 case 21:
1335 v_noun(4, dobj_rec);
1336 break; /* Change Location */
1337
1338 case 51:
1339 v_wear(dobj_rec);
1340 break;
1341 case 33:
1342 v_get(dobj_rec);
1343 break; /* ? */
1344 case 52:
1345 v_remove(dobj_rec);
1346 break;
1347 case 41:
1348 v_drop(dobj_rec);
1349 break;
1350
1351 case 19:
1352 v_look();
1353 break;
1354 case 25:
1355 print_score();
1356 break;
1357 case 30:
1358 cmd_saveable = 0;
1359 v_quit();
1360 break;
1361 /* case 40: SHOW --> default message */
1362 case 39:
1363 case 42:
1364 v_listexit();
1365 break;
1366 case 43:
1367 cmd_saveable = 0;
1368 verboseflag = 0; /* BRIEF */
1369 writeln(
1370 "[Now in BRIEF mode (room descriptions will only be printed"
1371 " when they are entered the first time)]");
1372 break;
1373 case 44:
1374 cmd_saveable = 0;
1375 verboseflag = 1;
1376 v_look(); /* VERBOSE */
1377 writeln("[Now in VERBOSE mode (room descriptions will be"
1378 " printed every time you enter a room)]");
1379 break;
1380 case 45:
1381 cmd_saveable = 0;
1382 g_vm->saveGame();
1383 break;
1384 case 46:
1385 cmd_saveable = 0;
1386 doing_restore = 1;
1387 return;
1388 break;
1389 case 53:
1390 cmd_saveable = 0;
1391 script(1);
1392 break;
1393 case 54:
1394 cmd_saveable = 0;
1395 script(0);
1396 break;
1397 case 58: /* INSTRUCTIONS */
1398 agt_clrscr();
1399 print_instructions(hold_fc);
1400 close_ins_file();
1401 break;
1402 case (OLD_VERB+1):
1403 cmd_saveable = 0; /* RESTART */
1404 if (restart_state == NULL)
1405 writeln("Sorry, too little memory to support RESTART.");
1406 else {
1407 doing_restore = 2;
1408 return;
1409 }
1410 break;
1411 case (OLD_VERB+4):
1412 cmd_saveable = 0; /* NOTIFY */
1413 notify_flag = !notify_flag;
1414 if (notify_flag) writeln("Score notification is now on.");
1415 else writeln("Score notification is now off.");
1416 break;
1417 case (OLD_VERB+5):
1418 listexit_flag = 1;
1419 writeln("[LISTEXIT mode on: room exits will be listed.]");
1420 break; /* LISTEXIT ON */
1421 case (OLD_VERB+6):
1422 listexit_flag = 0;
1423 writeln("[LISTEXIT mode off: room exits will not be listed.]");
1424 break;
1425 case (OLD_VERB+7): /* AGILDEBUG */
1426 if (debug_mode) get_debugcmd();
1427 else writeln("Nice try.");
1428 break;
1429 case (OLD_VERB+8): /* LOG, LOG ON */
1430 logon();
1431 break;
1432 case (OLD_VERB+9): /* LOG OFF */
1433 if (logflag & 2) break; /* We're replaying; ignore. */
1434 if (logflag & 1) close_pfile(log_out, 5);
1435 logflag = 0;
1436 break;
1437 case (OLD_VERB+10): /* REPLAY n */
1438 fast_replay = 0;
1439 replay(dobj_rec->num);
1440 break;
1441 case (OLD_VERB+11): /* REPLAY STEP */
1442 fast_replay = 0;
1443 replay(-1);
1444 break;
1445 case (OLD_VERB+13): /* REPLAY FAST */
1446 fast_replay = 1;
1447 replay(0);
1448 break;
1449 case (OLD_VERB+12): /* MENU */
1450 if (verbmenu == NULL) {
1451 writeln("Sorry, but menus are not supported by this game.");
1452 menu_mode = 0;
1453 break;
1454 }
1455 if (freeze_mode) {
1456 writeln("Sorry, but that is not allowed.");
1457 break;
1458 }
1459 menu_mode = !menu_mode;
1460 break;
1461 case 57: /* AFTER ?!? */
1462 writeln("INTERNAL ERROR: Invalid execution of AFTER");
1463 break;
1464 case (OLD_VERB+14): /* SOUND ON */
1465 musiccmd(8, 0);
1466 break;
1467 case (OLD_VERB+15): /* SOUND OFF */
1468 musiccmd(9, 0);
1469 break;
1470 case (OLD_VERB+16): /* INTRO */
1471 agt_clrscr();
1472 print_descr(intro_ptr, 1);
1473 break;
1474 default:
1475 sysmsg(185, "Don't know how to $verb$ here...");
1476 return;
1477 }
1478 }
1479
1480 compute_seen();
1481
1482 if (!PURE_AFTER && !doing_restore && end_of_turn)
1483 increment_turn();
1484
1485 beforecmd = 0;
1486
1487 /* In AGT 1.8x, run aftercommand verb metacommands. */
1488 /* (This is the most serious flaw in 1.82/1.83; it drastically changes the
1489 semantics of metacommand execution from the earlier formats) */
1490 if (TWO_CYCLE && !quitflag && !turndone && !deadflag) {
1491 if (DEBUG_AGT_CMD)
1492 debugout("*** Scanning (after) metacommands ****\n");
1493 /* Normal treatment */
1494 turndone = turndone || metacommand_cycle(save_vb, &redir_flag);
1495 }
1496
1497 if (aver >= AGT15 && !quitflag && !endflag && !deadflag) {
1498 if (DEBUG_AGT_CMD)
1499 debugout("*** Scanning: AFTER metacommands ****\n");
1500 /* AFTER metacommands: */
1501 supress_debug = !debug_any;
1502 clear_stack();
1503 if ((PURE_METAVERB || !was_metaverb) &&
1504 2 == scan_metacommand(0, 57, 0, 0, 0, NULL))
1505 turndone = 1;
1506 supress_debug = 0;
1507 }
1508
1509 /* If the player really typed 'q' and we generated an "EndGame"
1510 metacommand, then really quit. (usually it just gives the
1511 "restart, restore, undo, quit..." message */
1512 if (save_vb == 30 && endflag) quitflag = 1;
1513 }
1514
1515
1516
1517
1518
1519
1520
1521 /* We need to be able to handle both NOUN and OBJECT searches */
1522 /* If obj==0, then we are doing a noun search, otherwise we are doing
1523 an object search */
1524 /* Return the disambiguation score;
1525 0 if the object doesn't trigger anything
1526 1000 if it runs an action token or built in verb.
1527 Other values may be returned if an ErrMessage token is encountered.
1528 500 is the cutoff for ALL expansion.
1529 */
1530
1531
objcheck_cycle(rbool * success,parse_rec * act,int verbid,parse_rec * dorec,word prep_,parse_rec * iorec)1532 int objcheck_cycle(rbool *success, parse_rec *act, int verbid,
1533 parse_rec *dorec, word prep_, parse_rec *iorec) {
1534 int result;
1535
1536 actor = act->obj;
1537 actor_rec = copy_parserec(act);
1538 /* The xobj_rec don't really matter */
1539 dobj = dorec->obj;
1540 dobj_rec = copy_parserec(dorec);
1541 if (iorec == NULL) {
1542 iobj_rec = make_parserec(0, NULL);
1543 iobj = 0;
1544 } else {
1545 iobj = iorec->obj;
1546 iobj_rec = copy_parserec(iorec);
1547 }
1548
1549 clear_stack();
1550 *success = 1;
1551 supress_debug = !debug_disambig;
1552 if (actor != 0 && aver < AGX00) {
1553 result = scan_metacommand(2, verbid, dobj, prep_, iobj, NULL);
1554 if (result == 2) {
1555 free_all_parserec();
1556 return disambig_score;
1557 }
1558 if (result == -2) {
1559 free_all_parserec();
1560 return DISAMBIG_SUCC;
1561 }
1562 }
1563 clear_stack();
1564 result = scan_metacommand(actor, verbid, dobj, prep_, iobj, NULL);
1565 supress_debug = 0;
1566 switch (result) {
1567 case -2:
1568 free_all_parserec();
1569 return DISAMBIG_SUCC; /* We matched with something */
1570 case 0:
1571 case 1:
1572 break; /* Nothing matched, but we still need to check
1573 built-in verbs */
1574 case 2:
1575 free_all_parserec();
1576 return disambig_score; /* End of turn, no match */
1577 default:
1578 writeln("INTERNAL ERROR: Invalid scan_metacommand return value.");
1579 }
1580 *success = 0;
1581 free_all_parserec();
1582 return 0;
1583 }
1584
1585
1586
check_obj(parse_rec * act,int verbid,parse_rec * dorec,word prep_,parse_rec * iorec)1587 int check_obj(parse_rec *act, int verbid,
1588 parse_rec *dorec, word prep_, parse_rec *iorec) {
1589 int result;
1590 rbool success;
1591
1592 if (iorec == NULL)
1593 do_disambig = 1; /* Disambiguating dobj */
1594 else
1595 do_disambig = 2; /* Disambiguating iobj */
1596
1597 disambig_score = 0;
1598 if (have_meta) {
1599 beforecmd = 1;
1600 result = objcheck_cycle(&success, act, verbid, dorec, prep_, iorec);
1601 if (success) return result;
1602 }
1603
1604 /* Check built-in verbs here */
1605 if (verbid < BASE_VERB)
1606 switch (verbid) {
1607 case 14: /* THROW dobj prep_ iobj */
1608 case 29: /* PUT dobj prep_ iobj */
1609 if (do_disambig == 2 && genvisible(iorec)) return DISAMBIG_SUCC;
1610 // fallthrough
1611 case 41: /* DROP */
1612 if (do_disambig == 1 && it_possess(dobj)) return DISAMBIG_SUCC;
1613 break;
1614
1615 case 49: /* SHOOT ... AT or WITH ... */
1616 if (prep_ == ext_code[wwith]) {
1617 if (do_disambig == 1 && tcreat(dobj)) return DISAMBIG_SUCC;
1618 else if (do_disambig == 2 && it_possess(iobj) && tnoun(iobj)
1619 && noun[iobj - first_noun].shootable)
1620 return DISAMBIG_SUCC;
1621 } else { /* prep_!=wwith */
1622 if (do_disambig == 2 && tcreat(iobj)) return DISAMBIG_SUCC;
1623 else if (do_disambig == 1 && it_possess(dobj) && tnoun(dobj)
1624 && noun[dobj - first_noun].shootable)
1625 return DISAMBIG_SUCC;
1626 }
1627 break;
1628
1629 case 26: /* ATTACK ... WITH ... */
1630 if (do_disambig == 2 && it_possess(iobj)) return DISAMBIG_SUCC;
1631 if (do_disambig == 1 && tcreat(dobj) && visible(dobj))
1632 return DISAMBIG_SUCC;
1633 break;
1634
1635 case 51: /* WEAR */
1636 if (do_disambig == 1)
1637 if (tnoun(dobj) && visible(dobj) && noun[dobj - first_noun].wearable
1638 && it_loc(dobj) != 1000)
1639 return DISAMBIG_SUCC;
1640 break;
1641 case 33: /* GET */
1642 if (do_disambig == 1 && tnoun(dobj)
1643 && visible(dobj)
1644 && noun[dobj - first_noun].location != 1
1645 && noun[dobj - first_noun].movable)
1646 return (player_has(dobj)) ? 499 : DISAMBIG_SUCC;
1647 break;
1648 case 52: /* REMOVE */
1649 if (do_disambig == 1 && it_loc(dobj) == 1000) return DISAMBIG_SUCC;
1650 break;
1651
1652 /* The following could be better, but I don't want to give
1653 away puzzles by accident */
1654 case 15: /* OPEN */
1655 case 17: /* LOCK */
1656 case 18: /* UNLOCK */
1657 if (do_disambig == 2 && it_possess(iobj)) return DISAMBIG_SUCC;
1658 /* ... fall through ... */
1659 default: /* All other verbs just use visibility check */
1660 if (do_disambig == 1 && genvisible(dorec)) return DISAMBIG_SUCC;
1661 if (do_disambig == 2 && genvisible(iorec)) return DISAMBIG_SUCC;
1662 }
1663
1664 if (have_meta && TWO_CYCLE) {
1665 beforecmd = 0;
1666 result = objcheck_cycle(&success, act, verbid, dorec, prep_, iorec);
1667 if (success) return result;
1668 }
1669
1670 return disambig_score; /* Failed to find a match */
1671 }
1672
1673 } // End of namespace AGT
1674 } // End of namespace Glk
1675