/* 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); }