750 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			750 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
  Utility Routines
 | 
						|
  the next logical funtions describe attributes of objects.
 | 
						|
  (ajar, hinged, opaque, printd, treasr, vessel, wearng)
 | 
						|
*/
 | 
						|
 | 
						|
#include	<stdio.h>
 | 
						|
#include	<stdlib.h>
 | 
						|
#include	<ctype.h>
 | 
						|
#include	<string.h>
 | 
						|
#include	"advent.h"
 | 
						|
#include	"advdec.h"
 | 
						|
 | 
						|
/*
 | 
						|
  ajar .TRUE. if item is container and is open or unhinged
 | 
						|
*/
 | 
						|
boolean ajar(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    return ((bitset(g.obj_state[item], OPENBT))
 | 
						|
	    || (vessel(item) && !hinged(item)));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  at .TRUE. To tell if player is on either side of a two sided object.
 | 
						|
*/
 | 
						|
boolean at(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    if (item < 1 || item > MAXOBJ)
 | 
						|
	return (FALSE);
 | 
						|
    else
 | 
						|
	return (g.place[item] == g.loc || g.fixed[item] == g.loc);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  athand .TRUE. if item readily reachable
 | 
						|
  it can be lying here, in hand or in open container.
 | 
						|
*/
 | 
						|
boolean athand(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    int contnr;
 | 
						|
    boolean aaa;
 | 
						|
 | 
						|
    contnr = -g.place[item];
 | 
						|
    aaa = enclosed(item) && ajar(contnr);
 | 
						|
 | 
						|
    return ((g.place[item] == g.loc) || holding(item)
 | 
						|
	    || (aaa && ((g.place[contnr] == g.loc)
 | 
						|
			|| (toting(item) && holding(contnr)))));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  bitoff turns off (sets to 0) a bit in obj_state word
 | 
						|
*/
 | 
						|
void bitoff(obj, bit)
 | 
						|
int obj, bit;
 | 
						|
{
 | 
						|
    long val;
 | 
						|
 | 
						|
    val = 1L << bit;
 | 
						|
    g.obj_state[obj] &= ~val;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  biton turns on (sets to 1) a bit in obj_state word
 | 
						|
*/
 | 
						|
void biton(obj, bit)
 | 
						|
int obj, bit;
 | 
						|
{
 | 
						|
    long val;
 | 
						|
 | 
						|
    val = 1L << bit;
 | 
						|
    g.obj_state[obj] |= val;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   bitset .TRUE. if object_state has bit N set
 | 
						|
*/
 | 
						|
boolean bitset(state, bit)
 | 
						|
long state;
 | 
						|
int bit;
 | 
						|
{
 | 
						|
    return (((state >> bit) & 1) == 1);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  blind .TRUE. if you can't see at this loc, (darkness of glare)
 | 
						|
*/
 | 
						|
boolean blind()
 | 
						|
{
 | 
						|
    return (dark() || (g.loc == 200
 | 
						|
		       && athand(LAMP) && (g.prop[LAMP] == 1)));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   burden .. returns weight of items being carried
 | 
						|
 | 
						|
   if obj=0, burden calculates the total weight of the adventurer's burden
 | 
						|
   including everything in all containers (except the boat) that he is
 | 
						|
   carring.
 | 
						|
 | 
						|
   if object is a container, calculate the weight of everything inside
 | 
						|
   the container (including the container itself). Since donkey FORTRAN
 | 
						|
   isn't recursive, we will only calculate weight of contained containers
 | 
						|
   one level down.  The only serious contained container would be the sack
 | 
						|
   The only thing we'll miss will be filled VS empty bottle or cage.
 | 
						|
 | 
						|
   If object isn't a container, return its weight.
 | 
						|
*/
 | 
						|
int burden(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    int i, sum, temp;
 | 
						|
 | 
						|
    sum = 0;
 | 
						|
    if (obj == 0) {
 | 
						|
	for (i = 1; i < MAXOBJ; i++) {
 | 
						|
	    if (toting(i) && (g.place[i] != -BOAT))
 | 
						|
		sum += g.weight[i];
 | 
						|
	}
 | 
						|
    } else {
 | 
						|
	if (obj != BOAT) {
 | 
						|
	    sum = g.weight[obj];
 | 
						|
	    temp = g.holder[obj];
 | 
						|
	    while (temp != 0) {
 | 
						|
		sum += g.weight[temp];
 | 
						|
		temp = g.hlink[temp];
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return (sum);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Routine to carry an object
 | 
						|
  start toting an object, removing it from the list of things
 | 
						|
  at its former location.  If object > MAXOBJ ( moving "FIXED"
 | 
						|
  or second loc), then don't change place.
 | 
						|
*/
 | 
						|
void carry(obj, where)
 | 
						|
int obj, where;
 | 
						|
{
 | 
						|
    int temp;
 | 
						|
 | 
						|
    if (obj < MAXOBJ) {
 | 
						|
	if (g.place[obj] == -1)
 | 
						|
	    return;
 | 
						|
	g.place[obj] = -1;
 | 
						|
    }
 | 
						|
    if (g.atloc[where] == obj)
 | 
						|
	g.atloc[where] = g.link[obj];
 | 
						|
    else {
 | 
						|
	temp = g.atloc[where];
 | 
						|
	while (g.link[temp] != obj) {
 | 
						|
	    temp = g.link[temp];
 | 
						|
	    if (temp == 0)
 | 
						|
		bug(35);
 | 
						|
	}
 | 
						|
	g.link[temp] = g.link[obj];
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  confuz generates some variant of "Don't understand that" message.
 | 
						|
*/
 | 
						|
int confuz()
 | 
						|
{
 | 
						|
    int msg;
 | 
						|
 | 
						|
    msg = 60;
 | 
						|
    if (pct(50))
 | 
						|
	msg = 61;
 | 
						|
    if (pct(33))
 | 
						|
	msg = 13;
 | 
						|
    if (pct(25))
 | 
						|
	msg = 347;
 | 
						|
    if (pct(20))
 | 
						|
	msg = 195;
 | 
						|
    return (msg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  dark .TRUE. if there is no light here
 | 
						|
*/
 | 
						|
boolean dark()
 | 
						|
{
 | 
						|
    return (!(g.loc_attrib[g.loc] & LIGHT) &&
 | 
						|
	    (!g.prop[LAMP] || !athand(LAMP)));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Routine to check for presence
 | 
						|
  of dwarves..
 | 
						|
*/
 | 
						|
int dcheck()
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 1; i < (DWARFMAX); ++i)
 | 
						|
	if (g.dloc[i] == g.loc)
 | 
						|
	    return (i);
 | 
						|
    return (0);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   dead .TRUE. if object is now dead
 | 
						|
*/
 | 
						|
boolean dead(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[obj], 10));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  drop Place an object at a given loc, prefixing it onto the atloc list.
 | 
						|
*/
 | 
						|
void drop(obj, where)
 | 
						|
int obj, where;
 | 
						|
{
 | 
						|
    if (obj > MAXOBJ)
 | 
						|
	g.fixed[obj - MAXOBJ] = where;
 | 
						|
    else
 | 
						|
	g.place[obj] = where;
 | 
						|
    if (where > 0) {
 | 
						|
	g.link[obj] = g.atloc[where];
 | 
						|
	g.atloc[where] = obj;
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  destroy Permanently eliminate "object" by moving it to
 | 
						|
  a non-existent location.
 | 
						|
*/
 | 
						|
void destroy(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    move(obj, 0);
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   edible .TRUE. if obj can be eaten.
 | 
						|
*/
 | 
						|
boolean edible(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[obj], 7));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  enclosed .TRUE. If object is inside a container.
 | 
						|
*/
 | 
						|
boolean enclosed(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    if (item < 1 || item > MAXOBJ)
 | 
						|
	return (FALSE);
 | 
						|
    else
 | 
						|
	return (g.place[item] < -1);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   extract remove "object" from a container.
 | 
						|
   origionally name "remove" but rename to avoid conflict with stdio.h
 | 
						|
*/
 | 
						|
void extract(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    int contnr, temp;
 | 
						|
 | 
						|
    contnr = -g.place[obj];
 | 
						|
    g.place[obj] = -1;
 | 
						|
    if (g.holder[contnr] == obj)
 | 
						|
	g.holder[contnr] = g.hlink[obj];
 | 
						|
    else {
 | 
						|
	temp = g.holder[contnr];
 | 
						|
	while (g.hlink[temp] != obj) {
 | 
						|
	    temp = g.hlink[temp];
 | 
						|
	    if (temp == 0)
 | 
						|
		bug(35);
 | 
						|
	}
 | 
						|
	g.hlink[temp] = g.hlink[obj];
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  forced To tell if a location will causes a forced move.
 | 
						|
  A forced location is one from which he is immediately bounced
 | 
						|
  to another.  Normal use is for death (forced to location zero)
 | 
						|
  and for description of journey from on place to another.
 | 
						|
*/
 | 
						|
int forced(at_loc)
 | 
						|
int at_loc;
 | 
						|
{
 | 
						|
    return ((g.loc_attrib[at_loc] & 10) == 2);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  here .TRUE. If an item is at location or is being carried.
 | 
						|
*/
 | 
						|
boolean here(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    return (g.place[item] == g.loc || toting(item));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  hinged .TRUE. If object can be opened or shut.
 | 
						|
*/
 | 
						|
boolean hinged(object)
 | 
						|
int object;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[object], 1));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  holding .TRUE. If the object is being carried in hand.
 | 
						|
*/
 | 
						|
boolean holding(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    if (item < 1 || item > MAXOBJ)
 | 
						|
	return (FALSE);
 | 
						|
    else
 | 
						|
	return (g.place[item] == -1);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  insert
 | 
						|
*/
 | 
						|
void insert(obj, contnr)
 | 
						|
int obj, contnr;
 | 
						|
{
 | 
						|
    int temp;
 | 
						|
 | 
						|
    if (contnr == obj)
 | 
						|
	bug(32);
 | 
						|
    carry(obj, g.loc);
 | 
						|
 | 
						|
    temp = g.holder[contnr];
 | 
						|
    g.holder[contnr] = obj;
 | 
						|
    g.hlink[obj] = temp;
 | 
						|
    g.place[obj] = -contnr;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  inside = .TRUE. If location is well within cave
 | 
						|
*/
 | 
						|
boolean inside(loc)
 | 
						|
int loc;
 | 
						|
{
 | 
						|
    return (!outside(loc) && !portal(loc));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Juggle an object by picking it up and putting it down again,
 | 
						|
  The purpose being to get the object to the front of the chain
 | 
						|
  at its loc.
 | 
						|
*/
 | 
						|
void juggle(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    int i, j;
 | 
						|
 | 
						|
    i = g.place[obj];
 | 
						|
    j = g.fixed[obj];
 | 
						|
    move(obj, i);
 | 
						|
    move(obj + MAXOBJ, j);
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Determine liquid in the vessel
 | 
						|
*/
 | 
						|
int liq(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    int liquid;
 | 
						|
 | 
						|
    if ((item == BOTTLE) || (item == CASK))
 | 
						|
	liquid = liq2(((int) g.prop[item] >> 1) & 7);
 | 
						|
    else
 | 
						|
	liquid = 0;
 | 
						|
 | 
						|
    return (liquid);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Determine type of liquid in vessel
 | 
						|
*/
 | 
						|
int liq2(liquid)
 | 
						|
int liquid;
 | 
						|
{
 | 
						|
    switch (liquid) {
 | 
						|
    case 4:
 | 
						|
	return (WATER);
 | 
						|
    case 5:
 | 
						|
	return (OIL);
 | 
						|
    case 6:
 | 
						|
	return (WINE);
 | 
						|
    default:
 | 
						|
	return (0);			/* empty */
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Determine liquid at a location
 | 
						|
*/
 | 
						|
int liqloc(loc)
 | 
						|
int loc;
 | 
						|
{
 | 
						|
    return (liq2((int) ((g.loc_attrib[loc] >> 1) & 7)));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   living .TRUE. If object is living, bear for example
 | 
						|
*/
 | 
						|
boolean living(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[obj], 9));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   locked .TRUE. if lockable object is locked
 | 
						|
*/
 | 
						|
boolean locked(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[item], 4));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   locks .TRUE. if you can lock this object
 | 
						|
*/
 | 
						|
boolean locks(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[item], 3));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  LOOKIN list contents if obj is a container and is open or transparent.
 | 
						|
*/
 | 
						|
void lookin(contnr)
 | 
						|
int contnr;
 | 
						|
{
 | 
						|
    int temp;
 | 
						|
    boolean first_time;
 | 
						|
 | 
						|
    if (vessel(contnr) && (ajar(contnr) || !opaque(contnr))) {
 | 
						|
	temp = g.holder[contnr];
 | 
						|
	first_time = TRUE;
 | 
						|
	while (temp != 0) {
 | 
						|
	    if (first_time)
 | 
						|
		rspeak(360);
 | 
						|
	    printf("     ");
 | 
						|
	    pspeak(temp, -1);
 | 
						|
	    temp = g.hlink[temp];
 | 
						|
	    first_time = FALSE;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Routine to move an object
 | 
						|
*/
 | 
						|
void move(obj, where)
 | 
						|
int obj, where;
 | 
						|
{
 | 
						|
    int from;
 | 
						|
 | 
						|
    if (obj > MAXOBJ)
 | 
						|
	from = g.fixed[obj - MAXOBJ];
 | 
						|
    else {
 | 
						|
	if (enclosed(obj))
 | 
						|
	    extract(obj);
 | 
						|
	from = g.place[obj];
 | 
						|
    }
 | 
						|
    if ((from > 0) && (from < MAXOBJ * 2))
 | 
						|
	carry(obj, from);
 | 
						|
    drop(obj, where);
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  noway, generate's some variant of "can't do that" message.
 | 
						|
*/
 | 
						|
int noway()
 | 
						|
{
 | 
						|
    int msg;
 | 
						|
 | 
						|
    msg = 14;
 | 
						|
    if (pct(50))
 | 
						|
	msg = 110;
 | 
						|
    if (pct(33))
 | 
						|
	msg = 147;
 | 
						|
    if (pct(25))
 | 
						|
	msg = 250;
 | 
						|
    if (pct(20))
 | 
						|
	msg = 262;
 | 
						|
    if (pct(17))
 | 
						|
	msg = 25;
 | 
						|
    if (pct(14))
 | 
						|
	msg = 345;
 | 
						|
    if (pct(12))
 | 
						|
	msg = 346;
 | 
						|
    return (msg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  opaque .TRUE. If obj is non-transparent container
 | 
						|
*/
 | 
						|
boolean opaque(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[obj], 6));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   outsid .TRUE. If location is outside the cave
 | 
						|
*/
 | 
						|
boolean outside(loc)
 | 
						|
int loc;
 | 
						|
{
 | 
						|
    return (bitset(g.loc_attrib[loc], 6));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Routine true x% of the time. (x an integer from 0 to 100)
 | 
						|
*/
 | 
						|
int pct(x)
 | 
						|
int x;
 | 
						|
{
 | 
						|
    return (ranz(100) < x);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   plural .TRUE. if object is multiple objects
 | 
						|
*/
 | 
						|
boolean plural(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[obj], 13));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   portal .TRUE. If location is a cave entrance
 | 
						|
*/
 | 
						|
boolean portal(loc)
 | 
						|
int loc;
 | 
						|
{
 | 
						|
    return (bitset(g.loc_attrib[loc], 5));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   printed .TRUE. If object can be read.
 | 
						|
*/
 | 
						|
boolean printed(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[obj], 8));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  put is the same as move, except it returns a
 | 
						|
  value used to set the negated prop values
 | 
						|
  for the repository objects.
 | 
						|
*/
 | 
						|
int put(obj, where, pval)
 | 
						|
int obj, where, pval;
 | 
						|
{
 | 
						|
    move(obj, where);
 | 
						|
    return ((-1) - pval);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  RANZ
 | 
						|
*/
 | 
						|
int ranz(range)
 | 
						|
int range;
 | 
						|
{
 | 
						|
    return (rand() % range);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   small .TRUE. If object fits in sack or small container
 | 
						|
*/
 | 
						|
boolean small(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[obj], 5));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  toting .TRUE. If an item is being caried.
 | 
						|
*/
 | 
						|
int toting(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    boolean aaa, bbb, ccc;
 | 
						|
    int contnr, outer, outer2;
 | 
						|
 | 
						|
    contnr = -g.place[item];
 | 
						|
    outer = -g.place[contnr];
 | 
						|
    outer2 = -g.place[outer];
 | 
						|
 | 
						|
    aaa = holding(contnr);
 | 
						|
    bbb = enclosed(contnr) && holding(outer);
 | 
						|
    ccc = enclosed(outer) && holding(outer2);
 | 
						|
 | 
						|
    return (holding(item) || (enclosed(item) && (aaa || bbb || ccc)));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  treasr .TRUE. If object is valuable for points
 | 
						|
*/
 | 
						|
boolean treasr(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[obj], 14));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  vessel .TRUE. if object can hold a liquid
 | 
						|
*/
 | 
						|
boolean vessel(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[obj], 15));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  wearng .TRUE. If wearing obj
 | 
						|
*/
 | 
						|
boolean wearng(item)
 | 
						|
int item;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[item], WEARBT));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
   worn .TRUE. if object is being worn
 | 
						|
*/
 | 
						|
boolean worn(obj)
 | 
						|
int obj;
 | 
						|
{
 | 
						|
    return (bitset(g.obj_state[obj], 11));
 | 
						|
}
 | 
						|
 | 
						|
static char *e_msg[] = {
 | 
						|
			"message line > 70 characters",	/* 00 */
 | 
						|
			"null line in message",	/* 01 */
 | 
						|
			"too many words of messages",	/* 02 */
 | 
						|
			"too many travel options",	/* 03 */
 | 
						|
			"too many vocabulary words",	/* 04 */
 | 
						|
			"required vocabulary word not found",	/* 05 */
 | 
						|
			"too many rtext or mtext messages",	/* 06 */
 | 
						|
			"too many hints",	/* 07 */
 | 
						|
			"location has loc_attrib bit being set twice",	/* 08 */
 | 
						|
			"invalid section number in database",	/* 09 */
 | 
						|
			"out of order locs or rspeak entries.",	/* 10 */
 | 
						|
			"illegal motion word in travel table",	/* 11 */
 | 
						|
			"** unused **.",/* 12 */
 | 
						|
			"unknown or illegal word in adjective table.",	/* 13 */
 | 
						|
			"illegal word in prep/obj table",	/* 14 */
 | 
						|
			"too many entries in prep/obj table",	/* 15 */
 | 
						|
			"object has condition bit set twice",	/* 16 */
 | 
						|
			"object number too large",	/* 17 */
 | 
						|
			"too many entries in adjective/noun table.",	/* 18 */
 | 
						|
			"** unused **.",/* 19 */
 | 
						|
			"special travel (500>l>300) exceeds goto list",	/* 20 */
 | 
						|
			"ran off end of vocabulary table",	/* 21 */
 | 
						|
			"verb class (n/1000) not between 1 and 3",	/* 22 */
 | 
						|
			"intransitive action verb exceeds goto list",	/* 23 */
 | 
						|
			"transitive action verb exceeds goto list",	/* 24 */
 | 
						|
			"conditional travel entry with no alternative",	/* 25 */
 | 
						|
			"location has no travel entries",	/* 26 */
 | 
						|
			"hint number exceeds goto list",	/* 27 */
 | 
						|
			"invalid month returned by date function",	/* 28 */
 | 
						|
			"action verb 'leave' has no object.",	/* 29 */
 | 
						|
			"preposition found in unexpected table",	/* 30 */
 | 
						|
		 "received an unexpected word terminator from a1toa5",	/* 31 */
 | 
						|
		    "trying to put a container into itself (tricky!)",	/* 32 */
 | 
						|
			"unknown word class in getwds",	/* 33 */
 | 
						|
			"** unused **.",/* 34 */
 | 
						|
			"trying to carry a non-existent object"};	/* 35 */
 | 
						|
 | 
						|
/*
 | 
						|
  Fatal error routine
 | 
						|
*/
 | 
						|
void bug(n)
 | 
						|
unsigned int n;
 | 
						|
{
 | 
						|
    if (n < 36 && *e_msg[n] != '*')
 | 
						|
	fprintf(stderr, "Fatal error, probable cause: %s\n", e_msg[n]);
 | 
						|
    else
 | 
						|
	fprintf(stderr, "Fatal error number %d - Unused error number!\n", n);
 | 
						|
    panic((char *) 0, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  Prompt for input, strip leading and trailing spaces,
 | 
						|
  return &buf[first non-whitespace].
 | 
						|
  Does not return if end of input.
 | 
						|
*/
 | 
						|
char *
 | 
						|
 ask(prompt, buf, buflen)
 | 
						|
char *prompt, *buf;
 | 
						|
int buflen;
 | 
						|
{
 | 
						|
    fputs(prompt, stdout);
 | 
						|
    fflush(stdout);
 | 
						|
    if (!fgets(buf, buflen, stdin))
 | 
						|
	panic("end of input", FALSE);
 | 
						|
    if (*buf) {
 | 
						|
	int c;
 | 
						|
	char *end = buf + strlen(buf);
 | 
						|
	if (end[-1] != '\n')
 | 
						|
	    /* Skip to end of line */
 | 
						|
	    while ((c = getchar()) != '\n' && c != EOF);
 | 
						|
	while (*buf && isspace(*buf))
 | 
						|
	    buf++;
 | 
						|
	while (buf <= --end && isspace(*end))
 | 
						|
	    *end = '\0';
 | 
						|
    }
 | 
						|
    return buf;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  save and abort
 | 
						|
*/
 | 
						|
 | 
						|
void panic(msg, save)
 | 
						|
char *msg;
 | 
						|
boolean save;
 | 
						|
{
 | 
						|
    fprintf(stderr, "\nPANIC: %s%s\n",
 | 
						|
	 msg ? msg : "", save ? ". Save..." : msg ? "" : "aborting.");
 | 
						|
    if (save)
 | 
						|
	saveadv("advpanic.sav");
 | 
						|
    exit(EXIT_FAILURE);
 | 
						|
}
 |