Example #1
0
// Fetch attribute text. Use a revolving queue of LBUFFS
//
char *my_atr_get(dbref obj, const char *atrname)
{
    int atr, aflags;
    dbref aowner;
    char *value;
    char name[SBUF_SIZE];
    static char buff[LBUF_SIZE][NUM_BUFFS];
    static int x = 0;

    x = (x + 1) % NUM_BUFFS;

    // Crashes and burns without this. Dunno why.
    strncpy(name, atrname, SBUF_SIZE - 1);
#ifdef TM3
    int alen;
    atr = mkattr(name);
    value = atr_pget(obj, atr, &aowner, &aflags, &alen);
#endif

#ifdef MUX
    atr = mkattr(GOD, name);
    value = atr_pget(obj, atr, &aowner, &aflags);
#endif

    strncpy(buff[x], value, LBUF_SIZE - 1);
    free_lbuf(value);

    return buff[x];
}
Example #2
0
File: eval.c Project: gtaylor/btmux
int get_gender(dbref player)
{
	char first, *atr_gotten;
	dbref aowner;
	long aflags;

	atr_gotten = atr_pget(player, A_SEX, &aowner, &aflags);
	first = *atr_gotten;
	free_lbuf(atr_gotten);
	switch (first) {
	case 'P':
	case 'p':
		return 4;
	case 'M':
	case 'm':
		return 3;
	case 'F':
	case 'f':
	case 'W':
	case 'w':
		return 2;
	default:
		return 1;
	}
}
Example #3
0
static void NDECL(check_cron)
{
    struct tm *ltime;
    int minute, hour, dom, month, dow;
    CRONTAB *crp;
    char *cmd;
    dbref aowner;
    int aflags, alen;

    /* Convert our time to a zero basis, so the elements can be used
     * as indices.
     */

    ltime = localtime(&mudstate.events_counter);
    minute = ltime->tm_min - FIRST_MINUTE;
    hour = ltime->tm_hour - FIRST_HOUR;
    dom = ltime->tm_mday - FIRST_DOM;
    month = ltime->tm_mon + 1 - FIRST_MONTH; /* must convert 0-11 to 1-12 */
    dow = ltime->tm_wday - FIRST_DOW;

    /* Do it if the minute, hour, and month match, plus a day selection
     * matches. We handle stars and the day-of-month vs. day-of-week
     * exactly like Unix (Vixie) cron does.
     */

    for (crp = cron_head; crp != NULL; crp = crp->next) {
	if (bit_test(crp->minute, minute) &&
	    bit_test(crp->hour, hour) &&
	    bit_test(crp->month, month) &&
	    (((crp->flags & DOM_STAR) || (crp->flags & DOW_STAR)) ?
	     (bit_test(crp->dow, dow) && bit_test(crp->dom, dom)) :
	     (bit_test(crp->dow, dow) || bit_test(crp->dom, dom)))) {
	    cmd = atr_pget(crp->obj, crp->atr, &aowner, &aflags, &alen);
	    if (*cmd && Good_obj(crp->obj)) {
		wait_que(crp->obj, crp->obj, 0, NOTHING, 0, cmd,
			 (char **) NULL, 0, NULL);
	    }
	    free_lbuf(cmd);
	}
    }
}
Example #4
0
/* ---------------------------------------------------------------------------
 * did_it_rlevel: Have player do something to/with thing, watching the
 * attributes. 'what' is actually ignored, the desclist match being used
 * instead.
 */
