Danzig
Look at this link:
www.lua.org/The lua script files have only scratched the surface of what is possible for BK. They use the most basic functions and capabilities.
From the Lua website:
Lua is embeddable
Lua is a fast language engine with small footprint that you can embed easily into your application. Lua has a simple and well documented API that allows strong integration with code written in other languages. It is easy to extend Lua with libraries written in other languages. It is also easy to extend programs written in other languages with Lua. Lua has been used to extend programs written not only in C and C++, but also in Java, C#, Smalltalk, Fortran, Ada, Erlang, and even in other scripting languages, such as Perl and Ruby. In some of the scripts I wrote, I exploited the array function. This provided some very strong capabilities; like naming individual units or several units. The array function can be used to store variables which can be passed into functions or mathmatical calculations which establish locations, units, script ids.
Example: I named all of the script units for German in a Kursk map; stored in a array:
GArmy = {}
GArmy = {
"Major Roome/9th Army", -- Commander Tiger
"BIV Tank/314th RC Pz Co", -- pzBIV RC
"I/18th Pz Reg/18th Pz Div", -- 5pzII 5pzIII
"II/18th Pz Reg/18th Pz Div", --6pzIII 4pzIV
"III/18th Pz Reg/18th Pz Div", --6pzIII 4pzIV
"Iv/18th Pz Reg/18th Pz Div", --6pzIII 4pzIV
"I/10th Pz Reg/10th PzG Div", --4pzIV
"II/10th Pz Reg/10th PzG Div", --4pzIV
"III/10th Pz Reg/10th PzG Div", --4pzIV
"IV/10th Pz Reg/10th PzG Div", --4pzIVEach of these named units has a unique id# which correesponds to its Script ID#
I also placed map locations and gave them a name which could also be referenced by a variable in a function.
GMap = {}
GMap = {
"C1001", "C1002", "C1003", "C1004", "C1005", "C1006", "C1007", "C1008", "C1009", "C1010",
"C1011", "C1012", "C1013", "C1014", "C1015", "C1016", "C1017", "C1018", "C1019", "C1020",
"C1021", "C1022", "C1023", "C1024", "C1025", "C1026", "C1027", "C1028", "C1029", "C1030",
"C1031", "C1032", "C1033", "C1034", "C1035", "C1036", "C1037", "C1038", "C1039", "C1040",
"C1041", "C1042", "C1043", "C1044", "C1045", "C1046", "C1047", "C1048", "C1049", "C1050",
}The specific German units: Script ID# = Array ID# + 1000
The specific Map Location = Array ID# + 1000
Both arrays store String variables ($), not numercial variables (#). However, arrays can store whatever data you want to put in them.
By using the random function, you can manipulate the script to do severals things.
If the player moves into a location, a trigger reads that action and passes several variables to various functions that perform specific tasks.
In the case of this mission, the player moves his command tank to a location... that triggers reinforcements. Each game in this case is different since the random function is used to determine which set of reinforcements arrive. The player does not know until they arrive in his line of sight; They land and move as Player 2, and not visable until they arrive in the sector and perform the ChangePlayer Function.
In a nut shell (in laymens terms)
The Player moves.
The variable (GID) is established once the location trigger fires.
GID is the variable that equals the Script ID that is set by the random function. GID = (Unit# - 1000): -> In example below I only show the random function for the amount of delay time for reinforcements. The actual ID is determined before land function.
GTN is the Map Location variable : GTN = (Location# + 1000)
DisplayTrace announces reinforcements are moving to the sector.
Reinforcements land & move toward sector.
When units arrive within line of sight of the trigger unit...
Display Trace announces the name of the Reinforcements that have arrived.
-------------------------------------------------------------------------------
-- GERMAN REINFORCEMENTS --
-------------------------------------------------------------------------------
function GBUILD()
if GID > 1000 then
RunScript("GHOLD", RandomInt(30)*1000); -- SET MAXIMUM 30 SECONDS
DisplayTrace("CONFIRM ---- REINF ORDERED....."); -- DEBUG
Suicide();
end;
end;
-----------------
function GHOLD()
GTN = GID - 1000 -- THIS IS GERMAN TABLE NUMBER
RunScript("GLAND", RandomInt(30)*1000); -- SET MAXIMUM 30 SECONDS
DisplayTrace(" ");
DisplayTrace("Reinforcements have been assigned to this Sector");
DisplayTrace(" ");
Suicide();
end;
----------------
function GLAND()
LandReinforcement (GID);
RunScript("GMOVE", 3000);
DisplayTrace("CONFIRM ---- REINF BUILT....."); -- DEBUG
Suicide();
end;
----------------
function GMOVE()
Cmd(0, GID, GetScriptAreaParams(GMap[GTN]));
RunScript("GSTOP", 1000);
DisplayTrace("CONFIRM ---- REINF MOVING....."); -- DEBUG
Suicide();
end;
----------------
function GSTOP()
GNUM = GetNScriptUnitsInArea(GID,GMap[GTN])
if (GNUM > 2) then
ChangePlayer(GID,0);
Cmd(9, GID);
DisplayTrace(" ");
DisplayTrace(GArmy[GTN]);
DisplayTrace("has arrived in the Sector");
DisplayTrace(" ");
GID = 0 -- ZERO ID
Suicide();
end;
end;
--------------------------------------------------------------------------------
In the DisplayTrace(GArmy[GTN]); line the name of the unit is displayed:
III/18th Pz Reg/18th Pz Div
has arrived in the Sector
The useful purpose of this type of scripting allows the same functions to be used for any number of units. You don't have to have a separate function to LandReinforcements, Move, or ChangePlayer for every units in the game.
The use of the random function provides some mystery; the player doesn't know what kind of reinforcements he will receive. But additional use of triggers may actually prevent reinforcements or cause an attack from the enemy. This keeps the player on his toes as he works out the objective goals.
In my research and tests, I was able to pass these variables as Global, for multiple use in several maps. The only issue that I had not solved was passing unit strength, ammo level and experience levels. But because Lua is so flexible and can be embedded and expanded, it was a logical selection by NIVAL.
As you move into C# or C++, you may find that Lua will provide the path between the platforms.
I am still looking for the Test Scripts I worked on which passed Globals between maps. But you can see an example of the use in every Chapter that has many maps:
This function looks at the value of
local variable gew:
Mission Script File (Lua):
----------------------------
-- victory -----------------
----------------------------
function victory()
local gew = GetIGlobalVar("temp.gela.objective.0", 0) *
GetIGlobalVar("temp.gela.objective.1", 0) *
GetIGlobalVar("temp.gela.objective.2", 0) *
GetIGlobalVar("temp.gela.objective.3", 0) *
GetIGlobalVar("temp.gela.objective.4", 0);
if (gew == 1) then
RunScript("Sieg", 5000);
Suicide();
end;
end;If it is equal to 1 (all objectives successful) it runs Script "Sieg" after a 5 second pause (5000).
----------
-- Sieg --
----------
function Sieg()
Win(0);
Suicide();
end;The Win(0) triggers the end of the map, which automatically calls the Chapter Screen... with the Chapter Lua Script.
This line checks the status of variable in the Chapter Script (Lua).
if ( strMissionName == "scenarios\scenariomissions\allies\gela\1") thenIn this case "strMissionName" must be the 'gela' path.
If true: the then statement is carried out... move to next mission or chapter.
So this illustrates how variables are exchanged. Global Variables can be accesses in the Chapter Script file which can be compared against a look-up table or array within the Chapter Script file.
So lets set up a look-up table.
This is how the maps are arranged by Maps numbers:
------------------------------
|..1..|..2..|..3..|..4..|..5..|
------------------------------
|..6..|..7..|..8..|..9..|.10.|
------------------------------
|.11.|.12.|.13.|.14.|.15.|
------------------------------
We have 15 maps. If we are in Map 8 and move to the Hot Zone to the North, we will arrive at Map 3. We pass the Global Variable for North to the Chapter Map... In the Look-up Table (Array), the Map # we are leaving is referenced in relation to the map to the North Map. The Chapter Script knows that we have moved to Map #3 and loads it.
***
Remember this from the old days?
..............0
...........7..|..1
............\.../
.........6-.....-2
............/...\
..........5..|..3
..............4
The compass and corresponding values for each direction.
***
You may be asking about what happens if you try to move out of bounds... or off the grid. That is handles any number of ways...
1) your command orders you to another map inside the grid, determined by the table
2) you are advised that an obstacle blocks that direction; water, mountains, impassable desert, etc.
3) The easiest way is to restrict movement a particular direction in the map itself; water, mountains, impassable desert, etc. This use also is useful when you need to set up choke points.... like the Kasserine Pass. You have to get past it in order to advance to the next map.
Objectives should not be loaded into every map, but should be scattered about. Scoring of these objectives may serve as a means to gain equipment or units; perhaps clearing the AA guns on Map #5 gives you para transports for other areas. Once you arrive at a specific map, you find out you can call airborne units.
Each Chapter may have a Primary Objective, or perhaps several primary objectives which must be taken in order to win. Some of these can be defined as the game progresses, or all at once in the first briefing.
As mentioned before, maps should be uniform: 21 x 21 is roughly 1 square kilometer. If you encounter resistance that is overwhelming, you can move back and regroup, or try another location by flanking or passing by the stronghold by way of adjacent maps. In the test maps, we set up a defensive line across several adjacent maps. This provided the aspect of a front.
Since an army that defends a line must cover alot of ground with limited but equal strength, it is difficult to move to an area which might be receiving overwhelming attackers. A focused concentrated attack on weak areas after probing will likely force defensive units to fall back, bend or break. It is possible to hold the line, but we will look at that aspect later, for counterattacks perhaps. The defender must move to the location. In our test maps, we used the landreinforcment function between several maps using the same script ids and profiles. So no matter where the player attacks, at some point he will meet the concentrated units coming to meet and greet him. But, what if the player punches through the line and moves on? Now you have another situation.
Most of the Battles in France were much like this. Patton didn't worry about occupation during his drive.... he was trying to cut off the enemy's supply lines and force units from well defended fortifications by threatening key points behind their lines. Patton at the Rhine was a pretty big threat if you have 2/3 of the defending forces between two armies. Can you say Pincher or Falaise?
So the point of all of this is the power of what could be exploited in Scripts. Of course.... one trade off. Missions would have a lot of idle time.. pause between map loads. The sense of urgency in a map might change, but in my opinion, the big picture is much much much bigger in scope, realism and the way it really was.
I hope this provides a little point of reference.