I have a feature request for the Rightclick API.
Or more correctly, "I have some code changes (that I've already made and tested on my end) that may be beneficial, and was wondering if you'd incorporate them."
We can make custom sections and put new orders under them, but they don't get mouseover tooltips, target names on the right side, etc. that orders under certain regular sections get (that we might want in ours as well).
What I did was replace the simple comparison checks with functions that do the same check plus an additional check against a list of registered custom section IDs.
The following is the entire modified right_click_api.lua file, patched for 2.20 beta2 (mostly just "Attackinrange" order addition and some changes to a few parameters when making buttons and such) along with the changes mentioned above.
(The additional lists and API functions start at line 864. You might want to move it near the other declarations if you decide to incorporate this.)
Code: Select all
-- ffi setup
local ffi = require("ffi")
local C = ffi.C
ffi.cdef[[
typedef uint64_t BuildTaskID;
typedef uint64_t UniverseID;
typedef struct {
const char* macro;
const char* ware;
uint32_t amount;
uint32_t capacity;
} AmmoData;
typedef struct {
int x;
int y;
} Coord2D;
typedef struct {
float x;
float y;
float z;
} Coord3D;
typedef struct {
size_t queueidx;
const char* state;
const char* statename;
const char* orderdef;
size_t actualparams;
bool enabled;
bool isinfinite;
bool issyncpointreached;
bool istemporder;
} Order;
typedef struct {
const char* id;
const char* name;
const char* desc;
uint32_t amount;
uint32_t numtiers;
bool canhire;
} PeopleInfo;
typedef struct {
uint32_t id;
const char* text;
const char* type;
bool ispossible;
bool istobedisplayed;
} UIAction;
typedef struct {
UniverseID component;
const char* connection;
} UIComponentSlot;
typedef struct {
const char* shape;
const char* name;
uint32_t requiredSkill;
float radius;
bool rollMembers;
bool rollFormation;
size_t maxShipsPerLine;
} UIFormationInfo;
typedef struct {
const float x;
const float y;
const float z;
const float yaw;
const float pitch;
const float roll;
} UIPosRot;
typedef struct {
const char* wareid;
int32_t amount;
} YieldInfo;
bool CanAcceptSubordinate(UniverseID commanderid, UniverseID potentialsubordinateid);
bool CancelConstruction(UniverseID containerid, BuildTaskID id);
bool CanCancelConstruction(UniverseID containerid, BuildTaskID id);
const char* CanTeleportPlayerTo(UniverseID controllableid, bool allowcontrolling, bool force);
uint32_t GetAllLaserTowers(AmmoData* result, uint32_t resultlen, UniverseID defensibleid);
uint32_t GetAllMines(AmmoData* result, uint32_t resultlen, UniverseID defensibleid);
uint32_t GetAllNavBeacons(AmmoData* result, uint32_t resultlen, UniverseID defensibleid);
uint32_t GetAllResourceProbes(AmmoData* result, uint32_t resultlen, UniverseID defensibleid);
uint32_t GetAllSatellites(AmmoData* result, uint32_t resultlen, UniverseID defensibleid);
uint32_t GetCompSlotPlayerActions(UIAction* result, uint32_t resultlen, UIComponentSlot compslot);
Coord2D GetCompSlotScreenPos(UIComponentSlot compslot);
UniverseID GetContextByClass(UniverseID componentid, const char* classname, bool includeself);
uint32_t GetFormationShapes(UIFormationInfo* result, uint32_t resultlen);
uint32_t GetMineablesAtSectorPos(YieldInfo* result, uint32_t resultlen, UniverseID sectorid, Coord3D position);
uint32_t GetMissionThreadSubMissions(MissionID* result, uint32_t resultlen, MissionID missionid);
uint32_t GetNumAllLaserTowers(UniverseID defensibleid);
uint32_t GetNumAllMines(UniverseID defensibleid);
uint32_t GetNumAllRoles(void);
uint32_t GetNumAllNavBeacons(UniverseID defensibleid);
uint32_t GetNumAllResourceProbes(UniverseID defensibleid);
uint32_t GetNumAllSatellites(UniverseID defensibleid);
uint32_t GetNumCompSlotPlayerActions(UIComponentSlot compslot);
uint32_t GetNumFormationShapes(void);
uint32_t GetNumMineablesAtSectorPos(UniverseID sectorid, Coord3D position);
uint32_t GetNumMissionThreadSubMissions(MissionID missionid);
uint32_t GetNumVenturePlatformDocks(UniverseID ventureplatformid);
uint32_t GetNumVenturePlatforms(UniverseID defensibleid);
uint32_t GetNumWares(const char* tags, bool research, const char* licenceownerid, const char* exclusiontags);
UniverseID GetPlayerContainerID(void);
UniverseID GetPlayerID(void);
UniverseID GetPlayerOccupiedShipID(void);
uint32_t GetPeople(PeopleInfo* result, uint32_t resultlen, UniverseID controllableid);
float GetTextWidth(const char*const text, const char*const fontname, const float fontsize);
uint32_t GetVenturePlatformDocks(UniverseID* result, uint32_t resultlen, UniverseID ventureplatformid);
uint32_t GetVenturePlatforms(UniverseID* result, uint32_t resultlen, UniverseID defensibleid);
uint32_t GetWares(const char** result, uint32_t resultlen, const char* tags, bool research, const char* licenceownerid, const char* exclusiontags);
bool HasVenturerDock(UniverseID containerid, UniverseID shipid, UniverseID ventureplatformid);
bool IsBuilderBusy(UniverseID shipid);
bool IsDefensibleBeingBoardedBy(UniverseID defensibleid, const char* factionid);
bool IsMouseEmulationActive(void);
bool IsObjectKnown(const UniverseID componentid);
bool IsPlayerCameraTargetViewPossible(UniverseID targetid, bool force);
void LaunchLaserTower(UniverseID defensibleid, const char* lasertowermacroname);
void LaunchMine(UniverseID defensibleid, const char* minemacroname);
void LaunchNavBeacon(UniverseID defensibleid, const char* navbeaconmacroname);
void LaunchResourceProbe(UniverseID defensibleid, const char* resourceprobemacroname);
void LaunchSatellite(UniverseID defensibleid, const char* satellitemacroname);
void MakePlayerOwnerOf(UniverseID objectid);
void MovePlayerToSectorPos(UniverseID sectorid, UIPosRot position);
void NotifyInteractMenuHidden(const uint32_t id, const bool allclosed);
void NotifyInteractMenuShown(const uint32_t id);
bool PerformCompSlotPlayerAction(UIComponentSlot compslot, uint32_t actionid);
bool RemoveOrder(UniverseID controllableid, size_t idx, bool playercancelled, bool checkonly);
bool RequestDockAt(UniverseID containerid, bool checkonly);
UIFormationInfo SetFormationShape(UniverseID objectid, const char* formationshape);
void SetGuidance(UniverseID componentid, UIPosRot offset);
bool TeleportPlayerTo(UniverseID controllableid, bool allowcontrolling, bool instant, bool force);
]]
local orig = {}
capi = {}
local accountmanagementActions = {}
local assignActions = {}
local attackActions = {}
local attackinrangeActions = {}
local attackmultipleActions = {}
local attackplayertargetActions = {}
local boardActions = {}
local buildActions = {}
local buildshipsActions = {}
local changeformationActions = {}
local configurestationActions = {}
local collectActions = {}
local collectspaceActions = {}
local deployhereActions = {}
local deployatActions = {}
local dockatActions = {}
local dockatplayerActions = {}
local dockrequestActions = {}
local exploreActions = {}
local exploreupdateActions = {}
local flytoActions = {}
local followActions = {}
local guidanceActions = {}
local hireActions = {}
local logicalstationoverviewActions = {}
local manageassignmentsActions = {}
local miningActions = {}
local orderoverviewActions = {}
local paintmodActions = {}
local player_docktotradeActions = {}
local proceedwithordersActions = {}
local protectstationActions = {}
local recallsubsActions = {}
local removeallordersActions = {}
local sellshipsActions = {}
local stopandholdfireActions = {}
local targetviewActions = {}
local teleportActions = {}
local upgradeActions = {}
local upgradeshipsActions = {}
local venturedockatActions = {}
local wareexchangeActions = {}
local withdrawandholdActions = {}
local withdrawfromcombatActions = {}
local cheat_satelliteActions = {}
local cheat_navbeaconActions = {}
local cheat_resourceprobeActions = {}
local cheat_takeownershipActions = {}
local cheat_warpActions = {}
function capi.InsertLuaAction(actiontype, istobedisplayed)
-- process your own action
if actiontype == "accountmanagement" then
capi.OnAccountmanagement()
elseif actiontype == "assign" then
capi.OnAssign()
elseif actiontype == "attack" then
capi.OnAttack()
elseif actiontype == "attackinrange" then
capi.OnAttackinrange()
elseif actiontype == "attackmultiple" then
capi.OnAttackmultiple()
elseif actiontype == "attackplayertarget" then
capi.OnAttackplayertarget()
elseif actiontype == "board" then
capi.OnBoard()
elseif actiontype == "build" then
capi.OnBuild()
elseif actiontype == "buildships" then
capi.OnBuildships()
elseif actiontype == "changeformation" then
capi.OnChangeformation()
elseif actiontype == "configurestation" then
capi.OnConfigurestation()
elseif actiontype == "collect" then
capi.OnCollect()
elseif actiontype == "collectspace" then
capi.OnCollectspace()
elseif actiontype == "deployhere" then
capi.OnDeployhere()
elseif actiontype == "deployat" then
capi.OnDeployat()
elseif actiontype == "dockat" then
capi.OnDockat()
elseif actiontype == "dockatplayer" then
capi.OnDockatplayer()
elseif actiontype == "dockrequest" then
capi.OnDockrequest()
elseif actiontype == "explore" then
capi.OnExplore()
elseif actiontype == "exploreupdate" then
capi.OnExploreupdate()
elseif actiontype == "flyto" then
capi.OnFlyto()
elseif actiontype == "follow" then
capi.OnFollow()
elseif actiontype == "guidance" then
capi.OnGuidance()
elseif actiontype == "hire" then
capi.OnHire()
elseif actiontype == "logicalstationoverview" then
capi.OnLogicalstationoverview()
elseif actiontype == "manageassignments" then
capi.OnManageassignments()
elseif actiontype == "mining" then
capi.OnMining()
elseif actiontype == "orderoverview" then
capi.OnOrderoverview()
elseif actiontype == "paintmod" then
capi.OnPaintmod()
elseif actiontype == "player_docktotrade" then
capi.OnPlayer_docktotrade()
elseif actiontype == "proceedwithorders" then
capi.OnProceedwithorders()
elseif actiontype == "protectstation" then
capi.OnProtectstation()
elseif actiontype == "recallsubs" then
capi.OnRecallsubs()
elseif actiontype == "removeallorders" then
capi.OnRemoveallorders()
elseif actiontype == "sellships" then
capi.OnSellships()
elseif actiontype == "stopandholdfire" then
capi.OnStopandholdfire()
elseif actiontype == "targetview" then
capi.OnTargetview()
elseif actiontype == "teleport" then
capi.OnTeleport()
elseif actiontype == "upgrade" then
capi.OnUpgrade()
elseif actiontype == "upgradeships" then
capi.OnUpgradeships()
elseif actiontype == "venturedockat" then
capi.OnVenturedockat()
elseif actiontype == "wareexchange" then
capi.OnWareexchange()
elseif actiontype == "withdrawandhold" then
capi.OnWithdrawandhold()
elseif actiontype == "withdrawfromcombat" then
capi.OnWithdrawfromcombat()
elseif actiontype == "cheat_satellite" then--I don't know if modders can get access to these, so Im adding them anyway.
capi.OnCheat_satellite()
elseif actiontype == "cheat_navbeacon" then
capi.OnCheat_navbeacon()
elseif actiontype == "cheat_resourceprobe" then
capi.OnCheat_resourceprobe()
elseif actiontype == "cheat_takeownership" then
capi.OnCheat_takeownership()
elseif actiontype == "cheat_warp" then
capi.OnCheat_warp()
end
--then call original function first
orig.insertLuaAction(actiontype, istobedisplayed)
end
function capi.RegisterAccountmanagementAction(actionFunction)
table.insert(accountmanagementActions, actionFunction)
end
function capi.OnAccountmanagement()
for _, func in ipairs(accountmanagementActions) do
func(orig.menu)
end
end
function capi.RegisterAssignAction(actionFunction)
table.insert(assignActions, actionFunction)
end
function capi.OnAssign()
for _, func in ipairs(assignActions) do
func(orig.menu)
end
end
function capi.RegisterAttackAction(actionFunction)
table.insert(attackActions, actionFunction)
end
function capi.OnAttack()
for _, func in ipairs(attackActions) do
func(orig.menu)
end
end
function capi.RegisterAttackinrangeAction(actionFunction)
table.insert(attackinrangeActions, actionFunction)
end
function capi.OnAttackinrange()
for _, func in ipairs(attackinrangeActions) do
func(orig.menu)
end
end
function capi.RegisterAttackmultipleAction(actionFunction)
table.insert(attackmultipleActions, actionFunction)
end
function capi.OnAttackmultiple()
for _, func in ipairs(attackmultipleActions) do
func(orig.menu)
end
end
function capi.RegisterAttackplayertargetAction(actionFunction)
table.insert(attackplayertargetActions, actionFunction)
end
function capi.OnAttackplayertarget()
for _, func in ipairs(attackplayertargetActions) do
func(orig.menu)
end
end
function capi.RegisterBoardAction(actionFunction)
table.insert(boardActions, actionFunction)
end
function capi.OnBoard()
for _, func in ipairs(boardActions) do
func(orig.menu)
end
end
function capi.RegisterBuildAction(actionFunction)
table.insert(buildActions, actionFunction)
end
function capi.OnBuild()
for _, func in ipairs(buildActions) do
func(orig.menu)
end
end
function capi.RegisterBuildshipsAction(actionFunction)
table.insert(buildshipsActions, actionFunction)
end
function capi.OnBuildships()
for _, func in ipairs(buildshipsActions) do
func(orig.menu)
end
end
function capi.RegisterChangeformationAction(actionFunction)
table.insert(changeformationActions, actionFunction)
end
function capi.OnChangeformation()
for _, func in ipairs(changeformationActions) do
func(orig.menu)
end
end
function capi.RegisterConfigurestationAction(actionFunction)
table.insert(configurestationActions, actionFunction)
end
function capi.OnConfigurestation()
for _, func in ipairs(configurestationActions) do
func(orig.menu)
end
end
function capi.RegisterCollectAction(actionFunction)
table.insert(collectActions, actionFunction)
end
function capi.OnCollect()
for _, func in ipairs(collectActions) do
func(orig.menu)
end
end
function capi.RegisterCollectspaceAction(actionFunction)
table.insert(collectspaceActions, actionFunction)
end
function capi.OnCollectspace()
for _, func in ipairs(collectspaceActions) do
func(orig.menu)
end
end
function capi.RegisterDeployhereAction(actionFunction)
table.insert(deployhereActions, actionFunction)
end
function capi.OnDeployhere()
for _, func in ipairs(deployhereActions) do
func(orig.menu)
end
end
function capi.RegisterDeployatAction(actionFunction)
table.insert(deployatActions, actionFunction)
end
function capi.OnDeployat()
for _, func in ipairs(deployatActions) do
func(orig.menu)
end
end
function capi.RegisterDockatAction(actionFunction)
table.insert(dockatActions, actionFunction)
end
function capi.OnDockat()
for _, func in ipairs(dockatActions) do
func(orig.menu)
end
end
function capi.RegisterDockatplayerAction(actionFunction)
table.insert(dockatplayerActions, actionFunction)
end
function capi.OnDockatplayer()
for _, func in ipairs(dockatplayerActions) do
func(orig.menu)
end
end
function capi.RegisterDockrequestAction(actionFunction)
table.insert(dockrequestActions, actionFunction)
end
function capi.OnDockrequest()
for _, func in ipairs(dockrequestActions) do
func(orig.menu)
end
end
function capi.RegisterExploreAction(actionFunction)
table.insert(exploreActions, actionFunction)
end
function capi.OnExplore()
for _, func in ipairs(exploreActions) do
func(orig.menu)
end
end
function capi.RegisterExploreupdateAction(actionFunction)
table.insert(exploreupdateActions, actionFunction)
end
function capi.OnExploreupdate()
for _, func in ipairs(exploreupdateActions) do
func(orig.menu)
end
end
function capi.RegisterFlytoAction(actionFunction)
table.insert(flytoActions, actionFunction)
end
function capi.OnFlyto()
for _, func in ipairs(flytoActions) do
func(orig.menu)
end
end
function capi.RegisterFollowAction(actionFunction)
table.insert(followActions, actionFunction)
end
function capi.OnFollow()
for _, func in ipairs(followActions) do
func(orig.menu)
end
end
function capi.RegisterGuidanceAction(actionFunction)
table.insert(guidanceActions, actionFunction)
end
function capi.OnGuidance()
for _, func in ipairs(guidanceActions) do
func(orig.menu)
end
end
function capi.RegisterHireAction(actionFunction)
table.insert(hireActions, actionFunction)
end
function capi.OnHire()
for _, func in ipairs(hireActions) do
func(orig.menu)
end
end
function capi.RegisterLogicalstationoverviewAction(actionFunction)
table.insert(logicalstationoverviewActions, actionFunction)
end
function capi.OnLogicalstationoverview()
for _, func in ipairs(logicalstationoverviewActions) do
func(orig.menu)
end
end
function capi.RegisterManageassignmentsAction(actionFunction)
table.insert(manageassignmentsActions, actionFunction)
end
function capi.OnManageassignments()
for _, func in ipairs(manageassignmentsActions) do
func(orig.menu)
end
end
function capi.RegisterMiningAction(actionFunction)
table.insert(miningActions, actionFunction)
end
function capi.OnMining()
for _, func in ipairs(miningActions) do
func(orig.menu)
end
end
function capi.RegisterOrderoverviewAction(actionFunction)
table.insert(orderoverviewActions, actionFunction)
end
function capi.OnOrderoverview()
for _, func in ipairs(orderoverviewActions) do
func(orig.menu)
end
end
function capi.RegisterPaintmodAction(actionFunction)
table.insert(paintmodActions, actionFunction)
end
function capi.OnPaintmod()
for _, func in ipairs(paintmodActions) do
func(orig.menu)
end
end
function capi.RegisterPlayer_docktotradeAction(actionFunction)
table.insert(player_docktotradeActions, actionFunction)
end
function capi.OnPlayer_docktotrade()
for _, func in ipairs(player_docktotradeActions) do
func(orig.menu)
end
end
function capi.RegisterProceedwithordersAction(actionFunction)
table.insert(proceedwithordersActions, actionFunction)
end
function capi.OnProceedwithorders()
for _, func in ipairs(proceedwithordersActions) do
func(orig.menu)
end
end
function capi.RegisterProtectstationAction(actionFunction)
table.insert(protectstationActions, actionFunction)
end
function capi.OnProtectstation()
for _, func in ipairs(protectstationActions) do
func(orig.menu)
end
end
function capi.RegisterRecallsubsAction(actionFunction)
table.insert(recallsubsActions, actionFunction)
end
function capi.OnRecallsubs()
for _, func in ipairs(recallsubsActions) do
func(orig.menu)
end
end
function capi.RegisterRemoveallordersAction(actionFunction)
table.insert(removeallordersActions, actionFunction)
end
function capi.OnRemoveallorders()
for _, func in ipairs(removeallordersActions) do
func(orig.menu)
end
end
function capi.RegisterSellshipsAction(actionFunction)
table.insert(sellshipsActions, actionFunction)
end
function capi.OnSellships()
for _, func in ipairs(sellshipsActions) do
func(orig.menu)
end
end
function capi.RegisterStopandholdfireAction(actionFunction)
table.insert(stopandholdfireActions, actionFunction)
end
function capi.OnStopandholdfire()
for _, func in ipairs(stopandholdfireActions) do
func(orig.menu)
end
end
function capi.RegisterTargetviewAction(actionFunction)
table.insert(targetviewActions, actionFunction)
end
function capi.OnTargetview()
for _, func in ipairs(targetviewActions) do
func(orig.menu)
end
end
function capi.RegisterTeleportAction(actionFunction)
table.insert(teleportActions, actionFunction)
end
function capi.OnTeleport()
for _, func in ipairs(teleportActions) do
func(orig.menu)
end
end
function capi.RegisterUpgradeAction(actionFunction)
table.insert(upgradeActions, actionFunction)
end
function capi.OnUpgrade()
for _, func in ipairs(upgradeActions) do
func(orig.menu)
end
end
function capi.RegisterUpgradeshipsAction(actionFunction)
table.insert(upgradeshipsActions, actionFunction)
end
function capi.OnUpgradeships()
for _, func in ipairs(upgradeshipsActions) do
func(orig.menu)
end
end
function capi.RegisterVenturedockatAction(actionFunction)
table.insert(venturedockatActions, actionFunction)
end
function capi.OnVenturedockat()
for _, func in ipairs(venturedockatActions) do
func(orig.menu)
end
end
function capi.RegisterWareexchangeAction(actionFunction)
table.insert(wareexchangeActions, actionFunction)
end
function capi.OnWareexchange()
for _, func in ipairs(wareexchangeActions) do
func(orig.menu)
end
end
function capi.RegisterWithdrawandholdAction(actionFunction)
table.insert(withdrawandholdActions, actionFunction)
end
function capi.OnWithdrawandhold()
for _, func in ipairs(withdrawandholdActions) do
func(orig.menu)
end
end
function capi.RegisterWithdrawfromcombatAction(actionFunction)
table.insert(withdrawfromcombatActions, actionFunction)
end
function capi.OnWithdrawfromcombat()
for _, func in ipairs(withdrawfromcombatActions) do
func(orig.menu)
end
end
function capi.RegisterCheat_satelliteAction(actionFunction)
table.insert(cheat_satelliteActions, actionFunction)
end
function capi.OnCheat_satellite()
for _, func in ipairs(cheat_satelliteActions) do
func(orig.menu)
end
end
function capi.RegisterCheat_navbeaconAction(actionFunction)
table.insert(cheat_navbeaconActions, actionFunction)
end
function capi.OnCheat_navbeacon()
for _, func in ipairs(cheat_navbeaconActions) do
func(orig.menu)
end
end
function capi.RegisterCheat_resourceprobeAction(actionFunction)
table.insert(cheat_resourceprobeActions, actionFunction)
end
function capi.OnCheat_resourceprobe()
for _, func in ipairs(cheat_resourceprobeActions) do
func(orig.menu)
end
end
function capi.RegisterCheat_takeownershipAction(actionFunction)
table.insert(cheat_takeownershipActions, actionFunction)
end
function capi.OnCheat_takeownership()
for _, func in ipairs(cheat_takeownershipActions) do
func(orig.menu)
end
end
function capi.RegisterCheat_warpAction(actionFunction)
table.insert(cheat_warpActions, actionFunction)
end
function capi.OnCheat_warp()
for _, func in ipairs(cheat_warpActions) do
func(orig.menu)
end
end
function capi.processSelectedPlayerShips()
local convertedComponent = ConvertStringTo64Bit(tostring(orig.menu.componentSlot.component))
local isplayerownedtarget = false
if convertedComponent ~= 0 then
isplayerownedtarget = GetComponentData(convertedComponent, "isplayerowned")
end
local playercontainer = C.GetPlayerContainerID()
local convertedPlayerContainer
if playercontainer ~= 0 then
convertedPlayerContainer = ConvertStringTo64Bit(tostring(playercontainer))
end
orig.menu.possibleorders = capi.possibleorders
orig.menu.numdockingpossible = 0
orig.menu.numassignableships = 0
orig.menu.numassignableminingships = 0
orig.menu.numremovableorders = 0
orig.menu.numremovabledefaultorders = 0
orig.menu.numwaitingforsignal = 0
orig.menu.numdockingatplayerpossible = 0
for i = #orig.menu.selectedplayerships, 1, -1 do
local ship = orig.menu.selectedplayerships[i]
if ship == orig.menu.componentSlot.component then
table.remove(orig.menu.selectedplayerships, i)
else
-- Check orders
for orderid, value in pairs(capi.possibleorders) do
if not value then
if C.IsOrderSelectableFor(orderid, ship) then
capi.possibleorders[orderid] = true
end
end
end
-- Check assignments
if isplayerownedtarget and C.IsComponentClass(orig.menu.componentSlot.component, "controllable") then
local commander = ConvertIDTo64Bit(GetCommander(ship))
if commander ~= convertedComponent and C.CanAcceptSubordinate(orig.menu.componentSlot.component, ship) then
orig.menu.numassignableships = orig.menu.numassignableships + 1
if GetComponentData(ship, "primarypurpose") == "mine" then
orig.menu.numassignableminingships = orig.menu.numassignableminingships + 1
end
end
end
-- Check docking
if C.IsComponentClass(orig.menu.componentSlot.component, "container") then
if (convertedComponent ~= 0) and IsDockingPossible(ship, convertedComponent) then
orig.menu.numdockingpossible = orig.menu.numdockingpossible + 1
end
end
if (playercontainer ~= 0) and IsDockingPossible(ship, convertedPlayerContainer) then
orig.menu.numdockingatplayerpossible = orig.menu.numdockingatplayerpossible + 1
end
-- check order removal
local numorders = C.GetNumOrders(ship)
local currentorders = ffi.new("Order[?]", numorders)
numorders = C.GetOrders(currentorders, numorders, ship)
for i = numorders, 1, -1 do
local isdocked, isdocking = GetComponentData(ship, "isdocked", "isdocking")
if (i == 1) and ((ffi.string(currentorders[0].orderdef) == "DockAndWait") and (isdocked or isdocking)) then
-- do nothing - removing the dock order would create an undock order ... rather have the ship stay put [Nick]
else
if C.RemoveOrder(ship, i, false, true) then
orig.menu.numremovableorders = orig.menu.numremovableorders + 1
break
end
local currentdefaultorder = ffi.new("Order")
if C.GetDefaultOrder(currentdefaultorder, ship) then
if (ffi.string(currentdefaultorder.orderdef) ~= "Wait") and (ffi.string(currentdefaultorder.orderdef) ~= "DockAndWait") then
orig.menu.numremovabledefaultorders = orig.menu.numremovabledefaultorders + 1
break
end
end
local commander = ConvertIDTo64Bit(GetCommander(convertedComponent))
if commander and (commander ~= 0) and (commander ~= ConvertStringTo64Bit(tostring(C.GetPlayerOccupiedShipID()))) then
orig.menu.numremovabledefaultorders = orig.menu.numremovabledefaultorders + 1
break
end
end
end
-- check for waiting for signal
local numorders = C.GetNumOrders(ship)
if numorders > 0 then
local orderparams = GetOrderParams(ship, 1)
local iswaitingforsignal = false
for i, param in ipairs(orderparams) do
if param.name == "releasesignal" and type(param.value) == "table" and param.value[1] == "playerownedship_proceed" then
orig.menu.numwaitingforsignal = orig.menu.numwaitingforsignal + 1
break
end
end
end
end
end
local occupiedPlayerShip = ConvertStringTo64Bit(tostring(C.GetPlayerOccupiedShipID()))
if (#orig.menu.selectedplayerships == 1) and (orig.menu.selectedplayerships[1] == occupiedPlayerShip) then
orig.menu.showPlayerInteractions = true
else
for i, ship in ipairs(orig.menu.selectedplayerships) do
if ship == occupiedPlayerShip then
orig.menu.removedOccupiedPlayerShip = occupiedPlayerShip
table.remove(orig.menu.selectedplayerships, i)
break
end
end
end
if isplayerownedtarget and C.IsComponentClass(orig.menu.componentSlot.component, "ship") then
if (playercontainer ~= 0) and (convertedComponent ~= 0) and IsDockingPossible(convertedComponent, convertedPlayerContainer) then
orig.menu.numdockingatplayerpossible = orig.menu.numdockingatplayerpossible + 1
end
end
for i = #orig.menu.selectednpcships, 1, -1 do
local ship = orig.menu.selectednpcships[i]
if ship == orig.menu.componentSlot.component then
table.remove(orig.menu.selectednpcships, i)
break
end
end
end
function capi.addOrder(order)
capi.possibleorders[order] = false
end
capi.config = {
layer = 3,
width = 250,
rowHeight = 16,
entryFontSize = Helper.standardFontSize,
entryX = 3,
mouseOutRange = 100,
border = 5,
sections = {
{ id = "main", text = "", isorder = false },
{ id = "interaction", text = ReadText(1001, 7865), isorder = false },
{ id = "hiringbuilderoption", text = "", isorder = false, subsections = {
{ id = "hiringbuilder", text = ReadText(1001, 7873) },
}},
{ id = "trade", text = ReadText(1001, 7104), isorder = false },
{ id = "playersquad_orders", text = ReadText(1001, 1002), isorder = false }, -- Broadcast
{ id = "main_orders", text = ReadText(1001, 7802), isorder = false },
{ id = "formationshapeoption", text = "", isorder = false, subsections = {
{ id = "formationshape", text = ReadText(1001, 7862) },
}},
{ id = "main_assignments", text = ReadText(1001, 7803), isorder = false },
{ id = "order", text = "", isorder = nil },
{ id = "guidance", text = "", isorder = nil, isplayerinteraction = true },
{ id = "player_interaction", text = ReadText(1001, 7843), isorder = false, isplayerinteraction = true },
{ id = "consumables", text = ReadText(1001, 7846), isorder = false, subsections = {
{ id = "consumables_civilian", text = ReadText(1001, 7847) },
{ id = "consumables_military", text = ReadText(1001, 7848) },
}},
{ id = "cheats", text = "Cheats", isorder = false }, -- (cheat only)
{ id = "selected", text = "", isorder = true, isplayerinteraction = true },
{ id = "selected_orders_all", text = ReadText(1001, 7804), isorder = true },
{ id = "selected_orders", text = ReadText(1001, 7804), isorder = true },
{ id = "mining_orders", text = "", isorder = true, subsections = {
{ id = "mining", text = ReadText(1041, 351) },
}},
{ id = "venturedockoption", text = "", isorder = true, subsections = {
{ id = "venturedock", text = ReadText(1001, 7844) },
}},
{ id = "trade_orders", text = ReadText(1001, 7861), isorder = true },
{ id = "selected_assignments", text = ReadText(1001, 7805), isorder = true },
{ id = "selected_consumables", text = ReadText(1001, 7849), isorder = true, subsections = {
{ id = "selected_consumables_civilian", text = ReadText(1001, 7847) },
{ id = "selected_consumables_military", text = ReadText(1001, 7848) },
}},
},
}
local sectionMainAssignments = {}
local sectionPlayerInteraction = {}
local sectionSelectedOrdersAll = {}
local sectionSelectedOrders = {}
local sectionTradeOrders = {}
local sectionSelectedAssignments = {}
local sectionTrade = {}
function capi.AddSectionMainAssignments(id)
sectionMainAssignments[id] = true
end
function capi.AddSectionPlayerInteraction(id)
sectionPlayerInteraction[id] = true
end
function capi.AddSectionSelectedOrdersAll(id)
sectionSelectedOrdersAll[id] = true
end
function capi.AddSectionSelectedOrders(id)
sectionSelectedOrders[id] = true
end
function capi.AddSectionTradeOrders(id)
sectionTradeOrders[id] = true
end
function capi.AddSectionSelectedAssignments(id)
sectionSelectedAssignments[id] = true
end
function capi.AddSectionTrade(id)
sectionTrade[id] = true
end
function capi.IsSectionMainAssignments(id)
if (id == "main_assignments") or sectionMainAssignments[id] then
return true
end
return false
end
function capi.IsSectionPlayerInteraction(id)
if (id == "player_interaction") or sectionPlayerInteraction[id] then
return true
end
return false
end
function capi.IsSectionSelectedOrdersAll(id)
if (id == "selected_orders_all") or sectionSelectedOrdersAll[id] then
return true
end
return false
end
function capi.IsSectionSelectedOrders(id)
if (id == "selected_orders") or sectionSelectedOrders[id] then
return true
end
return false
end
function capi.IsSectionTradeOrders(id)
if (id == "trade_orders") or sectionTradeOrders[id] then
return true
end
return false
end
function capi.IsSectionSelectedAssignments(id)
if (id == "selected_assignments") or sectionSelectedAssignments[id] then
return true
end
return false
end
function capi.IsSectionTrade(id)
if (id == "trade") or sectionTrade[id] then
return true
end
return false
end
function capi.addSectionTitle(ftable, section, first)
local height = 0
if section.text ~= "" then
if not first then
local row = ftable:addRow(false, { bgColor = Helper.color.transparent })
row[1]:setColSpan(2):createText("", { minRowHeight = capi.config.rowHeight / 2, fontsize = 1 })
height = height + row:getHeight() + Helper.borderSize
end
local row = ftable:addRow(false, { bgColor = Helper.color.transparent })
if capi.IsSectionMainAssignments(section.id) then
row[1]:createText(string.format(section.text, orig.menu.texts.commanderShortName), { font = Helper.standardFontBold, mouseOverText = orig.menu.texts.commanderName, titleColor = Helper.defaultSimpleBackgroundColor })
row[2]:createText("[" .. GetComponentData(ConvertStringTo64Bit(tostring(orig.menu.componentSlot.component)), "assignmentname") .. "]", { font = Helper.standardFontBold, halign = "right", height = Helper.subHeaderHeight, titleColor = Helper.defaultSimpleBackgroundColor })
elseif capi.IsSectionPlayerInteraction(section.id) then
if not first then
row[1]:createText(section.text, { font = Helper.standardFontBold, mouseOverText = section.text .. " " .. orig.menu.texts.targetName, titleColor = Helper.defaultSimpleBackgroundColor })
row[2]:createText(orig.menu.texts.targetBaseName or orig.menu.texts.targetShortName, { font = Helper.standardFontBold, halign = "right", color = orig.menu.colors.target, mouseOverText = section.text .. " " .. orig.menu.texts.targetName, height = Helper.subHeaderHeight, titleColor = Helper.defaultSimpleBackgroundColor })
end
elseif capi.IsSectionSelectedOrdersAll(section.id) then
row[1]:createText(section.text, { font = Helper.standardFontBold, mouseOverText = orig.menu.texts.selectedFullNamesAll, titleColor = Helper.defaultSimpleBackgroundColor })
row[2]:createText(orig.menu.texts.selectedNameAll, { font = Helper.standardFontBold, halign = "right", color = orig.menu.colors.selected, mouseOverText = orig.menu.texts.selectedFullNamesAll, height = Helper.subHeaderHeight, titleColor = Helper.defaultSimpleBackgroundColor })
elseif capi.IsSectionSelectedOrders(section.id) or capi.IsSectionTradeOrders(section.id) or capi.IsSectionSelectedAssignments(section.id) then
row[1]:createText(section.text, { font = Helper.standardFontBold, mouseOverText = orig.menu.texts.selectedFullNames, titleColor = Helper.defaultSimpleBackgroundColor })
row[2]:createText(orig.menu.texts.selectedName, { font = Helper.standardFontBold, halign = "right", color = orig.menu.colors.selected, mouseOverText = orig.menu.texts.selectedFullNames, height = Helper.subHeaderHeight, titleColor = Helper.defaultSimpleBackgroundColor })
else
row[1]:setColSpan(2):createText(section.text, { font = Helper.standardFontBold, height = Helper.subHeaderHeight, titleColor = Helper.defaultSimpleBackgroundColor })
end
height = height + row:getHeight() + Helper.borderSize
end
return height
end
function capi.createContentTable(frame, position)
local x = 0
if position == "right" then
x = orig.menu.width + Helper.borderSize
end
local ftable = frame:addTable(2, { tabOrder = orig.menu.subsection and 2 or 1, x = x, width = orig.menu.width, backgroundID = "solid", backgroundColor = Helper.color.semitransparent, highlightMode = "off" })
ftable:setDefaultCellProperties("text", { minRowHeight = capi.config.rowHeight, fontsize = capi.config.entryFontSize, x = capi.config.entryX })
ftable:setDefaultCellProperties("button", { height = capi.config.rowHeight })
ftable:setDefaultComplexCellProperties("button", "text", { fontsize = capi.config.entryFontSize, x = capi.config.entryX })
ftable:setDefaultComplexCellProperties("button", "text2", { fontsize = capi.config.entryFontSize, x = capi.config.entryX })
ftable:setColWidthPercent(2, 40)
ftable:setDefaultBackgroundColSpan(1, 2)
local height = 0
-- title
local row = ftable:addRow(false, { bgColor = Helper.color.transparent })
local text = orig.menu.texts.targetShortName
if orig.menu.construction then
text = orig.menu.texts.constructionName
end
text = TruncateText(text, Helper.standardFontBold, Helper.scaleFont(Helper.standardFontBold, Helper.headerRow1FontSize), orig.menu.width - Helper.standardButtonWidth - 2 * capi.config.entryX)
row[1]:setColSpan(2):createText(text, Helper.headerRowCenteredProperties)
row[1].properties.color = orig.menu.colors.target
height = height + row:getHeight() + Helper.borderSize
-- entries
local convertedComponent = ConvertStringTo64Bit(tostring(orig.menu.componentSlot.component))
local isonlinetarget, isplayerownedtarget
if convertedComponent ~= 0 then
isonlinetarget, isplayerownedtarget = GetComponentData(convertedComponent, "isonlineobject", "isplayerowned")
end
if (#orig.menu.selectedplayerships == 0) and (#orig.menu.selectednpcships > 0) then
-- only npc ships are selected, show the player that they cannot do anything with an npc ship
local row = ftable:addRow(false, { bgColor = Helper.color.transparent })
row[1]:createText(ReadText(1001, 7804), { mouseOverText = orig.menu.texts.npcFullNames, titleColor = Helper.defaultSimpleBackgroundColor })
row[2]:createText(orig.menu.texts.npcName, { halign = "right", color = orig.menu.colors.selected, mouseOverText = orig.menu.texts.npcFullNames, titleColor = Helper.defaultSimpleBackgroundColor })
local row = ftable:addRow(true, { bgColor = Helper.color.transparent })
local button = row[1]:setColSpan(2):createButton({ active = false, bgColor = Helper.color.darkgrey }):setText(ReadText(1001, 7852), { color = Helper.color.red })
elseif isonlinetarget and isplayerownedtarget then
local row = ftable:addRow(true, { fixed = true, bgColor = Helper.color.transparent })
local button = row[1]:setColSpan(2):createButton({ active = false, bgColor = Helper.color.darkgrey }):setText(ReadText(1001, 7868), { color = Helper.color.red })
else
local first = true
for _, section in ipairs(capi.config.sections) do
local pass = false
if orig.menu.showPlayerInteractions then
if section.isplayerinteraction or (orig.menu.shown and (not section.isorder)) then
pass = true
end
elseif (section.isorder == nil) or (section.isorder == (#orig.menu.selectedplayerships > 0)) then
pass = true
end
if pass then
if section.subsections then
local hastitle = false
for _, subsection in ipairs(section.subsections) do
if (#orig.menu.actions[subsection.id] > 0) or orig.menu.forceSubSection[subsection.id] then
if not hastitle then
height = height + capi.addSectionTitle(ftable, section, first)
first = false
hastitle = true
end
local data = { id = subsection.id, y = height }
local row = ftable:addRow(data, { bgColor = Helper.color.transparent })
local iconHeight = Helper.scaleY(capi.config.rowHeight)
local button = row[1]:setColSpan(2):createButton({
bgColor = #orig.menu.actions[subsection.id] > 0 and Helper.color.transparent or Helper.color.darkgrey,
highlightColor = #orig.menu.actions[subsection.id] > 0 and Helper.defaultButtonHighlightColor or Helper.defaultUnselectableButtonHighlightColor,
mouseOverText = (#orig.menu.actions[subsection.id] > 0) and "" or orig.menu.forceSubSection[subsection.id]
}):setText(subsection.text, { color = Helper.color.white }):setIcon("table_arrow_inv_right", { scaling = false, width = iconHeight, height = iconHeight, x = orig.menu.width - iconHeight })
row[1].handlers.onClick = function () return orig.menu.handleSubSectionOption(data) end
height = height + row:getHeight() + Helper.borderSize
end
end
elseif #orig.menu.actions[section.id] > 0 then
height = height + capi.addSectionTitle(ftable, section, first)
first = false
local availabletextwidth
if capi.IsSectionSelectedOrders(section.id) or capi.IsSectionTradeOrders(section.id) or capi.IsSectionSelectedAssignments(section.id) or capi.IsSectionPlayerInteraction(section.id) or capi.IsSectionTrade(section.id) then
local maxtextwidth = 0
for _, entry in ipairs(orig.menu.actions[section.id]) do
if not entry.hidetarget then
maxtextwidth = math.max(maxtextwidth, C.GetTextWidth(entry.text .. " ", Helper.standardFont, Helper.scaleFont(Helper.standardFont, capi.config.entryFontSize, true)))
end
end
availabletextwidth = orig.menu.width - maxtextwidth - 2 * Helper.scaleX(capi.config.entryX) - Helper.borderSize
end
for _, entry in ipairs(orig.menu.actions[section.id]) do
if entry.active == nil then
entry.active = true
end
local row = ftable:addRow(true, { bgColor = Helper.color.transparent })
local button = row[1]:setColSpan(2):createButton({
bgColor = entry.active and Helper.color.transparent or Helper.color.darkgrey,
highlightColor = entry.active and Helper.defaultButtonHighlightColor or Helper.defaultUnselectableButtonHighlightColor,
mouseOverText = entry.mouseOverText
}):setText(entry.text, { color = entry.active and Helper.color.white or Helper.color.lightgrey })
button.properties.uiTriggerID = entry.type
if capi.IsSectionSelectedOrders(section.id) or capi.IsSectionTradeOrders(section.id) or capi.IsSectionSelectedAssignments(section.id) or capi.IsSectionPlayerInteraction(section.id) or capi.IsSectionTrade(section.id) then
if not entry.hidetarget then
local text2 = ""
if entry.text2 then
text2 = entry.text2
else
if (capi.IsSectionTradeOrders(section.id) or capi.IsSectionTrade(section.id)) and entry.buildstorage then
text2 = orig.menu.texts.buildstorageName
else
text2 = orig.menu.texts.targetBaseName or orig.menu.texts.targetShortName
end
end
text2 = TruncateText(text2, button.properties.text.font, Helper.scaleFont(button.properties.text.font, button.properties.text.fontsize, button.properties.scaling), availabletextwidth)
button:setText2(text2, { halign = "right", color = orig.menu.colors.target })
if entry.mouseOverText == nil then
button.properties.mouseOverText = entry.text .. " " .. orig.menu.texts.targetName
end
end
end
if entry.active then
row[1].handlers.onClick = entry.script
end
height = height + row:getHeight() + Helper.borderSize
end
end
end
end
if first then
local row = ftable:addRow(true, { bgColor = Helper.color.transparent })
local button = row[1]:setColSpan(2):createButton({ active = false, bgColor = Helper.color.darkgrey }):setText("---", { halign = "center", color = Helper.color.red })
end
end
ftable:setSelectedRow(orig.menu.selectedRows.contentTable)
orig.menu.selectedRows.contentTable = nil
return ftable
end
function capi.prepareSections()
orig.menu.actions = {}
for _, section in ipairs(capi.config.sections) do
if section.subsections then
for _, subsection in ipairs(section.subsections) do
orig.menu.actions[subsection.id] = {}
end
else
orig.menu.actions[section.id] = {}
end
end
end
local function init()
for _, menu in ipairs(Menus) do
if menu.name == "InteractMenu" then
orig.menu = menu -- save entire menu, for other helper function access
orig.insertLuaAction = menu.insertLuaAction -- save original function
menu.insertLuaAction = capi.InsertLuaAction -- replace called function with you own
orig.menu.processSelectedPlayerShips = menu.processSelectedPlayerShips
menu.processSelectedPlayerShips = capi.processSelectedPlayerShips
orig.menu.addSectionTitle = menu.addSectionTitle
menu.addSectionTitle = capi.addSectionTitle
orig.menu.createContentTable = menu.createContentTable
menu.createContentTable = capi.createContentTable
orig.menu.prepareSections = menu.prepareSections
menu.prepareSections = capi.prepareSections
break
end
end
orig.menu.possibleorders = {
["Attack"] = false,
["AttackInRange"] = false,
["Board"] = false,
["Collect"] = false,
["CollectDropsInRadius"] = false,
["DeployObjectAtPosition"] = false,
["DockAndWait"] = false,
["Explore"] = false,
["ExploreUpdate"] = false,
["Flee"] = false,
["Follow"] = false,
["MiningPlayer"] = false,
["MoveWait"] = false,
["Player_DockToTrade"] = false,
["ProtectStation"] = false,
["Repair"] = false,
}
capi.possibleorders = orig.menu.possibleorders
capi.forceSubSection = orig.menu.forceSubSection
--orig.menu.possibleorders = capi.possibleorders
end
init()