[API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.32 (02/27/19))

The place to discuss scripting and game modifications for X4: Foundations.

Moderators: Scripting / Modding Moderators, Moderators for English X Forum

LegionOfOne
Posts: 122
Joined: Sun, 16. Dec 18, 13:16
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.20

Post by LegionOfOne » Wed, 9. Jan 19, 23:15

DeadMor0z wrote:
Wed, 9. Jan 19, 04:39
Rewrited latest API to use raise_lua_event and RegisterEvent
I don't know enough to say if the code itself is better or worse than before.
But I tested it with my UI mod, and it worked just fine, while clearing up the debug log a bit. It's still full, but of unrelated things.
So from a purely empirical view, it seems like an interesting improvement.

Thanks for sharing it !

In that spirit, I have code that adds a 'Create/Remove Buy Offer' button to the station logical overview UI, and allows buy offers to display for 'trade goods', not used in production or produced by the station.
It is mostly useful if you use the Warehouse mod, but anyone who wants to see how it works, or wants to integrate it in a mod can request it via PM.

Unclejack
Posts: 24
Joined: Wed, 5. Dec 18, 01:50
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.20

Post by Unclejack » Thu, 10. Jan 19, 04:13

Hello again.

Thanks for keeping this updated and working hard on it everyone. I just downloaded the latest package from DeadMorOz (v0.3) and it works with my lua scripts.
@DeadMorOz, I just wanted to let you know the version in the content.xml file is still 0.2 (but I guess this is for the dependency?)

Also, more importantly maybe, a nexusmods user (Te1waz) has reported that when playing the game in a borderless window and pressing alt+enter, which kind of minimizes the window, the mod's lua script he is using fails to work.
I tried repeating his problem and it is reproducible with the v0.1, 0.2 and 0.3 API and two of my lua scripts (one is the Enhanced Holomap 3). In addition, I also tried the command /reloadui in game, which also fails to reinitiliaze the modded lua script/G_Work_Around (maybe as expected). As Alt+Enter from a borderless window seems to fully reset the UI, I tried to call /refreshmd (edit) before using alt+enter or the /reloadui command. However, this failed to reinitialize the lua script/G_Work_Around as well. I guess it would be difficult to fix and the md scripts would need to keep running. Maybe we can think of something to recall the lua script from the md file when the UI is just reloaded for a given game, although I do not really know. I know the debugging tools "allow" for reloadui, but as Alt+enter in a borderless window is user input that any player (not debugging or using the chat console) might use, it would be nice to find a way to prevent the problem.

Then, when I downloaded the current 0.2 version of the API, I noticed that in every subfolder a hidden folder called: ".tmp.drivedownload" is present.This folder was not present in 0.1 AFAIK and is also not present in the "0.3" version. Is this an oversight when packaging your folder?

Finally, I just saw the updated "user" terms and will update my mod accordingly when possible. However, do you think it would be possible to include a user friendly download link at the top which does not include the hidden folder and the debugging tools and template? It would increase the user friendlyness of the post and would make it easier to send people here, where they find the download link at the top without the extra baggage. Also, maybe it would be possible to include a basic readme within the downloaded package, this will help people that just want to download it quickly without scrolling through the forum post. I understand if you would prefer not to do this, it is just a suggestion.. although having multiple download links is not nice either.
Last edited by Unclejack on Thu, 10. Jan 19, 15:41, edited 1 time in total.

DeadMor0z
Posts: 26
Joined: Fri, 29. Nov 13, 18:20
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.20

Post by DeadMor0z » Thu, 10. Jan 19, 10:07

Unclejack wrote:
Thu, 10. Jan 19, 04:13
Hello again.

Thanks for keeping this updated and working hard on it everyone. I just downloaded the latest package from DeadMorOz (v0.3) and it works with my lua scripts.
@DeadMorOz, I just wanted to let you know the version in the content.xml file is still 0.2 (but I guess this is for the dependency?)

