  The little terrorist: make your own weapons
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. PRE-REQUISITES

To start tinkering with weapons, you need:
 * current Liero-AI/MP release,
 * suitable Weapon Construction Kit,
 * imagination,
 * some programming expertise.

The WCK is a standard issue on all pre-release versions of Liero-AI, so you
should already have one (you are reading this!).

2. FRAMEWORK

Firstly, make a directory, where will you store the source and another one for
the binaries. It's generally a good idea to make both of them subdirectories of
the WCK root. Note that you should allow no file to have name longer than 7
chars (yes, seven, not eight) or the creator will fail.

Create a file with extension '.VWS', let it be a standard text file. Each line
should be in form <Key>=<Value>. List of legal keys (mind case!):

 Name          Weapon name as displayed in Liero-AI
 Launch        Name of launch procedure (see below for more background on this)
 CoolDown      Speed of weapon cooldown (inverse of time between shots)
 Number        Number of shots between reloads
 Reload        Speed of reload (inverse of reload time)
 Laser         If value is positive, a laser sight is defined for this weapon
 ENIAC         Name of projectile for ENIAC toolbox bonus
 ESpeed        Speed of projectile for ENIAC toolbox bonus
 Picture       Picture to be displayed near the weapon description.
 Desc1         First line of the weapon description.
 Desc2         Second line of the weapon description.
 Desc3         Third line of the weapon description.

3. PROJECTILES

Think about what projectiles will your weapon need. If you are willing to make
a modified standard weapon, you may use some standard parts. For instance, you
don't need to create a poison or water projectile, or larpa/missile splinters,
or nuke stars. Explosions are handled as projectiles as well. These all, and
more, are standard projectiles and you may use it on your will.

For each projectile you have to make a '.VUP' file in the source directory. It
will be a regular text file so you can edit it with Notepad or Norton's F4 (my
way - the best DOS text editor).

The lines of this file contain, one by one, the key properties of a projectile.
Lines are formed of name, equal sign '=' and value. Names are case-sensitive.

