;"Thank you for installing this Object." ;"This installation file was created by debug(smithdm@metronet.com)" ;"Other Generics are availible at http://www.cmoo.com/moo/moogens.html" ;"This object was created by: Frand of LambdaMOO" ;"*Please make sure that you have edited this script and replaced with the appropriate object number*" @prop ."directions" {} rc ;;.("directions") = {"north", "ne", "east", "se", "south", "sw", "west", "nw", "up", "down", "enter", "out"} @prop ."running" 0 r @prop ."stay_time" 15 rc @prop ."more_steps" 10 rc @prop ."steps_left" 0 r @prop ."not_my_tell" 1 r ;;.("seek_failed_msg") = "%n bounces off a topographical barrier." ;;.("home2") = #13240 ;;.("home") = #13240 ;;.("brief") = 1 ;;.("simulating") = 0 ;;.("listen_actions") = {} ".("key") => E_PERM (Permission denied) ;;.("aliases") = {"Frand's generic wanderer", "wanderer"} ;;.("description") = "This wandering monster (actually owned by FrandMaster, not Frand) is started up by its :tell verb. It has a countdown 'clock' of actions to take, and every :tell (except those which the monster itself is responsible for) resets the clock to its maximum value. The monster will then wander that many steps before halting. It is designed to be easily customizable; you can add fancy behavior fairly easily. Empirico's monster is an example customized wanderer." ;;.("object_size") = {11997, 865021722} @verb :"tell" this none this @program :tell "'tell ()' - When the wanderer hears something other than itself, it rewinds its clock. If the clock has run down and stopped, it sets it running again."; pass(@args); if (this.not_my_tell && this.running) if (!this.steps_left) "The clock has run down; start it running again. The forked task, of course, doesn't run until after the clock has been rewound, below."; fork (this:stay_time()) this:wander(); endfork endif "Rewind the clock--set the number of steps the wanderer is to take."; this.steps_left = this:more_steps(); endif . @verb :"take_exit" this none this @program :take_exit "'take_exit ()' - Find an exit in the room and take it. If no exit can be found, or if all exits are tried and fail, call :give_up."; if (!this:secure()) return E_PERM; endif if (!$object_utils:has_verb(this.location, "match_exit")) "Match_exit is used by :find_exits()."; this:give_up(); return; endif exits = this:find_exits(this.directions); place = this.location; while (exits) exit = this:pick_exit(exits); if ((typeof(exit) == OBJ) && valid(exit)) exit:move(this); if (this.location != place) return; endif elseif (exit == 0) "Special case: pick_exit said to sit tight and go nowhere."; return; endif exits = setremove(exits, exit); endwhile this:give_up(); . @verb :"wander" this none this @program :wander "'wander ()' - If there is time left on the clock, then wander. That means subtract one from the clock, behave, and fork. Do nothing if the wanderer is not running, or is dead."; if ((((this.steps_left > 0) && this.running) && this:should_wander()) && this:secure()) this.steps_left = this.steps_left - 1; this.not_my_tell = 0; this:behave(); this.not_my_tell = 1; fork (this:stay_time()) this:wander(); endfork endif . @verb :"behave" this none this @program :behave "'behave ()' - Do something. The default behavior is to call take_exit(). You can override it to do anything you like--not necessarily wander."; if (this:secure()) this:take_exit(); else return E_PERM; endif . @verb :"give_up" this none this @program :give_up "'give_up ()' - Take the wanderer home. This is called when it gets stuck somewhere--when it lands in a non-room, or when it can't find any exit from a room. You can customize it if you want the monster to take some other action when it gets stuck. Or you might want to print a message before and after going home."; if (this:secure()) this:moveto(this.home); else return E_PERM; endif . @verb :"more_steps" this none this @program :more_steps "'more_steps ()' - Return how many steps (calls to wander()) the monster should make (at a minimum; the clock might be reset later, upping the number again). Customize this if you want the wanderer to put different amounts of time on its clock under different circumstances."; return this.more_steps; . @verb :"stay_time" this none this @program :stay_time "'stay_time ()' - Return how long the wanderer should wait before making the next wander() call. Customize this if you want the wanderer to sometimes hurry and sometimes dally."; return this.stay_time; . @verb :"exit_ok" this none this @program :exit_ok "'exit_ok ()' - Given an exit object (which is not necessarily a descendant of $exit), return whether it is OK for the wanderer to take the exit. This default verb only checks whether the exit is unlocked. Customize this verb if you want to limit the wanderer to certain areas."; exit = args[1]; return exit:is_unlocked_for(this); . @verb :"pick_exit" this none this @program :pick_exit "'pick_exit ()' - Given a list of exits (which is guaranteed to have at least one element), choose the one to take. This default verb picks an exit at random. Customize it if you want the wanderer to be more choosy."; exits = args[1]; return exits[random(length(exits))]; . @verb :"secure" this none this @program :secure "'secure ()' - Check the callers() list to see whether the caller of the caller of this verb is an OK one. You can customize this to provide different security arrangements."; who = (length(callers()) < 2) ? player | callers()[2][3]; return (who in {this.owner, #11422.owner, #259.owner}) || who.wizard; . @verb :"find_exits" this none this @program :find_exits "'find_exits ()' - Given a list of possible exit names, return a list of the exit objects in this room that have those names. It requires that the location have :match_exit; you'd better check before you call it. This verb is used in :take_exit, but it's also a utility verb that you can use if you want your wanderer to have specific ways of moving around."; exits = {}; for name in (args[1]) exit = this.location:match_exit(name); if ((valid(exit) && (!(exit in exits))) && this:exit_ok(exit)) exits = listappend(exits, exit); endif endfor return exits; . @verb :"@start" this none none @program :@start "'@start ' - Start the wanderer wandering."; if ((player == this.owner) || player.wizard) this.running = 1; this.steps_left = this:more_steps(); this:wander(); player:tell(this.name, " started up."); else player:tell(E_PERM); endif . @verb :"@stop" this none none @program :@stop "'@stop ' - Stop the wanderer."; if ((player == this.owner) || player.wizard) this.running = 0; player:tell(this.name, " stopped."); else player:tell(E_PERM); endif . @verb :"birth" this none this @program :birth "The wanderer stops when it is killed. This restarts it when it is reborn. (If it's not supposed to be running, the :wander call will do nothing.) WARNING: It's important for the wanderer's gestation period (this.gestate) to be longer than any stay time. Make sure this is true!"; fork (max(this.stay_time, 5)) this:wander(); endfork return pass(@args); . @verb :"should_wander" this none this @program :should_wander "'should_wander ()' - Return whether it's OK for the wanderer to be wandering around now. By default, it is an RPG monster and should only wander if it is alive. NOTE: If it is not an RPG monster, and should wander no matter what, then override this verb to return 1."; return this.alive; . ;"Your object should now be installed."