Introduction
Lifecycle
Game Styles
Artwork
Starting Guide
Config file overview
Config file syntax and declaration order
Config file reference guide
Engine variables reference guide
AI Types
Tips and Samples
Sample Zot config files
ZOT Introduction
The ZOT-Engine is a reasonably generic tile based game engine designed
with the goal of enablind creation of simple "Action RPGs" and
"Action Puzzle Games", in the grain of Gauntlet, Sokobon, Time
Bandits, and maybe even simple forms of Zelda or early Final
Fantasy's. Its a moving target with the engine being designed
for making a number of games that I've been wanting to for a long
time...
NOTE that as ZOT grows, its config file will change, but I will
try to keep the documentation halfway right :)
-- Jeff
ZOT 0.19 Engine Lifecycle
- Run Zot!
- Finds a Zot directory; starts zotlog.txt within it, if a
desktop platform
- Parse Zot/config.txt -- this first config.txt is just a
minimal one, to load up and define a font, and specify artwork
to use for game picker skin
- Look for Zot subdirectories; each entry that doesn't have a dot
in it is assumed to be a game directory, and is listed in the
game Picker
- Show picker and artwork; allow player to pick a game
- Change directory into the games directory
- Load up config.txt for this game (which may in turn pull in
other config files, etc)
- Run the engine until player or system requests exeunt
- Finish.
Supported Game Styles
This is not an exhaustive list.. certainly although
I don't say we can do "Bomberman" style games, you very much can
since Bomberman is just a limited tilemap with sprites on top... very
much within the domain of things Zot! can manage. However, that said,
Zot! was designed with a few game types in mind, so is probably
better at them than some other styles of game. (ie: Zot! will not
likely be good for making Street Fighter style games in.)
- Top-down action puzzlers; think Gauntlet, original Zelda or
Final Fantasy's, Time Bandits .. action or simple-RPG games.
- Platform run-and-jumpers; think Mario, Great Guina Sisters, etc.
- Rotate-and-thruster; think Asteroids/Blasteroids, etc.
Really, Zot is just an engine that knows how to draw tiled images
in a background, with sprites and transparencies on top of it. So
any game you can think of like that, with lots of smaller sprites
instead of a few giant sprites, should be within the realm of the
doable.
Zot! is a general purpose engine, which means its always a work
in progress. You will likely need new Triggers or Actions or engine
features (AI modules, weapon attack types, etc) that the engine
does not support, or doesn't quite do what you need. Feel free to
just ask .. maybe its already covered and you overlooked it, or
maybe a feature can be done through other means, or maybe I need
to build it. At earlier Zot stages, most things will need to be
built in...
How to configure for each style
Note that it is trivial to change between the different playstyles,
since in essence we're just altering how the player does his
thing.
- Top down free movement; this is the default behaviour. If
player has no "option velocity" active in his sprite config,
this is what will be going on.
- Platformer; just add "option velocity" to player's sprite
definition, and it will now be effected by gravity and friction.
You will want to set up the world variables to have gravity and
friction .. so the player drops to the platform, and so he slides
a little (but not too much!) for your game. You might as how
to define gravity etc... simply use a trigger that fires off
when the level loads, and has variable-set actions to set up
all the goods.
- Asteroids; add both "option velocity" and "option angles".
You will also *need* a "anim_spritedef" section for "angles", so
the engine will have all the pre-rotated artwork; if you specify
"option angles" and then no angles section, the results are
undefined. (maybe it'll crash, who knows?). Gravity and such
apply in this mode of course.
As you can see, you can just leave those options in the config
and comment them out (put "#" at the line beginning) to turn them
on or off and experiment.
Starting Guide
I believe Zotscript is relatively easy to get into (though it
can take some work to get to the advanced parts for sure!), though
it can be intimidating to look at for the first time due to the
sheer variety of options and statements available. To try and
make it a little easier to climb into for the first time, here are
some basic pointers..
- You can probably just copy the "nil" gamelet from the dev kit
and have a basic empty gamelet going in seconds!
- For making new artwork, or converting artowkr, you'll need some
graphics program that speaks PCX and TGA, since those are the only
two that Zot currently handles. (Because they're simple formats, so
keeps the engine small; I built a module to load PNG artwork
and the application quadrupled in size.. just for loading PNGs! When
its a handheld application, size is to be avoided, so there you go.)
I suggest using The Gimp for Windows or Linux.
- When you start hacking away at your first config.txt you'll
want to keep it simple -- don't bite off too much all at once or
you'll just hang yourself :) Start adding to it like this perhaps..
- First add in a couple of images in your image-list block.
You'll want at least an image for the player artwork, and an image
for the first tile, and I think you need the first image for the
font as well if you expect any text to show up. To keep it easy,
keep the player artwork separate from the tile artwork, though you
do not have to. ie: A tile art coudl be any image in PCX or TGA
format that is at least 16x16 big, though 16x16 exactly is better :)
- Define at least one basic "tile" definition; it needn't be anything
fancy.. just:
tile .
name floor
image myimage
tile end
- Define your basic tilemap for the first level; a tilemap must
be at least 15x15 or so to keep the devices happy, but you could
create something all empty using your first tile, like this.
Remember you need to specify a width and height first, and then
provide one 'row' for each of the height. The '@' is defined
below!
tilemap level1
width 15
height 15
row ...............
row ...............
row ...............
row ...............
row ...............
row ...............
row ...............
row ...............
row ...............
row ...............
row ...............
row .......@.......
row ...............
row ...............
row ...............
tilemap end
- Define the player sprite; you can copy it from another
sample config file. It has to have at least a "still" animation
in it, though you can add all the directions in if you like.
- Make sure to have a tiledef with "option starthere" in it,
so that the engine knows where to start the player. So add a second
tile definition like this:
tile .
name floor
image myimage
option starthere
tile end
- You can break things up into multiple config files, but you do
not have to; its just as easy (especially when starting out!) to
just have the one config. Since you must always have a config.txt
for your game, you might as well start with... config.txt :)
- Some sprite definitions are required for the engine
to run at all so be careful to include them, somewhere,
in your config :) For instance, you must have a sprite
whose id is player, or the engine won't know what to display.
You can copy it from any of the sample configs to get going, though
remember to copy any required artwork! Furthermore, if you want
to fire, you must have a sprite id of arrow in there somewhere,
unless you define a change-weapon action that fires off right when
the game begins, to specify another sprite that is the weapon! If
you plan on using explosions, remember that they have sprite
names they need for the components of the fire (See the AI for
the explosions for details.)
Artwork
Artwork is pretty simple, but theres a few basic rules. I'm not
honouring fancy or recent file formats.. they tend to be very complex
to build and have a million variations and options.. PNG support
tripled the size of the application! As of Zot 013 only supports
Targa (TGA) and PCX, each with different features..
PCX
- Always 'fast' (as fast as sprites can be)
- Must be 8bpp (not 16bpp or 24bpp) -- each image has its
own palette space though, so each image can have its own
8bpp palette
- Since PCX has no alpha channel, use a pixel value of
RGB(123,123,123) to make it 100% transparent (see through)
- Use a pixel colour of RGB(222,111,222) to darken the
existing screen pixel (like an alpha-darken effect)
TGA
- Targa optionally carries an alpha channel; without alpha,
its just as fast as PCX above; with an alpha channel, it is much
slower so should be used sparingly.. can easily cost a few FPS
for each sprite!
- 32bpp is ideal (RGB 8bpp each, plus 8bit alpha)
- Alpha channel is blending/transparency -- using dark with
alpha to darken background; use light with alpha to lighten.
Use whatever colours you like and optional alpha for cool
blending and shading and tinting effects...
ZOT 0.10 Config File Overview
config.txt is the default loaded config; to keep things 'simpler'
for the level designer, I've broken out another config file and called
it 'preconfig.txt'; config.txt includes a directive first-thing
that causes ZOT to load preconfig.txt, and thus essentially
preconfig.txt gets loaded first, and then config.txt's main
body gets loaded. With this in mind, I make careful choices of
where to put things..
- preconfig.txt -- contain "models" and "archetypes" -- these
are abstract descriptions of things that will be reused on
each game floor. For instance, you would define a generic monster
here, so that you could use it in multiple floors without having
to redefine it. This keeps the level designers from having to look
at monster definitions all the time, keeps the config for each
floor down in file size, and provides a nice split.
- config.txt -- contains "physical real world objects" -- so
while you might define a monster in preconfig.txt, you would tell
the engine to create a copy of that monster at coordinate 10,20
(say) in config.txt; you define the tilemaps and tile definitions
in the config.txt, since they are real world things unique to a given
floor.
So the rule becomes.. if its a definition of something you
intend to re-use .. a toolbox object.. you put it in a preconfig.txt
type file; if its somethign that belongs on a single level, like
a tile or map definition, it goes in a level config such as
config.txt.
ZOT Config Syntax and Declaration Order
The syntax of the configuration file is fairly flexible,
but the engine interprets it very carefully, so you must
be careful to conform.
The config file is a line based key/value pair file, with
comments. This means..
- You DO NOT end lines with anything (like a semicolon, etc)
- Every option is KEY and VALUE
- Spacing before and after each key/value is IGNORED
- Comments can begin anywhere, but finish the line
- Order of key/value pairs is usually not relevent
- Order of groups IS relevent
- Spacing is spaces, tabs and other junk
- Non-spacing counts as key/value!
- Case tends NOT to matter
- Multiword Values may be quoted
Example Good Lines:
somekey somevalue # tab between key and value
somekey somevalue # indented child item just for us puny humans
anotherkey anothervalkue # spacing between key/value is ignored..
fookey foovalue # spacing irrelevent
# comment can begin line # comments can begin anywhere
somekey somevalue # comments can begin at end of line
say "hello friend" # multiword 'value'
Most OBJECTs in the config are not a single key/value pairing,
though several engine options are; for instance, one might specify
the starting level with a single key/value pair, but defining a
monster is a block of some 5-20 key/value pairs (each one with its
own line in the config), all grouped within a sprite-start and
sprite-end pair. See the reference guide for details...
Order of Declarations
Note that for most references, something must 'exist' (be
declared and loaded) before you refer to it; ie: You must use
an image-list to load up and name images, before referring to the
image in tiles, sprites, etc. But some objects can refer to things
that do not yet exist, for convenience of writing the configuration
file..
- A sprite can refer to a generator that is not yet declared
- A tile can refer to a conveyer that does not yet exist
- A tile can refer to a door that does not yet exist
- A tile can refer to a wayout that does not yet exist
- A tile can refer to a button that does not yet exist
- An action-group can be defined later; an action can refer to
"action-group 10" before action group 10 is defined. This can
be a handy way to work around that some actoins depend on things
being created, that you've not yet defined in the config. Then
after they're defined, have an action group that refers to them.
- Everything else requires the object to exist before being
referred to
ZOT Config File Reference Guide
ZOT is almost entirely driven by configuration files, so this is
the real meat of the engine.
- Directives
- Variables
- Image-list
- Fonts
- Sprites
- Tiles
- Complex or Special Tiles
- Text Menus
- Triggers
- Events
- Actions
Directives
A directive is a key/value pair that is not within a larger
block. ie: Its not part of a sprite definition.. it just says
what level to start at, and thats it.
- "config-read" instructs ZOT to go read another config, and
then when finished, to come back and finish this one. Avoid
circular references on your own :)
ex: config-read preconfig.txt
- "post-message" instructs ZOT to post a message to the
screen right away; when the game world draws, the message will
be right there. A good way to put some quick credits or level
titles onto the screen. NOTE -- be sure to quote multiwords.
ex: post-message "Demo Level". See the post-message action for
details of formatting.
- "startmap" -- specifies the tilemap the player will begin
in in this config-set.
ex: startmap mainfloor
- "score VARNAME" -- identify variable as being a player
Score; the Zot engine will do something with it, such as display
it in the screen corner.
- "health VARNAME" -- identify variable as being a player
Health variable; the engine doesn't care about it, but it will
display it somehow or another.
Variables
Variables are in essence holders of numbers. You can create, set
or read them. (Creating a variable occurs just by referring to it
in a read or write.) There are two kinds of variables -- special
engine variables, and user-land variables.
- "engine variables" are variables in the engine itself; you can
read or set them (some are read only, some are write only, and
some are read-and-write), and usually something will occur when
you do so. ie: The player location is an engine variable.. you
can use it in a trigger to make something occur if near the player,
say, or write to them to move the player.
- "user variables" are variables you make for your own purposes...
you can name them whatever you want pretty much. Just read or
write to a variable to create it.
There are a few rules to note..
- Engine variables begin with "_" (underscore). You cannot
make variables that begin with underscore, or Bad Things will
happen.
- User variables must begin with a letter. If they begin with
anything else, Bad Things will happen.
image-list
An image-list block has the engine load up a series of
artwork files and associate them to a name that can be referred to
in all other sections of the configuration; ie: instead of
referring to "house_white_32px.pcx", you would use the image-list
to load it up as "house" and use it thereafter. This is the only
way to get images into the engine.
image-list start
bluebrick bluebrick.pcx # basic 16x16 blue floor tile
brownbrick brwnbrick.pcx
floorgreen floorgr.pcx
image-list end
The image-list can also accept a few basic transformations; put them
on the line after the filename for them to kick in. Note that the
alpha layer (if present) is also transformed :) (Zot engine v013
or later only!)
image-list start
floorgreen floorgr.pcx rotate90
image-list end
Possible transformations are:
- rotate90 -- rotate the image 90deg (counterclockwise)
- rotate180 -- rotate the image 180deg
- rotate270 -- rotate the image 90deg (clockwise)
- flipx -- flip the image left over right (across the Y axis)
- flipy -- flip the image top over bottom (across the X axis)
- rotate### -- you can now do arbitrary rotations; for example,
"rotate230" will rotate 230 degrees for you; note that using
the arbitrary rotator hits the load time a touch, especially for
larger images.
Fonts
The font-block defines a font for later use by the engine.
offset_x and offset_y define the beginning of the image data in
the artwork; char_offset_x is the spacing between characters in
the artwork, while kern_offset_x specifies the spacing to use
between characters when they are rendered (kern_offset_y specifies
the spacing to be used between lines). image defines the
artwork to use (previously loaded by an image-list). Lastly,
the charmap lists the characters in the font, in order.. it is
used by the engine to find the characters to display them.
font fpsfont
offset_x 1
offset_y 1
char_offset_x 10
kern_offset_x 9
kern_offset_y 9
image skeefont
charmap "! #$%&'[]*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRST" # etc
font end
Sprites
The sprite-block defines a sprite 'model'; nothing is added into
the game world, but you can turn this sprite model into one or
more sprites easily in another section of the configuration.
The 'sprite' word's value is the name of the sprite, used forever
after to refer to this model. The name is only used for displaying
the name of the sprite if we ever need to do that. order is used
for render order -- its a value from 1 through 3 inclusive, and
the "1"'s are drawn first with the "3"'s drawn last. If you want to
draw rooftops or treetops or transparent catwalks above the level,
you would use large order-3 sprites to do it. speed is the walking
speed of the sprite.
AI is the 'intelligence' function used to make the sprite do things.
For instance, you can set up "mob_wander" which simply guides the
sprite to wander randomly around the area. "mob_robotron" on the
other hand makes the sprite attempt to move directly towards the
player, always. You can (as of ZOT 0.10) specify two kinds of AI --
one for "always" and one for "when player is near"; you then specify
the number of tiles that define "near".
image_width and image_height define the clipping of the artwork.
width and height define the size of the 'body' -- the substantial
part of the sprite. You can also use offset_x and offset_y to
specify the location of the body within the sprite itself.
So for instance, it is cool to specify a large sprite, and then
make the body a smaller square within it; also, specify the body
to be a little down from the top using an offset_y, so that the "head"
of the sprite can go onto walls etc (since the body is the part that
impacts for collision test sake); this gives it an isometric appearance
since the head goes over the wall...
Sprites are animated; as such, you must specify at least one
animation state, though you can specify many animation states (one
for each state the AI function can be in); most sprites care only
about movement direction states, so they MUST have a state for
"still" (standing still), but can also have state for
"up" (while moving up), or "upright" while moving up and right, etc.
All 9 directions are covered, of course. An animation block is
by state, and can have anim_steps (number of steps in the animation
before going back to frame-zero), anim_offset_x and anim_offset_y
(the number of pixels to move over for each frame of animation)
and anim_image (the name of the artwork to obtain animation frames
from). "anim_shift_y" is how far to go down in the artwork to find
this animation set. (ie: So you can have X going across for
animaiton frames, and shift-y to go down to find alternate sets of
animation; thus define one artwork file for all animation for a
given sprite!)
sprite states are (as of ZOT 0.10):
still, up, down, left, right, upleft, upright, downleft, downright,
inactive, angles
The special states work as follows:
"anim_steps" may have an option line in it; "option once" will
make that animation occur only once (not repeat). Only applies
to sprites.. not conveyers, etc.
The sprite-block ends with a 'sprite' keyword.
sprite baba # name of sprite for later use
name baba # display name of sprite if we ever display it
order 1 # spr. order is 1..3 (start at 1, 3 is drawn last)
speed 3
# AI details
ai mob_wander # the AI to use
ainear mob_robotron # the AI to use when player is "near"
near 3 # 7 tiles away is "near"
# dimensions; artwork dimensions and sprite body dimensions!
image_width 16
image_height 16
width 16
height 16
#
# while standing still
anim_statedef still # if engine needs a missing state, first state used
anim_steps 5 # 7 artworks in pcx file
anim_offset_x 25 # artwork is 25px offset from last step
anim_image pointyplus # use this image for animating this state
#
sprite end
NOTE that sprites have options you can turn on and off; options
available to sprites are:
- "option pushable" -- if present, this sprite will get
pushed when a player bumps into it; the player is able to
push the sprite any which way, though it never allows the
sprite to move in a way he can't normally move (ie: If the
sprite bumps into a wall or other sprite, it just won't
push any more); ex: pushable walls
- "option carryable" -- if present, this sprite will
be taken out of the world and put into the players inventory
when bumped into by the player. ex: keys for doors
- "option indestructable" -- if present, the player's
shot does not damage this object; the players shot will simply
stop, as if it hit a wall. ex: for keys, so you don't destroy
them...
- "option airborne" -- if present, the sprite's movement
is not impacted by floor based effects (as of ZOT 0.10, this
means conveyer-belts). ex: players shot "arrow" sprite..
it doesn't make sense for players shot to get altered by
flying over a conveyer belt..
- "option impassable" -- if present, sprite cannot be
walked through; if not present, sprite is like a ghost.. you can
go right through it. (Any mob can go through it). ex: Maybe
set a bouncy fireball so it goes through the player, hitting him
and keeping going. But most sprites should be impassable.
- "option ethereal" -- a sprite marked ethereal can *always*
enter another sprite (though it still cannot enter impassable
tiles); ex: fireballs -- you want them to fly a constant path,
maybe using mob_bounce to bounce around. They should go through
player and mobs, so make them ethereal; you could leave the
option off, and then they bounce off players :) You may want to
make fireballs indestructable too..
- "option nostill" -- the sprite will start in Still state of
course, but this option prevents it from returning to the still
state; ie: Once it stops moving, it'll stay in the same state if
the player lets go of controls; normally he would, for example,
return to the still state.
Other keywords..
- "start_direction DIRNAME" -- suggest to the AI that it
begins in that direction; ex: mob_bounce needs this.
Tiles
A 'tile' is a building block of the world; it is re-used, though
can be unique for the really interesting squares on the map.
For instance, you would define a tile to represent a common
floor square, with some pretty floor tile artwork. You would then
assign this same tile to most squares on the map. This is done
for efficiency sake.. rather than us store a giant 2000 by 2000
pixel map, we store a map of tiles, and most tiles are just
references to the same tile object. This is how we have very
large maps playable on very low powered devices. (A 'tilemap',
detailed later, is how you build up the world based on tiles.)
Your basic tile, for a floor or wall, is simply defined:
# a sample floor tile
tile x # tile is called "x" in tilemap
name floor # name if we ever display it
image floorgreen # artwork to use
tile end # end of tile def
So the most basic tile definition is very short; the most important
parts are the "x" above and the image; the "x" is the name of the
tile and must be a single character. To draw a row of this tile
in the tilemap, you would just say "xxxxx" to put 5 of these tiles
onto the map.
NOTE the size of a tile is built into the game engine; it is
changable only by Codejedi, but for efficiency and to allow complex
artwork and walkways etc, we've chosen a tile-size of 16 pixels
square. Before you run away in fear of making hundreds of little
tiles of a large piece of artwork, note that the options below allow
you to use larger pieces of artwork and have the engine split it
up dynamicly for you, so you can have large artworks on your tilemap
easily.
Here is a sample wall tile:
tile N # call it "N"
name northwall # display name
image brownbrick # artwork
option impassable # make it a wall
tile end # end
Note that the only difference here is we just added an option
to the tile, and this option says this tile is not enterable by
sprites or player. Thus, it is conceptually a wall.
The usual artwork options exist: offset_x and offset_y allow
you to specify the offset to the tile in question, within the
great artwork body. The main reason to use offsets is to allow
you to draw a piece of artwork (say) 48x16, and then be able to
refer to the left part as a tile, the middle part as a tile, and
the right part as a tile. Quite handy. Check out autotile
below which is a HUGE TIMESAVER.
Example: It could be handy to draw all the wall artwork in a
single artwork file; then you could use offsets to specify where
in the artwork each wall tile is. This lets the artist have it
much easier (one file rather than dozens), and the level designer
need only specify the coordinates of the specific tiles artwork.
Options available are:
- "option impassable" (watch the spelling!) -- an impassable
tile cannot be entered by anything. Its like a wall.
(This is a conveniance function that is the same as doing all
4 option_impassable_directions)
- "option impassable_up", "option impassable_down",
"option impassable_left" and "option impassable_right"; the direction
refers to where the sprite is coming from; ie: impassable_down says
this tile cannot be entered from the down-side.
- "option autotile" -- SUPER USEFULL. If you draw a piece
of artwork that is larger than one tile, but wish to display it,
you would have to manually specify all the offset_x's to get
to each piece of it, and make a number of tiles. Autotile lets
the engine do it FOR YOU. Ex: If you made a doorway that is 32x16
pixels (2 tiles across, 1 tile tall), then you could manually
create a tile 'l' (left), and another tile 'r' (right), and 'right'
would have to have "offset_x 16" to tell it to use the right-half
of the artwork. INSTEAD, you would just define one tile (call it
'd' for door, say), and mark it with "option autotile". Then in
the tilemap you can refer to "d<" instead of "lr"; "d" would be
the tile you defined (the left half, since no "offset_x"), and
the "<" is a special symbol that uses autotile to determine that
this is the "next tile over" which would be the right half. So
you can define a loooong piece of artwork like this "a<<<<<<<<"
and define only one 4 line tile in the config to do it. SEXY!
Complex or Special Tiles
Most tiles are just plain ordinary unanimated background tiles..
the player runs over them, or into them, but they don't really do
anything fancy.
Some tiles are interesting -- wayout tiles can transport a player
to another floor, while door tiles block the players passage while
closed, etc. These tiles are further described here..
Complex tiles are tiles that "do something" other than just
sit there or apply flags against the player. For instance, a 'door'
tile is really a fancy tile than can exist in one of several states
at any given time. A wayout tile is one that shifts the player from
one map to another, and is also animated so it can do stuff.
Note that usually you tie a regular tile to a complex tile
reference; this lets us do thing slike have 5 tiles that all point
to a single (say) door tile reference; opening the door will be
reflected in all referring tiles, for instance. Make multiple
buttons work together (change one, they all change) for example
if you want to, and tie groups of conveyers together..
NOTE: Yes you can construct much of these tiles via complex
trigger/action scripting but it is better to use the built in
mechanisms for both performnce reasons, and the fact the engine can
Do the Right Thing with them.
NOTE: Yes, you can use these tiles for other than the intended
purpose; a door tile is really just a multi-state tile, and a wayout
is an animated exit tile.. but you needn't exit the player anywhere.
If you want an animated tile, use a conveyer say or wayout and
away you go :)
TIP: A conveyer needn't look like a conveyer; you could dress it
up like water and use it for urrent, say..
Here are the types of complex tiles..
- Button (multiple states with action on state change)
- Door (multiple states gadget)
- Wayout (animated, allows for player map change)
- Conveyer (animated, can push player around)
- Mob Generator (is actually a sprite; see mob_generator AI!)
Each complex tile is detailed below..
Button
A button is a gadget that can be in one of a few different
states. Since you use artwork of your choice for each state, it
needn't *look* like a button .. it could look like any gadget you
want, such as a lever, a pressure plate, a fountain, or anything
else. A button can be activated by the player just entering the
tile, or you can require the player to press the action button
on his controls. Thus, a pressure plate is (for example) just a
two-state button that is triggered on player entry, while a
wall mounted switch is a two state object that is toggled by the
player pressing his action button. When activated, a button changes
state (and thus can use alternate artwork to look different)
and fires off an Action (which can in turn fire off an Action
Group).
Configuring is easy; you need to make a button object
in your config, and then you need to associate one (or more!)
tiles to it. ie: You might associate multiple tiles to the button
object, so that adjusting the button in one place impacts it
in other places as well. Note that the tiledef does not need
an artwork setting.. the buttons artwork is used instead.
Note that the tile can refer to a button
that does not yet exist, if it wants to.. the tile can be defined
before the button.
Note that a button can have 4 states: alpha, beta, delta, sigma
You should specify the beginning state, and for each state you
should specify which the next state is when changing; ie: When you
activate the alpha state, does it go to the beta state? And when going
from beta state, does it go back to alpha state?
A button state can have an Action mentioned; this Action will be
fired off when the state is .. 'exitted'. ie: When player enters it
or hits his action button, as the button dictates, the states Action
will fire off.
A note about Actions and buttons: Note that usually buttons are
defined before a tilemap (floor) is, so you might wonder how to have a
button do a "goto-floor", since you cna't set up a goto-floor when the floor
is not yet defined. In this case, set up an action to invoke an action-group,
and that action-group includes goto-floor command... and the action-group
is defined AFTER the tilemap! hoho!
A typical boring button setup might be:
# define a tiledef that happens to refer to a button
# notice.. no artwork is defined for the tiledef
tile b
name buttondoorx
button 1 # associate with button-1
tile end
# create a button object; note its button '1' mentioned above
# notice each state has an artwork defined for it
# notice you specify the state to begin in!
# a button has at max 4 states
# notice that "toggle_door" is a special built in Action, but you can
# specify actual Actions to invoke, to do all sorts of crazy things
# notice you can specify the statee to change to when this state becomes
# activated
button 1 # a lever is the same as a button w/ alt. artwork
state alpha # state to begin in
anim_state alpha
anim_image buttongr
toggle_door 1 # action to take on exit of state
option trigger_entry
exit_state beta # state to go to after this one
anim_state beta
anim_image buttonor
exit_state alpha
toggle_door 1
option trigger_entry
button end
Text menus (dialog, talk trees, etc)
As of Zot 014 this is still WIP, but seems to be working well.
The basics are.. a text menu tree is popped up by a Trigger, and
offers some text and options, where picking an option fires off
an Action(s).
text-menu 10
preamble "Welcome to this menu; blah blah blah, blah blah rant."
"Open the door" end-dialog
"Quit" goto-menu 5
text-menu end
In essence, there are few options though more will be added
hopefully (such as hints to show a character portrait while talking,
etc); namely, you need to include a 'preamble' with a quoted value
which is the text menus main text. The system will word wrap it
as appropriate to fit the screen. Other than preamble, you need to
supply 1 or more options, which are quoted text keys, with the
value(s) being action(s) to take when that option is selected.
See the section on Actions for a discussion of actions that
can be assigned, but typically you could open another text menu
to continue the discussion, or you could close the dialog and
return to the game.
NOTE: The default artwork to show the selection is an image
named "textsel"
NOTE: As of Zot GBAX edition, up to 10 option entries are allowed
in a textmenu.
Additional options:
- "avatar-image IMAGENAME" -- show a textmenu with a little
picture to its left side; textmenu is offset to the right
enough not to collide with the image. Good for showing a
picture of someone/something the textmenu is dialoging or
describing.
- "avatar-name" -- name an avatar image; shows up under the
image.
Triggers
A trigger is a set of required conditions, along with an action
request to perform when the conditions are all met. An Action of course
can be an Action Group and thus the trigger could result in several
things going off. An example might be to require that the trigger
watches for a player entering a certain square, while also carrying
a certain item, causing something to occur. Note that there are
interesting Actions like turning on or off a trigger, or setting
variables.. so you could require that player goes to a certain area
which invokes a trigger to set a variable, and have another trigger
that awaits player to show up somewhere while having that variable
set, and thus require the player to go to one place before going to
another, etc. A lot of flexibility is granted here!
NOTE that there is a special class of triggers known as "Events".
See them below!
NOTE that with Triggers and Actions you can reconstuct some
other primitives of the engine.. for instance, you could implement
triggers and actions to facilitate Exits/Wayouts, or Doors, or
Buttons. It is usually better to use the built in systems, however,
since they already have animation, state saving and all the goodies
worked into them. Triggers and Actions are usually used for defining
things the engine doesn't already do :)
You can combine many triggers, but one action; that action can
invoke an action group however, so in effect you can have many trigger
criterion, and many actions as a result of the matching of all
criterion.
trigger 1
on-player-entry 5,6 # when player enters 5,6
on-floor mainfloor # and on floor 'mainfloor'
action action-group 10 # perform a group of actions
trigger end
The trigger criterions are:
- on-player-entry (requires argument of x,y for coordinate) --
satisfied only when player is in square
- on-floor (argument of floor name .. the tilemap name) -- only
satisfied if player is on the mentioned floor
- on-variable-equals (requires two arguments; variable name and
value that satisfies the trigger).
ex: "on-variable-equals foobar 5"
- on-variable-lt (requires var name, value); less than.
- on-variable-gt (requires var name, value); greater than.
- on-variable-ne (requires var name, value); not-equal to.
- on-no-sprite (requires floorname spritename); example:
"on-no-sprite mainfloor orangekey"; this lets you say to do
something if all of a monster has been destroyed, say.
- on-pickup-sprite (requires spritename); example is
"on-pickup-sprite orangekey". You can use this trigger
to make a message or chage variables or goto floors etc, when
the player picks up something.
You can also specify some options to triggers..
- "option continuous" -- normally a trigger can get activated and
then it will not be activatable again until it becomes unactive.
(ie: Once it matches, it stays matched and does not re-match).
With this option it matches, fires off, and then unmatches so
that it can match again next check. This is slightly higher load
of course, but good for continuous effects like damage-by-time
traps, etc.
- "option disabled" -- disables the trigger. This is useful
because you might have an action set up which later enables it
(or disables it again, etc).
- "option onceonly" -- stops trigger processing after this
trigger. Allows one trigger to catch an event (say), and then
halt processing before another trigger also processes it.
Events
An Event is a special kind of trigger that occurs in real-time
during world processing. Thats hard to think about, but its
for things like damage -- if one object runs into another object,
it has to be dealt with immediately, since (1) one of them may die or
otherwise impact the world .. mob changes direction, etc.,
or (2) thats the only time we know what object hit what other
object.
So if one mob (for example) runs into another mob, a "collision"
event is generated immediately, all event-triggers are checked for
handling this type of event, and then the world continues. Since you
can have a lot of these (hundreds of mobs walking into each other
for example) it is best to keep the resulting actions simple and
not length, but you can do whatever you like.
An event is just a trigger that has a "when-" clause within it;
it should likely also have other "on-" trigger clauses in it as well!
Event clauses:
- "when-collide " -- to make an event
for one mob running into another. (ie: A robot walking into a
player works fine!). The action (or group) invoked as a result
of this event has _from and _into special variables defined.
- "when-dies " -- to make something happen when a
mob dies. Not player, since player death ends the game :)
Special variable _mob is defined during the duration of this
event.
- "when-ltezero " -- to make something
occur when a mob-variable goes to (or less than) zero. _mob
special variable is defined during this event.
ex: "when-ltezero player health"
Actions
An action is a 'transformation' you can cause in the world; usually
an action is the result of a Trigger, or perhaps a Text Menu item being
picked. For instance, you may configure a Trigger to watch for
some event to occur, and when those event conditions are met, that
an Action will be fired off. So the Trigger is the "watch" condition
while the "Action" is the "result of the trigger. You "enter the door"
and "as a result, the pie hits you in the face" :)
NOTE that there are two kinds of actions really.. a single "action"
which is something specific, like "open the door number 17", and also
"action groups" which is a collection of actions. So you may want
a text menu to simply end the dialog and return to the game (a single
Action), or you may want the text menu to cause a monster to be
created, a door to be opened, and player to get some score. This would
be an Action Group, and the text menu would refer to an action that
launches the group as a whole.
NOTE: ZOT is currently being built to allow no more than 10
actions in each action-group, but its possible to invoke action-groups
from within action groups..
action-group 10
post-message "Welcome to 6,5" 3
post-message "Second action.. after Welcome" 3
goto-text 1
action-group end
The available actions are:
- "goto-text" -- argument is ID of text menu to display.
- "end-dialog" -- no argument; end text menu session.
- "action-group" -- argument is ID of action-group to invoke.
- "post-message" -- argument is quoted string to display.
Note that variables can be embedded in the string.. use "$varname"
to do so. As such, use "$$" to put a single dollar-sign into
the string, since otherwise a single dollarsign begins a variable
expansion. You may use variables side by side, ie: "$var1$var2".
Ex: "something '$myvar' foo" will come out as
say "something '2' foo".
- "variable-add" -- argument of variable name and value to
add to it when activated
- "variable-sub" -- argument of variable name and value to
subtract to it when activated. This function may be appled
to a mob during an event trigger:
ex: "variable-sub _from.myhealth 10"
- "variable-set" -- argument of variable name and value to
set it to when activated
- "trigger-change" -- argument is trigger ID and one of:
'0' is disable trigger, '1' is enable trigger, 'toggle' is
toggle trigger. Use this action to turn a trigger to enabled or
disabled.
- "goto-floor" -- argument is name of floor; note, this most
be defined after the floor has been defined in a tilemap. You
could define an action that invokes an action-group, and then
after the floor is defined define the action-group with the
goto-floor in it. "action goto-floor 2ndfloor".
- "make-sprite" -- argument is spritename and x,y coordinate
(in tiles); ex: "make-sprite baba 3,5". Attaching this to a
on-entry button allows you to have a pressure plate that spills
out monsters say... or a textmenu option that creates a mob to
talk to, etc. As of GBAX edition, make-sprite can use
_from or _into as location, meaning it copies the location from
the referenced mob.
- "kill" -- only usable during an event trigger; as of ZotGBAX
only the when-ltezero event trigger supports it. Use
"action kill _mob" in the action or action-group fired off
by the event.
- "end-game"; kills the application.
- "script"; A powerful Action that lets a trigger, button, door,
etc fire off a Zotscript script. The action requires two
arguments.. the script-name, and the function-name. Example:
"action script myscript myfunction"
ZOT AI Types
Each sprite must have at least one AI's chosen for it; the AI
is the "behaviour" the sprite takes while active in the game
world.
The player must be 'player'. Sprite definitions should usually
use the mob_ series of AIs.
Many AI's have options you can set. You can also use 'near'
to define an AI for when player is near, and when player is not
near; ex: Set a mob to wander randomly, then robotron him when
he approaches. Or run form player when he nears, but otherwise
act as a mobile generator :)
- mob_arrow -- moves in a straight line, removes itself and
enemy on impact.
- nil -- does nothing on its own
- player -- does nothing on its own
- mob_robotron -- always move directly towards player; will
throw when-collide events when bumping into player or mob.
- mob_generator -- wants to create new mobs (see generators)
- mod_wander -- wander randomly; will
throw when-collide events when bumping into player or mob.
- mob_flee -- always move directly away from player
- mob_bounce -- move straight, reverse direction on impact
- mob_animonce -- no intelligence, but animate once and then
kill self. You should use "option once" in the anim-steps
definition, so that it can actually qualify for this. This
was used in ZotGBAX for example to make a floating damage
indicator above impacted sprite.
- mob_guard -- stand where created; if away from this spot,
uses robotron logic to move back to that spot. For example, can
use ainear to have mob go towards player, and if player gets
too far away the mob_guard will then return to spot. However,
shooting the mob will make him robotron the player. Note that
for guard->attack mode to occur, guard must have a variable
"health" so it knows its gone down.
Engine Variables Reference Guide
The ZOT engine includes a number of internal variables; some of
these can be read, or written to, or both.
For mob-specific variables, see below.
All internal variables begin with an underscore ( "_" ). When you
create your own variables you can name them whatever you want.. as
long as they do not begin with an underscore. Those are reserved.
Engine variables may be entirely useless, or may do cool things..
its entirely up to what you want to do :)
- "_player_speed" -- read and write. Setting it adjusts the
players speed. A player default speed is defined in the
configuration (say, preconfig.txt in the default ZOT setup).
You can do math to it.. say, add 1 when a player picks up
"speed boots" by using a trigger, for example.. (and then
subtract 1 when player loses speed boots, say.)
- "_player_x" "_player_y" -- read and write. Player location..
setting it will teleport the player. Not usually a good idea,
since you don't know whats there.. but if you make a map area
that monsters can't go into or the like, it makes a good
candidate..
- "_player_dirmask" -- write-only. Setting it limits the
players input buttons. (ie: There are 6 inputs.. the 4
directions and the fire and action button.) The bits are:
left(1), right(2), up(4), down(8), fire(16), action(32).
ie: The default mask is hex=3F which is all flags allowed.
By limiting it to say decimal=3 you limit the player to
left and right only. The value must be in DECIMAL.
- "_ticks_since_begin" -- read/write; When the engine starts
up this is 0; for each world tick (not player ticks, which happen
twice as often) this increments by 1. You can read it, or set it
if you wish to alter it. ie: You could do a trigger on this to
have some pre-game initialization, for example, or do periodic
events.
- "_world_gravity_x" and "_world_gravity_y"; Can be negative.
Adjust these to put forces against the player sprite. ie: A
_world_gravity_y of "1" will push the player down 1 thrust
unit each tick. "-1" would push the player up the screen! You
can therefore have gravity in any arbitrary direction and
strength using these two variables. An example is in a platformer..
player jumps, and then comes back down to his platform; if he
runs off a platform, he falls to the next one down. This is
gravity. (Requires "option velocity")
- "_world_friction_x" and "_world_friction_y"; These are similar
to gravity, but they converge on zero. (ie: Gravity can take a
positive velocity and eventually make it negative; friction just
reduces it to zero, stopping the player.) An example is a
platformer.. player runs for a bit, and when he lets go of the
controls, his sprite slows to a stop (but doens't stop
immediately.) (Requires "option velocity")
- "_player_jumpvelocity_y"; 175 is default. When player pushes
"up" on controls, and is in "option velocity" (but not angles)
mode, he'll thrust up. This variable controls the amount of thrust
(or the height of the jump). The jump height is relative to this
variable against the current gravity and friction. (Requires
"option velocity")
- "_player_movevelocity" (default 7); change this to change how
much thrust the player exerts when trying to move. This is only
useful when "option velocity" is active.
Mob-variables
Variables created inside of a sprite-block are attached to the
sprite definition, and whenever that sprite is created into a mob,
the variables will be copied into it. As such, this lets you create
variables that belong to the player or mobs, with each mob having
its own set. Perfect for health, etc!
"variable myhealth 100"
Tips and Samples
A ghostly cathedral or graveyard
could easily be simulates thusly:
-
In ZOT 0.11 you can flag a sprite as "ethereal", meaning it can go
through other sprites, always. (Sprites marked "impassable" as of 0.11 are
not normally enterable, but if you forget to mark them impassable, things
can enter it, but it cannot go through other things unless it is also
ethereal)
So, say you want a graveyard or other ghostly place where the
monsters can come through the walls, but the player cannot?
Simply make the walls out of sprites (using the same artwork as
walls normally would), and flag the monsters as ethereal.. the mobs will
then walk through the walls, and the player.. will not.
Note that there is a performance hit here, since we'd be using
sprites for walls.. meaning, the tile underneath would be rendered, and
then the sprite... so double the cost for each tile. Framerates could
suffer, so use sprite-walls sparingly!
Or how about a vertical shooter level?
- A conveyer square need not *look* like a conveyer; it could
just use floor tile artwork and no animation. Simply set a whole
area of map as conveyer that looks like "shooter background"
(floor, outer space, whatever), and the player will be constantly
pushed in the direction and speed you've set for the conveyer.
Then you place mobs with limited "vision" at points in the level..
such as setting them to "nil" AI until player is "near", and set
up a suitable "near" setting. So the player will be forced along
at a constant speed, and can fire at incoming enemies. Thats it..
a simple rudimentary shooter :)
If you want something to occur every few times, you can
use variables: See this example below -- trigger ID 2 increments
a variable every time player enters its square. Trigger ID 1
will only fire off when player enters the square and the variable
is equal to 5; when it fires off, it shows a dialog, but also
sets the variable vack to zero(0), so that it can go off again..
Thus you can see the action-group ID 10 goes off every 5 times
the player walks by it.
action-group 10
goto-text 1 # show a message/dialog tree
variable-set foobar 0
action-group end
trigger 1
on-player-entry 5,6
on-floor mainfloor
on-variable-equals foobar 5
action action-group 10 # do stuff
trigger end
trigger 2
on-player-entry 5,6
on-floor mainfloor
action variable-add foobar 1
trigger end
Sample Zot config files
Some sample simple config files are here:
Zot 0.1.5c:
config.txt and
preconfig.txt