/*
* funceval.c - MUX function handlers
*/
/*
* $Id: funceval.c,v 1.4 2005/08/08 09:43:07 murrayma Exp $
*/
#include "copyright.h"
#include "config.h"
#include <limits.h>
#include <math.h>
#include "mudconf.h"
#include "config.h"
#include "db.h"
#include "flags.h"
#include "powers.h"
#include "attrs.h"
#include "externs.h"
#include "match.h"
#include "command.h"
#include "functions.h"
#include "misc.h"
#include "alloc.h"
#include "ansi.h"
#include "comsys.h"
/*
* Note: Many functions in this file have been taken, whole or in part, from
* * PennMUSH 1.50, and TinyMUSH 2.2, for softcode compatibility. The
* * maintainers of MUX would like to thank those responsible for PennMUSH 1.50
* * and TinyMUSH 2.2, and hope we have adequately noted in the source where
* * credit is due.
*/
extern NAMETAB indiv_attraccess_nametab[];
extern char *trim_space_sep(char *, char);
extern char *next_token(char *, char);
extern char *split_token(char **, char);
extern dbref match_thing(dbref, char *);
extern int countwords(char *, char);
extern int check_read_perms(dbref, dbref, ATTR *, int, int, char *, char **);
extern void arr2list(char **, int, char *, char **, char);
extern void make_portlist(dbref, dbref, char *, char **);
extern INLINE char *get_mail_message(int);
extern struct channel *select_channel(char *channel);
extern void do_pemit_list(dbref, char *, const char *);
extern int fn_range_check(const char *, int, int, int, char *, char **);
extern int delim_check(char *[], int, int, char *, char *, char **, int,
dbref, dbref, char *[], int);
extern char *upcasestr(char *s);
extern void count_mail(dbref, int, int *, int *, int *);
extern int list2arr(char *[], int, char *, int);
extern struct comuser *select_user(struct channel *, dbref);
/*
* This is for functions that take an optional delimiter character
*/
#define varargs_preamble(xname,xnargs) \
if (!fn_range_check(xname, nfargs, xnargs-1, xnargs, buff, bufc)) \
return; \
if (!delim_check(fargs, nfargs, xnargs, &sep, buff, bufc, 0, \
player, cause, cargs, ncargs)) \
return;
#define evarargs_preamble(xname,xnargs) \
if (!fn_range_check(xname, nfargs, xnargs-1, xnargs, buff, bufc)) \
return; \
if (!delim_check(fargs, nfargs, xnargs, &sep, buff, bufc, 1, \
player, cause, cargs, ncargs)) \
return;
#define mvarargs_preamble(xname,xminargs,xnargs) \
if (!fn_range_check(xname, nfargs, xminargs, xnargs, buff, bufc)) \
return; \
if (!delim_check(fargs, nfargs, xnargs, &sep, buff, bufc, 0, \
player, cause, cargs, ncargs)) \
return;
/* Returns the dbref of the specified channel's channel object. */
void fun_cobj(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
struct channel *ch;
struct comuser *user;
static char smbuf[SBUF_SIZE];
if (!(ch = select_channel(fargs[0]))) {
safe_str("#-1 CHANNEL NOT FOUND", buff, bufc);
return;
}
if (!mudconf.have_comsys || (!Comm_All(player) &&
(player != ch->charge_who))) {
safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
return;
}
if (ch->chan_obj == -1) {
safe_str("#-1 NO CHANNEL OBJECT", buff, bufc);
return;
}
safe_tprintf_str(buff, bufc, "#%d", ch->chan_obj);
}
/* Lists who is on a channel. */
void fun_cwho(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
struct channel *ch;
struct comuser *user;
int len = 0;
static char smbuf[SBUF_SIZE];
if (!(ch = select_channel(fargs[0]))) {
safe_str("#-1 CHANNEL NOT FOUND", buff, bufc);
return;
}
if (!mudconf.have_comsys || (!Comm_All(player) &&
(player != ch->charge_who))) {
safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
return;
}
for (user = ch->on_users; user; user = user->on_next) {
/* if (Connected(user->who)) */
{
if (len) {
sprintf(smbuf, " #%d", user->who);
if ((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
safe_str(" #-1", buff, bufc);
return;
}
safe_str(smbuf, buff, bufc);
len += strlen(smbuf);
} else {
safe_tprintf_str(buff, bufc, "#%d", user->who);
len = strlen(buff);
}
}
}
}
/* Returns a list of all channels. */
void fun_clist(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
struct channel *ch;
struct comuser *user;
int thing;
int len = 0;
static char smbuf[SBUF_SIZE];
if (!(ch = select_channel(fargs[0]))) {
safe_str("#-1 CHANNEL NOT FOUND", buff, bufc);
return;
}
if (!mudconf.have_comsys || (!Comm_All(player) &&
(player != ch->charge_who))) {
safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
return;
}
for (thing = 0; thing < mudstate.db_top; thing++) {
if (!Good_obj(thing))
continue;
if ((user = select_user(ch, thing))) {
if (len) {
sprintf(smbuf, " #%d", user->who);
if ((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
safe_str(" #-1", buff, bufc);
return;
}
safe_str(smbuf, buff, bufc);
len += strlen(smbuf);
} else {
safe_tprintf_str(buff, bufc, "#%d", user->who);
len = strlen(buff);
}
}
}
}
void fun_beep(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
safe_chr(BEEP_CHAR, buff, bufc);
}
/*
* This function was originally taken from PennMUSH 1.50
*/
void fun_ansi(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *s = fargs[0];
while (*s) {
switch (*s) {
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);
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;
}
s++;
}
safe_str(fargs[1], buff, bufc);
safe_str(ANSI_NORMAL, buff, bufc);
}
void fun_zone(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref it;
if (!mudconf.have_zones) {
return;
}
it = match_thing(player, fargs[0]);
if (it == NOTHING || !Examinable(player, it)) {
safe_str("#-1", buff, bufc);
return;
}
safe_tprintf_str(buff, bufc, "#%d", Zone(it));
}
#ifdef SIDE_EFFECT_FUNCTIONS
void fun_link(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
do_link(player, cause, 0, fargs[0], fargs[1]);
}
void fun_tel(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
do_teleport(player, cause, 0, fargs[0], fargs[1]);
}
void fun_pemit(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
do_pemit_list(player, fargs[0], fargs[1]);
}
/*------------------------------------------------------------------------
* fun_create: Creates a room, thing or exit
*/
static int check_command(player, name, buff, bufc)
dbref player;
char *name, *buff, **bufc;
{
CMDENT *cmd;
if ((cmd = (CMDENT *) hashfind(name, &mudstate.command_htab)))
if (!check_access(player, cmd->perms)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return (1);
}
return (0);
}
void fun_create(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref thing;
int cost;
char sep, *name;
varargs_preamble("CREATE", 3);
name = fargs[0];
if (!name || !*name) {
safe_str("#-1 ILLEGAL NAME", buff, bufc);
return;
}
if (fargs[2] && *fargs[2])
sep = *fargs[2];
else
sep = 't';
switch (sep) {
case 'r':
if (check_command(player, "@dig", buff, bufc)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
thing = create_obj(player, TYPE_ROOM, name, 0);
break;
case 'e':
if (check_command(player, "@open", buff, bufc)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
thing = create_obj(player, TYPE_EXIT, name, 0);
if (thing != NOTHING) {
s_Exits(thing, player);
s_Next(thing, Exits(player));
s_Exits(player, thing);
}
break;
default:
if (check_command(player, "@create", buff, bufc)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
if (fargs[1] && *fargs[1]) {
cost = atoi(fargs[1]);
if (cost < mudconf.createmin || cost > mudconf.createmax) {
safe_str("#-1 COST OUT OF RANGE", buff, bufc);
return;
}
} else
cost = mudconf.createmin;
thing = create_obj(player, TYPE_THING, name, cost);
if (thing != NOTHING) {
move_via_generic(thing, player, NOTHING, 0);
s_Home(thing, new_home(player));
}
break;
}
safe_tprintf_str(buff, bufc, "#%d", thing);
}
/*---------------------------------------------------------------------------
* fun_set: sets an attribute on an object
*/
static void set_attr_internal(player, thing, attrnum, attrtext, key, buff,
bufc)
dbref player, thing;
int attrnum, key;
char *attrtext, *buff;
char **bufc;
{
dbref aowner;
int aflags, could_hear;
ATTR *attr;
attr = atr_num(attrnum);
atr_pget_info(thing, attrnum, &aowner, &aflags);
if (attr && Set_attr(player, thing, attr, aflags)) {
if ((attr->check != NULL) &&
(!(*attr->check) (0, player, thing, attrnum, attrtext))) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
could_hear = Hearer(thing);
atr_add(thing, attrnum, attrtext, Owner(player), aflags);
handle_ears(thing, could_hear, Hearer(thing));
if (!(key & SET_QUIET) && !Quiet(player) && !Quiet(thing))
notify_quiet(player, "Set.");
} else {
safe_str("#-1 PERMISSION DENIED.", buff, bufc);
}
}
void fun_set(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref thing, thing2, aowner;
char *p, *buff2;
int atr, atr2, aflags, clear, flagvalue, could_hear;
ATTR *attr, *attr2;
/*
* obj/attr form?
*/
if (parse_attrib(player, fargs[0], &thing, &atr)) {
if (atr != NOTHING) {
/*
* must specify flag name
*/
if (!fargs[1] || !*fargs[1]) {
safe_str("#-1 UNSPECIFIED PARAMETER", buff, bufc);
}
/*
* are we clearing?
*/
clear = 0;
if (*fargs[0] == NOT_TOKEN) {
fargs[0]++;
clear = 1;
}
/*
* valid attribute flag?
*/
flagvalue =
search_nametab(player, indiv_attraccess_nametab, fargs[1]);
if (flagvalue < 0) {
safe_str("#-1 CAN NOT SET", buff, bufc);
return;
}
/*
* make sure attribute is present
*/
if (!atr_get_info(thing, atr, &aowner, &aflags)) {
safe_str("#-1 ATTRIBUTE NOT PRESENT ON OBJECT", buff,
bufc);
return;
}
/*
* can we write to attribute?
*/
attr = atr_num(atr);
if (!attr || !Set_attr(player, thing, attr, aflags)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
/*
* just do it!
*/
if (clear)
aflags &= ~flagvalue;
else
aflags |= flagvalue;
could_hear = Hearer(thing);
atr_set_flags(thing, atr, aflags);
return;
}
}
/*
* find thing
*/
if ((thing = match_controlled(player, fargs[0])) == NOTHING) {
safe_str("#-1", buff, bufc);
return;
}
/*
* check for attr set first
*/
for (p = fargs[1]; *p && (*p != ':'); p++);
if (*p) {
*p++ = 0;
atr = mkattr(fargs[1]);
if (atr <= 0) {
safe_str("#-1 UNABLE TO CREATE ATTRIBUTE", buff, bufc);
return;
}
attr = atr_num(atr);
if (!attr) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
atr_get_info(thing, atr, &aowner, &aflags);
if (!Set_attr(player, thing, attr, aflags)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
buff2 = alloc_lbuf("fun_set");
/*
* check for _
*/
if (*p == '_') {
StringCopy(buff2, p + 1);
if (!parse_attrib(player, p + 1, &thing2, &atr2) ||
(atr == NOTHING)) {
free_lbuf(buff2);
safe_str("#-1 NO MATCH", buff, bufc);
return;
}
attr2 = atr_num(atr);
p = buff2;
atr_pget_str(buff2, thing2, atr2, &aowner, &aflags);
if (!attr2 || !See_attr(player, thing2, attr2, aowner, aflags)) {
free_lbuf(buff2);
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
}
/*
* set it
*/
set_attr_internal(player, thing, atr, p, 0, buff, bufc);
free_lbuf(buff2);
return;
}
/*
* set/clear a flag
*/
flag_set(thing, player, fargs[1], 0);
}
#endif
/*
* Code for encrypt() and decrypt() was taken from the DarkZone server
*/
/*
* Copy over only alphanumeric chars
*/
static char *crunch_code(code)
char *code;
{
char *in;
char *out;
static char output[LBUF_SIZE];
out = output;
in = code;
while (*in) {
if ((*in >= 32) || (*in <= 126)) {
printf("%c", *in);
*out++ = *in;
}
in++;
}
*out = '\0';
return (output);
}
static char *crypt_code(code, text, type)
char *code;
char *text;
int type;
{
static char textbuff[LBUF_SIZE];
char codebuff[LBUF_SIZE];
int start = 32;
int end = 126;
int mod = end - start + 1;
char *p, *q, *r;
if (!text && !*text)
return ((char *) "");
StringCopy(codebuff, crunch_code(code));
if (!code || !*code || !codebuff || !*codebuff)
return (text);
StringCopy(textbuff, "");
p = text;
q = codebuff;
r = textbuff;
/*
* Encryption: Simply go through each character of the text, get its
* * * * ascii value, subtract start, add the ascii value (less
* start) * of * * the code, mod the result, add start. Continue
*/
while (*p) {
if ((*p < start) || (*p > end)) {
p++;
continue;
}
if (type)
*r++ = (((*p++ - start) + (*q++ - start)) % mod) + start;
else
*r++ = (((*p++ - *q++) + 2 * mod) % mod) + start;
if (!*q)
q = codebuff;
}
*r = '\0';
return (textbuff);
}
/*
* Borrowed from DarkZone
*/
void fun_zwho(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref it = match_thing(player, fargs[0]);
dbref i;
int len = 0;
if (!mudconf.have_zones || (!Controls(player, it) && !WizRoy(player))) {
safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
return;
}
for (i = 0; i < mudstate.db_top; i++)
if (Typeof(i) == TYPE_PLAYER) {
if (Zone(i) == it) {
if (len) {
static char smbuf[SBUF_SIZE];
sprintf(smbuf, " #%d", i);
if ((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
safe_str(" #-1", buff, bufc);
return;
}
safe_str(smbuf, buff, bufc);
len += strlen(smbuf);
} else {
safe_tprintf_str(buff, bufc, "#%d", i);
len = strlen(buff);
}
}
}
}
void fun_zplayers(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref it = match_thing(player, fargs[0]);
dbref i;
int len = 0;
if (!mudconf.have_zones || (!Controls(player, it) && !WizRoy(player))) {
safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
return;
}
for (i = 0; i < mudstate.db_top; i++)
if (Typeof(i) == TYPE_PLAYER)
if (Zone(i) == it) {
if (!(Connected(i)))
continue;
if (len) {
static char smbuf[SBUF_SIZE];
sprintf(smbuf, " #%d", i);
if ((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
safe_str(" #-1", buff, bufc);
return;
}
safe_str(smbuf, buff, bufc);
len += strlen(smbuf);
} else {
safe_tprintf_str(buff, bufc, "#%d", i);
len = strlen(buff);
}
}
}
/*
* Borrowed from DarkZone
*/
void fun_inzone(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref it = match_thing(player, fargs[0]);
dbref i;
int len = 0;
if (!mudconf.have_zones || !(Controls(player, it) || !WizRoy(player))) {
safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
return;
}
for (i = 0; i < mudstate.db_top; i++)
if (Typeof(i) == TYPE_ROOM)
if (db[i].zone == it) {
if (len) {
static char smbuf[SBUF_SIZE];
sprintf(smbuf, " #%d", i);
if ((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
safe_str(" #-1", buff, bufc);
return;
}
safe_str(smbuf, buff, bufc);
len += strlen(smbuf);
} else {
safe_tprintf_str(buff, bufc, "#%d", i);
len = strlen(buff);
}
}
}
/*
* Borrowed from DarkZone
*/
void fun_children(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref it = match_thing(player, fargs[0]);
dbref i;
int len = 0;
if (!(Controls(player, it)) || !(WizRoy(player))) {
safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
return;
}
for (i = 0; i < mudstate.db_top; i++)
if (Parent(i) == it) {
if (len) {
static char smbuf[SBUF_SIZE];
sprintf(smbuf, " #%d", i);
if ((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
safe_str(" #-1", buff, bufc);
return;
}
safe_str(smbuf, buff, bufc);
len += strlen(smbuf);
} else {
safe_tprintf_str(buff, bufc, "#%d", i);
len = strlen(buff);
}
}
}
void fun_encrypt(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
safe_str(crypt_code(fargs[1], fargs[0], 1), buff, bufc);
}
void fun_decrypt(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
safe_str(crypt_code(fargs[1], fargs[0], 0), buff, bufc);
}
#if 0 /* Currently not used. */
static void noquotes(clean, dirty)
char *clean;
char *dirty;
{
while (*dirty != '\0') {
if (*dirty == '"')
*clean++ = '\\';
*clean++ = *dirty++;
}
*clean = '\0';
}
#endif
void fun_objeval(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref obj;
char *name, *bp, *str;
if (!*fargs[0]) {
return;
}
name = bp = alloc_lbuf("fun_objeval");
str = fargs[0];
exec(name, &bp, 0, player, cause, EV_FCHECK | EV_STRIP | EV_EVAL, &str,
cargs, ncargs);
*bp = '\0';
obj = match_thing(player, name);
if ((obj == NOTHING) || ((Owner(obj) != player) && (!(Wizard(player))))
|| (obj == GOD))
obj = player;
str = fargs[1];
exec(buff, bufc, 0, obj, obj, EV_FCHECK | EV_STRIP | EV_EVAL, &str,
cargs, ncargs);
free_lbuf(name);
}
void fun_squish(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *p, *q, *bp;
bp = alloc_lbuf("fun_squish");
StringCopy(bp, fargs[0]);
p = q = bp;
while (*p) {
while (*p && (*p != ' '))
*q++ = *p++;
while (*p && (*p == ' '))
p++;
if (*p)
*q++ = ' ';
}
*q = '\0';
safe_str(bp, buff, bufc);
free_lbuf(bp);
}
void fun_stripansi(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
safe_str((char *) strip_ansi(fargs[0]), buff, bufc);
}
/*
* Borrowed from PennMUSH 1.50
*/
void fun_zfun(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref aowner;
int aflags;
int attrib;
char *tbuf1, *str;
dbref zone = Zone(player);
if (!mudconf.have_zones) {
safe_str("#-1 ZONES DISABLED", buff, bufc);
return;
}
if (zone == NOTHING) {
safe_str("#-1 INVALID ZONE", buff, bufc);
return;
}
if (!fargs[0] || !*fargs[0])
return;
/*
* find the user function attribute
*/
attrib = get_atr(upcasestr(fargs[0]));
if (!attrib) {
safe_str("#-1 NO SUCH USER FUNCTION", buff, bufc);
return;
}
tbuf1 = atr_pget(zone, attrib, &aowner, &aflags);
if (!See_attr(player, zone, (ATTR *) atr_num(attrib), aowner, aflags)) {
safe_str("#-1 NO PERMISSION TO GET ATTRIBUTE", buff, bufc);
free_lbuf(tbuf1);
return;
}
str = tbuf1;
exec(buff, bufc, 0, zone, player, EV_EVAL | EV_STRIP | EV_FCHECK, &str,
&(fargs[1]), nfargs - 1);
free_lbuf(tbuf1);
}
void fun_columns(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int spaces, number, ansinumber, count, i;
static char buf[LBUF_SIZE];
char *p, *q;
int isansi = 0, rturn = 1;
char *curr, *objstring, *bp, *cp, sep, *str;
evarargs_preamble("COLUMNS", 3);
number = atoi(fargs[1]);
if ((number < 1) || (number > 78)) {
safe_str("#-1 OUT OF RANGE", buff, bufc);
return;
}
cp = curr = bp = alloc_lbuf("fun_columns");
str = fargs[0];
exec(curr, &bp, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL, &str,
cargs, ncargs);
*bp = '\0';
cp = trim_space_sep(cp, sep);
if (!*cp) {
free_lbuf(curr);
return;
}
safe_chr(' ', buff, bufc);
while (cp) {
objstring = split_token(&cp, sep);
ansinumber = number;
if (ansinumber > strlen((char *) strip_ansi(objstring)))
ansinumber = strlen((char *) strip_ansi(objstring));
p = objstring;
q = buf;
count = 0;
while (p && *p) {
if (count == number) {
break;
}
if (*p == ESC_CHAR) {
/*
* Start of ANSI code. Skip to end.
*/
isansi = 1;
while (*p && !isalpha(*p))
*q++ = *p++;
if (*p)
*q++ = *p++;
} else {
*q++ = *p++;
count++;
}
}
if (isansi)
safe_str(ANSI_NORMAL, buf, &q);
*q = '\0';
isansi = 0;
spaces = number - strlen((char *) strip_ansi(objstring));
/*
* Sanitize number of spaces
*/
if (spaces > LBUF_SIZE) {
spaces = LBUF_SIZE;
}
safe_str(buf, buff, bufc);
for (i = 0; i < spaces; i++)
safe_chr(' ', buff, bufc);
if (!(rturn % (int) (78 / number)))
safe_str((char *) "\r\n ", buff, bufc);
rturn++;
}
free_lbuf(curr);
}
/*
* Code for objmem and playmem borrowed from PennMUSH 1.50
*/
static int mem_usage(thing)
dbref thing;
{
int k;
int ca;
char *as, *str;
ATTR *attr;
k = sizeof(struct object);
k += strlen(Name(thing)) + 1;
for (ca = atr_head(thing, &as); ca; ca = atr_next(&as)) {
str = atr_get_raw(thing, ca);
if (str && *str)
k += strlen(str);
attr = atr_num(ca);
if (attr) {
str = (char *) attr->name;
if (str && *str)
k += strlen(((ATTR *) atr_num(ca))->name);
}
}
return k;
}
void fun_objmem(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref thing;
thing = match_thing(player, fargs[0]);
if (thing == NOTHING || !Examinable(player, thing)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
safe_tprintf_str(buff, bufc, "%d", mem_usage(thing));
}
void fun_playmem(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int tot = 0;
dbref thing;
dbref j;
thing = match_thing(player, fargs[0]);
if (thing == NOTHING || !Examinable(player, thing)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
DO_WHOLE_DB(j)
if (Owner(j) == thing)
tot += mem_usage(j);
safe_tprintf_str(buff, bufc, "%d", tot);
}
/*
* Code for andflags() and orflags() borrowed from PennMUSH 1.50
*/
static int handle_flaglists(player, name, fstr, type)
dbref player;
char *name;
char *fstr;
int type; /*
* 0 for orflags, 1 for andflags
*/
{
char *s;
char flagletter[2];
FLAGSET fset;
FLAG p_type;
int negate, temp;
int ret = type;
dbref it = match_thing(player, name);
negate = temp = 0;
if (it == NOTHING)
return 0;
for (s = fstr; *s; s++) {
/*
* Check for a negation sign. If we find it, we note it and
* * * * * increment the pointer to the next character.
*/
if (*s == '!') {
negate = 1;
s++;
} else {
negate = 0;
}
if (!*s) {
return 0;
}
flagletter[0] = *s;
flagletter[1] = '\0';
if (!convert_flags(player, flagletter, &fset, &p_type)) {
/*
* Either we got a '!' that wasn't followed by a * *
* * letter, or * we couldn't find that flag. For
* AND, * * * since we've failed * a check, we can
* return * * false. * Otherwise we just go on.
*/
if (type == 1)
return 0;
else
continue;
} else {
/*
* does the object have this flag?
*/
if ((Flags(it) & fset.word1) || (Flags2(it) & fset.word2) ||
(Typeof(it) == p_type)) {
if (isPlayer(it) && (fset.word2 == CONNECTED) &&
((Flags(it) & (WIZARD | DARK)) == (WIZARD | DARK)) &&
!Wizard(player))
temp = 0;
else
temp = 1;
} else {
temp = 0;
}
if ((type == 1) && ((negate && temp) || (!negate && !temp))) {
/*
* Too bad there's no NXOR function... * At *
*
* * * * this point we've either got a flag
* and * we * * don't want * it, or we don't
* have a * flag * * and we want it. Since
* it's * AND, * we * * return false.
*/
return 0;
} else if ((type == 0) && ((!negate && temp) || (negate &&
!temp))) {
/*
* We've found something we want, in an OR. *
*
* * * * We OR a * true with the current
* value.
*/
ret |= 1;
}
/*
* Otherwise, we don't need to do anything.
*/
}
}
return (ret);
}
void fun_orflags(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
safe_tprintf_str(buff, bufc, "%d", handle_flaglists(player, fargs[0],
fargs[1], 0));
}
void fun_andflags(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
safe_tprintf_str(buff, bufc, "%d", handle_flaglists(player, fargs[0],
fargs[1], 1));
}
void fun_strtrunc(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int number, count = 0;
static char buf[LBUF_SIZE];
char *p = (char *) fargs[0];
char *q = buf;
int isansi = 0;
number = atoi(fargs[1]);
if (number > strlen((char *) strip_ansi(fargs[0])))
number = strlen((char *) strip_ansi(fargs[0]));
if (number < 0) {
safe_str("#-1 OUT OF RANGE", buff, bufc);
return;
}
while (p && *p) {
if (count == number) {
break;
}
if (*p == ESC_CHAR) {
/*
* Start of ANSI code. Skip to end.
*/
isansi = 1;
while (*p && !isalpha(*p))
*q++ = *p++;
if (*p)
*q++ = *p++;
} else {
*q++ = *p++;
count++;
}
}
if (isansi)
safe_str(ANSI_NORMAL, buf, &q);
*q = '\0';
safe_str(buf, buff, bufc);
}
void fun_ifelse(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
/* This function now assumes that its arguments have not been
evaluated. */
char *str, *mbuff, *bp;
mbuff = bp = alloc_lbuf("fun_ifelse");
str = fargs[0];
exec(mbuff, &bp, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
&str, cargs, ncargs);
*bp = '\0';
if (!mbuff || !*mbuff || ((atoi(mbuff) == 0) && is_number(mbuff))) {
str = fargs[2];
exec(buff, bufc, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
&str, cargs, ncargs);
} else {
str = fargs[1];
exec(buff, bufc, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
&str, cargs, ncargs);
}
free_lbuf(mbuff);
}
void fun_inc(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int number;
if (!is_number(fargs[0])) {
safe_str("#-1 ARGUMENT MUST BE A NUMBER", buff, bufc);
return;
}
number = atoi(fargs[0]);
safe_tprintf_str(buff, bufc, "%d", (++number));
}
void fun_dec(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int number;
if (!is_number(fargs[0])) {
safe_str("#-1 ARGUMENT MUST BE A NUMBER", buff, bufc);
return;
}
number = atoi(fargs[0]);
safe_tprintf_str(buff, bufc, "%d", (--number));
}
/*
* Mail functions borrowed from DarkZone
*/
void fun_mail(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
/*
* This function can take one of three formats: 1. mail(num) --> *
* * * returns * message <num> for privs. 2. mail(player) -->
* returns * * * number of * messages for <player>. 3.
* mail(player, num) --> * * * returns message <num> * for
* <player>.
*/
/*
* It can now take one more format: 4. mail() --> returns number of
* * * * * messages for executor
*/
struct mail *mp;
dbref playerask;
int num, rc, uc, cc;
/*
* make sure we have the right number of arguments
*/
if ((nfargs != 0) && (nfargs != 1) && (nfargs != 2)) {
safe_str("#-1 FUNCTION (MAIL) EXPECTS 0 OR 1 OR 2 ARGUMENTS", buff,
bufc);
return;
}
if ((nfargs == 0) || !fargs[0] || !fargs[0][0]) {
count_mail(player, 0, &rc, &uc, &cc);
safe_tprintf_str(buff, bufc, "%d", rc + uc);
return;
}
if (nfargs == 1) {
if (!is_number(fargs[0])) {
/*
* handle the case of wanting to count the number of
* * * * messages
*/
if ((playerask =
lookup_player(player, fargs[0], 1)) == NOTHING) {
safe_str("#-1 NO SUCH PLAYER", buff, bufc);
return;
} else if ((player != playerask) && !Wizard(player)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
} else {
count_mail(playerask, 0, &rc, &uc, &cc);
safe_tprintf_str(buff, bufc, "%d %d %d", rc, uc, cc);
return;
}
} else {
playerask = player;
num = atoi(fargs[0]);
}
} else {
if ((playerask = lookup_player(player, fargs[0], 1)) == NOTHING) {
safe_str("#-1 NO SUCH PLAYER", buff, bufc);
return;
} else if ((player != playerask) && !God(player)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
num = atoi(fargs[1]);
}
if ((num < 1) || (Typeof(playerask) != TYPE_PLAYER)) {
safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
return;
}
mp = mail_fetch(playerask, num);
if (mp != NULL) {
safe_str(get_mail_message(mp->number), buff, bufc);
return;
}
/*
* ran off the end of the list without finding anything
*/
safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
}
void fun_mailfrom(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
/*
* This function can take these formats: 1) mailfrom(<num>) 2) * * *
* * mailfrom(<player>,<num>) It returns the dbref of the player the
* * * * mail is * from
*/
struct mail *mp;
dbref playerask;
int num;
/*
* make sure we have the right number of arguments
*/
if ((nfargs != 1) && (nfargs != 2)) {
safe_str("#-1 FUNCTION (MAILFROM) EXPECTS 1 OR 2 ARGUMENTS", buff,
bufc);
return;
}
if (nfargs == 1) {
playerask = player;
num = atoi(fargs[0]);
} else {
if ((playerask = lookup_player(player, fargs[0], 1)) == NOTHING) {
safe_str("#-1 NO SUCH PLAYER", buff, bufc);
return;
} else if ((player != playerask) && !Wizard(player)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
num = atoi(fargs[1]);
}
if ((num < 1) || (Typeof(playerask) != TYPE_PLAYER)) {
safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
return;
}
mp = mail_fetch(playerask, num);
if (mp != NULL) {
safe_tprintf_str(buff, bufc, "#%d", mp->from);
return;
}
/*
* ran off the end of the list without finding anything
*/
safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
}
/*
* ---------------------------------------------------------------------------
* * fun_hasattr: does object X have attribute Y.
*/
/*
* Hasattr (and hasattrp, which is derived from hasattr) borrowed from
* * TinyMUSH 2.2.
*/
void fun_hasattr(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref thing, aowner;
int aflags;
ATTR *attr;
char *tbuf;
thing = match_thing(player, fargs[0]);
if (thing == NOTHING) {
safe_str("#-1 NO MATCH", buff, bufc);
return;
} else if (!Examinable(player, thing)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
attr = atr_str(fargs[1]);
if (!attr) {
safe_str("0", buff, bufc);
return;
}
atr_get_info(thing, attr->number, &aowner, &aflags);
if (!See_attr(player, thing, attr, aowner, aflags))
safe_str("0", buff, bufc);
else {
tbuf = atr_get(thing, attr->number, &aowner, &aflags);
if (*tbuf)
safe_str("1", buff, bufc);
else
safe_str("0", buff, bufc);
free_lbuf(tbuf);
}
}
void fun_hasattrp(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref thing, aowner;
int aflags;
ATTR *attr;
char *tbuf;
thing = match_thing(player, fargs[0]);
if (thing == NOTHING) {
safe_str("#-1 NO MATCH", buff, bufc);
return;
} else if (!Examinable(player, thing)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
attr = atr_str(fargs[1]);
if (!attr) {
safe_str("0", buff, bufc);
return;
}
atr_pget_info(thing, attr->number, &aowner, &aflags);
if (!See_attr(player, thing, attr, aowner, aflags))
safe_str("0", buff, bufc);
else {
tbuf = atr_pget(thing, attr->number, &aowner, &aflags);
if (*tbuf)
safe_str("1", buff, bufc);
else
safe_str("0", buff, bufc);
free_lbuf(tbuf);
}
}
/*
* ---------------------------------------------------------------------------
* * fun_default, fun_edefault, and fun_udefault:
* * These check for the presence of an attribute. If it exists, then it
* * is gotten, via the equivalent of get(), get_eval(), or u(), respectively.
* * Otherwise, the default message is used.
* * In the case of udefault(), the remaining arguments to the function
* * are used as arguments to the u().
*/
/*
* default(), edefault(), and udefault() borrowed from TinyMUSH 2.2
*/
void fun_default(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref thing, aowner;
int attrib, aflags;
ATTR *attr;
char *objname, *atr_gotten, *bp, *str;
objname = bp = alloc_lbuf("fun_default");
str = fargs[0];
exec(objname, &bp, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
&str, cargs, ncargs);
*bp = '\0';
/*
* First we check to see that the attribute exists on the object. * *
*
* * * * If so, we grab it and use it.
*/
if (objname != NULL) {
if (parse_attrib(player, objname, &thing, &attrib) &&
(attrib != NOTHING)) {
attr = atr_num(attrib);
if (attr && !(attr->flags & AF_IS_LOCK)) {
atr_gotten = atr_pget(thing, attrib, &aowner, &aflags);
if (*atr_gotten &&
check_read_perms(player, thing, attr, aowner, aflags,
buff, bufc)) {
safe_str(atr_gotten, buff, bufc);
free_lbuf(atr_gotten);
free_lbuf(objname);
return;
}
free_lbuf(atr_gotten);
}
}
free_lbuf(objname);
}
/*
* If we've hit this point, we've not gotten anything useful, so * we
*
* * * * * * go and evaluate the default.
*/
str = fargs[1];
exec(buff, bufc, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
&str, cargs, ncargs);
}
void fun_edefault(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref thing, aowner;
int attrib, aflags;
ATTR *attr;
char *objname, *atr_gotten, *bp, *str;
objname = bp = alloc_lbuf("fun_edefault");
str = fargs[0];
exec(objname, &bp, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
&str, cargs, ncargs);
*bp = '\0';
/*
* First we check to see that the attribute exists on the object. * *
*
* * * * If so, we grab it and use it.
*/
if (objname != NULL) {
if (parse_attrib(player, objname, &thing, &attrib) &&
(attrib != NOTHING)) {
attr = atr_num(attrib);
if (attr && !(attr->flags & AF_IS_LOCK)) {
atr_gotten = atr_pget(thing, attrib, &aowner, &aflags);
if (*atr_gotten &&
check_read_perms(player, thing, attr, aowner, aflags,
buff, bufc)) {
str = atr_gotten;
exec(buff, bufc, 0, thing, player,
EV_FIGNORE | EV_EVAL, &str, (char **) NULL, 0);
free_lbuf(atr_gotten);
free_lbuf(objname);
return;
}
free_lbuf(atr_gotten);
}
}
free_lbuf(objname);
}
/*
* If we've hit this point, we've not gotten anything useful, so * we
*
* * * * * * go and evaluate the default.
*/
str = fargs[1];
exec(buff, bufc, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
&str, cargs, ncargs);
}
void fun_udefault(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref thing, aowner;
int aflags, anum;
ATTR *ap;
char *objname, *atext, *bp, *str;
if (nfargs < 2) /*
* must have at least two arguments
*/
return;
str = fargs[0];
objname = bp = alloc_lbuf("fun_udefault");
exec(objname, &bp, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
&str, cargs, ncargs);
*bp = '\0';
/*
* First we check to see that the attribute exists on the object. * *
*
* * * * If so, we grab it and use it.
*/
if (objname != NULL) {
if (parse_attrib(player, objname, &thing, &anum)) {
if ((anum == NOTHING) || (!Good_obj(thing)))
ap = NULL;
else
ap = atr_num(anum);
} else {
thing = player;
ap = atr_str(objname);
}
if (ap) {
atext = atr_pget(thing, ap->number, &aowner, &aflags);
if (atext) {
if (*atext &&
check_read_perms(player, thing, ap, aowner, aflags,
buff, bufc)) {
str = atext;
exec(buff, bufc, 0, thing, cause, EV_FCHECK | EV_EVAL,
&str, &(fargs[2]), nfargs - 1);
free_lbuf(atext);
free_lbuf(objname);
return;
}
free_lbuf(atext);
}
}
free_lbuf(objname);
}
/*
* If we've hit this point, we've not gotten anything useful, so * we
*
* * * * * * go and evaluate the default.
*/
str = fargs[1];
exec(buff, bufc, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
&str, cargs, ncargs);
}
/*
* ---------------------------------------------------------------------------
* * fun_findable: can X locate Y
*/
/*
* Borrowed from PennMUSH 1.50
*/
void fun_findable(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref obj = match_thing(player, fargs[0]);
dbref victim = match_thing(player, fargs[1]);
if (obj == NOTHING)
safe_str("#-1 ARG1 NOT FOUND", buff, bufc);
else if (victim == NOTHING)
safe_str("#-1 ARG2 NOT FOUND", buff, bufc);
else
safe_tprintf_str(buff, bufc, "%d", locatable(obj, victim, obj));
}
/*
* ---------------------------------------------------------------------------
* * isword: is every character in the argument a letter?
*/
/*
* Borrowed from PennMUSH 1.50
*/
void fun_isword(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *p;
for (p = fargs[0]; *p; p++) {
if (!isalpha(*p)) {
safe_str("0", buff, bufc);
return;
}
}
safe_str("1", buff, bufc);
}
/*
* ---------------------------------------------------------------------------
* * fun_visible: Can X examine Y. If X does not exist, 0 is returned.
* * If Y, the object, does not exist, 0 is returned. If
* * Y the object exists, but the optional attribute does
* * not, X's ability to return Y the object is returned.
*/
/*
* Borrowed from PennMUSH 1.50
*/
void fun_visible(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref it, thing, aowner;
int aflags, atr;
ATTR *ap;
if ((it = match_thing(player, fargs[0])) == NOTHING) {
safe_str("0", buff, bufc);
return;
}
if (parse_attrib(player, fargs[1], &thing, &atr)) {
if (atr == NOTHING) {
safe_tprintf_str(buff, bufc, "%d", Examinable(it, thing));
return;
}
ap = atr_num(atr);
atr_pget_info(thing, atr, &aowner, &aflags);
safe_tprintf_str(buff, bufc, "%d", See_attr(it, thing, ap, aowner,
aflags));
return;
}
thing = match_thing(player, fargs[1]);
if (!Good_obj(thing)) {
safe_str("0", buff, bufc);
return;
}
safe_tprintf_str(buff, bufc, "%d", Examinable(it, thing));
}
/*
* ---------------------------------------------------------------------------
* * fun_elements: given a list of numbers, get corresponding elements from
* * the list. elements(ack bar eep foof yay,2 4) ==> bar foof
* * The function takes a separator, but the separator only applies to the
* * first list.
*/
/*
* Borrowed from PennMUSH 1.50
*/
void fun_elements(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int nwords, cur;
char *ptrs[LBUF_SIZE / 2];
char *wordlist, *s, *r, sep, *oldp;
varargs_preamble("ELEMENTS", 3);
oldp = *bufc;
/*
* Turn the first list into an array.
*/
wordlist = alloc_lbuf("fun_elements.wordlist");
StringCopy(wordlist, fargs[0]);
nwords = list2arr(ptrs, LBUF_SIZE / 2, wordlist, sep);
s = trim_space_sep(fargs[1], ' ');
/*
* Go through the second list, grabbing the numbers and finding the *
*
* * * * * * corresponding elements.
*/
do {
r = split_token(&s, ' ');
cur = atoi(r) - 1;
if ((cur >= 0) && (cur < nwords) && ptrs[cur]) {
if (oldp != *bufc)
safe_chr(sep, buff, bufc);
safe_str(ptrs[cur], buff, bufc);
}
} while (s);
free_lbuf(wordlist);
}
/*
* ---------------------------------------------------------------------------
* * fun_grab: a combination of extract() and match(), sortof. We grab the
* * single element that we match.
* *
* * grab(Test:1 Ack:2 Foof:3,*:2) => Ack:2
* * grab(Test-1+Ack-2+Foof-3,*o*,+) => Ack:2
*/
/*
* Borrowed from PennMUSH 1.50
*/
void fun_grab(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *r, *s, sep;
varargs_preamble("GRAB", 3);
/*
* Walk the wordstring, until we find the word we want.
*/
s = trim_space_sep(fargs[0], sep);
do {
r = split_token(&s, sep);
if (quick_wild(fargs[1], r)) {
safe_str(r, buff, bufc);
return;
}
} while (s);
}
/*
* ---------------------------------------------------------------------------
* * fun_scramble: randomizes the letters in a string.
*/
/*
* Borrowed from PennMUSH 1.50
*/
void fun_scramble(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int n, i, j;
char c, *old;
if (!fargs[0] || !*fargs[0]) {
return;
}
old = *bufc;
safe_str(fargs[0], buff, bufc);
**bufc = '\0';
n = strlen(old);
for (i = 0; i < n; i++) {
j = (random() % (n - i)) + i;
c = old[i];
old[i] = old[j];
old[j] = c;
}
}
/*
* ---------------------------------------------------------------------------
* * fun_shuffle: randomize order of words in a list.
*/
/*
* Borrowed from PennMUSH 1.50
*/
static void swap(p, q)
char **p;
char **q;
{
/*
* swaps two points to strings
*/
char *temp;
temp = *p;
*p = *q;
*q = temp;
}
void fun_shuffle(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *words[LBUF_SIZE];
int n, i, j;
char sep;
if (!nfargs || !fargs[0] || !*fargs[0]) {
return;
}
varargs_preamble("SHUFFLE", 2);
n = list2arr(words, LBUF_SIZE, fargs[0], sep);
for (i = 0; i < n; i++) {
j = (random() % (n - i)) + i;
swap(&words[i], &words[j]);
}
arr2list(words, n, buff, bufc, sep);
}
/*
* sortby() code borrowed from TinyMUSH 2.2
*/
static char ucomp_buff[LBUF_SIZE];
static dbref ucomp_cause;
static dbref ucomp_player;
static int u_comp(s1, s2)
const void *s1, *s2;
{
/*
* Note that this function is for use in conjunction with our own * *
*
* * * * sane_qsort routine, NOT with the standard library qsort!
*/
char *result, *tbuf, *elems[2], *bp, *str;
int n;
if ((mudstate.func_invk_ctr > mudconf.func_invk_lim) ||
(mudstate.func_nest_lev > mudconf.func_nest_lim))
return 0;
tbuf = alloc_lbuf("u_comp");
elems[0] = (char *) s1;
elems[1] = (char *) s2;
StringCopy(tbuf, ucomp_buff);
result = bp = alloc_lbuf("u_comp");
str = tbuf;
exec(result, &bp, 0, ucomp_player, ucomp_cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, &(elems[0]), 2);
*bp = '\0';
if (!result)
n = 0;
else {
n = atoi(result);
free_lbuf(result);
}
free_lbuf(tbuf);
return n;
}
static void sane_qsort(array, left, right, compare)
void *array[];
int left, right;
int (*compare) ();
{
/*
* Andrew Molitor's qsort, which doesn't require transitivity between
* * * * * comparisons (essential for preventing crashes due to *
* boneheads * * * who write comparison functions where a > b doesn't
* * mean b < a).
*/
int i, last;
void *tmp;
loop:
if (left >= right)
return;
/*
* Pick something at random at swap it into the leftmost slot
*/
/*
* This is the pivot, we'll put it back in the right spot later
*/
i = random() % (1 + (right - left));
tmp = array[left + i];
array[left + i] = array[left];
array[left] = tmp;
last = left;
for (i = left + 1; i <= right; i++) {
/*
* Walk the array, looking for stuff that's less than our
*/
/*
* pivot. If it is, swap it with the next thing along
*/
if ((*compare) (array[i], array[left]) < 0) {
last++;
if (last == i)
continue;
tmp = array[last];
array[last] = array[i];
array[i] = tmp;
}
}
/*
* Now we put the pivot back, it's now in the right spot, we never
*/
/*
* need to look at it again, trust me.
*/
tmp = array[last];
array[last] = array[left];
array[left] = tmp;
/*
* At this point everything underneath the 'last' index is < the
*/
/*
* entry at 'last' and everything above it is not < it.
*/
if ((last - left) < (right - last)) {
sane_qsort(array, left, last - 1, compare);
left = last + 1;
goto loop;
} else {
sane_qsort(array, last + 1, right, compare);
right = last - 1;
goto loop;
}
}
void fun_sortby(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *atext, *list, *ptrs[LBUF_SIZE / 2], sep;
int nptrs, aflags, anum;
dbref thing, aowner;
ATTR *ap;
if ((nfargs == 0) || !fargs[0] || !*fargs[0]) {
return;
}
varargs_preamble("SORTBY", 3);
if (parse_attrib(player, fargs[0], &thing, &anum)) {
if ((anum == NOTHING) || !Good_obj(thing))
ap = NULL;
else
ap = atr_num(anum);
} else {
thing = player;
ap = atr_str(fargs[0]);
}
if (!ap) {
return;
}
atext = atr_pget(thing, ap->number, &aowner, &aflags);
if (!atext) {
return;
} else if (!*atext || !See_attr(player, thing, ap, aowner, aflags)) {
free_lbuf(atext);
return;
}
StringCopy(ucomp_buff, atext);
ucomp_player = thing;
ucomp_cause = cause;
list = alloc_lbuf("fun_sortby");
StringCopy(list, fargs[1]);
nptrs = list2arr(ptrs, LBUF_SIZE / 2, list, sep);
if (nptrs > 1) /*
* pointless to sort less than 2 elements
*/
sane_qsort((void *) ptrs, 0, nptrs - 1, u_comp);
arr2list(ptrs, nptrs, buff, bufc, sep);
free_lbuf(list);
free_lbuf(atext);
}
/*
* ---------------------------------------------------------------------------
* * fun_last: Returns last word in a string
*/
/*
* Borrowed from TinyMUSH 2.2
*/
void fun_last(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *s, *last, sep;
int len, i;
/*
* If we are passed an empty arglist return a null string
*/
if (nfargs == 0) {
return;
}
varargs_preamble("LAST", 2);
s = trim_space_sep(fargs[0], sep); /*
* trim leading spaces
*/
/*
* If we're dealing with spaces, trim off the trailing stuff
*/
if (sep == ' ') {
len = strlen(s);
for (i = len - 1; s[i] == ' '; i--);
if (i + 1 <= len)
s[i + 1] = '\0';
}
last = (char *) rindex(s, sep);
if (last)
safe_str(++last, buff, bufc);
else
safe_str(s, buff, bufc);
}
/*
* Borrowed from TinyMUSH 2.2
*/
void fun_matchall(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int wcount;
char *r, *s, *old, sep, tbuf[8];
varargs_preamble("MATCHALL", 3);
old = *bufc;
/*
* Check each word individually, returning the word number of all * *
*
* * * * that match. If none match, return 0.
*/
wcount = 1;
s = trim_space_sep(fargs[0], sep);
do {
r = split_token(&s, sep);
if (quick_wild(fargs[1], r)) {
sprintf(tbuf, "%d", wcount);
if (old != *bufc)
safe_chr(' ', buff, bufc);
safe_str(tbuf, buff, bufc);
}
wcount++;
} while (s);
if (*bufc == old)
safe_str("0", buff, bufc);
}
/*
* ---------------------------------------------------------------------------
* * fun_ports: Returns a list of ports for a user.
*/
/*
* Borrowed from TinyMUSH 2.2
*/
void fun_ports(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref target;
if (!Wizard(player)) {
return;
}
target = lookup_player(player, fargs[0], 1);
if (!Good_obj(target) || !Connected(target)) {
return;
}
make_portlist(player, target, buff, bufc);
}
/*
* ---------------------------------------------------------------------------
* * fun_mix: Like map, but operates on two lists simultaneously, passing
* * the elements as %0 as %1.
*/
/*
* Borrowed from PennMUSH 1.50
*/
void fun_mix(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref aowner, thing;
int aflags, anum;
ATTR *ap;
char *atext, *os[2], *oldp, *str, *cp1, *cp2, *atextbuf, sep;
varargs_preamble("MIX", 4);
oldp = *bufc;
/*
* Get the attribute, check the permissions.
*/
if (parse_attrib(player, fargs[0], &thing, &anum)) {
if ((anum == NOTHING) || !Good_obj(thing))
ap = NULL;
else
ap = atr_num(anum);
} else {
thing = player;
ap = atr_str(fargs[0]);
}
if (!ap) {
return;
}
atext = atr_pget(thing, ap->number, &aowner, &aflags);
if (!atext) {
return;
} else if (!*atext || !See_attr(player, thing, ap, aowner, aflags)) {
free_lbuf(atext);
return;
}
/*
* process the two lists, one element at a time.
*/
cp1 = trim_space_sep(fargs[1], sep);
cp2 = trim_space_sep(fargs[2], sep);
if (countwords(cp1, sep) != countwords(cp2, sep)) {
free_lbuf(atext);
safe_str("#-1 LISTS MUST BE OF EQUAL SIZE", buff, bufc);
return;
}
atextbuf = alloc_lbuf("fun_mix");
while (cp1 && cp2) {
if (*bufc != oldp)
safe_chr(sep, buff, bufc);
os[0] = split_token(&cp1, sep);
os[1] = split_token(&cp2, sep);
StringCopy(atextbuf, atext);
str = atextbuf;
exec(buff, bufc, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
&str, &(os[0]), 2);
}
free_lbuf(atext);
free_lbuf(atextbuf);
}
/*
* ---------------------------------------------------------------------------
* * fun_foreach: like map(), but it operates on a string, rather than on a list,
* * calling a user-defined function for each character in the string.
* * No delimiter is inserted between the results.
*/
/*
* Borrowed from TinyMUSH 2.2
*/
void fun_foreach(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref aowner, thing;
int aflags, anum, flag = 0;
ATTR *ap;
char *atext, *atextbuf, *str, *cp, *bp;
char cbuf[2], prev = '\0';
if ((nfargs != 2) && (nfargs != 4)) {
safe_str("#-1 FUNCTION (FOREACH) EXPECTS 2 or 4 ARGUMENTS", buff,
bufc);
return;
}
if (parse_attrib(player, fargs[0], &thing, &anum)) {
if ((anum == NOTHING) || !Good_obj(thing))
ap = NULL;
else
ap = atr_num(anum);
} else {
thing = player;
ap = atr_str(fargs[0]);
}
if (!ap) {
return;
}
atext = atr_pget(thing, ap->number, &aowner, &aflags);
if (!atext) {
return;
} else if (!*atext || !See_attr(player, thing, ap, aowner, aflags)) {
free_lbuf(atext);
return;
}
atextbuf = alloc_lbuf("fun_foreach");
cp = trim_space_sep(fargs[1], ' ');
bp = cbuf;
cbuf[1] = '\0';
if (nfargs == 4) {
while (cp && *cp) {
cbuf[0] = *cp++;
if (flag) {
if ((cbuf[0] == *fargs[3]) && (prev != '\\') &&
(prev != '%')) {
flag = 0;
continue;
}
} else {
if ((cbuf[0] == *fargs[2]) && (prev != '\\') &&
(prev != '%')) {
flag = 1;
continue;
} else {
safe_chr(cbuf[0], buff, bufc);
continue;
}
}
StringCopy(atextbuf, atext);
str = atextbuf;
exec(buff, bufc, 0, player, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, &bp, 1);
prev = cbuf[0];
}
} else {
while (cp && *cp) {
cbuf[0] = *cp++;
StringCopy(atextbuf, atext);
str = atextbuf;
exec(buff, bufc, 0, player, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, &bp, 1);
}
}
free_lbuf(atextbuf);
free_lbuf(atext);
}
/*
* ---------------------------------------------------------------------------
* * fun_munge: combines two lists in an arbitrary manner.
*/
/*
* Borrowed from TinyMUSH 2.2
*/
void fun_munge(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref aowner, thing;
int aflags, anum, nptrs1, nptrs2, nresults, i, j;
ATTR *ap;
char *list1, *list2, *rlist;
char *ptrs1[LBUF_SIZE / 2], *ptrs2[LBUF_SIZE / 2],
*results[LBUF_SIZE / 2];
char *atext, *bp, *str, sep, *oldp;
oldp = *bufc;
if ((nfargs == 0) || !fargs[0] || !*fargs[0]) {
return;
}
varargs_preamble("MUNGE", 4);
/*
* Find our object and attribute
*/
if (parse_attrib(player, fargs[0], &thing, &anum)) {
if ((anum == NOTHING) || !Good_obj(thing))
ap = NULL;
else
ap = atr_num(anum);
} else {
thing = player;
ap = atr_str(fargs[0]);
}
if (!ap) {
return;
}
atext = atr_pget(thing, ap->number, &aowner, &aflags);
if (!atext) {
return;
} else if (!*atext || !See_attr(player, thing, ap, aowner, aflags)) {
free_lbuf(atext);
return;
}
/*
* Copy our lists and chop them up.
*/
list1 = alloc_lbuf("fun_munge.list1");
list2 = alloc_lbuf("fun_munge.list2");
StringCopy(list1, fargs[1]);
StringCopy(list2, fargs[2]);
nptrs1 = list2arr(ptrs1, LBUF_SIZE / 2, list1, sep);
nptrs2 = list2arr(ptrs2, LBUF_SIZE / 2, list2, sep);
if (nptrs1 != nptrs2) {
safe_str("#-1 LISTS MUST BE OF EQUAL SIZE", buff, bufc);
free_lbuf(atext);
free_lbuf(list1);
free_lbuf(list2);
return;
}
/*
* Call the u-function with the first list as %0.
*/
bp = rlist = alloc_lbuf("fun_munge");
str = atext;
exec(rlist, &bp, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
&str, &fargs[1], 1);
*bp = '\0';
/*
* Now that we have our result, put it back into array form. Search *
*
* * * * * * through list1 until we find the element position, then
* copy * the * * * corresponding element from list2.
*/
nresults = list2arr(results, LBUF_SIZE / 2, rlist, sep);
for (i = 0; i < nresults; i++) {
for (j = 0; j < nptrs1; j++) {
if (!strcmp(results[i], ptrs1[j])) {
if (*bufc != oldp)
safe_chr(sep, buff, bufc);
safe_str(ptrs2[j], buff, bufc);
ptrs1[j][0] = '\0';
break;
}
}
}
free_lbuf(atext);
free_lbuf(list1);
free_lbuf(list2);
free_lbuf(rlist);
}
/*
* die() code borrowed from PennMUSH 1.50
*/
int getrandom(x)
int x;
{
/*
* In order to be perfectly anal about not introducing any further *
* * * sources * of statistical bias, we're going to call random() *
* until * * we get a number * less than the greatest representable *
* multiple * of * x. We'll then return * n mod x.
*/
long n;
if (x <= 0)
return -1;
do {
n = random();
} while (LONG_MAX - n < x);
/*
* N.B. This loop happens in randomized constant time, and pretty damn
* * fast randomized constant time too, since P(LONG_MAX - n < x) < 0.5
* * for any x, so for any X, the average number of times we should
* * have to call random() is less than 2.
*/
return (n % x);
}
void fun_die(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int n, die, count;
int total = 0;
if (!fargs[0] || !fargs[1])
return;
n = atoi(fargs[0]);
die = atoi(fargs[1]);
if ((n < 1) || (n > 20)) {
safe_str("#-1 NUMBER OUT OF RANGE", buff, bufc);
return;
}
if (die > 100) {
safe_str("#-1 DON'T BE AN ASSHOLE", buff, bufc);
return;
}
for (count = 0; count < n; count++)
total += getrandom(die) + 1;
safe_tprintf_str(buff, bufc, "%d", total);
}
/*
* Borrowed from PennMUSH 1.50
*/
void fun_lit(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
/*
* Just returns the argument, literally
*/
safe_str(fargs[0], buff, bufc);
}
/*
* shl() and shr() borrowed from PennMUSH 1.50
*/
void fun_shl(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
if (is_number(fargs[0]) && is_number(fargs[1]))
safe_tprintf_str(buff, bufc, "%d",
atoi(fargs[0]) << atoi(fargs[1]));
else
safe_str("#-1 ARGUMENTS MUST BE NUMBERS", buff, bufc);
}
void fun_shr(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
if (is_number(fargs[0]) && is_number(fargs[1]))
safe_tprintf_str(buff, bufc, "%d",
atoi(fargs[0]) >> atoi(fargs[1]));
else
safe_str("#-1 ARGUMENTS MUST BE NUMBERS", buff, bufc);
}
/*
* ------------------------------------------------------------------------
* * Vector functions: VADD, VSUB, VMUL, VCROSS, VMAG, VUNIT, VDIM
* * Vectors are space-separated numbers.
*/
/*
* Vector functions borrowed from PennMUSH 1.50
*/
#define MAXDIM 20
void fun_vadd(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *v1[LBUF_SIZE], *v2[LBUF_SIZE];
char vres[MAXDIM][LBUF_SIZE];
int n, m, i;
char sep;
varargs_preamble("VADD", 3);
/*
* split the list up, or return if the list is empty
*/
if (!fargs[0] || !*fargs[0] || !fargs[1] || !*fargs[1]) {
return;
}
n = list2arr(v1, LBUF_SIZE, fargs[0], sep);
m = list2arr(v2, LBUF_SIZE, fargs[1], sep);
if (n != m) {
safe_str("#-1 VECTORS MUST BE SAME DIMENSIONS", buff, bufc);
return;
}
if (n > MAXDIM) {
safe_str("#-1 TOO MANY DIMENSIONS ON VECTORS", buff, bufc);
return;
}
/*
* add it
*/
for (i = 0; i < n; i++) {
sprintf(vres[i], "%f", atof(v1[i]) + atof(v2[i]));
v1[i] = (char *) vres[i];
}
arr2list(v1, n, buff, bufc, sep);
}
void fun_vsub(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *v1[LBUF_SIZE], *v2[LBUF_SIZE];
char vres[MAXDIM][LBUF_SIZE];
int n, m, i;
char sep;
varargs_preamble("VSUB", 3);
/*
* split the list up, or return if the list is empty
*/
if (!fargs[0] || !*fargs[0] || !fargs[1] || !*fargs[1]) {
return;
}
n = list2arr(v1, LBUF_SIZE, fargs[0], sep);
m = list2arr(v2, LBUF_SIZE, fargs[1], sep);
if (n != m) {
safe_str("#-1 VECTORS MUST BE SAME DIMENSIONS", buff, bufc);
return;
}
if (n > MAXDIM) {
safe_str("#-1 TOO MANY DIMENSIONS ON VECTORS", buff, bufc);
return;
}
/*
* sub it
*/
for (i = 0; i < n; i++) {
sprintf(vres[i], "%f", atof(v1[i]) - atof(v2[i]));
v1[i] = (char *) vres[i];
}
arr2list(v1, n, buff, bufc, sep);
}
void fun_vmul(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *v1[LBUF_SIZE], *v2[LBUF_SIZE];
char vres[MAXDIM][LBUF_SIZE];
int n, m, i;
float scalar;
char sep;
varargs_preamble("VMUL", 3);
/*
* split the list up, or return if the list is empty
*/
if (!fargs[0] || !*fargs[0] || !fargs[1] || !*fargs[1]) {
return;
}
n = list2arr(v1, LBUF_SIZE, fargs[0], sep);
m = list2arr(v2, LBUF_SIZE, fargs[1], sep);
if ((n != 1) && (m != 1) && (n != m)) {
safe_str("#-1 VECTORS MUST BE SAME DIMENSIONS", buff, bufc);
return;
}
if (n > MAXDIM) {
safe_str("#-1 TOO MANY DIMENSIONS ON VECTORS", buff, bufc);
return;
}
/*
* multiply it - if n or m is 1, it's scalar multiplication by a * *
* * vector, otherwise it's a dot-product
*/
if (n == 1) {
scalar = atof(v1[0]);
for (i = 0; i < m; i++) {
sprintf(vres[i], "%f", atof(v2[i]) * scalar);
v1[i] = (char *) vres[i];
}
n = m;
} else if (m == 1) {
scalar = atof(v2[0]);
for (i = 0; i < n; i++) {
sprintf(vres[i], "%f", atof(v1[i]) * scalar);
v1[i] = (char *) vres[i];
}
} else {
/*
* dot product
*/
scalar = 0;
for (i = 0; i < n; i++) {
scalar += atof(v1[i]) * atof(v2[i]);
v1[i] = (char *) vres[i];
}
safe_tprintf_str(buff, bufc, "%f", scalar);
return;
}
arr2list(v1, n, buff, bufc, sep);
}
void fun_vmag(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *v1[LBUF_SIZE];
int n, i;
float tmp, res = 0;
char sep;
varargs_preamble("VMAG", 2);
/*
* split the list up, or return if the list is empty
*/
if (!fargs[0] || !*fargs[0]) {
return;
}
n = list2arr(v1, LBUF_SIZE, fargs[0], sep);
if (n > MAXDIM) {
StringCopy(buff, "#-1 TOO MANY DIMENSIONS ON VECTORS");
return;
}
/*
* calculate the magnitude
*/
for (i = 0; i < n; i++) {
tmp = atof(v1[i]);
res += tmp * tmp;
}
if (res > 0)
safe_tprintf_str(buff, bufc, "%f", sqrt(res));
else
safe_str("0", buff, bufc);
}
void fun_vunit(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *v1[LBUF_SIZE];
char vres[MAXDIM][LBUF_SIZE];
int n, i;
float tmp, res = 0;
char sep;
varargs_preamble("VUNIT", 2);
/*
* split the list up, or return if the list is empty
*/
if (!fargs[0] || !*fargs[0]) {
return;
}
n = list2arr(v1, LBUF_SIZE, fargs[0], sep);
if (n > MAXDIM) {
StringCopy(buff, "#-1 TOO MANY DIMENSIONS ON VECTORS");
return;
}
/*
* calculate the magnitude
*/
for (i = 0; i < n; i++) {
tmp = atof(v1[i]);
res += tmp * tmp;
}
if (res <= 0) {
safe_str("#-1 CAN'T MAKE UNIT VECTOR FROM ZERO-LENGTH VECTOR",
buff, bufc);
return;
}
for (i = 0; i < n; i++) {
sprintf(vres[i], "%f", atof(v1[i]) / sqrt(res));
v1[i] = (char *) vres[i];
}
arr2list(v1, n, buff, bufc, sep);
}
void fun_vdim(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char sep;
if (fargs == 0)
safe_str("0", buff, bufc);
else {
varargs_preamble("VDIM", 2);
safe_tprintf_str(buff, bufc, "%d", countwords(fargs[0], sep));
}
}
void fun_strcat(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int i;
safe_str(fargs[0], buff, bufc);
for (i = 1; i < nfargs; i++) {
safe_str(fargs[i], buff, bufc);
}
}
/*
* grep() and grepi() code borrowed from PennMUSH 1.50
*/
char *grep_util(player, thing, pattern, lookfor, len, insensitive)
dbref player, thing;
char *pattern;
char *lookfor;
int len;
int insensitive;
{
/*
* returns a list of attributes which match <pattern> on <thing> * *
* * * whose contents have <lookfor>
*/
dbref aowner;
char *tbuf1, *buf, *text, *attrib;
char *bp, *bufc;
int found;
int ca, aflags;
tbuf1 = alloc_lbuf("grep_util");
bufc = buf = alloc_lbuf("grep_util.parse_attrib");
bp = tbuf1;
safe_tprintf_str(buf, &bufc, "#%d/%s", thing, pattern);
olist_push();
if (parse_attrib_wild(player, buf, &thing, 0, 0, 1)) {
for (ca = olist_first(); ca != NOTHING; ca = olist_next()) {
attrib = atr_get(thing, ca, &aowner, &aflags);
text = attrib;
found = 0;
while (*text && !found) {
if ((!insensitive && !strncmp(lookfor, text, len)) ||
(insensitive && !strncasecmp(lookfor, text, len)))
found = 1;
else
text++;
}
if (found) {
if (bp != tbuf1)
safe_chr(' ', tbuf1, &bp);
safe_str((char *) (atr_num(ca))->name, tbuf1, &bp);
}
free_lbuf(attrib);
}
}
free_lbuf(buf);
*bp = '\0';
olist_pop();
return tbuf1;
}
void fun_grep(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *tp;
dbref it = match_thing(player, fargs[0]);
if (it == NOTHING) {
safe_str("#-1 NO MATCH", buff, bufc);
return;
} else if (!(Examinable(player, it))) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
/*
* make sure there's an attribute and a pattern
*/
if (!fargs[1] || !*fargs[1]) {
safe_str("#-1 NO SUCH ATTRIBUTE", buff, bufc);
return;
}
if (!fargs[2] || !*fargs[2]) {
safe_str("#-1 INVALID GREP PATTERN", buff, bufc);
return;
}
tp = grep_util(player, it, fargs[1], fargs[2], strlen(fargs[2]), 0);
safe_str(tp, buff, bufc);
free_lbuf(tp);
}
void fun_grepi(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *tp;
dbref it = match_thing(player, fargs[0]);
if (it == NOTHING) {
safe_str("#-1 NO MATCH", buff, bufc);
return;
} else if (!(Examinable(player, it))) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
/*
* make sure there's an attribute and a pattern
*/
if (!fargs[1] || !*fargs[1]) {
safe_str("#-1 NO SUCH ATTRIBUTE", buff, bufc);
return;
}
if (!fargs[2] || !*fargs[2]) {
safe_str("#-1 INVALID GREP PATTERN", buff, bufc);
return;
}
tp = grep_util(player, it, fargs[1], fargs[2], strlen(fargs[2]), 1);
safe_str(tp, buff, bufc);
free_lbuf(tp);
}
/*
* Borrowed from PennMUSH 1.50
*/
void fun_art(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
/*
* checks a word and returns the appropriate article, "a" or "an"
*/
char c = tolower(*fargs[0]);
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
safe_str("an", buff, bufc);
else
safe_str("a", buff, bufc);
}
/*
* Borrowed from PennMUSH 1.50
*/
void fun_alphamax(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *amax;
int i = 1;
if (!fargs[0]) {
safe_str("#-1 TOO FEW ARGUMENTS", buff, bufc);
return;
} else
amax = fargs[0];
while ((i < 10) && fargs[i]) {
amax = (strcmp(amax, fargs[i]) > 0) ? amax : fargs[i];
i++;
}
safe_tprintf_str(buff, bufc, "%s", amax);
}
/*
* Borrowed from PennMUSH 1.50
*/
void fun_alphamin(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
char *amin;
int i = 1;
if (!fargs[0]) {
safe_str("#-1 TOO FEW ARGUMENTS", buff, bufc);
return;
} else
amin = fargs[0];
while ((i < 10) && fargs[i]) {
amin = (strcmp(amin, fargs[i]) < 0) ? amin : fargs[i];
i++;
}
safe_tprintf_str(buff, bufc, "%s", amin);
}
/*
* Borrowed from PennMUSH 1.50
*/
void fun_valid(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
/*
* Checks to see if a given <something> is valid as a parameter of a
* * given type (such as an object name).
*/
if (!fargs[0] || !*fargs[0] || !fargs[1] || !*fargs[1])
safe_str("0", buff, bufc);
else if (!strcasecmp(fargs[0], "name"))
safe_tprintf_str(buff, bufc, "%d", ok_name(fargs[1]));
else
safe_str("#-1", buff, bufc);
}
/*
* Borrowed from PennMUSH 1.50
*/
void fun_hastype(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref it = match_thing(player, fargs[0]);
if (it == NOTHING) {
safe_str("#-1 NO MATCH", buff, bufc);
return;
}
if (!fargs[1] || !*fargs[1]) {
safe_str("#-1 NO SUCH TYPE", buff, bufc);
return;
}
switch (*fargs[1]) {
case 'r':
case 'R':
safe_str((Typeof(it) == TYPE_ROOM) ? "1" : "0", buff, bufc);
break;
case 'e':
case 'E':
safe_str((Typeof(it) == TYPE_EXIT) ? "1" : "0", buff, bufc);
break;
case 'p':
case 'P':
safe_str((Typeof(it) == TYPE_PLAYER) ? "1" : "0", buff, bufc);
break;
case 't':
case 'T':
safe_str((Typeof(it) == TYPE_THING) ? "1" : "0", buff, bufc);
break;
default:
safe_str("#-1 NO SUCH TYPE", buff, bufc);
break;
};
}
/*
* Borrowed from PennMUSH 1.50
*/
void fun_lparent(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref it;
dbref par;
char tbuf1[20];
it = match_thing(player, fargs[0]);
if (!Good_obj(it)) {
safe_str("#-1 NO MATCH", buff, bufc);
return;
} else if (!(Examinable(player, it))) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
sprintf(tbuf1, "#%d", it);
safe_str(tbuf1, buff, bufc);
par = Parent(it);
while (Good_obj(par) && Examinable(player, it)) {
sprintf(tbuf1, " #%d", par);
safe_str(tbuf1, buff, bufc);
it = par;
par = Parent(par);
}
}
/* stacksize - returns how many items are stuffed onto an object stack */
int stacksize(doer)
dbref doer;
{
int i;
STACK *sp;
for (i = 0, sp = Stack(doer); sp != NULL; sp = sp->next, i++);
return i;
}
void fun_lstack(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
STACK *sp;
dbref doer;
if (nfargs > 1) {
safe_str("#-1 FUNCTION (CSTACK) EXPECTS 0-1 ARGUMENTS", buff,
bufc);
return;
}
if (!fargs[0]) {
doer = player;
} else {
doer = match_thing(player, fargs[0]);
}
if (!Controls(player, doer)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
for (sp = Stack(doer); sp != NULL; sp = sp->next) {
safe_str(sp->data, buff, bufc);
safe_chr(' ', buff, bufc);
}
if (sp)
(*bufc)--;
}
void fun_empty(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
STACK *sp, *next;
dbref doer;
if (nfargs > 1) {
safe_str("#-1 FUNCTION (CSTACK) EXPECTS 0-1 ARGUMENTS", buff,
bufc);
return;
}
if (!fargs[0]) {
doer = player;
} else {
doer = match_thing(player, fargs[0]);
}
if (!Controls(player, doer)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
for (sp = Stack(doer); sp != NULL; sp = next) {
next = sp->next;
free_lbuf(sp->data);
free(sp);
}
s_Stack(doer, NULL);
}
void fun_items(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
dbref doer;
if (nfargs > 1) {
safe_str("#-1 FUNCTION (NUMSTACK) EXPECTS 0-1 ARGUMENTS", buff,
bufc);
return;
}
if (!fargs[0]) {
doer = player;
} else {
doer = match_thing(player, fargs[0]);
}
if (!Controls(player, doer)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
safe_tprintf_str(buff, bufc, "%d", stacksize(doer));
}
void fun_peek(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
STACK *sp;
dbref doer;
int count, pos;
if (nfargs > 2) {
safe_str("#-1 FUNCTION (PEEK) EXPECTS 0-2 ARGUMENTS", buff, bufc);
return;
}
if (!fargs[0]) {
doer = player;
} else {
doer = match_thing(player, fargs[0]);
}
if (!Controls(player, doer)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
if (!fargs[1] || !*fargs[1]) {
pos = 0;
} else {
pos = atoi(fargs[1]);
}
if (stacksize(doer) == 0) {
return;
}
if (pos > (stacksize(doer) - 1)) {
safe_str("#-1 POSITION TOO LARGE", buff, bufc);
return;
}
count = 0;
sp = Stack(doer);
while (count != pos) {
if (sp == NULL) {
return;
}
count++;
sp = sp->next;
}
safe_str(sp->data, buff, bufc);
}
void fun_pop(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
STACK *sp, *prev = NULL;
dbref doer;
int count, pos;
if (nfargs > 2) {
safe_str("#-1 FUNCTION (POP) EXPECTS 0-2 ARGUMENTS", buff, bufc);
return;
}
if (!fargs[0]) {
doer = player;
} else {
doer = match_thing(player, fargs[0]);
}
if (!Controls(player, doer)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
if (!fargs[1] || !*fargs[1]) {
pos = 0;
} else {
pos = atoi(fargs[1]);
}
sp = Stack(doer);
count = 0;
if (stacksize(doer) == 0) {
return;
}
if (pos > (stacksize(doer) - 1)) {
safe_str("#-1 POSITION TOO LARGE", buff, bufc);
return;
}
while (count != pos) {
if (sp == NULL) {
return;
}
prev = sp;
sp = sp->next;
count++;
}
safe_str(sp->data, buff, bufc);
if (count == 0) {
s_Stack(doer, sp->next);
free_lbuf(sp->data);
free(sp);
} else {
prev->next = sp->next;
free_lbuf(sp->data);
free(sp);
}
}
void fun_push(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
STACK *sp;
dbref doer;
char *data;
if ((nfargs > 2) || (nfargs < 1)) {
safe_str("#-1 FUNCTION (PUSH) EXPECTS 1-2 ARGUMENTS", buff, bufc);
return;
}
if (!fargs[1]) {
doer = player;
data = fargs[0];
} else {
doer = match_thing(player, fargs[0]);
data = fargs[1];
}
if (!Controls(player, doer)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
if (stacksize(doer) >= mudconf.stack_limit) {
safe_str("#-1 STACK SIZE EXCEEDED", buff, bufc);
return;
}
sp = (STACK *) malloc(sizeof(STACK));
sp->next = Stack(doer);
sp->data = alloc_lbuf("push");
StringCopy(sp->data, data);
s_Stack(doer, sp);
}
/* ---------------------------------------------------------------------------
* fun_regmatch: Return 0 or 1 depending on whether or not a regular
* expression matches a string. If a third argument is specified, dump
* the results of a regexp pattern match into a set of arbitrary r()-registers.
*
* regmatch(string, pattern, list of registers)
* If the number of matches exceeds the registers, those bits are tossed
* out.
* If -1 is specified as a register number, the matching bit is tossed.
* Therefore, if the list is "-1 0 3 5", the regexp $0 is tossed, and
* the regexp $1, $2, and $3 become r(0), r(3), and r(5), respectively.
*
*/
void fun_regmatch(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int i, nqregs, curq, len;
char *qregs[10];
int matchnum;
regexp *re;
if (!fn_range_check("REGMATCH", nfargs, 2, 3, buff, bufc))
return;
if ((re = regcomp(fargs[1])) == NULL) {
/* Matching error. */
notify_quiet(player, (const char *) regexp_errbuf);
safe_chr('0', buff, bufc);
return;
}
matchnum = regexec(re, fargs[0]);
safe_tprintf_str(buff, bufc, "%d", matchnum);
/* If we don't have a third argument, we're done. */
if (nfargs != 3) {
free(re);
return;
}
/* We need to parse the list of registers. Anything that we don't get is
* assumed to be -1.
*/
nqregs = list2arr(qregs, 10, fargs[2], ' ');
for (i = 0; i < nqregs; i++) {
if (qregs[i] && *qregs[i] && isdigit(*qregs[i]))
curq = atoi(qregs[i]);
else
continue;
if (curq < 0 || curq > 9)
continue;
if (!mudstate.global_regs[curq])
mudstate.global_regs[curq] = alloc_lbuf("fun_regmatch");
if (!matchnum || !re->startp[i] || !re->endp[i]) {
mudstate.global_regs[curq][0] = '\0';
continue;
}
len = re->endp[i] - re->startp[i];
if (len < 0)
len = 0;
if (len >= LBUF_SIZE)
len = LBUF_SIZE - 1;
strncpy(mudstate.global_regs[curq], re->startp[i], len);
mudstate.global_regs[curq][len] = '\0'; /* must null-terminate */
}
free(re);
}
/* ---------------------------------------------------------------------------
* fun_translate: Takes a string and a second argument. If the second argument
* is 0 or s, control characters are converted to spaces. If it's 1 or p,
* they're converted to percent substitutions.
*/
void fun_translate(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs)
{
int type = 0;
if (fargs[0] && fargs[1]) {
if (*fargs[1] && ((*fargs[1] == 's') || (*fargs[1] == '0')))
type = 0;
else if (*fargs[1] && ((*fargs[1] == 'p') || (*fargs[1] == '1')))
type = 1;
safe_str(translate_string(fargs[0], type), buff, bufc);
}
}
/*
* ---------------------------------------------------------------------------
* fun_setlock: Set lock from a function (like @lock)
*/
extern NAMETAB lock_sw;
void fun_setlock(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs) {
int switchkey = 0;
dbref thing, aowner;
int atr, aflags;
ATTR *ap;
struct boolexp *okey;
if (*fargs[0]) {
switchkey = search_nametab(player, &lock_sw, fargs[0]);
if (switchkey < 0) {
safe_str("#-1 SWITCH ERROR", buff, bufc);
return;
}
}
if (parse_attrib(player, fargs[1], &thing, &atr)) {
if (atr != NOTHING) {
if (!atr_get_info(thing, atr, &aowner, &aflags)) {
safe_str("#-1 ATTR NOT FOUND", buff, bufc);
return;
}
ap = atr_num(atr);
/*
* You may lock an attribute iff: you could write the
* attribute if it were stored on yourself --and-- you own
* the attribute or are a wizard as long as you are not #1
* and are trying to do something to #1.
*/
if (ap && (God(player) || (!God(thing) &&
(Set_attr(player, player, ap, 0) && (Wizard(player)
|| aowner == Owner(player)))))) {
if (*fargs[2])
aflags |= AF_LOCK;
else
aflags &= ~AF_LOCK;
atr_set_flags(thing, atr, aflags);
safe_str("1", buff, bufc);
} else {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
}
return;
}
}
init_match(player, fargs[1], NOTYPE);
match_everything(MAT_EXIT_PARENTS);
thing = match_result();
switch (thing) {
case NOTHING:
safe_str("#-1 NOT FOUND", buff, bufc);
return;
case AMBIGUOUS:
safe_str("#-1 AMBIGUOUS MATCH", buff, bufc);
return;
default:
if (!controls(player, thing)) {
safe_str("#-1 PERMISSION DENIED", buff, bufc);
return;
}
}
if (!switchkey)
switchkey = A_LOCK;
if (!*fargs[2]) {
atr_clr(thing, switchkey);
safe_str("1", buff, bufc);
return;
}
okey = parse_boolexp(player, fargs[2], 0);
if (okey == TRUE_BOOLEXP) {
safe_str("#-1 KEY ERROR", buff, bufc);
} else {
/*
* everything ok, do it
*/
atr_add_raw(thing, switchkey, unparse_boolexp_quiet(player, okey));
safe_str("1", buff, bufc);
}
free_boolexp(okey);
}