Skip to content

Layer Z Script

Original script and idea by Small_Pox Small changes and additions by Kad_Venku

Abstract

The Layer Z Script serves as an improvement upon the standard Empire at War layer z offset. This offset enables you to position units at different heights during the pseudo-3D space battle, but at the same time binds one unit type to one particular z-axis offset. Using variants of a unit is not an option here, as this creates several severe issues with unit selection: You can no longer select all ships of one type via Ctrl+LeftMouse, as EaW handles them as different unit types, not the same unit at different z-axis positions. Luckily Small_Pox managed to create a fully working scripted solution to this problem.

Download

The library can be downloaded from the Shaper's Lab.

Requirements

This download includes a pre-packaged LUA-module that has to be dropped into the data folder of your mod. It contains a library module called libLayerZ.lua and an example gameobject script called objectscript_example.lua. It also includes a xml file called LayerZDummy.xml which you’ll have to register in your GameObjectsFile.xml.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
+[Mod base folder]
|
+−+[Data]
|
+−+[Scripts]
| |
| +−+[Library]
| | |
| | +− libLayerZ.lua
| |
| +−+[GameObject]
| |
| +− objectscript_example.lua
|
+−+[Xml]
|
+− LayerZDummy.xml

In addition you will have to create a bone-only object and assign the model to the object defined in the LayerZDummy.xml file. The bones of this object mark the possible unit heights the script can use. See fig. 1 and fig. 2 as a reference for the used model.

Fig.1:The actual bone model.

Fig.2: The bone model spread out for better visualisation.

In addition you have to fill the bone names you want to assign to a certain ship class into the libLayerZ.lua file. The table in question is defined in the function libLayerZ.setLayerZ(...) and marked as TODO as can be seen in the following source code snippet:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
--- Teleports the given object to a randomized Z-Layer.
-- @tparam GameObject gameObject
function libLayerZ.setLayerZ(gameObject)
    local layerZObj = Spawn_Unit(Find_Object_Type("LAYER_Z_DUMMY"), gameObject.Get_Position(), gameObject.Get_Owner())
    layerZObj = layerZObj[1]
    local layer = "CORVETTE"
    if gameObject.Is_Category("Frigate") then
        layer = "FRIGATE"
    elseif gameObject.Is_Category("Capital") then
        layer = "CAPITAL"
    elseif gameObject.Is_Category("Super") then
        layer = "SUPER"
    end
    local layerMarkerTable = {
        ["CORVETTE"] = {
            -- TODO: Add bone names!
        },
        ["FRIGATE"] = {
            -- TODO: Add bone names!
        },
        ["CAPITAL"] = {
            -- TODO: Add bone names!
        },
        ["SUPER"] = {
            -- TODO: Add bone names!
        },
    }
    local finalBoneTab = layerMarkerTable[layer]
    if finalBoneTab then
        local bone = finalBoneTab[GameRandom(1,table.getn(finalBoneTab))]
        if bone then
            gameObject.Teleport(layerZObj.Get_Bone_Position(bone))
        else
            gameObject.Teleport(layerZObj.Get_Position())
        end
    else
        gameObject.Teleport(layerZObj.Get_Position())
    end
    layerZObj.Despawn()
end

Usage

Once set up, using the script is pretty simple and only requires you to add three lines to an existing object script. The ObjectScript_Example.lua contains a minimal example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
require("PGStateMachine")
require("PGSpawnUnits")
local LayerUtility = require("libLayerZ")

function Definitions()
    ServiceRate = 1
    Define_State("State_Init", State_Init)
end

function State_Init(message)
    if message == OnEnter then
        if Get_Game_Mode() ~= "Space" then
            ScriptExit()
        end
        LayerUtility.enterBattlefield(Object)
    end
end

The added lines are local LayerUtility = require("libLayerZ") in line 3 and LayerUtility.enterBattlefield(Object) in line 14. Also take note of the two imports at the top: require("PGStateMachine") and require("PGSpawnUnits"), both are required for the script to work. The line local LayerUtility = require("libLayerZ") imports the layer z module and allows you to call functions contained within it. The line LayerUtility.enterBattlefield(Object) on the other hand is responsible for setting the layer of the given object.

Merging the Layer-Z Functionality into Existing Scripts

As aforementioned, it only takes the addition of three lines to merge the functionality into an existing script. First you have to make sure that all require(...) statements are fulfilled, so make sure that the script's require(...) statements at least look like the excerpt below, obviously you don't want to remove any require(...) statements.

1
2
3
require("PGStateMachine")
require("PGSpawnUnits")
local LayerUtility = require("libLayerZ")

Then you'll have to identify the first state, usually called State_Init, but to make sure to identify the first state declared in the Definitions() function of the script via the Define_State(...) function.
You then want to make sure that you use the LayerUtility.enterBattlefield(Object) function call at an appropriate time during the OnEnter block of the first state.

1
2
3
4
5
6
7
8
function State_Init(message)
    if message == OnEnter then
        if Get_Game_Mode() ~= "Space" then
            ScriptExit()
        end
        LayerUtility.enterBattlefield(Object)
    end
end