Economy: metal.lua

File metal.lua, 4.8 KB (added by evil4zerggin, 8 months ago)

Part of a system that would allow us to take over metal extractor behavior from the engine. Probably buggy.

Line 
1----------------------------------------------------------------
2--parameters
3----------------------------------------------------------------
4local maxMetal = 1 --scale metal by this value; acts like map max metal
5
6----------------------------------------------------------------
7--speed-ups
8----------------------------------------------------------------
9local mapSizeX = Game.mapSizeX
10local mapSizeZ = Game.mapSizeZ
11local extractorRadius = Game.extractorRadius
12
13local GetGroundInfo = Spring.GetGroundInfo
14local GetUnitPosition = Spring.GetUnitPosition
15
16----------------------------------------------------------------
17--constants
18----------------------------------------------------------------
19
20local metalMapMaxX = math.floor(mapSizeX / metalMapScale) - 1
21local metalMapMaxZ = math.floor(mapSizeX / metalMapScale) - 1
22local extractSearchMax = math.floor(extractorRadius / metalMapScale)
23
24local metalMapScale = 16
25local metalMapScaleSq = 256
26
27----------------------------------------------------------------
28--locals
29----------------------------------------------------------------
30
31--2-D array that stores the metal map
32local metalMap = {}
33
34--3-D array that stores what mexes are lined up to control each particular square on the metal map
35local controlMap = {}
36
37--quarter-circle indicating whether a particular metal map square is within the extractor radius of the origin
38local circleMask = {}
39
40--table of mexes; entries are indexed by unitID and have values equal to the raw metal produced by the mex
41local mexes = {}
42
43--setup metal map, control map
44local function SetupMaps()
45  for i = 0, metalMapMaxX do
46    metalMap[i] = {}
47    controlMap[i] = {}
48    for j = 0, metalMapMaxZ do
49      _, metalMap[i][j] = GetGroundInfo(metalMapScale * i + 8, metalMapScale * j + 8) * maxMetal
50      controlMap[i][j] = {}
51    end
52  end
53end
54
55--setup circle mask
56local function SetupCircleMask()
57  do
58    local radiusSq = extractorRadius * extractorRadius
59    for i = 0, extractSearchMax do
60      for j = 0, extractSearchMax do
61        if ((i*i + j*j) * metalMapScaleSq < radiusSq) then
62          circleMask[i][j] = true
63        end
64      end
65    end
66  end
67end
68
69local function GetTotalGlobalMetal()
70  local result = 0
71  for i = 0, metalMapMaxX do
72    for j = 0, metalMapMaxZ do
73      result = result + metalMap[i][j]
74    end
75  end
76  return result
77end
78
79local function GetMetalMapCoords(posX, posZ)
80  return math.floor(posX / metalMapScale), math.floor(posZ / metalMapScale)
81end
82
83local function AddMex(unitID)
84  local metal = 0
85  local posX, _, posZ = GetUnitPosition(unitID)
86  local mPosX, mPosZ = GetMetalMapCoords(posX, posZ)
87 
88  --establish how far we are willing to search
89  local backX = math.min(extractSearchMax, mPosX)
90  local frontX = math.min(extractSearchMax, metalMapMaxX - mPosX)
91  local backZ = math.min(extractSearchMax, mPosZ)
92  local frontZ = math.min(extractSearchMax, metalMapMaxZ - mPosZ)
93 
94  --iterate over the search area
95  for i = -backX, frontX do
96    for j = -backZ, frontZ do
97      --check our pre-calculated mask to see if each spot is within the extractor radius
98      if (circleMask[math.abs(i)][math.abs(j)]) then
99        --position on metal map
100        local iPos = mPosX + i
101        local jPos = mPosZ + j
102       
103        --if spot not already claimed, give the metal to the mex
104        if (not controlMap[iPos][jPos]) then
105          metal = metal + metalMap[iPos][jPos]
106        end
107       
108        --add the mex to the queue of controllers
109        table.insert(controlMap[iPos][jPos], unitID)
110      end
111    end
112  end
113  mexes[unitID] = metal
114end
115
116local function RemoveMex(unitID)
117  local metal = 0
118  local posX, _, posZ = GetUnitPosition(unitID)
119  local mPosX, mPosZ = GetMetalMapCoords(posX, posZ)
120 
121  --establish how far we are willing to search
122  local backX = math.min(extractSearchMax, mPosX)
123  local frontX = math.min(extractSearchMax, metalMapMaxX - mPosX)
124  local backZ = math.min(extractSearchMax, mPosZ)
125  local frontZ = math.min(extractSearchMax, metalMapMaxZ - mPosZ)
126 
127  --iterate over the search area
128  for i = -backX, frontX do
129    for j = -backZ, frontZ do
130      --position on metal map
131      local iPos = mPosX + i
132      local jPos = mPosZ + j
133     
134      --if we control this spot, give it to the next in line
135      if (controlMap[i][j][1] == unitID) then
136        --remove any mexes in line which no longer exist
137        local nextID
138       
139        repeat
140          table.remove(controlMap[i][j], 1)
141          nextID = controlMap[i][j][1]
142        until (not nextID or mexes[nextID])
143       
144        --add the metal to the new owner
145        if (nextID) then
146          mexes[nextID] = mexes[nextID] + metalMap[iPos][jPos]
147        end
148      end
149    end
150  end
151  mexes[unitID] = nil
152end