# # Patch name: vts # Patch version: 5 # Author's name: Thorvald Natvig # Author's email: slicer@bimbo.hive.no # Version of PennMUSH: 1.7.2p14 # Date patch made: fre aug 28 01:38:33 CEST 1998 # Author is willing to support (yes/no): yes # Patch format: context diff # # # This is a contributed PennMUSH patch. Its use is subject to the # same restrictions found in PennMUSH's hdrs/copyrite.h file. # # No warranty is given for this patch. It is not necessarily going # to work on your system, with any version of PennMUSH other than # the one above, etc. # # If the author given above was willing to support the patch, you # should write to the author if you have any questions or problems. Do # *NOT* send email messages to Javelin or any PennMUSH mailing list about # this patch! # # Below this line is the author's description of the patch, # followed by the patch itself. If the patch is in context diff # format, you'll probably apply it by typing: patch < patchfile # in your top-level MUSH directory, unless instructed otherwise # below. # This header and patchfile is autogenerated - Patch Version 5 Patch comments (if any): This is VTS, made by me (Trivian) and Halatir@M*U*S*H. Have fun. *** ../clean/hdrs/atr_tab.h Fri Aug 14 17:49:43 1998 --- hdrs/atr_tab.h Fri Aug 28 00:03:26 1998 *************** *** 123,128 **** --- 123,129 ---- {(char *) "VM", 0, NULL, 0}, {(char *) "VN", 0, NULL, 0}, {(char *) "VO", 0, NULL, 0}, + {(char *) "VTPLURAL", AF_NOPROG, NULL, 0}, {(char *) "VP", 0, NULL, 0}, {(char *) "VQ", 0, NULL, 0}, {(char *) "VR", 0, NULL, 0}, *** ../clean/hdrs/externs.h Fri Aug 14 17:49:50 1998 --- hdrs/externs.h Fri Aug 28 00:03:26 1998 *************** *** 417,422 **** --- 417,433 ---- /* funlist.c */ void do_gensort _((char **s, int n, int sort_type)); + /* vts.c */ + int vts_drop _((dbref player, char *what)); + int vts_give _((dbref player, dbref who, char *what)); + int vts_get _((dbref player, char *what)); + int vts_examine _((dbref player, char *what, char *aname)); + void vts_look_contents _((dbref player, dbref loc, const char *contents_name, int header)); + int vts_inventory _((dbref player, int header)); + int vts_look_at _((dbref player, char *what)); + int vts_command_match _((dbref player, const char *string)); + char *vts_mkconlist _((char *buff, char **bp, dbref looker, dbref loc)); + /* This is from utils.c, but put at the end because it confuses indent */ typedef *** ../clean/hdrs/flags.h Fri Aug 14 17:49:51 1998 --- hdrs/flags.h Fri Aug 28 00:03:26 1998 *************** *** 138,143 **** --- 138,146 ---- #define THING_LISTEN 0x20 /* checks for ^ patterns */ #define THING_NOLEAVE 0x40 /* Can't be left */ + #define THING_VTM 0x10000 /* Thing is a valid VTS thing */ + #define THING_VTCOUNT 0x20000 /* Ving is countable */ + /*-------------------------------------------------------------------------- * Room flags */ *** /dev/null Tue May 5 22:32:27 1998 --- hdrs/vts.h Fri Aug 28 00:19:41 1998 *************** *** 0 **** --- 1,62 ---- + #ifndef _VTS_H + #define _VTS_H + + #include "vtslocal.h" + #include "htab.h" + + #define Can_Vts_Create(p,x) (controls(p,x)) + #define Can_Vts_Examine(p,i) Can_Examine(p,i->master) + + struct vts_instance { + struct vts_instance *next; + dbref master; + void *data; + }; + + #define VtMaster(i) (i->master) + #define Vts_IsAttr(i) (!IS(VtMaster(i), TYPE_THING, THING_VTCOUNT)) + #define Vts_IsCount(i) (IS(i, TYPE_THING, THING_VTCOUNT)) + + struct vts_attr { + struct vts_attr *next; + HASHENT *aname; + char value[0]; + }; + + #ifndef _VTS_DATA_INTERFACE + #define vts_data_struc(p) LocData(p) + #define vts_make_data_struc(p) LocData(p) + #endif + + #define VMAT_REF 0x0001 /* Match Vtref */ + #define VMAT_INV 0x0002 /* Match in inventory */ + #define VMAT_LOC 0x0004 /* Match in location */ + #define VMAT_OLOC 0x0008 /* Match other vings in above locations */ + #define VMAT_ALL -1 + + /* Error messages (Not VTS specific) */ + + #define ERR_INVALIDARG "#-1 INVALID ARGUMENT" + #define ERR_PERMDENIED "#-1 PERMISSION DENIED" + #define ERR_HASHFAIL "#-1 HASH FAILURE" + #define ERR_INTEGER "#-1 ARGUMENT MUST BE INTEGER" + #define ERR_UNKNOWNDEST "#-1 UNKNOWN DESTINATION" + #define ERR_AMBIGDEST "#-1 AMBIGUOUS DESTINATION" + #define ERR_BADDEST "#-1 BAD DESTINATION" + #define ERR_CONTAINERS "#-1 TOO MANY CONTAINERS" + #define ERR_NOTELFROM "#-1 NO TELEPORT FROM THERE" + #define ERR_NOTELZONE "#-1 NO TELEPORT OUT OF ZONE" + #define ERR_NOTFOUND "#-1 OBJECT NOT FOUND" + + /* Error messages (VTS specific) */ + + #define VERR_NEGATIVECOUNT "#-1 NEGATIVE COUNT" + #define VERR_CREATIONFAIL "#-1 CREATION FAILED" + #define VERR_REFMISMATCH "#-1 VTREF MISMATCH" + #define VERR_NOTFOUND "#-1 VING NOT FOUND" + #define VERR_COUNTABLE "#-1 COUNTABLE VING" + #define VERR_NONCOUNTABLE "#-1 NOT A COUNTABLE VING" + #define VERR_MATCHTYPE "#-1 UNKNOWN CHARACTER IN MATCH TYPE" + + + #endif /* _VTS_H */ *** /dev/null Tue May 5 22:32:27 1998 --- hdrs/vtslocal.h Fri Aug 28 00:20:16 1998 *************** *** 0 **** --- 1,15 ---- + #ifndef _VTS_LOCAL_H + #define _VTS_LOCAL_H + + /* Put new data interface here, if you need to */ + + + + + + + + + + + #endif *** ../clean/src/cmdlocal.c Fri Aug 28 01:07:33 1998 --- src/cmdlocal.c Fri Aug 28 01:04:37 1998 *************** *** 72,75 **** --- 72,76 ---- #ifdef EXAMPLE command_add("@SILLY", CMD_T_ANY, 0, 0, 0, switchmask("NOISY NOEVAL"), cmd_local_silly); #endif + command_add("@VTS", CMD_T_ANY|CMD_T_EQSPLIT, WIZARD, 0, 0, switchmask("WIPE SET"), cmd_vts); } *** ../clean/src/cque.c Fri Aug 14 17:50:14 1998 --- src/cque.c Fri Aug 28 00:03:26 1998 *************** *** 33,38 **** --- 33,39 ---- extern char ccom[]; extern dbref cplr; extern time_t mudtime; + extern char *vtref; char *wenv[10]; /* working environment (wptr/rptr equiv) */ char renv[10][BUFFER_LEN]; *************** *** 48,53 **** --- 49,55 ---- int left; /* seconds left until execution */ char *env[10]; /* environment, from wild match */ char *rval[10]; /* environment, from setq() */ + char *vts; /* throughstorange of vtsvalue */ char *comm; /* command to be executed */ }; *************** *** 166,171 **** --- 168,175 ---- } if (point->comm) mush_free((Malloc_t) point->comm, "bqueue_comm"); + if (point->vts) + mush_free((Malloc_t) point->vts, "vts_ref"); mush_free((Malloc_t) point, "BQUE"); } *************** *** 230,235 **** --- 234,247 ---- add_check("bqueue_rval"); #endif } + if (vtref) { + tmp->vts=strdup(vtref); + #ifdef MEM_CHECK + add_check("vts_ref"); + #endif + } else { + tmp->vts=NULL; + } if (Typeof(cause) == TYPE_PLAYER) { if (qlast) { qlast->next = tmp; *************** *** 291,296 **** --- 303,317 ---- } } + if (vtref) { + tmp->vts=strdup(vtref); + #ifdef MEM_CHECK + add_check("vts_ref"); + #endif + } else { + tmp->vts=NULL; + } + if (wait >= 0) tmp->left = mudtime + wait; else *************** *** 439,444 **** --- 460,466 ---- else renv[a][0] = '\0'; } + vtref=qfirst->vts; s = qfirst->comm; while (*s) { r = ccom; *** ../clean/src/flags.c Fri Aug 14 17:50:22 1998 --- src/flags.c Fri Aug 28 00:03:26 1998 *************** *** 157,162 **** --- 157,164 ---- {"DESTROY_OK", 'd', TYPE_THING, THING_DEST_OK, F_ANY, F_ANY}, {"PUPPET", 'p', TYPE_THING, THING_PUPPET, F_ANY, F_ANY}, {"NO_LEAVE", 'N', TYPE_THING, THING_NOLEAVE, F_ANY, F_ANY}, + {"VTM", '@', TYPE_THING, THING_VTM, F_INTERNAL, F_INTERNAL}, + {"VTCOUNT", '$', TYPE_THING, THING_VTCOUNT, F_INTERNAL, F_INTERNAL}, {"ABODE", 'A', TYPE_ROOM, ROOM_ABODE, F_ANY, F_ANY}, {"FLOATING", 'F', TYPE_ROOM, ROOM_FLOATING, F_ANY, F_ANY}, *** ../clean/src/function.c Fri Aug 14 17:50:23 1998 --- src/function.c Fri Aug 28 00:03:26 1998 *************** *** 390,395 **** --- 390,408 ---- {"TAG", fun_tag, 1, INT_MAX, FN_REG}, {"ENDTAG", fun_endtag, 1, 1, FN_REG}, {"TAGWRAP", fun_tagwrap, 2, 3, FN_REG}, + + {"VTATTR", fun_vts_attr, 2, 3, FN_REG}, + {"VTCOUNT", fun_vts_count, 1, 1, FN_REG}, + {"VTCREATE", fun_vts_create, 2, 3, FN_REG}, + {"VTDESTROY", fun_vts_destroy, 1, 1, FN_REG}, + {"VTLCON", fun_vts_lcon, 1, 1, FN_REG}, + {"VTLOC", fun_vts_container, 1, 1, FN_REG}, + {"VTLOCATE", fun_vts_locate, 2, 3, FN_REG}, + {"VTMASTER", fun_vts_master, 1, 1, FN_REG}, + {"VTNAME", fun_vts_name, 1, 1, FN_REG}, + {"VTREF", fun_vts_getref, 2, 3, FN_REG}, + {"VTTEL", fun_vts_tel, 2, 3, FN_REG}, + {NULL, NULL, 0, 0} }; *** ../clean/src/game.c Fri Aug 14 17:50:29 1998 --- src/game.c Fri Aug 28 00:03:26 1998 *************** *** 914,919 **** --- 914,923 ---- if (Location(player) != player) a += list_match(Contents(player)); + /* Check on virtual things, since you never know when they stick around */ + if (!a) + a += vts_command_match(player, cptr); + /* now do check on zones */ if ((!a) && (Zone(Location(player)) != NOTHING)) { if (DO_GLOBALS && (Typeof(Zone(Location(player))) == TYPE_ROOM)) { *** ../clean/src/local.c Fri Aug 28 01:07:29 1998 --- src/local.c Fri Aug 28 01:05:22 1998 *************** *** 28,33 **** --- 28,34 ---- void local_startup() { + vts_db_read(); } /* Called when the database will be saved *************** *** 39,44 **** --- 40,46 ---- void local_dump_database() { + vts_db_dump(); } /* Called when the MUSH is shutting down. *************** *** 110,115 **** --- 112,118 ---- local_data_free(object) dbref object; { + vts_data_free(object); } /* Initiation of objects after a reload or dumping to disk should *** ../clean/src/look.c Fri Aug 14 17:50:34 1998 --- src/look.c Fri Aug 28 00:04:40 1998 *************** *** 224,229 **** --- 224,231 ---- { dbref thing; dbref can_see_loc; + int did=0; + ATTR *a; PUEBLOBUFF; /* check to see if he can see the location */ *************** *** 237,242 **** --- 239,245 ---- if (a) { char *wsave[10], *rsave[10]; char arg[BUFFER_LEN], buff[BUFFER_LEN], *bp; + char vtarg[BUFFER_LEN]; char const *src, *sp; int j; save_global_regs("look_contents", rsave); *************** *** 255,260 **** --- 258,265 ---- } *bp = '\0'; wenv[0] = arg; + wenv[1] = vts_mkconlist(vtarg, NULL, player, loc); + sp = src = safe_uncompress(a->value); bp = buff; process_expression(buff, &bp, &sp, loc, player, player, *************** *** 285,290 **** --- 290,297 ---- notify_by(loc, player, pbuff); } } + did=1; + vts_look_contents(player, loc, contents_name, 0); PUSE; tag_cancel("UL"); PEND; *************** *** 292,297 **** --- 299,306 ---- break; /* we're done */ } } + if (!did) + vts_look_contents(player, loc, contents_name, 1); } static int *************** *** 543,549 **** if ((thing = match_result(player, name, NOTYPE, MAT_NEARBY)) == NOTHING) { thing = parse_match_possessive(player, name); if (!GoodObject(thing)) { ! notify(player, "I don't see that here."); return; } if ((Flags(Location(thing)) & OPAQUE) && --- 552,559 ---- if ((thing = match_result(player, name, NOTYPE, MAT_NEARBY)) == NOTHING) { thing = parse_match_possessive(player, name); if (!GoodObject(thing)) { ! if (!vts_look_at(player, name)) ! notify(player, "I don't see that here."); return; } if ((Flags(Location(thing)) & OPAQUE) && *************** *** 637,645 **** } real_name = (char *) name; /* look it up */ ! if ((thing = noisy_match_result(player, real_name, NOTYPE, MAT_EVERYTHING)) == NOTHING) return; } /* can't examine destructed objects */ if (Destroyed(thing)) { notify(player, "Garbage is garbage."); --- 647,662 ---- } real_name = (char *) name; /* look it up */ ! switch ((thing = match_result(player, real_name, NOTYPE, MAT_EVERYTHING))) { ! case NOTHING: ! if (!vts_examine(player, real_name, attrib_name)) ! notify(player, "I can't see that here."); ! return; ! case AMBIGUOUS: ! notify(player, "I don't know which one you mean!"); return; } + } /* can't examine destructed objects */ if (Destroyed(thing)) { notify(player, "Garbage is garbage."); *************** *** 739,744 **** --- 756,767 ---- } notify(player, object_header(player, content)); } + vts_look_contents(player, thing, "", 0); + } else { + if (Typeof(thing) == TYPE_PLAYER) + vts_look_contents(player, thing, "Carrying:", 1); + else + vts_look_contents(player, thing, "Contents:", 1); } if (!ok) { /* if not examinable, just show obvious exits and name and owner */ *************** *** 842,855 **** { dbref thing; if ((thing = Contents(player)) == NOTHING) { notify(player, "You aren't carrying anything."); } else { notify(player, "You are carrying:"); DOLIST(thing, thing) { notify(player, unparse_object(player, thing)); } } - do_score(player); } --- 865,879 ---- { dbref thing; if ((thing = Contents(player)) == NOTHING) { + if (!vts_inventory(player, 1)) notify(player, "You aren't carrying anything."); } else { notify(player, "You are carrying:"); DOLIST(thing, thing) { notify(player, unparse_object(player, thing)); } + vts_inventory(player, 0); } do_score(player); } *** ../clean/src/move.c Fri Aug 14 17:50:37 1998 --- src/move.c Fri Aug 28 00:07:35 1998 *************** *** 447,453 **** /* take care of possessive get (stealing) */ thing = parse_match_possessive(player, what); if (!GoodObject(thing)) { ! notify(player, "I don't see that here."); return; } /* to steal something, you have to be able to get it, and the --- 447,454 ---- /* take care of possessive get (stealing) */ thing = parse_match_possessive(player, what); if (!GoodObject(thing)) { ! if (!vts_get(player, what)) ! notify(player, "I don't see that here."); return; } /* to steal something, you have to be able to get it, and the *************** *** 471,477 **** did_it(player, thing, "FAILURE", "You can't take that from there.", "OFAILURE", NULL, "AFAILURE", NOTHING); } else { ! notify(player, "I don't see that here."); } return; } else { --- 472,479 ---- did_it(player, thing, "FAILURE", "You can't take that from there.", "OFAILURE", NULL, "AFAILURE", NOTHING); } else { ! if (!vts_get(player, what)) ! notify(player, "I don't see that here."); } return; } else { *************** *** 523,529 **** switch (thing = match_result(player, name, TYPE_THING, MAT_POSSESSION | MAT_ABSOLUTE | MAT_CONTROL)) { case NOTHING: ! notify(player, "You don't have that!"); return; case AMBIGUOUS: notify(player, "I don't know which you mean!"); --- 525,532 ---- switch (thing = match_result(player, name, TYPE_THING, MAT_POSSESSION | MAT_ABSOLUTE | MAT_CONTROL)) { case NOTHING: ! if (!vts_drop(player, name)) ! notify(player, "You don't have that!"); return; case AMBIGUOUS: notify(player, "I don't know which you mean!"); *** ../clean/src/parse.c Fri Aug 14 17:50:39 1998 --- src/parse.c Fri Aug 28 00:03:26 1998 *************** *** 30,35 **** --- 30,36 ---- extern char ccom[]; /* bsd.c */ extern char *absp[], *obj[], *poss[], *subj[]; /* fundb.c */ + extern char *vtref; int global_fun_invocations; int global_fun_recursions; *************** *** 401,406 **** --- 402,411 ---- break; case '#': /* enactor dbref */ safe_str(unparse_dbref(enactor), buff, bp); + break; + case '&': /* VTS reference */ + if (vtref) + safe_str(vtref, buff, bp); break; case '?': /* function limits */ if (pe_info) { *** ../clean/src/rob.c Fri Aug 14 17:50:43 1998 --- src/rob.c Fri Aug 28 00:08:17 1998 *************** *** 186,192 **** dbref thing; switch (thing = match_result(player, amnt, TYPE_THING, MAT_POSSESSION)) { case NOTHING: ! notify(player, "You don't have that!"); return; case AMBIGUOUS: notify(player, "I don't know which you mean!"); --- 186,193 ---- dbref thing; switch (thing = match_result(player, amnt, TYPE_THING, MAT_POSSESSION)) { case NOTHING: ! if (!vts_give(player, who, amnt)) ! notify(player, "You don't have that!"); return; case AMBIGUOUS: notify(player, "I don't know which you mean!"); *** ../clean/src/unparse.c Fri Aug 14 17:50:52 1998 --- src/unparse.c Fri Aug 28 00:03:26 1998 *************** *** 24,30 **** char *unparse_boolexp _((dbref player, struct boolexp * b, int flag)); /* Hack added by Thorvald for object_header Pueblo */ ! static int couldunparse; const char * object_header(player, loc) --- 24,30 ---- char *unparse_boolexp _((dbref player, struct boolexp * b, int flag)); /* Hack added by Thorvald for object_header Pueblo */ ! int couldunparse; const char * object_header(player, loc) *** /dev/null Tue May 5 22:32:27 1998 --- src/vts.c Fri Aug 28 00:59:09 1998 *************** *** 0 **** --- 1,1456 ---- + /* A virtual things system + */ + + #include + #ifdef I_STDARG + #include + #else + #include + #endif + #include + #ifdef I_STRING + #include + #else + #include + #endif + #ifdef I_SYS_TYPES + #include + #endif + #ifdef I_SYS_TIME + #include + #else + #include + #endif + #ifdef I_STDLIB + #include + #endif + + #include "conf.h" + #include "externs.h" + #include "mushdb.h" + #include "intrface.h" + #include "globals.h" + #include "match.h" + #include "ansi.h" + #include "parse.h" + #include "dbdefs.h" + #include "pueblo.h" + #include "htab.h" + #include "command.h" + #ifdef MEM_CHECK + #include "memcheck.h" + #endif + #include "mymalloc.h" + #include "confmagic.h" + + #include "vts.h" + + + extern int couldunparse; + + char *vtref; + HASHTAB htab_vatr; + + extern int tport_control_ok _((dbref player, dbref victim, dbref loc)); + extern int tport_dest_ok _((dbref player, dbref victim, dbref dest)); + + + char *vts_mkref(char *buff, dbref container, struct vts_instance *vt, int count) + { + int c; + if (!Vts_IsAttr(vt)) { + if ((!count) || (count > (int) (vt->data))) + c = (int) (vt->data); + else + c = count; + } else { + c = 0; + } + sprintf(buff, "%p#%d!%d", vt, container, c); + return buff; + } + + int vts_can_see(dbref player, dbref container, struct vts_instance *vi) + { + dbref master; + master = VtMaster(vi); + if (Can_Examine(player, container) || Can_Examine(player, master)) + return 1; + if ((Location(player) != container) || (Dark(master) || (Dark(container) && !Light(master)))) + return 0; + if ((Typeof(container) == TYPE_PLAYER) && Opaque(container)) + return 0; + return 1; + } + + struct vts_instance *vts_getref(dbref *container, struct vts_instance **vt, int *count, char *string) + { + struct vts_instance *to; + int c; + if (sscanf(string, "%p#%d!%d", &to, container, &c) != 3) + return NULL; + + *vt = to; + + if (!GoodObject(*container)) + return NULL; + + to = vts_data_struc(*container); + while (to && to != *vt) + to = to->next; + + if (!to) + return NULL; + + if (count) { + if (!Vts_IsAttr(to) && (c > (int) (to->data))) + c = (int) (to->data); + *count = c; + } + return to; + } + + + struct vts_instance *vts_create(dbref master, dbref container, int count) + { + struct vts_instance *vt, *no; + + if (!IS(master, TYPE_THING, THING_VTM)) + return NULL; + + switch (Typeof(container)) { + case TYPE_THING: + case TYPE_ROOM: + case TYPE_PLAYER: + break; + default: + return NULL; + } + + if (Vts_IsCount(master)) { + no = vts_data_struc(container); + while (no && VtMaster(no) != master) + no = no->next; + if (no) { + (int) no->data += count; + return no; + } + } + no = mush_malloc(sizeof(struct vts_instance), "vts_instance"); + memset(no, 0, sizeof(struct vts_instance)); + no->master = master; + if (Vts_IsCount(master)) { + no->data = (void *) count; + } else { + no->data = NULL; + } + no->next = NULL; + + vt = vts_make_data_struc(container); + if (!vt) { + vts_make_data_struc(container) = no; + } else { + while (vt->next) + vt = vt->next; + vt->next = no; + } + return no; + } + + void vts_free(struct vts_instance *vt) + { + struct vts_attr *va, *van; + HASHENT *ahash; + if (Vts_IsAttr(vt)) { + va = vt->data; + while (va) { + van = va->next; + ahash = va->aname; + (int) (ahash->data) -= 1; + if ((int) (ahash->data) == 0) { + hash_delete(&htab_vatr, ahash); + } + mush_free(va, "vts_attr"); + va = van; + } + } + mush_free(vt, "vts_instance"); + } + + void vts_destroy(dbref container, struct vts_instance *vt) + { + struct vts_instance *to; + + to = vts_data_struc(container); + if (!to) + return; + if (to == vt) { + vts_make_data_struc(container) = vt->next; + } else { + while (to && to->next != vt) + to = to->next; + if (!to) + return; + to->next = vt->next; + } + + vts_free(vt); + } + + const char *vts_real_unparse(dbref player, dbref container, struct vts_instance *vt, int obey_myopic) + { + static char b[256]; + static char ref[256]; + dbref master = VtMaster(vt); + + if (Can_Examine(player, master)) { + vts_mkref(b, container, vt, 0); + sprintf(ref, " (%s)", b); + } else { + ref[0]='\0'; + } + if (Vts_IsCount(master) && ((int) (vt->data) != 1)) { + sprintf(b, "%s [%d]%s", real_unparse(player, master, obey_myopic), (int) (vt->data), ref); + } else { + sprintf(b, "%s%s", real_unparse(player, master, obey_myopic), ref); + } + return b; + } + + const char *vts_unparse_ving(dbref player, dbref container, struct vts_instance *vt) + { + static PUEBLOBUFF; + char ref[256]; + const char *result; + result = vts_real_unparse(player, container, vt, 1); + if (couldunparse) { + PUSE; + vts_mkref(ref, container, vt, 0); + tag_wrap("A", tprintf("XCH_CMD=\"examine %s\"", ref), result); + PEND; + return pbuff; + } else { + return result; + } + } + + + struct vts_instance *vts_place_match(dbref player, dbref where, char *m, int l, int num) + { + struct vts_instance *to; + + to = vts_data_struc(where); + + while (to) { + if ((strncasecmp(Name(VtMaster(to)), m, l) == 0) && (vts_can_see(player, where, to))) { + num--; + if (num == 0) { + return to; + } + } + to = to->next; + } + return NULL; + } + + struct vts_instance *vts_match(dbref player, struct vts_instance **vt, int *count, dbref *where, int flags, char *string) + { + int l; + int f; + struct vts_instance *to; + char *p, *m; + int num; + dbref c; + + if ((flags & VMAT_REF) && (vts_getref(&c, vt, count, string))) { + *where = c; + if (vts_can_see(player, c, *vt)) + return *vt; + else + return NULL; + } + if (count) { + *count = strtoul(string, &m, 10); + while (m && *m == ' ') + m++; + if (!m || !*m || (*count < 1)) { + *count = 1; + m = string; + } + } else { + m = string; + } + + num = 1; + p = index(m, '#'); + if (p) { + if (is_integer(p + 1)) { + num = parse_integer(p + 1); + if (num > 0) { + *p = '\0'; + p--; + while (p >= m && *p == ' ') { + *p = '\0'; + p--; + } + } else { + num = 1; + } + } + } + l = strlen(m); + + if (!l) + return NULL; + + to = NULL; + + if (flags & VMAT_INV) { + *where = player; + to = vts_place_match(player, *where, m, l, num); + } + if (!to && (flags & VMAT_LOC)) { + *where = Location(player); + to = vts_place_match(player, *where, m, l, num); + } + if (!to && (flags & VMAT_OLOC)) { + p = index(m, '\''); + if (!p) + return NULL; + *p = '\0'; + if (p == m) + return NULL; + if (*(p - 1) != 's') { + if (*(p + 1) != 's') + return NULL; + p += 2; + } + while (*p == ' ') + p++; + f = 0; + if (flags & VMAT_INV) + f = MAT_POSSESSION; + if (flags & VMAT_LOC) + f |= MAT_NEIGHBOR; + *where = match_result(player, m, TYPE_THING | TYPE_PLAYER, f | MAT_NOISY); + if (!GoodObject(*where)) + return NULL; + to = vts_place_match(player, *where, p, l, num); + } + if (count && to) { + if (Vts_IsAttr(to)) { + *count = 0; + } else if (*count < 1) { + return NULL; + } else if (*count > (int) (to->data)) { + *count = (int) (to->data); + } + } + *vt = to; + return to; + } + + struct vts_instance *vts_transfer(dbref to, dbref from, struct vts_instance *vt, int *count) + { + struct vts_instance *vi, *vr; + dbref master; + char ref[256]; + char *oref; + + switch (Typeof(to)) { + case TYPE_THING: + case TYPE_ROOM: + case TYPE_PLAYER: + break; + default: + return NULL; + } + + master = VtMaster(vt); + if (!Vts_IsAttr(vt)) { + if (*count > (int) vt->data) + *count = (int) vt->data; + vr = vts_create(master, to, *count); + (int) (vt->data) -= *count; + if ((int) (vt->data) == 0) + vts_destroy(from, vt); + } else { + /* First, let's unlink this sorry thing from the old list... */ + vi = vts_data_struc(from); + if (vi == vt) { + /* Nice */ + vts_make_data_struc(from) = vi->next; + } else { + while (vi && vi->next != vt) + vi = vi->next; + if (!vi) + return NULL; + vi->next = vt->next; + } + + /* Link into new location */ + vt->next = NULL; + + vi = vts_data_struc(to); + if (!vi) { + vts_make_data_struc(to) = vt; + } else { + while (vi->next) + vi = vi->next; + vi->next = vt; + } + vr = vt; + } + oref=vtref; + vts_mkref(ref,to,vr,0); + vtref=ref; + if (!WIZ_NOAENTER || !(Wizard(master) && Dark(master))) { + if ((to != NOTHING) && (from != to)) { + did_it(master, master, NULL, NULL, "OXMOVE", NULL, NULL, from); + if (Hearer(master)) { + did_it(master, from, "LEAVE", NULL, "OLEAVE", "has left.", + "ALEAVE", from); + if (Typeof(to) != TYPE_ROOM) + did_it(master, to, NULL, NULL, "OXENTER", NULL, NULL, from); + if (Typeof(from) != TYPE_ROOM) + did_it(master, from, NULL, NULL, "OXLEAVE", NULL, NULL, to); + did_it(master, to, "ENTER", NULL, "OENTER", "has arrived.", + "AENTER", to); + } else { + /* non-listeners only trigger the actions not the messages */ + did_it(master, from, NULL, NULL, NULL, NULL, "ALEAVE", from); + did_it(master, to, NULL, NULL, NULL, NULL, "AENTER", to); + } + } + } + did_it(master, master, "MOVE", NULL, "OMOVE", NULL, "AMOVE", to); + vtref=oref; + + return vr; + } + + void vts_db_dump() + { + FILE *f; + + dbref i; + struct vts_instance *vi; + struct vts_attr *va; + + f = fopen("vts.db", "w"); + if (!f) + return; + for (i = 0; i < db_top; i++) { + if (GoodObject(i)) { + vi = vts_data_struc(i); + if (vi) { + fprintf(f, "#%d\n", i); + while (vi) { + fprintf(f, "-%d\n", VtMaster(vi)); + if (!Vts_IsAttr(vi)) { + fprintf(f, "+%d\n", (int) vi->data); + } else { + va = vi->data; + while (va) { + fprintf(f, "^%s\n", va->aname->key); + fprintf(f, "&%s\n", va->value); + va = va->next; + } + } + vi = vi->next; + } + } + } + } + fclose(f); + } + + void vts_db_read() + { + FILE *f; + char buff[BUFFER_LEN]; + char *p = buff + 1; + char *t; + + dbref i = -1; + dbref master = -1; + struct vts_instance *vi = NULL; + struct vts_instance *vl = NULL; + struct vts_attr *va = NULL; + HASHENT *ahash = NULL; + + f = fopen("vts.db", "r"); + if (!f) { + do_rawlog(LT_TRACE, "No db"); + return; + } + while (!feof(f)) { + + if (!fgets(buff, BUFFER_LEN, f)) + continue; + t = index(buff, '\n'); + if (t) + *t = '\0'; + switch (buff[0]) { + case '#': + i = atoi(p); + if (!GoodObject(i)) + i = -1; + va = NULL; + vi = NULL; + ahash = NULL; + break; + case '-': + master = atoi(p); + if (GoodObject(i) && GoodObject(master) && IS(master, TYPE_THING, THING_VTM)) { + vi = mush_malloc(sizeof(struct vts_instance), "vts_instance"); + memset(vi, 0, sizeof(struct vts_instance)); + vi->master = master; + if (!Vts_IsCount(master)) { + vi->data = NULL; + } else { + (int) (vi->data) = 1; + } + vi->next = NULL; + vl = vts_data_struc(i); + if (!vl) { + vts_make_data_struc(i) = vi; + } else { + while (vl->next) + vl = vl->next; + vl->next = vi; + } + } else { + master = -1; + vi = NULL; + } + va = NULL; + ahash = NULL; + break; + case '+': + if (vi && !Vts_IsAttr(vi)) { + (int) (vi->data) = atoi(p); + if ((int) vi->data < 1) + (int) (vi->data) = 1; + } + break; + case '^': + if (vi && Vts_IsAttr(vi)) { + if (!htab_vatr.buckets) + hash_init(&htab_vatr, 64); + ahash = hash_find(&htab_vatr, p); + if (!ahash) { + ahash = hash_new(&htab_vatr, p); + (int) (ahash->data) = 0; + } + (int) (ahash->data) += 1; + } + break; + case '&': + if (vi && Vts_IsAttr(vi) && ahash) { + va = mush_malloc(sizeof(struct vts_attr) + strlen(p) + 1, "vts_attr"); + strcpy(va->value, p); + va->aname = ahash; + va->next = vi->data; + vi->data = va; + } + ahash = NULL; + break; + default: + fprintf(stderr, "VTS reload: Unhandled line \"%s\".", buff); + } + } + fclose(f); + } + + void vts_data_free(dbref thing) + { + dbref i; + struct vts_instance *vi, *vi_next, *vi_last, *vi_tofree; + + vi = vts_data_struc(thing); + if (vi) { + vts_make_data_struc(thing) = NULL; + while (vi) { + vi_next = vi->next; + vts_free(vi); + vi = vi_next; + } + } + if (IS(thing, TYPE_THING, THING_VTM)) { + for (i = 0; i < db_top; i++) { + if (GoodObject(i) && (vi = vts_data_struc(i))) { + /* Blunder */ + vi_last = vi; + while (vi) { + vi_next = vi->next; + if (VtMaster(vi) == thing) { + /* Ok, we got a match */ + while (vi_next && (VtMaster(vi_next) == thing)) { + /* Make vi_next next good object */ + vi_tofree = vi_next; + vi_next = vi_next->next; + vts_free(vi_tofree); + } + /* Unlink */ + if (vi == vts_data_struc(i)) { + vts_make_data_struc(i) = vi_next; + } else { + vi_last->next = vi_next; + } + vi_last = vi_next; + vts_free(vi); + } else { + vi_last = vi; + } + vi = vi_next; + } + } + } + } + } + + int is_vowel(char c) + { + switch (tolower(c)) { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + return 1; + } + return 0; + } + + char *vts_refstring(struct vts_instance *vt, int count) + { + static char buff[BUFFER_LEN]; + dbref master; + ATTR *a; + int l; + const char *p; + + master = VtMaster(vt); + + p = Name(master); + + if (Vts_IsAttr(vt)) { + sprintf(buff, p); + } else if (count == 1) { + sprintf(buff, "%s %s", is_vowel(*p) ? "an" : "a", p); + } else { + a = atr_get(master, "VTPLURAL"); + if (a) { + sprintf(buff, "%d %s", count, uncompress(a->value)); + } else { + l = strlen(p); + if (*(p + l - 1) == 's') + sprintf(buff, "%d %ses", count, p); + else + sprintf(buff, "%d %ss", count, p); + } + } + return buff; + } + + char *vts_mkconlist(char *buff, char **bp, dbref looker, dbref loc) + { + char **mbp; + char *lbp; + int first = 1; + struct vts_instance *vt; + char ref[256]; + + if (bp) + mbp = bp; + else { + lbp = buff; + mbp = &lbp; + } + + vt = vts_data_struc(loc); + while (vt) { + if (vts_can_see(looker, loc, vt)) { + if (first) + first = 0; + else + safe_chr(' ', buff, mbp); + safe_str(vts_mkref(ref, loc, vt, 0), buff, mbp); + } + vt = vt->next; + } + **mbp = '\0'; + return buff; + } + + + FUNCTION(fun_vts_create) + { + dbref master; + dbref container; + int count; + struct vts_instance *vt; + char ref[256]; + + if (!is_dbref(args[0]) || !is_dbref(args[1]) || (nargs == 3 && !is_integer(args[2]))) { + safe_str(ERR_INVALIDARG, buff, bp); + return; + } + master = parse_dbref(args[0]); + container = parse_dbref(args[1]); + if (!controls(executor, master) || !controls(executor, container)) { + safe_str(ERR_PERMDENIED, buff, bp); + return; + } + if (nargs == 3) + count = parse_integer(args[2]); + else + count = 1; + if (count < 1) { + safe_str(VERR_NEGATIVECOUNT, buff, bp); + return; + } + vt = vts_create(master, container, count); + if (!vt) { + safe_str(VERR_CREATIONFAIL, buff, bp); + return; + } + vts_mkref(ref, container, vt, 0); + safe_str(ref, buff, bp); + } + + FUNCTION(fun_vts_getref) + { + dbref master; + dbref container; + int count; + struct vts_instance *vt; + char ref[256]; + + if (!is_dbref(args[0]) || !is_dbref(args[1]) || (nargs == 3 && !is_integer(args[2]))) { + safe_str(ERR_INVALIDARG, buff, bp); + return; + } + master = parse_dbref(args[0]); + container = parse_dbref(args[1]); + if (nargs == 3) + count = parse_integer(args[2]); + else + count = 1; + if (count < 1) { + safe_str(VERR_NEGATIVECOUNT, buff, bp); + return; + } + if (!Can_Examine(executor, container) && !Can_Examine(executor, master)) { + safe_str(ERR_PERMDENIED, buff, bp); + return; + } + vt = vts_data_struc(container); + while (vt) { + if (VtMaster(vt) == master) { + count--; + if (count == 0) { + vts_mkref(ref, container, vt, 0); + safe_str(ref, buff, bp); + return; + } + } + vt = vt->next; + } + } + + FUNCTION(fun_vts_destroy) + { + dbref container; + struct vts_instance *vt; + + if (!vts_getref(&container, &vt, NULL, args[0])) { + safe_str(VERR_REFMISMATCH, buff, bp); + return; + } + if (!vt) { + safe_str(VERR_NOTFOUND, buff, bp); + return; + } + if (!controls(executor, VtMaster(vt))) { + safe_str(ERR_PERMDENIED, buff, bp); + return; + } + vts_destroy(container, vt); + } + + FUNCTION(fun_vts_attr) + { + dbref container; + struct vts_instance *vt; + struct vts_attr *va, *na; + HASHENT *ahash; + + if (!vts_getref(&container, &vt, NULL, args[0])) { + safe_str(VERR_REFMISMATCH, buff, bp); + return; + } + if (!vt) { + safe_str(VERR_NOTFOUND, buff, bp); + return; + } + if (((nargs == 3) && !controls(executor, VtMaster(vt))) || + ((nargs == 2) && !Can_Examine(executor, VtMaster(vt)))) { + safe_str(ERR_PERMDENIED, buff, bp); + return; + } + if (!Vts_IsAttr(vt)) { + safe_str(VERR_COUNTABLE, buff, bp); + return; + } + upcasestr(args[1]); + va = (struct vts_attr *) vt->data; + + if (htab_vatr.buckets) + ahash = hash_find(&htab_vatr, args[1]); + else + ahash = NULL; + + if (nargs == 2) { + if (!htab_vatr.buckets || !va) + return; + + if (!ahash) + return; + + while (va && va->aname != ahash) + va = va->next; + + if (va) + safe_str(va->value, buff, bp); + } else { + na = NULL; + if (htab_vatr.buckets && va && ahash) { + if (va->aname == ahash) { + vt->data = va->next; + } else { + while (va->next && va->next->aname != ahash) + va = va->next; + na = va->next; + if (na->aname == ahash) { + va->next = na->next; + mush_free(na, "vts_attr"); + } else { + na = NULL; + } + } + } + if (!args[2] || !*args[2]) { + if (na) { + (int) ahash->data -= 1; + if ((int) ahash->data == 0) + hash_delete(&htab_vatr, ahash); + } + return; + } + if (!htab_vatr.buckets) { + hash_init(&htab_vatr, 64); + } + if (!ahash) { + ahash = hash_new(&htab_vatr, args[1]); + if (!ahash) { + safe_str(ERR_HASHFAIL, buff, bp); + return; + } + (int) (ahash->data) = 1; + } + va = mush_malloc(sizeof(struct vts_attr) + strlen(args[2]) + 1, "vts_attr"); + va->next = vt->data; + va->aname = ahash; + strcpy(va->value, args[2]); + vt->data = va; + } + } + + FUNCTION(fun_vts_name) + { + struct vts_instance *vt; + dbref wmatch; + char *p; + int count; + + if (!vts_match(executor, &vt, &count, &wmatch, VMAT_ALL, args[0])) { + safe_str(VERR_NOTFOUND, buff, bp); + return; + } + p = vts_refstring(vt, count); + safe_str(p, buff, bp); + } + + FUNCTION(fun_vts_master) + { + dbref master; + struct vts_instance *vt; + dbref wmatch; + + if (!vts_match(executor, &vt, NULL, &wmatch, VMAT_ALL, args[0])) { + safe_str("#-1", buff, bp); + return; + } + master = VtMaster(vt); + safe_str(unparse_dbref(master), buff, bp); + } + + FUNCTION(fun_vts_container) + { + struct vts_instance *vt; + dbref wmatch; + + if (!vts_match(executor, &vt, NULL, &wmatch, VMAT_ALL, args[0])) { + safe_str("#-1", buff, bp); + return; + } + safe_str(unparse_dbref(wmatch), buff, bp); + } + + FUNCTION(fun_vts_count) + { + struct vts_instance *vt; + dbref wmatch; + int count; + char ref[256]; + + if (!vts_match(executor, &vt, &count, &wmatch, VMAT_ALL, args[0])) { + safe_str("#-1", buff, bp); + return; + } + if (nargs == 1) { + safe_str(unparse_integer(count), buff, bp); + } else { + if (!is_integer(args[1])) { + safe_str(ERR_INTEGER, buff, bp); + return; + } + count = parse_integer(args[1]); + vts_mkref(ref, wmatch, vt, count); + safe_str(ref, buff, bp); + } + } + + FUNCTION(fun_vts_tel) + { + struct vts_instance *vt; + dbref wmatch; + dbref dest; + dbref thing; + int count; + char *oref; + char ref[256]; + dbref absroom; /* "absolute room", for NO_TEL check */ + int rec = 0; /* recursion counter */ + + if (!vts_match(executor, &vt, &count, &wmatch, VMAT_ALL, args[0])) { + safe_str(VERR_REFMISMATCH, buff, bp); + return; + } + thing = VtMaster(vt); + + count = 1; + if ((nargs == 3) && ((count = parse_integer(args[2])) > 1) && (!Vts_IsCount(thing))) { + safe_str(VERR_NONCOUNTABLE, buff, bp); + return; + } + if (count < 1) { + safe_str(VERR_NEGATIVECOUNT, buff, bp); + return; + } + oref = vtref; + vts_mkref(ref, wmatch, vt, count); + vtref = ref; + + + dest = match_result(executor, args[1], TYPE_PLAYER | TYPE_THING | TYPE_ROOM, MAT_EVERYTHING); + + switch (dest) { + case NOTHING: + safe_str(ERR_UNKNOWNDEST, buff, bp); + break; + case AMBIGUOUS: + safe_str(ERR_AMBIGDEST, buff, bp); + break; + case HOME: + dest = Home(thing); + default: + /* check victim, destination types, teleport if ok */ + if (!GoodObject(dest)) { + safe_str(ERR_BADDEST, buff, bp); + } else if (recursive_member(dest, thing, 0) || (thing == dest)) { + safe_str(ERR_BADDEST, buff, bp); + } else { + /* find the "absolute" room */ + absroom = wmatch; + while (GoodObject(absroom) && (Typeof(absroom) != TYPE_ROOM) && (rec <= 15)) { + absroom = db[absroom].location; + rec++; + } + + if (rec > 15) { + safe_str(ERR_CONTAINERS, buff, bp); + } else if (IS(absroom, TYPE_ROOM, ROOM_NO_TEL) + && !controls(executor, absroom) + && !Tel_Anywhere(executor)) { + safe_str(ERR_NOTELFROM, buff, bp); + } else if (GoodObject(Zone(absroom)) && + (IS(absroom, TYPE_ROOM, ROOM_Z_TEL) || + IS(Zone(absroom), TYPE_ROOM, ROOM_Z_TEL)) + && !controls(executor, absroom) + && !Tel_Anywhere(executor) + && (Zone(absroom) != Zone(dest))) { + safe_str(ERR_NOTELZONE, buff, bp); + } else if (Typeof(dest) != TYPE_EXIT) { + if (tport_control_ok(executor, thing, wmatch) && + tport_dest_ok(executor, thing, wmatch) + #ifdef FIXED_FLAG + && (Tel_Anything(executor) || + (!Fixed(Owner(thing)) && !Fixed(Owner(executor)))) + #endif + ) { + vt = vts_transfer(dest, wmatch, vt, &count); + if (vt) { + vts_mkref(ref, dest, vt, 0); + safe_str(ref, buff, bp); + if (wmatch != dest) + did_it(thing, thing, NULL, NULL, "OXTPORT", NULL, NULL, wmatch); + if (wmatch != dest) + did_it(thing, thing, "TPORT", NULL, "OTPORT", NULL, "ATPORT", dest); + } else { + safe_str(ERR_PERMDENIED, buff, bp); + } + } else { + did_it(executor, dest, "EFAIL", "Permission denied.", + "OEFAIL", NULL, "AEFAIL", Location(executor)); + safe_str(ERR_PERMDENIED, buff, bp); + } + } else { + /* attempted teleport to an exit */ + if (controls(executor, thing) || + controls(executor, Location(thing))) { + dest = Location(dest); + vt = vts_transfer(dest, wmatch, vt, &count); + if (vt) { + vts_mkref(ref, dest, vts_transfer(dest, wmatch, vt, &count), 0); + safe_str(ref, buff, bp); + } else { + safe_str(ERR_PERMDENIED, buff, bp); + } + } + } + } + } + vtref = oref; + } + + FUNCTION(fun_vts_lcon) + { + dbref loc; + + if (GoodObject((loc = match_thing(executor, args[0]))) && + (Can_Examine(executor, loc) || (Location(executor) == loc) || + (enactor == loc))) { + vts_mkconlist(buff, bp, executor, loc); + } else { + safe_str("#-1", buff, bp); + } + } + + FUNCTION(fun_vts_locate) + { + dbref whom; + int flags; + char *p; + struct vts_instance *vi; + dbref where; + char ref[256]; + + if (nargs == 2) { + flags = VMAT_ALL; + } else { + p = args[2]; + flags = 0; + while (*p) { + switch (tolower(*p)) { + case 'r': + flags |= VMAT_REF; + break; + case 'i': + flags |= VMAT_INV; + break; + case 'l': + flags |= VMAT_LOC; + break; + case 'o': + flags |= VMAT_OLOC; + break; + default: + safe_str(VERR_MATCHTYPE, buff, bp); + return; + } + p++; + } + } + whom = match_thing(executor, args[0]); + if (!whom) { + safe_str(ERR_NOTFOUND, buff, bp); + return; + } + vi = vts_match(whom, &vi, NULL, &where, flags, args[1]); + if (!Can_Examine(executor, whom) && + (!vi || ( + !Can_Examine(executor, where) && + !Can_Examine(executor, VtMaster(vi)) + ))) { + safe_str(ERR_PERMDENIED, buff, bp); + return; + } + if (!vi) { + safe_str("#-1", buff, bp); + } else { + vts_mkref(ref, where, vi, 0); + safe_str(ref, buff, bp); + } + } + + int vts_drop(dbref player, char *what) + { + struct vts_instance *vt; + dbref loc; + dbref thing; + int count; + char *oref; + char ref[256]; + dbref where; + char *p; + char tbuf1[BUFFER_LEN]; + char tbuf2[BUFFER_LEN]; + + if ((loc = Location(player)) == NOTHING) + return 0; + + if (!vts_match(player, &vt, &count, &where, VMAT_INV | VMAT_REF, what) || (where != player)) + return 0; + + thing = VtMaster(vt); + + oref = vtref; + vts_mkref(ref, where, vt, count); + vtref = ref; + + #ifdef DROP_LOCK + if (!eval_lock(player, thing, Drop_Lock)) { + notify(player, "You can't seem to get rid of that."); + } else if ((Typeof(loc) == TYPE_ROOM) && + !eval_lock(player, loc, Drop_Lock)) { + notify(player, "You can't seem to drop things here."); + } else + #else + if (1) + #endif + { + vt = vts_transfer(loc, player, vt, &count); + if (vt) { + vts_mkref(ref, where, vt, count); + p = vts_refstring(vt, count); + sprintf(tbuf1, "drops %s.", p); + sprintf(tbuf2, "Dropped %s.", p); + did_it(player, thing, "DROP", tbuf2, "ODROP", tbuf1, "ADROP", NOTHING); + } + } + vtref = oref; + return 1; + } + + int vts_give(dbref player, dbref who, char *what) + { + struct vts_instance *vt; + dbref thing; + int count; + char *oref; + char ref[256]; + dbref where; + char *p; + + if (!vts_match(player, &vt, &count, &where, VMAT_INV | VMAT_REF, what) || (where != player)) + return 0; + + thing = VtMaster(vt); + + oref = vtref; + vts_mkref(ref, player, vt, count); + vtref = ref; + + #ifdef GIVE_LOCK + if (!eval_lock(player, thing, Give_Lock)) { + notify(player, "You can't give that away."); + } else + #endif + if (((Typeof(thing) == TYPE_THING) || + (Typeof(thing) == TYPE_PLAYER)) && + ((Flags(who) & ENTER_OK) || controls(player, who))) { + vt = vts_transfer(who, where, vt, &count); + if (vt) { + vts_mkref(ref, where, vt, count); + p = vts_refstring(vt, count); + notify(who, tprintf("%s gave you %s.", Name(player), p)); + notify(player, tprintf("Gave %s to %s.", p, Name(who))); + did_it(who, thing, "SUCCESS", NULL, "OSUCCESS", NULL, "ASUCCESS", + NOTHING); + } + } else { + notify(player, "Permission denied."); + } + + vtref = oref; + return 1; + } + + int vts_get(dbref player, char *what) + { + struct vts_instance *vt; + dbref loc; + dbref thing; + int count; + char *oref; + char ref[256]; + char tbuf1[BUFFER_LEN]; + char tbuf2[BUFFER_LEN]; + dbref where; + char *p; + + if ((loc = Location(player)) == NOTHING) + return 0; + + if (!vts_match(player, &vt, &count, &where, VMAT_LOC | VMAT_OLOC | VMAT_REF, what) || + (!Long_Fingers(player) && (where != loc) && (Location(where) != loc) && (Location(where) != player))) + return 0; + + thing = VtMaster(vt); + + if (!Long_Fingers(player) && (where != player) && ( + (!POSSESSIVE_GET && (where != loc) && (Location(where) != player)) || + (!POSSGET_ON_DISCONNECTED && IS(where, TYPE_PLAYER, PLAYER_CONNECT)))) { + notify(player, "I don't THINK so, thief!"); + return 1; + } + oref = vtref; + vts_mkref(ref, player, vt, count); + vtref = ref; + + if (could_doit(player, thing)) { + vt = vts_transfer(player, where, vt, &count); + if (vt) { + vts_mkref(ref, where, vt, count); + p = vts_refstring(vt, count); + if (where != loc) { + notify(where, tprintf("%s took %s from you.", Name(player), p)); + sprintf(tbuf1, "takes %s from %s.", p, Name(where)); + sprintf(tbuf2, "Took %s from %s.", p, Name(where)); + } else { + sprintf(tbuf1, "takes %s.", p); + sprintf(tbuf2, "Took %s.", p); + } + did_it(player, thing, "SUCCESS", tbuf2, "OSUCCESS", tbuf1, + "ASUCCESS", NOTHING); + } + } else { + did_it(player, thing, "FAILURE", "You can't pick that up.", + "OFAILURE", NULL, "AFAILURE", NOTHING); + } + + vtref = oref; + return 1; + } + + int vts_look_at(dbref player, char *what) + { + struct vts_instance *vt; + dbref thing; + dbref loc; + char *oref; + char ref[256]; + PUEBLOBUFF; + dbref wmatch; + + if ((loc = Location(player)) == NOTHING) + return 0; + + if (!vts_match(player, &vt, NULL, &wmatch, VMAT_ALL, what)) + return 0; + + thing = VtMaster(vt); + + oref = vtref; + vts_mkref(ref, wmatch, vt, 0); + vtref = ref; + + if (controls(player, thing) || Visual(thing)) { + PUSE; + tag_wrap("FONT", "SIZE=+2", vts_unparse_ving(player, wmatch, vt)); + PEND; + notify(player, pbuff); + } + did_it(player, thing, "DESCRIBE", "You see nothing special.", "ODESCRIBE", + NULL, "ADESCRIBE", NOTHING); + + vtref = oref; + + return 1; + } + + int vts_inventory(dbref player, int header) + { + struct vts_instance *vt; + + vt = vts_data_struc(player); + if (!vt) + return 0; + if (vt && header) + notify(player, "You are carrying:"); + while (vt) { + notify(player, vts_unparse_ving(player, player, vt)); + vt = vt->next; + } + return 1; + } + + void vts_look_contents(dbref player, dbref loc, const char *contents_name, int header) + { + struct vts_instance *vt; + char ref[256]; + PUEBLOBUFF; + + if (!(vt = vts_data_struc(loc))) + return; + + if (header) { + PUSE; + tag_wrap("FONT", "SIZE=+1", contents_name); + tag("UL"); + PEND; + notify_nopenter(player, pbuff); + } + while (vt) { + if (vts_can_see(player, loc, vt)) { + PUSE; + tag("LI"); + vts_mkref(ref, loc, vt, 0); + tag_wrap("A", tprintf("XCH_CMD=\"look %s\"", ref), vts_real_unparse(player, loc, vt, 1)); + PEND; + notify_by(loc, player, pbuff); + } + vt = vt->next; + } + + if (header) { + PUSE; + tag_cancel("UL"); + PEND; + notify_by(loc, player, pbuff); + } + vt = vt->next; + } + + int vts_examine(dbref player, char *what, char *aname) + { + struct vts_instance *vt; + struct vts_attr *va; + dbref loc; + dbref thing; + dbref wmatch; + char ref[256]; + + if ((loc = Location(player)) == NOTHING) + return 0; + + if (!vts_match(player, &vt, NULL, &wmatch, VMAT_ALL, what)) + return 0; + + thing = VtMaster(vt); + + notify(player, vts_unparse_ving(player, wmatch, vt)); + if (Can_Examine(player, thing)) { + if (!aname) { + notify(player, tprintf("%-10s: %s", "Master", unparse_object(player, thing))); + notify(player, tprintf("%-10s: %s", "Ref", vts_mkref(ref, wmatch, vt, 0))); + notify(player, tprintf("%-10s: %s", "Location", unparse_object(player, wmatch))); + if (!Vts_IsAttr(vt)) + notify(player, tprintf("%-10s: %d", "Count", (int) (vt->data))); + } + if (Vts_IsAttr(vt)) { + va = vt->data; + while (va) { + if (!aname || local_wild_match(aname, va->aname->key)) + notify(player, tprintf("%-10s: %s", va->aname->key, va->value)); + va = va->next; + } + } + } + return 1; + } + + int vts_command_matchloc(dbref container, dbref player, const char *string) + { + struct vts_instance *vi; + dbref master; + int a; + char ref[256]; + char *oref; + a = 0; + + oref = vtref; + + vi = vts_data_struc(container); + while (vi) { + master = VtMaster(vi); + vts_mkref(ref, container, vi, 0); + vtref = ref; + a += atr_comm_match(master, player, '$', ':', string, 0); + vi = vi->next; + } + vtref = oref; + return a; + } + + int vts_command_match(dbref player, const char *string) + { + int a; + a = vts_command_matchloc(player, player, string); + a += vts_command_matchloc(Location(player), player, string); + return a; + } + + COMMAND (cmd_vts) { + dbref which; + + which = match_thing(player, arg_left); + if (!GoodObject(which)) + return; + + if (SW_ISSET(sw, SWITCH_WIPE)) { + vts_data_free(which); + notify(player, "Thing wiped from VTS storage."); + } + if (SW_ISSET(sw, SWITCH_SET)) { + if (!SW_ISSET(sw, SWITCH_WIPE)) { + notify(player, "You can't use /SET without /WIPE."); + return; + } + if (strcasecmp(arg_right, "none") == 0) { + Toggles(which) &= ~(THING_VTM | THING_VTCOUNT); + } else if (strcasecmp(arg_right, "count") == 0) { + Toggles(which) |= THING_VTM | THING_VTCOUNT; + } else if (strcasecmp(arg_right, "normal") == 0) { + Toggles(which) |= THING_VTM; + Toggles(which) &= ~THING_VTCOUNT; + } else { + notify(player, "Unknown state."); + return; + } + notify(player, "Set."); + } + } *** ../clean/src/Makefile Fri Aug 14 17:50:03 1998 --- src/Makefile Fri Aug 28 00:03:26 1998 *************** *** 110,116 **** version.o \ warnings.o \ wild.o \ ! wiz.o # This is a dummy target, in case you type 'make' in the source --- 110,117 ---- version.o \ warnings.o \ wild.o \ ! wiz.o \ ! vts.o # This is a dummy target, in case you type 'make' in the source *** /dev/null Tue May 5 22:32:27 1998 --- game/txt/hlp/vts.hlp Fri Aug 28 00:12:38 1998 *************** *** 0 **** --- 1,145 ---- + + & VTS + The Virtual Thing System (VTS) is designed to handle things which are + required in any great amount (basically, any item which would otherwise + be @cloned multiple times). All Virtual Things (vings) are instances of + a Master Virtual Thing (VTM), and may be countable, or non-countable; the + former will stack in inventory lists (for instance, "You have twelve vings" + rather than "ving" repeated twelve times), while the latter behave as per + normal objects in this respect. + + The following flags can be set on VTMs: + VTM - Makes the Thing a VTM. + VTCOUNT - Makes vings using this VTM countable + + These can be (re)set via the @vts command. + + See also: @vts, VTS functions, @vtplural, VTREF + + & VTREF + Any Ving in a given location can be referred to by its VTREF, which is + returned by the token %&. + + See also: VTS + + & VTM + This flag is used to denote a Thing as being a VTS Master Thing (VTM), and + can be set with the @vts command. + + See also: VTS, @vts + + & VTCOUNT + This flag is set on a VTM in order to make all the Vings which are connected + to that VTM 'countable'. Countable Vings will stack in inventory lists, + giving 'You have twelve vings' instead of 'ving' being listed twelve times. + It can be set via the @vts command. + + See also: VTS, @vts + + & VTS functions + The following functions exist within the VTS: + + vtattr() vtcount() vtcreate() + vtdestroy() vtlcon() vtloc() + vtlocate() vtmaster() vtname() + vttel() vtref() + + & VTATTR() + vtattr(, [, ]) + + This can only be used on non-countable vings. + + Without specified, this returns the value of the local + attribute on . + When is given, is set to . + + & VTLOC() + vtloc() + + This function returns the dbref of 's location. + + & VTCOUNT() + vtcount() + + This returns the count of , in other words, the number of Vings which + are represented by that object. + For non-countable vings it returns 0. + + & VTCREATE() + vtcreate(, [, ]) + + This creates a new ving, using as its VTM, at , and if + the optional third argument is passed, with count . The count + denotes how many objects are represented by this Ving, for instance, a + coin Ving with a count of 10 would represent ten coins. + + See also: vtdestroy() + + & VTDESTROY + vtdestroy() + + This destroys the Ving with the corresponding vtref. + + See also: vtcreate(), vtref() + + & VTLCON() + vtlcon() + + This returns a list of the vtrefs of all Vings within . + + & VTLOCATE() + vtlocate(, [, ]) + + This function will attempt to find the Ving relative to , + modifying the search based upon the which are specified (if + any). + + Valid parameters are: + r - Match by vtref + i - Match those vings in inventory + l - Match all vings at the same location + o - Match other vings in above location + + This function returns the vtref of the matched Ving. + + & VTMASTER() + vtmaster() + + This returns the VTM of . + + & VTNAME() + vtname() + + This returns the name of , including the count value, if is + countable. + + See also: @vtplural + + & VTTEL() + vttel(, [, ]) + + This teleports of to . By default, is + equal to 1, and the function will return the new vtref. + + & VTREF() + vtref(, [, ]) + + This returns the vtref of Vings at with VTM , and + optionally , which is a number specifying which one you want, + in case you don't want the first one. + + & @VTPLURAL + @vtplural = + + Sets the VTPLURAL attribute of a VTM. + + See also: VTS + + & @VTS + @vts/set/wipe = + @vts/wipe + + Only wizards may use this command. It sets/unsets the VTS and/or + VTCOUNT flag and wipes out any instances of the given VTM that may exist. + + See also: VTS