/* 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; }
/** A wrapper for real_did_it that can set %0 and %1 to dbrefs. * \param player the enactor. * \param thing object being triggered. * \param what message attribute for enactor. * \param def default message to enactor. * \param owhat message attribute for others. * \param odef default message to others. * \param awhat action attribute to trigger. * \param loc location in which action is taking place. * \param env0 dbref to pass as %0, or NOTHING. * \param env1 dbref to pass as %1, or NOTHING. * \param flags interaction flags to pass to real_did_it. * \retval 0 no attributes were present, only defaults were used if given. * \retval 1 some attributes were evaluated and used. */ int did_it_with(dbref player, dbref thing, const char *what, const char *def, const char *owhat, const char *odef, const char *awhat, dbref loc, dbref env0, dbref env1, int flags, int an_flags) { PE_REGS *pe_regs = pe_regs_create(PE_REGS_ARG, "did_it_with"); int retval; if (env0 != NOTHING) { pe_regs_setenv(pe_regs, 0, unparse_dbref(env0)); } if (env1 != NOTHING) { pe_regs_setenv(pe_regs, 1, unparse_dbref(env1)); } retval = real_did_it(player, thing, what, def, owhat, odef, awhat, loc, pe_regs, flags, an_flags); pe_regs_free(pe_regs); return retval; }
/** 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); }
/** 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); }
/** The switch command. * \verbatim * For lack of better place the @switch code is here. * @switch expression=args * \endverbatim * \param executor the executor. * \param expression the expression to test against cases. * \param argv array of cases and actions. * \param enactor the object that caused this code to run. * \param first if 1, run only first matching case; if 0, run all matching cases. * \param notifyme if 1, perform a notify after executing matched cases. * \param regexp if 1, do regular expression matching; if 0, wildcard globbing. * \param queue_type the type of queue to run any new commands as * \param queue_entry the queue entry \@switch is being run in */ void do_switch(dbref executor, char *expression, char **argv, dbref enactor, int first, int notifyme, int regexp, int queue_type, MQUE *queue_entry) { int any = 0, a; char buff[BUFFER_LEN], *bp; char const *ap; char *tbuf1; PE_REGS *pe_regs; if (!argv[1]) return; /* now try a wild card match of buff with stuff in coms */ for (a = 1; !(first && any) && (a < (MAX_ARG - 1)) && argv[a] && argv[a + 1]; a += 2) { /* eval expression */ ap = argv[a]; bp = buff; if (process_expression(buff, &bp, &ap, executor, enactor, enactor, PE_DEFAULT, PT_DEFAULT, queue_entry->pe_info)) { return; } *bp = '\0'; /* check for a match */ pe_regs = pe_regs_create(PE_REGS_SWITCH | PE_REGS_CAPTURE, "do_switch"); pe_regs_set(pe_regs, PE_REGS_SWITCH, "t0", expression); if (regexp ? regexp_match_case_r(buff, expression, 0, NULL, 0, NULL, 0, pe_regs, 0) : local_wild_match(buff, expression, pe_regs)) { tbuf1 = replace_string("#$", expression, argv[a + 1]); if (!any) { /* Add the new switch context to the parent queue... */ any = 1; } if (queue_type & QUEUE_INPLACE) { new_queue_actionlist(executor, enactor, enactor, tbuf1, queue_entry, PE_INFO_SHARE, queue_type, pe_regs); } else { new_queue_actionlist(executor, enactor, enactor, tbuf1, queue_entry, PE_INFO_CLONE, queue_type, pe_regs); } mush_free(tbuf1, "replace_string.buff"); } } /* do default if nothing has been matched */ if ((a < MAX_ARG) && !any && argv[a]) { tbuf1 = replace_string("#$", expression, argv[a]); pe_regs = pe_regs_create(PE_REGS_SWITCH | PE_REGS_CAPTURE, "do_switch"); pe_regs_set(pe_regs, PE_REGS_SWITCH, "t0", expression); if (queue_type & QUEUE_INPLACE) { new_queue_actionlist(executor, enactor, enactor, tbuf1, queue_entry, PE_INFO_SHARE, queue_type, pe_regs); } else { new_queue_actionlist(executor, enactor, enactor, tbuf1, queue_entry, PE_INFO_CLONE, queue_type, pe_regs); } mush_free(tbuf1, "replace_string.buff"); } if (!(queue_type & QUEUE_INPLACE) && notifyme) { parse_que(executor, enactor, "@notify me", NULL); } }