void did_it_rlevel
(
    dbref player,
    dbref thing,
    int   what,
    const UTF8 *def,
    int   owhat,
    const UTF8 *odef,
    int   awhat,
    int   ctrl_flags,
    const UTF8 *args[],
    int   nargs
)
{
    if (MuxAlarm.bAlarmed)
    {
        return;
    }

    UTF8 *d, *buff, *act, *charges, *bp;
    dbref aowner;
    int num, aflags;
    int i;
    bool found_a_desc;

    reg_ref **preserve = NULL;
    bool need_pres = false;

    // Message to player.
    //
    if (0 < what)
    {
        // Get description list.
        //
        DESC_INFO *desclist = desclist_match(player, thing);
        found_a_desc = false;
        for (i = 0; i < desclist->n; i++)
        {
            // Ok, if it's A_DESC, we need to check against A_IDESC.
            //
            if (  A_IDESC == what
               && A_DESC == desclist->descs[i])
            {
                d = atr_pget(thing, A_IDESC, &aowner, &aflags);
            }
            else
            {
                d = atr_pget(thing, desclist->descs[i], &aowner, &aflags);
            }

            if ('\0' != d[0])
            {
                // No need for the 'def' message.
                //
                found_a_desc = true;
                if (!need_pres)
                {
                    need_pres = true;
                    preserve = PushRegisters(MAX_GLOBAL_REGS);
                    save_global_regs(preserve);
                }
                buff = bp = alloc_lbuf("did_it.1");
                mux_exec(d, LBUF_SIZE-1, buff, &bp, thing, thing, player,
                    AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_TOP),
                    args, nargs);
                *bp = '\0';

                if (  A_HTDESC == desclist->descs[i]
                   && Html(player))
                {
                    safe_str(T("\r\n"), buff, &bp);
                    *bp = '\0';
                    notify_html(player, buff);
                }
                else
                {
                    notify(player, buff);
                }
                free_lbuf(buff);
            }
            free_lbuf(d);
        }

        if (!found_a_desc)
        {
            // No desc found... try the default desc (again).
            // A_DESC or A_HTDESC... the worst case we look for it twice.
            //
            d = atr_pget(thing, what, &aowner, &aflags);
            if ('\0' != d[0])
            {
                // No need for the 'def' message
                //
                found_a_desc = true;
                if (!need_pres)
                {
                    need_pres = true;
                    preserve = PushRegisters(MAX_GLOBAL_REGS);
                    save_global_regs(preserve);
                }
                buff = bp = alloc_lbuf("did_it.1");
                mux_exec(d, LBUF_SIZE-1, buff, &bp, thing, thing, player,
                    AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_TOP),
                    args, nargs);
                *bp = '\0';

                if (  A_HTDESC == what
                   && Html(player))
                {
                    safe_str(T("\r\n"), buff, &bp);
                    *bp = '\0';
                    notify_html(player, buff);
                }
                else
                {
                    notify(player, buff);
                }
                free_lbuf(buff);
            }
            else if (def)
            {
                notify(player, def);
            }
            free_lbuf(d);
        }
    }
    else if (  what < 0
            && def)
    {
        notify(player, def);
    }

    if (isPlayer(thing))
    {
       d = atr_pget(mudconf.master_room, get_atr(T("ASSET_DESC")), &aowner, &aflags);
       if (*d)
       {
          if (!need_pres)
          {
             need_pres = true;
             preserve = PushRegisters(MAX_GLOBAL_REGS);
             save_global_regs(preserve);
          }
          buff = bp = alloc_lbuf("did_it.1");
          mux_exec(d, LBUF_SIZE-1, buff, &bp, thing, thing, player,
              AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_TOP),
              args, nargs);
          *bp = '\0';
          notify(player, buff);
          free_lbuf(buff);
       }
       free_lbuf(d);
    }

    // Message to neighbors.
    //
    dbref loc;
    if (  0 < owhat
       && Has_location(player)
       && Good_obj(loc = Location(player)))
    {
        d = atr_pget(thing, owhat, &aowner, &aflags);
        if (*d)
        {
            if (!need_pres)
            {
                need_pres = true;
                preserve = PushRegisters(MAX_GLOBAL_REGS);
                save_global_regs(preserve);
            }
            buff = bp = alloc_lbuf("did_it.2");
            mux_exec(d, LBUF_SIZE-1, buff, &bp, thing, thing, player,
                AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_TOP),
                args, nargs);
            *bp = '\0';

            if (*buff)
            {
                if (aflags & AF_NONAME)
                {
                    notify_except2_rlevel2(loc, player, player, thing, buff);
                }
                else
                {
                    notify_except2_rlevel2(loc, player, player, thing,
                        tprintf(T("%s %s"), Name(player), buff));
                }
            }
            free_lbuf(buff);
        }
        else if (odef)
        {
            if (ctrl_flags & VERB_NONAME)
            {
                notify_except2_rlevel2(loc, player, player, thing, odef);
            }
            else
            {
                notify_except2_rlevel2(loc, player, player, thing,
                    tprintf(T("%s %s"), Name(player), odef));
            }
        }
        free_lbuf(d);
    }
    else if (  owhat < 0
            && odef
            && Has_location(player)
            && Good_obj(loc = Location(player)))
    {
        if (ctrl_flags & VERB_NONAME)
        {
            notify_except2_rlevel2(loc, player, player, thing, odef);
        }
        else
        {
            notify_except2_rlevel2(loc, player, player, thing,
                tprintf(T("%s %s"), Name(player), odef));
        }
    }

    // If we preserved the state of the global registers, restore them.
    //
    if (need_pres)
    {
        restore_global_regs(preserve);
        PopRegisters(preserve, MAX_GLOBAL_REGS);
    }

    // Do the action attribute.
    //
    if (  awhat > 0
       && IsReal(thing, player))
    {
        act = atr_pget(thing, awhat, &aowner, &aflags);
        if (*act != '\0')
        {
            charges = atr_pget(thing, A_CHARGES, &aowner, &aflags);
            if (*charges)
            {
                num = mux_atol(charges);
                if (num > 0)
                {
                    buff = alloc_sbuf("did_it.charges");
                    mux_ltoa(num-1, buff);
                    atr_add_raw(thing, A_CHARGES, buff);
                    free_sbuf(buff);
                }
                else
                {
                    buff = atr_pget(thing, A_RUNOUT, &aowner, &aflags);
                    if (*buff != '\0')
                    {
                        free_lbuf(act);
                        act = buff;
                    }
                    else
                    {
                        free_lbuf(act);
                        free_lbuf(buff);
                        free_lbuf(charges);
                        return;
                    }
                }
            }
            free_lbuf(charges);

            CLinearTimeAbsolute lta;
            wait_que(thing, player, player, AttrTrace(aflags, 0), false, lta,
                NOTHING, 0,
                act,
                nargs, args,
                mudstate.global_regs);
        }
        free_lbuf(act);
    }
}
Example #5
0
UTF8 *get_rlevel_desc
(
    dbref player,
    dbref thing,
    int  *piDescUsed
)
{
    dbref aowner;
    int aflags;
    UTF8 *buff = alloc_lbuf("get_rlevel_desc.");
    UTF8 *bp = buff;;
    reg_ref **preserve = NULL;
    bool need_pres = false;
    bool bFirst = true;

    // Get description list.
    //
    DESC_INFO *desclist = desclist_match(player, thing);
    bool found_a_desc = false;
    for (int i = 0; i < desclist->n; i++)
    {
        UTF8 *d = atr_pget(thing, desclist->descs[i], &aowner, &aflags);
        if ('\0' != d[0])
        {
            found_a_desc = true;
            if (!need_pres)
            {
                need_pres = true;
                preserve = PushRegisters(MAX_GLOBAL_REGS);
                save_global_regs(preserve);
            }

            mux_exec(d, LBUF_SIZE-1, buff, &bp, thing, thing, player,
                AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_TOP),
                NULL, 0);

            if (!bFirst)
            {
                safe_str(T("\r\n"), buff, &bp);
            }
            else
            {
                bFirst = false;
                *piDescUsed = desclist->descs[i];
            }
        }
        free_lbuf(d);
    }

    if (!found_a_desc)
    {
        UTF8 *d = atr_pget(thing, A_DESC, &aowner, &aflags);
        if ('\0' != d[0])
        {
            found_a_desc = true;
            if (!need_pres)
            {
                need_pres = true;
                preserve = PushRegisters(MAX_GLOBAL_REGS);
                save_global_regs(preserve);
            }

            mux_exec(d, LBUF_SIZE-1, buff, &bp, thing, thing, player,
                AttrTrace(aflags, EV_EVAL|EV_FIGNORE|EV_TOP),
                NULL, 0);
            *bp = '\0';

            *piDescUsed = A_DESC;
        }
        free_lbuf(d);
    }

    // If we preserved the state of the global registers, restore them.
    //
    if (need_pres)
    {
        restore_global_regs(preserve);
        PopRegisters(preserve, MAX_GLOBAL_REGS);
    }

    *bp = '\0';
    return buff;
}
Example #6
0
static void give_money (dbref giver, dbref recipient, int key, int amount)
{
dbref	aowner;
int	cost, pcost, rcost, aflags, dpamount;
char	*str;

	/* do amount consistency check */

	if (amount < 0 && ((!Builder(giver) && !HasPriv(giver,recipient,POWER_STEAL,POWER3,NOTHING)) ||
				DePriv(giver,recipient,DP_STEAL,POWER6,NOTHING))) {
		notify(giver,
			unsafe_tprintf("You look through your pockets. Nope, no negative %s.",
				mudconf.many_coins));
		return;
	}

	if (!amount) {
		notify(giver,
			unsafe_tprintf("You must specify a positive number of %s.",
							mudconf.many_coins));
		return;
	}

	dpamount = 0;
	if (amount < 0) 
	  dpamount = DePriv(giver,NOTHING,DP_NOSTEAL,POWER7,POWER_LEVEL_NA);
	else
	  dpamount = DePriv(giver,NOTHING,DP_NOGOLD,POWER7,POWER_LEVEL_NA);
	if (dpamount) {
	  if (DPShift(giver))
	    dpamount--;
	  dpamount = mudconf.money_limit[dpamount];
	}
	else
	  dpamount = -1;
	if (!Admin(Owner(giver))) {
		if ((Typeof(recipient) == TYPE_PLAYER) && (Pennies(recipient) + amount > mudconf.paylimit)) {
			notify(giver,
				unsafe_tprintf("That player doesn't need that many %s!",
					mudconf.many_coins));
			return;
		}
		if ((Typeof(recipient) != TYPE_PLAYER) && (!could_doit(giver, recipient, A_LUSE,1))) {
			notify(giver,
				unsafe_tprintf("%s won't take your money.",
					Name(recipient)));
			return;
		}
	}

	str = atr_get(Owner(giver), A_PAYLIM, &aowner, &aflags);
	pcost = atoi(str);
	free_lbuf(str);
	if (!Immortal(Owner(giver)) && pcost) {
		if ((Typeof(recipient) == TYPE_PLAYER) && (amount > 0) &&
			 (Pennies(recipient) + amount > pcost)) {
			notify(giver,
				unsafe_tprintf("That player doesn't need that many %s!",
					mudconf.many_coins));
			return;
		}
		else if (Pennies(recipient) + amount < (-pcost)) {
			notify(giver,"That player doesn't need that much debt!");
			return;
		}
	}
        str = atr_get(Owner(recipient), A_RECEIVELIM, &aowner, &aflags);
        rcost = atoi(str);
        free_lbuf(str);
	if (!Immortal(Owner(giver)) && rcost) {
		if ((Typeof(recipient) == TYPE_PLAYER) && (amount > 0) &&
			 (Pennies(recipient) + amount > rcost)) {
			notify(giver,
				unsafe_tprintf("That player doesn't need that many %s!",
					mudconf.many_coins));
			return;
		}
		else if (Pennies(recipient) + amount < (-rcost)) {
			notify(giver,"That player doesn't need that much debt!");
			return;
		}
	}

	if (!Immortal(Owner(giver))) {
	  if (dpamount >= 0) {
	    if (amount > 0) {
	      if ((Typeof(recipient) == TYPE_PLAYER) && (Pennies(recipient) + amount > dpamount)) {
		notify(giver,
			unsafe_tprintf("That player doesn't need that many %s!",
				mudconf.many_coins));
		return;
	      }
	      else if (amount > dpamount) {
		notify(giver, "Permission denied.");
		return;
	      }
	    }
	    else {
	      if ((Typeof(recipient) == TYPE_PLAYER) && (Pennies(recipient) + amount < (-dpamount))) {
		notify(giver,
			unsafe_tprintf("That player doesn't need that many %s!",
				mudconf.many_coins));
		return;
	      }
	      else if (amount < (-dpamount)) {
		notify(giver, "Permission denied.");
		return;
	      }
	    }
	  }
	}

	/* try to do the give */

	if (!payfor_give(giver, amount)) {
		notify(giver,
			unsafe_tprintf("You don't have that many %s to give!",
				mudconf.many_coins));
		return;
	}

	/* Find out cost if an object */

	if (Typeof(recipient) == TYPE_THING) {
		str = atr_pget(recipient, A_COST, &aowner, &aflags);
		cost = atoi(str);
		free_lbuf(str);

		/* Can't afford it? */

		if (amount < cost) {
			notify(giver, "Feeling poor today?");
			giveto(giver, amount, NOTHING);
			return;
		}

		/* Negative cost */

		if (cost < 0) {
			return;
		}
	} else {
		cost = amount;
	}

	if (!(key & GIVE_QUIET)) {
		if (amount == 1) {
			notify(giver,
				unsafe_tprintf("You give a %s to %s.",
					mudconf.one_coin, Name(recipient)));
			notify_with_cause(recipient, giver,
				unsafe_tprintf("%s gives you a %s.", Name(giver),
					mudconf.one_coin));
		} else {
			notify(giver,
				unsafe_tprintf("You give %d %s to %s.", amount,
					mudconf.many_coins, Name(recipient)));
			notify_with_cause(recipient, giver,
				unsafe_tprintf("%s gives you %d %s.", Name(giver),
				amount, mudconf.many_coins));
		}
	}
	else {
		if (amount == 1) {
			notify(giver,
				unsafe_tprintf("You give a %s to %s. (quiet)",
					mudconf.one_coin, Name(recipient)));
		}
		else {
			notify(giver,
				unsafe_tprintf("You give %d %s to %s. (quiet)",
					amount, mudconf.many_coins,
					Name(recipient)));
		}
	}

	/* Report change given */

	if((amount - cost) == 1) {
        	notify(giver,
			unsafe_tprintf("You get 1 %s in change.", mudconf.one_coin));
		giveto(giver, 1, NOTHING);
	} else if (amount != cost) {
		notify(giver,
			unsafe_tprintf("You get %d %s in change.",
				(amount - cost), mudconf.many_coins));
		giveto(giver, (amount - cost), NOTHING);
	}
	if (pcost && (Pennies(Owner(recipient)) + cost > pcost)) {
	  pcost = pcost - Pennies(Owner(recipient));
	  if (pcost < 0)
	    pcost = 0;
	}
	else
	  pcost = cost;
	if (!giveto(recipient, pcost, giver))
		giveto(giver, cost, NOTHING);

	/* Transfer the money and run PAY attributes */
        /* Rooms should not kick off the PAY attribute */

        if ( !isRoom(giver) )
	   did_it(giver, recipient, A_PAY, NULL, A_OPAY, NULL, A_APAY,
	   	  (char **)NULL, 0);
	return;
}
Example #7
0
File: eval.c Project: gtaylor/btmux
void exec(char *buff, char **bufc, int tflags, dbref player, dbref cause,
		  int eval, char **dstr, char *cargs[], int ncargs)
{
#define	NFARGS	30
	char *fargs[NFARGS];
	char *preserve[MAX_GLOBAL_REGS];
	char *tstr, *tbuf, *tbufc, *savepos, *atr_gotten, *start, *oldp, *savestr;
	char savec, ch, *str;
	char *realbuff = NULL, *realbp = NULL;
	dbref aowner;
	int at_space, nfargs, gender, i, j, alldone, feval; long aflags;
	int is_trace, is_top, save_count;
	int ansi;
	FUN *fp;
	UFUN *ufp;

	static const char *subj[5] = { "", "it", "she", "he", "they" };
	static const char *poss[5] = { "", "its", "her", "his", "their" };
	static const char *obj[5] = { "", "it", "her", "him", "them" };
	static const char *absp[5] = { "", "its", "hers", "his", "theirs" };

	if(*dstr == NULL)
		return;

	// dprintk("%d/%s", player, *dstr);

	at_space = 1;
	gender = -1;
	alldone = 0;
	ansi = 0;

	is_trace = Trace(player) && !(eval & EV_NOTRACE);
	is_top = 0;

	/* Extend the buffer if we need to. */

	if(((*bufc) - buff) > (LBUF_SIZE - SBUF_SIZE)) {
		realbuff = buff;
		realbp = *bufc;
		buff = (char *) malloc(LBUF_SIZE);
		*bufc = buff;
	}

	oldp = start = *bufc;

	/*
	 * If we are tracing, save a copy of the starting buffer 
	 */

	savestr = NULL;
	if(is_trace) {
		is_top = tcache_empty();
		savestr = alloc_lbuf("exec.save");
		StringCopy(savestr, *dstr);
	}
	while (**dstr && !alldone) {
		switch (**dstr) {
		case ' ':
			/*
			 * A space.  Add a space if not compressing or if * * 
			 * 
			 * *  * * previous char was not a space 
			 */

			if(!(mudconf.space_compress && at_space) ||
			   (eval & EV_NO_COMPRESS)) {
				safe_chr(' ', buff, bufc);
				at_space = 1;
			}
			break;
		case '\\':
			/*
			 * General escape.  Add the following char without *
			 * * * * special processing 
			 */

			at_space = 0;
			(*dstr)++;
			if(**dstr)
				safe_chr(**dstr, buff, bufc);
			else
				(*dstr)--;
			break;
		case '[':
			/*
			 * Function start.  Evaluate the contents of the * *
			 * * * square brackets as a function.  If no closing
			 * * * * * bracket, insert the [ and continue. 
			 */

			at_space = 0;
			tstr = (*dstr)++;
			if(eval & EV_NOFCHECK) {
				safe_chr('[', buff, bufc);
				*dstr = tstr;
				break;
			}
			tbuf = parse_to(dstr, ']', 0);
			if(*dstr == NULL) {
				safe_chr('[', buff, bufc);
				*dstr = tstr;
			} else {
				str = tbuf;
				exec(buff, bufc, 0, player, cause,
					 (eval | EV_FCHECK | EV_FMAND), &str, cargs, ncargs);
				(*dstr)--;
			}
			break;
		case '{':
			/*
			 * Literal start.  Insert everything up to the * * *
			 * * terminating } without parsing.  If no closing *
			 * * * * brace, insert the { and continue. 
			 */

			at_space = 0;
			tstr = (*dstr)++;
			tbuf = parse_to(dstr, '}', 0);
			if(*dstr == NULL) {
				safe_chr('{', buff, bufc);
				*dstr = tstr;
			} else {
				if(!(eval & EV_STRIP)) {
					safe_chr('{', buff, bufc);
				}
				/*
				 * Preserve leading spaces (Felan) 
				 */

				if(*tbuf == ' ') {
					safe_chr(' ', buff, bufc);
					tbuf++;
				}
				str = tbuf;
				exec(buff, bufc, 0, player, cause,
					 (eval & ~(EV_STRIP | EV_FCHECK)), &str, cargs, ncargs);
				if(!(eval & EV_STRIP)) {
					safe_chr('}', buff, bufc);
				}
				(*dstr)--;
			}
			break;
		case '%':
			/*
			 * Percent-replace start.  Evaluate the chars * * *
			 * following * and perform the appropriate * * *
			 * substitution. 
			 */

			at_space = 0;
			(*dstr)++;
			savec = **dstr;
			savepos = *bufc;
			switch (savec) {
			case '\0':			/*
								 * Null - all done 
								 */
				(*dstr)--;
				break;
			case '|':			/* piped command output */
				safe_str(mudstate.pout, buff, bufc);
				break;
			case '%':			/*
								 * Percent - a literal % 
								 */
				safe_chr('%', buff, bufc);
				break;
			case 'c':
			case 'C':
				(*dstr)++;
				if(!**dstr)
					(*dstr)--;
				ansi = 1;
				switch (**dstr) {
				case 'h':		/*
								 * hilite 
								 */
					safe_str(ANSI_HILITE, buff, bufc);
					break;
				case 'i':		/*
								 * inverse 
								 */
					safe_str(ANSI_INVERSE, buff, bufc);
					break;
				case 'f':		/*
								 * flash 
								 */
					safe_str(ANSI_BLINK, buff, bufc);
					break;
				case 'u':		/* underline */
					safe_str(ANSI_UNDER, buff, bufc);
					break;
				case 'n':		/*
								 * normal 
								 */
					safe_str(ANSI_NORMAL, buff, bufc);
					ansi = 0;
					break;
				case 'x':		/*
								 * black fg 
								 */
					safe_str(ANSI_BLACK, buff, bufc);
					break;
				case 'r':		/*
								 * red fg 
								 */
					safe_str(ANSI_RED, buff, bufc);
					break;
				case 'g':		/*
								 * green fg 
								 */
					safe_str(ANSI_GREEN, buff, bufc);
					break;
				case 'y':		/*
								 * yellow fg 
								 */
					safe_str(ANSI_YELLOW, buff, bufc);
					break;
				case 'b':		/*
								 * blue fg 
								 */
					safe_str(ANSI_BLUE, buff, bufc);
					break;
				case 'm':		/*
								 * magenta fg 
								 */
					safe_str(ANSI_MAGENTA, buff, bufc);
					break;
				case 'c':		/*
								 * cyan fg 
								 */
					safe_str(ANSI_CYAN, buff, bufc);
					break;
				case 'w':		/*
								 * white fg 
								 */
					safe_str(ANSI_WHITE, buff, bufc);
					break;
				case 'X':		/*
								 * black bg 
								 */
					safe_str(ANSI_BBLACK, buff, bufc);
					break;
				case 'R':		/*
								 * red bg 
								 */
					safe_str(ANSI_BRED, buff, bufc);
					break;
				case 'G':		/*
								 * green bg 
								 */
					safe_str(ANSI_BGREEN, buff, bufc);
					break;
				case 'Y':		/*
								 * yellow bg 
								 */
					safe_str(ANSI_BYELLOW, buff, bufc);
					break;
				case 'B':		/*
								 * blue bg 
								 */
					safe_str(ANSI_BBLUE, buff, bufc);
					break;
				case 'M':		/*
								 * magenta bg 
								 */
					safe_str(ANSI_BMAGENTA, buff, bufc);
					break;
				case 'C':		/*
								 * cyan bg 
								 */
					safe_str(ANSI_BCYAN, buff, bufc);
					break;
				case 'W':		/*
								 * white bg 
								 */
					safe_str(ANSI_BWHITE, buff, bufc);
					break;
				default:
					safe_chr(**dstr, buff, bufc);
				}
				break;
			case 'r':			/*
								 * Carriage return 
								 */
			case 'R':
				safe_str((char *) "\r\n", buff, bufc);
				break;
			case 't':			/*
								 * Tab 
								 */
			case 'T':
				safe_chr('\t', buff, bufc);
				break;
			case 'B':			/*
								 * Blank 
								 */
			case 'b':
				safe_chr(' ', buff, bufc);
				break;
			case '0':			/*
								 * Command argument number N 
								 */
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				i = (**dstr - '0');
				if((i < ncargs) && (cargs[i] != NULL))
					safe_str(cargs[i], buff, bufc);
				break;
			case 'V':			/*
								 * Variable attribute 
								 */
			case 'v':
				(*dstr)++;
				ch = ToUpper(**dstr);
				if(!**dstr)
					(*dstr)--;
				if((ch < 'A') || (ch > 'Z'))
					break;
				i = 100 + ch - 'A';
				atr_gotten = atr_pget(player, i, &aowner, &aflags);
				safe_str(atr_gotten, buff, bufc);
				free_lbuf(atr_gotten);
				break;
			case 'Q':
			case 'q':
				(*dstr)++;
				i = (**dstr - '0');
				if((i >= 0) && (i <= 9) && mudstate.global_regs[i]) {
					safe_str(mudstate.global_regs[i], buff, bufc);
				}
				if(!**dstr)
					(*dstr)--;
				break;
			case 'O':			/*
								 * Objective pronoun 
								 */
			case 'o':
				if(gender < 0)
					gender = get_gender(cause);
				if(!gender)
					tbuf = Name(cause);
				else
					tbuf = (char *) obj[gender];
				safe_str(tbuf, buff, bufc);
				break;
			case 'P':			/*
								 * Personal pronoun 
								 */
			case 'p':
				if(gender < 0)
					gender = get_gender(cause);
				if(!gender) {
					safe_str(Name(cause), buff, bufc);
					safe_chr('s', buff, bufc);
				} else {
					safe_str((char *) poss[gender], buff, bufc);
				}
				break;
			case 'S':			/*
								 * Subjective pronoun 
								 */
			case 's':
				if(gender < 0)
					gender = get_gender(cause);
				if(!gender)
					tbuf = Name(cause);
				else
					tbuf = (char *) subj[gender];
				safe_str(tbuf, buff, bufc);
				break;
			case 'A':			/*
								 * Absolute posessive 
								 */
			case 'a':			/*
								 * idea from Empedocles 
								 */
				if(gender < 0)
					gender = get_gender(cause);
				if(!gender) {
					safe_str(Name(cause), buff, bufc);
					safe_chr('s', buff, bufc);
				} else {
					safe_str((char *) absp[gender], buff, bufc);
				}
				break;
			case '#':			/*
								 * Invoker DB number 
								 */
				tbuf = alloc_sbuf("exec.invoker");
				sprintf(tbuf, "#%ld", cause);
				safe_str(tbuf, buff, bufc);
				free_sbuf(tbuf);
				break;
			case '!':			/*
								 * Executor DB number 
								 */
				tbuf = alloc_sbuf("exec.executor");
				sprintf(tbuf, "#%ld", player);
				safe_str(tbuf, buff, bufc);
				free_sbuf(tbuf);
				break;
			case 'N':			/*
								 * Invoker name 
								 */
			case 'n':
				safe_str(Name(cause), buff, bufc);
				break;
			case 'L':			/*
								 * Invoker location db# 
								 */
			case 'l':
				if(!(eval & EV_NO_LOCATION)) {
					tbuf = alloc_sbuf("exec.exloc");
					sprintf(tbuf, "#%ld", where_is(cause));
					safe_str(tbuf, buff, bufc);
					free_sbuf(tbuf);
				}

				break;
			default:			/*
								 * Just copy 
								 */
				safe_chr(**dstr, buff, bufc);
			}
			if(isupper(savec))
				*savepos = ToUpper(*savepos);
			break;
		case '(':
			/*
			 * Arglist start.  See if what precedes is a function. If so,
			 * execute it if we should.
			 */

			at_space = 0;
			if(!(eval & EV_FCHECK)) {
				safe_chr('(', buff, bufc);
				break;
			}
			/*
			 * Load an sbuf with an uppercase version of the func name, and
			 * see if the func exists.  Trim trailing spaces from the name
			 * if configured.
			 */

			**bufc = '\0';
			tbufc = tbuf = alloc_sbuf("exec.tbuf");
			safe_sb_str(oldp, tbuf, &tbufc);
			*tbufc = '\0';
			if(mudconf.space_compress) {
				while ((--tbufc >= tbuf) && isspace(*tbufc));
				tbufc++;
				*tbufc = '\0';
			}
			for(tbufc = tbuf; *tbufc; tbufc++)
				*tbufc = ToLower(*tbufc);
			fp = (FUN *) hashfind(tbuf, &mudstate.func_htab);

			/*
			 * If not a builtin func, check for global func 
			 */

			ufp = NULL;
			if(fp == NULL) {
				ufp = (UFUN *) hashfind(tbuf, &mudstate.ufunc_htab);
			}
			/*
			 * Do the right thing if it doesn't exist 
			 */

			if(!fp && !ufp) {
				if(eval & EV_FMAND) {
					*bufc = oldp;
					safe_str((char *) "#-1 FUNCTION (", buff, bufc);
					safe_str(tbuf, buff, bufc);
					safe_str((char *) ") NOT FOUND", buff, bufc);
					alldone = 1;
				} else {
					safe_chr('(', buff, bufc);
				}
				free_sbuf(tbuf);
				eval &= ~EV_FCHECK;
				break;
			}
			free_sbuf(tbuf);

			/*
			 * Get the arglist and count the number of args * Neg 
			 * 
			 * *  * *  * * # of args means catenate subsequent
			 * args 
			 */

			if(ufp)
				nfargs = NFARGS;
			else if(fp->nargs < 0)
				nfargs = -fp->nargs;
			else
				nfargs = NFARGS;
			tstr = *dstr;
			if(fp && (fp->flags & FN_NO_EVAL))
				feval = (eval & ~EV_EVAL) | EV_STRIP_ESC;
			else
				feval = eval;
			*dstr =
				parse_arglist(player, cause, *dstr + 1, ')', feval, fargs,
							  nfargs, cargs, ncargs);

			/*
			 * If no closing delim, just insert the '(' and * * * 
			 * 
			 * * continue normally 
			 */

			if(!*dstr) {
				*dstr = tstr;
				safe_chr(**dstr, buff, bufc);
				for(i = 0; i < nfargs; i++)
					if(fargs[i] != NULL)
						free_lbuf(fargs[i]);
				eval &= ~EV_FCHECK;
				break;
			}
			/*
			 * Count number of args returned 
			 */

			(*dstr)--;
			j = 0;
			for(i = 0; i < nfargs; i++)
				if(fargs[i] != NULL)
					j = i + 1;
			nfargs = j;

			/*
			 * If it's a user-defined function, perform it now. 
			 */

			if(ufp) {
				mudstate.func_nest_lev++;
				if(!check_access(player, ufp->perms)) {
					safe_str("#-1 PERMISSION DENIED", buff, &oldp);
					*bufc = oldp;
				} else {
					tstr = atr_get(ufp->obj, ufp->atr, &aowner, &aflags);
					if(ufp->flags & FN_PRIV)
						i = ufp->obj;
					else
						i = player;
					str = tstr;

					if(ufp->flags & FN_PRES) {
						for(j = 0; j < MAX_GLOBAL_REGS; j++) {
							if(!mudstate.global_regs[j])
								preserve[j] = NULL;
							else {
								preserve[j] = alloc_lbuf("eval_regs");
								StringCopy(preserve[j],
										   mudstate.global_regs[j]);
							}
						}
					}

					exec(buff, &oldp, 0, i, cause, feval, &str, fargs,
						 nfargs);
					*bufc = oldp;

					if(ufp->flags & FN_PRES) {
						for(j = 0; j < MAX_GLOBAL_REGS; j++) {
							if(preserve[j]) {
								if(!mudstate.global_regs[j])
									mudstate.global_regs[j] =
										alloc_lbuf("eval_regs");
								StringCopy(mudstate.global_regs[j],
										   preserve[j]);
								free_lbuf(preserve[j]);
							} else {
								if(mudstate.global_regs[j])
									*(mudstate.global_regs[i]) = '\0';
							}
						}
					}

					free_lbuf(tstr);
				}

				/*
				 * Return the space allocated for the args 
				 */

				mudstate.func_nest_lev--;
				for(i = 0; i < nfargs; i++)
					if(fargs[i] != NULL)
						free_lbuf(fargs[i]);
				eval &= ~EV_FCHECK;
				break;
			}
			/*
			 * If the number of args is right, perform the func.
			 * Otherwise return an error message.  Note
			 * that parse_arglist returns zero args as one
			 * null arg, so we have to handle that case
			 * specially. 
			 */

			if((fp->nargs == 0) && (nfargs == 1)) {
				if(!*fargs[0]) {
					free_lbuf(fargs[0]);
					fargs[0] = NULL;
					nfargs = 0;
				}
			}
			if((nfargs == fp->nargs) || (nfargs == -fp->nargs) ||
			   (fp->flags & FN_VARARGS)) {

				/*
				 * Check recursion limit 
				 */

				mudstate.func_nest_lev++;
				mudstate.func_invk_ctr++;
				if(mudstate.func_nest_lev >= mudconf.func_nest_lim) {
					safe_str("#-1 FUNCTION RECURSION LIMIT EXCEEDED", buff,
							 bufc);
				} else if(mudstate.func_invk_ctr == mudconf.func_invk_lim) {
					safe_str("#-1 FUNCTION INVOCATION LIMIT EXCEEDED",
							 buff, bufc);
				} else if(!check_access(player, fp->perms)) {
					safe_str("#-1 PERMISSION DENIED", buff, &oldp);
					*bufc = oldp;
				} else if(mudstate.func_invk_ctr < mudconf.func_invk_lim) {
					fp->fun(buff, &oldp, player, cause, fargs, nfargs,
							cargs, ncargs);
					*bufc = oldp;
				} else {
					**bufc = '\0';
				}
				mudstate.func_nest_lev--;
			} else {
				*bufc = oldp;
				tstr = alloc_sbuf("exec.funcargs");
				sprintf(tstr, "%d", fp->nargs);
				safe_str((char *) "#-1 FUNCTION (", buff, bufc);
				safe_str((char *) fp->name, buff, bufc);
				safe_str((char *) ") EXPECTS ", buff, bufc);
				safe_str(tstr, buff, bufc);
				safe_str((char *) " ARGUMENTS", buff, bufc);
				free_sbuf(tstr);
			}

			/*
			 * Return the space allocated for the arguments 
			 */

			for(i = 0; i < nfargs; i++)
				if(fargs[i] != NULL)
					free_lbuf(fargs[i]);
			eval &= ~EV_FCHECK;
			break;
		default:
			/*
			 * A mundane character.  Just copy it 
			 */

			at_space = 0;
			safe_chr(**dstr, buff, bufc);
		}
		(*dstr)++;
	}

	/*
	 * If we're eating spaces, and the last thing was a space, eat it
	 * up. Complicated by the fact that at_space is initially
	 * true. So check to see if we actually put something in the
	 * buffer, too. 
	 */

	if(mudconf.space_compress && at_space && !(eval & EV_NO_COMPRESS)
	   && (start != *bufc))
		(*bufc)--;

	/*
	 * The ansi() function knows how to take care of itself. However, 
	 * if the player used a %c sub in the string, and hasn't yet
	 * terminated the color with a %cn yet, we'll have to do it for 
	 * them. 
	 */

	if(ansi == 1)
		safe_str(ANSI_NORMAL, buff, bufc);

	**bufc = '\0';

	/*
	 * Report trace information 
	 */

	if(realbuff) {
		**bufc = '\0';
		*bufc = realbp;
		safe_str(buff, realbuff, bufc);
		free(buff);
		buff = realbuff;
	}

	if(is_trace) {
		tcache_add(savestr, start);
		save_count = tcache_count - mudconf.trace_limit;;
		if(is_top || !mudconf.trace_topdown)
			tcache_finish(player);
		if(is_top && (save_count > 0)) {
			tbuf = alloc_mbuf("exec.trace_diag");
			sprintf(tbuf, "%d lines of trace output discarded.", save_count);
			notify(player, tbuf);
			free_mbuf(tbuf);
		}
	}
}