John@71
|
1 local bsk=bsk
|
John@71
|
2 local _G=_G
|
John@71
|
3 local table=table
|
John@71
|
4 local pairs=pairs
|
John@71
|
5 local setmetatable=setmetatable
|
John@71
|
6 local ipairs=ipairs
|
John@71
|
7 local string=string
|
John@71
|
8 local sformat=string.format
|
John@71
|
9 local tostring=tostring
|
John@71
|
10 local type=type
|
John@71
|
11 local unpack=unpack
|
John@71
|
12 local getn=getn
|
John@71
|
13 setfenv(1,bsk)
|
John@71
|
14
|
John@71
|
15 -- simple state machine
|
John@71
|
16
|
John@71
|
17 --Begin loot
|
John@71
|
18 --Activate list ... only during looting?
|
John@71
|
19 --open bidding/rolling
|
John@71
|
20 --bid/roll occurred
|
John@71
|
21 --remove bid/roll
|
John@71
|
22 --close bidding
|
John@71
|
23 --remove item
|
John@71
|
24
|
John@71
|
25
|
John@71
|
26 -- we'll track state, but that may or may not result in a GUI change until down
|
John@71
|
27 -- the road
|
John@71
|
28
|
John@71
|
29 -- todo: transmit this all to only the raid, not the guild?
|
John@71
|
30
|
John@71
|
31 -- sample procedure
|
John@71
|
32 -- person B opens GUI.
|
John@71
|
33 -- person A begins looting, sets a list
|
John@71
|
34 -- person A begins bidding, transmists the state
|
John@71
|
35 -- person B goes into bidding state, their button activates
|
John@71
|
36 -- person B clicks the button. button changes state.
|
John@71
|
37 -- person B broadcasts their bid. if a bid, everyone just accepts it.
|
John@71
|
38 -- - if a roll, then the master does the roll and rebroadcasts
|
John@71
|
39
|
John@72
|
40 state = "neutral" -- states that are possible: neutral, looting, bidding
|
John@71
|
41 local looting = false
|
John@71
|
42 stateactive = nil
|
John@71
|
43 stateitem = nil
|
John@73
|
44 stateitemlist = {}
|
John@71
|
45 statebids = {}
|
John@71
|
46 staterolls = {}
|
John@78
|
47 staterollvalues = {}
|
John@73
|
48 stateactivelist = nil
|
John@71
|
49
|
John@76
|
50 -- todo: protect initiators to admin only
|
John@76
|
51
|
John@71
|
52 local rollListeners = {}
|
John@71
|
53 function RegisterListenerRolls(listener)
|
John@71
|
54 table.insert(rollListeners,listener)
|
John@71
|
55 end
|
John@71
|
56 function AlertRollListeners()
|
John@71
|
57 for i,v in pairs(rollListeners) do
|
John@71
|
58 print("roll out")
|
John@71
|
59 v["RollEvent"](v)
|
John@71
|
60 end
|
John@71
|
61 end
|
John@71
|
62
|
John@72
|
63 local listChangeListeners = {}
|
John@72
|
64 function RegisterListenerActiveListChanged(listener)
|
John@72
|
65 table.insert(listChangeListeners,listener)
|
John@72
|
66 end
|
John@72
|
67 function AlertActiveListChangedListeners()
|
John@72
|
68 for i,v in pairs(listChangeListeners) do
|
John@72
|
69 print("list out")
|
John@72
|
70 v["ActiveListEvent"](v)
|
John@72
|
71 end
|
John@72
|
72 end
|
John@72
|
73
|
John@72
|
74 local stateChangeListeners = {}
|
John@72
|
75 function RegisterListenerStateChange(listener)
|
John@72
|
76 table.insert(stateChangeListeners,listener)
|
John@72
|
77 end
|
John@72
|
78 function AlertStateChangeListeners()
|
John@72
|
79 for i,v in pairs(stateChangeListeners) do
|
John@72
|
80 print("state out")
|
John@72
|
81 v["StateEvent"](v)
|
John@72
|
82 end
|
John@72
|
83 end
|
John@72
|
84
|
John@73
|
85 local itemListListeners = {}
|
John@73
|
86 function RegisterItemListListener(listener)
|
John@73
|
87 table.insert(itemListListeners,listener)
|
John@73
|
88 end
|
John@73
|
89 function AlertItemListListeners()
|
John@73
|
90 for i,v in pairs(itemListListeners) do
|
John@73
|
91 print("item change")
|
John@73
|
92 v["ItemListEvent"](v)
|
John@73
|
93 end
|
John@73
|
94 end
|
John@73
|
95
|
John@73
|
96 function BeginLoot(packet)
|
John@73
|
97 local items, listValue = unpack(packet)
|
John@71
|
98 if state == "neutral" then
|
John@71
|
99 state = "looting"
|
John@73
|
100 stateactivelist = listValue
|
John@73
|
101 stateitemlist = items
|
John@73
|
102 AlertItemListListeners()
|
John@73
|
103 CreateGUI() -- todo: bad spot, but that's ok for now
|
John@71
|
104 else
|
John@71
|
105 _G.error("Bad state transition", state, "looting")
|
John@71
|
106 end
|
John@71
|
107 end
|
John@71
|
108
|
John@73
|
109 function InitiateBeginLoot(items,listValue)
|
John@73
|
110 if state == "neutral" then
|
John@73
|
111 Comm:SendStateChange("BL",items,listValue)
|
John@73
|
112 end
|
John@73
|
113 end
|
John@72
|
114
|
John@72
|
115 -- Activate List {{{
|
John@72
|
116 function ActivateList(packet) -- doesn't cause a transition, but we only enforce a list selection during certain times
|
John@72
|
117 local list = unpack(packet)
|
John@71
|
118 if state == "looting" then
|
John@72
|
119 stateactivelist = list
|
John@72
|
120 AlertActiveListChangedListeners()
|
John@71
|
121 end
|
John@71
|
122 end
|
John@71
|
123
|
John@72
|
124 function InitiateActivateList(list)
|
John@72
|
125 if state == "looting" then
|
John@72
|
126 Comm:SendStateChange("AL",list)
|
John@72
|
127 end
|
John@72
|
128 end
|
John@72
|
129 --}}}
|
John@72
|
130 -- Open Bidding {{{
|
John@71
|
131 function OpenBid(packet)
|
John@71
|
132 local item = unpack(packet)
|
John@73
|
133 if state == "looting" then
|
John@71
|
134 state = "bidding"
|
John@75
|
135 stateitem = item
|
John@73
|
136 AlertStateChangeListeners()
|
John@89
|
137 if admin and masterLooterIsMe then
|
John@81
|
138 local chan
|
John@81
|
139 if _G.GetNumRaidMembers() > 0 then chan = "RAID" else chan = "PARTY" end
|
John@81
|
140 _G.SendChatMessage("Bidding is now open for "..item.link.."!",chan)
|
John@81
|
141 _G.SendChatMessage("Whisper me \"bid\" to bid or \"roll\" to offset roll; \"retract\" will remove your bid",chan)
|
John@81
|
142 end
|
John@73
|
143 end
|
John@71
|
144 end
|
John@71
|
145
|
John@71
|
146 function InitiateOpenBid(item)
|
John@73
|
147 if state == "looting" then
|
John@73
|
148 Comm:SendStateChange("OB",item)
|
John@73
|
149 end
|
John@71
|
150 end
|
John@72
|
151 --}}}
|
John@72
|
152 -- Bid {{{
|
John@78
|
153 local function SortByList(lref,unordered)
|
John@78
|
154 local t = {}
|
John@78
|
155 for le in lref:OrderedListEntryIter() do
|
John@78
|
156 local lid = le:GetId()
|
John@78
|
157 for i,v in pairs(unordered) do
|
John@78
|
158 if v.value == lid then
|
John@78
|
159 print("Sort time: insert", lid)
|
John@78
|
160 table.insert(t,v)
|
John@78
|
161 table.remove(unordered,i)
|
John@78
|
162 break -- done with this inner iteration
|
John@78
|
163 end
|
John@78
|
164 end
|
John@78
|
165 end
|
John@78
|
166 if getn(t) > 0 then
|
John@78
|
167 for i,v in pairs(unordered) do
|
John@78
|
168 printf("Disregarding bid/roll from %s because they are not on the list", v.textPlain)
|
John@78
|
169 end
|
John@78
|
170 end
|
John@78
|
171 return t
|
John@78
|
172 end
|
John@79
|
173 local function SortByRoll(values,unordered)
|
John@79
|
174 local t = {}
|
John@79
|
175 for r = 100,1,-1 do -- 100:1
|
John@79
|
176 if values[r] then
|
John@79
|
177 for i,v in pairs(unordered) do
|
John@79
|
178 if v.value == values[r].value then
|
John@79
|
179 print("Sort time: insert", v.value, r)
|
John@79
|
180 table.insert(t,v)
|
John@79
|
181 table.remove(unordered,i)
|
John@79
|
182 break
|
John@79
|
183 end
|
John@79
|
184 end
|
John@79
|
185 end
|
John@79
|
186 end
|
John@79
|
187 if getn(t) > 0 then
|
John@79
|
188 for i,v in pairs(unordered) do
|
John@79
|
189 printf("Disregarding bid/roll from %s because they are not on the list", v.textPlain)
|
John@79
|
190 end
|
John@79
|
191 end
|
John@79
|
192 return t
|
John@79
|
193 end
|
John@71
|
194 function ReceivedBid(packet) -- no state transition, but only matters during one state
|
John@71
|
195 local person, roll = unpack(packet)
|
John@71
|
196
|
John@71
|
197 if state == "bidding" then
|
John@71
|
198 if roll then
|
John@79
|
199 table.insert(staterolls,person)
|
John@79
|
200 staterollvalues[roll] = person
|
John@79
|
201 staterolls = SortByRoll(staterollvalues,staterolls)
|
John@78
|
202 else
|
John@79
|
203 local lref = LootLists:Select(stateactivelist)
|
John@79
|
204 table.insert(statebids,person)
|
John@78
|
205 statebids = SortByList(lref,statebids)
|
John@71
|
206 end
|
John@71
|
207 AlertRollListeners()
|
John@89
|
208 if admin and masterLooterIsMe then
|
John@81
|
209 local leader
|
John@81
|
210 if getn(statebids) > 0 then
|
John@81
|
211 leader = statebids[1].textPlain
|
John@81
|
212 elseif getn(staterolls) > 0 then
|
John@81
|
213 leader = staterolls[1].textPlain
|
John@81
|
214 end
|
John@81
|
215
|
John@81
|
216 local chan -- todo: this idiom is wearing on me already
|
John@81
|
217 if _G.GetNumRaidMembers() > 0 then chan = "RAID" else chan = "PARTY" end
|
John@81
|
218
|
John@81
|
219 if roll then
|
John@81
|
220 _G.SendChatMessage(sformat("Received roll of %d from %s; current leader is %s", roll, person.textPlain, leader),chan)
|
John@81
|
221 else
|
John@81
|
222 _G.SendChatMessage(sformat("Received bid from %s; current leader is %s", person.textPlain, leader),chan) -- todo: tell what spot they're bidding from
|
John@81
|
223 end
|
John@81
|
224 end
|
John@71
|
225 end
|
John@71
|
226
|
John@71
|
227 -- else ignore ...
|
John@71
|
228 end
|
John@71
|
229
|
John@71
|
230 function InitiateBid(person,roll)
|
John@71
|
231 if state == "bidding" then
|
John@78
|
232 if not person then
|
John@78
|
233 print("You cannot bid becuase you are not on the list")
|
John@78
|
234 return
|
John@78
|
235 end
|
John@71
|
236 for i,v in pairs(statebids) do
|
John@78
|
237 if person and person.value == v.value then
|
John@71
|
238 print(person.value .. " is already on the list")
|
John@71
|
239 return -- no double adds please
|
John@71
|
240 end
|
John@71
|
241 end
|
John@79
|
242 for i,v in pairs(staterolls) do
|
John@79
|
243 if person and person.value == v.value then
|
John@79
|
244 print(person.value .. " is already on the list")
|
John@79
|
245 return -- no double adds please
|
John@79
|
246 end
|
John@79
|
247 end
|
John@71
|
248 Comm:SendStateChange("RB",person,roll)
|
John@71
|
249 end
|
John@71
|
250 end
|
John@72
|
251 --}}}
|
John@72
|
252 -- Retration {{{
|
John@71
|
253 function ReceivedRetraction(packet)
|
John@71
|
254 local person = unpack(packet)
|
John@71
|
255 if state == "bidding" then
|
John@71
|
256 for i,v in pairs(statebids) do
|
John@71
|
257 if v.value == person.value then
|
John@71
|
258 table.remove(statebids,i)
|
John@71
|
259 AlertRollListeners()
|
John@71
|
260 return
|
John@71
|
261 end
|
John@71
|
262 end
|
John@79
|
263 for i,v in pairs(staterolls) do
|
John@79
|
264 if v.value == person.value then
|
John@79
|
265 table.remove(staterolls,i)
|
John@79
|
266 AlertRollListeners()
|
John@79
|
267 return
|
John@79
|
268 end
|
John@79
|
269 end
|
John@71
|
270 end
|
John@71
|
271 end
|
John@71
|
272
|
John@71
|
273 function InitiateRetract(person)
|
John@71
|
274 if state == "bidding" then
|
John@81
|
275 Comm:SendStateChange("RR",person)
|
John@71
|
276 end
|
John@71
|
277 end
|
John@72
|
278 --}}}
|
John@72
|
279 -- Close Bidding {{{
|
John@89
|
280 function CloseBidding(packet)
|
John@89
|
281 local awardedTo = unpack(packet) -- todo: unused
|
John@75
|
282 if state == "bidding" then
|
John@75
|
283 state = "looting"
|
John@89
|
284 stateitem = nil
|
John@89
|
285 statebids = {}
|
John@89
|
286 staterolls = {}
|
John@89
|
287 staterollvalues = {}
|
John@75
|
288 AlertStateChangeListeners()
|
John@89
|
289 AlertItemListListeners()
|
John@81
|
290 -- todo: record history
|
John@81
|
291 if admin then
|
John@81
|
292 local chan -- todo: this idiom is wearing on me already
|
John@81
|
293 if _G.GetNumRaidMembers() > 0 then chan = "RAID" else chan = "PARTY" end
|
John@81
|
294 _G.SendChatMessage("Bidding is closed",chan)
|
John@81
|
295 end
|
John@75
|
296 end
|
John@71
|
297 end
|
John@71
|
298
|
John@72
|
299 function InitiateCloseBidding(awardedTo)
|
John@75
|
300 if state == "bidding" then
|
John@75
|
301 Comm:SendStateChange("CB",awardedTo)
|
John@75
|
302 end
|
John@72
|
303 end
|
John@72
|
304 --}}}
|
John@73
|
305 -- Close Looting {{{
|
John@72
|
306 function CloseLooting(packet)
|
John@71
|
307 state = "neutral"
|
John@73
|
308 stateactive = nil
|
John@73
|
309 stateitem = nil
|
John@73
|
310 stateitemlist = {}
|
John@73
|
311 statebids = {}
|
John@73
|
312 staterolls = {}
|
John@78
|
313 staterollvalues = {}
|
John@73
|
314 AlertStateChangeListeners()
|
John@73
|
315 AlertItemListListeners()
|
John@71
|
316 end
|
John@72
|
317
|
John@72
|
318 function InitiateCloseLooting()
|
John@72
|
319 Comm:SendStateChange("CL")
|
John@72
|
320 end
|
John@73
|
321 --}}}
|
John@79
|
322 function RollRequest(packet)
|
John@79
|
323 local person = unpack(packet)
|
John@79
|
324
|
John@89
|
325 if state == "bidding" and admin and masterLooterIsMe then
|
John@79
|
326 local roll
|
John@79
|
327 for i,v in pairs(staterollvalues) do
|
John@79
|
328 if v and v.value == person.value then
|
John@79
|
329 roll = i
|
John@79
|
330 break
|
John@79
|
331 end
|
John@79
|
332 end
|
John@79
|
333 if not roll then -- roll isn't on cache
|
John@79
|
334 repeat -- random until you find a good value
|
John@79
|
335 roll = _G.random(100)
|
John@79
|
336 until staterollvalues[roll] == nil
|
John@79
|
337 print("rolling! ", roll)
|
John@79
|
338 staterollvalues[roll] = person
|
John@79
|
339 end
|
John@79
|
340 InitiateBid(person,roll)
|
John@79
|
341 end
|
John@79
|
342 end
|
John@79
|
343 function InitiateRollRequest(person)
|
John@79
|
344 if state == "bidding" then
|
John@79
|
345 if not person then
|
John@79
|
346 print("You cannot bid becuase you are not on the list")
|
John@79
|
347 return
|
John@79
|
348 end
|
John@79
|
349 for i,v in pairs(staterolls) do
|
John@79
|
350 if person and person.value == v.value then
|
John@79
|
351 print(person.value .. " is already on the list")
|
John@79
|
352 return -- no double adds please
|
John@79
|
353 end
|
John@79
|
354 end
|
John@79
|
355 for i,v in pairs(statebids) do
|
John@79
|
356 if person and person.value == v.value then
|
John@79
|
357 print(person.value .. " is already on the list")
|
John@79
|
358 return -- no double adds please
|
John@79
|
359 end
|
John@79
|
360 end
|
John@79
|
361 Comm:SendStateChange("IR",person,roll)
|
John@79
|
362 end
|
John@79
|
363 end
|
John@82
|
364
|
John@82
|
365 local function LootSlotCleared(packet)
|
John@82
|
366 local index = unpack(packet)
|
John@82
|
367 if state == "looting" or state == "bidding" then
|
John@82
|
368 for i,v in pairs(stateitemlist) do
|
John@82
|
369 if v.mlid == index then
|
John@82
|
370 v.disabled = true
|
John@82
|
371 print("DISABLING")
|
John@82
|
372 AlertItemListListeners()
|
John@82
|
373 return
|
John@82
|
374 end
|
John@82
|
375 end
|
John@82
|
376 end
|
John@82
|
377 end
|
John@82
|
378 function InitiateLSClear(index)
|
John@82
|
379 if state == "looting" or state == "bidding" then
|
John@82
|
380 Comm:SendStateChange("SC",index)
|
John@82
|
381 end
|
John@82
|
382 end
|
John@72
|
383 function DispatchState(packet)
|
John@72
|
384 local state = table.remove(packet,1)
|
John@72
|
385 print("Dispatching", state)
|
John@72
|
386 if state == "RB" then
|
John@72
|
387 ReceivedBid(packet)
|
John@73
|
388 elseif state == "BL" then
|
John@73
|
389 BeginLoot(packet)
|
John@72
|
390 elseif state == "RR" then
|
John@72
|
391 ReceivedRetraction(packet)
|
John@72
|
392 elseif state == "OB" then
|
John@72
|
393 OpenBid(packet)
|
John@72
|
394 elseif state == "CB" then
|
John@72
|
395 CloseBidding(packet)
|
John@73
|
396 elseif state == "CL" then
|
John@72
|
397 CloseLooting(packet)
|
John@72
|
398 elseif state == "AL" then
|
John@72
|
399 ActivateList(packet)
|
John@79
|
400 elseif state == "IR" then
|
John@79
|
401 RollRequest(packet)
|
John@82
|
402 elseif state == "SC" then
|
John@82
|
403 LootSlotCleared(packet)
|
John@89
|
404 else
|
John@82
|
405 _G.error("Cannot dispatch message of type:",state)
|
John@72
|
406 end
|
John@72
|
407 end
|
John@72
|
408
|
John@73
|
409 function InitializeState()
|
John@79
|
410 -- basically, find a value for stateactivelist. it really doesn't matter
|
John@79
|
411 -- which one, but I decided on trying to choose one that has entries on it
|
John@79
|
412 -- so the whole thing isn't all empty. stateactivelist being anything
|
John@79
|
413 -- besides a valid ID could trigger errors
|
John@73
|
414 local ltemp = 0
|
John@73
|
415 local lids = LootLists:GetAllIds()
|
John@73
|
416 for _,v in pairs(lids) do
|
John@73
|
417 local l = LootLists:Select(v)
|
John@73
|
418 if l:GetLength() > 0 then
|
John@73
|
419 if ltemp == 0 then
|
John@73
|
420 ltemp = l:GetId()
|
John@73
|
421 end
|
John@73
|
422 end
|
John@73
|
423 end
|
John@73
|
424 stateactivelist = ltemp
|
John@73
|
425 end
|
John@73
|
426
|