Guest User

researchstation.lua

a guest
Jun 9th, 2024
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 39.17 KB | Gaming | 0 0
  1. UpgradeGenerator = include("upgradegenerator")
  2. include("azimuthlib-uiproportionalsplitter")
  3. Azimuth = include("azimuthlib-basic")
  4.  
  5. local window, aur_itemTypeCombo, aur_typesAllCheckBox, aur_typesCheckBoxes, aur_rarityCombo, aur_materialCombo, aur_minAmountCombo, aur_maxAmountCombo, aur_separateAutoCheckBox, aur_separateAutoLabel, aur_autoBtn, aur_typeScrollFrame, aur_turretDPS, aur_turretDPSLabel, aur_mixTypesCheckBox, aur_mixTypesLabel -- client UI
  6. local aur_systemNames, aur_systemPathByName, aur_systemAmounts, aur_turretNames, aur_turretTypeByName, aur_turretAmounts, aur_typesCheckBoxesCache, aur_type, aur_inProcess -- client
  7. local aur_onShowWindow, aur_onClickResearch -- client extended functions
  8. local aur_initialize -- client/server extended functions
  9. local aur_config, aur_log, aur_playerLocks -- server
  10.  
  11.  
  12. if onClient() then
  13.  
  14. local researchButton
  15.  
  16. aur_initialize = ResearchStation.initialize
  17. function ResearchStation.initialize(...)
  18.     aur_initialize(...)
  19.    
  20.     invokeServerFunction("aur_sendSettings")
  21. end
  22.  
  23. function ResearchStation.initUI() -- overridden
  24.     local res = getResolution()
  25.     local size = vec2(1020, 600)
  26.  
  27.     local menu = ScriptUI()
  28.     window = menu:createWindow(Rect(res * 0.5 - size * 0.5, res * 0.5 + size * 0.5))
  29.  
  30.     window.caption = "Research /* station title */"%_t
  31.     window.showCloseButton = 1
  32.     window.moveable = 1
  33.     menu:registerWindow(window, "Research"%_t);
  34.  
  35.     local vPartitions = UIVerticalProportionalSplitter(Rect(window.size), 10, 10, {0.5, 290})
  36.  
  37.     local hsplit = UIHorizontalSplitter(vPartitions[1], 10, 0, 0.4)
  38.  
  39.     inventory = window:createInventorySelection(hsplit.bottom, 11)
  40.  
  41.     local vsplit = UIVerticalSplitter(hsplit.top, 10, 10, 0.35)
  42.  
  43.     local hsplitleft = UIHorizontalSplitter(vsplit.left, 10, 10, 0.5)
  44.  
  45.     hsplitleft.padding = 6
  46.     local rect = hsplitleft.top
  47.     rect.width = 220
  48.     required = window:createSelection(rect, 3)
  49.  
  50.     local rect = hsplitleft.bottom
  51.     rect.width = 150
  52.     optional = window:createSelection(rect, 2)
  53.  
  54.     for _, sel in pairs({required, optional}) do
  55.         sel.dropIntoEnabled = 1
  56.         sel.entriesSelectable = 0
  57.         sel.onReceivedFunction = "onRequiredReceived"
  58.         sel.onDroppedFunction = "onRequiredDropped"
  59.         sel.onClickedFunction = "onRequiredClicked"
  60.     end
  61.  
  62.     inventory.dragFromEnabled = 1
  63.     inventory.onClickedFunction = "onInventoryClicked"
  64.  
  65.     vsplit.padding = 30
  66.     local rect = vsplit.right
  67.     rect.width = 70
  68.     rect.height = 70
  69.     rect.position = rect.position - vec2(180, 0)
  70.     results = window:createSelection(rect, 1)
  71.     results.entriesSelectable = 0
  72.     results.dropIntoEnabled = 0
  73.     results.dragFromEnabled = 0
  74.  
  75.     vsplit.padding = 10
  76.     local organizer = UIOrganizer(vsplit.right)
  77.     organizer.marginBottom = 5
  78.  
  79.     button = window:createButton(Rect(vec2(200, 30)), "Research"%_t, "onClickResearch")
  80.     button.maxTextSize = 15
  81.     organizer:placeElementBottomLeft(button)
  82.     button.position = button.position + vec2(-30, 20)
  83.     researchButton = button
  84.    
  85.     local hsplit = UIHorizontalSplitter(Rect(vsplit.right.lower.x, vsplit.right.lower.y - 15, vsplit.right.upper.x + 15, vsplit.right.upper.y), 5, 5, 0.5)
  86.     aur_itemTypeCombo = window:createComboBox(Rect(vec2(145, 25)), "aur_onItemTypeSelect")
  87.     hsplit:placeElementTopRight(aur_itemTypeCombo)
  88.     aur_itemTypeCombo:addEntry("System"%_t)
  89.     aur_itemTypeCombo:addEntry("Turret"%_t)
  90.  
  91.     local rect = vPartitions[2]
  92.     aur_typeScrollFrame = window:createScrollFrame(rect)
  93.     aur_typeScrollFrame.scrollSpeed = 40
  94.    
  95.     aur_rarityCombo = window:createComboBox(Rect(vec2(145, 25)), "aur_onItemRaritySelect")
  96.     aur_rarityCombo.position = aur_itemTypeCombo.position + vec2(-155, 0)
  97.     aur_rarityCombo:addEntry("Common"%_t)
  98.     aur_rarityCombo:addEntry("Uncommon"%_t)
  99.     aur_rarityCombo:addEntry("Rare"%_t)
  100.     aur_rarityCombo:addEntry("Exceptional"%_t)
  101.     aur_rarityCombo:addEntry("Exotic"%_t)
  102.     aur_rarityCombo.tooltip = "up to"%_t .. " " .. "Common"%_t
  103.    
  104.     aur_materialCombo = window:createComboBox(Rect(vec2(115, 25)), "aur_onItemMaterialSelect")
  105.     aur_materialCombo.position = aur_rarityCombo.position - vec2(125, 0)
  106.     aur_materialCombo:addEntry("All"%_t)
  107.     for i = 1, NumMaterials() do
  108.         aur_materialCombo:addEntry(Material(i-1).name)
  109.     end
  110.     aur_materialCombo.visible = false
  111.    
  112.     aur_maxAmountCombo = window:createComboBox(Rect(vec2(50, 25)), "aur_onMaxAmountSelect")
  113.     hsplit:placeElementTopRight(aur_maxAmountCombo)
  114.     aur_maxAmountCombo.position = aur_maxAmountCombo.position + vec2(0, 35)
  115.     aur_maxAmountCombo:addEntry(5)
  116.     aur_maxAmountCombo:addEntry(4)
  117.     aur_maxAmountCombo:addEntry(3)
  118.    
  119.     aur_minAmountCombo = window:createComboBox(Rect(vec2(50, 25)), "aur_onMinAmountSelect")
  120.     hsplit:placeElementTopRight(aur_minAmountCombo)
  121.     aur_minAmountCombo.position = aur_minAmountCombo.position + vec2(-60, 35)
  122.     aur_minAmountCombo:addEntry(5)
  123.     aur_minAmountCombo:addEntry(4)
  124.     aur_minAmountCombo:addEntry(3)
  125.    
  126.     local label = window:createLabel(Rect(vec2(150, 25)), "Min & max amount"%_t, 13)
  127.     hsplit:placeElementTopRight(label)
  128.     label.position = label.position + vec2(-120, 35)
  129.     label:setRightAligned()
  130.    
  131.     aur_mixTypesCheckBox = window:createCheckBox(Rect(vec2(340, 20)), "", "")
  132.     hsplit:placeElementTopRight(aur_mixTypesCheckBox)
  133.     aur_mixTypesCheckBox.position = aur_mixTypesCheckBox.position + vec2(0, 70)
  134.    
  135.     aur_mixTypesLabel = window:createLabel(Rect(vec2(320, 20)), "Research selected types together"%_t, 12)
  136.     aur_mixTypesLabel.position = aur_mixTypesCheckBox.position - vec2(10, 0)
  137.     aur_mixTypesLabel:setRightAligned()
  138.     aur_mixTypesLabel.tooltip = "After researching items of the same type, different types will be mixed and researched"%_t
  139.    
  140.     aur_turretDPS = window:createTextBox(Rect(vec2(80, 25)), "")
  141.     hsplit:placeElementTopRight(aur_turretDPS)
  142.     aur_turretDPS.position = aur_turretDPS.position + vec2(0, 100)
  143.     aur_turretDPS.allowedCharacters = "0123456789"
  144.     aur_turretDPS.tooltip = "0/empty = no restrictions"%_t
  145.    
  146.     aur_turretDPSLabel = window:createLabel(Rect(vec2(150, 25)), "Max turret DPS"%_t, 13)
  147.     hsplit:placeElementTopRight(aur_turretDPSLabel)
  148.     aur_turretDPSLabel.position = aur_turretDPSLabel.position + vec2(-90, 100)
  149.     aur_turretDPSLabel:setRightAligned()
  150.    
  151.     aur_separateAutoCheckBox = window:createCheckBox(Rect(vec2(340, 20)), "", "")
  152.     aur_separateAutoCheckBox.checked = true
  153.     hsplit:placeElementTopRight(aur_separateAutoCheckBox)
  154.     aur_separateAutoCheckBox.position = aur_separateAutoCheckBox.position + vec2(0, 135)
  155.     aur_separateAutoCheckBox.visible = false
  156.    
  157.     aur_separateAutoLabel = window:createLabel(Rect(vec2(320, 20)), "Research Auto/Non-auto turrets separately"%_t, 12)
  158.     aur_separateAutoLabel.position = aur_separateAutoCheckBox.position - vec2(10, 0)
  159.     aur_separateAutoLabel:setRightAligned()
  160.     aur_separateAutoLabel.visible = false
  161.    
  162.     if GameVersion() >= Version("2.0") then
  163.         aur_separateAutoCheckBox.active = false
  164.         aur_separateAutoLabel.active = false
  165.         aur_separateAutoCheckBox.tooltip = "No longer used in 2.0+"%_t
  166.         aur_separateAutoLabel.tooltip = "No longer used in 2.0+"%_t
  167.     end
  168.    
  169.     aur_autoBtn = window:createButton(Rect(vec2(200, 30)), "Auto Research"%_t, "aur_onClickAutoResearch")
  170.     aur_autoBtn.maxTextSize = 15
  171.     hsplit:placeElementBottomRight(aur_autoBtn)
  172.     aur_autoBtn.position = aur_autoBtn.position + vec2(0, 20)
  173.    
  174.     ResearchStation.aur_initTypesUI()
  175. end
  176.  
  177. -- fix
  178. aur_refreshButton = ResearchStation.refreshButton
  179. function ResearchStation.refreshButton()
  180.     local requiredItems = required:getItems()
  181.     researchButton.active = (tablelength(requiredItems) == 3)
  182.  
  183.     if tablelength(requiredItems) ~= 3 then
  184.         researchButton.tooltip = "Place at least 3 items for research!"%_t
  185.     else
  186.         researchButton.tooltip = "Feed to Research AI"%_t
  187.     end
  188.  
  189.     for _, items in pairs({requiredItems, optional:getItems()}) do
  190.         for _, item in pairs(items) do
  191.             if item.item
  192.                 and item.item.itemType ~= InventoryItemType.TurretTemplate
  193.                 and item.item.itemType ~= InventoryItemType.SystemUpgrade
  194.                 and item.item.itemType ~= InventoryItemType.Turret then
  195.  
  196.                 researchButton.active = false
  197.                 researchButton.tooltip = "Invalid items in ingredients."%_t
  198.             end
  199.         end
  200.     end
  201.  
  202. end
  203. -- end fix
  204.  
  205. -- TODO CHECK: If player loads sector while being IN research station, initUI will start sooner than server data with custom names, no?
  206.  
  207. aur_onShowWindow = ResearchStation.onShowWindow
  208. function ResearchStation.onShowWindow()
  209.     aur_onShowWindow()
  210.    
  211.     ResearchStation.aur_updateAmounts()
  212. end
  213.  
  214. -- CALLBACKS
  215.  
  216. aur_onClickResearch = ResearchStation.onClickResearch
  217. function ResearchStation.onClickResearch(...)
  218.     if aur_inProcess then return end
  219.  
  220.     aur_onClickResearch(...)
  221. end
  222.  
  223. function ResearchStation.aur_onItemTypeSelect()    
  224.     if aur_type == aur_itemTypeCombo.selectedIndex then return end
  225.     aur_type = aur_itemTypeCombo.selectedIndex
  226.  
  227.     ResearchStation.aur_fillTypes()
  228.  
  229.     if aur_type == 0 then -- Systems
  230.         aur_materialCombo.visible = false
  231.         aur_turretDPS.visible = false
  232.         aur_turretDPSLabel.visible = false
  233.         aur_separateAutoCheckBox.visible = false
  234.         aur_separateAutoLabel.visible = false
  235.     else -- Turrets
  236.         aur_materialCombo.visible = true
  237.         aur_turretDPS.visible = true
  238.         aur_turretDPSLabel.visible = true
  239.         aur_separateAutoCheckBox.visible = true
  240.         aur_separateAutoLabel.visible = true
  241.     end
  242. end
  243.  
  244. function ResearchStation.aur_onMinAmountSelect()
  245.     local minAmount = tonumber(aur_minAmountCombo.selectedEntry)
  246.     local maxAmount = tonumber(aur_maxAmountCombo.selectedEntry)
  247.     if minAmount > maxAmount then
  248.         aur_maxAmountCombo.selectedIndex = aur_minAmountCombo.selectedIndex
  249.     end
  250. end
  251.  
  252. function ResearchStation.aur_onMaxAmountSelect()
  253.     local minAmount = tonumber(aur_minAmountCombo.selectedEntry)
  254.     local maxAmount = tonumber(aur_maxAmountCombo.selectedEntry)
  255.     if minAmount > maxAmount then
  256.         aur_minAmountCombo.selectedIndex = aur_maxAmountCombo.selectedIndex
  257.     end
  258. end
  259.  
  260. function ResearchStation.aur_onItemRaritySelect()
  261.     aur_rarityCombo.tooltip = "up to"%_t .. " " .. aur_rarityCombo.selectedEntry
  262. end
  263.  
  264. function ResearchStation.aur_onItemMaterialSelect()
  265.     if aur_materialCombo.selectedEntry == "All"%_t then
  266.         aur_materialCombo.tooltip = nil
  267.     else
  268.         aur_materialCombo.tooltip = "up to"%_t .. " " .. aur_materialCombo.selectedEntry
  269.     end
  270. end
  271.  
  272. function ResearchStation.aur_onClickAutoResearch()
  273.     if not aur_inProcess then
  274.         -- get system/turret indexex
  275.         local selectedTypes = {}
  276.         local hasTypes = false
  277.        
  278.         local names, typeByName
  279.         if aur_type == 0 then -- systems
  280.             names = aur_systemNames
  281.             typeByName = aur_systemPathByName
  282.         else -- turrets
  283.             names = aur_turretNames
  284.             typeByName = aur_turretTypeByName
  285.         end
  286.         for i = 1, #names do
  287.             local pair = aur_typesCheckBoxes[i]
  288.             if pair.checkBox.checked then
  289.                 selectedTypes[typeByName[pair.name]] = true
  290.                 hasTypes = true
  291.             end
  292.         end
  293.         if not hasTypes then return end -- no types selected
  294.  
  295.         local minAmount = tonumber(aur_minAmountCombo.selectedEntry) or 5
  296.         local maxAmount = tonumber(aur_maxAmountCombo.selectedEntry) or 5
  297.         local materialType = aur_materialCombo.selectedIndex - 1
  298.         local maxDPS = tonumber(aur_turretDPS.text) or 0
  299.         local separateAutoTurrets = aur_separateAutoCheckBox.checked
  300.         local mixTypes = aur_mixTypesCheckBox.checked
  301.         aur_inProcess = true
  302.         aur_autoBtn.caption = "Stop"%_t
  303.  
  304.         invokeServerFunction("aur_start", Rarity(aur_rarityCombo.selectedIndex).value, aur_type, selectedTypes, materialType, minAmount, maxAmount, separateAutoTurrets, maxDPS, mixTypes)
  305.     else -- stop auto research
  306.         invokeServerFunction("aur_stop")
  307.     end
  308. end
  309.  
  310. function ResearchStation.aur_onTypesAllChecked(checkBox)
  311.     local checked = checkBox.checked
  312.     local count = aur_type == 0 and #aur_systemNames or #aur_turretNames
  313.     for i = 1, count do
  314.         aur_typesCheckBoxes[i].checkBox:setCheckedNoCallback(checked)
  315.     end
  316. end
  317.  
  318. function ResearchStation.aur_onTypeChecked(checkBox)
  319.     if not checkBox.checked then
  320.         aur_typesAllCheckBox:setCheckedNoCallback(false)
  321.     else
  322.         local allChecked = true
  323.         local count = aur_type == 0 and #aur_systemNames or #aur_turretNames
  324.         for i = 1, count do
  325.             if not aur_typesCheckBoxes[i].checkBox.checked then
  326.                 allChecked = false
  327.                 break
  328.             end
  329.         end
  330.         aur_typesAllCheckBox:setCheckedNoCallback(allChecked)
  331.     end
  332. end
  333.  
  334. -- CALLABLE
  335.  
  336. function ResearchStation.aur_receiveSettings(serverSystems)
  337.     aur_systemNames = serverSystems
  338.     ResearchStation.aur_initTypesUI()
  339. end
  340.  
  341. function ResearchStation.aur_completed()
  342.     aur_inProcess = false
  343.     aur_autoBtn.caption = "Auto Research"%_t
  344.    
  345.     ResearchStation.aur_updateAmounts()
  346. end
  347.  
  348. -- CUSTOM
  349.  
  350. function ResearchStation.aur_initTypesUI()
  351.     if not window then -- initUI didn't happen yet
  352.         return
  353.     end
  354.     if not aur_systemNames then -- aur_receiveSettings didn't happen yet
  355.         return
  356.     end
  357.  
  358.     -- system upgrades
  359.     local integration = include("AutoResearchIntegration")
  360.    
  361.     local serverSystems = aur_systemNames
  362.     aur_systemNames = {}
  363.     aur_systemPathByName = {}
  364.     local generator = UpgradeGenerator(Seed(0))
  365.     for path in pairs(generator.scripts) do
  366.         local system = SystemUpgradeTemplate(path, Rarity(-1), Seed(0))
  367.         if system and system.script ~= "" then
  368.             if serverSystems[system.script] then
  369.                 local customName = (serverSystems[system.script].name%_t) % (serverSystems[system.script].extra or {})
  370.                 aur_systemNames[#aur_systemNames + 1] = customName
  371.                 aur_systemPathByName[customName] = system.script
  372.             elseif integration[system.script] then
  373.                 local customName = (integration[system.script].name%_t) % (integration[system.script].extra or {})
  374.                 aur_systemNames[#aur_systemNames + 1] = customName
  375.                 aur_systemPathByName[customName] = system.script
  376.             else
  377.                 aur_systemNames[#aur_systemNames + 1] = system.name
  378.                 aur_systemPathByName[system.name] = system.script
  379.             end
  380.         end
  381.     end
  382.     if isBlackMarketDLCInstalled and isBlackMarketDLCInstalled() then
  383.         local BMGenerator = include("internal/dlc/blackmarket/public/upgradegenerator")
  384.         if BMGenerator then
  385.             local list = {}
  386.             BMGenerator.addUpgrades(list)
  387.             for _, v in ipairs(list) do
  388.                 local system = SystemUpgradeTemplate(v.script, Rarity(-1), Seed(0))
  389.                 if system and system.script ~= "" then
  390.                     if serverSystems[system.script] then
  391.                         local customName = (serverSystems[system.script].name%_t) % (serverSystems[system.script].extra or {})
  392.                         aur_systemNames[#aur_systemNames + 1] = customName
  393.                         aur_systemPathByName[customName] = system.script
  394.                     elseif integration[system.script] then
  395.                         local customName = (integration[system.script].name%_t) % (integration[system.script].extra or {})
  396.                         aur_systemNames[#aur_systemNames + 1] = customName
  397.                         aur_systemPathByName[customName] = system.script
  398.                     else
  399.                         aur_systemNames[#aur_systemNames + 1] = system.name
  400.                         aur_systemPathByName[system.name] = system.script
  401.                     end
  402.                 end
  403.             end
  404.         end
  405.     end
  406.     table.sort(aur_systemNames)
  407.    
  408.     -- turrets
  409.     aur_turretNames = {}
  410.     aur_turretTypeByName = {}
  411.     for weaponType, weaponName in pairs(WeaponTypes.nameByType) do
  412.         aur_turretNames[#aur_turretNames + 1] = weaponName
  413.         aur_turretTypeByName[weaponName] = weaponType
  414.     end
  415.     table.sort(aur_turretNames)
  416.    
  417.     -- create UI
  418.     local lister = UIVerticalLister(Rect(0, 0, aur_typeScrollFrame.localRect.width, aur_typeScrollFrame.localRect.height), 10, 10)
  419.     if GameVersion() >= Version("2.0") then
  420.         lister.marginRight = 15
  421.     else
  422.         lister.marginRight = 30
  423.     end
  424.    
  425.     local rect = lister:placeCenter(vec2(lister.inner.width, 26))
  426.     aur_typesAllCheckBox = aur_typeScrollFrame:createCheckBox(Rect(rect.lower, rect.upper + vec2(0, -1)), "All"%_t, "aur_onTypesAllChecked")
  427.     aur_typesAllCheckBox.fontSize = 12
  428.     aur_typesAllCheckBox.captionLeft = false
  429.     aur_typesAllCheckBox:setCheckedNoCallback(true)
  430.    
  431.     aur_typeScrollFrame:createLine(vec2(rect.lower.x, rect.upper.y), rect.upper)
  432.    
  433.     local count = math.max(#aur_systemNames, #aur_turretNames)
  434.     aur_typesCheckBoxes = {}
  435.     aur_typesCheckBoxesCache = { systems = {}, turrets = {} }
  436.     for i = 1, count do
  437.         local rect = lister:placeCenter(vec2(lister.inner.width, 25))
  438.         local vPartitions = UIVerticalProportionalSplitter(rect, 7, 0, {0.5, 25})
  439.        
  440.         local checkBox = aur_typeScrollFrame:createCheckBox(vPartitions[1], "", "aur_onTypeChecked")
  441.         checkBox.fontSize = 12
  442.         checkBox.captionLeft = false
  443.         checkBox:setCheckedNoCallback(true)
  444.        
  445.         local amountLabel = aur_typeScrollFrame:createLabel(vPartitions[2], "0", 11)
  446.         amountLabel.color = ColorRGB(0.5, 0.5, 0.5)
  447.         amountLabel:setRightAligned()
  448.        
  449.         aur_typesCheckBoxes[i] = {checkBox = checkBox, amountLabel = amountLabel}
  450.     end
  451.    
  452.     for i = 1, #aur_systemNames do
  453.         aur_typesCheckBoxesCache.systems[i] = true
  454.     end
  455.    
  456.     ResearchStation.aur_onItemTypeSelect()
  457. end
  458.  
  459. function ResearchStation.aur_updateAmounts()
  460.     if aur_inProcess or not window or not window.visible then return end
  461.    
  462.     local amounts = {}
  463.     local items = Player():getInventory():getItems()
  464.     for _, v in pairs(items) do
  465.         if aur_type == 0 and v.item.itemType == InventoryItemType.SystemUpgrade then
  466.             if not amounts[v.item.script] then
  467.                 amounts[v.item.script] = 0
  468.             end
  469.             amounts[v.item.script] = amounts[v.item.script] + 1
  470.         elseif aur_type == 1 and (v.item.itemType == InventoryItemType.Turret or v.item.itemType == InventoryItemType.TurretTemplate) then
  471.             local weaponType = WeaponTypes.getTypeOfItem(v.item)
  472.             if weaponType then
  473.                 if not amounts[weaponType] then
  474.                     amounts[weaponType] = 0
  475.                 end
  476.                 amounts[weaponType] = amounts[weaponType] + 1
  477.             end
  478.         end
  479.     end
  480.    
  481.     local names, typeByName
  482.     if aur_type == 0 then -- systems
  483.         names = aur_systemNames
  484.         typeByName = aur_systemPathByName
  485.     else -- turrets
  486.         names = aur_turretNames
  487.         typeByName = aur_turretTypeByName
  488.     end
  489.     local amountLabelByType = {}
  490.     for name, _type in pairs(typeByName) do
  491.         for i, _name in ipairs(names) do
  492.             if name == _name then
  493.                 amountLabelByType[_type] = aur_typesCheckBoxes[i].amountLabel
  494.                 break
  495.             end
  496.         end
  497.     end
  498.    
  499.     for _type, amount in pairs(amounts) do
  500.         if amountLabelByType[_type] then
  501.             amountLabelByType[_type].caption = amount
  502.             amountLabelByType[_type] = false
  503.         end
  504.     end
  505.     for _, label in pairs(amountLabelByType) do
  506.         if label then
  507.             label.caption = "0"
  508.         end
  509.     end
  510. end
  511.  
  512. function ResearchStation.aur_fillTypes()
  513.     local allChecked = true
  514.     local oldNames, newNames, oldCache, newCache
  515.     if aur_type == 0 then -- turrets -> systems
  516.         oldNames = aur_turretNames
  517.         newNames = aur_systemNames
  518.         oldCache = "turrets"
  519.         newCache = "systems"
  520.     else -- systems -> turrets
  521.         oldNames = aur_systemNames
  522.         newNames = aur_turretNames
  523.         oldCache = "systems"
  524.         newCache = "turrets"
  525.     end
  526.     -- save old checkbox values
  527.     for i = 1, #oldNames do
  528.         aur_typesCheckBoxesCache[oldCache][i] = aur_typesCheckBoxes[i].checkBox.checked
  529.     end
  530.     -- restore saved checkbox values
  531.     for i = 1, #newNames do
  532.         local data = aur_typesCheckBoxes[i]
  533.         data.name = newNames[i]
  534.         data.checkBox.caption = data.name
  535.         data.checkBox.visible = true
  536.         if not aur_typesCheckBoxesCache[newCache][i] then
  537.             allChecked = false
  538.         end
  539.         data.checkBox:setCheckedNoCallback(aur_typesCheckBoxesCache[newCache][i])
  540.        
  541.         aur_typesCheckBoxes[i].amountLabel.visible = true
  542.     end
  543.     for i = #newNames + 1, #aur_typesCheckBoxes do
  544.         aur_typesCheckBoxes[i].checkBox.visible = false
  545.         aur_typesCheckBoxes[i].amountLabel.visible = false
  546.     end
  547.     aur_typesAllCheckBox:setCheckedNoCallback(allChecked)
  548.    
  549.     ResearchStation.aur_updateAmounts()
  550. end
  551.  
  552.  
  553. else -- onServer
  554.  
  555.  
  556. aur_initialize = ResearchStation.initialize
  557. function ResearchStation.initialize(...)
  558.     aur_initialize(...)
  559.    
  560.     aur_playerLocks = {} -- save player index in order to prevent from starting 2 researches at the same time
  561.    
  562.     local configOptions = {
  563.       ["_version"] = {"1.3", comment = "Config version. Don't touch."},
  564.       ["ConsoleLogLevel"] = {2, round = -1, min = 0, max = 4, comment = "0 - Disable, 1 - Errors, 2 - Warnings, 3 - Info, 4 - Debug."},
  565.       ["FileLogLevel"] = {2, round = -1, min = 0, max = 4, comment = "0 - Disable, 1 - Errors, 2 - Warnings, 3 - Info, 4 - Debug."},
  566.       ["CustomNames"] = {{},
  567.         comment = [[Here you can add custom names for systems to help better describe them.
  568. Format: { ["systemfilename"] = { ["name"] = "System Display Name MK-${mark}", ["extra"] = { mark = "X" } }}.
  569. "Extra" table holds additional name variables - just replace them all with "X ".
  570. Server adds empty names for all used systems for your convenience.]]
  571.       },
  572.       ["CustomNames.*.name"] = {"", required = 1, comment = false},
  573.       ["CustomNames.*.extra"] = {{}, optional = 1},
  574.       ["ResearchGroupVolume"] = {10, round = -1, min = 5, comment = "Make a slight delay after specified amount of researches to prevent server from hanging."},
  575.       ["DelayInterval"] = {1, min = 0.05, comment = "Delay interval in seconds between research batches."}
  576.     }
  577.     local isModified
  578.     aur_config, isModified = Azimuth.loadConfig("AutoResearch", configOptions)
  579.     -- upgrade config
  580.     if aur_config._version == "1.1" then
  581.         aur_config._version = "1.2"
  582.         isModified = true
  583.         aur_config.ResearchGroupVolume = 10
  584.         aur_config.DelayInterval = 1
  585.     end
  586.     if aur_config._version == "1.2" then
  587.         aur_config._version = "1.3"
  588.         aur_config.CustomSystems = nil
  589.     end
  590.    
  591.     -- add all systems to config with empty names so server admins would have easier time changing names
  592.     local systems = {}
  593.     -- vanilla
  594.     local generator = UpgradeGenerator()
  595.     for path in pairs(generator.scripts) do
  596.         local system = SystemUpgradeTemplate(path, Rarity(-1), Seed(0))
  597.         if system and system.script ~= "" then
  598.             if not aur_config.CustomNames[system.script] then
  599.                 aur_config.CustomNames[system.script] = { name = "" }
  600.                 isModified = true
  601.             end
  602.         end
  603.     end
  604.     -- DLC
  605.     if GameVersion() >= Version("1.3.4") then
  606.         local BMGenerator = include("internal/dlc/blackmarket/public/upgradegenerator")
  607.         if BMGenerator then
  608.             local list = {}
  609.             BMGenerator.addUpgrades(list)
  610.             for _, v in ipairs(list) do
  611.                 local system = SystemUpgradeTemplate(v.script, Rarity(-1), Seed(0))
  612.                 if system and system.script ~= "" then
  613.                     if not aur_config.CustomNames[system.script] then
  614.                         aur_config.CustomNames[system.script] = { name = "" }
  615.                         isModified = true
  616.                     end
  617.                 end
  618.             end
  619.         end
  620.     end
  621.    
  622.     if isModified then
  623.         Azimuth.saveConfig("AutoResearch", aur_config, configOptions)
  624.     end
  625.     aur_log = Azimuth.logs("AutoResearch", aur_config.ConsoleLogLevel, aur_config.FileLogLevel)
  626. end
  627.  
  628. if not ResearchStation.updateServer then -- fixing deferredCallback
  629.     function ResearchStation.updateServer() end
  630. end
  631.  
  632. -- CALLABLE
  633.  
  634. function ResearchStation.aur_sendSettings()
  635.     local r = {}
  636.     for path, data in pairs(aur_config.CustomNames) do
  637.         if data.name ~= "" then
  638.             r[path] = data
  639.         end
  640.     end
  641.     invokeClientFunction(Player(callingPlayer), "aur_receiveSettings", r)
  642. end
  643. callable(ResearchStation, "aur_sendSettings")
  644.  
  645. function ResearchStation.aur_start(maxRarity, itemType, selectedTypes, materialType, minAmount, maxAmount, separateAutoTurrets, maxTurretDPS, mixTypes)
  646.     maxRarity = tonumber(maxRarity)
  647.     itemType = tonumber(itemType)
  648.     materialType = tonumber(materialType)
  649.     maxTurretDPS = tonumber(maxTurretDPS)
  650.     if anynils(maxRarity, itemType, selectedTypes, materialType, maxTurretDPS) then return end
  651.     minAmount = tonumber(minAmount) or 5
  652.     maxAmount = tonumber(maxAmount) or 5
  653.     minAmount = math.min(minAmount, maxAmount)
  654.     maxAmount = math.max(minAmount, maxAmount)
  655.     maxTurretDPS = math.max(0, maxTurretDPS)
  656.     mixTypes = not not mixTypes
  657.  
  658.     local buyer, ship, player = getInteractingFaction(callingPlayer, AlliancePrivilege.SpendResources)
  659.     if not player then return end
  660.     if not buyer then
  661.         invokeClientFunction(player, "aur_completed")
  662.         return
  663.     end
  664.  
  665.     if aur_playerLocks[callingPlayer] then -- auto research is already going
  666.         invokeClientFunction(player, "aur_completed")
  667.         return
  668.     end
  669.     aur_playerLocks[callingPlayer] = 1
  670.  
  671.     if materialType == -1 then
  672.         materialType = nil
  673.     end
  674.    
  675.     if GameVersion() >= Version("2.0") then
  676.         separateAutoTurrets = false
  677.     else
  678.         separateAutoTurrets = not not separateAutoTurrets
  679.     end
  680.  
  681.     --local inventory = buyer:getInventory() -- get just once
  682.     aur_log:Debug("Player %i - Research started", callingPlayer)
  683.     local result = deferredCallback(0, "aur_deferred", callingPlayer, buyer.index, buyer.isAlliance, separateAutoTurrets, maxRarity, minAmount, maxAmount, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, {{},{}})
  684.     if not result then
  685.         aur_log:Error("Player %i - Failed to defer research", callingPlayer)
  686.         aur_playerLocks[callingPlayer] = nil
  687.         invokeClientFunction(player, "aur_completed")
  688.     end
  689. end
  690. callable(ResearchStation, "aur_start")
  691.  
  692. function ResearchStation.aur_stop()
  693.     aur_playerLocks[callingPlayer] = 2 -- ask to stop
  694. end
  695. callable(ResearchStation, "aur_stop")
  696.  
  697. -- CUSTOM
  698.  
  699. function ResearchStation.aur_deferred(playerIndex, buyerId, bAlliance, separateAutoTurrets, maxRarity, minAmount, maxAmount, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, skipRarities)
  700.     aur_log:Debug("Player %i - Another iteration: separate %s, min %i, max %i, itemtype %i, system %s, material %s, maxTurretDPS %i, mixTypes %s, skipRarities %s", playerIndex, separateAutoTurrets, minAmount, maxAmount, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, skipRarities)
  701.  
  702.     if not Server():isOnline(playerIndex) then -- someone got bored and left..
  703.         aur_log:Debug("Player %i - End of research (player offline/away)", playerIndex)
  704.         aur_playerLocks[playerIndex] = nil -- unlock
  705.         return
  706.     end
  707.    
  708.     local player = Player(playerIndex)
  709.  
  710.     local buyer -- fix start
  711.     if bAlliance then
  712.     buyer = Alliance(buyerId)
  713.     else
  714.     buyer = Player(buyerId)
  715.     end
  716.     if not buyer then
  717.     aur_log:Debug("Cant instantiate buyer %i", buyerId)
  718.     return
  719.     end
  720.     local inventory = buyer:getInventory() -- fix end
  721.  
  722.     local itemIndices, itemsLength, isResearchFine, researchCode
  723.     local separateCounter = 1
  724.     if itemType == 1 and separateAutoTurrets then
  725.         separateCounter = 2
  726.     end
  727.     local timer
  728.     if aur_log.isDebug then
  729.         timer = HighResolutionTimer()
  730.         timer:start()
  731.     end
  732.     local j = 1
  733.     callingPlayer = playerIndex -- make server think that player invoked usual research
  734.     for i = 1, separateCounter do -- if itemType is turret, research independently 2 times (no auto fire and auto fire)
  735.         local separateValue = i
  736.         if not separateAutoTurrets then
  737.             separateValue = 0 -- will turn into -1
  738.         end
  739.         while true do
  740.             if j == aur_config.ResearchGroupVolume then -- we need to make a small delay to prevent script from hanging
  741.                 goto aur_finish
  742.             end
  743.             if not aur_playerLocks[playerIndex] then
  744.                 break -- interrupted by player
  745.             end
  746.  
  747.             itemsLength = 0
  748.             if not skipRarities[i][RarityType.Petty] then
  749.                 itemsLength, itemIndices = ResearchStation.aur_getIndices(inventory, RarityType.Petty, minAmount, maxAmount, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, separateValue)
  750.                 if itemsLength < minAmount then
  751.                     skipRarities[i][RarityType.Petty] = true -- skip this rarity in the future
  752.                 end
  753.             end
  754.             if itemsLength < minAmount and not skipRarities[i][RarityType.Common] then
  755.                 itemsLength, itemIndices = ResearchStation.aur_getIndices(inventory, RarityType.Common, minAmount, maxAmount, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, separateValue)
  756.                 if itemsLength < minAmount then
  757.                     skipRarities[i][RarityType.Common] = true
  758.                 end
  759.             end
  760.             if itemsLength < minAmount and maxRarity >= RarityType.Uncommon and not skipRarities[i][RarityType.Uncommon] then
  761.                 itemsLength, itemIndices = ResearchStation.aur_getIndices(inventory, RarityType.Uncommon, minAmount, maxAmount, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, separateValue)
  762.                 if itemsLength < minAmount then
  763.                     skipRarities[i][RarityType.Uncommon] = true
  764.                 end
  765.             end
  766.             if itemsLength < minAmount and maxRarity >= RarityType.Rare and not skipRarities[i][RarityType.Rare] then
  767.                 itemsLength, itemIndices = ResearchStation.aur_getIndices(inventory, RarityType.Rare, minAmount, maxAmount, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, separateValue)
  768.                 if itemsLength < minAmount then
  769.                     skipRarities[i][RarityType.Rare] = true
  770.                 end
  771.             end
  772.             if itemsLength < minAmount and maxRarity >= RarityType.Exceptional and not skipRarities[i][RarityType.Exceptional] then
  773.                 itemsLength, itemIndices = ResearchStation.aur_getIndices(inventory, RarityType.Exceptional, minAmount, maxAmount, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, separateValue)
  774.                 if itemsLength < minAmount then
  775.                     skipRarities[i][RarityType.Exceptional] = true
  776.                 end
  777.             end
  778.             if itemsLength < minAmount and maxRarity >= RarityType.Exotic and not skipRarities[i][RarityType.Exotic] then
  779.                 itemsLength, itemIndices = ResearchStation.aur_getIndices(inventory, RarityType.Exotic, minAmount, maxAmount, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, separateValue)
  780.                 if itemsLength < minAmount then
  781.                     skipRarities[i][RarityType.Exotic] = true
  782.                 end
  783.             end
  784.  
  785.             if itemsLength >= minAmount then
  786.                 isResearchFine, researchCode = ResearchStation.research(itemIndices) -- thanks for Research Station Lib there is no need for double checks
  787.                 if not isResearchFine then break end -- something went wrong
  788.             else
  789.                 break
  790.             end
  791.             j = j + 1
  792.         end
  793.     end
  794.     ::aur_finish::
  795.     callingPlayer = nil
  796.     if aur_log.isDebug then
  797.         timer:stop()
  798.         aur_log:Debug("Iteration took %s", timer.secondsStr)
  799.     end
  800.     local endResearch
  801.     if isResearchFine == false then -- something went wrong (didn't pass one of the checks)
  802.         aur_log:Debug("Player %i - End of research (exited with code %i)", playerIndex, researchCode)
  803.         endResearch = true
  804.     elseif itemsLength < minAmount then -- nothing more to research, end auto research
  805.         aur_log:Debug("Player %i - End of research", playerIndex)
  806.         endResearch = true
  807.     elseif aur_playerLocks[playerIndex] and aur_playerLocks[playerIndex] == 2 then -- interrupted by player
  808.         aur_log:Debug("Player %i - End of research (stopped by player)", playerIndex)
  809.         endResearch = true
  810.     end
  811.  
  812.     if not endResearch then -- continue after a delay
  813.         local result = deferredCallback(aur_config.DelayInterval, "aur_deferred", playerIndex, buyerId, bAlliance, separateAutoTurrets, maxRarity, minAmount, maxAmount, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, skipRarities)
  814.         if result then return end
  815.         aur_log:Error("Player %i - Failed to defer research", playerIndex)
  816.     end
  817.  
  818.     -- end research
  819.     aur_playerLocks[playerIndex] = nil -- unlock
  820.     invokeClientFunction(player, "aur_completed")
  821. end
  822.  
  823. function ResearchStation.aur_getIndices(inventory, rarity, minItems, maxItems, itemType, selectedTypes, materialType, maxTurretDPS, mixTypes, isAutoFire)
  824.     local grouped
  825.     if itemType == 0 then
  826.         grouped = ResearchStation.aur_getSystemsByRarity(inventory, rarity, selectedTypes, maxItems)
  827.     else
  828.         grouped = ResearchStation.aur_getTurretsByRarity(inventory, rarity, selectedTypes, maxItems, mixTypes, materialType, maxTurretDPS, isAutoFire - 1)
  829.     end
  830.    
  831.     local itemLength = 0
  832.     local itemIndices = {}
  833.     for _, group in pairs(grouped) do
  834.         local isFullGroup = #group >= minItems
  835.         if isFullGroup then
  836.             itemLength = 0
  837.             itemIndices = {}
  838.         end
  839.         if isFullGroup or mixTypes then
  840.             for i, itemInfo in ipairs(group) do
  841.                 itemLength = itemLength + 1
  842.                 itemIndices[itemInfo.index] = (itemIndices[itemInfo.index] or 0) + 1
  843.                 if itemLength == maxItems then
  844.                     goto aur_indicesFound
  845.                 end
  846.             end
  847.         end
  848.     end
  849.     ::aur_indicesFound::
  850.  
  851.     return itemLength, itemIndices
  852. end
  853.  
  854. function ResearchStation.aur_getSystemsByRarity(inventory, rarityType, selectedTypes, maxItems)
  855.     local inventoryItems = inventory:getItemsByType(InventoryItemType.SystemUpgrade)
  856.     local grouped = {}
  857.  
  858.     for i, inventoryItem in pairs(inventoryItems) do
  859.         if (inventoryItem.item.rarity.value == rarityType and not inventoryItem.item.favorite)
  860.           and selectedTypes[inventoryItem.item.script] then
  861.             local existing = grouped[inventoryItem.item.script]
  862.             if existing == nil then
  863.                 grouped[inventoryItem.item.script] = {}
  864.                 existing = grouped[inventoryItem.item.script]
  865.             end
  866.             -- Systems can stack now
  867.             local length = math.min(inventoryItem.amount, maxItems - #existing)
  868.             for j = 1, length do
  869.                 existing[#existing + 1] = { item = inventoryItem.item, index = i }
  870.             end
  871.             if #existing == maxItems then -- no need to search for more, we already have max amount of systems
  872.                 aur_log:Debug("Systems (cycle): %s", existing)
  873.                 return {existing}
  874.             end
  875.         end
  876.     end
  877.  
  878.     aur_log:Debug("Systems (end): %s", grouped)
  879.     return grouped
  880. end
  881.  
  882. function ResearchStation.aur_getTurretsByRarity(inventory, rarityType, selectedTypes, maxItems, mixTypes, materialType, maxDPS, isAutoFire)
  883.     local inventoryItems = inventory:getItemsByType(InventoryItemType.Turret)
  884.     local turretTemplates = inventory:getItemsByType(InventoryItemType.TurretTemplate)
  885.     for i, inventoryItem in pairs(turretTemplates) do
  886.         inventoryItems[i] = inventoryItem
  887.     end
  888.     local grouped = {}
  889.  
  890.     local selectedKey
  891.     for i, inventoryItem in pairs(inventoryItems) do
  892.         if (inventoryItem.item.rarity.value == rarityType and not inventoryItem.item.favorite) then
  893.             if isAutoFire == -1 or (isAutoFire == 0 and not inventoryItem.item.automatic) or (isAutoFire == 1 and inventoryItem.item.automatic) then
  894.                 local weaponType = WeaponTypes.getTypeOfItem(inventoryItem.item)
  895.                 local materialValue = inventoryItem.item.material.value
  896.                 -- if selectedTypes[weaponType] and (not materialType or materialValue <= materialType) and (maxDPS == 0 or inventoryItem.item.dps <= maxDPS) then
  897.                 if selectedTypes[weaponType] and (not materialType or materialValue <= materialType) and (maxDPS == 0 or ((inventoryItem.item.dps / inventoryItem.item.slots) <= maxDPS)) then -- MOD
  898.                     local groupKey = materialValue.."_"..weaponType
  899.                     if not selectedKey or groupKey == selectedKey then
  900.                         local existing = grouped[groupKey] -- group by material, no need to mix iron and avorion
  901.                         if existing == nil then
  902.                             grouped[groupKey] = {}
  903.                             existing = grouped[groupKey]
  904.                         end
  905.                         for j = 1, inventoryItem.amount do
  906.                             existing[#existing + 1] = { item = inventoryItem.item, index = i }
  907.                         end
  908.                         if not selectedKey and #existing >= maxItems then -- we have max amount of items of that turret type + material, just focus on these and remove others
  909.                             selectedKey = groupKey
  910.                             grouped = { [selectedKey] = existing }
  911.                         end
  912.                     end
  913.                 end
  914.             end
  915.         end
  916.     end
  917.     if selectedKey then -- got full group, sort it so low-dps weapons will be researched first
  918.         -- table.sort(grouped[selectedKey], function(a, b) return a.item.dps < b.item.dps end)
  919.         table.sort(grouped[selectedKey], function(a, b) return ((a.item.dps / a.item.slots) < (b.item.dps / b.item.slots)) end)  -- MOD
  920.         return grouped
  921.     end
  922.     if mixTypes then -- no full groups, pile all turrets into one group and sort them by dps
  923.         local combined = {}
  924.         for _, group in pairs(grouped) do
  925.             for _, itemInfo in ipairs(group) do
  926.                 combined[#combined + 1] = itemInfo
  927.             end
  928.         end
  929.         -- table.sort(combined, function(a, b) return a.item.dps < b.item.dps end)
  930.         table.sort(combined, function(a, b) return ((a.item.dps / a.item.slots) < (b.item.dps / b.item.slots)) end)  -- MOD
  931.        
  932.         return {combined}
  933.     end
  934.    
  935.     return {}
  936. end
  937.  
  938.  
  939. end
Add Comment
Please, Sign In to add comment