Also, more importantly maybe, a nexusmods user (Te1waz) has reported that when playing the game in a borderless window and pressing alt+enter, which kind of minimizes the window, the mod's lua script he is using fails to work.
I tried repeating his problem and it is reproducible with the v0.1, 0.2 and 0.3 API and two of my lua scripts (one is the Enhanced Holomap 3). In addition, I also tried the command /reloadui in game, which also fails to reinitiliaze the modded lua script/G_Work_Around (maybe as expected). As Alt+Enter from a borderless window seems to fully reset the UI, I tried to call /resetmd before using alt+enter or the /reloadui command. However, this failed to reinitialize the lua script/G_Work_Around as well. I guess it would be difficult to fix and the md scripts would need to keep running. Maybe we can think of something to recall the lua script from the md file when the UI is just reloaded for a given game, although I do not really know. I know the debugging tools "allow" for reloadui, but as Alt+enter in a borderless window is user input that any player (not debugging or using the chat console) might use, it would be nice to find a way to prevent the problem.

Then, when I downloaded the current 0.2 version of the API, I noticed that in every subfolder a hidden folder called: ".tmp.drivedownload" is present.This folder was not present in 0.1 AFAIK and is also not present in the "0.3" version. Is this an oversight when packaging your folder?

Finally, I just saw the updated "user" terms and will update my mod accordingly when possible. However, do you think it would be possible to include a user friendly download link at the top which does not include the hidden folder and the debugging tools and template? It would increase the user friendlyness of the post and would make it easier to send people here, where they find the download link at the top without the extra baggage. Also, maybe it would be possible to include a basic readme within the downloaded package, this will help people that just want to download it quickly without scrolling through the forum post. I understand if you would prefer not to do this, it is just a suggestion.. although having multiple download links is not nice either.
About version - I just forgot to update it.
As of Alt-Enter/reloadui - there is a problem:
when ui is reloaded, lua stack will be cleared and all lua scripts will be initialized. since md scripts already triggered at savegame load/game start - lua workraround script will know nothing about lua addons and won't load them.
I don't see a way now how to track which lua addons were loaded and autoreload them when ui is reloaded. I can recommend to call /refreshmd (not /resetmd - there is no such command) AFTER UI reset (after Alt_Enter or /reloadui) - this should help. Also, reloading savegame will refresh md and ui and should help.

Romz
Posts: 21
Joined: Sat, 24. Dec 16, 19:39
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.20

Post by Romz » Fri, 11. Jan 19, 00:53

DeadMor0z wrote:
Wed, 9. Jan 19, 04:39
EDIT: Rewrited latest API to use raise_lua_event and RegisterEvent, checked - all done well. You can get and check it from here:

MUST BE INSTALLED IN YOUR %installdir%\extensions folder! REQUIRES: basic literacy to install.
v0.30 Right Click API, _G Work Around, Modding Templet, and Debugging Tools
[ external image ]
That broke all my mods, that use _G Workaround

DeadMor0z
Posts: 26
Joined: Fri, 29. Nov 13, 18:20
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.20

Post by DeadMor0z » Fri, 11. Jan 19, 01:59

Romz wrote:
Fri, 11. Jan 19, 00:53
DeadMor0z wrote:
Wed, 9. Jan 19, 04:39
EDIT: Rewrited latest API to use raise_lua_event and RegisterEvent, checked - all done well. You can get and check it from here:

MUST BE INSTALLED IN YOUR %installdir%\extensions folder! REQUIRES: basic literacy to install.
v0.30 Right Click API, _G Work Around, Modding Templet, and Debugging Tools
[ external image ]
That broke all my mods, that use _G Workaround
That was not intended to use with mods, which were made for v0.20 of this mod, as it uses different load technique. if you need all your mods to work with this new version - you need to change their md script in accordance with new template.
Also, I'm not the author of this mod - I made changes for him (or anyone interested) to CHECK how it works.

Romz
Posts: 21
Joined: Sat, 24. Dec 16, 19:39
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.20

Post by Romz » Fri, 11. Jan 19, 10:48

