1--------------------------------------------------------------------------------
2--------------------------------------------------------------------------------
3--
4--  file:    minimap_startbox.lua
5--  brief:   shows the startboxes in the minimap
6--  author:  Dave Rodgers
7--
8--  Copyright (C) 2007.
9--  Licensed under the terms of the GNU GPL, v2 or later.
10--
11--------------------------------------------------------------------------------
12--------------------------------------------------------------------------------
13
14function widget:GetInfo()
15  return {
16    name      = "MiniMap Start Boxes",
17    desc      = "MiniMap Start Boxes",
18    author    = "trepan, jK",
19    date      = "2007-2009",
20    license   = "GNU GPL, v2 or later",
21    layer     = 0,
22    enabled   = true  --  loaded by default?
23  }
24end
25
26--------------------------------------------------------------------------------
27--------------------------------------------------------------------------------
28
29if (Game.startPosType ~= 2) then
30  return false
31end
32
33if (Spring.GetGameFrame() > 1) then
34  widgetHandler:RemoveWidget()
35end
36
37--------------------------------------------------------------------------------
38--------------------------------------------------------------------------------
39--
40--  config options
41--
42
43-- enable simple version by default though
44local drawGroundQuads = true
45
46
47--------------------------------------------------------------------------------
48--------------------------------------------------------------------------------
49
50local gl = gl  --  use a local copy for faster access
51
52local msx = Game.mapSizeX
53local msz = Game.mapSizeZ
54
55local xformList = 0
56local coneList = 0
57local startboxDListStencil = 0
58local startboxDListColor = 0
59
60local gaiaTeamID
61local gaiaAllyTeamID
62
63local teamStartPositions = {}
64local startTimer = Spring.GetTimer()
65
66local texName = LUAUI_DIRNAME .. 'Images/highlight_strip.png'
67local texScale = 512
68
69--------------------------------------------------------------------------------
70
71GL.KEEP = 0x1E00
72GL.INCR_WRAP = 0x8507
73GL.DECR_WRAP = 0x8508
74GL.INCR = 0x1E02
75GL.DECR = 0x1E03
76GL.INVERT = 0x150A
77
78local stencilBit1 = 0x01
79local stencilBit2 = 0x10
80
81--------------------------------------------------------------------------------
82--------------------------------------------------------------------------------
83
84local function DrawMyBox(minX,minY,minZ, maxX,maxY,maxZ)
85  gl.BeginEnd(GL.QUADS, function()
86    --// top
87    gl.Vertex(minX, maxY, minZ);
88    gl.Vertex(maxX, maxY, minZ);
89    gl.Vertex(maxX, maxY, maxZ);
90    gl.Vertex(minX, maxY, maxZ);
91    --// bottom
92    gl.Vertex(minX, minY, minZ);
93    gl.Vertex(minX, minY, maxZ);
94    gl.Vertex(maxX, minY, maxZ);
95    gl.Vertex(maxX, minY, minZ);
96  end);
97  gl.BeginEnd(GL.QUAD_STRIP, function()
98    --// sides
99    gl.Vertex(minX, minY, minZ);
100    gl.Vertex(minX, maxY, minZ);
101    gl.Vertex(minX, minY, maxZ);
102    gl.Vertex(minX, maxY, maxZ);
103    gl.Vertex(maxX, minY, maxZ);
104    gl.Vertex(maxX, maxY, maxZ);
105    gl.Vertex(maxX, minY, minZ);
106    gl.Vertex(maxX, maxY, minZ);
107    gl.Vertex(minX, minY, minZ);
108    gl.Vertex(minX, maxY, minZ);
109  end);
110end
111
112--------------------------------------------------------------------------------
113--------------------------------------------------------------------------------
114
115function widget:Initialize()
116  -- only show at the beginning
117  if (Spring.GetGameFrame() > 1) then
118    widgetHandler:RemoveWidget()
119    return
120  end
121
122  -- get the gaia teamID and allyTeamID
123  gaiaTeamID = Spring.GetGaiaTeamID()
124  if (gaiaTeamID) then
125    local _,_,_,_,_,atid = Spring.GetTeamInfo(gaiaTeamID)
126    gaiaAllyTeamID = atid
127  end
128
129  -- flip and scale  (using x & y for gl.Rect())
130  xformList = gl.CreateList(function()
131    gl.LoadIdentity()
132    gl.Translate(0, 1, 0)
133    gl.Scale(1 / msx, -1 / msz, 1)
134  end)
135
136  -- cone list for world start positions
137  coneList = gl.CreateList(function()
138    local h = 100
139    local r = 25
140    local divs = 32
141    gl.BeginEnd(GL.TRIANGLE_FAN, function()
142      gl.Vertex( 0, h,  0)
143      for i = 0, divs do
144        local a = i * ((math.pi * 2) / divs)
145        local cosval = math.cos(a)
146        local sinval = math.sin(a)
147        gl.Vertex(r * sinval, 0, r * cosval)
148      end
149    end)
150  end)
151
152  if (drawGroundQuads) then
153    startboxDListStencil = gl.CreateList(function()
154      local minY,maxY = Spring.GetGroundExtremes()
155      minY = minY - 200; maxY = maxY + 100;
156      for _,at in ipairs(Spring.GetAllyTeamList()) do
157        if (true or at ~= gaiaAllyTeamID) then
158          local xn, zn, xp, zp = Spring.GetAllyTeamStartBox(at)
159          if (xn and ((xn ~= 0) or (zn ~= 0) or (xp ~= msx) or (zp ~= msz))) then
160
161            if (at == Spring.GetMyAllyTeamID()) then
162              gl.StencilMask(stencilBit2);
163              gl.StencilFunc(GL.ALWAYS, 0, stencilBit2);
164            else
165              gl.StencilMask(stencilBit1);
166              gl.StencilFunc(GL.ALWAYS, 0, stencilBit1);
167            end
168            DrawMyBox(xn,minY,zn, xp,maxY,zp)
169
170          end
171        end
172      end
173    end)
174
175    startboxDListColor = gl.CreateList(function()
176      local minY,maxY = Spring.GetGroundExtremes()
177      minY = minY - 200; maxY = maxY + 100;
178      for _,at in ipairs(Spring.GetAllyTeamList()) do
179        if (true or at ~= gaiaAllyTeamID) then
180          local xn, zn, xp, zp = Spring.GetAllyTeamStartBox(at)
181          if (xn and ((xn ~= 0) or (zn ~= 0) or (xp ~= msx) or (zp ~= msz))) then
182
183            if (at == Spring.GetMyAllyTeamID()) then
184              gl.Color( 0, 1, 0, 0.3 )  --  green
185              gl.StencilMask(stencilBit2);
186              gl.StencilFunc(GL.NOTEQUAL, 0, stencilBit2);
187            else
188              gl.Color( 1, 0, 0, 0.3 )  --  red
189              gl.StencilMask(stencilBit1);
190              gl.StencilFunc(GL.NOTEQUAL, 0, stencilBit1);
191            end
192            DrawMyBox(xn,minY,zn, xp,maxY,zp)
193
194          end
195        end
196      end
197    end)
198  end
199end
200
201
202function widget:Shutdown()
203  gl.DeleteList(xformList)
204  gl.DeleteList(coneList)
205  gl.DeleteList(startboxDListStencil)
206  gl.DeleteList(startboxDListColor)
207end
208
209
210--------------------------------------------------------------------------------
211--------------------------------------------------------------------------------
212
213local teamColors = {}
214
215local function GetTeamColor(teamID)
216  local color = teamColors[teamID]
217  if (color) then
218    return color
219  end
220  local r,g,b = Spring.GetTeamColor(teamID)
221
222  color = { r, g, b }
223  teamColors[teamID] = color
224  return color
225end
226
227
228--------------------------------------------------------------------------------
229--------------------------------------------------------------------------------
230
231local teamColorStrs = {}
232
233
234local function GetTeamColorStr(teamID)
235  local colorSet = teamColorStrs[teamID]
236  if (colorSet) then
237    return colorSet[1], colorSet[2]
238  end
239
240  local outlineChar = ''
241  local r,g,b = Spring.GetTeamColor(teamID)
242  if (r and g and b) then
243    local function ColorChar(x)
244      local c = math.floor(x * 255)
245      c = ((c <= 1) and 1) or ((c >= 255) and 255) or c
246      return string.char(c)
247    end
248    local colorStr
249    colorStr = '\255'
250    colorStr = colorStr .. ColorChar(r)
251    colorStr = colorStr .. ColorChar(g)
252    colorStr = colorStr .. ColorChar(b)
253    local i = (r * 0.299) + (g * 0.587) + (b * 0.114)
254    outlineChar = ((i > 0.25) and 'o') or 'O'
255    teamColorStrs[teamID] = { colorStr, outlineChar }
256    return colorStr, "s",outlineChar
257  end
258end
259
260--------------------------------------------------------------------------------
261--------------------------------------------------------------------------------
262
263local function DrawStartboxes3dWithStencil()
264  gl.DepthMask(false);
265  if (gl.DepthClamp) then gl.DepthClamp(true); end
266
267  gl.DepthTest(true);
268  gl.StencilTest(true);
269  gl.ColorMask(false, false, false, false);
270  gl.Culling(false);
271
272  gl.StencilOp(GL.KEEP, GL.INVERT, GL.KEEP);
273
274  gl.CallList(startboxDListStencil);   --// draw
275
276  gl.Culling(GL.BACK);
277  gl.DepthTest(false);
278
279  gl.ColorMask(true, true, true, true);
280
281  gl.CallList(startboxDListColor);   --// draw
282
283  if (gl.DepthClamp) then gl.DepthClamp(false); end
284  gl.StencilTest(false);
285  gl.DepthTest(true);
286  gl.Culling(false);
287end
288
289--------------------------------------------------------------------------------
290--------------------------------------------------------------------------------
291
292function widget:DrawWorld()
293  gl.Fog(false)
294
295  local time = Spring.DiffTimers(Spring.GetTimer(), startTimer)
296
297  -- show the ally startboxes
298  DrawStartboxes3dWithStencil()
299
300  -- show the team start positions
301  for _, teamID in ipairs(Spring.GetTeamList()) do
302    local _,leader = Spring.GetTeamInfo(teamID)
303    local name,_,spec = Spring.GetPlayerInfo(leader)
304    if ((not spec) and (teamID ~= gaiaTeamID)) then
305      local newx, newy, newz = Spring.GetTeamStartPosition(teamID)
306
307      if (teamStartPositions[teamID] == nil) then
308        teamStartPositions[teamID] = {newx, newy, newz}
309      end
310
311      local oldx, oldy, oldz =
312        teamStartPositions[teamID][1],
313        teamStartPositions[teamID][2],
314        teamStartPositions[teamID][3]
315
316      if (newx ~= oldx or newy ~= oldy or newz ~= oldz) then
317        Spring.PlaySoundFile("MapPoint")
318        Spring.MarkerErasePosition(oldx, oldy, oldz)
319        Spring.MarkerAddPoint(newx, newy, newz, "Start " .. teamID .. " (" .. name .. ")", 1)
320        teamStartPositions[teamID][1] = newx
321        teamStartPositions[teamID][2] = newy
322        teamStartPositions[teamID][3] = newz
323      end
324
325      if (newx ~= nil and newx ~= 0 and newz ~= 0 and newy > -500.0) then
326        local color = GetTeamColor(teamID)
327        local alpha = 0.5 + math.abs(((time * 3) % 1) - 0.5)
328        gl.PushMatrix()
329        gl.Translate(newx, newy, newz)
330        gl.Color(color[1], color[2], color[3], alpha)
331        gl.CallList(coneList)
332        gl.PopMatrix()
333      end
334    end
335  end
336
337  gl.Fog(true)
338end
339
340--------------------------------------------------------------------------------
341--------------------------------------------------------------------------------
342
343function widget:DrawScreenEffects()
344  -- show the names over the team start positions
345  gl.Fog(false)
346  gl.BeginText()
347  for _, teamID in ipairs(Spring.GetTeamList()) do
348    local _,leader = Spring.GetTeamInfo(teamID)
349    local name,_,spec = Spring.GetPlayerInfo(leader)
350    if ((not spec) and (teamID ~= gaiaTeamID)) then
351      local colorStr, outlineStr = GetTeamColorStr(teamID)
352      local x, y, z = Spring.GetTeamStartPosition(teamID)
353      if (x ~= nil and x > 0 and z > 0 and y > -500) then
354        local sx, sy, sz = Spring.WorldToScreenCoords(x, y + 120, z)
355        if (sz < 1) then
356          gl.Text(colorStr .. name, sx, sy, 18, 'cs')
357        end
358      end
359    end
360  end
361  gl.EndText()
362  gl.Fog(true)
363end
364
365--------------------------------------------------------------------------------
366--------------------------------------------------------------------------------
367
368function widget:DrawInMiniMap(sx, sz)
369  -- only show at the beginning
370  if (Spring.GetGameFrame() > 1) then
371    widgetHandler:RemoveWidget()
372  end
373
374  gl.PushMatrix()
375  gl.CallList(xformList)
376
377  gl.LineWidth(1.49)
378
379  local gaiaAllyTeamID
380  local gaiaTeamID = Spring.GetGaiaTeamID()
381  if (gaiaTeamID) then
382    local _,_,_,_,_,atid = Spring.GetTeamInfo(gaiaTeamID)
383    gaiaAllyTeamID = atid
384  end
385
386  -- show all start boxes
387  for _,at in ipairs(Spring.GetAllyTeamList()) do
388    if (at ~= gaiaAllyTeamID) then
389      local xn, zn, xp, zp = Spring.GetAllyTeamStartBox(at)
390      if (xn and ((xn ~= 0) or (zn ~= 0) or (xp ~= msx) or (zp ~= msz))) then
391        local color
392        if (at == Spring.GetMyAllyTeamID()) then
393          color = { 0, 1, 0, 0.1 }  --  green
394        else
395          color = { 1, 0, 0, 0.1 }  --  red
396        end
397        gl.Color(color)
398        gl.Rect(xn, zn, xp, zp)
399        color[4] = 0.5  --  pump up the volume
400        gl.Color(color)
401        gl.PolygonMode(GL.FRONT_AND_BACK, GL.LINE)
402        gl.Rect(xn, zn, xp, zp)
403        gl.PolygonMode(GL.FRONT_AND_BACK, GL.FILL)
404      end
405    end
406  end
407
408  gl.PushAttrib(GL_HINT_BIT)
409  gl.Smoothing(true) --enable point smoothing
410
411  -- show the team start positions
412  for _, teamID in ipairs(Spring.GetTeamList()) do
413    local _,leader = Spring.GetTeamInfo(teamID)
414    local _,_,spec = Spring.GetPlayerInfo(leader)
415    if ((not spec) and (teamID ~= gaiaTeamID)) then
416      local x, y, z = Spring.GetTeamStartPosition(teamID)
417      if (x ~= nil and x > 0 and z > 0 and y > -500) then
418        local color = GetTeamColor(teamID)
419        local r, g, b = color[1], color[2], color[3]
420        local time = Spring.DiffTimers(Spring.GetTimer(), startTimer)
421        local i = 2 * math.abs(((time * 3) % 1) - 0.5)
422        gl.PointSize(11)
423        gl.Color(i, i, i)
424        gl.BeginEnd(GL.POINTS, gl.Vertex, x, z)
425        gl.PointSize(7.5)
426        gl.Color(r, g, b)
427        gl.BeginEnd(GL.POINTS, gl.Vertex, x, z)
428      end
429    end
430  end
431
432  gl.LineWidth(1.0)
433  gl.PointSize(1.0)
434  gl.PopAttrib() --reset point smoothing
435  gl.PopMatrix()
436end
437
438
439--------------------------------------------------------------------------------
440--------------------------------------------------------------------------------
441