static int chown_ok(dbref player, dbref thing, dbref newowner, NEW_PE_INFO *pe_info) { /* Can't touch garbage */ if (IsGarbage(thing)) return 0; /* Wizards can do it all */ if (Wizard(player)) return 1; /* In order for non-wiz player to @chown thing to newowner, * player must control newowner or newowner must be a Zone Master * and player must pass its zone lock. * * In addition, one of the following must apply: * 1. player owns thing, or * 2. player controls Owner(thing), newowner is a zone master, * and Owner(thing) passes newowner's zone-lock, or * 3. thing is CHOWN_OK, and player holds thing if it's an object. * * The third condition is syntactic sugar to handle the situation * where Joe owns Box, an ordinary object, and Tool, an inherit object, * and ZMP, a Zone Master Player, is zone-locked to =tool. * In this case, if Joe doesn't pass ZMP's lock, we don't want * Joe to be able to @fo Tool=@chown Box=ZMP */ /* Does player control newowner, or is newowner a Zone Master and player * passes the lock? */ if (!(controls(player, newowner) || (ZMaster(newowner) && eval_lock_with(player, newowner, Zone_Lock, pe_info)))) return 0; /* Target player is legitimate. Does player control the object? */ if (Owns(player, thing)) return 1; if (controls(player, Owner(thing)) && ZMaster(newowner) && eval_lock_with(Owner(thing), newowner, Zone_Lock, pe_info)) return 1; if ((!IsThing(thing) || (Location(thing) == player)) && ChownOk(thing) && eval_lock_with(player, thing, Chown_Lock, pe_info)) return 1; return 0; }
/** Clone an object. * \verbatim * This is the top-level function for @clone, which creates a duplicate * of a (non-player) object. * \endverbatim * \param player the enactor. * \param name the name of the object to clone. * \param newname the name to give the duplicate. * \param preserve if 1, preserve ownership and privileges on duplicate. * \paran newdbref the (unparsed) dbref to give the object, or NULL to use the next free * \return dbref of the duplicate, or NOTHING. */ dbref do_clone(dbref player, char *name, char *newname, int preserve, char *newdbref) { dbref clone, thing; char dbnum[BUFFER_LEN]; thing = noisy_match_result(player, name, NOTYPE, MAT_EVERYTHING); if ((thing == NOTHING)) return NOTHING; if (newname && *newname && !ok_name(newname, IsExit(thing))) { notify(player, T("That is not a reasonable name.")); return NOTHING; } if (!controls(player, thing) || IsPlayer(thing) || (IsRoom(thing) && !command_check_byname(player, "@dig")) || (IsExit(thing) && !command_check_byname(player, "@open")) || (IsThing(thing) && !command_check_byname(player, "@create"))) { notify(player, T("Permission denied.")); return NOTHING; } /* don't allow cloning of destructed things */ if (IsGarbage(thing)) { notify(player, T("There's nothing left of it to clone!")); return NOTHING; } if (preserve && !Wizard(player)) { notify(player, T("You cannot @CLONE/PRESERVE. Use normal @CLONE instead.")); return NOTHING; } if (!make_first_free_wrapper(player, newdbref)) { return NOTHING; } /* make sure owner can afford it */ switch (Typeof(thing)) { case TYPE_THING: if (can_pay_fees(player, Pennies(thing))) { clone = clone_object(player, thing, newname, preserve); notify_format(player, T("Cloned: Object %s."), unparse_dbref(clone)); if (IsRoom(player)) moveto(clone, player, player, "cloned"); else moveto(clone, Location(player), player, "cloned"); current_state.things++; local_data_clone(clone, thing); real_did_it(player, clone, NULL, NULL, NULL, NULL, "ACLONE", NOTHING, global_eval_context.wenv, 0); return clone; } return NOTHING; break; case TYPE_ROOM: if (can_pay_fees(player, ROOM_COST)) { clone = clone_object(player, thing, newname, preserve); Exits(clone) = NOTHING; notify_format(player, T("Cloned: Room #%d."), clone); current_state.rooms++; local_data_clone(clone, thing); real_did_it(player, clone, NULL, NULL, NULL, NULL, "ACLONE", NOTHING, global_eval_context.wenv, 0); return clone; } return NOTHING; break; case TYPE_EXIT: /* For exits, we don't want people to be able to link it to a location they can't with @open. So, all this stuff. */ switch (Location(thing)) { case NOTHING: strcpy(dbnum, "#-1"); break; case HOME: strcpy(dbnum, "home"); break; case AMBIGUOUS: strcpy(dbnum, "variable"); break; default: strcpy(dbnum, unparse_dbref(Location(thing))); } if (newname && *newname) clone = do_real_open(player, newname, dbnum, NOTHING); else clone = do_real_open(player, Name(thing), dbnum, NOTHING); if (!GoodObject(clone)) { return NOTHING; } else { atr_cpy(clone, thing); clone_locks(player, thing, clone); Zone(clone) = Zone(thing); Parent(clone) = Parent(thing); Flags(clone) = clone_flag_bitmask("FLAG", Flags(thing)); if (!preserve) { clear_flag_internal(clone, "WIZARD"); clear_flag_internal(clone, "ROYALTY"); Warnings(clone) = 0; /* zap warnings */ Powers(clone) = new_flag_bitmask("POWER"); /* zap powers */ } else { Warnings(clone) = Warnings(thing); Powers(clone) = clone_flag_bitmask("POWER", Powers(thing)); } if (Wizard(clone) || Royalty(clone) || Warnings(clone) || !null_flagmask("POWER", Powers(clone))) notify(player, T ("Warning: @CLONE/PRESERVE on an object with WIZ, ROY, @powers, or @warnings.")); notify_format(player, T("Cloned: Exit #%d."), clone); local_data_clone(clone, thing); return clone; } } return NOTHING; }
/** Change an object's owner. * \verbatim * This implements @chown. * \endverbatim * \param player the enactor. * \param name name of object to change owner of. * \param newobj name of new owner for object. * \param preserve if 1, preserve privileges and don't halt the object. * \param pe_info the pe_info for lock checks */ void do_chown(dbref player, const char *name, const char *newobj, int preserve, NEW_PE_INFO *pe_info) { dbref thing; dbref newowner = NOTHING; long match_flags = MAT_POSSESSION | MAT_HERE | MAT_EXIT | MAT_ABSOLUTE; /* check for '@chown <object>/<atr>=<player>' */ if (strchr(name, '/')) { do_atrchown(player, name, newobj); return; } if (Wizard(player)) match_flags |= MAT_PLAYER; if ((thing = noisy_match_result(player, name, TYPE_THING, match_flags)) == NOTHING) return; if (!*newobj || !strcasecmp(newobj, "me")) { newowner = player; } else { if ((newowner = lookup_player(newobj)) == NOTHING) { notify(player, T("I couldn't find that player.")); return; } } if (IsPlayer(thing) && !God(player)) { notify(player, T("Players always own themselves.")); return; } /* Permissions checking */ if (!chown_ok(player, thing, newowner, pe_info)) { notify(player, T("Permission denied.")); return; } if (IsThing(thing) && !Hasprivs(player) && !(GoodObject(Location(thing)) && (Location(thing) == player))) { notify(player, T("You must carry the object to @chown it.")); return; } if (preserve && !Wizard(player)) { notify(player, T("You cannot @CHOWN/PRESERVE. Use normal @CHOWN.")); return; } /* chowns to the zone master don't count towards fees */ if (!ZMaster(newowner)) { /* Debit the owner-to-be */ if (!can_pay_fees(newowner, Pennies(thing))) { /* not enough money or quota */ if (newowner != player) notify(player, T ("That player doesn't have enough money or quota to receive that object.")); return; } /* Credit the current owner */ giveto(Owner(thing), Pennies(thing)); change_quota(Owner(thing), QUOTA_COST); } chown_object(player, thing, newowner, preserve); notify(player, T("Owner changed.")); }