Phantasmal MUD Lib for DGD

Phantasmal Site
Phantasmal API
Archive
DGD
Getting DGD
Game Design Issues
The Kernel Library
LPC
Writing a Library
Changing LPC
Object Cleanup
⁄cmd vs wiztool
Conditional Inheritance
Object Database
Distribute a State Dump?
Designing Driver Objs
FTPD
GurbaLib
HTTPD
State Dumps
Heaven7
InterMUD3
Interrupt Call
Designing AUTO Objs
Misc Issues
NFS
Object Binding
Object Management
Other Net Services
Persistent MUDLibs
Player vs Body
Precompiling
Reimplementing From Scratch
Releasing Code
Rlimits
Script Delays
Misc Security
Outgoing Email
So You Want To...
Start from Scratch?
Supplementary Documentation
Telnet Protocol
Using the Kernel
Using Melville
Using Phantasmal
WebDAV
Which License
What Does It Do?
DGD LPC Reference
Running a MUD
Skotos
CSharp vs DGD
Contributing to DGD
DGD Glossary
Java vs DGD
DGD MUDs
Miscellaneous DGD
MudOS vs DGD
Slush Bucket
Why Use DGD?
Design
Development
Innsmouth MUD
Phantasmal Operation
Setup
Test module index
Phantasmal Tutorials
Comparison to Other Libs
Credits
Current Features
History
Installing Baseline Phantasmal
About

Delays in In-MUD Scripting Languages

In a MUD, mobile scripts and object scripts tend to be pretty simple. They mostly go through a set of actions in order, with an occasional conditional (like an 'if' statement) or loop. So mostly LPC works very well for them, and is far more than they need. In LPMUDs, it's usually far and away the most convenient to just use LPC for all your scripting - it's fast, it's flexible, and you've already got a nice interface to everything your MUD does.

However, there's a problem with that. Specifically, there's a problem if you want your script to delay for a few seconds or a few minutes and then start happening again. Say that you want a mobile to look at what it's been given, wait a few seconds and then give it back disdainfully. It's important to wait that few seconds. The problem is that DGD is single-threaded, which means that execution rounds need to finish quickly so that the rest of the MUD can get on with what it's doing. A three-second delay loop isn't an option, and would halt the rest of the MUD, spoiling the effect. It doesn't work.

One way to do this is to schedule call_outs, or do something roughly similar. That's a bit ugly because you need to split your function into pieces -- "give_script_start", "give_script_after_delay_1", "give_script_after_delay_2", etc. However, once you get over the syntactic ugliness it's not too bad. It does what you want it to. You just have to cut your script up into lots of little sub-scripts.

You could write an entire other language on top of LPC, or perhaps modify LPC in some way for the scripting language. Or compile the language to LPC. Then you could interpret that language, which would let you pause it for delay statements and go back to what you were doing.

You could queue up actions in advance, but have LPC functions that put actions into the queue. So you'd have functions like mobile_do_run(), mobile_do_sharpen(), etc that would queue up actions like "run" and "sharpen" to be done when the current action is finished. Your scripts could have conditionals and other interesting code when they first ran, and add actions into the queue in variable ways. Unfortunately, that means that all control structures must have finished before any of the delays happen. That's not great. It means that mobiles will get stupider as the script goes on for more clock-time. And if a mobile needs to enter a room and then respond to it, it will need to use some variation of the call_out approach above.

A third possibility is to run the script again after each delay statement, and pass some kind of argument to it to tell it where it came back. So your function would use switch() or if() to jump to where you should be after the delay. A delay would become a return statement, along with how long you should delay, and then you'd get called again with an argument for how long you've delayed or something. Your builders would hate you and want to kill you, but it would work.

A popular variation on the above is to write an LPC preprocessor which will turn you delay() statement into a case for a switch() statement, and put a switch() inside your function to jump to the right case. It's potentially more annoying to deal with restoring values of variables this way, though. Remember that local variables lose their value if you jump out of the function and then back in.

From: DGD Mailing List (Par Winzell)
Date: Sun Jan  4 11:31:00 2004
Subject: [DGD] Delay statements in scripting

Merry is Skotos' LPC-based scripting system. It's pretty much straight 
LPC with 'additions' -- e.g. delays, which are implemented with the 
switch solution given by Dworkin above.

Merry is parsed using parse_string() and a rathed mutated version of 
Felix's old LPC-grammar-for-parse_string() grammar. It's broken down 
into a binary format and stored in LWO's. The LWO can reconstruct the 
Merry source or underlying LPC source on demand (the former for editing 
the script, the latter for compiling it to a real LPC object).

The systems keeps a cache of a few hundred compiled Merry scripts 
around, but they can be destructed and recompiled on demand.

One tip for anybody implementing this: remember that the compiled 
objects can't keep any real state. For delays, for example, the callouts 
themselves can't be kept in the generated object. You -must- be able to 
destruct such objects at will.

If I execute an action that requires a delay, it's my body that should 
keep the callout, and then relayeto the appropriate script handler when 
the callout expires.

Zell