Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- include('keysym.h.lua')
- function widget:GetInfo()
- return {
- name = "Graphic Unit Selector Redux2",
- desc = "Selects units when a user presses a certain key.",
- author = "Shaman, mod by Helwor, NCG. Almost total rewrite ivand. Almost total rewrite esainane.",
- date = "May, 2017",
- license = "None",
- layer = 15,
- enabled = false,
- }
- end
- local Echo = Spring.Echo
- local TableEcho = Spring.Utilities.TableEcho
- local glBillboard = gl.Billboard
- local glColor = gl.Color
- local glDrawGroundCircle = gl.DrawGroundCircle
- local glLineStipple = gl.LineStipple
- local glLineWidth = gl.LineWidth
- local glPushMatrix = gl.PushMatrix
- local glPopMatrix = gl.PopMatrix
- local glText = gl.Text
- local glTranslate = gl.Translate
- local GetModKeyState = Spring.GetModKeyState
- local GetMouseState = Spring.GetMouseState
- local GetMyTeamID = Spring.GetMyTeamID
- local GetSpectatingState = Spring.GetSpectatingState
- local GetUnitDefID = Spring.GetUnitDefID
- local GetUnitPosition = Spring.GetUnitPosition
- local GetUnitsInCylinder = Spring.GetUnitsInCylinder
- local SelectUnitArray = Spring.SelectUnitArray
- local IsReplay = Spring.IsReplay
- local TraceScreenRay = Spring.TraceScreenRay
- local ValidUnitID = Spring.ValidUnitID
- ------------------------------------------------------------------------------------------------------------
- --- CONFIG
- ------------------------------------------------------------------------------------------------------------
- local useIndividualHaloColors = true
- local requireMouseCommit = false
- local orderOfClass = {
- Constructor = 1,
- Raider = 2,
- Skirmisher = 3,
- Riot = 4,
- Assault = 5,
- Artillery = 6,
- ["Weird Raider"] = 7, -- Also heavy raider
- ["Anti Air"] = 8,
- Fat = 9,
- Artificier = 10,
- Utility = 11,
- tiny = 12,
- BOOM = 13,
- Druid = 14,
- }
- local keysByClass = {
- Constructor = KEYSYMS.Z,
- Raider = KEYSYMS.Q,
- Skirmisher = KEYSYMS.F,
- Riot = KEYSYMS.R,
- Assault = KEYSYMS.T,
- Artillery = KEYSYMS.G,
- ["Weird Raider"] = KEYSYMS.E,
- ["Anti Air"] = KEYSYMS.N,
- Fat = KEYSYMS.Y,
- Artificier = KEYSYMS.H,
- Utility = KEYSYMS.X,
- tiny = KEYSYMS.C,
- BOOM = KEYSYMS.V,
- Druid = KEYSYMS.B
- }
- local classByKeys = {}
- for k, v in pairs(keysByClass) do
- classByKeys[v] = k
- end
- local colorByClass = {
- Constructor = {1,1,1},
- Raider = {0,0.83,0.85},
- Skirmisher = {0.35,0.87,0.23},
- Riot = {0.86,0.28,0.34},
- Assault = {0.25,0.41,1},
- Artillery = {0,0,1},
- -- next row
- ["Weird Raider"] = {0.27,0.79,0.88},
- ["Anti Air"] = {0.34,0.59,.9},
- Fat = {1,.23,.8},
- Artificier = {0,0,0},
- Utility = {0.75,0.41,1},
- tiny = {0,1,1},
- BOOM = {1,0,0},
- Druid = {0,1,0},
- --growth = {0.19,0.5,0.08},
- --shrink = {1,0.08,0.58},
- }
- local colorByKey = {}
- for k,v in pairs(colorByClass) do
- colorByKey[keysByClass[k]] = v
- end
- local keysAux={
- plus = KEYSYMS.KP6,
- minus = KEYSYMS.KP4,
- }
- local auxByKey = {}
- for k, v in pairs(keysAux) do
- auxByKey[v] = k
- end
- local rad = 550
- local unitTypes = {
- Constructor = {
- cloakcon = true,
- shieldcon = true,
- vehcon = true,
- hovercon = true,
- gunshipcon = true,
- planecon = true,
- spidercon = true,
- jumpcon = true,
- tankcon = true,
- amphcon = true,
- shipcon = true,
- },
- Raider = {
- cloakraid = true,
- shieldraid = true,
- hoverraid = true,
- amphraid = true,
- shiptorpraider = true,
- },
- Skirmisher = {
- cloakskirm = true,
- cloaksnipe = true,
- shieldskirm = true,
- hoverskirm = true,
- spiderskirm = true,
- jumpskirm = true,
- amphfloater = true,
- shipskirm = true,
- jumpblackhole = true,
- shieldfelon = true,
- vehcapture = true,
- },
- Riot = {
- cloakriot = true,
- shieldriot = true,
- shieldfelon = true,
- vehriot = true,
- hoverriot = true,
- hoverdepthcharge = true,
- spiderriot = true,
- tankriot = true,
- amphriot = true,
- },
- Assault = {
- cloakassault = true,
- shieldassault = true,
- vehassault = true,
- hoverassault = true,
- spiderassault = true,
- jumpassault = true,
- tankheavyraid = true,
- tankassault = true,
- shipassault = true,
- },
- Artillery = {
- cloakarty = true,
- cloaksnipe = true,
- shieldarty = true,
- veharty = true,
- gunshipskirm = true,
- gunshipheavyskirm = true,
- jumparty = true,
- shiparty = true,
- },
- ["Weird Raider"] = {
- cloakheavyraid = true,
- subraider = true,
- hoverheavyraid = true,
- spideremp = true,
- tankraid = true,
- amphimpulse = true,
- shipriot = true,
- vehraid = true,
- gunshipraid = true,
- jumpraid = true,
- },
- ["Anti Air"] = {
- cloakaa = true,
- shieldaa = true,
- vehaa = true,
- hoveraa = true,
- gunshipaa = true,
- spideraa = true,
- jumpaa = true,
- tankaa = true,
- amphaa = true,
- shipaa = true,
- },
- Fat = {
- jumpsumo = true,
- tankheavyassault = true,
- amphassault = true,
- striderbantha = true,
- striderdetriment = true,
- striderdante = true,
- striderscorpion = true,
- },
- Artificier = {
- --spidercrabe = true,
- amphsupport =true,
- hoverarty = true,
- shipheavyarty = true,
- striderarty = true,
- tankarty = true,
- },
- Utility = {
- cloakjammer = true,
- shieldshield = true,
- gunshiptrans = true,
- amphtele = true,
- vehheavyarty = true,
- --spidercrabe = true,
- vehsupport = true,
- },
- tiny = {
- spiderscout = true,
- shieldscout = true,
- gunshipemp = true,
- jumpscout = true,
- vehscout = true,
- },
- BOOM = {
- cloakbomb = true,
- shieldbomb = true,
- gunshipbomb = true,
- amphbomb = true,
- jumpbomb = true,
- },
- Druid = {
- amphlaunch = true,
- shipcarrier = true,
- subtacmissile = true,
- spiderantiheavy = true,
- tankheavyarty = true,
- spidercrabe = true,
- },
- }
- local keyByUnitDefID = {}
- for class,entries in pairs(unitTypes) do
- local key = keysByClass[class]
- for unitDefName,_ in pairs(entries) do
- local ud = UnitDefNames[unitDefName]
- if not ud then
- Echo('Could not find', unitDefName)
- end
- --Echo(ud, unitDefName, '->', key)
- keyByUnitDefID[ud.id] = key
- end
- end
- --[[
- for unitDefID,unitDef in ipairs(UnitDefs) do
- if keyByUnitDefID[unitDefID] == nil and not string.match(UnitDefs[unitDefID].name, "dyn") and not string.match(UnitDefs[unitDefID].name, "comm_") and not string.match(UnitDefs[unitDefID].name, "chicken") and not string.match(UnitDefs[unitDefID].name, "pw_") then
- Echo('Warning, no type set for', unitDef.name)
- end
- end
- --]]
- ------------------------------------------------------------------------------------------------------------
- --- END OF CONFIG
- ------------------------------------------------------------------------------------------------------------
- function widget:Initialize()
- --Unload if in replay or if mod is not Zero-K
- if IsReplay() then
- widgetHandler:RemoveWidget(widget)
- end
- end
- function widget:GameOver(winningAllyTeams)
- --GameOver is irreversable with cheats, thus removing
- widgetHandler:RemoveWidget(widget)
- end
- local myTeamID = GetMyTeamID()
- local unloaded = false
- local function CheckIfSpectator()
- if GetSpectatingState() then
- myTeamID = nil
- else
- myTeamID = GetMyTeamID()
- end
- --spectator state is reversable with cheats
- -- Lets see what its like as a spectator
- --[[if GetSpectatingState() then
- widgetHandler:RemoveCallIn("KeyPress")
- widgetHandler:RemoveCallIn("KeyRelease")
- widgetHandler:RemoveCallIn("Update")
- widgetHandler:RemoveCallIn("DrawWorld")
- unloaded = true
- else
- if unloaded then
- widgetHandler:UpdateCallIn("KeyPress")
- widgetHandler:UpdateCallIn("KeyRelease")
- widgetHandler:UpdateCallIn("Update")
- widgetHandler:UpdateCallIn("DrawWorld")
- unloaded = false
- end
- end--]]
- end
- function widget:TeamChanged(teamID)
- CheckIfSpectator()
- end
- function widget:PlayerChanged(playerID)
- CheckIfSpectator()
- end
- function widget:PlayerAdded(playerID)
- CheckIfSpectator()
- end
- function widget:PlayerRemoved(playerID)
- CheckIfSpectator()
- end
- function widget:TeamDied(teamID)
- CheckIfSpectator()
- end
- function widget:TeamChanged(teamID)
- CheckIfSpectator()
- end
- local currentSelection = {}
- function widget:SelectionChanged(selection)
- currentSelection = selection
- end
- local function CompareButtonOrder(l,r)
- return orderOfClass[l] < orderOfClass[r]
- end
- -- Key -> true | nil
- local selectingKeys = {}
- local activeSelectionKeys = 0
- local selectionStrings
- local selectionColors
- local function activeKeysChanged()
- selectionStrings = {}
- selectionColors = {}
- for k,_ in pairs(selectingKeys) do
- selectionStrings[#selectionStrings + 1] = classByKeys[k]
- selectionColors[#selectionColors+1] = colorByKey[k]
- end
- table.sort(selectionStrings, CompareButtonOrder)
- end
- local isPregame = true
- function widget:GameFrame(n)
- if n > 2 then
- isPregame = false
- widgetHandler:RemoveCallIn("GameFrame")
- end
- end
- -- {unitID} -> key | nil
- local pendingSelection = {}
- -- [unitID]
- local pendingSelectionArray = {}
- local acc = 0
- function widget:KeyPress(key, mods, isRepeat)
- if isPregame then return end -- pregame effectively has your starting unit "selected"
- if selectingKeys[key] then return end -- No dupes
- if mods.alt then return end -- we want to be able to quickly select factories with no selection
- if mods.ctrl then return end -- also many global commands
- if auxByKey[key] then
- if key == keysAux.plus then
- rad = math.min(3000, rad+100)
- end
- if key == keysAux.minus then
- rad = math.max(100, rad-100)
- end
- elseif not classByKeys[key]then
- -- Not a key we're interested in
- return
- elseif activeSelectionKeys == 0 then
- if #currentSelection ~= 0 then
- -- If we aren't already selecting types, and we already have an existing selection, do nothing - we'd more likely want these keys to issue orders to them.
- return
- end
- -- New selection! How exciting.
- acc = 0
- end
- selectingKeys[key] = true
- activeSelectionKeys = activeSelectionKeys + 1
- activeKeysChanged()
- return true
- end
- local function DoCommitSelection()
- local _, _, _, shiftKey = GetModKeyState()
- if #pendingSelectionArray then
- SelectUnitArray(pendingSelectionArray, shiftKey)
- end
- table.clear(pendingSelection)
- table.clear(pendingSelectionArray)
- end
- function widget:KeyRelease(key) -- Called whenever user stops pressing a key.
- if not selectingKeys[key] then return end -- Not a key we're using
- selectingKeys[key] = nil
- activeSelectionKeys = activeSelectionKeys - 1
- activeKeysChanged()
- if activeSelectionKeys > 0 then return true end -- Still selecting more types with other keys
- -- We've released all type selection buttons. Commit the pending selection.
- if not requireMouseCommit then
- DoCommitSelection()
- end
- return true
- end
- local mouseAdding = false
- function widget:MousePress(x,y,btn)
- if btn == 1 and activeSelectionKeys > 0 then
- -- Start adding
- mouseAdding = true
- elseif btn == 3 and mouseAdding then
- -- Cancel adding
- mouseAdding = false
- table.clear(pendingSelection)
- table.clear(pendingSelectionArray)
- else
- -- Don't interfere with dragging or other potential hotkeys
- return false
- end
- return true
- end
- function widget:MouseRelease(x,y,btn)
- if btn ~= 1 or not mouseAdding then return end
- mouseAdding = false
- DoCommitSelection()
- end
- local function GetCameraHeight()
- local cs = Spring.GetCameraState()
- local gy = Spring.GetGroundHeight(cs.px, cs.pz)
- local testHeight = cs.py - gy
- if cs.name == "ov" then
- testHeight = WG.AllUnitIcon.iconheight * 2
- elseif cs.name == "ta" then
- testHeight = cs.height - gy
- end
- return testHeight
- end
- local radAdj = 1
- local x, y, z
- local unitsPos = {}
- function widget:Update(dt)
- if not (activeSelectionKeys or (requireMouseCommit and mouseAdding)) then return end
- acc = acc + dt
- local mouseX, mouseY = GetMouseState()
- local desc, mpos = TraceScreenRay(mouseX, mouseY, true)
- radAdj = GetCameraHeight() / 6000
- -- Is the mouse over the map?
- if desc ~= nil then
- -- Save its position
- x, y, z = unpack(mpos)
- -- If we're currently holding down left mouse, or if we don't require mouse clicks to add units, add all units in the area
- if activeSelectionKeys and (mouseAdding or not requireMouseCommit) then
- for _, uID in ipairs(GetUnitsInCylinder(x, z, rad * radAdj, myTeamID)) do
- -- Make sure not to add units multiple times
- if not pendingSelection[uID] then
- local key = keyByUnitDefID[GetUnitDefID(uID)]
- -- If this is the sort of unit we're looking for, add it
- if key and selectingKeys[key] then
- pendingSelection[uID] = key
- pendingSelectionArray[#pendingSelectionArray+1] = uID
- end
- end
- end
- end
- else
- x = nil
- end
- -- We can continue to update unit halo information even when the mouse is off the world
- table.clear(unitsPos)
- for _,uID in ipairs(pendingSelectionArray) do
- if ValidUnitID(uID) then
- local pos = {GetUnitPosition(uID)}
- unitsPos[uID] = pos
- end
- end
- end
- local lineHeight = 80
- local textSize = 66
- local textX = 85
- function widget:DrawWorld() -- this is used for openGL stuff.
- if (activeSelectionKeys == 0 and not (requireMouseCommit and mouseAdding)) or not x then return end
- local color = activeSelectionKeys == 0 and {.46,.41,.41} or selectionColors[1 + ((math.floor(acc * 5)) % #selectionColors)]
- glPushMatrix() --This is the start of an openGL function.
- glLineStipple(true)
- glLineWidth(2.0)
- glTranslate(x, y, z)
- glColor(color[1], color[2], color[3], 1)
- glDrawGroundCircle(0, 0, 0, rad * radAdj, 25) -- draws a simple circle.
- glColor(1,1,1,1)
- glBillboard()
- local description = "AH"
- if mouseAdding or not requireMouseCommit then
- description = "OH"
- end
- local textY = (#selectionStrings * lineHeight * .5 + 25)
- glText(description, textX, textY, textSize, "v") -- Displays text. First value is the string, second is a modifier for x (in this case it's x-25), third is a modifier for y, fourth is the size, then last is a modifier for the text itself. "v" means vertical align.
- for i=1,#selectionStrings do
- local text = selectionStrings[i]
- color = colorByClass[text]
- glColor(color[1], color[2], color[3], 1)
- textY = textY - lineHeight
- glText(text, textX, textY, textSize, "v")
- end
- glColor(1, 1, 1, 1) -- we have to reset what we did here.
- glLineWidth(1.0)
- glLineStipple(false)
- glPopMatrix() -- end of function. Have to use this with after a push!
- glPushMatrix()
- glLineWidth(3.0)
- for uID, key in pairs(pendingSelection) do
- local pos = unitsPos[uID]
- if pos ~= nil then
- if useIndividualHaloColors then
- color = colorByKey[key]
- end
- glColor(color[1], color[2], color[3], 0.4)
- local px,py,pz = unpack(pos)
- glDrawGroundCircle(px, py, pz, 60, 60)
- end
- end
- glColor(1, 1, 1, 1)
- glPopMatrix()
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement