| 1 | ----------------------------------------------------------------
|
|---|
| 2 | --parameters
|
|---|
| 3 | ----------------------------------------------------------------
|
|---|
| 4 | local maxMetal = 1 --scale metal by this value; acts like map max metal
|
|---|
| 5 |
|
|---|
| 6 | ----------------------------------------------------------------
|
|---|
| 7 | --speed-ups
|
|---|
| 8 | ----------------------------------------------------------------
|
|---|
| 9 | local mapSizeX = Game.mapSizeX
|
|---|
| 10 | local mapSizeZ = Game.mapSizeZ
|
|---|
| 11 | local extractorRadius = Game.extractorRadius
|
|---|
| 12 |
|
|---|
| 13 | local GetGroundInfo = Spring.GetGroundInfo
|
|---|
| 14 | local GetUnitPosition = Spring.GetUnitPosition
|
|---|
| 15 |
|
|---|
| 16 | ----------------------------------------------------------------
|
|---|
| 17 | --constants
|
|---|
| 18 | ----------------------------------------------------------------
|
|---|
| 19 |
|
|---|
| 20 | local metalMapMaxX = math.floor(mapSizeX / metalMapScale) - 1
|
|---|
| 21 | local metalMapMaxZ = math.floor(mapSizeX / metalMapScale) - 1
|
|---|
| 22 | local extractSearchMax = math.floor(extractorRadius / metalMapScale)
|
|---|
| 23 |
|
|---|
| 24 | local metalMapScale = 16
|
|---|
| 25 | local metalMapScaleSq = 256
|
|---|
| 26 |
|
|---|
| 27 | ----------------------------------------------------------------
|
|---|
| 28 | --locals
|
|---|
| 29 | ----------------------------------------------------------------
|
|---|
| 30 |
|
|---|
| 31 | --2-D array that stores the metal map
|
|---|
| 32 | local metalMap = {}
|
|---|
| 33 |
|
|---|
| 34 | --3-D array that stores what mexes are lined up to control each particular square on the metal map
|
|---|
| 35 | local controlMap = {}
|
|---|
| 36 |
|
|---|
| 37 | --quarter-circle indicating whether a particular metal map square is within the extractor radius of the origin
|
|---|
| 38 | local circleMask = {}
|
|---|
| 39 |
|
|---|
| 40 | --table of mexes; entries are indexed by unitID and have values equal to the raw metal produced by the mex
|
|---|
| 41 | local mexes = {}
|
|---|
| 42 |
|
|---|
| 43 | --setup metal map, control map
|
|---|
| 44 | local 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
|
|---|
| 53 | end
|
|---|
| 54 |
|
|---|
| 55 | --setup circle mask
|
|---|
| 56 | local 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
|
|---|
| 67 | end
|
|---|
| 68 |
|
|---|
| 69 | local 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
|
|---|
| 77 | end
|
|---|
| 78 |
|
|---|
| 79 | local function GetMetalMapCoords(posX, posZ)
|
|---|
| 80 | return math.floor(posX / metalMapScale), math.floor(posZ / metalMapScale)
|
|---|
| 81 | end
|
|---|
| 82 |
|
|---|
| 83 | local 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
|
|---|
| 114 | end
|
|---|
| 115 |
|
|---|
| 116 | local 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
|
|---|
| 152 | end
|
|---|
| 153 |
|
|---|