Report Data
First step in making a report is deciding what data to use, and where that data comes from. For this report, we're looking at unit HP, which comes from RGDs in the attrib\ebps\races folder. For each RGD we want to know:
- HP (GameData\health_ext\hitpoints)
- Name (GameData\ui_ext\screen_name)
- Is the unit only in the campaign? (filename will have "sp" in it)
A rough idea of the process is also helpful:
- Make list of units that have HP
- Sort list according to HP
- Print list
Making the unit list
We will have a table called unit_list into which suitable RGDs are placed: (The first line here is a neat little hack to put methods from
table
into the table itself)
unit_list = setmetatable({}, {__index = table})
function each_file(rgd)
if rgd:GET("GameData","health_ext","hitpoints") then
unit_list:insert(rgd)
end
end
Sorting the list
By using the at_end function, we can carry out an action after all the RGDs have been processed. This is the perfect time for sorting our list: (no need to use GET() as we checked that the RGD had a hitpoint value before inserting it into the list)
function at_end()
unit_list:sort( [ (a,b)
| a.GameData.health_ext.hitpoints
> b.GameData.health_ext.hitpoints
] )
end
Printing the list
We can only print the list after we've sorted it, so we will add printing code after the sorting code. For now we'll print the filename of the rgd (minus the initial "attrib\attrib\ebps\") along with the hitpoint value:
function at_end()
unit_list:sort( [ (a,b)
| a.GameData.health_ext.hitpoints
> b.GameData.health_ext.hitpoints
] )
for pos,rgd in ipairs(unit_list)
local unit_name = rgd.path:after "ebps\\"
print("#" .. pos .. ": " .. unit_name .. " ("
.. rgd.GameData.health_ext.hitpoints .. " hp)")
end
end
Full macro, version 1
Here is the complete macro so far:
unit_list = setmetatable({}, {__index = table})
function each_file(rgd)
if rgd:GET("GameData","health_ext","hitpoints") then
unit_list:insert(rgd)
end
end
function at_end()
unit_list:sort( [ (a,b)
| a.GameData.health_ext.hitpoints
> b.GameData.health_ext.hitpoints
] )
for pos,rgd in ipairs(unit_list)
local unit_name = rgd.path:after "ebps\\"
print("#" .. pos .. ": " .. unit_name .. " ("
.. rgd.GameData.health_ext.hitpoints .. " hp)")
end
end
The output should consist of lots of lines like these:
...
#14: races\axis\buildings\hq_3.rgd (1500 hp)
#15: races\allies\buildings\hq_4.rgd (1500 hp)
#16: races\allies\buildings\hq_sp_m06.rgd (1500 hp)
#17: races\allies\buildings\hq_2.rgd (1500 hp)
#18: races\axis\vehicles\tiger_ace.rgd (1500 hp)
#19: races\axis\buildings\hq_sp_noterritory.rgd (1500 hp)
#20: races\allies\buildings\hq_3.rgd (1500 hp)
...
Replacing file name with unit name
Let's change the printing code to get the value of GameData\ui_ext\screen_name, turn it into text if it's a UCS reference, and then print that in addition to the file name. If screen_name is "$0" (eg, the default UCS reference), then we'll treat it as if screen_name didn't exist. We'll then use the UCS() function to turn the UCS reference into normal text:
function at_end()
unit_list:sort( [ (a,b)
| a.GameData.health_ext.hitpoints
> b.GameData.health_ext.hitpoints
] )
for pos,rgd in ipairs(unit_list)
local unit_name = rgd.path:after "ebps\\"
screen_name = rgd.GameData:GET("ui_ext","screen_name")
if screen_name and screen_name != "$0"
screen_name = UCS(screen_name)
unit_name = screen_name.." ("..unit_name..")"
end
print("#" .. pos .. ": " .. unit_name .. " ("
.. rgd.GameData.health_ext.hitpoints .. " hp)")
end
end
Output is now something like this:
...
#14: Reich Headquarters (races\axis\buildings\hq_3.rgd) (1500 hp)
#15: Headquarters (races\allies\buildings\hq_4.rgd) (1500 hp)
#16: Headquarters (races\allies\buildings\hq_sp_m06.rgd) (1500 hp)
#17: Headquarters (races\allies\buildings\hq_2.rgd) (1500 hp)
#18: Tiger Ace (races\axis\vehicles\tiger_ace.rgd) (1500 hp)
...
Filtering out campaign files
Campaign files all have "sp" appear in the filename (eg. "rifleman_sp.rgd"), but not every file with "sp" in the name is from the campaign (eg. "spartaaa.rgd"). Therefore the problem is slightly more complex than looking for "sp" in the name. A better filter is: slash/underscore followed by "sp" followed by slash/underscore/dot. If a file path matches that, we'll say it's from the campaign. Therefore we'll only add a file to our list if it doesn't match that:
unit_list = setmetatable({}, {__index = table})
campaign_file = "[/_\\]sp[/_%.\\]"
function each_file(rgd)
if (not rgd.path:find(campaign_file)) and
rgd:GET("GameData","health_ext","hitpoints") then
unit_list:insert(rgd)
end
end
Output is looking slightly better:
...
#12: Headquarters (races\allies\buildings\hq_3.rgd) (1500 hp)
#13: Tiger Ace (races\axis\vehicles\tiger_ace.rgd) (1500 hp)
#14: Headquarters (races\allies\buildings\hq.rgd) (1500 hp)
#15: Tiger (races\axis\vehicles\tiger.rgd) (1064 hp)
#16: Tiger Ace (races\axis\vehicles\tiger_spg_ace.rgd) (1064 hp)
#17: M26 Pershing (races\allies\vehicles\m26_pershing.rgd) (990 hp)
...
Filtering out duplicates
After looking at the output, you'll see that many units have several variations with the same name and hp value. We can filter these out by keeping a list of unit names and hp values, and before printing a result, checking if it is unique. One caveat is that we can no longer use the 'pos' variable given to us from ipairs as we may choose not to print some entries:
function at_end()
unit_list:sort( [ (a,b)
| a.GameData.health_ext.hitpoints
> b.GameData.health_ext.hitpoints
] )
local pos = 0
for _,rgd in ipairs(unit_list)
local unit_name = rgd.path:after "ebps\\"
screen_name = rgd.GameData:GET("ui_ext","screen_name")
local hp = rgd.GameData.health_ext.hitpoints
local unique = true
if screen_name and screen_name != "$0"
screen_name = UCS(screen_name)
unit_name = screen_name.." ("..unit_name..")"
if unit_list[screen_name] == hp
unique = false
else
unit_list[screen_name] = hp
end
end
if unique
pos = pos + 1
print("#" .. pos .. ": " .. unit_name .. " ("
.. rgd.GameData.health_ext.hitpoints .. " hp)")
end
end
end
Output at this point is looking rather good:
...
#3: Tiger Ace (races\axis\vehicles\tiger_ace.rgd) (1500 hp)
#4: Tiger (races\axis\vehicles\tiger.rgd) (1064 hp)
#5: Tiger Ace (races\axis\vehicles\tiger_spg_ace.rgd) (1064 hp)
#6: M26 Pershing (races\allies\vehicles\m26_pershing.rgd) (990 hp)
...
Giving equal places equal numbers
You may have noticed that the top few results have the same HP value, but different numbers at the start. To finish, let's fix this by remembering the HP value of the previous unit and only incrementing the pos variable if this unit's HP is different:
function at_end()
unit_list:sort( [ (a,b)
| a.GameData.health_ext.hitpoints
> b.GameData.health_ext.hitpoints
] )
local pos = 0
local prev_hp
for _,rgd in ipairs(unit_list)
local unit_name = rgd.path:after "ebps\\"
screen_name = rgd.GameData:GET("ui_ext","screen_name")
local hp = rgd.GameData.health_ext.hitpoints
local unique = true
if screen_name and screen_name != "$0"
screen_name = UCS(screen_name)
unit_name = screen_name.." ("..unit_name..")"
if unit_list[screen_name] == hp
unique = false
else
unit_list[screen_name] = hp
end
end
if unique
if hp ~= prev_hp
pos = pos + 1
end
prev_hp = hp
print("#" .. pos .. ": " .. unit_name .. " ("
.. rgd.GameData.health_ext.hitpoints .. " hp)")
end
end
end
At this point, the report is complete.
...
#35: Mortar Team (races\allies\soldiers\mortar_gunner.rgd) (55 hp)
#35: Engineers (races\allies\soldiers\engineer.rgd) (55 hp)
#35: Repair Engineer (races\allies\soldiers\repair_engineer.rgd) (55 hp)
#36: Mines (races\allies\mines\allies_greyhound_drop_mine.rgd) (20 hp)
Full macro, version 2
Here is the complete macro: (included in the mod studio macro folder as "CoH Unit List by HP.lua"
unit_list = setmetatable({}, {__index = table})
campaign_file = "[/_\\]sp[/_%.\\]"
function each_file(rgd)
if (not rgd.path:find(campaign_file)) and
rgd:GET("GameData","health_ext","hitpoints") then
unit_list:insert(rgd)
end
end
function at_end()
unit_list:sort( [ (a,b)
| a.GameData.health_ext.hitpoints
> b.GameData.health_ext.hitpoints
] )
local pos = 0
local prev_hp
for _,rgd in ipairs(unit_list)
local unit_name = rgd.path:after "ebps\\"
screen_name = rgd.GameData:GET("ui_ext","screen_name")
local hp = rgd.GameData.health_ext.hitpoints
local unique = true
if screen_name and screen_name != "$0"
screen_name = UCS(screen_name)
unit_name = screen_name.." ("..unit_name..")"
if unit_list[screen_name] == hp
unique = false
else
unit_list[screen_name] = hp
end
end
if unique
if hp ~= prev_hp
pos = pos + 1
end
prev_hp = hp
print("#" .. pos .. ": " .. unit_name .. " ("
.. rgd.GameData.health_ext.hitpoints .. " hp)")
end
end
end
Back to tutorial list
This documentation is provided under the GNU General Public License. All trademarks / copyrights are tm/r/c their respective owners.