The key properties are:
 * Interpolation: how much times do you want the particle movement to be
   oversampled (if you want something to move really fast set it to some
   value like 8; otherwise don't use),
 * Gravity: to what extent is the projectile affected by gravity, typical value
   of this property is 0.04; any gravity is acceptable, including negative,
 * Bounce: how much of the particle's velocity is maintained after bouncing off
   a wall (don't set to more than 1 or prepare for flubber),
 * Air: how much of the air movement (wind, explosions) does the projectile
   inherit; typical value 0.02,
 * TTL: what is the standard Time-To-Live of the particle; the name is somewhat
   misleading, because the particle does not necessarily die afterwards, the
   actual action can be defined freely,
 * Collisions: if set to one, the projectile will be a target for other
   projectiles. Only 255 collider projectiles can be active at a time, so use
   it sparingly (by now...).
 * Directed: if set to one, then the particle automagically chooses one of 16
   supplied Images depending on what direction is it moving to; the directions
   are arranged clockwise every 22.5 deg apart:
    Image  #1 = S (South)
    Image  #2 = SSW
    Image  #3 = SW
    Image  #4 = WSW
    Image  #5 = W (West)
    Image  #6 = WNW
    Image  #7 = NW
    Image  #8 = NNW
    Image  #9 = N (North)
    Image #10 = NNE
    Image #11 = NE
    Image #12 = ENE
    Image #13 = E (East)
    Image #14 = ESE
    Image #15 = SE
    Image #16 = SSE
 * FrameSkip: if animated (not Directed), delay between animation images (in
   frames, that is roughly 1/36th of second when affordable); note that TTL
   counter is increased each image not frame (a frameskip of 2 will make TTL
   of 18 be a second, a frameskip of 1 would make it half a second),
 * IdleStop: if positive, the animation will be halted when the projectiles
   stops moving,
 * Image: a sequence of animation images, or 16 images of a directed weapon,
 * RealTime: that's a tough one. If positive, the projectile will use real
   animation frame instead of game time. This means the projectile won't move
   as fast when the framerate drops, but some special projectiles (doors,
   elevators and so on) need this feature.

Now, the procedures:
 * Create: called when the particle is spawned,
 * Fly: called in every frame for the projectile,
 * TerrainHit: called when the particle bounces off the terrain,
 * BonusHit: called when the particle hits a bonus,
 * WormHit: called when the particle hits a worm,
 * TimeExceeded: called when TTL expires.
 * Killed: called when a collider projectile gets hit by something else.

Note that without TimeExceeded, the particle will last forever no matter what
the TTL is. If not planning to write a handler, use DESTROY standard procedure.

An example projectile could be, say, CHIQ.VUP:

 Bounce=0.9
 Collisions=1
 Gravity=0.03
 Air=0.01
 TTL=18
 FrameSkip=2
 Image=CHIQ1
 Image=CHIQ2
 Image=CHIQ3
 Image=CHIQ4
 TimeExceeded=ECHIQ
 Killed=KCHIQ

provided you name the explosion procedure 'ECHIQ'.

4. PROCEDURES

You will need the most basic programming knowledge here. If you don't have one,
give it a try - the smarter half of the population should get it even in this
explanation (hey, I'm a programmer, I'm not that good in explaining ;-).

The procedure, like the projectile, is a named text file, this time with the
extension '.VPS'.

LAC reads a procedure in lines. Should a semicolon ';' be in a line, all chars
following the semi are ignored (commented out).
A line can be either empty or contain an instruction. Empty lines are thrown
away, while the instructions are interpreted.

You can place a label in the program. A label is postfixed with a colon ':'. It
can be the only thing in a line, but you can use labels before mnemonics. It is
up to your aesthetical sense.

Instructions are made up of a mnemonic and up to three operands. Empty operands
are usually assumed to be zero. Theses parts are separated by spaces, tabs or
commas (whatever you like wherever you like).

The usable operand templates are:
 * <const>: a floating point constant, i.e. '10.5',
 * PosX+<const>: current horiz position increased by a constant, i.e. 'PosX+1',
   or 'PosX+-1' (note that '-' is used together with '+'), or 'PosX' itself,
 * PosY+<const>: current vert position increased by a constant,
 * PosX+<const>*VelX: how do ya think? i.e. 'PosX+2*VelX' or 'PosX+VelX',
 * PosY+<const>*VelY: as above,
 * Target: the hit object (1-2 for worms, 3-255 for bonuses, 0 for none),
 * Owner: the current worm or the owner worm (for projectiles) (1-2),
 * Key[<name>]: state of worm's key; keys are: Left, Right, Jump, Up, Down,
   Mod, Shoot, i.e. 'Key[Jump]',
 * Image[<name>]: loaded sprite named <name>, i.e. 'Image[COLD2]',
 * Projectile[<name>]: loaded projectile <name>, i.e. 'Projectile[BIGNUKE]',
 * Program[<name>]: loaded program <name>, i.e. 'Program[EBNUKE]',
 * Menu[<name>]: loaded menu <name>, i.e. 'Menu[ROOT]',
 * VelX*<const>: how do ya think? i.e. 'VelX*3' or simply 'VelX',
 * VelY*<const>: as above,
 * $+<const>: address in a program, like '$+1' or '$+-1' (the current opcode),
   or '$+0' (the next opcode),
 * @<label>: address of the label for jump operations
 * Mem[<const>]: memory location <const>, i.e. 'Mem[0]',
 * Random*<const>: random number ranged 0..<const>, i.e. 'Random*3' or even
   'Random' (being 0..1),
 * BiRand*<const>: random number ranged -<const>/2..<const>/2, i.e. 'BiRand*3'
   or simply 'BiRand' (being -0.5..0.5),
 * Opponent: gives your chosen opponent,
 * KeyID[<name>]: internal key ID,
 * WVX*<const>: worm velocity i.e. 'WVX*3' or simply 'WVX',
 * WVY*<const>: as above,
 * Phase: current phase of worm animation,
 * Strings[<name>]: loaded string list <name>, i.e. 'Strings[DIEMSG]'
 * AnyBonus[<x>]: random bonus; probability of it being false is <x>/255th
 * HealthPack[<h>]: health pack with <h> energy (standard 30)

This is a fairly useful list of operands, allowing common operations to be made
in a single instruction.

And the instructions (case insensitive) are:

 * Abs <M>,<V>
  Like Let, only that the value <V> is converted to absolute (not less than 0)
  before it is written to memory cell number <M>.

 * Accel <X>,<Y>
  Adds <X>,<Y> to current projectile's velocity.

 * Add <M>,<V>
  Adds <V> to memory cell numbered <M>.

 * AdjFrame <N>
  Perturbs the TTL/frame counter of the projectile by <N> (bigger is shorter
  life span); affects the projectile just created.

 * AdjView <W>,<X>,<Y>
  Moves view of worm <W> by <X>,<Y>.

 * BinCall Strings[<L>],<I>
  Calls procedure named by the string <I> in stringlist <L>. The procedure must
  have the TBinCall type. For details, see the SDK.

 * Blood <X>,<Y>
  Converts material to blood (diggable to diggable blood, stone to stoned
  blood). Don't use.

 * BlueScreen <W>
  Shows a blue screen to worm <W>.

 * Call Program[<P>]
  Calls a foreign procedure, returning afterwards to the next instruction.

 * CallProj <I>,Program[P]
  Calls a foreign procedure for projectile <I>.

 * Chain Program[<P>]
  Jumps to a foreign procedure, not returning.

 * Cos <M>,<V>
  Places cosine of <V> in cell <M>.

 * Create Projectile[<P>],<X>,<Y>
  Creates a particle not inheriting creator's movement, velocity being <X>,<Y>.

 * Damage <T>,<H>
  Damages a target. Usually as Damage Target,10 or something like this. May,
  though, Damage Owner,100 (duh!) forcing the poor worm to commit suicide.
  If Damage is issued against bonuses (which do not have health points), the
  bonus evaporates even if the second operand is zero or empty.

 * Debug Strings[<L>],<S>,<V>
  Displays a debug message giving value of <V> where '%d' or '%f' is found in
  string <S> from string list <L>.

 * Destroy
  Kills the particle which issues it.

 * Dig <X>,<Y>,<R>
  Digs a hole in the dirt. Hole is circular with radius <R>, position <X>,<Y>.

 * Dirt <X>,<Y>,<R>
  Just like Dig, only creates dirt.

 * Div <M>,<V>
  Divides the memory cell numbered <M> by <V>.

 * Draw Image[<I>]
  Draws a picture on the screen.

 * DrawAlpha Alpha[<I>]
  Draws an alpha-blended picture on the screen (hi-res only). Alpha-blended
  pictures can be converted from Silicon Graphics RGB file format by RGBDUMP.
  If you don't know, where to find anything using this format, think: 3dsmax.

 * Dry <X>,<Y>,<R>
  Just like Dig, only clears all water and poison in the vicinity.

 * Explode <R>,<P>
  Create a repelling field of radius <R> with power <P>. Hint: negative powers
  will attract.

 * Fan <R>,<X>,<Y>
  Create a field of radius <R> with wind speed coordinates <X> and <Y>.

 * If <C> $+<R>
  If the value of <C> exceeds zero, a jump is performed.

 * IfGT <A>,<B> $+<R>
  If <A> is greater than <B>, jump relative <R>.

 * IfLT <A>,<B> $+<R>
  If <A> is less than <B>, jump relative <R>.

 * IfN <C> $+<R>
  If the value of <C> does not exceed zero, a jump to relative place is done.
  Observe that $+0 is _not_ the current instruction, rather the next one!

 * IfNE <A>,<B> $+<R>
  If <A> is not equal (roughly!) to <B>, jump relative <R>.

 * IfNW <T>,$+<R>
  Performs a relative jump if <T> (usually Target) is not a worm.

 * IsAlive <M>,<I>
  Gets alive status of worm number <I> to cell <M>.

 * IsClean <C>,Image[<I>]
  <C> contains 1 is current projectile, or picture <I> collides with clean
  water; otherwise 0.

 * IsPoison <C>,Image[<I>]
  <C> contains 1 is current projectile, or picture <I> collides with poison;
  otherwise 0.

 * IsWater <M>,Image[<I>]
  If image <I> placed where the projectile is collides with some water, then
  <M> is set to 1 else to 0. If second operand is empty, default image will be
  assumed, being current projectile's screen image.

 * Jump $+<R>
  Jumps inside the program no matter what.

 * KeyLock <W>
  Increase keyboard lock count for <W>.

 * KeyUnlock <W>
  Decrease keyboard lock count for <W>.

 * Laser <X>,<Y>
  Run laser from current center with steps <X> and <Y>.

 * LaserParm Program[<T>],Program[<W>],Image[<I>]
  Sets laser hit procedures to <T> for terrain, <W> for worms and bonuses. Also
  define the laser beam image.

 * Len <M>,<X>,<Y>
  Places length of vector {<X>,<Y>} in cell <M>.

 * Let <M>,<V>
  Sets the memory cell numbered <M> to <V>.

 * LMCS Menu[<M>],<A>,<V>
  Load cell <A> of config space of menu <M> to memory cell <V>.

 * MakeAir <Y>
  Clears all terrain (including stones and water) from the top to level <Y>.

 * MakeBonus <B>,<X>,<Y>
  A bonus of type <B> is created with velocity <X>,<Y>.

 * MakeGround
  Fills the board with dirt. Not particularly useful in weapons.

 * Message Strings[<L>],<I>
  Print message <I> from string list <L>.

 * Move <W>,<X>,<Y>
  Accelerates the worm by <X>,<Y>. May be used as well for recoil in construct
  'Move Owner,VelX*-0.4,VelY*-0.4' as well as for moving targets when hit.

 * Mul <M>,<V>
  Multiplies the memory cell numbered <M> by <V>.

 * NoAutoBonus
  If called in the launch procedure of a trigger map, no bonus will be spawned
  automatically, regardless of menu settings. Also no water will evaporate.

 * Nop
  Does nothing.

 * Normalize <X>,<Y>
  Normalizes vector in cells <X>,<Y>, unless it's zero, where it just stays so.

 * Paint <X>,<Y>,Image[<I>]
  Draws a sprite <I> or the current sprite, if third operand is empty, on the
  terrain.

 * Poison <X>,<Y>,<R>
  Just like Dig, only creates poisoned water.

 * SafeCall Program[<P>]
  Calls a foreign procedure, returning afterwards to the next instruction.
  Creates a new context for the procedure.

 * Sense <F>,<D>
  The memory cell number <F> gets set to the angle the object should rotate to
  be straight onto the target (picks a target by itself). The cell number <D>
  holds the current distance.

 * SetBounce <B>
  Sets particle bounce value to <B>.

 * SetGrav <G>
  Sets projectile gravity to <G>.

 * SetKey KeyID[<K>],<S>,<W>
  Set key state <K> of worm <W> (if empty: owner) to <S>.

 * SetLaunch Program[<P>]
  Sets the level start event service routine to <P>. If you want your generated
  levels to do something, you have to use this.

 * SetPos <X>,<Y>
  Sets position of current projectile to <X>,<Y>.

 * SetSrc <X>,<Y>
  Sets source position of new particles to <X>,<Y> relative to top left corner
  of the map.

 * SetVel <X>,<Y>
  Sets the projectile's velocity ignoring the previous value. Use if you want
  to stop immediately instead of using Steer 0,0 for that the Steer is slow.

 * SetView <W>,<X>,<Y>
  Sets view of worm <W> (your or your opponent's) so it is centered at <X>,<Y>
  if possible.

 * SetWV <X>,<Y>,<W>
  Sets velocity of worm <W> to <X>,<Y>.

 * SetXY <X>,<Y>,<W>
  Sets position of worm <W> to <X>,<Y>.

 * SetWind <V>
  Set wind velocity to <V>. Positive = to the right, negative = to the left.

 * SetZoom <W>,<X>,<Y>
  Sets zoom view (top left corner) of worm <W> (your or your opponent's) so it
  is centered at <X>,<Y> if possible.

 * ShowMenu Menu[<M>]
  Instantly show menu <M>.

 * SideDist <R>,<L>,Image[<I>]
  Checks the distance of the right side of the projectile to a wall and of the
  left side of the projectile to the wall. They get placed, respectively, in
  memory cells <R> and <L>. Optional <I> specifies the collider used. Note: the
  distance is measured 90 degs right and left from your move direction.

 * Sign <M>,<V>
  Places signum of <V> in cell <M>.

 * Sin <M>,<V>
  Places sine of <V> in cell <M>.

 * SMCS Menu[<M>],<A>,<V>
  Save float value <V> to cell <A> of config space of menu <M>.

 * Sound Wave[<F>],<V>,<B>
  Play sound named <F> with volume <V> (0..1) and balance <B> (-1..1).

 * Spawn Particle[<P>],<X>,<Y>
  Creates a particle that inherits creator's movement, added velocity <X>,<Y>.

 * Splash <R>,<D>
  Create a splash damage area of radius <R> with damage <D>. Hint: negative
  damage will actually heal.

 * Sqrt <M>,<V>
  Places square root of <V> in cell <M>.

 * Steer <F>,<S>
  Changes the particle's velocity so that it's speed is multiplied by <S> and
  it's flight angle is modified by <F>, <F> being counterclockwise in degrees.

 * Sub <M>,<V>
  Subtracts <V> from memory cell numbered <M>.

 * TargetXY <X>,<Y>,<W>
  Target's coordinates get written to memory cells numbers <X>,<Y>. Target is
  usually your opponent, or the worm <W>.

 * TerrainSeed
  Saves terrain generation seed. Must be done before generation start (you may
  not notice lack of it until you run the level over the network).

 * Touch <H>,<V>
  Checks touch sensors. Useful in Fly or TerrainHit procedures. Values of horiz
  and vert sensors are written to memory locations <H> and <V>.

 * Trunc <C>,<V>
  Places entier of <V> in cell <C>.

 * Ultra <M>,<N>
  Distance to nearest terrain collision is written to cell <M>, distance to
  nearest stone is written to cell <N>.

 * UltraParm <X>,<Y>,Image[<I>]
  Set parameters (destination and test sprite) for Ultra.

 * UnBlueScreen <W>
  Hides a blue screen to worm <W>.

 * Visible <S>
  Sets visibility status in hi-res mode.

 * WallDist <D>,Image[<I>],<S>
  Gets the distance to the nearest wall in line-of-flight. It is placed in cell
  number <D>. If <I> is given, a specified collider image is used; otherwise,
  a default one is assumed. Memory cell at <S> gets set to number of frames
  that will supposedly pass until the projectile hits the wall. If you need <S>
  but not <I>, use zero '0' instead of 'Image[<I>]'.

 * Water <X>,<Y>,<R>
  Just like Dig, only creates clean water.

To create blood after projectile hits, set Mem[0] to number of blood drops
and Call Program[BLOODR]. If you want the blood to roughly follow the movement
of a projectile, use Call Program[BLOODA]. Both discard Mem[1] and Mem[2].
Sorry.

5. MENUS

Input file is a text file, as usual, and follows a simple format. This time the
format is case-sensitive, so beware. Each line is formed as <Key>=<Value>.
Files should have extension '.VMS'.

The first key to be encountered is the Title key. It will govern display in the
top line.

 Title=Liero-AI 2.00 Settings

Next, there are some blocks consisting of a block header
 <Type>=<Caption>
and some of these:
 Transferable
 Value=<Value>
 Constraints=<Constraints>
 Event=<Handler>

The <Value> is, well, value. The <Constraints> vary from <Type> to <Type>. And
the <Handler> is name of your procedure (in LAIC), or some dark and still yet
undocumented kernel calls to modify low-level system variables, as gravity.
They will be available from LAIC shortly and hence you don't need to know them.
Maybe only 'SubMenu', give submenu name as <Value>. Mind the case or you'll get
screwed. The <Value> is converted to floating-point and assigned to PosX and
VelX arguments when running <Handler>.

All your options other than Buttons should always be Transferable, as there is
no use of another options. Generally, avoid Buttons for anything else than
submenu selection, because they do and will cause very serious problems in the
network mode, unless very special precautions are taken. I can't think of any
use for buttons short of choosing levels, anyway.

Available types are:
 'Text'        Does nothing but displaying a cute white bold text.
 'Button'      When pressed, calls <Handler>.
 'Single'      A slider to adjust a numeric value. <Constraints> hold the
               maximum for the slider. The minimum is zero.
 'Integer'     A input field for an integer. <Constraints> hold a text in form
               of '<Min>,<Max>'.
 'String'      A input field for a string. Don't know why you'd need it, since
               LAIC has no strings.
 'Key'         Press a key, get a code. Again, don't know why you'd need it.
 'Player'      Select player type (Human/AI/None).
 'Quit'        Closes the menu, (almost) just like [Esc]. You really don't what
               to know the difference. We rule. Power overwhelming.

Other information on menus is far above your security clearance, as for now.

6. STRING LISTS

You can't operate on strings in LAIC, but you can use strings as messages. This
is done through string list files, '.VSL'. Basically, each such file is a set
of lines, and you can access individually any line. Do you know that no strings
are held in the Liero-AI executable?!

7. GET IT TOGETHER

Now, unlike former releases of Liero-AI Developers' Release, you may use an
automatic compiler that will build any set of files for you free of charge ;).
Just invoke LAC on the '.VWS' file and it will do all the dirty work for you.
Exactly like this:

c:\liero-ai\wck\lac chiq.vws -c

and after some churning you get your file (the '-c' switch prevents dozens of
files from showing up). Copy the '.VPK' result to Liero-AI directory.

Hint: you can trick LAC into compiling more than one weapon into a '.VPK' file
by creating a '.VLF' file which lists all '.VWS' files. Build it instead of the
'.VWS' file and you get an archive. A good idea to create a '.VLF' listfile is
to use 'DIR /B /ON >TEST.VLF' MS-DOS command.

Note: if you do the above, you can write a single-line file of type '.VCR' and
include it in your build. It will be displayed on start in the copyrights
section. Always observe to add the new-line character to the end of file. If
you are not sure whether you have one, add it. It won't do any harm (unlike the
case you left it with no end-of-line; it would hang the game).

Caveat: don't be surprised if after adding or removing a line from your menu
the configuration didn't read from the last known set. Instead, it was restored
to defaults because Liero-AI can't determine if it can copy old configuration
to new menu. It could even result in heavy data corruption. For security, it's
omitted. The same rules of course pertain to kernel configuration, but that's
definitely none of your business...

Warning: avoid placing '.VKC' and '.VMC' files in archives. It should not do
any harm, but if it does, it will be some nasty GP fault or even disk scribble,
in the very unlikely pessimal case. In general, don't create binary files by
hand, even if you suppose that you can. Instead mail me, I will give you some
details on their structure. I don't want some boo-hoo just because you fiddled
with the binaries to get more funky colors. All that can be done is accessible
from the text file level, remember?

Good luck for all who read through about 600 lines of text,

Stanislaw Skowronek, thesis@elementy.pl
