/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/set.c,v 1.13 90/09/18 08:02:06 rearl Exp $ */ /* * $Log: set.c,v $ * Revision 1.13 90/09/18 08:02:06 rearl * Player hash table mods, took out FILTER. * * Revision 1.12 90/09/16 04:42:56 rearl * Preparation code added for disk-based MUCK. * * Revision 1.11 90/09/10 02:23:11 rearl * Took out get_string call. * * Revision 1.10 90/08/27 03:33:18 rearl * Fixed bug involving NULL player password entries. * * Revision 1.9 90/08/11 04:10:15 rearl * *** empty log message *** * * Revision 1.8 90/08/06 03:51:35 rearl * Redid @chown thing = me, the easy way... * * Revision 1.7 90/08/06 02:51:18 rearl * Added restricted() routine from predicates.c, any restricted * flags should be checked in there from now on. * * Revision 1.6 90/08/05 03:20:01 rearl * Redid matching routines. * * Revision 1.5 90/08/02 18:51:26 rearl * Enabled @chown <thing> = me in addition to @chown <thing>. * * Revision 1.4 90/07/29 17:43:30 rearl * Allows players to capitalize/decapitalize their names, added support * for setting programs DEBUG (DARK). * * * Revision 1.3 90/07/21 16:31:50 casie * added log_misc * * Revision 1.2 90/07/21 05:32:41 casie * Changed player chown to allow rooms and exits as well as things. * * Revision 1.1 90/07/19 23:04:09 casie * Initial revision * * */ #include "copyright.h" #include "config.h" /* commands which set parameters */ #include <stdio.h> #include <ctype.h> #include "strings.h" #include "db.h" #include "params.h" #include "match.h" #include "interface.h" #include "externs.h" dbref match_controlled(dbref player, const char *name) { dbref match; struct match_data md; init_match(player, name, NOTYPE, &md); match_everything(&md); match = noisy_match_result(&md); if(match != NOTHING && !(controls(player, match) || player == OWNER(match)) && !God(player)) { notify(player, "Permission denied."); return NOTHING; } else { return match; } } void do_name(dbref player, const char *name, char *newname) { dbref thing; char *password; if((thing = match_controlled(player, name)) != NOTHING) { /* check for bad name */ if(*newname == '\0') { notify(player, "Give it what new name?"); return; } /* check for renaming a player */ if(Typeof(thing) == TYPE_PLAYER) { /* split off password */ for(password = newname; *password && !isspace(*password); password++); /* eat whitespace */ if(*password) { *password++ = '\0'; /* terminate name */ while(*password && isspace(*password)) password++; } /* check for null password */ if(!*password) { notify(player, "You must specify a password to change a player name."); notify(player, "E.g.: name player = newname password"); return; } else if(strcmp(password, DoNull(DBFETCH(thing)->sp.player.password))) { notify(player, "Incorrect password."); return; } else if(string_compare(newname, NAME(thing)) && !ok_player_name(newname)) { notify(player, "You can't give a player that name."); return; } /* everything ok, notify */ log_status("NAME CHANGE: %s(#%d) to %s\n", NAME(thing), thing, newname); delete_player(thing); if (NAME(thing)) free((void *) NAME(thing)); NAME(thing) = alloc_string(newname); add_player(thing); notify(player, "Name set."); return; } else { if(!ok_name(newname)) { notify(player, "That is not a reasonable name."); return; } } /* everything ok, change the name */ if(NAME(thing)) { free((void *) NAME(thing)); } NAME(thing) = alloc_string(newname); notify(player, "Name set."); DBDIRTY(thing); } } void do_attr(dbref player, const char *name, const char *what, const char *value) { dbref thing; if((thing = match_controlled(player, what)) != NOTHING) { char *attribute = (char *) calloc(strlen(name) + 2, sizeof(char)); *attribute = PROP_WIZARD; strcat(attribute, name); if(value && *value) { add_property(thing, attribute, value); sprintf(buf,"%s -- %c%s set to \"%s\"", NAME(thing), PROP_WIZARD, name, value); notify(player, buf); } else { remove_property(thing, attribute); sprintf(buf,"%s -- %c%s removed.", NAME(thing), PROP_WIZARD, name); notify(player, buf); } free((void *) attribute); } } void do_lock(dbref player, const char *name, const char *keyname) { dbref thing; struct boolexp *key; struct match_data md; init_match(player, name, NOTYPE, &md); match_everything(&md); switch(thing = match_result(&md)) { case NOTHING: notify(player, "I don't see what you want to lock!"); return; case AMBIGUOUS: notify(player, "I don't know which one you want to lock!"); return; default: if(!controls(player, thing)) { notify(player, "You can't lock that!"); return; } break; } key = parse_boolexp(player, keyname); if(key == TRUE_BOOLEXP) { notify(player, "I don't understand that key."); } else { /* everything ok, do it */ free_boolexp(DBFETCH(thing)->key); DBSTORE(thing, key, key); notify(player, "Locked."); } } void do_unlock(dbref player, const char *name) { dbref thing; if((thing = match_controlled(player, name)) != NOTHING) { free_boolexp(DBFETCH(thing)->key); DBSTORE(thing, key, TRUE_BOOLEXP); notify(player, "Unlocked."); } } void do_unlink(dbref player, const char *name) { dbref exit; struct match_data md; init_match(player, name, TYPE_EXIT, &md); match_all_exits(&md); match_here(&md); match_absolute(&md); switch(exit = match_result(&md)) { case NOTHING: notify(player, "Unlink what?"); break; case AMBIGUOUS: notify(player, "I don't know which one you mean!"); break; default: if(!controls(player, exit)) { notify(player, "Permission denied."); } else { switch(Typeof(exit)) { case TYPE_EXIT: if(DBFETCH(exit)->sp.exit.ndest != 0) { DBFETCH(OWNER(exit))->sp.player.pennies += LINK_COST; DBDIRTY(OWNER(exit)); } DBSTORE(exit, sp.exit.ndest, 0); if (DBFETCH(exit)->sp.exit.dest) { free ((void *) DBFETCH(exit)->sp.exit.dest); DBSTORE(exit, sp.exit.dest, NULL); } notify(player, "Unlinked."); break; case TYPE_ROOM: DBSTORE(exit, link, NOTHING); notify(player, "Dropto removed."); break; default: notify(player, "You can't unlink that!"); break; } } } } #ifdef PLAYER_CHOWN void do_chown(dbref player, const char *name, const char *newowner) { dbref thing; dbref owner; struct match_data md; if (!*name) { notify(player, "You must specify what you want to take ownership of."); return; } init_match(player, name, NOTYPE, &md); match_everything(&md); if((thing = noisy_match_result(&md)) == NOTHING) return; if(*newowner && string_compare(newowner, "me")) { if ((owner = lookup_player(newowner)) == NOTHING) { notify(player, "I couldn't find that player."); return; } } else { owner = player; } if(!Wizard(player) && player != owner) { notify(player, "Only wizards can transfer ownership to others."); return; } if (!Wizard(player) && (!(FLAGS(thing) & CHOWN_OK) || Typeof(thing) == TYPE_PROGRAM)) { notify(player, "You can't take possession of that."); return; } switch (Typeof(thing)) { case TYPE_ROOM: if (!Arch(player) && DBFETCH(player)->location != thing) { notify(player, "You can only chown \"here\"."); return; } OWNER(thing) = owner; break; case TYPE_THING: if (!Arch(player) && DBFETCH(thing)->location != player) { notify(player, "You aren't carrying that."); return; } if (Typeof(player) == TYPE_PLAYER) OWNER(thing) = owner; FLAGS(thing) |= HALTED; /* halted... igg */ halt_long(thing); break; case TYPE_PLAYER: if(!Wizard(player) || Wizard(thing)) { notify(player, "Players always own themselves."); return; } DBFETCH(thing)->owner = owner; /* gotta do it w/o OWNER, cause owner */ break; /* is messed up for players. */ case TYPE_EXIT: OWNER(thing) = owner; break; #ifdef RECYCLE case TYPE_GARBAGE: notify(player, "No one wants to own garbage."); return; #endif default: if(!Arch(player)) { notify(player,"Permission denied."); return; } OWNER(thing) = owner; break; } if (owner == player) notify(player, "Owner changed to you."); else { char buf[BUFFER_LEN]; sprintf(buf, "Owner changed to %s.", unparse_object(player, owner)); notify(player, buf); } DBDIRTY(thing); } #else /* without PLAYER_CHOWN */ void do_chown(dbref player, const char *name, const char *newowner) { dbref thing; dbref owner; struct match_data md; if(!Arch(player)) { notify(player, "Permission denied."); return; } init_match(player, name, NOTYPE, &md); match_everything(&md); if((thing = noisy_match_result(&md)) == NOTHING) return; if((owner = lookup_player(newowner)) == NOTHING) { notify(player, "I couldn't find that player."); return; } switch (Typeof(thing)) { case TYPE_PLAYER: notify(player, "Players always own themselves."); return; case TYPE_ROOM: case TYPE_THING: case TYPE_EXIT: case TYPE_PROGRAM: OWNER(thing) = owner; #ifdef RECYCLE case TYPE_GARBAGE: notify(player, "No one wants to own garbage."); return; #endif } notify(player, "Owner changed."); DBDIRTY(thing); } #endif /* PLAYER_CHOWN */ /* Note: Gender code taken out. All gender references are now to be handled by property lists... Setting of flags and property code done here. Note that the PROP_DELIMITER identifies when you're setting a property. A @set <thing>= : will clear all properties. A @set <thing>= type: will remove that property. A @set <thing>= type: class will add that property or replace it. */ void do_set(dbref player, const char *name, const char *flag) { dbref thing; const char *p; object_flag_type f; int did_hear; /* hmm.... whether it heard before we * did a set on it. */ /* find thing */ if((thing = match_controlled(player, name)) == NOTHING) return; /* move p past NOT_TOKEN if present */ for(p = flag; *p && (*p == NOT_TOKEN || isspace(*p)); p++); /* Now we check to see if it's a property reference */ /* if this gets changed, please also modify boolexp.c */ if (index(flag, PROP_DELIMITER)) { /* copy the string so we can muck with it */ char *type = alloc_string(flag); /* type */ char *class = (char *)index(type, PROP_DELIMITER); /* class */ char *x; /* to preserve string location so we can free it */ char *temp; struct plist *prop, *last; x = type; while (isspace(*type) && (*type != PROP_DELIMITER)) type++; if ((*type == PROP_DELIMITER) || ((*type == PROP_WIZARD) && (*(type + 1) == PROP_DELIMITER))) { did_hear = can_hear(thing); if(*type == PROP_DELIMITER) { prop = DBFETCH(thing)->properties; } else { prop = DBFETCH(thing)->attributes; } /* clear all properties */ if(prop) { for (last = prop -> next; last; last = prop -> next) { prop -> next = last -> next; free_prop(last); } if(*type == PROP_DELIMITER) { notify(player, "All properties removed."); DBSTORE(thing, properties, NULL); } else { notify(player, "All attributes removed."); DBSTORE(thing, attributes, NULL); } free_prop(prop); } else { /* No properties to remove. */ if(*type == PROP_DELIMITER) notify(player, "No properties to remove."); else notify(player, "No attributes to remove."); } free((void *) x); if(can_hear(thing) && !did_hear) grow_ears(thing); if(!can_hear(thing) && did_hear) lose_ears(thing); return; } else { /* get rid of trailing spaces */ for (temp = class - 1; isspace(*temp); temp--) ; temp++; *temp = '\0'; } class++; /* move to next character */ while (isspace(*class) && *class) class++; if (!(*class)) { remove_property(thing, type); sprintf(buf, "%s -- %s removed.", NAME(thing), type); notify(player, buf); } else { if(*type == PROP_WIZARD && !Wizard(player)) { notify(player, "Permission denied."); free ((void *) x); return; } add_property(thing, type, class); sprintf(buf, "%s -- %s set to \"%s\"", NAME(thing), type, class); notify(player, buf); } free((void *) x); return; } did_hear = can_hear(thing); /* identify flag */ f = lookup_flag(p); if(f <= 0) { notify(player,"I don't recognize that flag."); return; } /* check for restricted flag */ if (restricted(player, thing, f)) { notify(player, "Permission denied."); return; } /* check for stupid wizard */ if(f == WIZARD && *flag == NOT_TOKEN && thing == player && !God(player)) { notify(player, "You cannot make yourself mortal."); return; } /* else everything is ok, do the set */ if(*flag == NOT_TOKEN) { /* reset the flag */ FLAGS(thing) &= ~f; DBDIRTY(thing); notify(player, "Flag reset."); } else { /* set the flag */ FLAGS(thing) |= f; DBDIRTY(thing); notify(player, "Flag set."); } if(can_hear(thing) && !did_hear) grow_ears(thing); if(!can_hear(thing) && did_hear) lose_ears(thing); } void do_field(dbref player, const char *name, const char *flag, dbref cause) { dbref thing; const char *p; /* find thing */ if((thing = match_controlled(player, name)) == NOTHING) return; /* move p past NOT_TOKEN if present */ for(p = flag; *p && (*p == NOT_TOKEN || isspace(*p)); p++); /* Now we check to see if it's a property reference */ /* if this gets changed, please also modify boolexp.c */ if (index(flag, PROP_DELIMITER)) { /* copy the string so we can muck with it */ char *type = alloc_string(flag); /* type */ char *rest = (char *)index(type, PROP_DELIMITER); /* class */ char *x; /* to preserve string location so we can free it */ char *temp; char *old; char new[BUFFER_LEN]; x = type; while (isspace(*type) && (*type != PROP_DELIMITER)) type++; if (*type == PROP_DELIMITER) { notify(player, "Usage: @field <object>=<property>:<old>,<new>"); free((void *) x); return; } else { /* get rid of trailing spaces */ for (temp = rest - 1; isspace(*temp); temp--) ; temp++; *temp = '\0'; } if(get_property_class(thing, type)) { old = (char *) calloc(strlen(get_property_class(thing, type)) + 1, sizeof(char)); strcpy(old, get_property_class(thing, type)); } else { notify(player, "No such property."); free((void *) x); return; } rest++; /* move to next character */ while (isspace(*rest) && *rest) rest++; if (!(*rest)) { notify(player, "Nothing to change."); free((void *) x); return; } else { const char *delimit = ","; char *arg1 = (char *) parse_up(&rest, delimit); char *arg2 = (char *) parse_up(&rest, delimit); arg1 = check_arg(arg1, player, cause); arg2 = check_arg(arg2, player, cause); if(!arg1 || !(*arg1)) { notify(player, "Nothing to change."); free((void *) x); return; } else { int len = strlen(arg1); int d; const char *r = (arg2 ? arg2 : (char *) ""); for (d = 0; (d < BUFFER_LEN) && *old;) if (strncmp(arg1, old, len) == 0) { if ((d + strlen(r)) < BUFFER_LEN) { strcpy(new + d, r); d += strlen(r); old += len; } else new[d++] = *old++; } else new[d++] = *old++; new[d++] = 0; free((void *) old); if(new && *new) { add_property(thing, type, new); sprintf(buf,"%s -- %s set to \"%s\"", NAME(thing), type, new); } else { remove_property(thing, type); sprintf(buf,"%s -- %s removed.", NAME(thing), type); } notify(player, buf); } } free((void *) x); } else notify(player, "Usage: @field <object>=<old>,<new>"); }