Some of the more recent maps don't come with metal spot textures. Players have to use the F4 view to see where they are, which is annoying.
I'd like to have a gadget which adds appropriate metal spot textures for a TA-like game on a specific set of maps. Any examples?
game adding metal spot textures on map if missing
Moderator: Moderators
- Silentwings
- Posts: 3720
- Joined: 25 Oct 2008, 00:23
Re: game adding metal spot textures on map if missing
Will need a little adaptation, but http://imolarpg.dyndns.org/trac/balates ... _spots.lua and http://imolarpg.dyndns.org/trac/balates ... _metal.lua
- Forboding Angel
- Evolution RTS Developer
- Posts: 14673
- Joined: 17 Nov 2005, 02:43
Re: game adding metal spot textures on map if missing
A better option would be to draw it with GL on the map itself instead of using textures for it.
Like this:

Like this:

Re: game adding metal spot textures on map if missing
Code: Select all
--------------------------------------------------------------------------------
--
-- file: ..
-- brief: Lua metal spots for *A mods. Credits to Niobium for metal finder. Place a .lmf file in map archive to enable support.
--
-- usage:
-- Step 1. Create a [mapname].lmf file in [mapname].sd7/maps/. The first line should be a relative path inside the spring directory in which to search for metal textures in.
-- The last three lines indicate rgb tint in the range of 0.0 to 1.0, and must be present.
-- Example .lmf file:
--
-- line 1: ./maps/textures/
-- line 2: 1.0
-- line 3: 1.0
-- line 4: 1.0
--
-- Step 2. Create a /textures/ folder in the archive and place metal spot textures there. In the example above they should be named "metal_high.png", "metal_medhigh.png", "metal_med.png", "metal_low.png".
--
--
-- Changelog:
-- v3.4
-- * set to use proper rendering function so it doesn't render over effects.
-- v3.3
-- * fixed issues with archive loading
-- v3.2
-- * fixed drawing on sloped terrain
-- * randomness and multiple textures is broken
--
-- v3.1
-- * fixed depth testing issue
--
-- v3
-- * changed to Niobium metal finder with mass metal detection.
--
-- v2
-- * added display lists
-- * added loading metal maps from file
--
--
-- author: Jahziah Wagner
--
-- Copyright (C) 2010.
-- Licensed under the terms of the LGPL
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function widget:GetInfo()
return {
name = "Metal Placer V3.3 Integrated Version for Seths Ravine",
desc = "Lua metal spots for maps that support them.",
author = "Halcyon",
date = "15/12/2010",
license = "LGPL v2",
layer = 5,
enabled = true -- loaded by default?
}
end
local enabled = true -- Spring.GetMapOptions("patches",true)
local floor = math.floor
local gridSize = 4
local mapWidth2 = floor(Game.mapSizeX / gridSize)
local mapHeight2 = floor(Game.mapSizeZ / gridSize)
local metalMap = {}
local spGetGroundInfo = Spring.GetGroundInfo
local threshFraction = 0.4
local metalDataCount = 0
local maxMetalData = 2500000
local maxMetal = 0
local mSpots = {}
local mexRad = Game.extractorRadius > 125 and Game.extractorRadius or 125
local metalSpotWidth = 64
local metalSpotHeight = 64
local randTexture = {}
local rgbr = 0
local rgbg = 0
local rgbb = 0
local searchPath = 0
local pathToSave = "LuaUI/Widgets/MetalMaps/" -- where to store mexmaps
local dl = 0
------------------------------------------------------------
-- Config
------------------------------------------------------------
local gridSize = 16 -- Resolution of metal map
local buildGridSize = 8 -- Resolution of build positions
------------------------------------------------------------
-- Speedups
------------------------------------------------------------
local min, max = math.min, math.max
local floor, ceil = math.floor, math.ceil
local sqrt = math.sqrt
local huge = math.huge
local spGetGroundInfo = Spring.GetGroundInfo
local spGetGroundHeight = Spring.GetGroundHeight
local spTestBuildOrder = Spring.TestBuildOrder
local extractorRadius = Game.extractorRadius
local extractorRadiusSqr = extractorRadius * extractorRadius
local buildmapSizeX = Game.mapSizeX - buildGridSize
local buildmapSizeZ = Game.mapSizeZ - buildGridSize
local buildmapStartX = buildGridSize
local buildmapStartZ = buildGridSize
local metalmapSizeX = Game.mapSizeX - 1.5 * gridSize
local metalmapSizeZ = Game.mapSizeZ - 1.5 * gridSize
local metalmapStartX = 1.5 * gridSize
local metalmapStartZ = 1.5 * gridSize
local mSpots = {}
-- saving metalmap
local function SaveMetalMap(filename)
mSpots = GetSpots()
if #mSpots == 0 then
widgetHandler:RemoveWidget()
return
end
--Spring.Echo("exporting mexmap to ".. filename);
local file = assert(io.open(filename,'w'), "Unable to save mexmap to "..filename)
for k, mex in pairs(mSpots) do
--file:write(k)
--file:write("\n")
file:write(mex.x)
file:write("\n")
file:write(mex.z)
file:write("\n")
--file:write(mex.weight)
--file:write("\n")
--if (Distance(cx,cz,mex.x,mex.z) < cr^2) then -- circle area, slower
--commands[#commands+1] = {x = mex.x, z = mex.z, d = Distance(aveX,aveZ,mex.x,mex.z)}
end
file:close()
Spring.Echo("mexmap exported to ".. filename);
end
local function LoadMetalMap(filename)
--Spring.Echo("importing mexmap from ".. filename);
local file = assert(io.open(filename,'r'), "Unable to load mexmap from "..filename)
index = 1
while true do
l1 = file:read()
if not l1 then break end
l2 = file:read()
--l3 = file:read()
--l4 = file:read()
mSpots[index] = {
x = l1,
z = l2--,
--weight = tonumber(l3)
}
index = index+1
end
Spring.Echo("mexmap imported from ".. filename);
end
------------------------------------------------------------------------------------------------------------------------------------
----------------------------------- NEW METAL FINDER ROUTINE, CREDIT GOES TO NIOBIUM ----------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------
function GetSpots()
-- Main group collection
local uniqueGroups = {}
-- Strip info
local nStrips = 0
local stripLeft = {}
local stripRight = {}
local stripGroup = {}
-- Indexes
local aboveIdx
local workingIdx
-- temp
local stripWorths = {}
local stripIndex = 0
-- Strip processing function (To avoid some code duplication)
local function DoStrip(x1, x2, z, worth)
local assignedTo
for i = aboveIdx, workingIdx - 1 do
if stripLeft[i] > x2 + gridSize then
break
elseif stripRight[i] + gridSize >= x1 then
local matchGroup = stripGroup[i]
if assignedTo then
if matchGroup ~= assignedTo then
for iz = matchGroup.minZ, assignedTo.minZ - gridSize, gridSize do
assignedTo.left[iz] = matchGroup.left[iz]
end
for iz = matchGroup.minZ, matchGroup.maxZ, gridSize do
assignedTo.right[iz] = matchGroup.right[iz]
end
if matchGroup.minZ < assignedTo.minZ then
assignedTo.minZ = matchGroup.minZ
end
assignedTo.maxZ = z
assignedTo.worth = assignedTo.worth + matchGroup.worth
uniqueGroups[matchGroup] = nil
end
else
assignedTo = matchGroup
assignedTo.left[z] = assignedTo.left[z] or x1 -- Only accept the first
assignedTo.right[z] = x2 -- Repeated overwrite gives us result we want
assignedTo.maxZ = z -- Repeated overwrite gives us result we want
assignedTo.worth = assignedTo.worth + worth
end
else
aboveIdx = aboveIdx + 1
end
end
nStrips = nStrips + 1
stripLeft[nStrips] = x1
stripRight[nStrips] = x2
if assignedTo then
stripGroup[nStrips] = assignedTo
else
local newGroup = {
left = {[z] = x1},
right = {[z] = x2},
minZ = z,
maxZ = z,
worth = worth
}
stripGroup[nStrips] = newGroup
uniqueGroups[newGroup] = true
end
end
-- Strip finding
workingIdx = huge
for mz = metalmapStartX, metalmapSizeZ, gridSize do
aboveIdx = workingIdx
workingIdx = nStrips + 1
local stripStart = nil
local stripWorth = 0
for mx = metalmapStartZ, metalmapSizeX, gridSize do
local _, groundMetal = spGetGroundInfo(mx, mz)
if groundMetal > 0 then
stripStart = stripStart or mx
stripWorth = stripWorth + groundMetal
elseif stripStart then
if mx - gridSize - stripStart > extractorRadius then
Spring.Echo('<WG.metalSpots> Mass metal detected. Disabling.')
return {}
end
DoStrip(stripStart, mx - gridSize, mz, stripWorth)
stripStart = nil
stripWorth = 0
end
end
if stripStart then
if metalmapSizeX - stripStart > extractorRadius then
Spring.Echo('<WG.metalSpots> Mass metal detected. Disabling.')
return {}
end
DoStrip(stripStart, metalmapSizeX, mz, stripWorth)
end
end
-- Final processing
local spots = {}
for g, _ in pairs(uniqueGroups) do
local gMinX, gMaxX = huge, -1
local gLeft, gRight = g.left, g.right
for iz = g.minZ, g.maxZ, gridSize do
if gLeft[iz] < gMinX then gMinX = gLeft[iz] end
if gRight[iz] > gMaxX then gMaxX = gRight[iz] end
end
g.minX = gMinX
g.maxX = gMaxX
g.x = (gMinX + gMaxX) * 0.5
g.z = (g.minZ + g.maxZ) * 0.5
g.y = spGetGroundHeight(g.x, g.z)
spots[#spots + 1] = g
end
return spots
end
function GetValidStrips(spot)
local sMinZ, sMaxZ = spot.minZ, spot.maxZ
local sLeft, sRight = spot.left, spot.right
local validLeft = {}
local validRight = {}
local maxZOffset = buildGridSize * floor(extractorRadius / buildGridSize)
for mz = max(sMaxZ - maxZOffset, buildmapStartZ), min(sMinZ + maxZOffset, buildmapSizeZ), buildGridSize do
local vLeft, vRight = buildmapStartX, buildmapSizeX
for sz = sMinZ, sMaxZ, gridSize do
local dz = sz - mz
local maxXOffset = buildGridSize * floor(sqrt(extractorRadiusSqr - dz * dz) / buildGridSize) -- Test for metal being included is dist < extractorRadius
local left, right = sRight[sz] - maxXOffset, sLeft[sz] + maxXOffset
if left > vLeft then vLeft = left end
if right < vRight then vRight = right end
end
validLeft[mz] = vLeft
validRight[mz] = vRight
end
spot.validLeft = validLeft
spot.validRight = validRight
end
------------------------------------------------------------
-- Callins
------------------------------------------------------------
-- checks if the current map uses lua metal spots
local function checkMap()
mapFileName = "maps/" .. Game.mapName .. ".sd7"
if VFS.MapArchive(mapFileName) == true then
--Spring.Echo("Map exists.")
else
Spring.Echo("Map does not exist.")
end
Spring.Echo("Testing map.")
-- check that texture exists, then load it
dirResult = VFS.DirList("maps/")
for i = 1, #dirResult do
--Spring.Echo(dirResult[i])
end
smfFileName = "maps/" .. Game.mapName .. ".lmf"
if VFS.FileExists(smfFileName) then
smfFileData = VFS.LoadFile(smfFileName)
--Spring.Echo("Lmf exists.")
io.output("m_tmp")
io.write(smfFileData)
io.output():close();
io.input( "m_tmp" )
searchPath = io.read() -- line 0 holds searchPath = 'archive' or a relative path
rgbr = io.read() -- line 2 red tint
rgbg = io.read() -- line 3 green tint
rgbb = io.read() -- line 4 blue tint
else -- not used for this map
Spring.Echo("Lmf does not exist.")
widgetHandler:RemoveWidget()
return
end
-- textureFileName = "maps/metal_high.png"
-- if VFS.FileExists(textureFileName) then
-- Spring.Echo("Texture exists.")
-- textureFileData = VFS.LoadFile(textureFileName)
-- else -- not used for this map
-- Spring.Echo("Texture does not exist.")
-- widgetHandler:RemoveWidget()
-- return
-- end
end
local function badInput()
widgetHandler:RemoveWidget()
return
end
local function parseLmf()
rgbr = tonumber(rgbr)
rgbg = tonumber(rgbg)
rgbb = tonumber(rgbb)
if ( assert(type( searchPath )) ~= "string" ) then
badInput()
end
if ( assert(type(rgbr)) ~= "number" or assert(type(rgbg)) ~= "number" or assert(type(rgbb)) ~= "number" or rgbr > 1 or rgbr < 0 or rgbg > 1 or rgbg < 0 or rgbb > 1 or rgbb < 0 ) then
badInput()
end
end
local function randomness()
for i = 1, #mSpots do
randTexture[i] = "LuaUI/Widgets/metalspots/metal"..math.random(1, 5)..".png"
end
end
function createDL()
local x = 0
local y = 0
local z = 0
gl.PushMatrix()
gl.DepthTest(true)
--gl.LoadIdentity()
gl.Color( rgbr, rgbg, rgbb, 1.0)
for i = 1, #mSpots do
gl.Texture(randTexture[i])
--gl.Translate( -mSpots[i].x, 0, -mSpots[i].z )
--gl.Rotate( 1, 0, 0, 1 )
gl.Translate( 0, 1, 0 )
gl.DrawGroundQuad( mSpots[i].x - metalSpotWidth/2, mSpots[i].z - metalSpotHeight/2, mSpots[i].x + metalSpotWidth/2, mSpots[i].z + metalSpotHeight/2, false, 0, 0, 1, 1)
gl.Translate( 0, -1, 0 )
end
gl.DepthTest(false)
gl.PopMatrix()
end
function widget:DrawWorldPreUnit()
--gl.CallList(dl)
createDL()
end
function widget:Initialize()
if (Spring.GetMapOptions().patches == "0") then
widgetHandler:Removewidget()
return
end
if (enabled==true) then
checkMap()
parseLmf()
Spring.CreateDir(pathToSave)
local filename = (pathToSave.. string.lower(string.gsub(Game.mapName, ".smf", "")) .. ".springmexmapv3")
file = io.open(filename,'r')
--io.close(file)
if file ~= nil then -- file exists?
Spring.Echo("Mexmap detected - loading...")
LoadMetalMap(filename)
else
Spring.Echo("Calculating mexmap")
SaveMetalMap(filename)
end
if #mSpots > 0 then
--Spring.Echo( 'worth', mSpots[1].worth )
randomness()
--dl = gl.CreateList(createDL)
end
else
widgetHandler:Removewidget()
end
end
- Attachments
-
- metal3.png (258.82 KiB) Viewed 1949 times
-
- metal2.png (251.56 KiB) Viewed 1949 times
-
- metal1.png (278.37 KiB) Viewed 1949 times
Re: game adding metal spot textures on map if missing
Thanks for the replies, i'll look into it.
My goal is to have a gadget that:
- only has effects on specific maps from a hard-coded list (I'll update it)
- has several different sets of textures (so I can assign different sets to each map)
- each set has a different subset of textures for spots with : lower-than-75%-median yield, close-to-median yield, greater-than-125%-median yield
I'll use only on maps which lack the textures. Btw, why do they lack the textures?
My goal is to have a gadget that:
- only has effects on specific maps from a hard-coded list (I'll update it)
- has several different sets of textures (so I can assign different sets to each map)
- each set has a different subset of textures for spots with : lower-than-75%-median yield, close-to-median yield, greater-than-125%-median yield
I'll use only on maps which lack the textures. Btw, why do they lack the textures?
Re: game adding metal spot textures on map if missing
because not every game gives a care about metal spots.