/** Helper function for calling \@functioned funs. * \param buff string to store result of evaluation. * \param bp pointer into end of buff. * \param obj object on which the ufun is stored. * \param attrib pointer to attribute on which the ufun is stored. * \param nargs number of arguments passed to the ufun. * \param args array of arguments passed to the ufun. * \param executor executor. * \param caller caller (unused). * \param enactor enactor. * \param pe_info pointer to structure for process_expression data. * \param extra_flags extra PE_ flags to pass in (PE_USERFN or 0). */ void do_userfn(char *buff, char **bp, dbref obj, ATTR *attrib, int nargs, char **args, dbref executor, dbref caller __attribute__ ((__unused__)), dbref enactor, NEW_PE_INFO *pe_info, int extra_flags) { int j; int made_pe_info = 0; char *tbuf; char const *tp; int pe_flags = PE_DEFAULT | extra_flags; PE_REGS *pe_regs; if (nargs > 10) nargs = 10; /* maximum ten args */ /* save our stack */ if (!pe_info) { made_pe_info = 1; pe_info = make_pe_info("pe_info-do_userfn"); } /* copy the appropriate args into pe_regs */ pe_regs = pe_regs_localize(pe_info, PE_REGS_ARG, "do_userfn"); for (j = 0; j < nargs; j++) { pe_regs_setenv_nocopy(pe_regs, j, args[j]); } tp = tbuf = safe_atr_value(attrib); if (AF_NoDebug(attrib)) pe_flags |= PE_NODEBUG; /* no_debug overrides debug */ else if (AF_Debug(attrib)) pe_flags |= PE_DEBUG; process_expression(buff, bp, &tp, obj, executor, enactor, pe_flags, PT_DEFAULT, pe_info); free(tbuf); pe_regs_restore(pe_info, pe_regs); pe_regs_free(pe_regs); if (made_pe_info) { free_pe_info(pe_info); } }
/** 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. * \param newdbref the (unparsed) dbref to give the object, or NULL to use the next free * \param pe_info The pe_info to use for lock and \@command priv checks * \return dbref of the duplicate, or NOTHING. */ dbref do_clone(dbref player, char *name, char *newname, int preserve, char *newdbref, NEW_PE_INFO *pe_info) { 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", pe_info)) || (IsExit(thing) && !command_check_byname(player, "@open", pe_info)) || (IsThing(thing) && !command_check_byname(player, "@create", pe_info))) { 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, preserve); real_did_it(player, clone, NULL, NULL, NULL, NULL, "ACLONE", NOTHING, NULL, 0, 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, preserve); real_did_it(player, clone, NULL, NULL, NULL, NULL, "ACLONE", NOTHING, NULL, 0, 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, pe_info); else clone = do_real_open(player, Name(thing), dbnum, NOTHING, pe_info); if (!GoodObject(clone)) { return NOTHING; } else { char *alias_val = NULL; ATTR *alias_attr = NULL; alias_attr = atr_get_noparent(clone, "ALIAS"); if (alias_attr) { alias_val = safe_atr_value(alias_attr, "atrval.do_clone"); atr_clr(clone, "ALIAS", GOD); } atr_cpy(clone, thing); if (alias_val) { atr_add(clone, "ALIAS", alias_val, player, 0); mush_free(alias_val, "atrval.do_clone"); } 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, preserve); return clone; } } return NOTHING; }