MUST BE INSTALLED IN YOUR %installdir%\extensions folder! REQUIRES: basic literacy to install.
v0.32 Right Click API, _G Work Around, Modding Templet, and Debug Tools
[ external image ]
- You may NOT: Host these files elsewhere without either my permission or if I have been inactive on these forums for over a month.
- You may NOT: Include the Right Click API or the _G Work Around with your mod until version 1.0 or later of this API
- You may NOT: Under any circumstances move the Right Click API or the _G Work Around mods to another folder when adding with your mod. You must keep them as their own separate mod so people can see which version they have installed.
- You may NOT: Under any circumstances include the debugging tools in a release of your mod.
First the MD script (you can find templet files in the download below)
Code: Select all
<cue name="RegisterShowRanks" version="4" instantiate="true">
<conditions>
<event_game_loaded />
</conditions>
<delay exact="3s"/>
<actions>
<signal_cue_instantly cue="md.G_Work_Around.Signal" param="'.\\extensions\\ShowRanks\\ShowRanks.lua'"/>
<reset_cue cue="Feedback_Wanted"/>
</actions>
</cue>
<cue name="Feedback_Wanted">
<conditions>
<event_cue_completed cue="RegisterShowRanks"/>
</conditions>
<delay exact="1s"/>
<actions>
<debug_text text="'Show Ranks Cue Loaded'" filter="error"/>
<reset_cue cue="RegisterShowRanks"/>
<reset_cue cue="Feedback_Wanted"/>
</actions>
</cue>
You may notice that there is also a short delay before the action. While not necessary for this particular mod, it is a good idea to include a delay if you have dependencies. Such as if you are using the right click menu API included in this download.
The cue Feedback_Wanted is reset by RegisterShowRanks and triggered when RegisterShowRanks is complete. Then Feedback_Wanted prints to the debug log and resets RegisterShowRanks. You could have RegisterShowRanks reset itself, but I left this debug text in to show you how you might ensure that your Lua file is being loaded.
Next we have the lua file itself.
Code: Select all
local orig = {}
local addRanks = {}
local function init()
--DebugError("Rank Display mod init")
for _, menu in ipairs(Menus) do
if menu.name == "MapMenu" then
orig.menu = menu -- save entire menu, for other helper function access
orig.playerInfoTextLeft=Helper.playerInfoTextLeft
orig.playerInfoTextRight=Helper.playerInfoTextRight
Helper.playerInfoTextLeft=addRanks.playerInfoTextLeft
Helper.playerInfoTextRight=addRanks.playerInfoTextRight
break
end
end
end
function addRanks.playerInfoTextLeft()
local playername = ffi.string(C.GetPlayerName())
local playermoney = ConvertMoneyString(GetPlayerMoney(), false, true, nil, true) .. " " .. ReadText(1001, 101)
local gametime = Helper.convertGameTimeToXTimeString(C.GetCurrentGameTime()) .. (C.IsSetaActive() and " \27G(" .. ReadText(1001, 3255) .. ")\27X" or "")
local stats = GetAllStatIDs()
return playername .. "\n" .. GetStatData(stats[98], "displayvalue") .. "\n" .. GetStatData(stats[101], "displayvalue") .. "\n" .. playermoney
end
function addRanks.playerInfoTextRight()
local curtime = getElapsedTime()
local playersector = C.GetContextByClass(C.GetPlayerID(), "sector", false)
-- expensive, only check every 5 seconds
if (not Helper.playerInfoTimer) or (Helper.playerInfoTimer < curtime) then
Helper.playerInfoTimer = curtime + 5
Helper.rawplayermoneydue = tonumber(C.GetCreditsDueFromPlayerTrades())
end
local playermoneydue = ConvertMoneyString(Helper.rawplayermoneydue, false, true, nil, true) .. " " .. ReadText(1001, 101)
local gametime = Helper.convertGameTimeToXTimeString(C.GetCurrentGameTime()) .. (C.IsSetaActive() and " \27G(" .. ReadText(1001, 3255) .. ")\27X" or "")
return "\n" .. ffi.string(C.GetComponentName(playersector)) .. "\n" .. gametime .. "\n" ..((Helper.rawplayermoneydue > 0) and ("(" .. string.format(ReadText(1001, 7704), playermoneydue) .. ")") or "")
end
init()
Code: Select all
for _, menu in ipairs(Menus) do
if menu.name == "MapMenu" then
Code: Select all
orig.playerInfoTextLeft=Helper.playerInfoTextLeft
orig.playerInfoTextRight=Helper.playerInfoTextRight
Code: Select all
Helper.playerInfoTextLeft=addRanks.playerInfoTextLeft
Helper.playerInfoTextRight=addRanks.playerInfoTextRight
Now we write our functions we replaced. As I said they are at the bottom. Ideally, we would include a call to the original function, i.e. orig.playerInfoTextLeft(), inside of our new function. However, in this case, that isn't possible. But you should endeavor to include such a call whenever feasible. This ensures that other mods can change other elements of that particular menu or function without causing compatibility issues. Modding it with this method ensures that it will continue to be compatible with future updates. When the _G issue is fixed, all you will have to do is make a ui.xml file and move the Lua file to a subfolder in your mod. Now you can do something about the horrible UI... please?
As adding commands/actions to the right-click menu ("InteractMenu") is more involved, I've included an API for adding your own right-click commands while playing well with others. This API uses the above work around to load, so it needs to be installed in the %installdir%\extensions folder. I'll be using my Collect Deployables mod as a brief example of how to use the API. If you want a more in-depth discussion you can look here: viewtopic.php?f=181&t=409723
Code in 2nd post
To add a new command (or menu or whatever) to the right-click menu we need 3 things. 1 a check, usually involving an order. This takes the form of
Code: Select all
if capi.possibleorders["CollectDeployables"]
Code: Select all
<order id="CollectDeployables" name="{1042, 400}" description="{1041, 401}"
Code: Select all
capi.possibleorders["CollectDeployables"] = false
Code: Select all
capi.RegisterGuidanceAction(CollectDeployablesAction)
In this case the check is a bit long:
Code: Select all
if capi.possibleorders["CollectDeployables"]
and #menu.selectedplayerships > 0
and menu.componentSlot.component
and isplayerownedtarget and (
(
C.IsComponentClass(menu.componentSlot.component, "satellite")
or C.IsComponentClass(menu.componentSlot.component, "resourceprobe")
or C.IsComponentClass(menu.componentSlot.component, "navbeacon")
)
or GetComponentData(ConvertStringTo64Bit(tostring(menu.componentSlot.component)), "shiptype") == "lasertower") then
Code: Select all
menu.insertInteractionContent("selected_orders", { type = actiontype, text = ReadText(1042, 400), script = function () return menu.buttonCollectDeployables(false) end })
Finally, the action is performed by menu.orderCollectDeployables. We create the order with:
Code: Select all
local orderidx = C.CreateOrder(component, "CollectDeployables", false)
Code: Select all
--Param 1: the deployable, macro is derived from this.
SetOrderParam(component, orderidx, 1, nil, ConvertStringToLuaID(tostring(target))
VERY IMPORTANT: THIS DOES NOT CHECK input_params!!!
Look at order.collect.deployables, the first parameter has the input params of:
Code: Select all
<param name="targetDeployable" type="object" text="{1041, 10027}" comment="The deployable to collect, macro and sector is taken from this object">
<input_param name="class" value="[class.navbeacon, class.resourceprobe, class.satellite]"/>
<input_param name="owner" value="faction.player"/>
</param>
the class must be either navbeacon, resourceprobe, satellite. But, if you recall from above, we are also passing lastertowers to the script. Lasertowers are class ship. But the lua file ignores this and passes them anyway. Therefore it is VERY important to make sure the check section of your Lua file is rigorous to prevent passing invalid data to your script and causing horrible errors.
You should add a dependency to your mod, in the content.xml, when you use the APIs shown below.
Code: Select all
<content id=......>
<dependency id="G_Work_Around" version="031" optional="false"/>
<text language=..../>
</content>