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