Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 151 additions & 13 deletions luaui/Widgets/cmd_area_mex.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ local spGetActiveCommand = Spring.GetActiveCommand
local spGetUnitCommands = Spring.GetUnitCommands
local spGetMapDrawMode = Spring.GetMapDrawMode
local spGetUnitPosition = Spring.GetUnitPosition
local spGetSelectedUnits = Spring.GetSelectedUnits
local spSendCommands = Spring.SendCommands
local taremove = table.remove

Expand All @@ -30,6 +31,8 @@ local mexBuildings
local metalSpots

local metalMap = false
local controllerAreaMexWarnings = {}
local IssueAreaMex


local function setAreaMexType(uDefID)
Expand All @@ -46,6 +49,19 @@ function widget:Initialize()
WG['areamex'].setAreaMexType = function(uDefID)
setAreaMexType(uDefID)
end

WG.controllerAreaMex = WG.controllerAreaMex or {}
WG.controllerAreaMex.issueArea = function(x, y, z, radius, opts)
local areaParams
local areaOptions = opts
if type(x) == "table" then
areaParams = x
areaOptions = y
else
areaParams = { x, y, z, radius }
end
return IssueAreaMex(areaParams, areaOptions, "controller")
end
end


Expand Down Expand Up @@ -92,7 +108,7 @@ local function getAvgPositionOfValidBuilders(units, constructorIds, buildingId,
x, _, z = spGetUnitPosition(id)
end
if z then
tX, tZ = tX + x, tZ + z
tX, tZ = tX+x, tZ+z
builderCount = builderCount + 1
end
end
Expand All @@ -104,14 +120,13 @@ local function getAvgPositionOfValidBuilders(units, constructorIds, buildingId,
return { x = tX / builderCount, z = tZ / builderCount }
end


---Get all mex spots in an area
---@param x number
---@param z number
---@param radius number
---@return table Array of spots within the specified area
local function getSpotsInArea(x, z, radius)
local validSpots = {}

for i = 1, #metalSpots do
local spot = metalSpots[i]
local dist = math.distance2dSquared(x, z, spot.x, spot.z)
Expand Down Expand Up @@ -174,36 +189,152 @@ local function calculateCmdOrder(cmds, spots, shift)
end


function widget:CommandNotify(id, params, options)
if id ~= CMD_AREA_MEX then
local function getAreaParam(params, key, index)
if params[key] ~= nil then
return params[key]
end
return params[index]
end


local function isFiniteNumber(value)
return type(value) == "number" and value == value and value ~= math.huge and value ~= -math.huge
end


local function warnControllerAreaMex(reason)
if controllerAreaMexWarnings[reason] then
return
end
controllerAreaMexWarnings[reason] = true
Spring.Echo("[AreaMex] Controller Area Mex ignored: " .. reason)
end

local cmdX, _, cmdZ, cmdRadius = params[1], params[2], params[3], params[4]
local spots = getSpotsInArea(cmdX, cmdZ, cmdRadius)
if WG['skip_allied_upgrade'] then
spots = WG['skip_allied_upgrade'].filterOutAlliedSpots(spots, mexBuildings)

local function validateAreaParams(areaParams, source)
if type(areaParams) ~= "table" then
if source == "controller" then
warnControllerAreaMex("missing area params")
end
return nil, "missing area params"
end

local cmdX = getAreaParam(areaParams, "x", 1)
local cmdY = getAreaParam(areaParams, "y", 2)
local cmdZ = getAreaParam(areaParams, "z", 3)
local cmdRadius = getAreaParam(areaParams, "radius", 4)

if not isFiniteNumber(cmdX) or not isFiniteNumber(cmdZ) or (cmdY ~= nil and not isFiniteNumber(cmdY)) then
if source == "controller" then
warnControllerAreaMex("invalid area position")
end
return nil, "invalid area position"
end

if not isFiniteNumber(cmdRadius) or cmdRadius <= 0 then
if source == "controller" then
warnControllerAreaMex("invalid area radius")
end
return nil, "invalid area radius"
end

return cmdX, cmdY, cmdZ, cmdRadius
end


local function getOptionShift(options)
if type(options) ~= "table" then
return false, false
end
if options.shift ~= nil then
return options.shift == true, true
end
for i = 1, #options do
if options[i] == "shift" then
return true, true
end
end
return false, false
end


IssueAreaMex = function(areaParams, areaOptions, source)
local cmdX, cmdY, cmdZ, cmdRadius = validateAreaParams(areaParams, source)
if not cmdX then
return false, cmdY
end

if type(metalSpots) ~= "table" then
return false, "metal spots unavailable"
end

local resourceSpotBuilder = WG['resource_spot_builder']
if type(resourceSpotBuilder) ~= "table"
or type(resourceSpotBuilder.GetBestExtractorFromBuilders) ~= "function"
or type(resourceSpotBuilder.PreviewExtractorCommand) ~= "function"
or type(resourceSpotBuilder.SpotHasExtractorQueued) ~= "function"
or type(resourceSpotBuilder.ApplyPreviewCmds) ~= "function"
then
return false, "resource spot builder unavailable"
end
if type(mexConstructors) ~= "table" or type(mexBuildings) ~= "table" then
return false, "mex builder data unavailable"
end

if type(selectedUnits) ~= "table" and type(spGetSelectedUnits) == "function" then
selectedUnits = spGetSelectedUnits()
end
if type(selectedUnits) ~= "table" or #selectedUnits <= 0 then
return false, "no selected units"
end

local spots = getSpotsInArea(cmdX, cmdZ, cmdRadius)

if not selectedMex then
selectedMex = resourceSpotBuilder.GetBestExtractorFromBuilders(selectedUnits, mexConstructors, mexBuildings)
end
if not selectedMex then
selectedMex = WG['resource_spot_builder'].GetBestExtractorFromBuilders(selectedUnits, mexConstructors, mexBuildings)
return false, "no mex builder selected"
end

local alt, ctrl, meta, shift = Spring.GetModKeyState()
local optionShift, hasOptionShift = getOptionShift(areaOptions)
local _, _, _, shift = Spring.GetModKeyState()
if source == "controller" then
shift = hasOptionShift and optionShift or false
end
local cmds = getCmdsForValidSpots(spots, shift)
local sortedCmds = calculateCmdOrder(cmds, spots, shift)

WG['resource_spot_builder'].ApplyPreviewCmds(sortedCmds, mexConstructors, shift)
local ok, err = pcall(resourceSpotBuilder.ApplyPreviewCmds, sortedCmds, mexConstructors, shift)

selectedMex = nil

if not options.shift then
if not ok then
if source == "controller" then
warnControllerAreaMex("failed to issue mex build orders")
end
return false, tostring(err)
end

if source ~= "controller" and not hasOptionShift then
optionShift = shift
end
if not optionShift then
if WG["gridmenu"] then WG["gridmenu"].clearCategory() end
end
return true
end


function widget:CommandNotify(id, params, options)
if id ~= CMD_AREA_MEX then
return
end

return IssueAreaMex(params, options, "mouse")
end


-- Adjust map view mode as needed
function widget:Update(dt)
local _, cmd, _ = spGetActiveCommand()
Expand All @@ -228,6 +359,13 @@ function widget:Update(dt)
end


function widget:Shutdown()
if WG.controllerAreaMex then
WG.controllerAreaMex.issueArea = nil
end
end


function widget:SelectionChanged(sel)
selectedUnits = sel
end
Expand Down