File: share_delayed.lua

package info (click to toggle)
spring 0.81.2.1%2Bdfsg1-6
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 28,496 kB
  • ctags: 37,096
  • sloc: cpp: 238,659; ansic: 13,784; java: 12,175; awk: 3,428; python: 1,159; xml: 738; perl: 405; sh: 297; makefile: 267; pascal: 228; objc: 192
file content (400 lines) | stat: -rw-r--r-- 11,120 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
--  file:    share_delayed.lua
--  brief:   delay unit sharing
--  author:  Dave Rodgers
--
--  Copyright (C) 2007.
--  Licensed under the terms of the GNU GPL, v2 or later.
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

function gadget:GetInfo()
  return {
    name      = "SharingDelayed",
    desc      = "delayed unit sharing",
    author    = "trepan",
    date      = "Apr 22, 2007",
    license   = "GNU GPL, v2 or later",
    layer     = -4,
    enabled   = true  --  loaded by default?
  }
end

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
--  FIXME: (TODO)
--  - Delayed resource sharing
--  - Visual indicators for units queued to be shared
--  - Update unit share times for fallen comrades
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

-- Only active in comm-ends games

if (Game.gameMode ~= 1) then
  return false
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
--  Proposed Command ID Ranges:
--
--    all negative:  Engine (build commands)
--       0 -   999:  Engine
--    1000 -  9999:  Group AI
--   10000 - 19999:  LuaUI
--   20000 - 29999:  LuaCob
--   30000 - 39999:  LuaRules
--

local CMD_CANCEL_SHARE = 33999


--------------------------------------------------------------------------------
--  COMMON
--------------------------------------------------------------------------------
if (gadgetHandler:IsSyncedCode()) then
--------------------------------------------------------------------------------
--  SYNCED
--------------------------------------------------------------------------------

local teams  = {}  --  teamID = { unitID = shareInfo }
local shares = {}  --  unitID = oldTeam
local frames = {}  --  unitID = framee

local enabled = true

local minDelay  = 1    -- minimum delay between shares
local costScale = 0.1  -- add extra cycles based on unit costs

local cancelShareCmdDesc = {
  id   = CMD_CANCEL_SHARE,
  type = CMDTYPE.ICON,
  name = '\255\255\100\100NoShare',
  tooltip = 'Cancel the unit transfer',
  action = 'cancel_share',
}


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

local function AllowAction(playerID)
  if (playerID ~= 0) then
    Spring.SendMessageToPlayer(playerID, "Must be the host player")
    return false
  end
  if (not Spring.IsCheatingEnabled()) then
    Spring.SendMessageToPlayer(playerID, "Cheating must be enabled")
    return false
  end
  return true
end


