ChangeLog:
10th May 2003 - added Rants, Wanders, More Complex Traps,
Advanced Rooms, Trade, Zone properties, Advanced Objects.
9th May 2003 - added Containers and States, Doors, and Mobiles.
If anything is particularly unclear, or you want to see something in particular covered next or you have any other comments, please feel free to mail me.
make zone
. You'll be asked to enter the name of the zone.
This should be a short string of alphanumeric characters. For the purposes
of this guide, we'll use the zone name example
. So, type that
in here, and your new zone will be created.
goin example_zone
, and you'll be moved to the zone object.
This is used to store rooms created as part of the zone, and any other
objects you happen to put there.
make room
. First of all you get prompted for the zone.
If you just press enter here it'll default to the zone you are in at the
moment. Then it will ask for the name of the room. This is what's displayed
in look, after You are standing on blah in. Let's call it a
Garden
.
Next, you get asked to confirm the room. Enter yes
. Your
room is created, and it tells you the ID of the room. It then sets you
editing the room description.
If you want to edit a room description do so. You can enter free-form text,
with a .
on a line by itself to end. Use blank lines to mark
new paragraphs.
If you don't want to edit one just now, just enter .
You can now go into the room by goin example_1
.
You displace yourself to the Garden (example_1). Flags [Fixed] [Room] This is a very nice garden. You see... {the floor template_floor_1} Obvious exits are... None...
One noticeable thing is that it hasn't realised this garden is supposed to be outdoors.
Fix this by flags here outdoors 1
, which sets the outdoors flag on the room
to 1 or true.
This will make two obvious changes. Firstly, the floor will be replaced with 'ground', and secondly, it will print out information about the estimated time of day - which will always be midday until this location gets hooked into a day/night cycle.
make room
again, only this time you want to make a Kitchen
, not a garden.
The process is the same as before. It'll create example_2 - which is another room, but
not connected to the Garden in any way.
To start creating a link, type make exit
(from example_1).
It will want the direction (say, north
), the start position (the default should be ok
so just hit enter), the zone (again, just press enter), and the destination. This would be example_2.
It defaults to choosing as the destination the most recently made room you made, so you should be
able to hit enter here again. You get asked whether you want an exit the other way from example_2
to example_1 - say yes
, and finally whether you want to confirm it. Say yes
once more.
It has now created the exits, and you can wander from example_1 north to example_2 and back again.
set example_1 name Front Garden
will change example_1's name to, well, Front Garden.
boot example_3
. While
this will delete all exits from example_3, it won't delete all exits to there. So, suppose you had
made a west exit from example_2 to example_3 - you'd boot example_2_west
.
set example_4_west link example_3
.
For example, if you dig west
from example_1, it will create a new room, example_3,
an example_1_west exit from example_1 to example_3, and an example_3_east from example_3 to example_1.
The rooms and exits created by dig can be amended as above.
Dig will copy some flags - for example Lit and Outdoors from the source room.
make object
.
The first thing it asks for is the short name of the object. In this case it wants to be tree
.
Then, it wants the normal name. It generates "a ^otree^n" by default, and since this is correct, we
just hit enter. (If it were wrong, you'd enter what you really wanted).
It then asks for the start location of the object - which is where you are, so just hit enter,
and the zone, which again defaults to the right thing. Finally it asks you if the object should
be a container no
, and whether it should be fixed yes
.
A container is an object which you can put other objects in, and a Fixed object is one which is scenery and cannot be taken. You can't put things in trees, and you can't take them.
You then get told the id of the tree (example_tree_1), and put in the description setting mode, which acts the same as for rooms.
So, we've got our tree now. What happens when you try and climb it? You get the default
response Nothing happens when you do that.
This response sucks
and we should change it.
We do this with a lua trap. In this case we want the one called climb, which is in the property 'lua.climb'.
Enter desc example_tree_1 lua.climb
, followed by
act(pl, "%1 %[tries/try] to climb the ^otree^n, but %[finds/find] it too smooth.")
and return 1
and finally terminate it with a full stop on a line by itself.
This will mean that code is executed every time someone tries to climb the tree. What does the code actually do?
act
is a messaging function. You have to give it an actor, and a string.
It then processes the string for printing to the actor, and everyone else in the same room as the
actor.
pl
is a constant that's been defined for you. It's the current player -
the one who did the climb.
act() uses the same syntax as action strings. In this case, %1 means the actor's name, or 'you',
if being printed to the actor. The "%[blahs/blah]" is processed according to plurality and target.
If it is being printed to the actor, or the actor is plural, it chooses the second one - blah,
and to others, it shows blahs. This means it will show
You try to climb the ^otree^n, but find it too smooth.
to the actor, and
[Name] tries to climb the ^otree^n, but finds it too smooth.
to everyone else.
The final bit, return 1
, gives a return value to the environment.
If you just fall off the end, or return without a value, or return 0, then it will still
cause the normal course of events to happen. To abort the printing of the default error message,
you do 'return 1'.
There are several ways of fixing this - the first is to displace example_tree_1 example_1
then unreset example_tree_1
. This moves the object to where it should be, then
'unreset's it. Unreset means updating the objects reset state with how it is now, so it
will reset to that position in future.
The other is to directly set the start property on the object, with
set example_tree_1 start example_1
. Nothing happens immediately, but the
next time the zone is reset (which you can force by reset example
, the
tree will be moved to where you said.
example_foot_1
, which is a severed foot.
If you wanted another one of these to play with, you could simply clone it by typing
clone example_foot_1
. This clone would save with you, and may disappear
when the zone it happens to be lying around in resets.
set example_1 name.plural feet
.
The normal name of the object is kept in 'name', and the short name is kept in 'short'.
set example_foot_1 mass 100
will set the mass of example_foot_1 to 100g.
This shows up in 'size', and stops you from carrying too much stuff, or putting
too much stuff in containers.
Two properties are used for clothing, wornon
and
wornlevel
. Wornon should be set to something like
body or legs or arm or hand or eyes or hands or leftleg as appropriate.
[XXX : make a link to a list].
Wornlevel determines what sort of clothing it is - and what it can be worn over. 0 indicates it can be worn over nothing, 1 can be worn over nothing or wornlevel 0 stuff, etc. 0 is used for underwear, 1 for stuff like tshirts or vests, 2 for regular outerwear like shirts, 3 is used for jackets, 4 would be used for overcoats or other protective equipment.
So for our shirt, you would want to set example_shirt_1 wornon body
and set example_shirt_1 wornlevel 2
. And then you can wear it.
set example_sword_1 wtype impact
.
Drink is just like food, except it has the Drink flag.
volume
property on the glass must be set (in millilitres),
along with the WaterTight flag. So, set example_glass_1 volume 568
.
set example_beer_1 abv 300
.
There are two flags here - CanOpen and CanLock. CanOpen means the user can use the 'open' and 'close' commands to change the object between state 0 and 1. (State is stored in the !state property, and gets set on a reset to either 0, or whatever is in the initstate property. An unreset will set the initstate to the current state.)
State 2 represents Locked. You can only transfer an object into or out of the Locked state if you have a key. For example, if example_box_1's key property is example_key_1 or if example_key_1's lock property is example_box_1. If something is a key for an object, then so are any clones of it.
You see... six boxes (locked) three boxes (open) three boxes (closed)This is perhaps rather ugly. We can set the name of the objects in a per-state way. For example, if you
set example_box_1 name.0 an open box
,
and set example_box_1 name.1 a closed box
, and set example_box_1 name.2 a locked box
, then you will see
You see three open boxes three locked six closed boxesThese can be more interesting than that, for example, people have made envelopes that when they are in state 1 represent a sealed envelope and when in 0 represent a torn open envelope.
Additionally, the stated names will be used in more places than just look. If you examine an object it will say "You examing the open box" rather than "You examine the box", and it will make them appear in inventory, etc.
If you need custom plurals for any of the state-specific names, you can put it in name.0.plural, etc.
For example, I might put an example_door_1 in example_1 and call it "a back door" and an identical object as example_door_2 in example_2. When I open one, it should open the other - this is accomplished by setting the 'other' property on each door to point to the other door.
However, this just will set up two linked items - it won't actually stop you from moving through the exit whilst the door is closed. To do this, set the 'door' property on the exit to the door.
set example_door_1 other example_door_2
set example_door_2 other example_door_1
set example_1_north door example_door_1
set example_1_south door example_door_2
How would we make the exit inaccessible? We'd set the 'door' property on the exit to an object, and make sure that is in state 1 - until you dig, when it should get changed to state 0. Let us use the room itself for that purpose. so
set example_1_down door example_1
set example_1 initstate 1
reset example
If you type 'down' you'll get a really nasty error message about the Back Garden not being open. So, set the 'Secret' flag on the down exit. Then, you will be given the usual 'that exit does not exist' error.
The code to discover the hidden exit is quite simple
desc example_1 lua.dig
So, after you've dug (for the first time), it will print a message to you and everyone in the room,
and the exit will then be free to traverse.
-- if example_2 is in state 0 already, we just return (and get the needlessly attempts to dig message)
if state(o1)==0 then
return
end
-- we now know it is in state 1
act(pl, "%1 %[digs/dig] and %[discovers/discovers] a tunnel leading downwards.")
-- do the messaging
setstate(o1, 0)
-- set the room to be in state 0, hence actually unblocking the exit.
return 1
-- return 1 to the environment, which will cause the usual handling to be aborted.
.
make mobile
, then enter at the zone, and enter
guard
for the short, and "a guard" for the long name (no colour
codes). Hardness should be set to whatever you like - say, medium. Wander
is whether the mobile should wander around - say no. Gender should be m or f
or n or a.
It then asks for for the tells. Just enter .
for all of these
at the moment.
Finally, it asks you to confirm the mobile. Do so. You now have
example_guard_1
pflags me NoHassle abey
- use reclaim instead of abey to
get it back).
set example_guard barwhy say You aren't allowed in there without a pass!
The code would be something like
if owner("example_pass_1")==pl then
act(o1, "%1 %[lets/let] %a pass.", pl)
return 1
end
If the owner of example_pass_1 is the player, then it prints a message that o1 (the potential blocker) lets pl (the player) pass. It then returns 1, which means to not block.
Otherwise, it will just fall off the end and block as per usual.
There are 6 flags, BarNorth/South/East/West/Up/Down, and also one that bars all movement RefuseMove. If you use RefuseMove you will probably want to check in the trap the destination (which is o2), and just return 1 if you don't want to block in that direction.
Firstly the body property (defaults to human, can also be set to fish, avian, tetrapod, droid, insect, etc). The only real ability this affects is that avians can fly with the 'fly' command.
The other capabilities are flags. Interesting ones include Gills (can breathe and swim underwater), NightVision (can see in dark), NoLegs (has no legs and can't walk), CantTalk (isn't capable of speech). CantTalk should definitely be set on all non-sentient mobiles.
At some point body types will be made more magical, so a certain body type will imply more flags, and different body parts.
Handlers can either be normal commands (in which case the property is tell.something), or lua code (lua.tell.something).
For example,
set example_guard_1 tell.name tell $1 None of your business.
Will make the guard do "tell $1 None of your business." when he is asked his name. $1 means the name of the player who triggered the tell - you can use this as a target of a give, or an action, or a tell. Of course, any random other command can be used also.
Lua tell handlers can be more complicated. Suppose we wanted the guard to be less rude to the person with the pass. We would remove tell.name from him and replace it with a lua.tell.name as follows
if pl==owner("example_pass_1") then
tell(o1, pl, "Mr Black, sir.")
else
tell(o1, pl, "None of your business.")
end
Note: a return 1 is not necessary for a tell trap.
XXX: Telldefault
It will consider all mobiles in the same room as template_person_1 and choose the best match. It matches on nation, 'role' property, body type (which must match) and gender (chooses matching gender if available).
You can override the default matching and directly set the wornfrom property. This can be set to a mobile id, or '-' to indicate nothing.
This is how the template mobiles should be equipped with template clothes, for example.
Rant array means that it has rant.count set to n, and then rant.0 through rant.n-1 existing.
For example
Then, from time to time, the ranter will execute one of the commands.
set example_ranter_1 rant.count 3
set example_ranter_1 rant.0 say This is the first rant.
set example_ranter_1 rant.1 say This is the second rant.
set example_ranter_1 rant.2 say This is the third rant.
XXX: Rantspeed.
This is what
does.
if o2==get("example_coffee_1") then
give(o1, "example_book_1", pl)
return 1
end
Of course, this only accepts the original coffee object. If there are clones around that ought to
be just as good, we need to handle that too, which can be done by
if isa(o2, "example_coffee_1") then
.
So, that's all well and good - except when you give him the second cup of coffee - he'll just try to give you the book again. Who knows whether it will actually teleport the book to him and cause him to give you it? Or whether it will just fail silently or what - try finding out if you like.
So, to handle that, it must be replaced by
if o2==get("example_coffee_1") then
if owner("example_book_1")==o1 then
give(o1, "example_book_1", pl)
else
tell(o1, pl, "That's funny, I could have sworn I had a book on me a moment ago.")
end
return 1
end
If you want a custom floor, there are several options. Firstly, you can make an object and put it in the room and give it the Floor flag. If you want it re-use another object you have used elsewhere, set the 'floor' attribute on the room to the id of the floor. You can do this to a whole zone with the 'floor' attribute on the zone. (floor on zone will be overriden by floor on room will be overriden by Floor flag on an object).
If you don't want a floor, just set the 'floor' attribute to '-'.
OnWater is used to model the surface of a body of water nowhere near land. You must have CanSwim to get to these.
UnderWater locations are those that are entirely underwater. You must have breathing equipment (Gills flag or wearing an object with Gills flag) to get here - and if you somehow wind up here without it, then you drown eventually.
You can set a 'seabed' property on a room which will mean when you type dive there, you arrive at the dest. There is also the corresponding 'surface'.
Objects dropped in a water location will (a) if they float, they will try to go to a surface if one is set, otherwise will remain where they are. (b) if they sink, they will go to a seabed location, otherwise they will vanish. The CanFloat flag is used to determine floatingness.
In a dark room, most commands will not work. For example, you won't be able to look, and you won't be able to examine objects. You can make some objects visible (or at least referrable to) without making the whole room light - set the Glowing flag on the object. You won't see it in look, but if you know the lightswitch is there you can 'press switch' to try and switch a Glowing lightswitch.
Outdoors rooms will be light and dark as per the day/night cycle - unless they have the Lit flag, in which case they get automatic lighting at dark. How does it decide on the day/night cycle? You set 'daylen' on the zone to a number, say, 100 or 200.
The price is determined by the 'cost' property on the objects, and the ripoff factor of the shop - shop.ripoff which should be a percentage (defaults to 100%).
By default, mobiles will buy back anything. You can change this behaviour by setting the 'stype' - it can be 'none', 'junk', 'anything', 'jewelry', 'vehicle', 'empty', 'weapon', or 'medical'.
[XXX : it's possible to write traps for more fine-grained control on selling back] The price paid for items will be by default 90% of the cost - you can configure this with shop.offer on the mobile.
Traders like this will be capable of wandering around and can sell you stuff from wherever they happen to be. If this isn't desirable, you may want to set the Store flag and all the shop properties on the room instead - and then simply have a shopmob property on the shop pointing at the shopkeeper.
Traders will not buy Contraband stuff unless they themselves have the Contraband flag.
So, $defhospital should be set up to the default hospital recovery room. And 'hospital' property on zones.
But for these zoneprops, it actually grabs the contents of the "zone" property and finds out what _zone object exists for it, and then uses that one. 'fwd' chains should be set up.
zone | fwd | planet | hospital |
city_zone | Foo City | city_10 (City Hospital) | |
suburb_zone | city_zone | suburb_3 (Outskirts Hospital) | |
enclave_zone | city_zone | Bar Enclave |
If you are in city_zone, then it will show up as Foo City, and when you die you wake up in the city hospital. If you are in the suburb_zone, it will show up as Foo City still, but when you die you will wake up in the Outskirts hospital. And if you are in the enclave, you'll show up as in Bar Enclave - and when you die you'll end up in the City hospital.
I tend to like making all rooms sticky apart from those which are part of quests, and that if you logged back into them would be bad.
There are two ways of doing this automatically. Auto clones or tele objects.
Auto objects act just like regular zone-based objects, they can be removed, they reset with the zone and cause the zone not to reset if observed, and they don't save.
Simply add them to the tele array on the room - e.g. tele.count 1, tele.0 example_wall_1, then it will appear that that room has a wall in it. You can examine it.
Note: tele objects must be non-interactive. They should not be Mobiles, Ranters, Wanders, Containers, Lightable, Pushtoggle, or non-Fixed, and their state may not change otherwise weirdness may result. Static scenery, including fixed tables, chairs and beds are ok.
set example_junk_1 discover example_cheque_1
.
Then when the junk is examined for the first time since the zone was reset, the
user will discover the cheque. (In the meantime the cheque should be placed somewhere
hidden, like example_zone, or an inaccessible storage room)
If you want to be able to discover multiple items, you can use the 'discover' array, (e.g. example_junk_1 discover.count 2, discover.0 example_cheque_1 and discover.1 example_single_1).
If you want to clone objects for discovery, rather than make specific ones, use the 'disc' array.
All the various forms of discovery can be done at once.
If you have more complex needs than this, you can actually override the handling with a trap. Setting lua.before_show_desc on an object lets you send stuff to pl, and then return 1 will abort the usual lookup for 'desc'.
If I had a lightbulb and a lightswitch, I could set PushToggle on the switch and set the light property on the switch to the lightbulb. Whenever i pushed the switch, it would toggle between state 0 and 1, and the lightbulb would get turned on (if the switch is in state 0 now), or turned off (if the switch is in state 1 now), with message to the room the lightbulb is in.
PushToggle objects can be set as doors for exits, and this is especially useful if they have a 'reveal' property, that describes what's going on.
For example, if I have a box that is the door for an exit (a hole in a wall perhaps), I can set the box to state 1, and make it PushToggle. I can then push the box to turn the exit on and off. By defualt it won't actually mention that, just will say "You push the box." But if I set 'reveal' to 'a hole in the north wall', then it will say "You push the box, revealing a hole in the north wall." or "You push a box, blocking a hole in the north wall."
A PushToggle object can also have an other, just like a door.
A bed is an object with the CanSleepOn flag. People can sleep on beds, and implicitly sit on them too. But you can't sleep on a chair.
A table is object with the Table flag. You can put stuff onto Tables, take stuff off them. Tables can have heights, so you can't see what's on a table (say, a really high shelf), this is modelled with the 'height' property (measured in mms). If set to above eyelevel (1500mm default), then you can't interact with the shelf.
But, if you stand on a chair or a lower table that's high enough, you can interact with the stuff on the high shelf!
You can stand on tables, beds, chairs, and the floor. Tables beds and chairs should be fixed objects, they will react wackily if moved around.
XXX : bunches of other properties mainly message customisation - including multiple mounters.
Objects with the Fragile flag will break when you smash them, when you drop them, sit on them, sleep on them, or stand on them, or when you throw them at things. You can avoid smashing them by 'putting' them on the floor, rather than dropping them.
Do you not want an object to appear in 'look', but just hide a reference to it in the room description? Set the Invisible flag on it.