improve behaviour under VPC, fixes from nicolas tittley.
[minix.git] / commands / advent / utility.c
blob40b768616c7eb37bc749c7bceb9edc429ab6b59d
1 /*
2 Utility Routines
3 the next logical funtions describe attributes of objects.
4 (ajar, hinged, opaque, printd, treasr, vessel, wearng)
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <ctype.h>
10 #include <string.h>
11 #include "advent.h"
12 #include "advdec.h"
15 ajar .TRUE. if item is container and is open or unhinged
17 boolean ajar(item)
18 int item;
20 return ((bitset(g.obj_state[item], OPENBT))
21 || (vessel(item) && !hinged(item)));
25 at .TRUE. To tell if player is on either side of a two sided object.
27 boolean at(item)
28 int item;
30 if (item < 1 || item > MAXOBJ)
31 return (FALSE);
32 else
33 return (g.place[item] == g.loc || g.fixed[item] == g.loc);
37 athand .TRUE. if item readily reachable
38 it can be lying here, in hand or in open container.
40 boolean athand(item)
41 int item;
43 int contnr;
44 boolean aaa;
46 contnr = -g.place[item];
47 aaa = enclosed(item) && ajar(contnr);
49 return ((g.place[item] == g.loc) || holding(item)
50 || (aaa && ((g.place[contnr] == g.loc)
51 || (toting(item) && holding(contnr)))));
55 bitoff turns off (sets to 0) a bit in obj_state word
57 void bitoff(obj, bit)
58 int obj, bit;
60 long val;
62 val = 1L << bit;
63 g.obj_state[obj] &= ~val;
67 biton turns on (sets to 1) a bit in obj_state word
69 void biton(obj, bit)
70 int obj, bit;
72 long val;
74 val = 1L << bit;
75 g.obj_state[obj] |= val;
79 bitset .TRUE. if object_state has bit N set
81 boolean bitset(state, bit)
82 long state;
83 int bit;
85 return (((state >> bit) & 1) == 1);
89 blind .TRUE. if you can't see at this loc, (darkness of glare)
91 boolean blind()
93 return (dark() || (g.loc == 200
94 && athand(LAMP) && (g.prop[LAMP] == 1)));
98 burden .. returns weight of items being carried
100 if obj=0, burden calculates the total weight of the adventurer's burden
101 including everything in all containers (except the boat) that he is
102 carring.
104 if object is a container, calculate the weight of everything inside
105 the container (including the container itself). Since donkey FORTRAN
106 isn't recursive, we will only calculate weight of contained containers
107 one level down. The only serious contained container would be the sack
108 The only thing we'll miss will be filled VS empty bottle or cage.
110 If object isn't a container, return its weight.
112 int burden(obj)
113 int obj;
115 int i, sum, temp;
117 sum = 0;
118 if (obj == 0) {
119 for (i = 1; i < MAXOBJ; i++) {
120 if (toting(i) && (g.place[i] != -BOAT))
121 sum += g.weight[i];
123 } else {
124 if (obj != BOAT) {
125 sum = g.weight[obj];
126 temp = g.holder[obj];
127 while (temp != 0) {
128 sum += g.weight[temp];
129 temp = g.hlink[temp];
133 return (sum);
137 Routine to carry an object
138 start toting an object, removing it from the list of things
139 at its former location. If object > MAXOBJ ( moving "FIXED"
140 or second loc), then don't change place.
142 void carry(obj, where)
143 int obj, where;
145 int temp;
147 if (obj < MAXOBJ) {
148 if (g.place[obj] == -1)
149 return;
150 g.place[obj] = -1;
152 if (g.atloc[where] == obj)
153 g.atloc[where] = g.link[obj];
154 else {
155 temp = g.atloc[where];
156 while (g.link[temp] != obj) {
157 temp = g.link[temp];
158 if (temp == 0)
159 bug(35);
161 g.link[temp] = g.link[obj];
163 return;
167 confuz generates some variant of "Don't understand that" message.
169 int confuz()
171 int msg;
173 msg = 60;
174 if (pct(50))
175 msg = 61;
176 if (pct(33))
177 msg = 13;
178 if (pct(25))
179 msg = 347;
180 if (pct(20))
181 msg = 195;
182 return (msg);
186 dark .TRUE. if there is no light here
188 boolean dark()
190 return (!(g.loc_attrib[g.loc] & LIGHT) &&
191 (!g.prop[LAMP] || !athand(LAMP)));
195 Routine to check for presence
196 of dwarves..
198 int dcheck()
200 int i;
202 for (i = 1; i < (DWARFMAX); ++i)
203 if (g.dloc[i] == g.loc)
204 return (i);
205 return (0);
209 dead .TRUE. if object is now dead
211 boolean dead(obj)
212 int obj;
214 return (bitset(g.obj_state[obj], 10));
218 drop Place an object at a given loc, prefixing it onto the atloc list.
220 void drop(obj, where)
221 int obj, where;
223 if (obj > MAXOBJ)
224 g.fixed[obj - MAXOBJ] = where;
225 else
226 g.place[obj] = where;
227 if (where > 0) {
228 g.link[obj] = g.atloc[where];
229 g.atloc[where] = obj;
231 return;
235 destroy Permanently eliminate "object" by moving it to
236 a non-existent location.
238 void destroy(obj)
239 int obj;
241 move(obj, 0);
242 return;
246 edible .TRUE. if obj can be eaten.
248 boolean edible(obj)
249 int obj;
251 return (bitset(g.obj_state[obj], 7));
255 enclosed .TRUE. If object is inside a container.
257 boolean enclosed(item)
258 int item;
260 if (item < 1 || item > MAXOBJ)
261 return (FALSE);
262 else
263 return (g.place[item] < -1);
267 extract remove "object" from a container.
268 origionally name "remove" but rename to avoid conflict with stdio.h
270 void extract(obj)
271 int obj;
273 int contnr, temp;
275 contnr = -g.place[obj];
276 g.place[obj] = -1;
277 if (g.holder[contnr] == obj)
278 g.holder[contnr] = g.hlink[obj];
279 else {
280 temp = g.holder[contnr];
281 while (g.hlink[temp] != obj) {
282 temp = g.hlink[temp];
283 if (temp == 0)
284 bug(35);
286 g.hlink[temp] = g.hlink[obj];
288 return;
292 forced To tell if a location will causes a forced move.
293 A forced location is one from which he is immediately bounced
294 to another. Normal use is for death (forced to location zero)
295 and for description of journey from on place to another.
297 int forced(at_loc)
298 int at_loc;
300 return ((g.loc_attrib[at_loc] & 10) == 2);
304 here .TRUE. If an item is at location or is being carried.
306 boolean here(item)
307 int item;
309 return (g.place[item] == g.loc || toting(item));
313 hinged .TRUE. If object can be opened or shut.
315 boolean hinged(object)
316 int object;
318 return (bitset(g.obj_state[object], 1));
322 holding .TRUE. If the object is being carried in hand.
324 boolean holding(item)
325 int item;
327 if (item < 1 || item > MAXOBJ)
328 return (FALSE);
329 else
330 return (g.place[item] == -1);
334 insert
336 void insert(obj, contnr)
337 int obj, contnr;
339 int temp;
341 if (contnr == obj)
342 bug(32);
343 carry(obj, g.loc);
345 temp = g.holder[contnr];
346 g.holder[contnr] = obj;
347 g.hlink[obj] = temp;
348 g.place[obj] = -contnr;
352 inside = .TRUE. If location is well within cave
354 boolean inside(loc)
355 int loc;
357 return (!outside(loc) && !portal(loc));
361 Juggle an object by picking it up and putting it down again,
362 The purpose being to get the object to the front of the chain
363 at its loc.
365 void juggle(obj)
366 int obj;
368 int i, j;
370 i = g.place[obj];
371 j = g.fixed[obj];
372 move(obj, i);
373 move(obj + MAXOBJ, j);
374 return;
378 Determine liquid in the vessel
380 int liq(item)
381 int item;
383 int liquid;
385 if ((item == BOTTLE) || (item == CASK))
386 liquid = liq2(((int) g.prop[item] >> 1) & 7);
387 else
388 liquid = 0;
390 return (liquid);
394 Determine type of liquid in vessel
396 int liq2(liquid)
397 int liquid;
399 switch (liquid) {
400 case 4:
401 return (WATER);
402 case 5:
403 return (OIL);
404 case 6:
405 return (WINE);
406 default:
407 return (0); /* empty */
412 Determine liquid at a location
414 int liqloc(loc)
415 int loc;
417 return (liq2((int) ((g.loc_attrib[loc] >> 1) & 7)));
421 living .TRUE. If object is living, bear for example
423 boolean living(obj)
424 int obj;
426 return (bitset(g.obj_state[obj], 9));
430 locked .TRUE. if lockable object is locked
432 boolean locked(item)
433 int item;
435 return (bitset(g.obj_state[item], 4));
439 locks .TRUE. if you can lock this object
441 boolean locks(item)
442 int item;
444 return (bitset(g.obj_state[item], 3));
448 LOOKIN list contents if obj is a container and is open or transparent.
450 void lookin(contnr)
451 int contnr;
453 int temp;
454 boolean first_time;
456 if (vessel(contnr) && (ajar(contnr) || !opaque(contnr))) {
457 temp = g.holder[contnr];
458 first_time = TRUE;
459 while (temp != 0) {
460 if (first_time)
461 rspeak(360);
462 printf(" ");
463 pspeak(temp, -1);
464 temp = g.hlink[temp];
465 first_time = FALSE;
468 return;
472 Routine to move an object
474 void move(obj, where)
475 int obj, where;
477 int from;
479 if (obj > MAXOBJ)
480 from = g.fixed[obj - MAXOBJ];
481 else {
482 if (enclosed(obj))
483 extract(obj);
484 from = g.place[obj];
486 if ((from > 0) && (from < MAXOBJ * 2))
487 carry(obj, from);
488 drop(obj, where);
489 return;
493 noway, generate's some variant of "can't do that" message.
495 int noway()
497 int msg;
499 msg = 14;
500 if (pct(50))
501 msg = 110;
502 if (pct(33))
503 msg = 147;
504 if (pct(25))
505 msg = 250;
506 if (pct(20))
507 msg = 262;
508 if (pct(17))
509 msg = 25;
510 if (pct(14))
511 msg = 345;
512 if (pct(12))
513 msg = 346;
514 return (msg);
518 opaque .TRUE. If obj is non-transparent container
520 boolean opaque(obj)
521 int obj;
523 return (bitset(g.obj_state[obj], 6));
527 outsid .TRUE. If location is outside the cave
529 boolean outside(loc)
530 int loc;
532 return (bitset(g.loc_attrib[loc], 6));
536 Routine true x% of the time. (x an integer from 0 to 100)
538 int pct(x)
539 int x;
541 return (ranz(100) < x);
545 plural .TRUE. if object is multiple objects
547 boolean plural(obj)
548 int obj;
550 return (bitset(g.obj_state[obj], 13));
554 portal .TRUE. If location is a cave entrance
556 boolean portal(loc)
557 int loc;
559 return (bitset(g.loc_attrib[loc], 5));
563 printed .TRUE. If object can be read.
565 boolean printed(obj)
566 int obj;
568 return (bitset(g.obj_state[obj], 8));
572 put is the same as move, except it returns a
573 value used to set the negated prop values
574 for the repository objects.
576 int put(obj, where, pval)
577 int obj, where, pval;
579 move(obj, where);
580 return ((-1) - pval);
584 RANZ
586 int ranz(range)
587 int range;
589 return (rand() % range);
593 small .TRUE. If object fits in sack or small container
595 boolean small(obj)
596 int obj;
598 return (bitset(g.obj_state[obj], 5));
602 toting .TRUE. If an item is being caried.
604 int toting(item)
605 int item;
607 boolean aaa, bbb, ccc;
608 int contnr, outer, outer2;
610 contnr = -g.place[item];
611 outer = -g.place[contnr];
612 outer2 = -g.place[outer];
614 aaa = holding(contnr);
615 bbb = enclosed(contnr) && holding(outer);
616 ccc = enclosed(outer) && holding(outer2);
618 return (holding(item) || (enclosed(item) && (aaa || bbb || ccc)));
622 treasr .TRUE. If object is valuable for points
624 boolean treasr(obj)
625 int obj;
627 return (bitset(g.obj_state[obj], 14));
631 vessel .TRUE. if object can hold a liquid
633 boolean vessel(obj)
634 int obj;
636 return (bitset(g.obj_state[obj], 15));
640 wearng .TRUE. If wearing obj
642 boolean wearng(item)
643 int item;
645 return (bitset(g.obj_state[item], WEARBT));
649 worn .TRUE. if object is being worn
651 boolean worn(obj)
652 int obj;
654 return (bitset(g.obj_state[obj], 11));
657 static char *e_msg[] = {
658 "message line > 70 characters", /* 00 */
659 "null line in message", /* 01 */
660 "too many words of messages", /* 02 */
661 "too many travel options", /* 03 */
662 "too many vocabulary words", /* 04 */
663 "required vocabulary word not found", /* 05 */
664 "too many rtext or mtext messages", /* 06 */
665 "too many hints", /* 07 */
666 "location has loc_attrib bit being set twice", /* 08 */
667 "invalid section number in database", /* 09 */
668 "out of order locs or rspeak entries.", /* 10 */
669 "illegal motion word in travel table", /* 11 */
670 "** unused **.",/* 12 */
671 "unknown or illegal word in adjective table.", /* 13 */
672 "illegal word in prep/obj table", /* 14 */
673 "too many entries in prep/obj table", /* 15 */
674 "object has condition bit set twice", /* 16 */
675 "object number too large", /* 17 */
676 "too many entries in adjective/noun table.", /* 18 */
677 "** unused **.",/* 19 */
678 "special travel (500>l>300) exceeds goto list", /* 20 */
679 "ran off end of vocabulary table", /* 21 */
680 "verb class (n/1000) not between 1 and 3", /* 22 */
681 "intransitive action verb exceeds goto list", /* 23 */
682 "transitive action verb exceeds goto list", /* 24 */
683 "conditional travel entry with no alternative", /* 25 */
684 "location has no travel entries", /* 26 */
685 "hint number exceeds goto list", /* 27 */
686 "invalid month returned by date function", /* 28 */
687 "action verb 'leave' has no object.", /* 29 */
688 "preposition found in unexpected table", /* 30 */
689 "received an unexpected word terminator from a1toa5", /* 31 */
690 "trying to put a container into itself (tricky!)", /* 32 */
691 "unknown word class in getwds", /* 33 */
692 "** unused **.",/* 34 */
693 "trying to carry a non-existent object"}; /* 35 */
696 Fatal error routine
698 void bug(n)
699 unsigned int n;
701 if (n < 36 && *e_msg[n] != '*')
702 fprintf(stderr, "Fatal error, probable cause: %s\n", e_msg[n]);
703 else
704 fprintf(stderr, "Fatal error number %d - Unused error number!\n", n);
705 panic((char *) 0, TRUE);
709 Prompt for input, strip leading and trailing spaces,
710 return &buf[first non-whitespace].
711 Does not return if end of input.
713 char *
714 ask(prompt, buf, buflen)
715 char *prompt, *buf;
716 int buflen;
718 fputs(prompt, stdout);
719 fflush(stdout);
720 if (!fgets(buf, buflen, stdin))
721 panic("end of input", FALSE);
722 if (*buf) {
723 int c;
724 char *end = buf + strlen(buf);
725 if (end[-1] != '\n')
726 /* Skip to end of line */
727 while ((c = getchar()) != '\n' && c != EOF);
728 while (*buf && isspace(*buf))
729 buf++;
730 while (buf <= --end && isspace(*end))
731 *end = '\0';
733 return buf;
737 save and abort
740 void panic(msg, save)
741 char *msg;
742 boolean save;
744 fprintf(stderr, "\nPANIC: %s%s\n",
745 msg ? msg : "", save ? ". Save..." : msg ? "" : "aborting.");
746 if (save)
747 saveadv("advpanic.sav");
748 exit(EXIT_FAILURE);