DeadMor0z wrote:
Fri, 11. Jan 19, 01:59
That was not intended to use with mods, which were made for v0.20 of this mod, as it uses different load technique. if you need all your mods to work with this new version - you need to change their md script in accordance with new template.
Also, I'm not the author of this mod - I made changes for him (or anyone interested) to CHECK how it works.
Ok.
Waiting oficial udate from morbideth.

DeadMor0z
Posts: 26
Joined: Fri, 29. Nov 13, 18:20
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.20

Post by DeadMor0z » Fri, 11. Jan 19, 12:43

Romz wrote:
Fri, 11. Jan 19, 10:48
DeadMor0z wrote:
Fri, 11. Jan 19, 01:59
That was not intended to use with mods, which were made for v0.20 of this mod, as it uses different load technique. if you need all your mods to work with this new version - you need to change their md script in accordance with new template.
Also, I'm not the author of this mod - I made changes for him (or anyone interested) to CHECK how it works.
Ok.
Waiting oficial udate from morbideth.
In any way, if he accepts these changes, you'll need to update your mods.

Romz
Posts: 21
Joined: Sat, 24. Dec 16, 19:39
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.20

Post by Romz » Fri, 11. Jan 19, 12:56

DeadMor0z wrote:
Fri, 11. Jan 19, 12:43
In any way, if he accepts these changes, you'll need to update your mods.
It is a morbideth's mods. And Unclejack

DeadMor0z
Posts: 26
Joined: Fri, 29. Nov 13, 18:20
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.20

Post by DeadMor0z » Fri, 11. Jan 19, 14:44

Made an Alt+Enter/reloadui workaround - now all addons loaded with _G Workaround will be reloaded properly after UI reset.
For changes need to be made in user-made addons md file - see template.

MUST BE INSTALLED IN YOUR %installdir%\extensions folder! REQUIRES: basic literacy to install.
v0.35 Right Click API, _G Work Around, Modding Templet, and Debugging Tools
[ external image ]

For now there is one problem remains - if user mod installed in documents location - passed lua filename will not be found.

morbideth
Posts: 391
Joined: Sun, 9. Nov 08, 03:07
x3tc

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.31

Post by morbideth » Tue, 22. Jan 19, 02:29

Updated to v0.31
  • Incorporated changes by DeadMor0z to use LUA events. This removes some debug spam and solves some issues with reloading the UI. \reloadui will now work with mods using the API. All previous versions using the menu or signals are depreciated and will no longer function. Ensure that your mods are updated before using this version.
  • Right click API added support for custom sections and subsections, see below for more details.
  • Debug Tools: Enabled the Cheat menu. This accessible from the left-hand bar, on the map menu.
  • Moved templet to the debug tools zip, renamed zip to modding tools.
  • Add content.xml with dependancy entries to the templet.
What are sections and subsection? A section would be like:
[ external image ]


And a subsection:
[ external image ]

The second post has been updated with instructions on how to implement sections and subsections.
Last edited by morbideth on Tue, 22. Jan 19, 07:13, edited 1 time in total.

Forleyor
Posts: 40
Joined: Thu, 11. Jun 15, 19:09
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.31

Post by Forleyor » Tue, 22. Jan 19, 04:34

Oh nice :D

Just pushed a release of Info Center to support 0.31, very cool morbideth

User avatar
Drewgamer
Posts: 536
Joined: Fri, 27. Aug 10, 08:39
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.31

Post by Drewgamer » Tue, 22. Jan 19, 17:24

I just wanted to thank you for your work on this! Also thanks to DeadMor0z for the tweaks you contributed. Tons of good information in this thread (especially the tutorials on the main page).

Keep it up :)
Check out my mod Crystal Rarities

LegionOfOne
Posts: 122
Joined: Sun, 16. Dec 18, 13:16
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.31

Post by LegionOfOne » Thu, 24. Jan 19, 21:05

The 0.31 workaround works great, thanks.

I implemented it in the Warehouse - Trade Station mod.
I also included in the download, but still in an independent folder, the 0.31 G_Workaround, for compatibility and ease of use.
In case the next version introduces new syntax, like between 0.20 and 0.31, it might be useful to include the compatible version.
But if it is contrary to your wishes, I will remove the workaround mod from my download and only leave a link to this thread.

