/* func-alloy.c - function handlers for functions new to AlloyMUSH */
#ifndef lint
static char RCSid[] = "$Id$";
#endif
#include "copyright.h"
#include "autoconf.h"
#include <limits.h>
#include <string.h>
#include <math.h>
#include "externs.h"
#include "flags.h"
#include "attrs.h"
#include "match.h"
#include "command.h"
#include "functions.h"
#include "misc.h"
#include "alloc.h"
#include "powers.h"
#ifdef FLOATING_POINTS
#ifndef linux /* linux defines atof as a macro */
double atof();
#endif /* ! linux */
#define aton atof
typedef double NVAL;
#else
#define aton atoi
typedef int NVAL;
#endif /* FLOATING_POINTS */
UFUN *ufun_head;
extern void FDECL(cf_log_notfound, (dbref player, char *cmd,
const char *thingname, char *thing));
extern void FDECL(make_portlist,
(dbref player, dbref target, char *buff));
/* This is the prototype for functions */
#define FUNCTION(x) \
void x(buff, player, cause, fargs, nfargs, cargs, ncargs) \
char *buff; \
dbref player, cause; \
char *fargs[], *cargs[]; \
int nfargs, ncargs;
/* 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)) \
return; \
if (!delim_check(fargs, nfargs, xnargs, &sep, buff, 0, \
player, cause, cargs, ncargs)) \
return;
#define evarargs_preamble(xname, xnargs) \
if (!fn_range_check(xname, nfargs, xnargs-1, xnargs, buff)) \
return; \
if (!delim_check(fargs, nfargs, xnargs, &sep, buff, 1, \
player, cause, cargs, ncargs)) \
return;
#define mvarargs_preamble(xname,xminargs,xnargs) \
if (!fn_range_check(xname, nfargs, xminargs, xnargs, buff)) \
return; \
if (!delim_check(fargs, nfargs, xnargs, &sep, buff, 0, \
player, cause, cargs, ncargs)) \
return;
/* Trim off leading and trailing spaces if the separator char is a space */
static char *
trim_space_sep(str, sep)
char *str, sep;
{
char *p;
if (sep != ' ')
return str;
while (*str && (*str == ' '))
str++;
for (p = str; *p; p++);
for (p--; *p == ' ' && p > str; p--);
p++;
*p = '\0';
return str;
}
/* next_token: Point at start of next token in string */
static char *
next_token(str, sep)
char *str, sep;
{
while (*str && (*str != sep))
str++;
if (!*str)
return NULL;
str++;
if (sep == ' ') {
while (*str == sep)
str++;
}
return str;
}
/* split_token: Get next token from string as null-term string. String is
* destructively modified.
*/
static char *
split_token(sp, sep)
char **sp, sep;
{
char *str, *save;
save = str = *sp;
if (!str) {
*sp = NULL;
return NULL;
}
while (*str && (*str != sep))
str++;
if (*str) {
*str++ = '\0';
if (sep == ' ') {
while (*str == sep)
str++;
}
} else {
str = NULL;
}
*sp = str;
return save;
}
/* ---------------------------------------------------------------------------
* List management utilities.
*/
#define ALPHANUM_LIST 1
#define NUMERIC_LIST 2
#define DBREF_LIST 3
#define FLOAT_LIST 4
static int
autodetect_list(ptrs, nitems)
char *ptrs[];
int nitems;
{
int sort_type, i;
char *p;
sort_type = NUMERIC_LIST;
for (i = 0; i < nitems; i++) {
switch (sort_type) {
case NUMERIC_LIST:
if (!is_number(ptrs[i])) {
/* If non-numeric, switch to alphanum sort.
* Exception: if this is the first element and
* it is a good dbref, switch to a dbref sort.
* We're a little looser than the normal
* 'good dbref' rules, any number following
* the #-sign is accepted.
*/
if (i == 0) {
p = ptrs[i];
if (*p++ != NUMBER_TOKEN) {
return ALPHANUM_LIST;
} else if (is_integer(p)) {
sort_type = DBREF_LIST;
} else {
return ALPHANUM_LIST;
}
} else {
return ALPHANUM_LIST;
}
} else if (index(ptrs[i], '.')) {
sort_type = FLOAT_LIST;
}
break;
case FLOAT_LIST:
if (!is_number(ptrs[i])) {
sort_type = ALPHANUM_LIST;
return ALPHANUM_LIST;
}
break;
case DBREF_LIST:
p = ptrs[i];
if (*p++ != NUMBER_TOKEN)
return ALPHANUM_LIST;
if (!is_integer(p))
return ALPHANUM_LIST;
break;
default:
return ALPHANUM_LIST;
}
}
return sort_type;
}
static int
get_list_type(fargs, nfargs, type_pos, ptrs, nitems)
char *fargs[], *ptrs[];
int nfargs, nitems, type_pos;
{
if (nfargs >= type_pos) {
switch (ToLower(*fargs[type_pos - 1])) {
case 'd':
return DBREF_LIST;
case 'n':
return NUMERIC_LIST;
case 'f':
return FLOAT_LIST;
case '\0':
return autodetect_list(ptrs, nitems);
default:
return ALPHANUM_LIST;
}
}
return autodetect_list(ptrs, nitems);
}
static int
list2arr(arr, maxlen, list, sep)
char *arr[], *list, sep;
int maxlen;
{
char *p;
int i;
list = trim_space_sep(list, sep);
p = split_token(&list, sep);
for (i = 0; p && i < maxlen; i++, p = split_token(&list, sep)) {
arr[i] = p;
}
return i;
}
static void
arr2list(arr, alen, list, sep)
char *arr[], *list, sep;
int alen;
{
char *p;
int i;
p = list;
for (i = 0; i < alen; i++) {
safe_str(arr[i], list, &p);
safe_chr(sep, list, &p);
}
if (p != list)
p--;
*p = '\0';
}
static int
dbnum(dbr)
char *dbr;
{
if ((strlen(dbr) < 2) && (*dbr != '#'))
return 0;
else
return atoi(dbr + 1);
}
/* ---------------------------------------------------------------------------
* fval: copy the floating point value into a buffer and make it presentable.
* alternatively, if we're not using floating points, then we just
* print the integer.
*/
#ifdef FLOATING_POINTS
static void fval(buff, result)
char *buff;
double result;
{
char *p;
sprintf(buff, "%.6f", result); /* get double val into buffer */
/* remove useless trailing 0's */
if ((p = (char *) rindex(buff, '0')) == NULL)
return;
else if (*(p + 1) == '\0') {
while (*p == '0')
*p-- = '\0';
}
p = (char *) rindex(buff, '.'); /* take care of dangling '.' */
if (*(p + 1) == '\0')
*p = '\0';
}
#else
#define fval(b,n) sprintf(b, "%d", n)
#endif /* FLOATING_POINTS */
/* ---------------------------------------------------------------------------
* fn_range_check: Check # of args to a function with an optional argument
* for validity.
*/
static int
fn_range_check(fname, nfargs, minargs, maxargs, result)
const char *fname;
char *result;
int nfargs, minargs, maxargs;
{
if ((nfargs >= minargs) && (nfargs <= maxargs))
return 1;
if (maxargs == (minargs + 1))
sprintf(result, "#-1 FUNCTION (%s) EXPECTS %d OR %d ARGUMENTS",
fname, minargs, maxargs);
else
sprintf(result,
"#-1 FUNCTION (%s) EXPECTS BETWEEN %d AND %d ARGUMENTS",
fname, minargs, maxargs);
return 0;
}
/* ---------------------------------------------------------------------------
* delim_check: obtain delimiter
*/
static int
delim_check(fargs, nfargs, sep_arg, sep, buff, eval, player, cause,
cargs, ncargs)
char *fargs[], *cargs[], *sep, *buff;
int nfargs, ncargs, sep_arg, eval;
dbref player, cause;
{
char *tstr;
int tlen;
if (nfargs >= sep_arg) {
tlen = strlen(fargs[sep_arg - 1]);
if (tlen <= 1)
eval = 0;
if (eval) {
tstr = exec(player, cause, EV_EVAL | EV_FCHECK,
fargs[sep_arg - 1], cargs, ncargs);
tlen = strlen(tstr);
*sep = *tstr;
free_lbuf(tstr);
}
if (tlen == 0) {
*sep = ' ';
} else if (tlen != 1) {
strcpy(buff,
"#-1 SEPARATOR MUST BE ONE CHARACTER");
return 0;
} else if (!eval) {
*sep = *fargs[sep_arg - 1];
}
} else {
*sep = ' ';
}
return 1;
}
/* fun_chr: return a specified ASCII character
* Defined as CA_WIZARD, so mortals don't go around beeping at people.
* by Alloy [3-10-95]
*/
FUNCTION(fun_chr)
{
int which;
which = atoi(fargs[0]);
if ((which < 0) || (which > 255))
{
strcpy(buff, "#-1 INVALID ASCII CHAR");
return;
}
sprintf(buff, "%c", (char)which);
}
/* ---------------------------------------------------------------------------
* fun_create: Creates a room, thing, zone, or exit
* check_command: needed by fun_create
* Original code by Darkenelf [??], modified by Alloy [3-24-95]
*/
static int check_command(player, name, buff)
dbref player;
char *name, *buff;
{
CMDENT *cmd;
if((cmd = (CMDENT *)hashfind(name, &mudstate.command_htab)))
if(!check_access(player, cmd->perms))
{ strcpy(buff, "#-1 PERMISSION DENIED");
return(1);
}
return(0);
}
FUNCTION(fun_create)
{
dbref thing;
int cost;
char sep, *name;
varargs_preamble("CREATE", 3);
name = fargs[0];
if(!name || !*name)
{ strcpy(buff, "#-1 ILLEGAL NAME");
return;
}
switch(ToLower(sep)) {
case 'r':
if(check_command(player, "@dig", buff)) return;
thing = create_obj(player, TYPE_ROOM, name, 0);
break;
case 'e':
if(check_command(player, "@open", buff)) 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;
case 't':
case ' ':
if(check_command(player, "@create", buff)) return;
cost = atoi(fargs[1]);
if(cost<0)
{ strcpy(buff, "#-1 ILLEGAL COST");
return;
}
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;
case 'z': /* by Alloy */
if (check_command(player, "@mkzone", buff)) return;
cost = mudconf.zonecost;
thing = create_obj(player, TYPE_ZONE, name, cost);
if (thing != NOTHING)
{
move_via_generic(thing, player, NOTHING, 0);
s_Home(thing, new_home(player));
}
break;
default:
strcpy(buff, "#-1 ILLEGAL OBJECT TYPE");
return;
}
if(thing != NOTHING)
{
switch (ToLower(sep))
{
case 'r':
notify_quiet(player, tprintf(
"%s created with room number %d.", name, thing));
break;
case 'e':
notify_quiet(player, "Opened.");
break;
case 't':
case ' ':
case 'z':
notify_quiet(player, tprintf(
"%s created as object #%d", name, thing));
}
}
sprintf(buff, "#%d", thing);
}
/* fun_set: sets an attribute and returns nothing
* set_attr_internal: needed by fun_set
* indiv_attraccess_nametab: needed by fun_set
* by Alloy [3-18-95]
*/
extern NAMETAB indiv_attraccess_nametab[];
static void
set_attr_internal(player, thing, attrnum, attrtext, key)
dbref player, thing;
int attrnum, key;
char *attrtext;
{
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)))
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 {
notify_quiet(player, "Permission denied.");
}
}
FUNCTION(fun_set)
{
dbref thing, thing2, aowner;
char *p, *buff2;
int atr, aflags, clear, flagvalue, could_hear;
ATTR *attr, *attr2;
/* do we have set(obj/attr,atrflag)? */
if (parse_attrib(player, fargs[0], &thing, &atr)) {
if (atr != NOTHING) {
/* must have flag name */
if (!fargs[1] || !*fargs[1]) {
notify_quiet(player,
"I don't know what you want to set!");
strcpy(buff, "#-1");
return;
}
/* check for clearing */
clear = 0;
if (*fargs[1] == NOT_TOKEN) {
fargs[1]++;
clear = 1;
}
/* make sure player specified a valid attr flag */
flagvalue = search_nametab(player,
indiv_attraccess_nametab, fargs[1]);
if (flagvalue == -1) {
notify_quiet(player, "You can't set that!");
strcpy(buff, "#-1");
return;
}
/* make sure the attribute is actually there */
if (!atr_get_info(thing, atr, &aowner, &aflags)) {
notify_quiet(player,
"Attribute not present on object.");
strcpy(buff, "#-1");
return;
}
/* can we write to the attr? */
attr = atr_num(atr);
if (!attr || !Set_attr(player, thing, attr, aflags)) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1");
return;
}
/* do it! */
if (clear)
aflags &= ~flagvalue;
else
aflags |= flagvalue;
could_hear = Hearer(thing);
atr_set_flags(thing, atr, aflags);
/* tell the player */
handle_ears(thing, could_hear, Hearer(thing));
if (!Quiet(player) && !Quiet(thing)) {
if (clear)
notify_quiet(player, "Cleared.");
else
notify_quiet(player, "Set.");
}
buff[0] = '\0';
return;
}
}
/* find thing */
if ((thing = match_controlled(player, fargs[0])) == NOTHING) {
strcpy(buff, "#-1");
return;
}
/* check for attribute set first */
for (p = fargs[1]; *p && (*p != ':'); p++);
if (*p) {
*p++ = 0;
atr = mkattr(fargs[1]);
if (atr <= 0) {
notify_quiet(player, "Couldn't create attribute.");
strcpy(buff, "#-1");
return;
}
attr = atr_num(atr);
if (!attr) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1");
return;
}
atr_get_info(thing, atr, &aowner, &aflags);
if (!Set_attr(player, thing, attr, aflags)) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1");
return;
}
buff2 = alloc_lbuf("fun_set");
/* check for _ */
if (*p == '_') {
strcpy(buff2, p + 1);
if (!parse_attrib(player, p + 1, &thing2, &atr) ||
(atr == NOTHING)) {
notify_quiet(player, "No match.");
strcpy(buff, "#-1");
free_lbuf(buff2);
return;
}
attr2 = atr_num(atr);
p = buff2;
atr_pget_str(buff2, thing2, atr, &aowner, &aflags);
if (!attr2 ||
!See_attr(player, thing2, attr2, aowner, aflags)) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1");
free_lbuf(buff2);
return;
}
}
/* do it! */
set_attr_internal(player, thing, attr->number, p, 0);
free_lbuf(buff2);
buff[0] = '\0';
return;
}
/* set or clear a flag */
flag_set(thing, player, fargs[1], 0);
buff[0] = '\0';
}
/* fun_ansi: do ansi color
* fun_stripansi: take out nasty ansi codes for !ansi players
* stolen from Penn by Alloy [3-20-95, 3-26-95]
*/
FUNCTION(fun_ansi)
{
char *bp;
bp = buff;
safe_str(ltrs2ansi(fargs[0]), buff, &bp);
safe_str(fargs[1], buff, &bp);
safe_str(ANSI_NORMAL, buff, &bp);
*bp = '\0';
}
FUNCTION(fun_stripansi)
{
char *buf = alloc_lbuf("fun_stripansi");
char *p = (char *) fargs[0];
char *q = buf;
while (p && *p) {
if (*p == ESC_CHAR) {
/* Start of ANSI code. Skip to end. */
while (*p && !isalpha(*p))
p++;
if (*p)
p++;
} else
*q++ = *p++;
}
*q = '\0';
strcpy(buff, buf);
free_lbuf(buf);
}
/* fun_zone: what is the zone of this thing? -or- @zone thing=zone
* by Alloy [3-20-95]
*/
FUNCTION(fun_zone)
{
char *atr;
dbref curr, it, zone;
int lev;
it = match_thing(player, fargs[0]);
if (nfargs < 2) {
if (Good_obj(it) && (Examinable(player, it) || (it == cause))) {
sprintf(buff, "#%d", Zone(it));
} else {
strcpy(buff, "#-1");
}
return;
}
if (!controls(player, it)) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1 PERMISSION DENIED");
return;
}
if (*fargs[1]) {
init_match(player, fargs[1], TYPE_ZONE);
match_everything(0);
zone = noisy_match_result();
if (zone == NOTHING) {
strcpy(buff, "#-1 NO MATCH");
return;
}
if (!isZone(zone)) {
strcpy(buff, "#-1 NOT A ZONE");
return;
}
if (!Controls(player, zone)) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1 PERMISSION DENIED");
return;
}
ITER_ZONES(zone, curr, lev) {
if (curr == it) {
notify_quiet(player, "Recursive zoning could cause problems.");
strcpy(buff, "#-1 RECURSIVE ZONE");
return;
}
}
if (atoi(atr_get_raw(zone, A_QUOTA)) != 0) {
atr = atr_get_raw(zone, A_RQUOTA);
lev = atoi(atr);
if ((lev < 1) &&
!(Wizard(player) || Has_power(player, POW_FREE_QUOTA) ||
Has_power(it, POW_FREE_QUOTA))) {
strcpy(buff, "#-1 ZONE FULL");
return;
}
atr_add_raw(zone, A_RQUOTA, tprintf("%d", --lev));
}
} else {
if (Good_obj(Zone(it))) {
atr = atr_get_raw(Zone(it), A_QUOTA);
if (atoi(atr) != 0) {
atr = atr_get_raw(Zone(it), A_RQUOTA);
lev = atoi(atr);
atr_add_raw(Zone(it), A_RQUOTA, tprintf("%d", ++lev));
}
}
zone = NOTHING;
}
s_Zone(it, zone);
if (!Quiet(it) && !Quiet(player)) {
if (zone == NOTHING)
notify_quiet(player, "Zone cleared.");
else
notify_quiet(player, "Zone set.");
}
*buff = '\0';
}
/* fun_trigger: trigger an attribute
* by Alloy [3-21-95]
*/
FUNCTION(fun_trigger)
{
dbref thing;
int attrib;
if (!parse_attrib(player, fargs[0], &thing, &attrib) || (attrib == NOTHING)) {
notify_quiet(player, "No match.");
return;
}
if (!controls(player, thing)) {
notify_quiet(player, "Permission denied.");
return;
}
did_it(player, thing, 0, NULL, 0, NULL, attrib, &(fargs[1]), nfargs - 1);
if (!Quiet(player))
notify_quiet(player, "Triggered.");
buff[0] = '\0';
}
/* fun_tport: teleport an object
* by Alloy [3-21-95]
*/
FUNCTION(fun_tport)
{
dbref victim, destination, loc;
char *to;
if (*fargs[1] == '\0') {
victim = player;
to = fargs[0];
} else {
init_match(player, fargs[0], NOTYPE);
match_everything(MAT_NO_EXITS);
victim = noisy_match_result();
if (victim == NOTHING) {
strcpy(buff, "#-1");
return;
}
to = fargs[1];
}
if (!Has_location(victim)) {
notify_quiet(player, "You can't teleport that.");
strcpy(buff, "#-1");
return;
}
if (!Controls(player, victim) && !Controls(player, Location(victim))) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1");
return;
}
if (!string_compare(to, "home")) {
(void) move_via_teleport(victim, HOME, cause, 0);
buff[0] = '\0';
return;
}
init_match(player, to, NOTYPE);
match_everything(0);
destination = match_result();
switch (destination) {
case NOTHING:
notify_quiet(player, "No match.");
strcpy(buff, "#-1");
return;
case AMBIGUOUS:
notify_quiet(player,
"I don't know which destination you mean!");
strcpy(buff, "#-1");
return;
default:
if (victim == destination) {
notify_quiet(player, "Bad destination.");
strcpy(buff, "#-1");
return;
}
}
if (mudconf.fascist_tport) {
loc = where_room(victim);
if (!Good_obj(loc) || !isRoom(loc) ||
(!Controls(player, loc) && !Jump_ok(loc))) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1");
return;
}
}
if (Has_contents(destination)) {
if (!Controls(player, destination) &&
(!Jump_ok(destination) || !could_doit(victim, destination, A_LTPORT))) {
if (player != victim)
notify_quiet(player, "Permission denied.");
did_it(victim, destination,
A_TFAIL, "You can't teleport there!",
A_OTFAIL, 0, A_ATFAIL, (char **) NULL, 0);
strcpy(buff, "#-1");
return;
}
if (move_via_teleport(victim, destination, cause, 0)) {
if (player != victim) {
if (!Quiet(player))
notify_quiet(player, "Teleported.");
}
}
} else if (isExit(destination)) {
if (Exits(destination) == Location(victim)) {
move_exit(victim, destination, 0, "You can't go that way.", 0);
} else {
notify_quiet(player, "I can't find that exit.");
}
}
buff[0] = '\0';
}
/* fun_link: link an object
* link_exit, parse_linkable_room: needed by fun_link
* by Alloy [3-21-95]
*/
static dbref
parse_linkable_room(player, room_name)
dbref player;
char *room_name;
{
dbref room;
init_match(player, room_name, NOTYPE);
match_everything(MAT_NO_EXITS | MAT_NUMERIC | MAT_HOME | MAT_VAR);
room = match_result();
/* HOME is always linkable */
if (room == HOME)
return HOME;
else if (room == VARIABLE)
return VARIABLE;
/* Make sure we can link to it */
if (!Good_obj(room)) {
notify_quiet(player, "That's not a valid object.");
return NOTHING;
} else if (!Has_contents(room) || !Linkable(player, room)) {
notify_quiet(player, "You can't link to that.");
return NOTHING;
} else {
return room;
}
}
static void
link_exit(player, exit, dest)
dbref player, exit, dest;
{
int cost, quot;
if ((dest != HOME) && (dest != VARIABLE) &&
((!controls(player, dest) && !Link_ok(dest)) ||
(!could_doit(player, dest, A_LLINK) &&
(!Wizard(player) || mudconf.wiz_obey_linklock)))) {
notify_quiet(player, "Permission denied.");
return;
}
if ((Location(exit) != NOTHING) && !controls(player, exit)) {
notify_quiet(player, "Permission denied.");
return;
}
cost = mudconf.linkcost;
quot = 0;
if (Owner(exit) != Owner(player)) {
cost += mudconf.opencost;
quot += mudconf.exit_quota;
}
if (!canpayfees(player, player, cost, quot, TYPE_EXIT))
return;
else
payfees(player, cost, quot, TYPE_EXIT);
if (Owner(exit) != Owner(player)) {
payfees(Owner(exit), -mudconf.opencost, -quot, TYPE_EXIT);
s_Owner(exit, Owner(player));
s_Flags(exit, (Flags(exit) & ~(INHERIT | WIZARD)) | HALT);
}
s_Location(exit, dest);
if (!Quiet(player));
notify_quiet(player, "Linked.");
}
FUNCTION(fun_link)
{
dbref thing, room;
char *buff2;
init_match(player, fargs[0], TYPE_EXIT);
match_everything(0);
thing = noisy_match_result();
if (thing == NOTHING) {
strcpy(buff, "#-1");
return;
}
if (!fargs[1] || !*fargs[1]) {
do_unlink(player, cause, 0, fargs[0]);
buff[0] = '\0';
return;
}
switch (Typeof(thing)) {
case TYPE_EXIT:
room = parse_linkable_room(player, fargs[1]);
if (room != NOTHING)
link_exit(player, thing, room);
buff[0] = '\0';
break;
case TYPE_PLAYER:
case TYPE_THING:
if (!Controls(player, thing)) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1");
break;
}
init_match(player, fargs[1], NOTYPE);
match_everything(MAT_NO_EXITS);
room = noisy_match_result();
if (!Good_obj(room)) {
strcpy(buff, "#-1");
break;
}
if (!Has_contents(room)) {
notify_quiet(player, "Can't link to an exit.");
strcpy(buff, "#-1");
break;
}
if (!can_set_home(player, thing, room) ||
(!could_doit(player, room, A_LLINK) &&
(!Wizard(player) || mudconf.wiz_obey_linklock))) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1");
} else if (room == HOME) {
notify_quiet(player, "Can't set home to home.");
strcpy(buff, "#-1");
} else {
s_Home(thing, room);
if (!Quiet(player))
notify_quiet(player, "Home set.");
buff[0] = '\0';
}
break;
case TYPE_ROOM:
if (!Controls(player, thing)) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1");
break;
}
room = parse_linkable_room(player, fargs[1]);
if (!(Good_obj(room) || (room == HOME))) {
strcpy(buff, "#-1");
break;
}
if ((room != HOME) && !isRoom(room)) {
notify_quiet(player, "That is not a room!");
strcpy(buff, "#-1");
} else if ((room != HOME) &&
((!controls(player, room) && !Link_ok(room)) ||
(!could_doit(player, room, A_LLINK) &&
(!Wizard(player) || mudconf.wiz_obey_linklock)))) {
notify_quiet(player, "Permission denied.");
strcpy(buff, "#-1");
} else {
s_Dropto(thing, room);
if (!Quiet(player))
notify_quiet(player, "Dropto set.");
buff[0] = '\0';
}
break;
case TYPE_ZONE:
notify_quiet(player, "Why bother?");
break;
default:
STARTLOG(LOG_BUGS, "BUG", "OTYPE");
buff2 = alloc_mbuf("fun_link.LOG.badtype");
sprintf(buff2, "Strange object type: object #%d = %d", thing,
Typeof(thing));
log_text(buff2);
free_mbuf(buff);
ENDLOG
}
}
/* fun_powers: what powers does this have?
* by Alloy [4-26-95]
*/
FUNCTION(fun_powers)
{
dbref it;
char *tmp, *p;
it = match_thing(player, fargs[0]);
if (!Good_obj(it)) {
sprintf(buff, "#-1 BAD OBJECT");
return;
}
if (!Examinable(player, it)) {
sprintf(buff, "#-1 PERMISSION DENIED");
return;
}
if (Powers(it) == 0) {
buff[0] = '\0';
return;
}
tmp = (char *) unparse_powers(Powers(it));
strcpy(buff, tmp);
free_lbuf(tmp);
}
/* fun_column: arrange stuff into a neat table, assuming that the user's screen
* is 76 chars wide.
* by Alloy [4-28-95]
* fixed [11-10-95]
*/
FUNCTION(fun_column)
{
int width, spaces, num, i;
float kar;
int count = 0;
char *r, *s, *bp, sep;
varargs_preamble("COLUMN", 3);
if (atoi(fargs[1]) < 1) {
strcpy(buff, "#-1 INVALID COLUMN NUMBER");
return;
}
num = atoi(fargs[1]);
bp = buff;
kar = 77 / atoi(fargs[1]);
width = (int) kar - 0.5; /* strip off the fraction part */
s = trim_space_sep(fargs[0], sep);
while (s) {
r = split_token(&s, sep);
if (count == num) {
safe_str((char *) "\r\n", buff, &bp);
count = 0;
}
spaces = width - strlen(r);
if (spaces == 0)
safe_str(r, buff, &bp);
else if (spaces < 0)
for (i = 0; *r && i < width; r++, i++)
safe_chr(*r, buff, &bp);
else {
safe_str(r, buff, &bp);
for (i = 0; i < spaces; i++)
safe_chr(' ', buff, &bp);
}
count++;
}
}
/* fun_elist: turns "foo bar baz spool" into "foo, bar, baz, and spool"
* by Alloy [5-19-95]
* evil bug (elist with no args crashes the server) fixed [11-10-95]
*/
FUNCTION(fun_elist)
{
int count, i;
char *bp, *items[LBUF_SIZE / 2], sep, *word;
if (nfargs == 0) {
strcpy(buff, "nothing");
return;
}
if (!*fargs[0]) {
buff[0] = '\0';
return;
}
word = alloc_sbuf("fun_elist");
if (nfargs < 3)
sep = ' ';
else
sep = *fargs[2];
bp = word;
if (nfargs < 2)
strcpy(word, "and");
else
safe_sb_str(fargs[1], word, &bp);
bp = buff;
count = list2arr(items, LBUF_SIZE / 2, fargs[0], sep);
switch (count) {
case 0: buff[0] = '\0'; break;
case 1: strcpy(buff, items[0]); break;
case 2:
safe_str(tprintf("%s %s %s", items[0], word, items[1]), buff, &bp);
break;
default:
for (i = 0; i < count; i++) {
if (i == count - 1)
safe_str(tprintf("%s %s", word, items[i]), buff, &bp);
else
safe_str(tprintf("%s, ", items[i]), buff, &bp);
}
}
free_sbuf(word);
}
/* fun_wrap: wraps some text so that lines are n chars long. if a sep is
* specified, it is inserted every n chars instead of a newline
*/
FUNCTION(fun_wrap)
{
char *bp, sep, *p;
int i, sepped, wrapat;
varargs_preamble("WRAP", 3);
wrapat = atoi(fargs[1]);
bp = buff;
i = 0;
for (p = fargs[0]; *p; p++) {
safe_chr(*p, buff, &bp);
i++;
if (*p == '\r') {
safe_chr(*(++p), buff, &bp);
i = 0;
}
if ((i != 0) && !(i % wrapat)) {
sepped = 1;
if (sep == ' ')
safe_str("\r\n", buff, &bp);
else
safe_chr(sep, buff, &bp);
}
else
sepped = 0;
}
if (sepped)
buff[strlen(buff) - ((sep == ' ') ? 2 : 1)] = '\0';
}
/* fun_id: turn an object match into something like Wizard(#1PWc)
* by Alloy [10-18-95]
*/
FUNCTION(fun_id)
{
char *s;
dbref it;
it = match_thing(player, fargs[0]);
if (it == NOTHING) {
buff[0] = '\0';
return;
}
if (!mudconf.read_rem_name ||
!(mudconf.pub_flags || Examinable(player, it) || (it == cause)))
if (!nearby_or_control(player, it) && !isPlayer(it)) {
strcpy(buff, "#-1 TOO FAR AWAY TO SEE");
return;
}
strcpy(buff, s = unparse_object(player, it, 0));
free_lbuf(s);
}
/* fun_art: return the article that should go with a certain noun
* by Alloy [10-21-95]
*/
FUNCTION(fun_art)
{
char c, *p;
p = fargs[0];
c = ToLower(*p);
if (index("aeiou",c))
strcpy(buff, "an");
else
strcpy(buff, "a");
}
/* fun_setqmatch: like strmatch, but put the matches into the setq registers
* by Alloy [11-19-95]
*/
FUNCTION(fun_setqmatch)
{
char *args[MAX_GLOBAL_REGS];
int i;
if (wild_match(fargs[1], fargs[0], args, MAX_GLOBAL_REGS, 0)) {
for (i = 0; i < MAX_GLOBAL_REGS; i++) {
if (args[i]) {
if (!mudstate.global_regs[i])
mudstate.global_regs[i] = alloc_lbuf("fun_setqmatch");
strcpy(mudstate.global_regs[i], args[i]);
free_lbuf(args[i]);
} else break;
}
strcpy(buff, "1");
} else {
strcpy(buff, "0");
}
}
/* fun_listmatch: like setqmatch, but return a list rather than putting the
* matches into the setq registers
* by Alloy [11-19-95]
*/
FUNCTION(fun_listmatch)
{
char *args[MAX_GLOBAL_REGS], *bp, sep;
int i;
varargs_preamble("LISTMATCH", 3);
bp = buff;
if (wild_match(fargs[1], fargs[0], args, MAX_GLOBAL_REGS, 0)) {
*buff = '\0'; /* so we get a blank if no wildcards */
for (i = 0; i < MAX_GLOBAL_REGS; i++) {
if (args[i]) {
if (bp != buff) safe_chr(sep, buff, &bp);
safe_str(args[i], buff, &bp);
free_lbuf(args[i]);
} else {
/* we've hit the last match, so stop */
break;
}
}
} else {
*buff = '\0';
}
}
/* fun_baseconv: convert a number from base A to base B.
* by Alloy [11-20-95]
*/
FUNCTION(fun_baseconv)
{
char c, *p, *tmp;
int factor;
int decnum, old, new, this, i;
if (!(fargs[0]) || !*(fargs[0])) {
strcpy(buff, "0");
return;
}
old = atoi(fargs[1]);
new = atoi(fargs[2]);
if ((old < 2) || (old > 36) || (new < 2) || (new > 36)) {
strcpy(buff, "#-1 INVALID BASE");
return;
}
/* convert input to a decimal number */
this = strlen(fargs[0]) - 1;
factor = 1;
for (i = 0; i < this; i++) {
factor *= old;
}
decnum = 0;
for (p = fargs[0]; *p; p++) {
*p = ToLower(*p);
if (isdigit(*p)) {
this = *p - '0';
} else if ((*p >= 'a') && (*p <= 'z') &&
((*p - 'a' + 10) < old)) {
this = *p - 'a' + 10;
} else {
strcpy(buff, "#-1 INVALID DIGIT");
return;
}
decnum += this * factor;
factor /= old;
}
/* convert decimal number to new base */
if (new == 10) {
/* cheat */
sprintf(buff, "%d", decnum);
} else {
tmp = alloc_mbuf("fun_baseconv");
*buff = '\0';
do {
this = decnum % new;
decnum /= new;
if (this <= 9)
c = this + '0';
else
c = this - 10 + 'A';
*tmp = c;
strcpy(tmp + 1, buff);
strcpy(buff, tmp);
} while (decnum);
free_mbuf(tmp);
}
}