/* functions.c - MUSH function handlers */ #include "copyright.h" #ifdef WANT_ANSI #ifdef __STDC__ #include <stdlib.h> #include <stddef.h> #endif /* __STDC__ */ #endif /* WANT_ANSI */ #include <ctype.h> #include <limits.h> #include <math.h> #include <time.h> #include "mudconf.h" #include "config.h" #include "db.h" #include "flags.h" #include "externs.h" #include "match.h" #include "command.h" #include "functions.h" #include "misc.h" extern char *index(); /* This is the prototype for functions */ #define FUNCTION(x) static void x(char *buff, dbref player, dbref cause, \ char *fargs[], int nfargs, \ char *cargs[], int ncargs) dbref match_thing(dbref player, char *name) { init_match(player, name, NOTYPE); match_everything(); return (noisy_match_result()); } /* --------------------------------------------------------------------------- * nearby_or_control: Check if player is near or controls thing */ int nearby_or_control (dbref player, dbref thing) { if (!Good_obj(player) || !Good_obj(thing)) return 0; if (Controls(player, thing)) return 1; if (!nearby(player, thing)) return 0; if ((Typeof(thing) == TYPE_EXIT) && Dark(thing)) return 0; return 1; } /* --------------------------------------------------------------------------- * fun_words: Returns number of words in a string. * Added 1/28/91 Philip D. Wasson */ FUNCTION(fun_words) { char *i; int n; for (i=fargs[0],n=0; strtok(i, " "); i=NULL,n++) ; sprintf(buff, "%d", n); } /* --------------------------------------------------------------------------- * fun_flags: Returns the flags on an object. * Because @switch is case-insensitive, not quite as useful as it could be. */ FUNCTION(fun_flags) { dbref it; char *buff2; it = match_thing(player, fargs[0]); if ((it != NOTHING) && (mudconf.pub_flags || Examinable(player, it) || (it == cause))) { buff2 = unparse_flags(player, it); strcpy(buff, buff2); free_sbuf(buff2); } else strcpy(buff, "#-1"); return; } /* --------------------------------------------------------------------------- * fun_rand: Return a random number from 0 to arg1-1 */ FUNCTION(fun_rand) { int num; num = atoi(fargs[0]); if (num < 1) strcpy(buff, "0"); else sprintf(buff, "%d", (int)((double)num * ((double)random() / (double)INT_MAX))); } /* --------------------------------------------------------------------------- * fun_abs: Returns the absolute value of its argument. */ FUNCTION(fun_abs) { int num; num = atoi(fargs[0]); if (num == 0) strcpy(buff, "0"); else sprintf(buff, "%d", abs(num)); } /* --------------------------------------------------------------------------- * fun_sign: Returns -1, 0, or 1 based on the the sign of its argument. */ FUNCTION(fun_sign) { int num; num = atoi(fargs[0]); if (num < 0) strcpy(buff, "-1"); else if (num > 0) strcpy(buff, "1"); else strcpy(buff, "0"); } /* --------------------------------------------------------------------------- * fun_time: Returns nicely-formatted time. */ FUNCTION(fun_time) { time_t tt; char *temp; time(&tt); temp = (char *)ctime(&tt); temp[strlen(temp) - 1] = '\0'; strcpy(buff, temp); } /* --------------------------------------------------------------------------- * fun_time: Seconds since 0:00 1/1/70 */ FUNCTION(fun_secs) { time_t tt; time(&tt); sprintf(buff, "%d", tt); } /* --------------------------------------------------------------------------- * 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'; strcpy(buff, temp); } /* --------------------------------------------------------------------------- * fun_get, fun_get_eval: Get attribute from object. */ FUNCTION(fun_get) { dbref thing, aowner; int attrib, free_buffer, aflags; ATTR *attr; char *atr_gotten; struct boolexp *bool; if (!parse_attrib(player, fargs[0], &thing, &attrib)) { strcpy(buff, "#-1 NO MATCH"); return; } if (attrib == NOTHING) { *buff = '\0'; return; } free_buffer = 1; attr = atr_num(attrib); /* We need the attr's flags for this: */ if (attr->flags & AF_IS_LOCK) { atr_gotten = atr_get(thing, attrib, &aowner, &aflags); if (Read_attr(player, thing, attr, aowner)) { bool = parse_boolexp(player, atr_gotten); free_lbuf(atr_gotten); atr_gotten = unparse_boolexp(player, bool); free_boolexp(bool); } else { free_lbuf(atr_gotten); atr_gotten = (char *)"#-1 PERMISSION DENIED"; } free_buffer = 0; } else { atr_gotten = atr_pget(thing, attrib, &aowner, &aflags); } if (Examinable(player, thing) && See_attr(player, thing, attr, aowner)) { ; } else if ((Typeof(thing) == TYPE_PLAYER) && See_attr(player, thing, attr, aowner)) { if (!mudconf.read_rem_desc && (attr->number == A_DESC) && !nearby(player, thing)) { free_lbuf(atr_gotten); atr_gotten = (char *)"#-1 TOO FAR AWAY TO SEE"; free_buffer = 0; } } else if (See_attr(player, thing, attr, aowner)) { if (!mudconf.read_rem_desc && !nearby(player, thing)) { free_lbuf(atr_gotten); atr_gotten = (char *)"#-1 TOO FAR AWAY TO SEE"; free_buffer = 0; } } else { free_lbuf(atr_gotten); atr_gotten = (char *)"#-1 PERMISSION DENIED"; free_buffer = 0; } strcpy(buff, atr_gotten); if (free_buffer) free_lbuf(atr_gotten); return; } FUNCTION(fun_get_eval) { dbref thing, aowner; int attrib, free_buffer, aflags, eval_it; ATTR *attr; char *atr_gotten; struct boolexp *bool; if (!parse_attrib(player, fargs[0], &thing, &attrib)) { strcpy(buff, "#-1 NO MATCH"); return; } if (attrib == NOTHING) { *buff = '\0'; return; } free_buffer = 1; eval_it = 1; attr = atr_num(attrib); /* We need the attr's flags for this: */ if (attr->flags & AF_IS_LOCK) { atr_gotten = atr_get(thing, attrib, &aowner, &aflags); if (Read_attr(player, thing, attr, aowner)) { bool = parse_boolexp(player, atr_gotten); free_lbuf(atr_gotten); atr_gotten = unparse_boolexp(player, bool); free_boolexp(bool); } else { free_lbuf(atr_gotten); atr_gotten = (char *)"#-1 PERMISSION DENIED"; } free_buffer = 0; eval_it = 0; } else { atr_gotten = atr_pget(thing, attrib, &aowner, &aflags); } if (Examinable(player, thing) && See_attr(player, thing, attr, aowner)) { ; } else if ((Typeof(thing) == TYPE_PLAYER) && See_attr(player, thing, attr, aowner)) { if (!mudconf.read_rem_desc && (attr->number == A_DESC) && !nearby(player, thing)) { free_lbuf(atr_gotten); atr_gotten = (char *)"#-1 TOO FAR AWAY TO SEE"; free_buffer = 0; eval_it = 0; } } else if (See_attr(player, thing, attr, aowner)) { if (!mudconf.read_rem_desc && !nearby(player, thing)) { free_lbuf(atr_gotten); atr_gotten = (char *)"#-1 TOO FAR AWAY TO SEE"; free_buffer = 0; eval_it = 0; } } else { free_lbuf(atr_gotten); atr_gotten = (char *)"#-1 PERMISSION DENIED"; free_buffer = 0; eval_it = 0; } strcpy(buff, atr_gotten); if (free_buffer) free_lbuf(atr_gotten); if (eval_it) { atr_gotten = exec(thing, player, EV_FIGNORE, buff, (char **)NULL, 0); strcpy(buff, atr_gotten); free_lbuf(atr_gotten); } return; } /* --------------------------------------------------------------------------- * fun_parent: Get parent of object. */ FUNCTION(fun_parent) { dbref it; it = match_thing(player, fargs[0]); if (Good_obj(it) && (Examinable(player, it) || (it == cause))) { sprintf(buff, "#%d", Parent(it)); } else { strcpy(buff, "#-1"); } return; } /* --------------------------------------------------------------------------- * fun_mid: mid(foobar,2,3) returns oba */ FUNCTION(fun_mid) { int l, len; l = atoi(fargs[1]); len = atoi(fargs[2]); if ((l < 0) || (len < 0) || ((len + l) > LBUF_SIZE)) { strcpy(buff, "#-1 OUT OF RANGE"); return; } if (l < strlen(fargs[0])) strcpy(buff, fargs[0] + l); else *buff = 0; buff[len] = 0; } /* --------------------------------------------------------------------------- * fun_first: Returns first word in a string */ FUNCTION(fun_first) { char *s, *b; /* get rid of leading space */ b = skip_space(fargs[0]); s = seek_char(b, ' '); if (s) *s = 0; strcpy(buff, b); } /* --------------------------------------------------------------------------- * fun_rest: Returns all but the first word in a string */ FUNCTION(fun_rest) { char *s; /* skip leading space */ s = skip_space(fargs[0]); /* skip firsts word */ s = seek_char(s, ' '); /* skip leading space */ s = skip_space(s); strcpy(buff, s); } /* --------------------------------------------------------------------------- * fun_v: Function form of %-substitution */ FUNCTION(fun_v) { dbref aowner; int aflags; char *sbuf, *sbufc, *tbuf; ATTR *ap; tbuf = fargs[0]; if (isalpha(tbuf[0]) && tbuf[1]) { /* Fetch an attribute from me. First see if it exists, * returning a null string if it does not. */ ap = atr_str(fargs[0]); if (!ap) { *buff = '\0'; return; } /* If we can access it, return it, otherwise return a * null string */ atr_pget_info(player, ap->number, &aowner, &aflags); if (See_attr(player, player, ap, aowner)) { tbuf = atr_pget(player, ap->number, &aowner, &aflags); strcpy(buff, tbuf); free_lbuf(tbuf); } else { *buff = '\0'; } return; } /* Not an attribute, process as %<arg> */ sbuf = alloc_sbuf("fun_v"); sbufc = sbuf; safe_sb_chr('%', sbuf, &sbufc); safe_sb_str(fargs[0], sbuf, &sbufc); *sbufc = '\0'; tbuf = exec(player, cause, EV_FIGNORE, sbuf, cargs, ncargs); strcpy(buff, tbuf); free_lbuf(tbuf); free_sbuf(sbuf); } /* --------------------------------------------------------------------------- * fun_s: Force substitution to occur. */ FUNCTION(fun_s) { char *tbuf; tbuf = exec(player, cause, EV_FIGNORE, fargs[0], cargs, ncargs); strcpy(buff, tbuf); free_lbuf(tbuf); } /* --------------------------------------------------------------------------- * fun_con: Returns first item in contents list of object/room */ FUNCTION(fun_con) { dbref it, loc_player; it = match_thing(player, fargs[0]); loc_player = where_is(player); if ((it != NOTHING) && (Has_contents(it)) && (Examinable(player, it) || (where_is(player) == it) || (it == cause))) { sprintf(buff, "#%d", Contents(it)); return; } strcpy(buff, "#-1"); return; } /* --------------------------------------------------------------------------- * fun_exit: Returns first exit in exits list of room. */ FUNCTION(fun_exit) { dbref it, exam; it = match_thing(player, fargs[0]); if (Good_obj(it) && (Typeof(it != TYPE_EXIT))) { exam = Examinable(player, it); if (exam || (where_is(player) == it) || (it == cause)) { sprintf(buff, "#%d", next_exit(player, Exits(it), exam)); return; } } strcpy(buff, "#-1"); return; } /* --------------------------------------------------------------------------- * fun_next: return next thing in contents or exits chain */ FUNCTION(fun_next) { dbref it, loc, exam_here; it = match_thing(player, fargs[0]); loc = where_is(it); if (loc != NOTHING) { exam_here = Examinable(player, loc); if (exam_here || (loc == player) || (loc == where_is(player))) { sprintf(buff, "#%d", next_exit(player, Next(it), exam_here)); return; } } strcpy(buff, "#-1"); return; } /* --------------------------------------------------------------------------- * fun_loc: Returns the location of something */ FUNCTION(fun_loc) { dbref it, loc_it; it = match_thing(player, fargs[0]); loc_it = where_is(it); if ((it != NOTHING) && (Examinable(player, it) || (loc_it == player) || ((loc_it != NOTHING) && (Examinable(player, loc_it) || loc_it == where_is(player))) || Wizard(cause) || Findable(it) || (it == cause))) { sprintf(buff, "#%d", Location(it)); return; } strcpy(buff, "#-1"); return; } /* --------------------------------------------------------------------------- * fun_room: Find the room an object is ultimately in. */ FUNCTION(fun_room) { dbref it; int count; it = match_thing(player, fargs[0]); if ((Good_obj(it) && Has_location(it)) && (Examinable(player, it) || nearby(player, it) || Wizard(cause) || Findable(it) || (it == cause))) { for (count=20; count>0; count--) { it = Location(it); if (Typeof(it) == TYPE_ROOM) { sprintf(buff, "#%d", it); return; } } strcpy(buff, "#-1"); } else if (Typeof(it) == TYPE_ROOM) { sprintf(buff, "#%d", it); } else { strcpy(buff, "#-1"); } return; } /* --------------------------------------------------------------------------- * fun_owner: Return the owner of an object. */ FUNCTION(fun_owner) { dbref it; it = match_thing(player, fargs[0]); if (it != NOTHING) it = Owner(it); sprintf(buff, "#%d", it); } /* --------------------------------------------------------------------------- * fun_name: Return the name of an object */ FUNCTION(fun_name) { dbref it; char *s; it = match_thing(player, fargs[0]); if (it == NOTHING) { buff[0] = '\0'; return; } if (!mudconf.read_rem_name) { if (!nearby_or_control(player, it) && (Typeof(it) != TYPE_PLAYER)) { strcpy(buff, "#-1 TOO FAR AWAY TO SEE"); return; } } if (Typeof(it) == TYPE_EXIT) { if (!Controls(player, it) && Dark(it)) { strcpy(buff, "#-1 TOO FAR AWAY TO SEE"); } else { strcpy(buff, Name(it)); for (s = buff; *s && (*s != ';'); s++) ; *s = '\0'; } } else strcpy(buff, Name(it)); } /* --------------------------------------------------------------------------- * fun_match: match(bar foo bar,foo) returns '2' (foo is the second word in * the first string.) */ FUNCTION(fun_match) { int wcount; char *r, *s; /* First check if we match the whole string. If so, return 1 */ if (wild_match(fargs[1], fargs[0], (char **)NULL, 0)) { strcpy(buff, "1"); return; } /* Now check each word individually, returning the word number of the * first one that matches. If none match, return 0. */ wcount = 1; s = fargs[0]; do { r = skip_space(s); s = seek_char(r, ' '); if (*s) *s++ = 0; if (wild_match(fargs[1], r, (char **)NULL, 0)) { sprintf(buff, "%d", wcount); return; } wcount++; } while (*s); strcpy(buff, "0"); } /* --------------------------------------------------------------------------- * fun_extract: extract words from string: * extract(foo bar baz,1,2) returns 'foo bar' * extract(foo bar baz,2,1) returns 'bar' * extract(foo bar baz,2,2) returns 'bar baz' * get it? */ FUNCTION(fun_extract) { int start, len; char *r, *s; s = fargs[0]; start = atoi(fargs[1]); len = atoi(fargs[2]); if ((start < 1) || (len < 1)) { *buff = '\0'; return; } start--; while (start && *s) { s = skip_space(s); s = seek_char(s, ' '); start--; } s = skip_space(s); r = s; while (len && *s) { s = skip_space(s); s = seek_char(s, ' '); len--; } if (s) *s = '\0'; strcpy(buff, r); } int xlate(char *arg) { int temp; char *temp2; if (arg[0] == '#') if ((temp = atoi(arg + 1)) == -1) return 0; else return temp; temp2 = skip_space(arg); if (!*temp2) return 0; if (is_number(temp2)) return atoi(temp2); return 1; } FUNCTION(fun_cat) { char *bp; bp = buff; safe_str(fargs[0], buff, &bp); safe_chr(' ', buff, &bp); safe_str(fargs[1], buff, &bp); *bp = '\0'; } FUNCTION(fun_version){ strcpy(buff, mudstate.version); } FUNCTION(fun_strlen){ sprintf(buff, "%d", (int) strlen(fargs[0])); } FUNCTION(fun_num) { sprintf(buff, "#%d", match_thing(player, fargs[0])); } FUNCTION(fun_gt) { sprintf(buff, "%d", (atoi(fargs[0])> atoi(fargs[1]))); } FUNCTION(fun_gte) { sprintf(buff, "%d", (atoi(fargs[0])>=atoi(fargs[1]))); } FUNCTION(fun_lt) { sprintf(buff, "%d", (atoi(fargs[0])< atoi(fargs[1]))); } FUNCTION(fun_lte) { sprintf(buff, "%d", (atoi(fargs[0])<=atoi(fargs[1]))); } FUNCTION(fun_eq) { sprintf(buff, "%d", (atoi(fargs[0])==atoi(fargs[1]))); } FUNCTION(fun_neq) { sprintf(buff, "%d", (atoi(fargs[0])!=atoi(fargs[1]))); } FUNCTION(fun_and) { sprintf(buff, "%d", xlate(fargs[0]) && xlate(fargs[1])); } FUNCTION(fun_or) { sprintf(buff, "%d", xlate(fargs[0]) || xlate(fargs[1])); } FUNCTION(fun_not) { sprintf(buff, "%d", !xlate(fargs[0])); } FUNCTION(fun_xor) { sprintf(buff, "%d", ((xlate(fargs[0]) && !xlate(fargs[1])) || (!xlate(fargs[0]) && xlate(fargs[1])))); } FUNCTION(fun_add) { sprintf(buff, "%d", atoi(fargs[0]) + atoi(fargs[1])); } FUNCTION(fun_sub) { sprintf(buff, "%d", atoi(fargs[0]) - atoi(fargs[1])); } FUNCTION(fun_mul) { sprintf(buff, "%d", atoi(fargs[0]) * atoi(fargs[1])); } FUNCTION(fun_div) { int bot; bot = atoi(fargs[1]); if (bot == 0) bot = 1; sprintf(buff, "%d", atoi(fargs[0]) / bot); } FUNCTION(fun_mod) { int bot; bot = atoi(fargs[1]); if (bot == 0) bot = 1; sprintf(buff, "%d", atoi(fargs[0]) % bot); } FUNCTION(fun_dist2d) { int d; double r; d = atoi(fargs[0]) - atoi(fargs[2]); r = (double)(d * d); d = atoi(fargs[1]) - atoi(fargs[3]); r +=(double)(d * d); d = (int)(sqrt(r) + 0.5); sprintf(buff, "%d", d); } FUNCTION(fun_dist3d) { int d; double r; d = atoi(fargs[0]) - atoi(fargs[3]); r = (double)(d * d); d = atoi(fargs[1]) - atoi(fargs[4]); r += (double)(d * d); d = atoi(fargs[2]) - atoi(fargs[5]); r += (double)(d * d); d = (int)(sqrt(r) + 0.5); sprintf(buff, "%d", d); } /* --------------------------------------------------------------------------- * fun_comp: string compare. */ FUNCTION(fun_comp) { int x; x = strcmp(fargs[0], fargs[1]); if (x > 0) strcpy(buff, "1"); else if (x < 0) strcpy(buff, "-1"); else strcpy(buff, "0"); } /* --------------------------------------------------------------------------- * fun_lcon: Return a list of contents. */ FUNCTION(fun_lcon) { dbref thing, it; char *bufp, *tbuf; it = match_thing(player, fargs[0]); *buff = '\0'; bufp = buff; if ((it != NOTHING) && (Has_contents(it)) && (Examinable(player, it) || (Location(player) == it) || (it == cause))) { tbuf = alloc_sbuf("fun_lcon"); DOLIST(thing, Contents(it)) { if (*buff) sprintf(tbuf, " #%d", thing); else sprintf(tbuf, "#%d", thing); safe_str(tbuf, buff, &bufp); } free_sbuf(tbuf); *bufp = '\0'; } else strcpy(buff, "#-1"); } /* --------------------------------------------------------------------------- * fun_lexits: Return a list of exits. */ FUNCTION(fun_lexits) { dbref thing, it; char *bufp, *tbuf; int exam, lev; *buff = '\0'; bufp = buff; it = match_thing(player, fargs[0]); if (!Good_obj(it) || (Typeof(it == TYPE_EXIT))) { strcpy(buff, "#-1"); return; } exam = Examinable(player, it); if (!exam && (where_is(player) != it) && (it != cause)) { strcpy(buff, "#-1"); return; } tbuf = alloc_sbuf("fun_lexits"); /* Return info for all parent levels */ for (lev=0; (Good_obj(it) && (lev < mudconf.parent_nest_lim)); it=Parent(it), lev++) { /* Look for exits at each level */ for (thing=next_exit(player, Exits(it), exam); thing!=NOTHING; thing=next_exit(player, Next(thing), exam)) { if (*buff) sprintf(tbuf, " #%d", thing); else sprintf(tbuf, "#%d", thing); safe_str(tbuf, buff, &bufp); } } free_sbuf(tbuf); *bufp = '\0'; return; } /* -------------------------------------------------------------------------- * fun_home: Return an object's home */ FUNCTION(fun_home) { dbref it; it = match_thing(player, fargs[0]); if (!Good_obj(it) || (Typeof(it) == TYPE_ROOM) || !Examinable(player, it)) sprintf(buff, "#-1"); else if (Typeof(it) == TYPE_EXIT) sprintf(buff, "#%d", Exits(it)); else sprintf(buff, "#%d", Home(it)); } /* --------------------------------------------------------------------------- * fun_money: Return an object's value */ FUNCTION(fun_money) { dbref it; it = match_thing(player, fargs[0]); if ((it == NOTHING) || !Examinable(player, it)) sprintf(buff, "#-1"); else sprintf(buff, "%d", Pennies(it)); } /* --------------------------------------------------------------------------- * fun_pos: Find a word in a string */ FUNCTION(fun_pos) { int i = 1; char *s,*t, *u; i = 1; s = fargs[1]; while (*s) { u = s; t = fargs[0]; while (*t && *t == *u) ++t, ++u; if (*t == '\0') { sprintf(buff, "%d", i); return; } ++i, ++s; } strcpy(buff, "#-1"); return; } /* --------------------------------------------------------------------------- * fun_remove: Remove a word from a string */ FUNCTION(fun_remove) { char *s, *t, *p; int done; done = 0; if (index(fargs[1], ' ')) { strcpy(buff, "#-1 CAN ONLY DELETE ONE ELEMENT"); return; } s = p = fargs[0]; t = fargs[1]; while (*s && !done) { if (*t) if (*s == *t) t++; else { t = fargs[1]; while (*(s + 1) && *s != ' ') s++; p = s; } else done = 1; s++; } if (!*t && ((*(s - 1) == ' ') || !*s)) { if (p == fargs[0]) strcpy(buff, s); else { *p = '\0'; if (!*s) strcpy(buff, fargs[0]); else sprintf(buff, "%s %s", fargs[0], s); } return; } strcpy(buff, fargs[0]); } /* --------------------------------------------------------------------------- * fun_member: Is a word in a string */ FUNCTION(fun_member) { int wcount; char *r, *s; if (index(fargs[1], ' ')) { strcpy(buff, "#-1 CAN ONLY TEST ONE ELEMENT"); return; } wcount = 1; s = fargs[0]; do { r = skip_space(s); s = seek_char(r, ' '); if (*s) *s++ = 0; if (!strcmp(fargs[1], r)) { sprintf(buff, "%d", wcount); return; } wcount++; } while (*s); strcpy(buff, "0"); } /* --------------------------------------------------------------------------- * fun_secure, fun_escape: escape [, ], %, \, and the beginning of the string. */ FUNCTION(fun_secure) { char *s, *d; s = fargs[0]; d = buff; while (*s) { switch (*s) { case '%': case '$': case '\\': case '[': case ']': case '(': case ')': case '{': case '}': case ',': case ';': safe_chr(' ', buff, &d); break; default: safe_chr(*s, buff, &d); } s++; } *d = '\0'; } FUNCTION(fun_escape) { char *s, *d; s = fargs[0]; d = buff; while (*s) { switch (*s) { case '%': case '\\': case '[': case ']': case '{': case '}': case ';': safe_chr('\\', buff, &d); default: if (d == buff) safe_chr('\\', buff, &d); safe_chr(*s, buff, &d); } s++; } *d = '\0'; } /* Take a character position and return which word that char is in. wordpos(<string>, <charpos>) */ FUNCTION(fun_wordpos) { char *cp; int charpos, curword; char done, inspace; charpos = atoi(fargs[1]); curword = 1; for (inspace = 0, done = 0, cp = fargs[0]; cp && *cp && !done; cp++) { if ((*cp == ' ') && (!inspace)) { curword++; inspace = 1; } if ((*cp != ' ') && (inspace)) inspace = 0; if ((cp - fargs[0] + 1) == charpos) done = 1; } if (!done) strcpy(buff, "#-1"); else sprintf(buff, "%d", curword); } FUNCTION(fun_type) { dbref it; it = match_thing(player, fargs[0]); if (!Good_obj(it)) { strcpy(buff, "#-1 NOT FOUND"); return; } switch (Typeof(it)) { case TYPE_ROOM: strcpy(buff, "ROOM"); break; case TYPE_EXIT: strcpy(buff, "EXIT"); break; case TYPE_PLAYER: strcpy(buff, "PLAYER"); break; case TYPE_THING: strcpy(buff, "THING"); break; default: strcpy(buff, "#-1 ILLEGAL TYPE"); } return; } FUNCTION(fun_hasflag) { dbref it; FLAGENT *fp; it = match_thing(player, fargs[0]); if (!Good_obj(it)) { strcpy(buff, "#-1 NOT FOUND"); return; } if (mudconf.pub_flags || Examinable(player, it) || (it == cause)) { fp = find_flag(it, fargs[1]); if (fp == NULL) { strcpy(buff, "0"); return; } if (((fp->listperm & CA_WIZARD) && !Wizard(player)) || ((fp->listperm & CA_GOD) && !God(player))) { strcpy(buff, "0"); } else if (IS(it, TYPE_PLAYER, WIZARD) && !Wizard(player) && (Flags(it) & DARK) && (fp->flagvalue == PLAYER_CONNECT)) { strcpy(buff, "0"); } else if (Flags(it) & fp->flagvalue) { strcpy(buff, "1"); } else { strcpy(buff, "0"); } } else { strcpy(buff, "#-1 PERMISSION DENIED"); } } FUNCTION(fun_delete) { char *s, *d; int i, start, nchars, len; s = fargs[0]; start = atoi(fargs[1]); nchars = atoi(fargs[2]); len = strlen(s); if ((start >= len) || (nchars <= 0)) { strcpy(buff, s); return; } d = buff; for (i=0; i<start; i++) *d++=(*s++); if ((i+nchars) < len) { s += nchars; while (*d++ = *s++) ; } else { *d = '\0'; } } FUNCTION(fun_lock) { dbref it, aowner; int aflags; char *tbuf; struct boolexp *bool; it = match_thing(player, fargs[0]); if (Good_obj(it)) { if (!controls(player, it)) { strcpy(buff, "#-1 PERMISSION DENIED"); return; } tbuf = atr_get(it, A_LOCK, &aowner, &aflags); bool = parse_boolexp(player, tbuf); free_lbuf(tbuf); tbuf = (char *)unparse_boolexp_function(player, bool); free_boolexp(bool); strcpy(buff, tbuf); } else { strcpy(buff, "#-1 NOT FOUND"); } } FUNCTION(fun_elock) { dbref it, victim, aowner; int aflags; char *tbuf; struct boolexp *bool; it = match_thing(player, fargs[0]); if (!Good_obj(it)) { strcpy(buff, "#-1 NOT FOUND"); } else { victim = match_thing(player, fargs[1]); if (!Good_obj(victim)) { strcpy(buff, "#-1 NOT FOUND"); } else if ((!nearby(player, victim) && !nearby(it, victim)) && !Wizard(player)) { strcpy(buff, "#-1 TOO FAR AWAY"); } else { tbuf = atr_get(it, A_LOCK, &aowner, &aflags); bool = parse_boolexp(player, tbuf); free_lbuf(tbuf); sprintf(buff, "%d", eval_boolexp(victim, it, bool)); free_boolexp(bool); } } } /* --------------------------------------------------------------------------- * fun_lwho: Return list of connected users. */ FUNCTION(fun_lwho) { make_ulist(player, buff); } /* --------------------------------------------------------------------------- * fun_nearby: Return whether or not obj1 is near obj2. */ FUNCTION(fun_nearby) { dbref obj1, obj2; obj1 = match_thing(player, fargs[0]); obj2 = match_thing(player, fargs[1]); if (!(nearby_or_control(player, obj1) || nearby_or_control(player, obj2))) strcpy(buff, "0"); else if (nearby(obj1, obj2)) strcpy(buff, "1"); else strcpy(buff, "0"); } /* --------------------------------------------------------------------------- * fun_obj, fun_poss, and fun_subj: perform pronoun sub for object. */ FUNCTION(fun_obj) { dbref it; char *tbuff; it = match_thing(player, fargs[0]); if (!nearby_or_control(player, it)) { strcpy(buff, "#-1 NO MATCH"); } else { tbuff = exec(it, it, 0, (char *)"%o", (char **)NULL, 0); strcpy(buff, tbuff); free_lbuf(tbuff); } } FUNCTION(fun_poss) { dbref it; char *tbuff; it = match_thing(player, fargs[0]); if (!nearby_or_control(player, it)) { strcpy(buff, "#-1 NO MATCH"); } else { tbuff = exec(it, it, 0, (char *)"%p", (char **)NULL, 0); strcpy(buff, tbuff); free_lbuf(tbuff); } } FUNCTION(fun_subj) { dbref it; char *tbuff; it = match_thing(player, fargs[0]); if (!nearby_or_control(player, it)) { strcpy(buff, "#-1 NO MATCH"); } else { tbuff = exec(it, it, 0, (char *)"%s", (char **)NULL, 0); strcpy(buff, tbuff); free_lbuf(tbuff); } } /* --------------------------------------------------------------------------- * fun_mudname: Return the name of the mud. */ FUNCTION(fun_mudname) { char *bp; bp = buff; safe_str(mudconf.mud_name, buff, &bp); *bp = '\0'; return; } /* --------------------------------------------------------------------------- * fun_lcstr, fun_ucstr, fun_capstr: Lowercase, uppercase, or capitalize str. */ FUNCTION(fun_lcstr) { char *ap, *bp; ap = fargs[0]; bp = buff; while (*ap) { if (isupper(*ap)) *bp++ = tolower(*ap++); else *bp++ = *ap++; } *bp = '\0'; } FUNCTION(fun_ucstr) { char *ap, *bp; ap = fargs[0]; bp = buff; while (*ap) { if (islower(*ap)) *bp++ = toupper(*ap++); else *bp++ = *ap++; } *bp = '\0'; } FUNCTION(fun_capstr) { strcpy(buff, fargs[0]); if (islower(*buff)) *buff = toupper(*buff); } /* --------------------------------------------------------------------------- * fun_lnum: Return a list of numbers. */ FUNCTION(fun_lnum) { char *bp, tbuff[10]; int ctr, limit, over; bp = buff; over = 0; limit = atol(fargs[0]); if (limit > 0) { safe_chr('0', buff, &bp); for (ctr=1; ctr<limit && !over; ctr++) { sprintf(tbuff, " %d", ctr); over = safe_str(tbuff, buff, &bp); } } *bp = '\0'; } /* --------------------------------------------------------------------------- * fun_lattr: Return list of attributes I can see on the object. */ FUNCTION(fun_lattr) { dbref thing, aowner; int ca, aflags; char *bp, *as; ATTR *attr; thing = match_thing(player, fargs[0]); if (thing == NOTHING) { strcpy(buff, "#-1 NO MATCH"); return; } bp = buff; for (ca=atr_head(thing, &as); ca; ca=atr_next(&as)) { attr = atr_num(ca); if (attr) { atr_get_info(thing, ca, &aowner, &aflags); if (See_attr(player, thing, attr, aowner)) { if (bp != buff) { safe_chr(' ', buff, &bp); } safe_str((char *)attr->name, buff, &bp); } } } *bp = '\0'; } /* --------------------------------------------------------------------------- * do_reverse, fun_reverse, fun_revwords: Reverse things. */ static void do_reverse (char *from, char *to) { char *tp; tp = to + strlen(from); *tp-- = '\0'; while (*from) { *tp-- = *from++; } } FUNCTION(fun_reverse) { do_reverse(fargs[0], buff); } FUNCTION(fun_revwords) { char *temp, *bp, *tp, *backp, savec; temp = alloc_lbuf("fun_revwords"); /* Reverse the whole string */ do_reverse(fargs[0], temp); /* Now individually reverse each word in the string. This will * undo the reversing of the words (so the words themselves are * forwards again. */ tp = temp; bp = buff; while (*tp) { backp = tp; while (isprint(*tp) && !isspace(*tp)) { tp++; } if (tp != backp) { savec = *tp; *tp = '\0'; do_reverse(backp, bp); bp += (tp - backp); *tp = savec; } if (!*tp) break; *bp++ = *tp++; } *bp = '\0'; free_lbuf(temp); } /* --------------------------------------------------------------------------- * fun_after, fun_before: Return substring after or before a specified string. */ FUNCTION(fun_after) { char *bp, *cp, *mp; int mlen; bp = fargs[0]; mp = fargs[1]; mlen = strlen(mp); /* If arg2 is empty, assume a space */ if (!*mp) { cp = index(bp, ' '); if (cp == NULL) { *buff = '\0'; } else { strcpy(buff, cp+1); } return; } /* Look for the target string */ while (*bp) { /* Search for the first character in the target string */ cp = index(bp, *mp); if (cp == NULL) { /* Not found, return empty string */ *buff = '\0'; return; } /* See if what follows is what we are looking for */ if (!strncmp(cp, mp, mlen)) { /* Yup, return what follows */ bp = cp + mlen; strcpy(buff, bp); return; } /* Continue search after found first character */ bp = cp+1; } /* Ran off the end without finding it */ *buff = '\0'; return; } FUNCTION(fun_before) { char *bp, *cp, *mp; int mlen; bp = fargs[0]; mp = fargs[1]; mlen = strlen(mp); /* If arg2 is empty, assume a space */ if (!*mp) { cp = index(bp, ' '); if (cp != NULL) { *cp = '\0'; } strcpy(buff, bp); return; } /* Look for the target string */ while (*bp) { /* Search for the first character in the target string */ cp = index(bp, *mp); if (cp == NULL) { /* Not found, return entire string */ strcpy(buff, fargs[0]); return; } /* See if what follows is what we are looking for */ if (!strncmp(cp, mp, mlen)) { /* Yup, return what follows */ *cp = '\0'; strcpy(buff, fargs[0]); return; } /* Continue search after found first character */ bp = cp+1; } /* Ran off the end without finding it */ strcpy(buff, fargs[0]); return; } /* --------------------------------------------------------------------------- * fun_max, fun_min: Return maximum (minimum) integer value. */ FUNCTION(fun_max) { int i, j, max, got_one; max = 0; for (i=0,got_one=0; i<nfargs; i++) { if (fargs[i]) { j = atoi(fargs[i]); if (!got_one || (j > max)) { got_one = 1; max = j; } } } if (!got_one) { strcpy(buff, "#-1 TOO FEW ARGUMENTS"); } else { sprintf(buff, "%d", max); } return; } FUNCTION(fun_min) { int i, j, min, got_one; min = 0; for (i=0,got_one=0; i<nfargs; i++) { if (fargs[i]) { j = atoi(fargs[i]); if (!got_one || (j < min)) { got_one = 1; min = j; } } } if (!got_one) { strcpy(buff, "#-1 TOO FEW ARGUMENTS"); } else { sprintf(buff, "%d", min); } return; } /* --------------------------------------------------------------------------- * fun_search: Search the db for things, returning a list of what matches */ FUNCTION(fun_search) { dbref thing; char *bp, *nbuf; SEARCH searchparm; /* Set up for the search. If any errors, abort. */ if (!search_setup(player, fargs[0], &searchparm)) { strcpy(buff, "#-1 ERROR DURING SEARCH"); return; } /* Do the search and report the results */ search_perform(player, cause, &searchparm); bp = buff; nbuf = alloc_sbuf("fun_search"); for (thing=olist_first(); thing!=NOTHING; thing=olist_next()) { if (bp == buff) sprintf(nbuf, "#%d", thing); else sprintf(nbuf, " #%d", thing); safe_str(nbuf, buff, &bp); } *bp = '\0'; free_sbuf(nbuf); olist_init(); } /* --------------------------------------------------------------------------- * fun_stats: Get database size statistics. */ FUNCTION(fun_stats) { dbref who; STATS statinfo; if ((!fargs[0]) || !*fargs[0] || !string_compare(fargs[0], "all")) { who = NOTHING; } else { who = lookup_player(player, fargs[0], 1); if (who == NOTHING) { strcpy(buff, "#-1 NOT FOUND"); return; } } if (!get_stats(player, who, &statinfo)) { strcpy(buff, "#-1 ERROR GETTING STATS"); return; } sprintf(buff, "%d %d %d %d %d %d", statinfo.s_total, statinfo.s_rooms, statinfo.s_exits, statinfo.s_things, statinfo.s_players, statinfo.s_garbage); } /* --------------------------------------------------------------------------- * fun_iter: Make list from evaluating arg2 with each member of arg1. */ FUNCTION(fun_iter) { char *curr, *objstring, *buff2, *result, *bp; curr = fargs[0]; bp = buff; while (curr && *curr) { while (*curr==' ') curr++; if (*curr) { objstring = parse_to(&curr, ' ', EV_STRIP); buff2 = replace_string(BOUND_VAR, objstring, fargs[1]); result = exec(player, cause, EV_FCHECK, buff2, (char **)NULL, 0); free_lbuf(buff2); if (buff != bp) safe_chr(' ', buff, &bp); safe_str(result, buff, &bp); free_lbuf(result); } } *bp = '\0'; } /* --------------------------------------------------------------------------- * do_edit: Edit text. */ FUNCTION(fun_edit) { char *tstr; edit_string(fargs[0], &tstr, fargs[1], fargs[2]); strcpy(buff, tstr); free_lbuf(tstr); } /* --------------------------------------------------------------------------- * do_u: Return result of evaluating attribute. */ FUNCTION(fun_u) { dbref aowner, thing; int aflags, anum; ATTR *ap; char *atext, *result; /* Two possibilities for the first arg: <obj>/<attr> and <attr>. */ 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]); } /* Make sure we got a good attribute */ if (!ap) { strcpy(buff, "#-1 NOT FOUND"); return; } /* Use it if we can access it, otherwise return an error. */ atext = atr_pget(thing, ap->number, &aowner, &aflags); if (!See_attr(player, thing, ap, aowner)) { free_lbuf(atext); strcpy(buff, "#-1 NOT FOUND"); return; } /* Evaluate it using the rest of the passed function args */ result = exec(player, cause, EV_FCHECK, atext, &(fargs[1]), nfargs-1); free_lbuf(atext); strcpy(buff, result); free_lbuf(result); } /* --------------------------------------------------------------------------- * fun_locate: Search for things with the perspective of another obj. */ FUNCTION(fun_locate) { int pref_type, check_locks, verbose; dbref thing, what; char *cp; pref_type = NOTYPE; check_locks = 0; verbose = 0; /* Find the thing to do the looking, make sure we control it. */ thing = match_controlled(player, fargs[0]); if (!Good_obj(thing)) { strcpy(buff, "#-1 PERMISSION DENIED"); return; } /* Get pre- and post-conditions and modifiers */ for (cp=fargs[2]; *cp; cp++) { switch (*cp) { case 'E': pref_type = TYPE_EXIT; break; case 'L': check_locks = 1; break; case 'P': pref_type = TYPE_PLAYER;break; case 'R': pref_type = TYPE_ROOM; break; case 'T': pref_type = TYPE_THING; break; case 'V': verbose = 1; break; } } /* Set up for the search */ if (check_locks) init_match_check_keys(thing, fargs[1], pref_type); else init_match(thing, fargs[1], pref_type); /* Search for each requested thing */ for (cp=fargs[2]; *cp; cp++) { switch(*cp) { case 'a': match_absolute(); break; case 'c': match_carried_exit_with_parents(); break; case 'e': match_exit_with_parents(); break; case 'h': match_here(); break; case 'i': match_possession(); break; case 'm': match_me(); break; case 'n': match_neighbor(); break; case 'p': match_player(); break; case '*': match_everything(); break; } } /* Get the result and return it to the caller */ if (verbose) what = noisy_match_result(); else what = match_result(); sprintf(buff, "#%d", what); } /* --------------------------------------------------------------------------- * fun_switch: Return value based on pattern matching (ala @switch) */ FUNCTION(fun_switch) { int i, got_any; char *tbuff; /* If we don't have at least 2 args, return nothing */ if (nfargs < 2) { *buff = '\0'; return; } got_any = 0; for (i=1; (i<nfargs-1) && fargs[i] && fargs[i+1]; i+=2) { tbuff = exec(player, cause, EV_STRIP+EV_FCHECK, fargs[i], (char **)NULL, 0); if (!got_any && quick_wild(tbuff, fargs[0])) { strcpy(buff, fargs[i+1]); got_any = 1; } free_lbuf(tbuff); } if (!got_any) { if ((i < nfargs) && fargs[i]) strcpy(buff, fargs[i]); else *buff = '\0'; } return; } /* --------------------------------------------------------------------------- * fun_space: Make spaces. */ FUNCTION(fun_space) { int num; char *cp; if (!fargs[0] || !(*fargs[0])) { num = 1; } else { num = atoi(fargs[0]); } if (num < 1) num = 1; else if (num >= LBUF_SIZE) num = LBUF_SIZE - 1; for (cp=buff; num>0; num--) *cp++ = ' '; *cp = '\0'; return; } /* --------------------------------------------------------------------------- * flist: List of existing functions in alphabetical order. */ FUN flist[] = { {"ABS", fun_abs, 1}, /* Absolute value */ {"ADD", fun_add, 2}, /* Integer addition */ {"AFTER", fun_after, -2}, /* Return part of arg1 after arg2 */ {"AND", fun_and, 2}, /* Logical AND */ {"BEFORE", fun_before, -2}, /* Return part of arg1 before arg2 */ {"CAPSTR", fun_capstr, -1}, /* Capitalize string */ {"CAT", fun_cat, -2}, /* Concatenate two strings */ {"COMP", fun_comp, 2}, /* String compare */ {"CON", fun_con, 1}, /* First item in contents list */ {"DELETE", fun_delete, 3}, /* Remove characters from string */ {"DIST2D", fun_dist2d, 4}, /* Distance in 2 dimensions */ {"DIST3D", fun_dist3d, 6}, /* Distance in 3 dimensions */ {"DIV", fun_div, 2}, /* Integer division */ {"EDIT", fun_edit, 3}, /* Edit text */ {"ELOCK", fun_elock, 2}, /* Evaluate lock with victim */ {"ESCAPE", fun_escape, -1}, /* Escape parser metacharacters */ {"EQ", fun_eq, 2}, /* Numeric equals */ {"EXIT", fun_exit, 1}, /* First item in exits list */ {"EXTRACT", fun_extract, 3}, /* Remove a word from a list */ {"FIRST", fun_first, -1}, /* Return first word in string */ {"FLAGS", fun_flags, 1}, /* Returns flags on an object */ {"GET", fun_get, 1}, /* Get attribute of object */ {"GET_EVAL", fun_get_eval, 1}, /* Get + eval the attr wrt its src */ {"GT", fun_gt, 2}, /* Numeric greater than */ {"GTE", fun_gte, 2}, /* Numeric greater than or equal */ {"HASFLAG", fun_hasflag, 2}, /* Does object have named flag? */ {"HOME", fun_home, 1}, /* Home of object */ {"ITER", fun_iter, 2}, /* Iterative evaluation */ {"LATTR", fun_lattr, 1}, /* List of visible attributes */ {"LCON", fun_lcon, 1}, /* List of contents */ {"LCSTR", fun_lcstr, -1}, /* Lowercase string */ {"LEXITS", fun_lexits, 1}, /* List of exits */ {"LNUM", fun_lnum, 1}, /* Return list of numbers 0 to n-1 */ {"LOC", fun_loc, 1}, /* Location of object */ {"LOCATE", fun_locate, 3}, /* Locate an object */ {"LOCK", fun_lock, 1}, /* Get lock of object */ {"LT", fun_lt, 2}, /* Numeric less than */ {"LTE", fun_lte, 2}, /* Numeric less than or equal */ {"LWHO", fun_lwho, 0}, /* Return list of connected users */ {"MATCH", fun_match, 2}, /* Find word in string */ {"MAX", fun_max, FN_VARARGS}, /* Return max integer value */ {"MEMBER", fun_member, 2}, /* Test if words is in list */ {"MID", fun_mid, 3}, /* Extract characters from string */ {"MIN", fun_min, FN_VARARGS}, /* Return min integer value */ {"MOD", fun_mod, 2}, /* Integer modulus */ {"MONEY", fun_money, 1}, /* Wealth of object */ {"MUDNAME", fun_mudname, 0}, /* Name of the running mud */ {"MUL", fun_mul, 2}, /* Integer multiplication */ {"NAME", fun_name, 1}, /* Name of object */ {"NEARBY", fun_nearby, 2}, /* Is obj1 near obj2? */ {"NEQ", fun_neq, 2}, /* Numeric not equal */ {"NEXT", fun_next, 1}, /* Next item/exit in chain */ {"NOT", fun_not, 1}, /* Logical NOT */ {"NUM", fun_num, 1}, /* Return DB number of object */ {"OBJ", fun_obj, 1}, /* Objective pronoun sub */ {"OR", fun_or, 2}, /* Logical OR */ {"OWNER", fun_owner, 1}, /* Owner of object */ {"PARENT", fun_parent, 1}, /* Parent of object */ {"POS", fun_pos, 2}, /* Find substring in string */ {"POSS", fun_poss, 1}, /* Possessive pronoun sub */ {"RAND", fun_rand, 1}, /* Return a random number */ {"REMOVE", fun_remove, 2}, /* Remove a word from a string */ {"REST", fun_rest, -1}, /* Return all but first word in str */ {"REVERSE", fun_reverse, -1}, /* Reverse a string */ {"REVWORDS", fun_revwords, -1}, /* Reverse order of words in string */ {"ROOM", fun_room, 1}, /* What room contains obj? */ {"S", fun_s, -1}, /* Perform substitution on string */ {"SEARCH", fun_search, -1}, /* Search the db for things */ {"SECS", fun_secs, 0}, /* seconds since 0:00 1/1/1970 */ {"SECURE", fun_secure, -1}, /* Remove '}' and ';' from string */ {"SIGN", fun_sign, 1}, /* Return sign of arg (-1, 0, or 1) */ {"SPACE", fun_space, 1}, /* Generate spaces */ {"STARTTIME", fun_starttime, 0}, /* Char string time when MUSH booted */ {"STATS", fun_stats, 1}, /* Get db size stats for player */ {"STRLEN", fun_strlen, -1}, /* Return length of string */ {"SUB", fun_sub, 2}, /* Subtract arg2 from arg1 */ {"SUBJ", fun_subj, 1}, /* Subjective pronoun sub */ {"SWITCH", fun_switch, FN_VARARGS}, /* Function from of @switch */ {"TIME", fun_time, 0}, /* Return the current time */ {"TYPE", fun_type, 1}, /* Return type of object */ {"U", fun_u, FN_VARARGS}, /* Return rslt of eval attr */ {"UCSTR", fun_ucstr, -1}, /* Uppercase string */ {"V", fun_v, 1}, /* All kinds of neat stuff */ {"VERSION", fun_version, 0}, /* Return MUSH version number */ {"WORDS", fun_words, -1}, /* Number of words in a string */ {"WORDPOS", fun_wordpos, 2}, /* which word is this char pos in? */ {"XOR", fun_xor, 2}, /* Logical XOR */ {NULL, NULL, 0} }; void init_functab() { FUN *fp; hashinit(&mudstate.func_htab, 29); for (fp=flist; fp->name; fp++) hashadd((char *)fp->name, (int *)fp, &mudstate.func_htab); }