Edit : I had missed the information in the OP, I stopped including the workaround.
Last edited by LegionOfOne on Fri, 25. Jan 19, 01:32, edited 2 times in total.

morbideth
Posts: 391
Joined: Sun, 9. Nov 08, 03:07
x3tc

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.31

Post by morbideth » Thu, 24. Jan 19, 23:55

LegionOfOne wrote:
Thu, 24. Jan 19, 21:05
The 0.31 workaround works great, thanks.

I implemented it in the Warehouse - Trade Station mod.
I also included in the download, but still in an independent folder, the 0.31 G_Workaround, for compatibility and ease of use.
In case the next version introduces new syntax, like between 0.20 and 0.31, it might be useful to include the compatible version.
But if it is contrary to your wishes, I will remove the workaround mod from my download and only leave a link to this thread.
morbideth wrote:
Wed, 2. Jan 19, 07:33
  • 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.
I believe I made my stance quite clear. Post 1.0 things will not be depreciated without significant notice. I will, in future versions, give a least a 1 update gap before depreciating anything. I meant to do so this time, just forgot.

goodlives13
Posts: 8
Joined: Fri, 28. Sep 18, 04:46
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.31

Post by goodlives13 » Fri, 22. Feb 19, 12:49

I use djfhes carrier mod but right click for my own ship is not responeding.

It's seems to worng for API system problem.

User avatar
Malakie
Posts: 1059
Joined: Tue, 13. Apr 04, 23:08
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.31

Post by Malakie » Fri, 22. Feb 19, 23:38

This no longer works in the current build of the game....

Activating it BREAKS the game... Trying to right click on ANY owned item in the list, no menu at all now appears. I downloaded the most current version I could find.. Now at least the right menu shows up for objects you own.. However the entire Ship design menu and stations design menu no longer does.. When you try to repair or update a ship or try to build a new one, the menu of items is completely gone.

Removing this mod, all is well again but of course that breaks any other mod using it.

Any idea on when a fix will be coming?
Take it light.....

Malakie

----------------------------------------------------

dwbennett
Posts: 56
Joined: Fri, 14. Dec 18, 02:15
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.31

Post by dwbennett » Tue, 26. Feb 19, 17:03

With Ver. 2.0 of the game, the RghtClickAPI part of UI_API_v0.35 causes major problems. After selecting a ship in map view and then right clicking on it (no holding the right button), the map view rotates and tilts as when the right mouse button is clicked and held on the map. After right clicking on the map again the right click and hold will finally release with the map in whatever final view the map gyrations generates. Left clicking on a ship in the map without selecting it first causes the same problem. Turning off the Community Right Click API mod in the Extension menu or removing the RightClickAPI folder from the Extension folder will both solve the problem as far as I can tell.

Take care,
dwbennett

morbideth
Posts: 391
Joined: Sun, 9. Nov 08, 03:07
x3tc

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.32 (02/27/19))

Post by morbideth » Wed, 27. Feb 19, 14:29

v0.32
  • Updated the right click api to work with 2.0.
  • Added 'showTypes' features to debugging tools, intended for use with the right-click menu. add capi.showTypes = true to your init() function to print the action types when you right-click on something. Use this to determine which action type you want to use to trigger your right-click menu.
  • Added right-click stuff to templet

Berserk Knight
Posts: 398
Joined: Tue, 17. Dec 13, 01:34
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.32 (02/27/19))

Post by Berserk Knight » Fri, 8. Mar 19, 12:21

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()

User avatar
Shuulo
Posts: 1629
Joined: Mon, 14. Apr 08, 17:03
x4

Re: [API/GUIDE] How to mod the UI (_G Workaround and Right Click API) v0.32 (02/27/19))

Post by Shuulo » Fri, 8. Mar 19, 18:40

Whenever G workaround is in my extensions folder launching game crashes my PC. Anyone encountered that?

Post Reply

Return to “X4: Foundations - Scripts and Modding”