local function ChatControl(cmd, line, words, playerID)
  if (not AllowAction(playerID)) then
    Spring.Echo('delayed sharing is ' .. (enabled and 'enabled' or 'disabled'))
    return true
  end
  if (#words == 0) then
    enabled = not enabled
  else
    enabled = (words[1] == '1')
  end
  Spring.Echo('delayed sharing is ' .. (enabled and 'enabled' or 'disabled'))
  return true
end


local function StopShare(cmd, line, words, playerID)
  local _,_,_,teamID = Spring.GetPlayerInfo(playerID)
  local team = teamID and teams[teamID] or nil
  if (team) then
    for _,data in pairs(team) do
      shares[data.unitID] = nil
      frames[data.unitID] = nil
    end
    teams[teamID] = nil
    Spring.Echo('cancelled remaining unit transfers')
  else
    Spring.Echo('there are no unit transfers to cancel')
  end
  return true
end


--------------------------------------------------------------------------------

function gadget:Initialize()
  gadgetHandler:RegisterCMDID(CMD_CANCEL_SHARE)
  _G.shareFrames = frames

  local cmd, help
  
  cmd  = "sharedelay"
  help = " [0|1]:  delayed unit sharing, useful for comm ends games"
  gadgetHandler:AddChatAction(cmd, ChatControl, help)
  Script.AddActionFallback(cmd .. ' ', help)

  cmd  = "stopshare"
  help = ":  cancel all queued unit transfers for your team"
  gadgetHandler:AddChatAction(cmd,  StopShare, help)
  Script.AddActionFallback(cmd, help)
end


function gadget:Shutdown()
  gadgetHandler:RemoveChatAction("sharedelay")
  Script.RemoveActionFallback("sharedelay")

  gadgetHandler:RemoveChatAction("stopshare")
  Script.RemoveActionFallback("stopshare")

  for _,unitID in ipairs(Spring.GetAllUnits()) do
    local cmdDescID = Spring.FindUnitCmdDesc(unitID, CMD_CANCEL_SHARE)
    if (cmdDescID) then
      Spring.RemoveUnitCmdDesc(unitID, cmdDescID)
    end
  end
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

local insert = table.insert
local remove = table.remove


local function InsertShare(unitID, oldTeam, newTeam, delay)
  if (shares[unitID]) then
    return  -- already active
  end

  local shareInfo = {
    unitID  = unitID,
    oldTeam = oldTeam,
    newTeam = newTeam,
    delay   = delay,
  }
  local team = teams[oldTeam]

  if (team) then
    print(team[#team].frame, delay)
    shareInfo.frame = team[#team].frame + delay
  else
    team = {}
    teams[oldTeam] = team
    shareInfo.frame = Spring.GetGameFrame() + delay
  end

  insert(team, shareInfo)
  shares[unitID] = oldTeam
  frames[unitID] = shareInfo.frame

  Spring.InsertUnitCmdDesc(unitID, 1, cancelShareCmdDesc)
end


--------------------------------------------------------------------------------

local function RecalcDelays(team)
  for i = 2, #team do
    team[i].frame = team[i - 1].frame + team[i].delay
    frames[team[i].unitID] = team[i].frame
  end
end


local function RemoveShare(unitID)
  local oldTeam = shares[unitID]
  shares[unitID] = nil
  frames[unitID] = nil

  local cmdDescID = Spring.FindUnitCmdDesc(unitID, CMD_CANCEL_SHARE)
  if (cmdDescID) then
    Spring.RemoveUnitCmdDesc(unitID, cmdDescID)
  end

  local team = teams[oldTeam]
  if ((oldTeam == nil) or (team == nil)) then
    return  -- not active
  end

  local index
  for i, shareInfo in ipairs(team) do
    if (shareInfo.unitID == unitID) then
      index = i
      break
    end
  end
  if (index == nil) then
    return  -- something is amiss
  end

  local shareInfo = team[index]
  remove(team, index)

  if (#team <= 0) then
    teams[oldTeam] = nil
  else
    if (index ~= 1) then
      RecalcDelays(team)
    else
      local nowFrame = Spring.GetGameFrame()
      if (shareInfo.frame > nowFrame) then
        local front = team[1]
        front.frame = nowFrame + front.delay
        frames[front.unitID] = front.frame
        RecalcDelays(team)
      end
    end
  end
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

function gadget:AllowUnitTransfer(unitID, unitDefID, oldTeam, newTeam, capture)
  if (capture) then
    return true
  end
  if (not enabled) then
    return true
  end

  local ud = UnitDefs[unitDefID]
  if (not ud) then
    return true  -- something is borked
  end

  -- compute the share delay
  local cost = ud.metalCost + (ud.energyCost / 60)
  local costDelay = math.floor(cost * costScale)
  local shareDelay = minDelay + costDelay

  local team = teams[oldTeam]
  if ((team == nil) and (shareDelay <= 0)) then
    return true  -- share the unit immediately
  end

  InsertShare(unitID, oldTeam, newTeam, shareDelay)

  return false
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

function gadget:GameFrame(frameNum)
  for _,team in pairs(teams) do
    while (team and (#team > 0)) do
      local front = team[1]
      if (front.frame > frameNum) then
        break  -- front is not yet ready to be shared
      end

      local curTeam = Spring.GetUnitTeam(front.unitID)
      if (curTeam and (curTeam == front.oldTeam)) then
        -- FIXME: see if newTeam is alive
        local tmp = AllowUnitTransfer
        AllowUnitTransfer = function() return true end
        Spring.TransferUnit(front.unitID, front.newTeam)
        AllowUnitTransfer = tmp
      end

      RemoveShare(front.unitID)
    end
  end
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

function gadget:AllowCommand(unitID, unitDefID, unitTeam,
                             cmdID, cmdParams, cmdOptions)
  if (cmdID == CMD_CANCEL_SHARE) then
    RemoveShare(unitID)
    return false
  end
  return true
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

function gadget:UnitDestroyed(unitID, unitDefID, unitTeam)
  RemoveShare(unitID)
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

function gadget:UnitTaken(unitID)
  RemoveShare(unitID)
end


--------------------------------------------------------------------------------
--  SYNCED
--------------------------------------------------------------------------------
else
--------------------------------------------------------------------------------
--  UNSYNCED
--------------------------------------------------------------------------------

function gadget:Initialize()
end


function gadget:Shutdown()
end


local GetGameFrame		   = Spring.GetGameFrame
local GetUnitPosition    = Spring.GetUnitPosition
local GetUnitAllyTeam    = Spring.GetUnitAllyTeam
local GetLocalAllyTeamID = Spring.GetLocalAllyTeamID
local AddWorldIcon       = Spring.AddWorldIcon
local AddWorldText       = Spring.AddWorldText

function gadget:DrawWorld()
  local frames = SYNCED.shareFrames
  if ((frames == nil) or (snext(frames) == nil)) then
    return
  end
  local nowFrame = GetGameFrame()
  local myAllyTeam = GetLocalAllyTeamID()
  for unitID, frame in spairs(frames) do
    if (GetUnitAllyTeam(unitID) == myAllyTeam) then
      local x, y, z = GetUnitPosition(unitID)
      if (x) then
        local str = string.format('%.1f', (frame - nowFrame) / Game.gameSpeed)
        AddWorldIcon(x, y, z, CMD.STOP)
        AddWorldText(str, x, y, z)
      end
    end
  end
end


--------------------------------------------------------------------------------
--  UNSYNCED
--------------------------------------------------------------------------------
end
--------------------------------------------------------------------------------
--  COMMON
--------------------------------------------------------------------------------