/* funmisc.c - misc functions */
/* $Id: funmisc.c,v 1.39 2004/02/23 04:35:14 rmg Exp $ */
#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "alloc.h" /* required by mudconf */
#include "flags.h" /* required by mudconf */
#include "htab.h" /* required by mudconf */
#include "mudconf.h" /* required by code */
#include "db.h" /* required by externs */
#include "externs.h" /* required by code */
#include "functions.h" /* required by code */
#include "attrs.h" /* required by code */
#include "powers.h" /* required by code */
#include "command.h" /* required by code */
#include "match.h" /* required by code */
extern NAMETAB indiv_attraccess_nametab[];
extern void FDECL(do_pemit_list, (dbref, char *, const char *, int));
extern void FDECL(do_pemit, (dbref, dbref, int, char *, char *));
extern void FDECL(set_attr_internal, (dbref, dbref, int, char *, int,
char *, char **));
/* ---------------------------------------------------------------------------
* fun_switch: Return value based on pattern matching (ala @switch/first)
* fun_switchall: Similar, but ala @switch/all
* fun_case: Like switch(), but a straight exact match instead of wildcard.
* NOTE: These functions expect that their arguments have not been evaluated.
*/
FUNCTION(fun_switchall)
{
int i, got_one;
char *mbuff, *tbuff, *bp, *str, *save_token;
/* If we don't have at least 2 args, return nothing */
if (nfargs < 2) {
return;
}
/* Evaluate the target in fargs[0] */
mbuff = bp = alloc_lbuf("fun_switchall");
str = fargs[0];
exec(mbuff, &bp, player, caller, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
&str, cargs, ncargs);
/* Loop through the patterns looking for a match */
mudstate.in_switch++;
save_token = mudstate.switch_token;
got_one = 0;
for (i = 1; (i < nfargs - 1) && fargs[i] && fargs[i + 1]; i += 2) {
tbuff = bp = alloc_lbuf("fun_switchall.2");
str = fargs[i];
exec(tbuff, &bp, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
if (quick_wild(tbuff, mbuff)) {
got_one = 1;
free_lbuf(tbuff);
mudstate.switch_token = mbuff;
str = fargs[i+1];
exec(buff, bufc, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
} else {
free_lbuf(tbuff);
}
}
/* If we didn't match, return the default if there is one */
if (!got_one && (i < nfargs) && fargs[i]) {
mudstate.switch_token = mbuff;
str = fargs[i];
exec(buff, bufc, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
}
free_lbuf(mbuff);
mudstate.in_switch--;
mudstate.switch_token = save_token;
}
FUNCTION(fun_switch)
{
int i;
char *mbuff, *tbuff, *bp, *str, *save_token;
/* If we don't have at least 2 args, return nothing */
if (nfargs < 2) {
return;
}
/* Evaluate the target in fargs[0] */
mbuff = bp = alloc_lbuf("fun_switch");
str = fargs[0];
exec(mbuff, &bp, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
/* Loop through the patterns looking for a match */
mudstate.in_switch++;
save_token = mudstate.switch_token;
for (i = 1; (i < nfargs - 1) && fargs[i] && fargs[i + 1]; i += 2) {
tbuff = bp = alloc_lbuf("fun_switch.2");
str = fargs[i];
exec(tbuff, &bp, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL,
&str, cargs, ncargs);
if (quick_wild(tbuff, mbuff)) {
free_lbuf(tbuff);
mudstate.switch_token = mbuff;
str = fargs[i+1];
exec(buff, bufc, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL,
&str, cargs, ncargs);
free_lbuf(mbuff);
mudstate.in_switch--;
mudstate.switch_token = save_token;
return;
}
free_lbuf(tbuff);
}
/* Nope, return the default if there is one */
if ((i < nfargs) && fargs[i]) {
mudstate.switch_token = mbuff;
str = fargs[i];
exec(buff, bufc, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL,
&str, cargs, ncargs);
}
free_lbuf(mbuff);
mudstate.in_switch--;
mudstate.switch_token = save_token;
}
FUNCTION(fun_case)
{
int i;
char *mbuff, *tbuff, *bp, *str;
/* If we don't have at least 2 args, return nothing */
if (nfargs < 2) {
return;
}
/* Evaluate the target in fargs[0] */
mbuff = bp = alloc_lbuf("fun_case");
str = fargs[0];
exec(mbuff, &bp, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
/* Loop through the patterns looking for an exact match */
for (i = 1; (i < nfargs - 1) && fargs[i] && fargs[i + 1]; i += 2) {
tbuff = bp = alloc_lbuf("fun_case.2");
str = fargs[i];
exec(tbuff, &bp, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL,
&str, cargs, ncargs);
if (!strcmp(tbuff, mbuff)) {
free_lbuf(tbuff);
str = fargs[i + 1];
exec(buff, bufc, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
free_lbuf(mbuff);
return;
}
free_lbuf(tbuff);
}
free_lbuf(mbuff);
/* Nope, return the default if there is one */
if ((i < nfargs) && fargs[i]) {
str = fargs[i];
exec(buff, bufc, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
}
return;
}
FUNCTION(fun_ifelse)
{
/* This function now assumes that its arguments have not been
evaluated. */
char *str, *mbuff, *bp;
VaChk_Range(2, 3);
mbuff = bp = alloc_lbuf("fun_ifelse");
str = fargs[0];
exec(mbuff, &bp, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
if (!mbuff || !*mbuff || !xlate(mbuff)) {
if (nfargs != 3) {
free_lbuf(mbuff);
return;
}
str = fargs[2];
exec(buff, bufc, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
} else {
str = fargs[1];
exec(buff, bufc, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
}
free_lbuf(mbuff);
}
FUNCTION(fun_nonzero)
{
/* MUX-style ifelse -- rather than bool check, check if the
* string is non-null/non-zero.
*/
char *str, *mbuff, *bp;
VaChk_Range(2, 3);
mbuff = bp = alloc_lbuf("fun_nonzero");
str = fargs[0];
exec(mbuff, &bp, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
if (!mbuff || !*mbuff || ((atoi(mbuff) == 0) && is_number(mbuff))) {
if (nfargs != 3) {
free_lbuf(mbuff);
return;
}
str = fargs[2];
exec(buff, bufc, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
} else {
str = fargs[1];
exec(buff, bufc, player, caller, cause,
EV_STRIP | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
}
free_lbuf(mbuff);
}
/* ---------------------------------------------------------------------------
* fun_rand: Return a random number from 0 to arg1-1
*/
FUNCTION(fun_rand)
{
int num;
num = atoi(fargs[0]);
if (num < 1) {
safe_chr('0', buff, bufc);
} else {
safe_tprintf_str(buff, bufc, "%ld", Randomize(num));
}
}
/* ---------------------------------------------------------------------------
* die(<number of dice>,<sides>): Roll XdY dice.
* lrand(<range bottom>,<range top>,<times>[,<delim>]): Generate random list.
*/
FUNCTION(fun_die)
{
int n, die, count;
int total = 0;
if (!fargs[0] || !fargs[1]) {
safe_chr('0', buff, bufc);
return;
}
n = atoi(fargs[0]);
die = atoi(fargs[1]);
if ((n == 0) || (die <= 0)) {
safe_chr('0', buff, bufc);
return;
}
if ((n < 1) || (n > 100)) {
safe_str("#-1 NUMBER OUT OF RANGE", buff, bufc);
return;
}
for (count = 0; count < n; count++)
total += (int) random_range(1, die);
safe_ltos(buff, bufc, total);
}
FUNCTION(fun_lrand)
{
Delim osep;
int n_times, r_bot, r_top, i;
double n_range;
unsigned int tmp;
char *bb_p;
/* Special: the delim is really an output delim. */
VaChk_Only_Out(4);
/* If we're generating no numbers, since this is a list function,
* we return empty, rather than returning 0.
*/
n_times = atoi(fargs[2]);
if (n_times < 1) {
return;
}
if (n_times > LBUF_SIZE) {
n_times = LBUF_SIZE;
}
r_bot = atoi(fargs[0]);
r_top = atoi(fargs[1]);
if (r_top < r_bot) {
/* This is an error condition. Just return an empty list. We
* obviously can't return a random number between X and Y if
* Y is less than X.
*/
return;
} else if (r_bot == r_top) {
/* Just generate a list of n repetitions. */
bb_p = *bufc;
for (i = 0; i < n_times; i++) {
if (*bufc != bb_p) {
print_sep(&osep, buff, bufc);
}
safe_ltos(buff, bufc, r_bot);
}
return;
}
/* We've hit this point, we have a range. Generate a list. */
n_range = (double) r_top - r_bot + 1;
bb_p = *bufc;
for (i = 0; i < n_times; i++) {
if (*bufc != bb_p) {
print_sep(&osep, buff, bufc);
}
tmp = (unsigned int) Randomize(n_range);
safe_ltos(buff, bufc, r_bot + tmp);
}
}
/* ---------------------------------------------------------------------------
* fun_lnum: Return a list of numbers.
*/
#define Lnum_Place(x) (((x) < 10) ? (2*(x)) : ((3*(x))-10))
FUNCTION(fun_lnum)
{
char tbuf[12];
Delim osep;
int bot, top, over, i;
char *bb_p, *startp, *endp;
static int lnum_init = 0;
static char lnum_buff[290];
if (nfargs == 0) {
return;
}
/* lnum() is special, since its single delimiter is really an output
* delimiter.
*/
VaChk_Out(1, 3);
if (nfargs >= 2) {
bot = atoi(fargs[0]);
top = atoi(fargs[1]);
} else {
bot = 0;
top = atoi(fargs[0]);
if (top-- < 1) /* still want to generate if arg is 1 */
return;
}
/* We keep 0-100 pre-generated so we can do quick copies. */
if (!lnum_init) {
strcpy(lnum_buff,
(char *) "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99");
lnum_init = 1;
}
/* If it's an ascending sequence crossing from negative numbers into
* positive, get the negative numbers out of the way first.
*/
bb_p = *bufc;
over = 0;
if ((bot < 0) && (top >= 0) && (osep.len == 1) && (osep.str[0] == ' ')) {
while ((bot < 0) && !over) {
if (*bufc != bb_p) {
print_sep(&osep, buff, bufc);
}
ltos(tbuf, bot);
over = safe_str_fn(tbuf, buff, bufc);
bot++;
}
if (over)
return;
}
/* Copy as much out of the pre-gen as we can. */
if ((bot >= 0) && (bot < 100) && (top > bot) &&
(osep.len == 1) && (osep.str[0] == ' ')) {
if (*bufc != bb_p) {
print_sep(&osep, buff, bufc);
}
startp = lnum_buff + Lnum_Place(bot);
if (top >= 99) {
safe_str(startp, buff, bufc);
} else {
endp = lnum_buff + Lnum_Place(top+1) - 1;
*endp = '\0';
safe_str(startp, buff, bufc);
*endp = ' ';
}
if (top < 100)
return;
else
bot = 100;
}
/* Print a new list. */
if (top == bot) {
if (*bufc != bb_p) {
print_sep(&osep, buff, bufc);
}
safe_ltos(buff, bufc, bot);
return;
} else if (top > bot) {
for (i = bot; (i <= top) && !over; i++) {
if (*bufc != bb_p) {
print_sep(&osep, buff, bufc);
}
ltos(tbuf, i);
over = safe_str_fn(tbuf, buff, bufc);
}
} else {
for (i = bot; (i >= top) && !over; i--) {
if (*bufc != bb_p) {
print_sep(&osep, buff, bufc);
}
ltos(tbuf, i);
over = safe_str_fn(tbuf, buff, bufc);
}
}
}
/* ---------------------------------------------------------------------------
* fun_time: Returns nicely-formatted time.
*/
FUNCTION(fun_time)
{
char *temp;
temp = (char *)ctime(&mudstate.now);
temp[strlen(temp) - 1] = '\0';
safe_str(temp, buff, bufc);
}
/* ---------------------------------------------------------------------------
* fun_time: Seconds since 0:00 1/1/70
*/
FUNCTION(fun_secs)
{
safe_ltos(buff, bufc, mudstate.now);
}
/* ---------------------------------------------------------------------------
* fun_convsecs: converts seconds to time string, based off 0:00 1/1/70
*/
FUNCTION(fun_convsecs)
{
char *temp;
time_t tt;
tt = atol(fargs[0]);
temp = (char *)ctime(&tt);
temp[strlen(temp) - 1] = '\0';
safe_str(temp, buff, bufc);
}
/* ---------------------------------------------------------------------------
* fun_convtime: converts time string to seconds, based off 0:00 1/1/70
* additional auxiliary function and table used to parse time string,
* since no ANSI standard function are available to do this.
*/
static const char *monthtab[] =
{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
static const char daystab[] =
{31, 29, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
/* converts time string to a struct tm. Returns 1 on success, 0 on fail.
* Time string format is always 24 characters long, in format
* Ddd Mmm DD HH:MM:SS YYYY
*/
#define get_substr(buf, p) { \
p = strchr(buf, ' '); \
if (p) { \
*p++ = '\0'; \
while (*p == ' ') p++; \
} \
}
int do_convtime(str, ttm)
char *str;
struct tm *ttm;
{
char *buf, *p, *q;
int i;
if (!str || !ttm)
return 0;
while (*str == ' ')
str++;
buf = p = alloc_sbuf("do_convtime"); /* make a temp copy of arg */
safe_sb_str(str, buf, &p);
*p = '\0';
get_substr(buf, p); /* day-of-week or month */
if (!p || strlen(buf) != 3) {
free_sbuf(buf);
return 0;
}
for (i = 0; (i < 12) && string_compare(monthtab[i], p); i++) ;
if (i == 12) {
get_substr(p, q); /* month */
if (!q || strlen(p) != 3) {
free_sbuf(buf);
return 0;
}
for (i = 0; (i < 12) && string_compare(monthtab[i], p); i++) ;
if (i == 12) {
free_sbuf(buf);
return 0;
}
p = q;
}
ttm->tm_mon = i;
get_substr(p, q); /* day of month */
if (!q || (ttm->tm_mday = atoi(p)) < 1 || ttm->tm_mday > daystab[i]) {
free_sbuf(buf);
return 0;
}
p = strchr(q, ':'); /* hours */
if (!p) {
free_sbuf(buf);
return 0;
}
*p++ = '\0';
if ((ttm->tm_hour = atoi(q)) > 23 || ttm->tm_hour < 0) {
free_sbuf(buf);
return 0;
}
if (ttm->tm_hour == 0) {
while (isspace(*q))
q++;
if (*q != '0') {
free_sbuf(buf);
return 0;
}
}
q = strchr(p, ':'); /* minutes */
if (!q) {
free_sbuf(buf);
return 0;
}
*q++ = '\0';
if ((ttm->tm_min = atoi(p)) > 59 || ttm->tm_min < 0) {
free_sbuf(buf);
return 0;
}
if (ttm->tm_min == 0) {
while (isspace(*p))
p++;
if (*p != '0') {
free_sbuf(buf);
return 0;
}
}
get_substr(q, p); /* seconds */
if (!p || (ttm->tm_sec = atoi(q)) > 59 || ttm->tm_sec < 0) {
free_sbuf(buf);
return 0;
}
if (ttm->tm_sec == 0) {
while (isspace(*q))
q++;
if (*q != '0') {
free_sbuf(buf);
return 0;
}
}
get_substr(p, q); /* year */
if ((ttm->tm_year = atoi(p)) == 0) {
while (isspace(*p))
p++;
if (*p != '0') {
free_sbuf(buf);
return 0;
}
}
free_sbuf(buf);
if (ttm->tm_year > 100)
ttm->tm_year -= 1900;
if (ttm->tm_year < 0) {
return 0;
}
/* We don't whether or not it's daylight savings time. */
ttm->tm_isdst = -1;
#define LEAPYEAR_1900(yr) ((yr)%400==100||((yr)%100!=0&&(yr)%4==0))
return (ttm->tm_mday != 29 || i != 1 || LEAPYEAR_1900(ttm->tm_year));
#undef LEAPYEAR_1900
}
FUNCTION(fun_convtime)
{
struct tm *ttm;
ttm = localtime(&mudstate.now);
if (do_convtime(fargs[0], ttm))
safe_ltos(buff, bufc, timelocal(ttm));
else
safe_known_str("-1", 2, buff, bufc);
}
/* ---------------------------------------------------------------------------
* fun_timefmt: Interface to strftime().
*/
FUNCTION(fun_timefmt)
{
time_t tt;
struct tm *ttm;
char str[LBUF_SIZE], tbuf[LBUF_SIZE], *tp, *p;
int len;
/* Check number of arguments. */
if ((nfargs < 1) || !fargs[0] || !*fargs[0])
return;
if (nfargs == 1) {
tt = mudstate.now;
} else if (nfargs == 2) {
tt = (time_t) atol(fargs[1]);
if (tt < 0) {
safe_str("#-1 INVALID TIME", buff, bufc);
return;
}
} else {
safe_tprintf_str(buff, bufc,
"#-1 FUNCTION (TIMEFMT) EXPECTS 1 OR 2 ARGUMENTS BUT GOT %d",
nfargs);
return;
}
/* Construct the format string. We need to convert instances of '$'
* into percent signs for strftime(), unless we get a '$$', which
* we treat as a literal '$'. Step on '$n' as invalid (output literal
* '%n'), because some strftime()s use it to insert a newline.
*/
for (tp = tbuf, p = fargs[0], len = 0;
*p && (len < LBUF_SIZE - 2);
tp++, p++) {
if (*p == '%') {
*tp++ = '%';
*tp = '%';
} else if (*p == '$') {
if (*(p+1) == '$') {
*tp = '$';
p++;
} else if (*(p+1) == 'n') {
*tp++ = '%';
*tp++ = '%';
*tp = 'n';
p++;
} else {
*tp = '%';
}
} else {
*tp = *p;
}
}
*tp = '\0';
/* Get the time and format it. We do this using the local timezone. */
ttm = localtime(&tt);
strftime(str, LBUF_SIZE - 1, tbuf, ttm);
safe_str(str, buff, bufc);
}
/* ---------------------------------------------------------------------------
* fun_starttime: What time did this system last reboot?
*/
FUNCTION(fun_starttime)
{
char *temp;
temp = (char *)ctime(&mudstate.start_time);
temp[strlen(temp) - 1] = '\0';
safe_str(temp, buff, bufc);
}
/* ---------------------------------------------------------------------------
* fun_restarts: How many times have we restarted?
*/
FUNCTION(fun_restarts)
{
safe_ltos(buff, bufc, mudstate.reboot_nums);
}
/* ---------------------------------------------------------------------------
* fun_restarttime: When did we last restart?
*/
FUNCTION(fun_restarttime)
{
char *temp;
temp = (char *)ctime(&mudstate.restart_time);
temp[strlen(temp) - 1] = '\0';
safe_str(temp, buff, bufc);
}
FUNCTION(fun_version)
{
safe_str(mudstate.version, buff, bufc);
}
/* ---------------------------------------------------------------------------
* fun_mudname: Return the name of the mud.
*/
FUNCTION(fun_mudname)
{
safe_str(mudconf.mud_name, buff, bufc);
}
/* ---------------------------------------------------------------------------
* fun_hasmodule: Return 1 if a module is installed, 0 if it is not.
*/
FUNCTION(fun_hasmodule)
{
MODULE *mp;
WALK_ALL_MODULES(mp) {
if (!strcasecmp(fargs[0], mp->modname)) {
safe_chr('1', buff, bufc);
return;
}
}
safe_chr('0', buff, bufc);
}
/* ---------------------------------------------------------------------------
* fun_connrecord: Get max number of simultaneous connects.
*/
FUNCTION(fun_connrecord)
{
safe_ltos(buff, bufc, mudstate.record_players);
}
/* ---------------------------------------------------------------------------
* State of the invocation and recursion counters.
*/
FUNCTION(fun_fcount)
{
safe_ltos(buff, bufc, mudstate.func_invk_ctr);
}
FUNCTION(fun_fdepth)
{
safe_ltos(buff, bufc, mudstate.func_nest_lev);
}
FUNCTION(fun_ccount)
{
safe_ltos(buff, bufc, mudstate.cmd_invk_ctr);
}
FUNCTION(fun_cdepth)
{
safe_ltos(buff, bufc, mudstate.cmd_nest_lev);
}
/* ---------------------------------------------------------------------------
* fun_s: Force substitution to occur.
* fun_subeval: Like s(), but don't do function evaluations.
*/
FUNCTION(fun_s)
{
char *str;
str = fargs[0];
exec(buff, bufc, player, caller, cause, EV_FIGNORE | EV_EVAL, &str,
cargs, ncargs);
}
FUNCTION(fun_subeval)
{
char *str;
str = fargs[0];
exec(buff, bufc, player, caller, cause,
EV_NO_LOCATION|EV_NOFCHECK|EV_FIGNORE|EV_NO_COMPRESS,
&str, (char **)NULL, 0);
}
/*------------------------------------------------------------------------
* Side-effect functions.
*/
static int check_command(player, name, buff, bufc, cargs, ncargs)
dbref player;
char *name, *buff, **bufc;
char *cargs[];
int ncargs;
{
CMDENT *cmdp;
if ((cmdp = (CMDENT *) hashfind(name, &mudstate.command_htab))) {
/* Note that these permission checks are NOT identical to the
* ones in process_cmdent(). In particular, side-effects are NOT
* subject to the CA_GBL_INTERP flag. This is a design decision
* based on the concept that these are functions and not commands,
* even though they behave like commands in many respects. This
* is also the same reason why side-effects don't trigger hooks.
*/
if (Invalid_Objtype(player) ||
!Check_Cmd_Access(player, cmdp, cargs, ncargs) ||
(!Builder(player) && Protect(CA_GBL_BUILD) &&
!(mudconf.control_flags & CF_BUILD))) {
safe_noperm(buff, bufc);
return 1;
}
}
return 0;
}
FUNCTION(fun_link)
{
if (check_command(player, "@link", buff, bufc, cargs, ncargs))
return;
do_link(player, cause, 0, fargs[0], fargs[1]);
}
FUNCTION(fun_tel)
{
if (check_command(player, "@teleport", buff, bufc, cargs, ncargs))
return;
do_teleport(player, cause, 0, fargs[0], fargs[1]);
}
FUNCTION(fun_wipe)
{
if (check_command(player, "@wipe", buff, bufc, cargs, ncargs))
return;
do_wipe(player, cause, 0, fargs[0]);
}
FUNCTION(fun_pemit)
{
if (check_command(player, "@pemit", buff, bufc, cargs, ncargs))
return;
do_pemit_list(player, fargs[0], fargs[1], 0);
}
FUNCTION(fun_remit)
{
if (check_command(player, "@pemit", buff, bufc, cargs, ncargs))
return;
do_pemit_list(player, fargs[0], fargs[1], 1);
}
FUNCTION(fun_oemit)
{
if (check_command(player, "@oemit", buff, bufc, cargs, ncargs))
return;
do_pemit(player, cause, PEMIT_OEMIT, fargs[0], fargs[1]);
}
FUNCTION(fun_force)
{
if (check_command(player, "@force", buff, bufc, cargs, ncargs))
return;
do_force(player, cause, FRC_NOW, fargs[0], fargs[1], cargs, ncargs);
}
FUNCTION(fun_trigger)
{
if (nfargs < 1) {
safe_str("#-1 TOO FEW ARGUMENTS", buff, bufc);
return;
}
if (check_command(player, "@trigger", buff, bufc, cargs, ncargs))
return;
do_trigger(player, cause, TRIG_NOW, fargs[0], &(fargs[1]), nfargs - 1);
}
FUNCTION(fun_wait)
{
do_wait(player, cause, 0, fargs[0], fargs[1], cargs, ncargs);
}
FUNCTION(fun_command)
{
CMDENT *cmdp;
char tbuf1[1], tbuf2[1];
char *p;
int key;
if (!fargs[0] || !*fargs[0])
return;
for (p = fargs[0]; *p; p++)
*p = tolower(*p);
cmdp = (CMDENT *) hashfind(fargs[0], &mudstate.command_htab);
if (!cmdp) {
notify(player, "Command not found.");
return;
}
if (Invalid_Objtype(player) ||
!Check_Cmd_Access(player, cmdp, cargs, ncargs) ||
(!Builder(player) && Protect(CA_GBL_BUILD) &&
!(mudconf.control_flags & CF_BUILD))) {
notify(player, NOPERM_MESSAGE);
return;
}
if (!(cmdp->callseq & CS_FUNCTION) || (cmdp->callseq & CS_ADDED)) {
notify(player, "Cannot call that command.");
return;
}
/* Strip command flags that are irrelevant. */
key = cmdp->extra;
key &= ~(SW_GOT_UNIQUE | SW_MULTIPLE | SW_NOEVAL);
/* Can't handle null args, so make sure there's something there. */
tbuf1[0] = '\0';
tbuf2[0] = '\0';
switch (cmdp->callseq & CS_NARG_MASK) {
case CS_NO_ARGS:
(*(cmdp->info.handler)) (player, cause, key);
break;
case CS_ONE_ARG:
(*(cmdp->info.handler)) (player, cause, key,
((fargs[1]) ? (fargs[1]) : tbuf1));
break;
case CS_TWO_ARG:
(*(cmdp->info.handler)) (player, cause, key,
((fargs[1]) ? (fargs[1]) : tbuf1),
((fargs[2]) ? (fargs[2]) : tbuf2));
break;
default:
notify(player, "Invalid command handler.");
return;
}
}
/*------------------------------------------------------------------------
* fun_create: Creates a room, thing or exit
*/
FUNCTION(fun_create)
{
dbref thing;
int cost;
char *name;
Delim isep;
VaChk_Only_InPure(3);
name = fargs[0];
if (!name || !*name) {
safe_str("#-1 ILLEGAL NAME", buff, bufc);
return;
}
switch (isep.str[0]) {
case 'r':
if (check_command(player, "@dig", buff, bufc)) {
return;
}
thing = create_obj(player, TYPE_ROOM, name, 0);
break;
case 'e':
if (check_command(player, "@open", 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)) {
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_dbref(buff, bufc, thing);
}
/*---------------------------------------------------------------------------
* fun_set: sets an attribute on an object
*/
FUNCTION(fun_set)
{
dbref thing, thing2, aowner;
char *p, *buff2;
int atr, atr2, aflags, alen, clear, flagvalue, could_hear;
ATTR *attr, *attr2;
/* obj/attr form? */
if (check_command(player, "@set", buff, bufc))
return;
if (parse_attrib(player, fargs[0], &thing, &atr, 0)) {
if (atr != NOTHING) {
/* must specify flag name */
if (!fargs[1] || !*fargs[1]) {
safe_str("#-1 UNSPECIFIED PARAMETER", buff, bufc);
}
/* are we clearing? */
clear = 0;
p = fargs[1];
if (*fargs[1] == NOT_TOKEN) {
p++;
clear = 1;
}
/* valid attribute flag? */
flagvalue = search_nametab(player,
indiv_attraccess_nametab, p);
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_noperm(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_nothing(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_noperm(buff, bufc);
return;
}
atr_get_info(thing, atr, &aowner, &aflags);
if (!Set_attr(player, thing, attr, aflags)) {
safe_noperm(buff, bufc);
return;
}
buff2 = alloc_lbuf("fun_set");
/* check for _ */
if (*p == '_') {
strcpy(buff2, p + 1);
if (!parse_attrib(player, p + 1, &thing2, &atr2, 0) ||
(atr == NOTHING)) {
free_lbuf(buff2);
safe_nomatch(buff, bufc);
return;
}
attr2 = atr_num(atr);
p = buff2;
atr_pget_str(buff2, thing2, atr2, &aowner,
&aflags, &alen);
if (!attr2 ||
!See_attr(player, thing2, attr2, aowner, aflags)) {
free_lbuf(buff2);
safe_noperm(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);
}