Advertisement
Guest User

Untitled

a guest
Apr 19th, 2023
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.69 KB | Gaming | 0 0
  1. -- this is a hack to get access to production module resource numbers that are not available to MD
  2.  
  3. local function GetProductionResources(event, param)
  4.     local data = GetLibraryEntry(GetMacroData(param, "infolibrary"), param)
  5.     AddUITriggeredEvent("faction_fix_pack", "resource_data", {param, data})
  6. end
  7.  
  8. RegisterEvent("GetProductionResources", GetProductionResources)
  9.  
  10. -- hack to address the AI shipyard build drones getting lost
  11. -- hack to set NPC blacklist to a special internal one so traders avoid Xenon sectors
  12. -- update to make 'sellable' actually respected by the UI
  13. -- those really shouldn't be in this file, but I don't want to deal with patching the ui.xml again right now
  14.  
  15. -- ffi setup
  16. local ffi = require("ffi")
  17. local C = ffi.C
  18. ffi.cdef[[
  19.     typedef uint64_t UniverseID;
  20.  
  21.     typedef struct {
  22.         const char* macro;
  23.         int amount;
  24.     } SupplyOverride;
  25.     void UpdateSupplyOverrides(UniverseID containerid, SupplyOverride* overrides, uint32_t numoverrides);
  26.     uint32_t GetNumSupplyOrders(UniverseID containerid, bool defaultorders);
  27.     uint32_t GetSupplyOrders(SupplyOverride* result, uint32_t resultlen, UniverseID containerid, bool defaultorders);
  28.  
  29.     typedef int32_t BlacklistID;
  30.     typedef uint64_t UniverseID;
  31.     typedef struct {
  32.         uint32_t nummacros;
  33.         uint32_t numfactions;
  34.     } BlacklistCounts;
  35.     typedef struct {
  36.         uint32_t id;
  37.         const char* type;
  38.         const char* name;
  39.         bool usemacrowhitelist;
  40.         uint32_t nummacros;
  41.         const char** macros;
  42.         bool usefactionwhitelist;
  43.         uint32_t numfactions;
  44.         const char** factions;
  45.         const char* relation;
  46.         bool hazardous;
  47.     } BlacklistInfo2;
  48.     BlacklistID CreateBlacklist2(BlacklistInfo2 info);
  49.     uint32_t GetAllBlacklists(BlacklistID* result, uint32_t resultlen);
  50.     uint32_t GetNumAllBlacklists(void);
  51.     void UpdateBlacklist2(BlacklistInfo2 info);
  52.     void SetControllableBlacklist(UniverseID controllableid, BlacklistID id, const char* listtype, bool value);
  53.     void RemoveBlacklist(BlacklistID id);
  54.     bool GetBlacklistInfo2(BlacklistInfo2* info, BlacklistID id);
  55.     BlacklistCounts GetBlacklistInfoCounts(BlacklistID id);
  56. ]]
  57.  
  58. local BLACKLIST_NAME = "Internal NPC Blacklist"
  59. local CachedBlacklistID = -1
  60.  
  61. local ExtraFactionBlacklistsCreated = false
  62.  
  63. -- todo grab relations from ingame and reset periodically in case they change dynamically?
  64. local FactionsWithExtraBlacklists = {}
  65.  
  66. -- base game factions
  67. FactionsWithExtraBlacklists["antigone"] =           {"holyorder", "holyorderfanatic", "scaleplate", "fallensplit", "split"}
  68. FactionsWithExtraBlacklists["argon"] =              {"holyorder", "holyorderfanatic", "scaleplate", "fallensplit", "split"}
  69. FactionsWithExtraBlacklists["holyorder"] =          {"antigone", "argon", "ministry", "paranid", "scaleplate", "teladi", "fallensplit", "boron"}
  70. FactionsWithExtraBlacklists["holyorderfanatic"] =   {"antigone", "argon", "paranid", "trinity", "fallensplit", "pioneers", "terran", "boron"}
  71. FactionsWithExtraBlacklists["ministry"] =           {"holyorder", "scaleplate", "fallensplit"}
  72. FactionsWithExtraBlacklists["paranid"] =            {"holyorder", "holyorderfanatic", "scaleplate", "fallensplit"}
  73. FactionsWithExtraBlacklists["teladi"] =             {"holyorder", "fallensplit"}
  74. FactionsWithExtraBlacklists["trinity"] =            {"holyorderfanatic", "scaleplate", "fallensplit"}
  75.  
  76. -- split
  77. FactionsWithExtraBlacklists["court"] =              {"fallensplit", "scaleplate"}
  78. FactionsWithExtraBlacklists["fallensplit"] =        {"antigone", "argon", "court", "holyorder", "holyorderfanatic", "ministry", "paranid", "split", "teladi", "trinity", "pioneers", "terran", "boron"}
  79. FactionsWithExtraBlacklists["freesplit"] =          {"scaleplate", "boron"}
  80. FactionsWithExtraBlacklists["split"] =              {"antigone", "argon", "court", "fallensplit", "scaleplate", "boron"}
  81.  
  82. -- terran
  83. FactionsWithExtraBlacklists["pioneers"] =           {"fallensplit", "holyorderfanatic", "scaleplate"}
  84. FactionsWithExtraBlacklists["terran"] =             {"fallensplit", "holyorderfanatic", "scaleplate"}
  85.  
  86. -- boron
  87. FactionsWithExtraBlacklists["boron"] =              {"fallensplit","freesplit","holyorder","holyorderfanatic","scaleplate","split"}
  88.  
  89. local BlacklistIDsForSpecificFactions = {}
  90.  
  91. local Super_ffiVLA = Helper.ffiVLA
  92.  
  93. local function CacheNPCBlacklist()
  94.     local blacklists = {}
  95.     Super_ffiVLA(blacklists, "BlacklistID", C.GetNumAllBlacklists, C.GetAllBlacklists)
  96.     local found = false
  97.     for i = #blacklists, 1, -1 do
  98.         local id = blacklists[i]
  99.  
  100.         local counts = C.GetBlacklistInfoCounts(id)
  101.         local buf = ffi.new("BlacklistInfo2")
  102.         buf.nummacros = counts.nummacros
  103.         buf.macros = Helper.ffiNewHelper("const char*[?]", counts.nummacros)
  104.         buf.numfactions = counts.numfactions
  105.         buf.factions = Helper.ffiNewHelper("const char*[?]", counts.numfactions)
  106.         if C.GetBlacklistInfo2(buf, id) then
  107.             if ffi.string(buf.name) == BLACKLIST_NAME then
  108.                 -- sanity check nobody has messed with it
  109. --[[ this does not work after all: seems 'relation' is always relative to player, not the ship owner!
  110.                 if ffi.string(buf.relation) == "nemesis" then
  111. ]]
  112.                 if buf.numfactions == 1 and ffi.string(buf.factions[0]) == "xenon" then
  113.                     CachedBlacklistID = id;
  114.                 else
  115.                     DebugError("Found NPC blacklist with the appropriate name but incorrect settings, resetting...")
  116.                     C.RemoveBlacklist(id)
  117.                 end
  118.             end
  119.  
  120.             for faction in pairs(FactionsWithExtraBlacklists) do
  121.                 if ffi.string(buf.name) == (BLACKLIST_NAME .. " " .. faction) then
  122.                     BlacklistIDsForSpecificFactions[faction] = id
  123.                     ExtraFactionBlacklistsCreated = true
  124.                 end
  125.             end
  126.         end
  127.     end
  128. end
  129.  
  130. local function CreateExtraFactionBlacklists()
  131.     for faction in pairs(FactionsWithExtraBlacklists) do
  132.         local blacklist = ffi.new("BlacklistInfo2")
  133.         blacklist.type = Helper.ffiNewString("sectortravel")
  134.         blacklist.name = Helper.ffiNewString(BLACKLIST_NAME .. " " .. faction)
  135.  
  136.         blacklist.relation = ""
  137.         blacklist.hazardous = false
  138.  
  139.         blacklist.nummacros = 0
  140.         blacklist.macros = Helper.ffiNewHelper("const char*[?]", blacklist.nummacros)
  141.  
  142.         local enemyFactions = FactionsWithExtraBlacklists[faction]
  143.  
  144.         blacklist.numfactions = table.getn(FactionsWithExtraBlacklists[faction]) + 1
  145.         blacklist.factions = Helper.ffiNewHelper("const char*[?]", blacklist.numfactions)
  146.         blacklist.factions[0] = Helper.ffiNewString("xenon")
  147.         for i,enemyFaction in pairs(FactionsWithExtraBlacklists[faction]) do
  148.             blacklist.factions[i] = Helper.ffiNewString(enemyFaction)
  149.         end
  150.  
  151.         blacklist.usemacrowhitelist = false
  152.         blacklist.usefactionwhitelist = false
  153.  
  154.         BlacklistIDsForSpecificFactions[faction] = C.CreateBlacklist2(blacklist)
  155.     end
  156. end
  157.  
  158. local function RemoveNPCBlacklist(event, param)
  159.     local NPC = ConvertIDTo64Bit(param)
  160.     C.SetControllableBlacklist(NPC, -1, "sectortravel", false)
  161. end
  162.  
  163. local function SetNPCBlacklist(event, param)
  164.     local NPC = ConvertIDTo64Bit(param)
  165.     local owner = GetComponentData(NPC, "owner")
  166.  
  167.     -- does not work for Xenon, see below
  168.     -- TODO: could create separate blacklist, but it doesn't seem worth it at the moment
  169.     if owner == "xenon" then
  170.         RemoveNPCBlacklist(event, param)
  171.         return
  172.     end
  173.  
  174.     if CachedBlacklistID == -1 then
  175.         CacheNPCBlacklist()
  176.     end
  177.  
  178.     if ExtraFactionBlacklistsCreated == false then
  179.         CreateExtraFactionBlacklists()
  180.         ExtraFactionBlacklistsCreated = true
  181.     end
  182.  
  183.     local SpecialBlacklistID = BlacklistIDsForSpecificFactions[owner]
  184.     if SpecialBlacklistID ~= nil then
  185.         C.SetControllableBlacklist(NPC, SpecialBlacklistID, "sectortravel", true)
  186.         return
  187.     end
  188.  
  189.     -- use global default blacklist
  190.     if CachedBlacklistID ~= -1 then
  191.         C.SetControllableBlacklist(NPC, CachedBlacklistID, "sectortravel", true)
  192.     else
  193.         local blacklist = ffi.new("BlacklistInfo2")
  194.         blacklist.type = Helper.ffiNewString("sectortravel")
  195.         blacklist.name = Helper.ffiNewString(BLACKLIST_NAME)
  196. --[[ this does not work after all: seems 'relation' is always relative to player, not the ship owner!
  197.         -- TODO: 'kill' would theoretically be better but going conservative for now - especially concerned about smugglers (does blacklist use cover owner or true owner? what happens if they get uncovered mid-flight? etc)
  198.         blacklist.relation = Helper.ffiNewString("nemesis")
  199.         blacklist.hazardous = false
  200.  
  201.         blacklist.nummacros = 0
  202.         blacklist.macros = Helper.ffiNewHelper("const char*[?]", blacklist.nummacros)
  203.  
  204.         blacklist.numfactions = 0
  205.         blacklist.factions = Helper.ffiNewHelper("const char*[?]", blacklist.numfactions)
  206.     ]]
  207.         blacklist.relation = ""
  208.         blacklist.hazardous = false
  209.  
  210.         blacklist.nummacros = 0
  211.         blacklist.macros = Helper.ffiNewHelper("const char*[?]", blacklist.nummacros)
  212.  
  213.         blacklist.numfactions = 1
  214.         blacklist.factions = Helper.ffiNewHelper("const char*[?]", blacklist.numfactions)
  215.         blacklist.factions[0] = Helper.ffiNewString("xenon")
  216.  
  217.         blacklist.usemacrowhitelist = false
  218.         blacklist.usefactionwhitelist = false
  219.  
  220.         CachedBlacklistID = C.CreateBlacklist2(blacklist)
  221.         C.SetControllableBlacklist(NPC, CachedBlacklistID, "sectortravel", true)
  222.     end
  223. end
  224.  
  225. RegisterEvent("SetNPCBlacklist", SetNPCBlacklist)
  226. RegisterEvent("RemoveNPCBlacklist", RemoveNPCBlacklist)
  227.  
  228. -- this is ugly but it's the only viable catch point for all places in the UI that request all blacklists
  229. local function OverrideBlacklistItems(result, vlaType, vlaSizeFunction, vlaFunction, ...)
  230.     Super_ffiVLA(result, vlaType, vlaSizeFunction, vlaFunction, ...)
  231.     if vlaSizeFunction == C.GetNumAllBlacklists and #result then
  232.         if CachedBlacklistID == -1 then
  233.             CacheNPCBlacklist()
  234.         end
  235.  
  236.         for i = #result, 1, -1 do
  237.             if result[i] == CachedBlacklistID then
  238.                 table.remove(result, i)
  239.             end
  240.  
  241.             -- todo make work
  242.             -- for specialBlackListId in ipairs(BlacklistIDsForSpecificFactions) do
  243.             --  if result[i] == specialBlackListId then
  244.             --      table.remove(result, i)
  245.             --  end
  246.             -- end
  247.         end
  248.     end
  249. end
  250. Helper.ffiVLA = OverrideBlacklistItems
  251.  
  252. local function FixShipyardBuildDrones(event, param)
  253.     local Shipyard = ConvertIDTo64Bit(param)
  254.  
  255.     local old_amount = 0
  256.  
  257.     local n = C.GetNumSupplyOrders(Shipyard, true)
  258.     local buf = ffi.new("SupplyOverride[?]", n)
  259.     n = C.GetSupplyOrders(buf, n, Shipyard, true)
  260.     for i = 0, n - 1 do
  261.         local macro = ffi.string(buf[i].macro)
  262.         if macro == "ship_gen_xs_buildingdrone_01_a_macro" then
  263.             old_amount = buf[i].amount
  264.         end
  265.     end
  266.  
  267.     local overrides = ffi.new("SupplyOverride[?]", 1)
  268.     overrides[0].macro = Helper.ffiNewString("ship_gen_xs_buildingdrone_01_a_macro")
  269.     if GetComponentData(Shipyard, "isshipyard") then
  270.         if GetComponentData(Shipyard, "owner") == "xenon" then
  271.             overrides[0].amount = math.max(old_amount, 20)
  272.         else
  273.             overrides[0].amount = math.max(old_amount, 50)
  274.         end
  275.     else
  276.         overrides[0].amount = math.max(old_amount, 15)
  277.     end
  278.     C.UpdateSupplyOverrides(Shipyard, overrides, 1)
  279.  
  280.     Helper.ffiClearNewHelper()
  281. end
  282.  
  283. RegisterEvent("FixShipyardBuildDrones", FixShipyardBuildDrones)
  284.  
  285. local menu = nil
  286. local Funcs = {}
  287. local territory_data = {}
  288.  
  289. local function InitMenu()
  290.     for _, OrigMenu in ipairs(Menus) do
  291.         if OrigMenu.name == "InteractMenu" then
  292.             menu = OrigMenu
  293.             Funcs.Super_insertLuaAction = menu.insertLuaAction
  294.             menu.insertLuaAction = Funcs.insertLuaAction
  295.             break
  296.         end
  297.     end
  298. end
  299.  
  300. function Funcs.insertLuaAction(actiontype, istobedisplayed)
  301.     if actiontype == "sellships" then
  302.     -- copy/paste from the top of the original
  303.         local convertedComponent = ConvertStringTo64Bit(tostring(menu.componentSlot.component))
  304.         local isplayerownedtarget = GetComponentData(convertedComponent, "isplayerowned")
  305.  
  306.         if #menu.selectedplayerships > 0 then
  307.             if not isplayerownedtarget then
  308.                 local shiptrader, isdock, iswharf, isshipyard = GetComponentData(convertedComponent, "shiptrader", "isdock", "iswharf", "isshipyard")
  309.                 if shiptrader and isdock and (iswharf or isshipyard) then
  310.                     local cansell = false
  311.                     for _, ship in ipairs(menu.selectedplayerships) do
  312.                         if C.CanContainerBuildShip(menu.componentSlot.component, ship) then
  313.                             cansell = true
  314.                             break
  315.                         end
  316.                     end
  317.                     if cansell then
  318.                         local sellable = true
  319.                         local unsellable_list = GetNPCBlackboard(ConvertStringTo64Bit(tostring(C.GetPlayerID())), "$unsellable_ships")
  320.                         if unsellable_list then
  321.                             for _, selected in ipairs(menu.selectedplayerships) do
  322.                                 for _, ship in ipairs(unsellable_list) do
  323.                                     if ConvertStringTo64Bit(tostring(ship)) == selected then
  324.                                         sellable = false
  325.                                         break
  326.                                     end
  327.                                 end
  328.                                 if not sellable then
  329.                                     break
  330.                                 end
  331.                             end
  332.                         end
  333.                         menu.insertInteractionContent("selected_orders", { type = actiontype, text = (#menu.selectedplayerships == 1) and ReadText(1001, 7855) or ReadText(1001, 7856), helpOverlayID = "interactmenu_sellships", helpOverlayText = " ", helpOverlayHighlightOnly = true, script = menu.buttonSellShips, active = sellable })
  334.                     end
  335.                 end
  336.             end
  337.         end
  338.     else
  339.         Funcs.Super_insertLuaAction(actiontype, istobedisplayed)
  340.     end
  341. end
  342.  
  343. InitMenu()
  344.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement