How to output text?

How can I output some text onto the screen or into the log file for testing purposes?
Like if i have some variables I want to output in an addCustomCode() lua.

Simplest way to output text on screen: Subtitle_Add

1 Like

print() will send stuff to the HWRM.log file(I think you need -luatrace in your shortcut too, though)

1 Like

That site keeps going down. :confused: What are the arguments for Subtitle_Add()?

And ah I figured print(), but I was missing that command line arg.

Subtitle sounds like a good way to do it, though.

Subtitle_Add(iActor, sText, fTime)
iActor: 0 to 10 perhaps more (index of SP voices such as Karan, Makaan, Fleet Intelligence…)
sText: your text string
fTime: number of seconds the text is printed on screen

There are other ways to display text, but they require preformating a box and the text options.

Odd. I’m getting “parameter: attempt to call global `Subtitle_Add’ (a nil value)” from

Subtitle_Add(1, " *** damage threshold for "..shipID.." old:"..lastHealth.." new:"..newHealth, 2)

Further, I must be doing something wrong with SobGroup_HealthPercentage() as it always is 0 even when HP isn’t 0.

lastHealth = 1

function Load_Tai_Grav_Shutter(playerIndex)

function Create_Tai_Grav_Shutter(CustomGroup, playerIndex, shipID) 

function Update_Tai_Grav_Shutter(CustomGroup, playerIndex, shipID)
    newHealth = SobGroup_HealthPercentage("grav_to_shutter"..shipID)

    print(" *** damage threshold for "..shipID.." old:"..lastHealth.." new:"..newHealth)
    Subtitle_Add(1, " *** damage threshold for "..shipID.." old:"..lastHealth.." new:"..newHealth, 2)

    lastHealth = newHealth

It’s outputting “*** damage threshold for 320 old:1 new:0” no matter the health to the log.

Would seem to imply that either the function is bugged now, or uh… I’m doing something wrong with creating the Sob_Group so it can’t check it.

It doesn’t look like you have added any ships to the sobgroup.

Also, your first function does not have shipID defined.

Ah indeed. I shouldn’t need that first function either, really.

But I don’t imagine that explains the error for Subtitle_Add().

I’m assuming if the sobgroup is empty then lastHealth will always be 0.

Right, I get that.
But uh, shouldn’t adding it to a group just be?:

function Create_Tai_Grav_Shutter(CustomGroup, playerIndex, shipID) 
    SobGroup_SobGroupAdd("grav_to_shutter"..shipID, CustomGroup)

Though for a single unit, I guess I don’t need a new SobGroup. I can just check health on CustomGroup

But anyway, bonus question: What’s the last argument for addCustomCode()? I can’t find that anywhere.
I was thinking it’s the time in seconds that “update” runs, but that doesn’t seem to be it. I’m not sure what triggers the “update” function. Maybe each time a command is issued? That can’t really be it either…

And oh god. How can I set a variable like for a sob group or something?
If I set it in the function, it’s going to be newly set each time that function is run.
If I set it outside of it, then it’ll be global for the whole game it seems. lastHealth wasn’t getting set to newHealth and was always 1.

I’m also having trouble on how I could create a loop that is destroyed when a ship is.
Like I can do

while true do
    --do something

But then how do I stop doing that when the ship is destroyed?..

Not prepared to comment on the rest, but don’t use true. Lua 4 does not have true and false keywords, it treats them as variable names.

Many questions together :smiley:
A loop that stops when a ship is destroyed, assuming you put it in a SobGroup named “grav_to_shutter”…shipID

while SobGroup_Empty(“grav_to_shutter”…shipID)==0 do
–do something


while true do
if SobGroup_Empty(“grav_to_shutter”…shipID)==1 then return
–do something

Well wouldn’t that make a lot of extra overhead for the “while” checks?

Like it would create a while loop each time a ship is made.

Once it’s destroyed, it’d STILL be checking it, just that it’d be returning false each time.

That’s a really horrible way to program things. But I guess if that’s the only way… And I appreciate the solution nontheless.

I would think there would be some way to get the actual ship object, like where you could set shipObject.maxHealth = n,
or AddShipMultiplier(shipObject,“WeaponAccuracy”,“EnemyShipsWithinRadius”,“Linear”,0.85,0.85,7000);,
or StartShipWeaponConfig(shipObject,“HW1_MothershipGun”,“Weapon_HullDefense2”,"");
and so on. Is that not possible?
And in having that object instance for the ship, I’d think I’d then be able to do something like set shipObject.myLoop = function…

It also doesn’t look like I can modify globals from inside a shallower scope. I’m new with Lua.
Can I make like a list or table that’s global, and set these “lastHealth” by shipID or somethig that way?

There is no way to get a ship object, you can handle only sobgroups.

If I understand correctly you create sobgroups using shipID as incremental index and you want to periodically check what happens to their health. So you can create an array at the beginning of your script:

Health = {}

Each time you create a new sobgroup:

Health[shipID] = 1

Then in your main loop:

for i=0, shipID do
if SobGroup_Empty((“grav_to_shutter”…i)==0 then
Update_Tai_Grav_Shutter(“grav_to_shutter”…i, Health[i], i)

And the function that updates and prints:

function Update_Tai_Grav_Shutter(Ship, lastHealth, j)
local newHealth = SobGroup_HealthPercentage(Ship)
print(" *** damage threshold for “…Ship…” old:"…lastHealth…" new:"…newHealth)
Subtitle_Add(1, " *** damage threshold for “…Ship…” old:"…lastHealth…" new:"…newHealth, 2)
Health[j]= newHealth

So you can update a list/array item of a global, but you can’t update the global itself? Got it. Thanks.

It is a shame there is no API to like add a variable to a SobGroup…

… Yet. :wink: If you guys can explain how something would be helpful or make the system faster, we can talk about what it would take to add that sort of functionality, yeah?

1 Like

It’s not even a matter of speed, there are just things that are plain impossible with the current API. Things have certainly made a bit better with the addAbility and addCustomCode functions. There are certainly more helper functions that could be added and exposed to do more things that modders would want but the game doesn’t nessisarily use. But there are really just some fundamental flaws on how modding HW works that severely limit what could ever possibly be done even with infinite time and determination.

You can’t directly edit ships as it stands. What you can do is edit them through SobGroups functions which are extremely limited. (At the very least, near term, it’d be nice to at least be able to READ variables from the ship object)

I understand there may be some things with how the engine works where some things can only be set on initialization. Like, what happens when you try to change a units max HP when it’s currently under attack? I mean the design answere is you adjust its current HP to be the same percentage wise, and tell the network this unit has a new max HP, but that’s surely not there now. Though, that’d also be a huge shame if true.
The way I generally write code is that I have my setters for variables, and I have that code for each setter that will both initialize or update something fine. Then the only difference between initialization options and setters that update after initialization is, well, nothing. The initialization options are simply iterated through and applied.

To me, I should be able to directly get the ship object with something like thisShip = getShipById(<ShipID>) which is exactly the same as what is returned by StartShipConfig(), and that should get the instance of that ship (so it isn’t changing all of the type. Though also getting the ShipConfig object after a game has started and changing it so all of that type are changed would also be nice)
Then I should be able to, say,

UpdateShipHardPointConfig(thisShip,"Weapon IonBeam 1","Hardpoint_IonBeam1","Weapon","Innate","Damageable","Hgn_BattleCruiserIonBeamTurret","","","","","","","","");

to add a BC ion onto that ships hardpoint.

It’d allow so much if you could modify ship objects directly instead of just through a few helper functions in SobGroup.

Like there’s research for MAXHEALTH and MAXSPEED. What if you want a research that increases damage or fire rate? Can’t do it. But if we had direct access to the ship objects, we could check if something is researched and damage accordingly.

Another thing that’s lacking is, as far as I know, there’s no Lua that is executed for every ship. So, if you want to change something on one ship, you have add an Lua file for every single ship that there is.

I would like to do something like this, in some Lua definition that gets applied to every ship before its ship specific Lua:

if (thisShip.DisplayFamily == "Fighter" || thisShip.DisplayFamily == "Corvette") && SobGroup_GetTactics(thisShip) == 0 then --or whatever equivalent function for supplying a ship object.  No reason why there shouldn't just be a GetTactics function that does a different lookup based on whether a SobGroup or ShipInstance is supplied.
   updateAbility(thisShip,"GuardCommand",1,2000,250); --guarding ships are tightly packed, and will break off to pursue

if t(thisShip.DisplayFamily == "Fighter" || thisShip.DisplayFamily == "Corvette") && SobGroup_GetTactics(thisShip) == 1 then
   updateAbility(thisShip,"GuardCommand",1,0,750); --guarding ships are spread out further from their target, but will not move from that position

So for every ship I could check if it’s a fighter. If it’s in one stance, I want to make its guard behavior way. If it’s another, I want to do another thing.
Pardon if my Lua is off. I’m used to C languages.

Note at the start I’m directly reading a ship’s variable. This way, instead of doing a copy of this for EVERY ship, I’m executing this code on every ship and checking if it’s a fighter or corvette. If not, exits out of the stanza.
Then I’m seeing if it’s aggressive for the first stanza, or defensive on the second.
For each I’m wanting to update how the GuardCommand is defined based on the that.

And IDEALLY I’d really be able to have this code running on command given, seeing that the guard command was given, have a target supplied, an array of ships the order was given to to loop through and apply this code to.

Like I’ve ALMOST gotten HW1 style formations working EXCEPT I can’t properly change them based on tactics, and that I can’t keep telling them to update. Not only that, but there are fundamental differences in HW1 having the superior “Aggressive, neutral, Defensive” while HW2 has this useless “passive” thing. Why would anyone else want to have a ship sit there and die? No, I want it to stay in its spot, evade a little, but still return fire.

What I’m missing is that I can’t adjust the NewShipType.formationSpacing=12, as it’s set on defintion. I can’t check what formation a ship is in. I can’t set a ships formation.
With how I have it set, they actually behave very very very close to HW1 on all formations except sphere, if they were set to aggressive, if you click the formation button like once every second.
So if I could tell ships to reform into their current formation every second, I’d have something that looks almost the same as HW1 formations. But I can’t. There is no way to check a ships current formation, nor a way to tell them to go back into formation So overtime they break out of formation too much.
And in addition to that, I can’t set the different behaviors right based on their stance(/tactic).

In general, there seems to be a lack of way to make some general event driven Lua.
I should have Lua for every event.
Like every time a ship is created, I should have a Lua that runs on that.
Every time a button is clicked, I should have Lua where I can see what type of button it has an all its properties to do stuff.
Every time a command is given, there should be a way to listen for it and see what the command was, a list/array of what objects it effects, etc.
Instead what we have is that Lua are usually lists, like JSON, that are read by hard coded game code.
Instead you have specific Lua files where the game expects certain functions by certain names that you can modify a bit of.

As I am ‘off’ today I’ll give a really quick answer:

This is a very basic result of LUA being used as an interface not the actual game data/state engine.

The results of this (that 99% of the ‘game’ is C/C++, not LUA) - is that when you think, in LUA ‘I should be able to get X’ - X being anything (Ship, Button, Properties, State, etc) - we’d have to pack all that up into a LUA context, wait for your edits, then put it all back (troublesome for many reason) - and SLOW.

So unfortunately, most of what you’ve asked for can’t happen - or is so expensive and dangerous that we wouldn’t add support for it. Some games actually bind LUA to their objects, actually ‘run’ LUA - the data and state is inside a LUA context. In this engine LUA is just a really, really shallow binding. Though some things do exist in the game-sim LUA context - it is MUCH less than you might think.

So you really don’t have any choice (nor, I think, do we as the devs) but to add APIs for specific actions (C being faster than LUA for interacting with the mostly C stuff), as well as for specific queries. If you keep that in mind when you make a request (and show code that does the request in ‘slow’ mode, as well as what it would do if we added or changed something) - it’ll be much easier to talk about the ideas, and quite likely implement them for you.


I know something can be written it in C/C++, with much of it hooked through Google V8 to expose virtually everything run every frame/tick/sim, and be extremely fast.
The concept is the same with Lua, though I have no experience doing that.

The other way is to effectively compile the Lua as C/C++. Some code written in Lua can be parsed and run just like the rest of game code. This isn’t too difficult when there’s only a few basics that plenty of parsers already do to cover, a long with a few exposed functions.

I don’t really see how it’s a problem, but oh well. This is why I hate modding.

I can’t show “How it can be written now, which would be nice to be simpler” because it’s more just fundamental problems of things being impossible with how limited modding HW2/HWRM is. I can’t do those things I said I want to do, like changing behavior based on what stance a ship is in.

And even though I can write scripts that will add some code to the Lua for every ship, it’d still be really nice to have a “catchall” Lua that is applied to every ship. :confused: