We should be ready to roll now... We're going to have the wind up toy start up when the player drops it. This introduces another concept, that of specializing an existing method. The generic located object ($located) defines the method .did_move that is called after an object has successfully been moved from one location to another. Normally, if we type "drop hduck" the .did_move method on $located gets invoked for the duck (even though it's a few levels removed from $located). If we define a .did_move method on $windup_toy, then that is the first definition of .did_move encountered as the ancestor heirarchy is searched, so it is the one that gets executed (as opposed to the definition on $located). Now we don't want to have to completely recreate everything $located.did_move() does, we just want our special action to happen after the normal drop actions finish. In order to accomplish this, we use the pass() function.
This is the slipperiest concent in ColdC programming, yet the basis for the entire object oriented nature of the system. An easy way to think of pass is like another method call: it just does the "basic thing" that this method normally does. We can add our specialization code both before and after this basic thing. The arguments you put in the pass() call are just like calling the ancester's definition of the method with those arguments. More sophisticated users of pass may wish to change these arguments; for now, just take it as gospel and pass the same arguments up the ancestral heirarchy. Sometimes you won't want to use pass at all, if you don't want the basic thing to happen, but want to completely override the default behavior. This is OK, you just have to think about what you want when deciding whether and where to put the call to pass().
We want the dropping to happen before any of our startup, so we call pass() right away. We better check if the toy has been wound up, and not do anything special if it hasn't. Also, we want to make sure that the location where the toy used to be was a person (or body), and that the new location is a place (or room). After we have established that these conditions are true, we can tell the toy to start moving around... otherwise, we'll make sure that it is not moving after any other move.
@program $windup_toy.did_move +access=protected
arg mover, old_place;
// Let ancestor handle normal tasks
pass(mover, old_place);
// Trigger walk event if dropping from person to room
if (.location().is($place) && old_place.is($body) && wound)
.go();
else
going = 0;
.
Next we'll define the .go() method which will do the actual work of moving the toy around. When we define .go, we set the forked flag. This means that when this method is called, it splits into its own task, allowing the calling method/task to continue on its way as if this method has already finished. We do this so that you and other players in the room will see the 'dropped' message immediately, and not after the toy has finished walking around the room. We separate the two tasks, because they are two different ideas that will execute apart from eachother -- but the dropping just triggers the moving.
@program $windup_toy.go +access=protected +flags=forked
var i, vars;
if (!going) {
going = 1;
vars = #[["$this", this().name()]];
.location().announce(.eval_message("startup", $windup_toy, vars));
for i in [1 .. wound] {
$scheduler.sleep(15);
if (going) {
.location().announce(.eval_message("continue", $windup_toy, vars));
wound--;
} else {
break;
}
}
going = 0;
}
.
You see that in this method we use thw wound and going object variables. This way if the .go() method is called while it is already moving around, the method will ignore the second call because the going object variable will be logically true (1) while the toy is moving around, and logically false (0) when it is idle.
We also use the core object $scheduler here to tell the system to wait for the indicated number of seconds (15) before continuing on to the rest of the code. This is useful if you need to write code that is somehow time-related. The $scheduler object offers many very useful methods for handling timed execution of tasks.
Now, let's drop our duck and see how it works!
drop duck You drop Heisenberg's Wind-Up Duck. Heisenberg's Wind-Up Duck waddles about and starts rolling forward. Heisenberg's Wind-Up Duck swivels its neck and emits a >> Quack << Heisenberg's Wind-Up Duck swivels its neck and emits a >> Quack <<
It actually waited 15 seconds in between each of those messages. I tried it again, but this time I typed @tasks right away to see that the tasks had been scheduled:
@tasks -- Suspended Tasks -- TASK TICKS METHOD RESUMABLE BY 210609 19985 $scheduler.sleep() $scheduler $user_heisenberg

