utility.c

Go to the documentation of this file.
00001 /*
00002   Utility Routines
00003   the next logical funtions describe attributes of objects.
00004   (ajar, hinged, opaque, printd, treasr, vessel, wearng)
00005 */
00006 
00007 #include        <stdio.h>
00008 #include        <stdlib.h>
00009 #include        <ctype.h>
00010 #include        <string.h>
00011 #include        "advent.h"
00012 #include        "advdec.h"
00013 
00014 /*
00015   ajar .TRUE. if item is container and is open or unhinged
00016 */
00017 boolean ajar(item)
00018 int item;
00019 {
00020     return ((bitset(g.obj_state[item], OPENBT))
00021             || (vessel(item) && !hinged(item)));
00022 }
00023 
00024 /*
00025   at .TRUE. To tell if player is on either side of a two sided object.
00026 */
00027 boolean at(item)
00028 int item;
00029 {
00030     if (item < 1 || item > MAXOBJ)
00031         return (FALSE);
00032     else
00033         return (g.place[item] == g.loc || g.fixed[item] == g.loc);
00034 }
00035 
00036 /*
00037   athand .TRUE. if item readily reachable
00038   it can be lying here, in hand or in open container.
00039 */
00040 boolean athand(item)
00041 int item;
00042 {
00043     int contnr;
00044     boolean aaa;
00045 
00046     contnr = -g.place[item];
00047     aaa = enclosed(item) && ajar(contnr);
00048 
00049     return ((g.place[item] == g.loc) || holding(item)
00050             || (aaa && ((g.place[contnr] == g.loc)
00051                         || (toting(item) && holding(contnr)))));
00052 }
00053 
00054 /*
00055   bitoff turns off (sets to 0) a bit in obj_state word
00056 */
00057 void bitoff(obj, bit)
00058 int obj, bit;
00059 {
00060     long val;
00061 
00062     val = 1L << bit;
00063     g.obj_state[obj] &= ~val;
00064 }
00065 
00066 /*
00067   biton turns on (sets to 1) a bit in obj_state word
00068 */
00069 void biton(obj, bit)
00070 int obj, bit;
00071 {
00072     long val;
00073 
00074     val = 1L << bit;
00075     g.obj_state[obj] |= val;
00076 }
00077 
00078 /*
00079    bitset .TRUE. if object_state has bit N set
00080 */
00081 boolean bitset(state, bit)
00082 long state;
00083 int bit;
00084 {
00085     return (((state >> bit) & 1) == 1);
00086 }
00087 
00088 /*
00089   blind .TRUE. if you can't see at this loc, (darkness of glare)
00090 */
00091 boolean blind()
00092 {
00093     return (dark() || (g.loc == 200
00094                        && athand(LAMP) && (g.prop[LAMP] == 1)));
00095 }
00096 
00097 /*
00098    burden .. returns weight of items being carried
00099 
00100    if obj=0, burden calculates the total weight of the adventurer's burden
00101    including everything in all containers (except the boat) that he is
00102    carring.
00103 
00104    if object is a container, calculate the weight of everything inside
00105    the container (including the container itself). Since donkey FORTRAN
00106    isn't recursive, we will only calculate weight of contained containers
00107    one level down.  The only serious contained container would be the sack
00108    The only thing we'll miss will be filled VS empty bottle or cage.
00109 
00110    If object isn't a container, return its weight.
00111 */
00112 int burden(obj)
00113 int obj;
00114 {
00115     int i, sum, temp;
00116 
00117     sum = 0;
00118     if (obj == 0) {
00119         for (i = 1; i < MAXOBJ; i++) {
00120             if (toting(i) && (g.place[i] != -BOAT))
00121                 sum += g.weight[i];
00122         }
00123     } else {
00124         if (obj != BOAT) {
00125             sum = g.weight[obj];
00126             temp = g.holder[obj];
00127             while (temp != 0) {
00128                 sum += g.weight[temp];
00129                 temp = g.hlink[temp];
00130             }
00131         }
00132     }
00133     return (sum);
00134 }
00135 
00136 /*
00137   Routine to carry an object
00138   start toting an object, removing it from the list of things
00139   at its former location.  If object > MAXOBJ ( moving "FIXED"
00140   or second loc), then don't change place.
00141 */
00142 void carry(obj, where)
00143 int obj, where;
00144 {
00145     int temp;
00146 
00147     if (obj < MAXOBJ) {
00148         if (g.place[obj] == -1)
00149             return;
00150         g.place[obj] = -1;
00151     }
00152     if (g.atloc[where] == obj)
00153         g.atloc[where] = g.link[obj];
00154     else {
00155         temp = g.atloc[where];
00156         while (g.link[temp] != obj) {
00157             temp = g.link[temp];
00158             if (temp == 0)
00159                 bug(35);
00160         }
00161         g.link[temp] = g.link[obj];
00162     }
00163     return;
00164 }
00165 
00166 /*
00167   confuz generates some variant of "Don't understand that" message.
00168 */
00169 int confuz()
00170 {
00171     int msg;
00172 
00173     msg = 60;
00174     if (pct(50))
00175         msg = 61;
00176     if (pct(33))
00177         msg = 13;
00178     if (pct(25))
00179         msg = 347;
00180     if (pct(20))
00181         msg = 195;
00182     return (msg);
00183 }
00184 
00185 /*
00186   dark .TRUE. if there is no light here
00187 */
00188 boolean dark()
00189 {
00190     return (!(g.loc_attrib[g.loc] & LIGHT) &&
00191             (!g.prop[LAMP] || !athand(LAMP)));
00192 }
00193 
00194 /*
00195   Routine to check for presence
00196   of dwarves..
00197 */
00198 int dcheck()
00199 {
00200     int i;
00201 
00202     for (i = 1; i < (DWARFMAX); ++i)
00203         if (g.dloc[i] == g.loc)
00204             return (i);
00205     return (0);
00206 }
00207 
00208 /*
00209    dead .TRUE. if object is now dead
00210 */
00211 boolean dead(obj)
00212 int obj;
00213 {
00214     return (bitset(g.obj_state[obj], 10));
00215 }
00216 
00217 /*
00218   drop Place an object at a given loc, prefixing it onto the atloc list.
00219 */
00220 void drop(obj, where)
00221 int obj, where;
00222 {
00223     if (obj > MAXOBJ)
00224         g.fixed[obj - MAXOBJ] = where;
00225     else
00226         g.place[obj] = where;
00227     if (where > 0) {
00228         g.link[obj] = g.atloc[where];
00229         g.atloc[where] = obj;
00230     }
00231     return;
00232 }
00233 
00234 /*
00235   destroy Permanently eliminate "object" by moving it to
00236   a non-existent location.
00237 */
00238 void destroy(obj)
00239 int obj;
00240 {
00241     move(obj, 0);
00242     return;
00243 }
00244 
00245 /*
00246    edible .TRUE. if obj can be eaten.
00247 */
00248 boolean edible(obj)
00249 int obj;
00250 {
00251     return (bitset(g.obj_state[obj], 7));
00252 }
00253 
00254 /*
00255   enclosed .TRUE. If object is inside a container.
00256 */
00257 boolean enclosed(item)
00258 int item;
00259 {
00260     if (item < 1 || item > MAXOBJ)
00261         return (FALSE);
00262     else
00263         return (g.place[item] < -1);
00264 }
00265 
00266 /*
00267    extract remove "object" from a container.
00268    origionally name "remove" but rename to avoid conflict with stdio.h
00269 */
00270 void extract(obj)
00271 int obj;
00272 {
00273     int contnr, temp;
00274 
00275     contnr = -g.place[obj];
00276     g.place[obj] = -1;
00277     if (g.holder[contnr] == obj)
00278         g.holder[contnr] = g.hlink[obj];
00279     else {
00280         temp = g.holder[contnr];
00281         while (g.hlink[temp] != obj) {
00282             temp = g.hlink[temp];
00283             if (temp == 0)
00284                 bug(35);
00285         }
00286         g.hlink[temp] = g.hlink[obj];
00287     }
00288     return;
00289 }
00290 
00291 /*
00292   forced To tell if a location will causes a forced move.
00293   A forced location is one from which he is immediately bounced
00294   to another.  Normal use is for death (forced to location zero)
00295   and for description of journey from on place to another.
00296 */
00297 int forced(at_loc)
00298 int at_loc;
00299 {
00300     return ((g.loc_attrib[at_loc] & 10) == 2);
00301 }
00302 
00303 /*
00304   here .TRUE. If an item is at location or is being carried.
00305 */
00306 boolean here(item)
00307 int item;
00308 {
00309     return (g.place[item] == g.loc || toting(item));
00310 }
00311 
00312 /*
00313   hinged .TRUE. If object can be opened or shut.
00314 */
00315 boolean hinged(object)
00316 int object;
00317 {
00318     return (bitset(g.obj_state[object], 1));
00319 }
00320 
00321 /*
00322   holding .TRUE. If the object is being carried in hand.
00323 */
00324 boolean holding(item)
00325 int item;
00326 {
00327     if (item < 1 || item > MAXOBJ)
00328         return (FALSE);
00329     else
00330         return (g.place[item] == -1);
00331 }
00332 
00333 /*
00334   insert
00335 */
00336 void insert(obj, contnr)
00337 int obj, contnr;
00338 {
00339     int temp;
00340 
00341     if (contnr == obj)
00342         bug(32);
00343     carry(obj, g.loc);
00344 
00345     temp = g.holder[contnr];
00346     g.holder[contnr] = obj;
00347     g.hlink[obj] = temp;
00348     g.place[obj] = -contnr;
00349 }
00350 
00351 /*
00352   inside = .TRUE. If location is well within cave
00353 */
00354 boolean inside(loc)
00355 int loc;
00356 {
00357     return (!outside(loc) && !portal(loc));
00358 }
00359 
00360 /*
00361   Juggle an object by picking it up and putting it down again,
00362   The purpose being to get the object to the front of the chain
00363   at its loc.
00364 */
00365 void juggle(obj)
00366 int obj;
00367 {
00368     int i, j;
00369 
00370     i = g.place[obj];
00371     j = g.fixed[obj];
00372     move(obj, i);
00373     move(obj + MAXOBJ, j);
00374     return;
00375 }
00376 
00377 /*
00378   Determine liquid in the vessel
00379 */
00380 int liq(item)
00381 int item;
00382 {
00383     int liquid;
00384 
00385     if ((item == BOTTLE) || (item == CASK))
00386         liquid = liq2(((int) g.prop[item] >> 1) & 7);
00387     else
00388         liquid = 0;
00389 
00390     return (liquid);
00391 }
00392 
00393 /*
00394   Determine type of liquid in vessel
00395 */
00396 int liq2(liquid)
00397 int liquid;
00398 {
00399     switch (liquid) {
00400     case 4:
00401         return (WATER);
00402     case 5:
00403         return (OIL);
00404     case 6:
00405         return (WINE);
00406     default:
00407         return (0);                     /* empty */
00408     }
00409 }
00410 
00411 /*
00412   Determine liquid at a location
00413 */
00414 int liqloc(loc)
00415 int loc;
00416 {
00417     return (liq2((int) ((g.loc_attrib[loc] >> 1) & 7)));
00418 }
00419 
00420 /*
00421    living .TRUE. If object is living, bear for example
00422 */
00423 boolean living(obj)
00424 int obj;
00425 {
00426     return (bitset(g.obj_state[obj], 9));
00427 }
00428 
00429 /*
00430    locked .TRUE. if lockable object is locked
00431 */
00432 boolean locked(item)
00433 int item;
00434 {
00435     return (bitset(g.obj_state[item], 4));
00436 }
00437 
00438 /*
00439    locks .TRUE. if you can lock this object
00440 */
00441 boolean locks(item)
00442 int item;
00443 {
00444     return (bitset(g.obj_state[item], 3));
00445 }
00446 
00447 /*
00448   LOOKIN list contents if obj is a container and is open or transparent.
00449 */
00450 void lookin(contnr)
00451 int contnr;
00452 {
00453     int temp;
00454     boolean first_time;
00455 
00456     if (vessel(contnr) && (ajar(contnr) || !opaque(contnr))) {
00457         temp = g.holder[contnr];
00458         first_time = TRUE;
00459         while (temp != 0) {
00460             if (first_time)
00461                 rspeak(360);
00462             printf("     ");
00463             pspeak(temp, -1);
00464             temp = g.hlink[temp];
00465             first_time = FALSE;
00466         }
00467     }
00468     return;
00469 }
00470 
00471 /*
00472   Routine to move an object
00473 */
00474 void move(obj, where)
00475 int obj, where;
00476 {
00477     int from;
00478 
00479     if (obj > MAXOBJ)
00480         from = g.fixed[obj - MAXOBJ];
00481     else {
00482         if (enclosed(obj))
00483             extract(obj);
00484         from = g.place[obj];
00485     }
00486     if ((from > 0) && (from < MAXOBJ * 2))
00487         carry(obj, from);
00488     drop(obj, where);
00489     return;
00490 }
00491 
00492 /*
00493   noway, generate's some variant of "can't do that" message.
00494 */
00495 int noway()
00496 {
00497     int msg;
00498 
00499     msg = 14;
00500     if (pct(50))
00501         msg = 110;
00502     if (pct(33))
00503         msg = 147;
00504     if (pct(25))
00505         msg = 250;
00506     if (pct(20))
00507         msg = 262;
00508     if (pct(17))
00509         msg = 25;
00510     if (pct(14))
00511         msg = 345;
00512     if (pct(12))
00513         msg = 346;
00514     return (msg);
00515 }
00516 
00517 /*
00518   opaque .TRUE. If obj is non-transparent container
00519 */
00520 boolean opaque(obj)
00521 int obj;
00522 {
00523     return (bitset(g.obj_state[obj], 6));
00524 }
00525 
00526 /*
00527    outsid .TRUE. If location is outside the cave
00528 */
00529 boolean outside(loc)
00530 int loc;
00531 {
00532     return (bitset(g.loc_attrib[loc], 6));
00533 }
00534 
00535 /*
00536   Routine true x% of the time. (x an integer from 0 to 100)
00537 */
00538 int pct(x)
00539 int x;
00540 {
00541     return (ranz(100) < x);
00542 }
00543 
00544 /*
00545    plural .TRUE. if object is multiple objects
00546 */
00547 boolean plural(obj)
00548 int obj;
00549 {
00550     return (bitset(g.obj_state[obj], 13));
00551 }
00552 
00553 /*
00554    portal .TRUE. If location is a cave entrance
00555 */
00556 boolean portal(loc)
00557 int loc;
00558 {
00559     return (bitset(g.loc_attrib[loc], 5));
00560 }
00561 
00562 /*
00563    printed .TRUE. If object can be read.
00564 */
00565 boolean printed(obj)
00566 int obj;
00567 {
00568     return (bitset(g.obj_state[obj], 8));
00569 }
00570 
00571 /*
00572   put is the same as move, except it returns a
00573   value used to set the negated prop values
00574   for the repository objects.
00575 */
00576 int put(obj, where, pval)
00577 int obj, where, pval;
00578 {
00579     move(obj, where);
00580     return ((-1) - pval);
00581 }
00582 
00583 /*
00584   RANZ
00585 */
00586 int ranz(range)
00587 int range;
00588 {
00589     return (rand() % range);
00590 }
00591 
00592 /*
00593    small .TRUE. If object fits in sack or small container
00594 */
00595 boolean small(obj)
00596 int obj;
00597 {
00598     return (bitset(g.obj_state[obj], 5));
00599 }
00600 
00601 /*
00602   toting .TRUE. If an item is being caried.
00603 */
00604 int toting(item)
00605 int item;
00606 {
00607     boolean aaa, bbb, ccc;
00608     int contnr, outer, outer2;
00609 
00610     contnr = -g.place[item];
00611     outer = -g.place[contnr];
00612     outer2 = -g.place[outer];
00613 
00614     aaa = holding(contnr);
00615     bbb = enclosed(contnr) && holding(outer);
00616     ccc = enclosed(outer) && holding(outer2);
00617 
00618     return (holding(item) || (enclosed(item) && (aaa || bbb || ccc)));
00619 }
00620 
00621 /*
00622   treasr .TRUE. If object is valuable for points
00623 */
00624 boolean treasr(obj)
00625 int obj;
00626 {
00627     return (bitset(g.obj_state[obj], 14));
00628 }
00629 
00630 /*
00631   vessel .TRUE. if object can hold a liquid
00632 */
00633 boolean vessel(obj)
00634 int obj;
00635 {
00636     return (bitset(g.obj_state[obj], 15));
00637 }
00638 
00639 /*
00640   wearng .TRUE. If wearing obj
00641 */
00642 boolean wearng(item)
00643 int item;
00644 {
00645     return (bitset(g.obj_state[item], WEARBT));
00646 }
00647 
00648 /*
00649    worn .TRUE. if object is being worn
00650 */
00651 boolean worn(obj)
00652 int obj;
00653 {
00654     return (bitset(g.obj_state[obj], 11));
00655 }
00656 
00657 static char *e_msg[] = {
00658                         "message line > 70 characters", /* 00 */
00659                         "null line in message", /* 01 */
00660                         "too many words of messages",   /* 02 */
00661                         "too many travel options",      /* 03 */
00662                         "too many vocabulary words",    /* 04 */
00663                         "required vocabulary word not found",   /* 05 */
00664                         "too many rtext or mtext messages",     /* 06 */
00665                         "too many hints",       /* 07 */
00666                         "location has loc_attrib bit being set twice",  /* 08 */
00667                         "invalid section number in database",   /* 09 */
00668                         "out of order locs or rspeak entries.", /* 10 */
00669                         "illegal motion word in travel table",  /* 11 */
00670                         "** unused **.",/* 12 */
00671                         "unknown or illegal word in adjective table.",  /* 13 */
00672                         "illegal word in prep/obj table",       /* 14 */
00673                         "too many entries in prep/obj table",   /* 15 */
00674                         "object has condition bit set twice",   /* 16 */
00675                         "object number too large",      /* 17 */
00676                         "too many entries in adjective/noun table.",    /* 18 */
00677                         "** unused **.",/* 19 */
00678                         "special travel (500>l>300) exceeds goto list", /* 20 */
00679                         "ran off end of vocabulary table",      /* 21 */
00680                         "verb class (n/1000) not between 1 and 3",      /* 22 */
00681                         "intransitive action verb exceeds goto list",   /* 23 */
00682                         "transitive action verb exceeds goto list",     /* 24 */
00683                         "conditional travel entry with no alternative", /* 25 */
00684                         "location has no travel entries",       /* 26 */
00685                         "hint number exceeds goto list",        /* 27 */
00686                         "invalid month returned by date function",      /* 28 */
00687                         "action verb 'leave' has no object.",   /* 29 */
00688                         "preposition found in unexpected table",        /* 30 */
00689                  "received an unexpected word terminator from a1toa5",  /* 31 */
00690                     "trying to put a container into itself (tricky!)",  /* 32 */
00691                         "unknown word class in getwds", /* 33 */
00692                         "** unused **.",/* 34 */
00693                         "trying to carry a non-existent object"};       /* 35 */
00694 
00695 /*
00696   Fatal error routine
00697 */
00698 void bug(n)
00699 unsigned int n;
00700 {
00701     if (n < 36 && *e_msg[n] != '*')
00702         fprintf(stderr, "Fatal error, probable cause: %s\n", e_msg[n]);
00703     else
00704         fprintf(stderr, "Fatal error number %d - Unused error number!\n", n);
00705     panic((char *) 0, TRUE);
00706 }
00707 
00708 /*
00709   Prompt for input, strip leading and trailing spaces,
00710   return &buf[first non-whitespace].
00711   Does not return if end of input.
00712 */
00713 char *
00714  ask(prompt, buf, buflen)
00715 char *prompt, *buf;
00716 int buflen;
00717 {
00718     fputs(prompt, stdout);
00719     fflush(stdout);
00720     if (!fgets(buf, buflen, stdin))
00721         panic("end of input", FALSE);
00722     if (*buf) {
00723         int c;
00724         char *end = buf + strlen(buf);
00725         if (end[-1] != '\n')
00726             /* Skip to end of line */
00727             while ((c = getchar()) != '\n' && c != EOF);
00728         while (*buf && isspace(*buf))
00729             buf++;
00730         while (buf <= --end && isspace(*end))
00731             *end = '\0';
00732     }
00733     return buf;
00734 }
00735 
00736 /*
00737   save and abort
00738 */
00739 
00740 void panic(msg, save)
00741 char *msg;
00742 boolean save;
00743 {
00744     fprintf(stderr, "\nPANIC: %s%s\n",
00745          msg ? msg : "", save ? ". Save..." : msg ? "" : "aborting.");
00746     if (save)
00747         saveadv("advpanic.sav");
00748     exit(EXIT_FAILURE);
00749 }

Generated on Fri Apr 14 22:56:39 2006 for minix by  doxygen 1.4.6