| |
|
Map Making Help
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.
This map however, needs a lua-file
attached, in which objectives, functions, conditions, counters,
troop reinforcements and behaviors, need to be scripted. To
attach this file, press the Add Script
button in the MapEditor.
The best way to understand map making, is to open existing bzm-files
with the MapEditor,
open their lua-files
with SciTe
Editor, and study them.
A third 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.
Open these and study them!
For fully comprehending the MapEditor,
you can use this mapeditor.chm,
created by Wespex.
Included are Calvin's
Lua Scripting Guide and other fine
examples.
Concerning the Lua Scripting,
there's a few very basic examples, further this page.
Also use this Basic
Lua Lessons from hitandrun,
[BKP] and Wespex.
Hereby, i thank the authors of these helping files.
|
|
Using the ResEditor to create
a mission:
When you have your graphical map ready, you want to add objectives
and markers
to the map. At first, i have copied these txt-files
and 1.xml from
other maps and simply changed those. But creating markers
and a 1.xml
can also be done with the ResEditor.
The txt-files
for the mission description and objectives, you will still have
to make yourself. Make sure to save these in Unicode
format!
To load a mission into the ResEditor,
you will need a current.mip-file.
This has to be copied from an existing mip-file
to your Run\Data\Scenarios\Custom\Missions\MyMap folder. Because
this is a original map, you will need to edit this file according
to your map.
In the ResEditor,
select the Mission Editor
from the menu and open the current.mip from your mission folder.
It should look like this:
By default, when the program opens, the Project
Tree and Object
Inspector will show the Basic
Info. Logically, in the Object
Inspector, you need to link the Properties
to the corresponding txt-files
from the Scenarios\Custom\Missions\MyMap folder that describe
your mission. Most important here is to set the Final
Map property. Clicking the value
will enable you to browse and select your mission (bzm) from
a list.
It is not an obligation to set a path for the Template
map nor the Settings
file. The above picture however shows
what it does.
Once the Basic Info
is set, you should be able to create a minimap by pressing the
only Toolbar button.
Further down the Project Tree,
you can set the background Music.
Obviously, when you click on one of the purple diamonds, you
can change it's path in the Object
Inspector (which i never do). Right-click
to delete items (which i do a lot!), and right-click on the
folder to insert an item.
Last in the Project Tree,
is to set the Objectives.
Again, right-click on the folder to insert more objectives and
in the Object Inspector,
link the objectives to your corresponding txt-files.
Same as before.
About the X-Y positions,
one should realize, these are not the same measures when using
the X-Y positions
in the MapEditor!
In the ResEditor
(Mission Editor), a map is always set to 512-512. That means
256-256 will always be the middle of the map.
To make it easy, one can simply click on the minimap and a crosshair
will be placed. The X-Y positions
will automatically be set in the Object
Inspector.
There is a little glitch here however, a small bias to the exact
positions on the minimap in the game. When you add 10 or 12
to the numberic value, the result seems to be better. Meaning
266-266 would better reflect the middle of the map on the minimap
in the game.
Next, you can set the Objective secret
flag to true or false and set the Objective
script ID.
When all these options are set, you can finally the mission.
From the Menu,
select Export Result
and you'll be prompted to set a path. In theory, one could use
any path, but logically you browse to your Scenarios\Custom\Missions\MyMap
folder.
It will place a 1.xml
there and some other files. You could still adjust the 1.xml,
the other files are only backups from the ResEditor,
so you don't need them, exept for the mip-file
if you ever want to reload it in the ResEditor.
What i'm trying to say, is that when you would place a download
for the map, the mission folder only needs the 1.xml
and the txt-files,
not the ResEditor
files and thus making the map smaller in size!
|
|
Lua Basics
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.
A script always needs a initializing
function, as shown below.
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 (no matter
where you write it in the script, but it is mostly put at the
bottom).
In the above picture, the function
Init() will start the function
RevealObjective0() after 1 second. Next,
the function Info(),
starting after 19 seconds. One second being 1000.
Make sure to close this function with end;.
The following picture shows a basic
example with one objective
and one reinforcement.
So, let's "drive" through the above script:
At the bottom, the function Init()
starts the function RevealObjective0()
after 1 second.
Jump to the function RevealObjective0()
and notice it will first set the ObjectiveChanged
to (0, 0) and then start the function
Objective0(), after again 1 second.
For the ObjectiveChanged:
(0=objective, 0=not accomplished)
Also notice, apart from the function
Init(), all other functions need Suicide();
besides end;
to stop the function from repeating itself.
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) and next, the function
Reinforce0() will start. Take good notice
that a if/then
condition needs closing with another end;.
Going on to the function Reinforce0():
it performs the action LandReinforcement
and will therefor place any Reinforcement
Groups you named in the MapEditor
(in this example named 0).
Oh yeah, for the function Info(),
that will display the traces written, in the game on screen.
|
|
Lua Basic Examples
* Objectives
The above shows a simple script having 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 an objective is completed.
Let's run through the script: Again, the function
Init() will start the function
RevealObjective0() after 1 second. The
function RevealObjective0()
then sets the ObjectiveChanged
and 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 with units of ScriptID
201.
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 can name the Area to whatever
you like in the MapEditor.
Alternatively, you can play around with the objectives and you
could start more 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 others with different time intervals.
In fact, you can start various functions at various time intervals:
* Win or Lose
Let's imagine a map where you have to defend a certain Area
and capture one. Player 0 has units with ScriptID 200 at the
Area "warehouse" and units with ScriptID 100 to attack
the Area "station". The enemy player 1 has units with
whatever ScriptID.
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 lose if less then 6 units with ScriptID 200 are in the Area
"warehouse".
Remember this is just a basic, imaginary example, to show the
possibilities of winning or losing. However, implement these
in your scripts; with enemy attacks and a chance to lose, the
game becomes more fun!
* Reinforcements
In the MapEditor,
when you doubleclick on a unit, you can set the unit's ScriptID.
Still in the editor, you can create Reinforcement
Groups. Next, you can add units with
a particular ScriptID
to a particular Group.
If you'd give multiple ScriptID's
to more players, they could all get reinforcements by calling
only one group at the same time.
So in the Lua script, you call this group with LandReinforcement().
In the following example, Group 0
will start when player enters the area "ambush" with
more then 2
units. Of course the function Ambush()
needs to be triggered somewhere in the script.
Personally, i mostly put reinforcements into functions that
i can call upon after a certain amount of time. The next picture
shows 6 reinforcements called upon in 3 different ways and different
time intervals:
* Planes
Aviation works a bit the same like reinforcements. Again, in
the MapEditor,
pressing the little plane icon
in the menu, will enable you to set plane types, appear points
and such.
Of course, these settings are the main importance and if correct,
all planes will start from the beginning of the game. However,
some Lua script commands let you play with their appearance
and behavior.
In the script above the function Init()
disables aviation for both parties and starts funtion
Objective0() after 1 second and function
AirForce() after 2 minutes. The function
Objective0()
states that if
more then 2 units of player enter the "facility" area,
then both players
receive recon planes. 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.
Sure, this is not a very logical script, but should only show
the possibilities. For the iTypes of Aviation, please refer
to Calvin's
Lua Scripting Guide.
In the 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. Again
for the iAction types, please refer to Calvin's
Lua Scripting Guide.
|
|
Lua Advanced Examples
* Commands
In the MapEditor,
one can use the Add Start Command
function to command a certain, selected unit. This can be done
in Lua scripting also, using Cmd
and QCmd. The
unit has to be given a ScriptID
of course.
The following picture shows a simple function that calls up
an enemy scout plane with ScriptID 999. It will fly to the given
co-ordinates in the different command lines.
You can give various commands to any kind of unit: For all iAction
types of commands, again, i would like to refer to Calvin's
Lua Scripting Guide.
The next example shows, let's say an infantry unit with ScriptID
19. After 1 second, it will enter building with ScriptID 1000.
After 2 minutes, the same unit will leave the building and go
to the given co-ordinates. From there, it will start to swarn
to the new given co-ordinates.
* Using a variable
In Lua you can assign a decimal, integer or string value to
a (global) variable. Using a function, you can check wether
it's value corresponds to a certain condition. And can be very
handy! However, i'm not going to explain variables here; i don't
consider myself such a great scripter so this isn't up to me
really.
The next example should give an idea of what is possible:
Each time an objective is reached, a SetIGlobalVar
with a particular name is given the integer value 1.
Next, using the GetIGlobalVar,
the function ToWin
will check if
all variables are equal to 1
(and the player will win).
* Using a variable as a counter
Again, this is a bit hard to explain, but i hope the picture
below will make things clear. Setting a local variable i,
one can add a +1 value to a global variable i.
Sounds complicated? Look at the example and try to understand
what happens:
First, it states the local i
value is equal to 0.
If the objective is reached, it will set i
to the value of the global variable numbMissionDone.
Next, it will add + 1
to its value and last it will set the global variable to that
value. So after the 1st objective it will set value 0 into 1
and after the second, it sets the value 1 into 2. The function
ToWin will check if that value is equal
to 2 and then start to run (meaning player will win in this
example).
|
|
|
|
|