|
LUA Scripting Guide for Blitzkrieg® Maps
by kaoz MMXI
|
|
|
|
|
|
01. Introduction
This guide is an attempt to make the Lua
Script file, added to a Blitzkrieg map, understandable for mappers. It
is not an explanation of the script language itself. Therefore, all Lua
references are only in relation to a Blitzkrieg map.
This guide will show a lot of examples, but it does not claim to hold
all the answers and/or solutions. Undoubtedly, more experienced scripters
could come up with a thousand more ingenious possibilities, however, for
the beginner, none of these make it easier to understand. The given examples
in this guide, however, will add flavour to a map, because even with a
simple script, the map possibilities are still interesting and providing
more fun to play the map.
Make it easy on yourself and use the program SciTE
to create or open Lua files; not only does
it provide a recognizable icon to your Lua
files, but through the use of different colours, the script simply shows
more lucid. Also included, is a search and replace function that come
in very useful. You can download it here: SciTE
Included in this guide, are also explanations that handle about map making,
rather than Lua, but I consider these essential,
because they are needed to see the complete picture.
I would not have been able to create this without those who created earlier
guides. Therefore, I need to thank hitandrun, [BKP], Wespex, Rémy, Tangram
and Leon. Besides, I studied and learned a lot from other Lua
files, therefore, I would also need to thank Dimitry M., Kristallagent,
CC_Commander, Milknova, Zigfrid and so many others.
Return to index
|
|
|
02. Map Structure
Obviously, there's two important things to create a map: the MapEditor
and a Lua script.
The MapEditor is used to create this map
graphically, to place objects and units, set planes and map tools, create
reinforcements, add start commands and so on. The map is saved as a bzm-file
or xml-file in the folder: Blitzkrieg\Run\data\maps.
In case of a mod, this would be: Blitzkrieg\Run\Mods\MyMod\data\maps.
The Lua-file is used to
create functions, conditions, counters, troop reinforcements and behaviors
for the map that cannot be achieved through the MapEditor.
This Lua-file also needs
to be saved in the folder: Blitzkrieg\Run\data\maps. (Admitted, you could
put this file somewhere else and link to it, but keeping the map-file
and lua-file together
gives you less headaches afterwards).
The Lua-file must be attached to the
map through the MapEditor.
To attach this file, in the MapEditor, press
the Set Script File button and browse to
the specific Lua-file.
A third important thing to finalize the map, is to create a folder
in the Blitzkrieg\Run\data\scenarios\Custom\Missions directory with the
name of the map. In this map are placed the txt-files
for the ingame objectives and one 1.xml-file
that holds map info, map settings and map markers. These files can be
created with the ResEditor, but can also
be copied from an existing map and then changed.
Make sure to save the txt-files in
Unicode format, if not, it will only show
square digits.
Open txt-files and 1.xml-file
from existing maps to learn from it!
Return to index
|
|
|
03. Lua Basic Aknowledgements
Lua scripting allows you to use some powerful
tools that bring action to a map. The main tool being a function,
which will "do" something. Within a function,
you can start another function or set a condition and moreover, various
functions after the condition. This way it is possible to let specific
things happen, accordingly to the player's or AI's behavior and that's
where it becomes very interesting.
Every Lua script needs a initializing function;
the function Init().
Look at it as if it's the ignition of the script: when the map loads in
the game, it will always start reading this (regardless of where this
is placed within the script).
|
In the above picture, the function Init()
will start the function RevealObjective0
after 1 second. Next, the function Info,
will start after 19 seconds. (1000ms being 1 second). The pre-defined
command RunScript will call the function
only by its title. There are several pre-defined so called keywords
for the Lua language itself and several especially for the Blitzkrieg
engine. The latter are summarized in Calvin's
Lua Scripting Guide (which should always be next to you when you are
map scripting) and we'll deal with most of them in this guide. (I sometimes
refer to these keywords as commands).
Notice that a script-line ends with a ;
(semicolon) and that a function needs to be closed with end;.
Personally, i believe typing a script character by character, is a waste
of time and more vulnerable to typos. Use copy/paste
and simply change the concerning parameters. This doesn't mean you shouldn't
copy without care of course. When a script becomes larger, it's easy to
lose focus. For this same reason, it is better to cluster or group the
script functions logically.
The Lua language is case-sensitive, meaning that it will see a difference
between upper and lower cases. Therefore, writing Function
init() will not work!
Using -- (dashes) allows you to put comments
in a script. Any line preceded with 2 dashes
will be ignored by the engine reading the script. This can also be used
to temporarely switch on or off a certain line.
|
The example above shows a function with the name DebugView
that is handy when testing your map. Unlike the function
Init(), you can specify the function names yourself, but it is
advised to keep this also logical. If the name shows what it does or wants
to execute, it just makes more sense.
Let's run through the script above:
The function Init() would start the function
DebugView after a second, if it wasn't preceded
by the 2 dashes. This is what i mean by switching on/off a specific line.
Imagine that it did start; it will first set the Password
Panzerklein, which enables other keywords like ShowActiveScripts,
ChangeWarFog and God.
After this, DisplayTrace will show the string
Test123 in the upper left corner of the
game screen. This is used so you get informed whether the script is loaded
and running or not.
Next, the ShowActiveScripts() function shows
the current functions executed by the RunScript()
functions of the script. Again, you get informed in Console mode during
a game whether the specific RunScript is
executed or not.
Next, the ChangeWarFog is set to player
1 (the AI), so in testing mode, you'll be able to see the enemy movements.
Next, God is set to player 0 and to mode
2, in which the player is invulnerable and the opponents are killed at
the first contact. In this example the keyword God
is also disabled by the 2 dashes and will not work. Using God mode can
be handy in the beginning of testing maps, but it is advised to test in
normal mode in later stages also, especially when you need to test balances
in strenght.
Notice that, the function DebugView() uses
the keyword Suicide(). Unlike the function
Init(), all other functions need this to prevent the function from
re-executing itself infinitely.
When a function is made to check a specific condition,
you need to also close this condition with
another end;.
|
The above function ToLose states that
if the player 0 has less than 5 units, then
a screen message will be displayed and another function Lost
will run after 9 seconds. The if/then is
a condition within the function ToLose.
From the moment this function has started, it will check the keyword GetNUnitsInSide
and proceed once the condition is true, in this case less than 5 units.
But for now, remember that with a condition
you need another end;.
Return to index
|
|
|
04. Setting Map Markers
Okay, imagine you, me or we have created a map with the MapEditor. So
we have a .bzm (or .xml)
file in our maps folder. (Always keep a backup copy in case something
happens...!). Now before starting to script the .lua
file, you will probably have a good idea what the objective(s) of your
map should be like. To describe the objective(s), set map markers for
them and setting up the map for the BK engine to find it, we need the
files in the folder Blitzkrieg\Run\data\scenarios\Custom\Missions\MyNewMap.
|
You'll see a few txt-files and one
1.xml file.
What is written in the header.txt is what
will appear as a title in the game missions overview, so you want to keep
this short and informative. Long titles make the missions list unreadable.
The description.txt is used to describe
the map's background, obviously. It is however, only shown in the game
when it is part of a chapter. So even there's no real use of it in a single
mission, you should still describe your map as some players might open
and read the file to get a better idea what the map is about.
Same for the subheader.txt: it isn't really
shown in the game, but it is mostly used to write the author's name into
it.
Then there's the objectives: in this example MyNewMap, there's 2 objectives,
being 0.txt and 1txt.
These objectives have both a title or header, being 0h.txt
and 1h.txt.
|
So, if you need more objectives, keep counting and create 2.txt
- 2h.txt - 3.txt - 3h.txt and so on.
Now, let's take a look to the 1.xml. This
file can be made with the ResEditor, but it's easier to copy one and adapt
it.
In xml-language, you will mainly see tags, like <base></base>.
Some tags are placed inbetween tags and some tags require a reference
to a specific file. Don't worry if you don't understand xml, this is just
how it works, but you should be able to read it and understand which particular
reference you need to change.
Everything between <History></History>
tags isn't really necessary. It only holds information about the path,
time and date, author, etc. when the file was created (through the ResEditor).
You could if you want, change the date and author to your desire.
On the other hand, the tags between <RPG></RPG>
are very important! Let's look at the first part:
|
So when the game loads, it will load and read this 1.xml
file. The path between the <HeaderText></HeaderText>
tags needs to point to the specific header.txt
file in your mission folder. If, for example, you have copied this 1.xml
and you have a mission folder called Belgium1940,
then you simply change all the MyNewMap's
into Belgium1940.
Okay, let's move on further through the xml:
The <FinalMap></FinalMap>
tags are also very important and refer to the name of your map, being
the .bzm file. The game will look in the
maps folder and search for the name. If, for example, you have a map Ardennes.bzm,
you refer to it in the 1.xml as <FinalMap>Ardennes</FinalMap>.
Next, you can set the music for the map. Some tags, like these, have items.
If, for instance, you want more music, you could add items,
so it would look this:
In case you don't want any music, just leave it empty between the
tags, like <CombatMusics></CombatMusics>.
Or you can also write <CombatMusics/> which
is the same, but shorter than <CombatMusics></CombatMusics>.
It's not of that great importance though.
Next important part of the 1.xml are the
objectives:
|
So again, you will see reference paths to the txt-files
in your mission folder. Again, change the MyNewMap
into the name of the mission folder.
As you can see, these 2 objectives are items
between the <Objectives></Objectives>
tags. The item Secret can be set to 0
or 1, where 0
will show the objective from the beginning of the game, in contrast to
1, that will keep the objective secret until
you call upon it through the lua script. If you need more objectives,
copy/paste more items and change them.
Now take a good look to the part that says: <PosOnMap
x="96" y="419"/>
These coordinates are used to place the map marker on the minimap for
the objective. In case you don't want any map marker, but still the objective,
simply set their value to zero.
How to find the correct coordinates for your map markers?
These could be set with the ResEditor, but there's an easier way. When
your map is loaded in the MapEditor and in the editor, you would press
the Create button on the bottom left, a
minimap will be created. These files are then created in your Blitzkrieg\Run\data\maps.
There you will find 2 .tga files and some
.dds files. Open MyMap_large.tga
with Photoshop or Gimp.
|
This large .tga file is always 512 pixels
on 512 pixels, no matter the measures of the actual map. In the picture
above, you see a .tga loaded in Photoshop.
Going over the picture, the mouse pointer will show the exact xy coordinates
in the info panel.
So logically, <PosOnMap x="0" y="0"/>
would be the upper left corner, <PosOnMap x="512"
y="512"/> the bottom right corner and <PosOnMap
x="256" y="256"/> the middle. There is however, a small glitch
as many times I noticed it wasn't shown exact. To solve this, you just
add 8 or 10 pixels to the value and you get a better result. Thus <PosOnMap
x="266" y="266"/> would be the exact middle (shown on the minimap
in the game that is). You will notice this glitch very clear when you
for example want a map marker upon a bridge or a house. In Gimp or Photoshop
you get the exact xy coordinates, but in the game the marker is not exactly
on top of the bridge or house. Like I said, add 8 or 10 pixels and it
will shown correct.
Return to index
|
|
|
05. Objectives
The following picture shows a basic example with one
objective and one reinforcement.
Let's
"drive" through the script:
At the bottom, the function Init()
starts the function RevealObjective0()
after 1 second and function Info after
19 seconds.
Jump to the function RevealObjective0()
and notice it will first set the keyword ObjectiveChanged
to (0, 0) and then start the function
Objective0(), after again 1 second.
For the ObjectiveChanged: (0=objective#,
0=not accomplished)
From the function RevealObjective0(),
let's jump further to the function Objective0().
This function holds a condition: if
all units from ScriptGroup 119 of
player 1 (enemy AI) is less
or equal to 1, then the ObjectiveChanged
is set to (0, 1), thus accomplished,
and next, the keyword LandReinforcement
will start and drop units with GroupScriptID
0 into the game.
|
In later chapters, we'll go deeper into reinforcements
and ScriptID's. For now, if you were able
to follow and read the script, then you should have gotten a basic idea
of how a Lua script is running. Which is only very logical in fact.
So, let's try more objectives:
This
script has 3 objectives that follow one another. Setting the secrecy
to the flag (in the 1.xml or Mission
Editor), the next objective and flag will only appear after a particular
objective is completed.
Again at the bottom, the function Init()
will start the function RevealObjective0()
after 1 second.
Next, the function RevealObjective0()
sets the ObjectiveChanged and then
runs the function Objective0() that
states if the units with ScriptID
200 of player 1 are equal
to zero, then the ObjectiveChanged
is accomplished and the next function RevealObjective1()
will start running after 19 seconds.
The same happens for the second objective: function
RevealObjective1() sets the ObjectiveChanged
of objective #1 to not accomplished and then runs Objective1.
When enemy units of ScriptID 201 are
all dead, the objective is accomplished and function
RevealObjective2() will be called.
The last objective states that if
all units of player 1 in Area
"totalMap" is less or equal
to 3, then player 0
will win.
|
Of course, you don't want the player to wait 19 seconds for the
next objective, but it should show that you can play around with timings.
And alternatively, in case you don't want the objectives one after another,
you can start more or all of them at the same time, whenever you like
this to happen.
In the following example, when the objective is reached, it will set off
3 other objectives with different time intervals.
In fact, you can start various functions at various time intervals:
At this point, you should start to see the possibilities that you
are able to call any function at a specific time whenever you desire,
in this case, after an objective is reached.
In case you want all objectives at the start, you could also script:
or even:
Do not "overscript" the function
Init() though; if you would script a dozen RunScript's
or more that would start running at the same time, you might ask for trouble.
Avoid script failures and try to set up a logical time schedule.
Return to index
|
|
|
06. Win or Lose
The 2 keywords Win and Loose
of course are of great importance in determining the game's outcome. Determining
when a player should win is mostly very easy, but the Loose
command, imho, is being very underestimated by most mappers. True, some
maps may not need this at all, but personally I think that if the player
has a chance to be beaten by f.e. an AI enemy attack, the game becomes
more challenging.
Let's
imagine a map where you have to defend a certain Area and capture
one. Player 0 has units with ScriptID 101
at the Area "warehouse"
and units with ScriptID 100 to attack
the Area "station". The
enemy player 1 has units with whatever ScriptID and some of them
will attack the Area "Warehouse".
The function Init() starts the function
ToWin() and function ToLose().
Player 0 will win if more or equal to 6 of units with ScriptID
100 are in the Area "station"
or will lose if less then 6 units with ScriptID
101 are present in the Area "warehouse".
|
Or
imagine a map where the player will lose if the general of his forces
gets killed.
The script doesn't show everything, but the function
Trigger01() states that if
unit with ScriptID 19 of player 0
is equal to zero (thus killed), then
a screen message will explain why. The keyword Loose
is put in a separate function and only starts after 7 seconds, so
the player gets the time for reading the onscreen message.
|
Or
in this example, the player will lose if he has less then 5 units
left.
Of course, this example also doesn't show the complete script. The
function Trigger01() must be called
upon into the function Init() or somewhere
else in the script...
|
How to create AI enemy attacks and Area's will be explained in
later chapters, but I wanted to focus on Win/Loose
first. Experiment with these to add spice to your scenario.
Return to index
|
|
|
07. ScriptID
Another important thing is the ScriptID.
In the MapEditor you can give any unit, building or object a ScriptID,
which can be referred to in the Lua script.
Double click to open the Properties window of any object. By default,
the value -1 is given by the editor.
There exists a suggestion to use the ScriptID's
as follows:
ScriptIDs 0 - 999 for terrain objects and buildings
ScriptIDs 1000 - 1999 for AI (enemy) units
ScriptIDs 2000 - 2999 for player units
However, this is not a written law, instead it is an advise to maintain
order over chaos.
From the moment you have defined ScriptID's,
you can do remarkable things in the Lua script:
The
function Trux() will change the units
with ScriptID 200 to player 0. You
are able to let units switch from sides, player 0, enemy or neutral.
I used this function a lot where the player gains enemy trucks when
a specific area is taken.
The function FrostBite() will damage
the object with ScriptID 100. Using
the following parameter 0 will cause
to completely destroy it. This object can be anything, a tank, a
squad, a building, a group of objects, etc.
The function EnterHouse() will give
a command to the (infantry) unit with ScriptID
300 to enter the house/building with ScriptID
10.
|
So, at this point, you should understand that ScriptID's
are a necessary thing in order to be able to let things happen to them.
This will bring action to your map in every way.
Return to index
|
|
|
08. Area's
Let's go back to the MapEditor for a moment; on the left side you'll
see the Map Tools panel. With this tool,
you can draw retangular or round Area's
upon the map. Hold the left mouse button and use the keyboard arrows to
enlarge the Area, if needed. When you release
the mouse button, you'll be prompted to set a name for the Area.
Take care, because this is case-sensitive!
Later on in the Lua script, you'll be able
to refer to these Area names.
In earlier examples, you have already seen some examples where
an Area was used. It's really handy to create
triggers and thus things will happen from the moment a specific unit or
units come in or leave a certain Area.
Here are 2 more examples:
The
function Objective2() states that
if more or equal than 2 units with
ScriptID 100 or more or equal than
2 units with ScriptID 102 are present
in Area "Fuel Dump", then
the objective is reached and it will start to rain ("RainyDay")
after 30 seconds.
|
The
function Trigger08() states that if
more than 0 units from Player 0 are
present in Area "zone1",
then a command will be given to unit
with ScriptID 111 (which in this case
is a artillery gun) to start shelling the Area
"zone1". After approximately 2 minutes it will
run the function HoldFire() and stop
shelling.
|
These examples should give a good idea of what is possible with
Area's in combination with the amount of
units in or out them. There's also a few keywords/commands that return
the number of mines, fences and trenches from a specific Area.
Check out Calvin's
Lua Scripting Guide for this.
Return to index
|
|
|
09. Start Commands
In the MapEditor, one can use the Add Start Command
function to command a certain, selected unit or even a group.
Select a unit, click on the icon and the Unit Start
Command Property window will open.
From a drop-down list, there's quite some choices of command. Select
one and next, with the window still open, you can click on any spot in
the map to set the x,y positions (notice the pink circle). Or you could
set these manually if you'd like.
You are able to set multiple commands in a row.
|
Use these commands logically; some commands work only in combination
with a specific unit. Although you can set the command, it might not work.
A tank cannot heal infantry and a truck cannot use a spyglass, and so
forth.
Some of these commands can also be achieved through a Lua
script, but not all and vice versa, there are commands within Lua
that cannot be found in the Add Start Command
from the MapEditor. It demands a little practice to know what is where.
Again, check out Calvin's
Lua Scripting Guide for the possibilities in Lua.
In Lua, the keywords Cmd
and QCmd are used to command specific units.
Pre-defined actions like MOVE_TO, SWARM_TO, CALL_BOMBERS, etc. are used
to specify the command. These actions are connected to numbers, which
can also be used instead. All actions are summorized in Calvin's
Lua Scripting Guide.
Let's show a few examples:
Imagine
you have a tank with ScriptID 100.
From the moment you call upon the function
Attack01(), the Cmd will move
the tank to the given coordinates. Next, the QCmd
will let the tank swarm to the given coordinates and finally the
next QCmd will let the tank attack
the unit with ScriptID 200 .
|
Here,
I have changed the actions with their corresponding numbers, so
this function will do exactly the same as the one in the previous
example.
MOVE_TO = 0
SWARM_TO = 3
ATTACK_UNIT = 1
|
This
example shows a simple function that calls an enemy scout plane
with ScriptID 999. It will fly and
scout (action = 21) to the given coordinates in the different command
lines.
|
This
example shows, let's say an infantry unit with ScriptID
19.
After 1 second, it will enter the building with ScriptID
1000.
After 2 minutes, the same unit will leave the building and go to
the given coordinates.
From there, it will start to swarm to the new given coordinates.
|
All these commands can be set for the AI enemy, but also for the player.
However, a player can chose to select the specific unit and change its
purpose; in that case, any given command will get cancelled. It may also
happen that you command a plane and then it suddenly starts to rain, cancelling
any given commands to it.
At this point, you should have a serious idea of command possibilities.
Again, these will bring action to your map. Beware although and always
test your given commands. In a lot of cases, the given commands might
react in the game different as expected. If you, for example, connect
a trigger to a certain action and when the action gets blocked or cancelled
in some way in the game, your trigger will also not work anymore. The
more complicated you make this, the more testing it will need, from various
points of view.
Return to index
|
|
|
10. Reinforcements
Let's return again to the MapEditor, where on the left side, you'll notice
the Reinforcement Groups panel.
First,
click on New Group and the Reinforcement
Group ID window opens. There, set the number you desire and
click ok. In this picture, I have already made a group called 0
and the Reinforcement Group ID window
shows I am making a second called 1.
When you select a group in the upper window, like Group
N:0 which is blue lined, then in the lower window, you can
click the Add group with scriptID
button. As the picture shows, I have already added ScriptID
1000, ScriptID 1001 and ScriptID
2000 to this group.
So, it is possible to create one group that gives reinforcements
to both the player and the AI enemy. In Lua,
you'll need to use the keyword/command LandReinforcement(0).
The parameter of the command refers to the GroupID,
in this case 0. Thus, not to the individual
ScriptID's!
If you have a map where you have lots of groups of units that you
want to "control" more separately, you could give the
same GroupID like the ScriptID,
which makes it a little easier to remember who's who when you are
scripting. So, GroupID 1000 holds
the units with ScriptID 1000, GroupID
1001 holds units with ScriptID 1001,
and so forth.
Then in Lua, when you use LandReinforcement(1001),
you see the concerning units more directly.
By the way, clicking and checking the small white square before
Group N:0 will hide all units belonging
to that group from the map in the editor, which is handy in some
cases.
|
We've seen the command earlier in an example, but here's a few
more:
When
function Ambush() is running, it will
check the Area "ambush"
and if there's more than 2 units of
player 0 present, then
the reinforcements of GroupID 0 will
immediatly take place.
|
In
case you want to have more control over the timing of your reinforcements,
it's better to put the LandReinforcement()
in a separate function, like in the example, function
Reinforce0 and function Reinforce1.
When function Objective0() is reached,
it will run RevealObjective1 after
1 second. Next, LandReinforcement(1001)
will happen after 3 minutes and LandReinforcement(1002)
will happen after 5 minutes.
|
There is one thing you need to pay attention to, when you combine
actions to reinforcements. Reinforcements do take some time to take place.
If a group of tanks would land, they'll do this in an unpredictable way,
one by one. It will not land all the tanks at the same time.
Have a look to the following function:
This
function makes perfect sense, but will perform poorly in the game.
So, imagine that group of tanks with ScriptID
1001; they will land, but the following command Cmd
will only apply to the first landed unit. Because it takes time
for the other units to land, they will completely miss the following
command and they won't do anything.
|
One
way to solve this, is using the Add Start
Command in the MapEditor and add it manually. These commands
work fine from the moment the units land.
However, if you need to set the commands in Lua,
then put the command in a separate function, which takes place after
a certain amount of time (at least the time that is needed to land
all concerning units).
So, in the example, when function Trigger_01()
is reached, it will land that group of tanks with ScriptID
1001 and after 1 minute it will start the function
Attack_01() so that the whole group of tanks start swarming
to Area "zone1".
|
Well, that's pretty much it concerning reinforcements. There is
still the keyword DeleteReinforcement(),
which you obviously, can use to remove reinforcements with GroupID
x.
Return to index
|
|
|
11. Aviation
Aviation works a bit the same like reinforcements. Back again, in the
MapEditor, pressing the little plane icon in the menu, will enable you
to set plane types, appear points and such. You ought to do this before
anything else, I think btw.
Once that is set, you have a little more options to "control"
the aviation through Lua: some Lua
script commands let you play with their appearance and behavior.
In
this script, the function Init() disables
all aviation (-1) for both parties
and starts function Objective0() after
1 second and function AirForce() after
2 minutes.
The function Objective0() states that
if more than 2 units of player 0
enter the "facility"
area, then both players receive recon
planes (0).
Next after 2 minutes, the function AirForce()
will check the "facility"
area and if there are more than 2
units of ScriptID 19 in there, then
both parties receive paratrooper planes (2).
For all the iTypes of Aviation, please refer to Calvin's
Lua Scripting Guide.
|
In
this next example, both parties start with no aviation.
After 10 seconds, the function BomberPlanez()
will enable this type for player 1
and fly to the given coordinates in the Cmd
command.
50 seconds later the function Attackplanez()
again will enable attack planes for player 1
that fly to the same coordinates.
iAction 19 = CALL_BOMBERS
iAction 36 = CALL_GROUND_ATTACK
|
I've
used this one in maps where the player has to conquer an enemy airfield.
It would only be logical that from that moment, enemy aviation becomes
disabled.
The function Objective_00 (the given
function name may seem a little odd, but never mind that) states
that if there is less than 1 enemy
in the "airport" area, then
aviation will become disabled for player 1.
|
Return to index |
|
|
12. Weather
Setting the weather is really easy in Lua,
and especially handy when you need good weather to call (enemy) planes
or when you need rain in case you surely don't want any aviation to happen
(for a specific time).
I
often use these 2 functions because they give me exactly what I
need.
When I call upon function Holiday(),
it will switch the weather to good (0).
It will NOT switch the weather automatically (0),
so sunny days remain infinite until I call upon function
RainyDay().
When I call upon function RainyDay(),
it will switch the weather to bad (1).
And it will switch the weather automatically (1),
back to random.
|
This works fine for me, but you could change it any way you want.
Return to index
|
|
|
13. Variables
In Lua (as in other script languages),
you can assign a decimal, an integer or a string value to a global
or local variable. Using a function, you
can then check whether it's value corresponds to a certain condition or
not. And this can be extremely handy!
Global means that this variable is set,
covering the whole script. Local means that
the variable is set and covering a part of the script. I can't explain
variables fully detailed here, because I don't consider myself such a
great scripter and so this task isn't up to me really. However, I hope
the following examples may show some of the possibilities.
In
this script example, each time an objective is reached, a SetIGlobalVar()
with a particular name (temp.template00.objective.1)
is given the integer value 1.
Next, using the GetIGlobalVar(), the
function ToWin() will check if
all variables are equal to 1 (and
then the player will win).
Again, the script is not complete and of course, the functions need
to be running/triggered in order to work!
|
In
this example, the variable is being used as a counter.
Setting a local variable i, one can
add a +1 value to a global variable
("numbMissionDone", i).
So, when the first objective is reached, it will take the local
i (which is 0).
It will also take the global variable (which is also 0)
and add +1, thus, it will set the
global variable to 1.
After the second objective is reached, it will again take the local
i, but it will also get the global
variable (which is now 1) and add
+1, so now the global variable is
2.
When the function ToWin() realizes
the value of the global variable is 2,
the player will win...
I know, when you see this for the first time, it seems a bit like
rocket science, but if you practice this more, you will get to understand
it.
|
Return to index |
|
|
14. A Few More Tricks
In this final chapter, you'll find a few examples of more complex situations
or goals, achievable through Lua. These
were not invented by myself, but I have adapted them and I often use them
when a particular situation asks for them.
This
script shows how to use a neutral
plane (which will not get shot down by the AI enemy) and drop a
para-squad that will change sides from the moment it enters a specific
Area.
The function Init() will set the global
variable "ParadropSquad.ScriptID"
to 2019, so the para-squad will have
ScriptID 2019 right from the start.
Two seconds later, a transport plane with ScriptID
999 of player 2 (neutral) will
paradrop (22) the squad at the given
coordinates. And calls the function MoveIt().
GetUnitState() will check whether
unit(s) 2019 are waiting. If so, they
receive the command to move to the "LandingZone"
area.
The function ChangePara() will check
if units with ScriptID 2019 are present
in the "LandingZone" area,
and if so, it will change the player side of with ScriptID
2019 to 0.
Thx to Leon.
|
This
script is again, not complete, but imagine the functions are running.
In this scenario, we have an enemy group of units with ScriptID
101. They have commands added and they are attacking the
player within an Area "Town".
When they are all dead, they will respawn and start attacking again.
Look at the function Respawn_00() and
function Reinforce_00() and notice
they keep on triggering each other infinitely.
However, from the moment where the player has more than 3 units
(thus 4), the KillScript() will stop
the respawning of the enemy units.
You can use the KillScript() for other
purposes as well; it can stop any named function.
Thx to GordonCZ.
|
In this scenario, we have a fort that needs to be defended by the
player, while the AI enemy is attacking with a group of units with
ScriptID 100, 101, 102.
What's important here, is the elseif.
The objective may have two outcomes; if
the player has no more units within the "fort"
area and the AI enemy has more than 3 units in the "nibeiwa"
area, then the player will lose and
the objective has failed (0, 2).
Otherwise (elseif), when all AI enemy
units with ScriptID 100, 101, 102
are less than 1 (meaning dead), the
objective is reached (0, 1) and the
player wins.
Thx to runrum for pointing at the 2 Suicide()'s.
|
This function MissionTimer() can be
used to display the time and so call upon the global variables when
you need to time something.
Thx to danzig70.
|
The keyword AskClient("SetCamera(x,y)")
will move the camera view to the given coordinates. To move the
camera to a more or less correct point, try to divide the coordinates
seen in the MapEditor by a value of 1.4 (meaning that if the place
is located in 3000,15000 in the MapEditor, then divide
both values by 1.4 and you will get
coordinates 2143,10714 for the script file).
Thx to [BKP], GordonCZ, cc_commander, runrum.
|
Return to index
|
|
|
created by kaoz - MMXI
|
|