/* Show the 'Obvious Exits' list for a room. Used in 'look' and 'examine'. * \param player The player looking * \param loc room whose exits we're showing * \param exit_name "Obvious Exits" string * \param pe_info the pe_info to use for evaluating EXITFORMAT and interact locks */ static void look_exits(dbref player, dbref loc, const char *exit_name, NEW_PE_INFO *pe_info) { dbref thing; char *tbuf1, *tbuf2, *nbuf; char *s1, *s2; char *p; int exit_count, this_exit, total_count; int texits; ufun_attrib ufun; PUEBLOBUFF; /* make sure location is a room */ if (!IsRoom(loc)) return; tbuf1 = (char *) mush_malloc(BUFFER_LEN, "string"); tbuf2 = (char *) mush_malloc(BUFFER_LEN, "string"); nbuf = (char *) mush_malloc(BUFFER_LEN, "string"); if (!tbuf1 || !tbuf2 || !nbuf) mush_panic("Unable to allocate memory in look_exits"); s1 = tbuf1; s2 = tbuf2; texits = exit_count = total_count = 0; this_exit = 1; if (fetch_ufun_attrib ("EXITFORMAT", loc, &ufun, UFUN_IGNORE_PERMS | UFUN_REQUIRE_ATTR)) { char *arg, *buff, *bp; PE_REGS *pe_regs = pe_regs_create(PE_REGS_ARG, "look_exits"); arg = (char *) mush_malloc(BUFFER_LEN, "string"); buff = (char *) mush_malloc(BUFFER_LEN, "string"); if (!arg || !buff) mush_panic("Unable to allocate memory in look_exits"); bp = arg; DOLIST(thing, Exits(loc)) { if (((Light(loc) || Light(thing)) || !(Dark(loc) || Dark(thing))) && can_interact(thing, player, INTERACT_SEE, pe_info)) { if (bp != arg) safe_chr(' ', arg, &bp); safe_dbref(thing, arg, &bp); } } *bp = '\0'; pe_regs_setenv_nocopy(pe_regs, 0, arg); call_ufun(&ufun, buff, player, player, pe_info, pe_regs); pe_regs_free(pe_regs); notify_by(loc, player, buff); mush_free(tbuf1, "string"); mush_free(tbuf2, "string"); mush_free(nbuf, "string"); mush_free(arg, "string"); mush_free(buff, "string"); return; }
/** The say command. * \param player the enactor. * \param message the message to say. * \param pe_info pe_info to eval speechmod with */ void do_say(dbref player, const char *message, NEW_PE_INFO *pe_info) { dbref loc; PE_REGS *pe_regs; char modmsg[BUFFER_LEN]; char says[BUFFER_LEN]; char *sp; int mod = 0; loc = speech_loc(player); if (!GoodObject(loc)) return; if (!Loud(player) && !eval_lock_with(player, loc, Speech_Lock, pe_info)) { fail_lock(player, loc, Speech_Lock, T("You may not speak here!"), NOTHING); return; } if (*message == SAY_TOKEN && CHAT_STRIP_QUOTE) message++; pe_regs = pe_regs_create(PE_REGS_ARG, "do_say"); pe_regs_setenv_nocopy(pe_regs, 0, message); pe_regs_setenv_nocopy(pe_regs, 1, "\""); modmsg[0] = '\0'; if (call_attrib(player, "SPEECHMOD", modmsg, player, pe_info, pe_regs) && *modmsg != '\0') mod = 1; pe_regs_free(pe_regs); /* notify everybody */ notify_format(player, T("You say, \"%s\""), (mod ? modmsg : message)); sp = says; safe_format(says, &sp, T("%s says, \"%s\""), spname(player), (mod ? modmsg : message)); *sp = '\0'; notify_except(player, loc, player, says, NA_INTER_HEAR); }
/** 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); } }
/** Rename something. * \verbatim * This implements @name. * \endverbatim * \param player the enactor. * \param name current name of object to rename. * \param newname_ new name for object. */ void do_name(dbref player, const char *name, char *newname_) { dbref thing; char oldname[BUFFER_LEN]; char *newname = NULL; char *alias = NULL; PE_REGS *pe_regs; if ((thing = match_controlled(player, name)) == NOTHING) return; /* check for bad name */ if ((*newname_ == '\0') || strchr(newname_, '[')) { notify(player, T("Give it what new name?")); return; } switch (Typeof(thing)) { case TYPE_PLAYER: switch (ok_object_name (newname_, player, thing, TYPE_PLAYER, &newname, &alias)) { case OPAE_INVALID: case OPAE_NULL: notify(player, T("You can't give a player that name or alias.")); if (newname) mush_free(newname, "name.newname"); if (alias) mush_free(alias, "name.newname"); return; case OPAE_TOOMANY: notify(player, T("Too many aliases.")); mush_free(newname, "name.newname"); return; case OPAE_SUCCESS: break; } break; case TYPE_EXIT: if (ok_object_name(newname_, player, thing, TYPE_EXIT, &newname, &alias) != OPAE_SUCCESS) { notify(player, T("That is not a reasonable name.")); if (newname) mush_free(newname, "name.newname"); if (alias) mush_free(alias, "name.newname"); return; } break; case TYPE_THING: case TYPE_ROOM: if (!ok_name(newname_, 0)) { notify(player, T("That is not a reasonable name.")); return; } newname = mush_strdup(trim_space_sep(newname_, ' '), "name.newname"); break; default: /* Should never occur */ notify(player, T("I don't see that here.")); return; } /* Actually change it */ mush_strncpy(oldname, Name(thing), BUFFER_LEN); if (IsPlayer(thing)) { do_log(LT_CONN, 0, 0, "Name change by %s(#%d) to %s", Name(thing), thing, newname); if (Suspect(thing) && strcmp(Name(thing), newname) != 0) flag_broadcast("WIZARD", 0, T("Broadcast: Suspect %s changed name to %s."), Name(thing), newname); reset_player_list(thing, Name(thing), NULL, newname, NULL); } set_name(thing, newname); if (alias) { if (*alias == ALIAS_DELIMITER) { do_set_atr(thing, "ALIAS", NULL, player, 0); } else { /* New alias to set */ do_set_atr(thing, "ALIAS", alias, player, 0); } mush_free(alias, "name.newname"); } queue_event(player, "OBJECT`RENAME", "%s,%s,%s", unparse_objid(thing), newname, oldname); if (!AreQuiet(player, thing)) notify(player, T("Name set.")); pe_regs = pe_regs_create(PE_REGS_ARG, "do_name"); pe_regs_setenv_nocopy(pe_regs, 0, oldname); pe_regs_setenv_nocopy(pe_regs, 1, newname); real_did_it(player, thing, NULL, NULL, "ONAME", NULL, "ANAME", NOTHING, pe_regs, NA_INTER_PRESENCE, AN_SYS); pe_regs_free(pe_regs); mush_free(newname, "name.newname"); }
/** User-defined verbs. * \verbatim * This implements the @verb command. * \endverbatim * \param executor the executor. * \param enactor the object causing this command to run. * \param arg1 the object to read verb attributes from. * \param argv the array of remaining arguments to the verb command. * \param queue_entry The queue entry \@verb is running in */ void do_verb(dbref executor, dbref enactor, char *arg1, char **argv, MQUE *queue_entry) { dbref victim; dbref actor; int i; PE_REGS *pe_regs = NULL; /* find the object that we want to read the attributes off * (the object that was the victim of the command) */ /* our victim object can be anything */ victim = match_result(executor, arg1, NOTYPE, MAT_EVERYTHING); if (!GoodObject(victim)) { notify(executor, T("What was the victim of the verb?")); return; } /* find the object that executes the action */ if (!argv || !argv[1] || !*argv[1]) { notify(executor, T("What do you want to do with the verb?")); return; } actor = match_result(executor, argv[1], NOTYPE, MAT_EVERYTHING); if (!GoodObject(actor)) { notify(executor, T("What do you want to do the verb?")); return; } /* Control check is fascist. * First check: we don't want <actor> to do something involuntarily. * Both victim and actor have to be controlled by the thing which did * the @verb (for speed we do a WIZARD check first), or: cause controls * actor plus the second check is passed. * Second check: we need read access to the attributes. * Either the player controls victim or the player * must be priviledged, or the victim has to be VISUAL. */ if (!(Wizard(executor) || (controls(executor, victim) && controls(executor, actor)) || ((controls(enactor, actor) && Can_Examine(executor, victim))))) { notify(executor, T("Permission denied.")); return; } /* We're okay. Send out messages. */ pe_regs = pe_regs_create(PE_REGS_ARG | PE_REGS_Q, "do_verb"); for (i = 0; i < MAX_STACK_ARGS; i++) { if (argv[i + 7]) { pe_regs_setenv_nocopy(pe_regs, i, argv[i + 7]); } } pe_regs_qcopy(pe_regs, queue_entry->pe_info->regvals); real_did_it(actor, victim, upcasestr(argv[2]), argv[3], upcasestr(argv[4]), argv[5], NULL, Location(actor), pe_regs, NA_INTER_HEAR, AN_SYS); /* Now we copy our args into the stack, and do the command. */ if (argv[6] && *argv[6]) queue_attribute_base(victim, upcasestr(argv[6]), actor, 0, pe_regs, (queue_entry->queue_type & QUEUE_EVENT)); pe_regs_free(pe_regs); }