← MegaMOO Guide

A World That Moves

Things that happen on their own: tickers and effects.

Everything so far happens because a player typed something. A world where nothing moves unless someone pokes it feels like a museum. Two systems let things happen on their own.

Tickers

A ticker calls a verb on an object over and over, every so many seconds, until you stop it. Start one from any verb:

ticker_add(30, 'at_regen', pobj, 'regen') ^ ^ ^ ^ seconds verb object a name for this ticker

Every thirty seconds, that calls the at_regen verb on the player. The last argument is a label so one object can run several tickers at once and you can stop them individually:

ticker_remove(pobj, 'regen') # stop that one ticker_remove_all(pobj) # stop all of this object's tickers

An example: a torch that burns down

First, a rule that catches everyone out: a verb can change a property but cannot invent one. Anything your verb writes to has to exist first, and running a ticker on an object needs one more — tickers, where the subscription is kept. Declare all three before writing any code:

> @adprop torch.fuel = 0 > @adprop torch.lit = 0 > @adprop torch.tickers = {}

Skip this and the verb fails at the first assignment with Permission denied: cannot create 'fuel' — a confusing message for what is really a missing declaration.

Now light the torch. It starts a ticker on itself; each tick reduces its fuel, and when the fuel runs out it goes dark and stops its own ticker:

# the `light_` exception verb on the torch this.fuel = 20 ticker_add(60, 'burn', this, 'burn') pobj.msg("The torch catches with a soft rush.") return True
# the `burn` verb on the torch — called once a minute this.fuel = (getattr(this, 'fuel', 0) or 0) - 1 if this.fuel <= 0: ticker_remove(this, 'burn') this.location.msg_room("The torch gutters and dies.") this.lit = False elif this.fuel == 5: this.location.msg_room("The torch is burning low.")

Watched with a two-second tick instead of a minute, that runs:

fuel 4 → 3 → 2 "The torch is burning low." fuel 1 → 0 "The torch gutters and dies." (ticker removed)
Keep tickers cheap and few

A ticker runs forever until something removes it, so always give a verb a way to stop its own. Prefer one ticker doing a small amount of work to many tickers doing almost nothing — a room can tick for everything in it.

Effects

An effect is a temporary state on a character that fires a set number of times and then ends by itself — drunk, poisoned, blessed, regenerating. You do not manage the countdown; the effects system does.

$eu.trigger(pobj, 'intoxicate', 3, 60) ^ ^ ^ ^ who effect name times seconds apart

That applies the intoxicate effect three times, a minute apart, and then it is over. Each effect is a verb named do_<name> on $eu, the effects object — the shipped world includes do_intoxicate, and you add your own the same way.

CallDoes
$eu.trigger(who, name, times, interval)Starts one effect.
$eu.trigger_all(who, effects)Starts a whole list at once.
$eu.cancel(who, name)Ends an effect early.
$eu.list_active(who)What is currently running on them.

Lists are written as one tuple per effect, which is what you store on any object that should apply several of them at once:

effects = [('intoxicate', 3, 60)] # name, times, seconds apart

The character sees the effect arrive, repeat, and wear off on its own:

A warm, dizzy feeling washes over you. The world spins around you... The world spins around you... Your head begins to clear.
The character needs a tickers property

Effects are timed, so applying one starts a ticker on the character. A character without a tickers property fails with Permission denied: cannot create 'tickers' the moment an effect lands. @adprop <character>.tickers = {} fixes it.

Which one do I want?

Use a ticker whenUse an effect when
An object should keep doing something — a torch burning, a fountain splashing, a beacon sweeping.A character is temporarily in some state that should wear off on its own.
You decide when it stops.It stops itself after the count you gave.
You write the verb it calls, on the object.You write the effect once on $eu, and anything can apply it.

Running code when the world starts

A ticker has to be registered before it can fire, and registration does not survive being set up by hand once. Anything a world needs done on every start — register a ticker, prime a cache, open a gate — goes in $startup_evals, a list of expressions on #0:

#0.startup_evals = ["ticker_add(60, 'sweep', $bin, 'sweep')"]

Each entry is evaluated the way eval evaluates one, so what goes in the list is written in the same language as everything else in the world. They run after the database, the listeners, the tickers and the background tasks are all up, so an entry can register a ticker or reach the network without needing ordering rules of its own.

Keep each subsystem's line with that subsystem rather than as a literal in the list — a property on the object it belongs to, gathered into #0:

$bin.sweep_eval = "ticker_add(60, 'sweep', $bin, 'sweep')" #0.startup_evals = [$bin.sweep_eval]

That stores the value of $bin.sweep_eval, not a live reference to it. Editing the property later does not change the list; the property is where the line lives, and the list is a snapshot of what runs.

A broken entry cannot stop the server

Each entry is isolated, and so is the machinery around them: a failure is logged and the next one runs. These are edited from inside a running game, where a typo is an ordinary afternoon — and a server that will not boot because of a line you can only fix from inside it is a trap. Check the startup log to see what ran:

Running 1 startup eval(s) from $startup_evals startup_evals[0] ok: ticker_add(60, 'sweep', ...)