#include <ctype.h> #include <string.h> #include "config.h" #include "db.h" #include "externs.h" #include "interface.h" #include "attrib.h" #include "oldattrib.h" #ifdef MEM_CHECK #include "mem_check.h" #endif #ifdef USE_NALLOC #include "nalloc.h" extern NALLOC *db_strings; #endif /* attribute list */ ATTR attr[] = { { (char *) "AAHEAR", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ACLONE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ACONNECT", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ADEATH", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ADESCRIBE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ADISCONNECT", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ADROP", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "AEFAIL", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "AENTER", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "AFAILURE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "AHEAR", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ALEAVE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "AMHEAR", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "AMOVE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "APAYMENT", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ASUCCESS", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "AUSE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "AWAY", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "CHARGES", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "CLASS", AF_NOPROG, NULL, 0 }, { (char *) "COST", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "DEATH", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "DESCRIBE", AF_NOPROG, NULL, 0 }, { (char *) "DOES", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "DROP", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "EALIAS", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "EFAIL", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ENTER", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "FAILURE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "HAVEN", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "IDESCRIBE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "IDLE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "LALIAS", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "LAST", AF_WIZARD | AF_LOCKED, NULL, 0 }, { (char *) "LASTSITE", AF_LOCKED | AF_ODARK, NULL, 0 }, { (char *) "LEAVE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "LISTEN", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "MOVE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ODEATH", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ODESCRIBE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "ODROP", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "OEFAIL", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "OENTER", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "OFAILURE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "OLEAVE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "OMOVE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "OPAYMENT", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "OSUCCESS", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "OUSE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "OXENTER", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "OXLEAVE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "PAYMENT", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "QUEUE", AF_ODARK | AF_WIZARD, NULL, 0 }, { (char *) "RACE", AF_NOPROG | AF_WIZARD, NULL, 0 }, { (char *) "RQUOTA", AF_DARK | AF_WIZARD, NULL, 0 }, { (char *) "RUNOUT", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "SEX", AF_NOPROG, NULL, 0 }, { (char *) "STARTUP", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "SUCCESS", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "USE", AF_ODARK | AF_NOPROG, NULL, 0 }, { (char *) "VA", AF_ODARK, NULL, 0 }, { (char *) "VB", AF_ODARK, NULL, 0 }, { (char *) "VC", AF_ODARK, NULL, 0 }, { (char *) "VD", AF_ODARK, NULL, 0 }, { (char *) "VE", AF_ODARK, NULL, 0 }, { (char *) "VF", AF_ODARK, NULL, 0 }, { (char *) "VG", AF_ODARK, NULL, 0 }, { (char *) "VH", AF_ODARK, NULL, 0 }, { (char *) "VI", AF_ODARK, NULL, 0 }, { (char *) "VJ", AF_ODARK, NULL, 0 }, { (char *) "VK", AF_ODARK, NULL, 0 }, { (char *) "VL", AF_ODARK, NULL, 0 }, { (char *) "VM", AF_ODARK, NULL, 0 }, { (char *) "VN", AF_ODARK, NULL, 0 }, { (char *) "VO", AF_ODARK, NULL, 0 }, { (char *) "VP", AF_ODARK, NULL, 0 }, { (char *) "VQ", AF_ODARK, NULL, 0 }, { (char *) "VR", AF_ODARK, NULL, 0 }, { (char *) "VS", AF_ODARK, NULL, 0 }, { (char *) "VT", AF_ODARK, NULL, 0 }, { (char *) "VU", AF_ODARK, NULL, 0 }, { (char *) "VV", AF_ODARK, NULL, 0 }, { (char *) "VW", AF_ODARK, NULL, 0 }, { (char *) "VX", AF_ODARK, NULL, 0 }, { (char *) "VY", AF_ODARK, NULL, 0 }, { (char *) "VZ", AF_ODARK, NULL, 0 }, { (char *) "WA", AF_ODARK, NULL, 0 }, { (char *) "WB", AF_ODARK, NULL, 0 }, { (char *) "WC", AF_ODARK, NULL, 0 }, { (char *) "WD", AF_ODARK, NULL, 0 }, { (char *) "WE", AF_ODARK, NULL, 0 }, { (char *) "WF", AF_ODARK, NULL, 0 }, { (char *) "WG", AF_ODARK, NULL, 0 }, { (char *) "WH", AF_ODARK, NULL, 0 }, { (char *) "WI", AF_ODARK, NULL, 0 }, { (char *) "WJ", AF_ODARK, NULL, 0 }, { (char *) "WK", AF_ODARK, NULL, 0 }, { (char *) "WL", AF_ODARK, NULL, 0 }, { (char *) "WM", AF_ODARK, NULL, 0 }, { (char *) "WN", AF_ODARK, NULL, 0 }, { (char *) "WO", AF_ODARK, NULL, 0 }, { (char *) "WP", AF_ODARK, NULL, 0 }, { (char *) "WQ", AF_ODARK, NULL, 0 }, { (char *) "WR", AF_ODARK, NULL, 0 }, { (char *) "WS", AF_ODARK, NULL, 0 }, { (char *) "WT", AF_ODARK, NULL, 0 }, { (char *) "WU", AF_ODARK, NULL, 0 }, { (char *) "WV", AF_ODARK, NULL, 0 }, { (char *) "WW", AF_ODARK, NULL, 0 }, { (char *) "WX", AF_ODARK, NULL, 0 }, { (char *) "WY", AF_ODARK, NULL, 0 }, { (char *) "WZ", AF_ODARK, NULL, 0 }, { (char *) "XA", AF_ODARK, NULL, 0 }, { (char *) "XB", AF_ODARK, NULL, 0 }, { (char *) "XC", AF_ODARK, NULL, 0 }, { (char *) "XD", AF_ODARK, NULL, 0 }, { (char *) "XE", AF_ODARK, NULL, 0 }, { (char *) "XF", AF_ODARK, NULL, 0 }, { (char *) "XG", AF_ODARK, NULL, 0 }, { (char *) "XH", AF_ODARK, NULL, 0 }, { (char *) "XI", AF_ODARK, NULL, 0 }, { (char *) "XJ", AF_ODARK, NULL, 0 }, { (char *) "XK", AF_ODARK, NULL, 0 }, { (char *) "XL", AF_ODARK, NULL, 0 }, { (char *) "XM", AF_ODARK, NULL, 0 }, { (char *) "XN", AF_ODARK, NULL, 0 }, { (char *) "XO", AF_ODARK, NULL, 0 }, { (char *) "XP", AF_ODARK, NULL, 0 }, { (char *) "XQ", AF_ODARK, NULL, 0 }, { (char *) "XR", AF_ODARK, NULL, 0 }, { (char *) "XS", AF_ODARK, NULL, 0 }, { (char *) "XT", AF_ODARK, NULL, 0 }, { (char *) "XU", AF_ODARK, NULL, 0 }, { (char *) "XV", AF_ODARK, NULL, 0 }, { (char *) "XW", AF_ODARK, NULL, 0 }, { (char *) "XX", AF_ODARK, NULL, 0 }, { (char *) "XY", AF_ODARK, NULL, 0 }, { (char *) "XZ", AF_ODARK, NULL, 0 }, { (char *) "XYXXY", AF_DARK | AF_NOPROG | AF_LOCKED | AF_WIZARD, NULL, 0 }, { NULL, 0, NULL, 0 } }; char *clean_atr_name(s) char *s; { static char buf[BUFFER_LEN]; char *q = buf; char *a; if(!*s || !s) { sprintf(buf, "NULL"); return buf; } if(!string_compare("KILL", s)) { sprintf(buf, "DEATH"); return buf; } if(!string_compare("KILL", s+1) && (*s == 'o' || *s == 'O' || *s == 'a' || *s == 'A')) { sprintf(buf, "%c%s", *s, s+1); return buf; } for(a = s; *a; a++) if(isprint(*a) && !isspace(*a)) *q++ = *a; *q = '\0'; return buf; } ATTR *atr_str(s) char *s; { ATTR *result; ATTR *a = attr; int done = 0; char *q; #ifdef USE_NALLOC result = (ATTR *)na_alloc(db_strings, sizeof (ATTR)); #else result = (ATTR *)malloc(sizeof (ATTR)); #endif q = clean_atr_name(s); #ifdef USE_NALLOC result->name = (char *) na_ualloc(db_strings, (strlen(q) + 1)); #else result->name = (char *) malloc(strlen(q)+1); #endif #ifdef MEM_CHECK add_check("attribute"); add_check("attribute_name"); #endif strcpy(result->name, strupper(q)); result->flags = AF_ODARK; while (a->name && !done) { if(!string_compare(result->name, a->name)) { result->flags = a->flags; done++; } a++; } return result; } struct boolatr *alloc_atr(name, s) char *name; char *s; { struct boolatr *a; const char *p; #ifdef USE_NALLOC a = (struct boolatr *)na_alloc(db_strings, sizeof(struct boolatr)); a->name = (char *)na_ualloc(db_strings, strlen(name) + 1); #else a = (struct boolatr *)malloc(sizeof (struct boolatr)); a->name = (char *)malloc(strlen(name)+1); #endif strcpy(a->name,name); p = compress(s); #ifdef USE_NALLOC a->text = (char *)na_ualloc(db_strings, strlen(p) + 1); #else a->text = (char *)malloc(strlen(p)+1); #endif strcpy(a->text, p); #ifdef MEM_CHECK add_check("bool_atr"); add_check("bool_atr_name"); add_check("bool_atr_val"); #endif return a; } void atr_clr(thing, atr) dbref thing; char *atr; { ALIST *ptr = db[thing].list; while(ptr) { if(!string_compare(atr, AL_NAME(ptr))) { AL_DISPOSE(ptr); return; } ptr = AL_NEXT(ptr); } } ALIST *AL_MAKE(type, next, string, owner, flags) char *type; ALIST *next; char *string; dbref owner; dbref flags; { ALIST *ptr; const char *p; #ifdef USE_NALLOC ptr = (ALIST *)na_alloc(db_strings, sizeof(ALIST)); #else ptr = (ALIST *)malloc(sizeof(ALIST)); #endif AL_ATTR(ptr) = atr_str(type); AL_CREATOR(ptr) = owner; p = compress(string); #ifdef USE_NALLOC AL_STR(ptr) = (char *)na_ualloc(db_strings, strlen(p) + 1); #else AL_STR(ptr) = (char *)malloc(strlen(p) + 1); #endif #ifdef MEM_CHECK add_check("ALIST"); add_check("attribute_value"); #endif strcpy(AL_STR(ptr), p); if(flags != NOTHING) AL_FLAGS(ptr) |= flags; AL_NEXT(ptr) = next; return ptr; } void atr_new_add(thing, atr, s, player, flags) dbref thing; char *atr; char *s; dbref player; dbref flags; { s = (char *) compress(s); db[thing].list = AL_MAKE(atr, db[thing].list, s, player, flags); } int atr_add(thing, atr, s, player, flags) dbref thing; char *atr; char *s; dbref player; dbref flags; { ALIST *ptr; dbref privs; if (thing == 0) { privs = GOD; /* should only be hit by first couple objects */ db[player].owner = GOD; } else privs = db[player].owner; if(!s) s = (char *)""; for (ptr = db[thing].list; (ptr && string_compare(atr, AL_NAME(ptr))); ptr = AL_NEXT(ptr)); if(!*s) { if(ptr) if(!Wizard(privs) && ((AL_FLAGS(ptr) & AF_WIZARD) || ((privs != db[AL_CREATOR(ptr)].owner) && (AL_FLAGS(ptr) & AF_LOCKED)))) { return -1; } else { AL_DISPOSE(ptr); return 1; } else return 0; } s = (char *) compress(s); if(!ptr) { db[thing].list = AL_MAKE(atr, db[thing].list, s, privs, flags); return 1; } else { if(!Wizard(privs) && ((AL_FLAGS(ptr) & AF_WIZARD) || ((privs != db[AL_CREATOR(ptr)].owner) && (AL_FLAGS(ptr) & AF_LOCKED)))) { return -1; } else { const char *p; #ifdef USE_NALLOC na_unalloc(db_strings, (char *) AL_STR(ptr)); #else free((char *) AL_STR(ptr)); #endif #ifdef MEM_CHECK del_check("attribute_value"); #endif p = compress(s); #ifdef USE_NALLOC AL_STR(ptr) = (char *)na_ualloc(db_strings, strlen(p)+1); #else AL_STR(ptr) = (char *)malloc(strlen(p)+1); #endif #ifdef MEM_CHECK add_check("attribute_value"); #endif strcpy(AL_STR(ptr), p); AL_CREATOR(ptr) = db[privs].owner; if(flags != NOTHING) AL_FLAGS(ptr) = flags; if(AL_BAD(ptr)) AL_FLAGS(ptr) &= ~AF_NUKED; return 1; } } /*NOTREACHED*/ return 0; } ATTR *atr_get(thing, atr) dbref thing; char *atr; { ALIST *ptr; if(thing == NOTHING || !atr) return NULL; for(ptr = db[thing].list; ptr; ptr = AL_NEXT(ptr)) { if(!AL_BAD(ptr) && !string_compare(AL_NAME(ptr), atr)) { return AL_ATTR(ptr); } } for(ptr = db[thing].list; ptr; ptr = AL_NEXT(ptr)) { if(!AL_BAD(ptr) && string_prefix(AL_NAME(ptr), atr)) { return(AL_ATTR(ptr)); } } return (ATTR *)NULL; } void free_attrib(thisattr) ATTR *thisattr; { if (thisattr) { #ifdef USE_NALLOC if (thisattr->name) na_unalloc(db_strings, (char *) thisattr->name); if (thisattr->value) na_unalloc(db_strings, (char *) thisattr->value); na_unalloc(db_strings, (char *) thisattr); #else if (thisattr->name) free((char *) thisattr->name); if (thisattr->value) free((char *) thisattr->value); free((char *) thisattr); #endif } #ifdef MEM_CHECK del_check("attribute_name"); del_check("attribute_value"); del_check("attribute"); #endif } void atr_free(thing) dbref thing; { ALIST *ptr, *next; for(ptr = db[thing].list; ptr; ptr = next) { next = AL_NEXT(ptr); free_attrib(AL_ATTR(ptr)); #ifdef USE_NALLOC na_unalloc(db_strings, (char *) ptr); #else free((char *) ptr); #endif #ifdef MEM_CHECK del_check("ALIST"); #endif } db[thing].list = (ALIST *)NULL; } /* reconstruct an attribute list */ void atr_collect(thing) dbref thing; { ALIST *ptr, *next; ptr = db[thing].list; db[thing].list = NULL; while(ptr) { if(!AL_BAD(ptr)) { db[thing].list = AL_MAKE(AL_NAME(ptr), db[thing].list, AL_STR(ptr), AL_CREATOR(ptr), AL_FLAGS(ptr)); } next = AL_NEXT(ptr); free_attrib(AL_ATTR(ptr)); #ifdef USE_NALLOC na_unalloc(db_strings, (char *)ptr); #else free((char *) ptr); #endif #ifdef MEM_CHECK del_check("ALIST"); #endif ptr = next; } } void atr_cpy(dest, source) dbref dest, source; { ALIST *ptr; ptr = db[source].list; db[dest].list = NULL; while(ptr) { if(!AL_BAD(ptr)) { db[dest].list = AL_MAKE(AL_NAME(ptr), db[dest].list, AL_STR(ptr), AL_CREATOR(ptr), AL_FLAGS(ptr)); } ptr = AL_NEXT(ptr); } } const char *convert_atr(oldatr) dbref oldatr; { const static char result[MAX_COMMAND_LEN]; int factor = 0; switch(oldatr) { case A_OSUCC: return "OSUCCESS"; case A_OFAIL: return "OFAILURE"; case A_FAIL: return "FAILURE"; case A_SUCC: return "SUCCESS"; case A_PASS: return "XYXXY"; case A_DESC: return "DESCRIBE"; case A_SEX: return "SEX"; case A_ODROP: return "ODROP"; case A_DROP: return "DROP"; case A_OKILL: return "OKILL"; case A_KILL: return "KILL"; case A_ASUCC: return "ASUCCESS"; case A_AFAIL: return "AFAILURE"; case A_ADROP: return "ADROP"; case A_AKILL: return "AKILL"; case A_USE: return "DOES"; case A_CHARGES: return "CHARGES"; case A_RUNOUT: return "RUNOUT"; case A_STARTUP: return "STARTUP"; case A_ACLONE: return "ACLONE"; case A_APAY: return "APAYMENT"; case A_OPAY: return "OPAYMENT"; case A_PAY: return "PAYMENT"; case A_COST: return "COST"; case A_RAND: return "RAND"; case A_LISTEN: return "LISTEN"; case A_AAHEAR: return "AAHEAR"; case A_AMHEAR: return "AMHEAR"; case A_AHEAR: return "AHEAR"; case A_LAST: return "LAST"; case A_QUEUE: return "QUEUE"; case A_IDESC: return "IDESCRIBE"; case A_ENTER: return "ENTER"; case A_OXENTER: return "OXENTER"; case A_AENTER: return "AENTER"; case A_ADESC: return "ADESCRIBE"; case A_ODESC: return "ODESCRIBE"; case A_RQUOTA: return "RQUOTA"; case A_ACONNECT: return "ACONNECT"; case A_ADISCONNECT: return "ADISCONNECT"; case A_LEAVE: return "LEAVE"; case A_ALEAVE: return "ALEAVE"; case A_OLEAVE: return "OLEAVE"; case A_OENTER: return "OENTER"; case A_OXLEAVE: return "OXLEAVE"; default: if(oldatr >= 100 && oldatr < 126) factor = 0; else if(oldatr >= 126 && oldatr < 152) factor = 1; else if(oldatr >= 152 && oldatr < 178) factor = 2; else { fprintf(stderr, "ERROR: Invalid attribute number in convert_atr. aborting.\n"); fflush(stderr); abort(); } sprintf((char *)result, "%c%c", 'V'+factor, oldatr - (100 + (factor * 26)) + 'A'); return result; } /*NOTREACHED*/ return ""; } ATTR *atr_match(string) char *string; { ATTR *a = attr; while (a->name) { if(!string_compare(string, a->name)) { return a; } a++; } return (ATTR *)NULL; } int atr_comm_match(thing, player, type, end, str) dbref thing, player; char type, end; char *str; { ALIST *ptr; int match = 0; char tbuf1[BUFFER_LEN]; char *s; if(thing < 0 || thing >= db_top) return 0; for(ptr = db[thing].list; ptr; ptr = AL_NEXT(ptr)) { if(!AL_BAD(ptr) && (*AL_STR(ptr) == type) && !(AL_FLAGS(ptr) & AF_NOPROG)){ strcpy(tbuf1, uncompress(AL_STR(ptr))); for(s = tbuf1 + 1; *s && (*s != end); s++); if(!*s) continue; *s++ = '\0'; if(wild_match(tbuf1 + 1, str)) { match = 1; if ((type == '$') && (!eval_boolexp(player, db[thing].usekey, thing, 0, USELOCK))) notify(player, "Permission denied."); else parse_que(thing, s, player); } } } return match; } void do_atrlock(player, arg1, arg2) dbref player; const char *arg1, *arg2; { dbref thing; char *p; ALIST *ptr; int status; if(!arg2 || !*arg2) status = 0; else { if(!string_compare(arg2, "on")) { status = 1; } else if(!string_compare(arg2, "off")) { status = 2; } else status = 0; } if(!arg1 || !*arg1) { notify(player, "You need to give an object/attribute pair."); return; } if(!(p = index(arg1, '/')) || !(*(p+1))) { notify(player, "You need to give an object/attribute pair."); return; } *p++ = '\0'; init_match(player, arg1, NOTYPE); match_everything(); if((thing = noisy_match_result()) == NOTHING) return; for(ptr = db[thing].list; ptr; ptr = AL_NEXT(ptr)) if(!AL_BAD(ptr) && !string_compare(AL_NAME(ptr), p)) break; if(!ptr) for(ptr = db[thing].list; ptr; ptr = AL_NEXT(ptr)) if(!AL_BAD(ptr) && string_prefix(AL_NAME(ptr), p)) break; if(ptr) { if(!status) { notify(player, tprintf("That attribute is %slocked.", (AL_FLAGS(ptr) & AF_LOCKED) ? "" : "un")); return; } else if(!Wizard(player) && (db[AL_CREATOR(ptr)].owner != db[player].owner)) { notify(player, "You need to own the attribute to change its lock."); return; } else { if(status == 1) { AL_FLAGS(ptr) |= AF_LOCKED; notify(player, "Attribute locked."); return; } else if(status == 2) { AL_FLAGS(ptr) &= ~AF_LOCKED; notify(player, "Attribute unlocked."); return; } else { notify(player, "Invalid status on atrlock.. Notify god."); return; } } } else notify(player, "No such attribute."); return; } void do_atrchown(player, arg1, arg2) dbref player; const char *arg1, *arg2; { dbref thing, new_owner; char *p; ALIST *ptr; if(!arg1 || !*arg1) { notify(player, "You need to give an object/attribute pair."); return; } if(!(p = index(arg1, '/')) || !(*(p+1))) { notify(player, "You need to give an object/attribute pair."); return; } *p++ = '\0'; init_match(player, arg1, NOTYPE); match_everything(); if((thing = noisy_match_result()) == NOTHING) return; if((!arg2 && !*arg2) || !string_compare(arg2, "me")) new_owner = player; else new_owner = lookup_player(arg2); if(new_owner == NOTHING) { notify(player, "I can't find that player"); return; } for(ptr = db[thing].list; ptr; ptr = AL_NEXT(ptr)) if(!AL_BAD(ptr) && !string_compare(AL_NAME(ptr), p)) break; if(!ptr) for(ptr = db[thing].list; ptr; ptr = AL_NEXT(ptr)) if(!AL_BAD(ptr) && string_prefix(AL_NAME(ptr), p)) break; if(ptr) { if((controls(player, thing) && !(AL_FLAGS(ptr) & AF_LOCKED)) || (db[player].owner == db[AL_CREATOR(ptr)].owner)) { if(new_owner != db[thing].owner && !Wizard(player)) { notify(player, "You can only chown an attribute to the current owner of the object."); return; } AL_CREATOR(ptr) = db[new_owner].owner; notify(player, "Attribute owner changed."); return; } else { notify(player, "You don't have the permission to chown that."); return; } } else notify(player, "No such attribute."); } ATTR *atr_complete_match(player, atr, privs) dbref player; char *atr; dbref privs; { ATTR *a; char *s = atr; dbref thing; if(*s == '_') s++; if((a = atr_get(player, s)) != NULL) { if(!controls(privs, player) && db[privs].owner != db[a->creator].owner && (a->flags & AF_ODARK)) { DOLIST(thing, db[player].contents) { if((a = atr_get(thing, s)) != NULL) { if(!controls(privs, player) && db[privs].owner != db[a->creator].owner && (a->flags & AF_ODARK)) { return NULL; } else { return a; } } } } else { return a; } } return NULL; }