· 6 years ago · Apr 19, 2019, 08:40 AM
1
2PASTEBIN
3new paste
4
5Guest User
6-
7SHARE
8TWEET
9Untitled
10a guest Apr 19th, 2019 0 Never
11NOTE: Your guest paste has been posted. If you sign up for a free account, you can edit and delete your pastes!
12rawdownloadcloneembedreportprint text 24.93 KB
13
14------------------------
15-- Collectable Trader --
16------------------------
17--- by my_hat_stinks ---
18------------------------
19
20-- If you're looking in this file, you probably want to know
21-- all the possible formats for collectable item descriptions.
22--
23--
24-- Details
25-- Collectable <append> - This is REQURIED on the first line of every collectable.
26-- `Collectible` is also acceptable.
27-- If you use the <append> value, it will be added to the end
28-- of the collectable's name in the trade menu. This allows you
29-- two have two separate listings for one item.
30--
31-- Cost <quantity> <name> - The cost for the item. If <quantity> is excluded, it will default
32-- to one of the listed item. <name> must match the required item
33-- name exactly, including formatting.
34-- Multiple Cost lines are allowed, all items will be required.
35-- If <name> matches a set, all items in that set are added to cost.
36--
37-- CostType <type> - Cost type, defaults to "all" if excluded. Only one CostType can be listed.
38-- All - All listed Cost items (including sets) are required to purchase
39-- this item.
40-- Any - Any listed Cost items (matching <quantity>) can be used to purchase
41-- this item.
42-- If a set is listed in Cost, <quantity> is the number of items from the
43-- set required to purchase this item.
44--
45-- Requires <name> - Items that are required, but NOT consumed, when purchasing this listing.
46-- Completely optional. <name> must match the required item name exactly,
47-- including formatting.
48-- `Require` is also acceptable.
49--
50-- Limit <quantity> - The user can't purchase another of this item if they already have <quantity>.
51-- If the item is part of a set, the limit counts for the entire set.
52--
53--
54-- SpawnAs <name> - Optional. Renames this item when it is spawned. Can include additional variables
55-- for dynamic names, case sensitive:
56-- {name} - Changes to the Steam name of the user.
57-- {id} - Changes to the Steam ID of the user.
58-- {color} - Changes to the color of the user at time of purchase.
59-- os.date() formatting is also available, eg "%Y-%b-%d" to mark the purchase date.
60--
61-- Category <Directory> - The menu this item should appear under. `>` indicates a sub-menu.
62-- Items without a Category will be listed on the main menu.
63-- Only one Category can be listed per item. Use Collectable <append>
64-- for additional listings.
65--
66-- Set <set name> - Optional. Marks this item as part of a set. Items do not need to be purchasable
67-- to be part of a set.
68--
69--
70-- Complete Example:
71--
72-- Collectable
73-- CostType: All
74-- Cost: 20 Collectable token
75-- Cost: Reward token
76-- Requires: [DEB444]Prestige 8[-]
77-- Require: Bankruptcy token
78-- Category: Main Directory > Sub Directory > Bottom Directory
79--
80
81
82TradeItems = {}
83
84DirectoryPath = {}
85
86ListData = {}
87ListReference = {}
88ListPage = 0
89ListTitle = ""
90
91AdminMode = false
92
93SpawnPos = { 1.168, 3.01, 0.02 }
94
95COST_ALL = 0
96COST_ANY = 1
97
98function onLoad()
99 refreshAllItems()
100
101 mainMenu()
102end
103function doNull() end
104
105
106-- Buy Item --
107--------------
108
109function spawnObject( item, c, spawnAs )
110 local ourColor = c and self.getName():lower():find(c:lower())
111
112 local params = {}
113 params.position = self.positionToWorld(SpawnPos)
114
115 local clone
116 if item.tag=="Infinite" then
117 clone = item.takeObject(params)
118 else
119 clone = item.clone(params)
120 end
121 clone.interactable = true
122 clone.setLock(false)
123 clone.setPosition(params.position)
124 clone.setDescription( ourColor and ("%s - %s"):format( Player[c].steam_id, Player[c].steam_name) or "" )
125
126 Wait.frames(function()
127 if (not clone) or clone==nil then return end
128
129 if clone.tag=="Bag" then
130 clone.reset()
131 end
132
133 if spawnAs and ourColor and Player[c].seated then
134 local newStr = os.date(spawnAs, os.time()):gsub("{name}", Player[c].steam_name):gsub("{id}", Player[c].steam_id):gsub("{color}", c)
135
136 clone.setName( newStr )
137 end
138 end, 0)
139end
140function buyItem( data, c )
141 if CooldownTime and CooldownTime>os.time() then return end
142
143 if not data.item then
144 broadcastToColor( "Something went wrong! (Item no longer exists)", c, {1,0.2,0.2} )
145 return
146 end
147
148 local ourColor = c and self.getName():lower():find(c:lower())
149
150 if ourColor then
151 if (not AdminMode) and Global.getVar("findObjectSetFromColor") then -- TODO: Support for non-blackjack tables?
152 local set = Global.call( "forwardFunction", {function_name="findObjectSetFromColor", data={c}} )
153
154 if not set then
155 broadcastToColor( "Something went wrong! (Your zones do not exist)", c, {1,0.2,0.2} )
156 return
157 end
158
159 local zoneObjects = set.zone.getObjects()
160 local tableObjects = set.tbl.getObjects()
161 local prestigeObjects = set.prestige.getObjects()
162
163 if data.req then
164 local req = {}
165 for i=1,#data.req do
166 req[data.req[i]] = true
167 end
168 for _,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
169 for _, obj in ipairs(zone) do
170 req[obj.getName():match("^%s*(.-)%s*$") or obj.getName() ] = nil
171 end
172 end
173
174 for missing in pairs(req) do
175 broadcastToColor( ("You need a %s on your table to buy this item."):format(tostring(missing)), c, {1,0.2,0.2} )
176 return
177 end
178 end
179
180 if data.cost then
181 if data.costType==COST_ANY then
182 if not processCostAny(c, data, set) then return end
183 else
184 if not processCostAll(c, data, set) then return end
185 end
186 end
187 end
188 elseif not AdminMode then
189 broadcastToColor( "You can't spawn items from other people's Traders. Toggle Admin Mode first.", c, {1,0.2,0.2} )
190 return
191 end
192
193 -- Cooldown to give objects a chance to be destroyed
194 CooldownTime = os.time() + 0.25
195 Wait.frames(function() CooldownTime = nil end, 1) -- Clear cooldown after 1 frames, time value is a failsafe
196
197 spawnObject( data.item, c, data.spawnAs )
198end
199
200function processCostAll( c, data, set )
201 local costData = data.cost
202
203 local missingCost = TranslateSetsToItems( CopyTable(costData) )
204 local foundStacks = {}
205
206 local sort = function(a,b)
207 return self.positionToLocal(a.getPosition()).z > self.positionToLocal(b.getPosition()).z
208 end
209 local zoneObjects = set.zone.getObjects() table.sort(zoneObjects, sort)
210 local tableObjects = set.tbl.getObjects() table.sort(tableObjects, sort)
211 local prestigeObjects = set.prestige.getObjects() table.sort(prestigeObjects, sort)
212
213 for _,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
214 -- for j, item in ipairs(zone) do
215 for i=1,#zone do
216 local item = zone[i]
217 local name = item.getName():match("^%s*(.-)%s*$") or item.getName()
218 if item and not (item==nil) and missingCost[name] and missingCost[name]>0 and item.interactable and not (item.getLock()) then
219 local count = item.getQuantity()
220 if count==-1 then count = 1 end
221
222 if item.tag=="Bag" then
223 count = 1
224 end
225
226 if count>missingCost[name] then
227 table.insert(foundStacks, {item, missingCost[name]})
228
229 missingCost[name] = nil
230 elseif count==missingCost[name] then
231 table.insert(foundStacks, {item})
232
233 missingCost[name] = nil
234 else
235 table.insert(foundStacks, {item})
236
237 missingCost[name] = (missingCost[name] or 0) - count
238 end
239 end
240 end
241 end
242
243 for missing,cost in pairs(missingCost) do -- Should only run if there's values left
244 broadcastToColor( ("You need %i more %s on your table to buy this item."):format(tonumber(cost) or 0, tostring(missing)), c, {1,0.2,0.2} )
245 return false
246 end
247
248 if exeedsLimits( data, {zoneObjects, tableObjects, prestigeObjects}, foundStacks ) then
249 broadcastToColor( "You have already reached your limit for this item.", c, {1,0.2,0.2} )
250 return false
251 end
252
253 local pos = self.getPosition()
254 pos.y = pos.y + 5
255
256 for i=1,#foundStacks do
257 local tbl = foundStacks[i]
258
259 if tbl[2] then
260 for i=1,tbl[2] do
261 local taken = tbl[1].takeObject( {position=pos, rotation={0,0,0}} )
262 destroyObject(taken)
263 end
264 else
265 destroyObject(tbl[1])
266 end
267 end
268
269 return true
270end
271function processCostAny( c, data, set )
272 local tblCost = data.cost
273
274 local missingFromSets = {}
275 local foundInSets = {}
276
277 for i=1,#tblCost do
278 local setName = tblCost[i][1]
279 local setCount = tblCost[i][2] or 1
280
281 if TradeSets[setName] then
282 missingFromSets[i] = {
283 Required = setCount,
284 Objects = {}
285 }
286
287 local tbl = missingFromSets[i].Objects
288 for objName,objCount in pairs(TradeSets[setName]) do
289 tbl[objName] = true
290 end
291 else
292 missingFromSets[i] = {
293 Required = setCount,
294 Objects = {
295 [setName] = true,
296 }
297 }
298 end
299 end
300
301 local foundStacks
302
303 local sort = function(a,b)
304 return self.positionToLocal(a.getPosition()).z > self.positionToLocal(b.getPosition()).z
305 end
306
307 local zoneObjects = set.zone.getObjects() table.sort(zoneObjects, sort)
308 local tableObjects = set.tbl.getObjects() table.sort(tableObjects, sort)
309 local prestigeObjects = set.prestige.getObjects() table.sort(prestigeObjects, sort)
310 local done = false
311
312 for _,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
313 -- for j, item in ipairs(zone) do
314 for i=1,#zone do
315 local item = zone[i]
316 local name = item.getName():match("^%s*(.-)%s*$") or item.getName()
317
318 for i=1,#missingFromSets do
319 local missingCost = missingFromSets[i]
320 foundInSets[i] = foundInSets[i] or {}
321
322 if missingCost.Objects[name] and missingCost.Required>0 and item.interactable and not (item.getLock()) then
323 local count = item.getQuantity()
324 if count==-1 then count = 1 end
325
326 if count>missingCost.Required then
327 table.insert(foundInSets[i], {item, missingCost.Required})
328
329 missingCost.Required = nil
330 elseif count==missingCost.Required then
331 table.insert(foundInSets[i], {item})
332
333 missingCost.Required = nil
334 else
335 table.insert(foundInSets[i], {item})
336
337 missingCost.Required = (missingCost.Required or 0) - count
338 end
339
340 if (not missingCost.Required) or missingCost.Required<=0 then
341 done = true
342
343 foundStacks = foundInSets[i] or {}
344
345 break
346 end
347 end
348 end
349 if done then break end
350 end
351 if done then break end
352 end
353
354 if not foundStacks then
355 broadcastToColor( "You don't have the necessary items on your table to buy this item.", c, {1,0.2,0.2} )
356 return false
357 end
358 if exeedsLimits( data, {zoneObjects, tableObjects, prestigeObjects}, foundStacks ) then
359 broadcastToColor( "You have already reached your limit for this item.", c, {1,0.2,0.2} )
360 return false
361 end
362
363 local pos = self.getPosition()
364 pos.y = pos.y + 5
365
366 for i=1,#foundStacks do
367 local tbl = foundStacks[i]
368
369 if tbl[2] then
370 for i=1,tbl[2] do
371 local taken = tbl[1].takeObject( {position=pos, rotation={0,0,0}} )
372 destroyObject(taken)
373 end
374 else
375 destroyObject(tbl[1])
376 end
377 end
378
379 return true
380end
381
382function exeedsLimits( data, zones, skipObjects )
383 if not data.limit then return false end
384
385 local restrictedObjects = {}
386
387 if data.item.tag=="Infinite" then
388 local clone = data.item.takeObject(params)
389 if clone then
390 restrictedObjects[clone.getName() or "[ITEM]"] = true
391 end
392 destroyObject(clone)
393 else
394 restrictedObjects[data.item.getName() or "[ITEM]"] = true
395 end
396
397 local limitLeft = data.limit
398 if data.sets then
399 for i=1,#data.sets do
400 for name in pairs(TradeSets[data.sets[i]] or {}) do
401 restrictedObjects[name] = true
402 end
403 end
404 end
405
406 for _,zone in pairs(zones) do
407 for j, item in ipairs(zone) do
408 local name = item.getName()
409
410 if restrictedObjects[name] then
411 local count = item.getQuantity()
412 if count==-1 then count = 1 end
413
414 if item.tag=="Bag" then
415 count = 1
416 end
417
418 for i=1,#skipObjects do
419 local tbl = skipObjects[i]
420
421 if tbl[1]==item then
422 if tbl[2] then
423 count = count - tbl[2]
424 else
425 count = count - 1
426 end
427 end
428 end
429
430 if count>0 then
431 limitLeft = limitLeft - count
432
433 if limitLeft<=0 then return true end
434 end
435 end
436 end
437 end
438 if limitLeft<= 0 then return true end
439
440 return false
441end
442
443-- Register Items --
444--------------------
445
446function clickAdminMode(o,c)
447 if not Player[c].admin then
448 printToColor( "You can't do this.", c, {1,0,0} )
449 return
450 end
451
452 AdminMode = not AdminMode
453 doMenu( ListPage )
454end
455function clickRefresh(o,c)
456 if not Player[c].admin then
457 printToColor( "You can't do this.", c, {1,0,0} )
458 return
459 end
460
461 refreshAllItems()
462end
463function refreshAllItems()
464 TradeItems = {}
465 TradeSets = {}
466
467 DirectoryPath = {}
468
469 ListData = {}
470 ListReference = {}
471 ListPage = 0
472
473 for _,obj in pairs(getAllObjects()) do
474 if obj.getDescription():match("^[Cc]ollect[ai]ble") then
475 registerItem( obj, obj.getDescription():match("^[Cc]ollect[ai]ble *([^\n]*)") )
476 end
477 end
478
479 mainMenu()
480end
481
482local TextToCostType = {
483 any = COST_ANY,
484 all = COST_ALL,
485}
486function registerItem( obj, appendName )
487 local desc = obj.getDescription()
488 local name = obj.getName() or "[ITEM]"
489
490 if obj.tag=="Infinite" then
491 local clone = obj.takeObject(params)
492 if clone then
493 name = clone.getName() or name
494 end
495 destroyObject(clone)
496 end
497
498 if appendName then
499 name = name .. " " .. tostring(appendName)
500 end
501
502
503 local CostType = COST_ALL
504 local hasCost = false
505 for foundType in desc:gmatch("[Cc]ost[Tt]ype:? *([^\n]+)") do
506 foundType = foundType:match("^%s*(.-)%s*$") or foundType
507
508 CostType = TextToCostType[ foundType:lower() ] or CostType
509 end
510
511 local cost = {}
512 local hasCost = false
513 for num,item in desc:gmatch("[Cc]ost:? +(%d*)x? *([^\n]+)") do
514 num = tonumber(num) or 1
515 if item then
516 hasCost = true
517 item = item:match("^%s*(.-)%s*$") or item
518
519 if CostType==COST_ALL then
520 cost[item] = (cost[item] or 0) + num
521 elseif CostType==COST_ANY then
522 table.insert(cost, {item,num})
523 end
524 end
525 end
526 if not hasCost then -- No cost, can't buy
527 registerSet( obj )
528 return
529 end
530
531 local req = {}
532 for foundReq in desc:gmatch("[Rr]equires?:? *([^\n]+)") do
533 foundReq = foundReq:match("^%s*(.-)%s*$") or foundReq
534 table.insert(req, foundReq)
535 end
536 if #req==0 then
537 req = nil
538 end
539
540 local spawnAs = ""
541 for foundName in desc:gmatch("[Ss]pawn[Aa]s?:? *([^\n]+)") do
542 spawnAs = foundName:match("^%s*(.-)%s*$") or foundName
543 break
544 end
545 if #spawnAs==0 then
546 spawnAs = nil
547 end
548
549 local limit = nil
550 for foundLimit in desc:gmatch("[Ll]imit:? *(%d+)") do
551 limit = tonumber(foundLimit) or 0
552 break
553 end
554
555 local workingDir = TradeItems
556
557 local cat = desc:match("[Cc]ategory:? *([^\n]+)")
558 if cat then
559 local exploded = {}
560
561 local str = cat
562 local s,e,before,after = str:find("^([^>]*)>(.*)$")
563 while s and e do
564 before = before:match( "^%s*(.+)$" ) or before
565
566 -- before = before:match( "^(.-)%s*$" ) or before -- "Too complex", apparently.
567 local posTrailingSpaces = before:find("%s*$")
568 if posTrailingSpaces then
569 before = before:sub(1,posTrailingSpaces-1)
570 end
571 if #before>0 then table.insert(exploded, before) end
572
573 str = after
574 s,e,before,after = str:find("^([^>]*)>(.*)$")
575 end
576
577 str = str:match( "^%s*(.+)$" ) or str
578 local posTrailingSpaces = str:find("%s*$")
579 if posTrailingSpaces then
580 str = str:sub(1,posTrailingSpaces-1)
581 end
582 if #str>0 then table.insert(exploded, str) end
583
584 for i=1,#exploded do
585 if not exploded[i] then break end
586
587 if (not workingDir[exploded[i]]) or (workingDir[exploded[i]].IsTraderItem) then -- Empty or an item, replace with category
588 workingDir[exploded[i]] = {}
589 end
590 workingDir = workingDir[exploded[i]]
591 end
592 end
593
594 workingDir[ name ] = {
595 IsTraderItem = true,
596 item = obj,
597
598 costType = CostType,
599 cost = cost,
600
601 req = req,
602
603 spawnAs = spawnAs,
604 limit = limit,
605 sets = registerSet( obj ),
606 }
607end
608function registerSet( obj )
609 local desc = obj.getDescription()
610 local name = obj.getName() or "[ITEM]"
611
612 if obj.tag=="Infinite" then
613 local clone = obj.takeObject(params)
614 if clone then
615 name = clone.getName() or name
616 end
617 destroyObject(clone)
618 end
619
620 local sets = {}
621 local hasSets = false
622 for num,setName in desc:gmatch("Set:? *(%d*)x? *([^\n]+)") do
623 num = tonumber(num) or 1
624 if setName then
625 sets[setName] = (sets[setName] or 0) + num
626 hasSets = true
627 end
628 end
629 if not hasSets then return end -- Not part of a set
630
631 local inSets = {}
632 for setName,num in pairs(sets) do
633 TradeSets[setName] = TradeSets[setName] or {}
634
635 TradeSets[setName][name] = num
636 table.insert(inSets, setName)
637 end
638
639 return inSets
640end
641
642
643-- Cost To String --
644--------------------
645
646function getCostString( costTable, costType )
647 if not costTable then return "" end
648
649 local str = ""
650 local orderedCost = {}
651 if costType==COST_ANY then
652 orderedCost = CopyTable(costTable)
653 else
654 for item,num in pairs(costTable) do
655 table.insert( orderedCost, {item,num} )
656 end
657 end
658 table.sort( orderedCost, function(a,b)
659 if a[2]==b[2] then
660 return a[1]<b[1]
661 end
662 return a[2]<b[2]
663 end)
664
665 for i=1,#orderedCost do
666 str = str .. ("%s%i %s[b]%s[/b]"):format(
667 (i==1 and "") or (i==#orderedCost and (costType==COST_ANY and ", or " or ", and ")) or ", ",
668 orderedCost[i][2],
669 costType==COST_ANY and TradeSets[ orderedCost[i][1] ] and "from " or "",
670 orderedCost[i][1]
671 )
672 end
673
674 return str
675end
676
677
678-- Menu --
679----------
680
681function doListData()
682 for k in pairs(ListReference) do
683 table.insert(ListData, k)
684 end
685 table.sort(ListData, function(a,b)
686 if ListReference[a].IsTraderItem and not ListReference[b].IsTraderItem then return false end
687 if ListReference[b].IsTraderItem and not ListReference[a].IsTraderItem then return true end
688
689 return a<b
690 end)
691end
692
693function clickMainMenu(o,c)
694 local ourColor = c and self.getName():lower():find(c:lower())
695 if not (c and (Player[c].admin or ourColor)) then
696 broadcastToColor( "This does not belong to you.", c, {1,0.2,0.2} )
697 return
698 end
699
700 mainMenu()
701end
702function mainMenu()
703 ListTitle = "Collectable Trader"
704 ListReference = TradeItems
705 ListData = {}
706
707 DirectoryPath = {}
708
709 doListData()
710
711 doMenu( 1 )
712end
713
714function doMenu(page)
715 self.clearButtons()
716 self.clearInputs()
717
718 ListPage = page or 1
719
720 -- Title
721 self.createButton({
722 label=ListTitle, click_function="doNull", function_owner=self, scale = {0.5,0.5,0.5},
723 position={1.2, 0.25, -1.23}, rotation={0,0,0}, width=0, height=0, font_size=170,
724 font_color = {r=1,g=1,b=1},
725 })
726
727 Targets = {}
728
729 local displayFrom = (ListPage-1)*10
730 -- List Page
731 for i=1,10 do
732 local data = ListData[displayFrom + i]
733
734 if not (data and ListReference[data]) then break end
735
736 local zpos = -1.17 + (i * 0.21)
737 local col = AdminMode and {r=1,g=0.1,b=0.1} or {r=1,b=1,g=1}
738
739 -- Button
740 if ListReference[data].IsTraderItem then
741 self.createButton({
742 label= ("[b][u]%s[/u][/b]\n%s"):format( data, getCostString(ListReference[data].cost, ListReference[data].costType) ), click_function="doAction"..i, function_owner=self, scale = {0.5,0.5,0.5},
743 position={1.2, 0.25, zpos}, rotation={0,0,0}, width=1800, height=220, font_size=80,
744 color = col
745 })
746 else
747 self.createButton({
748 label= ("[b]%s[b] >"):format( data ), click_function="doAction"..i, function_owner=self, scale = {0.5,0.5,0.5},
749 position={1.2, 0.25, zpos}, rotation={0,0,0}, width=1800, height=220, font_size=80,
750 color = col
751 })
752 end
753 end
754
755
756 -- Page Navigaton
757 local pageStr = ("Page %i of %i"):format( ListPage, math.ceil(#ListData/10) )
758 self.createButton({
759 label=pageStr, click_function="doNull", function_owner=self, scale = {0.5,0.5,0.5},
760 position={1.2, 0.25, 1.12}, rotation={0,0,0}, width=0, height=0, font_size=100,
761 font_color = {r=1,g=1,b=1},
762 })
763
764 self.createButton({
765 label="<", click_function="PrevPage", function_owner=self, scale = {1,1,1}, scale = {0.5,0.5,0.5},
766 position={0.7, 0.25, 1.12}, rotation={0,0,0}, width=100, height=100, font_size=80,
767 color = ListPage==1 and {0.5,0.5,0.5} or {1,1,1}
768 })
769 self.createButton({
770 label=">", click_function="NextPage", function_owner=self, scale = {1,1,1}, scale = {0.5,0.5,0.5},
771 position={1.7, 0.25, 1.12}, rotation={0,0,0}, width=100, height=100, font_size=80,
772 color = ListPage>=math.ceil(#ListData/10) and {0.5,0.5,0.5} or {1,1,1}
773 })
774
775
776 if #DirectoryPath>0 then
777 -- Return
778 self.createButton({
779 label="Back", click_function="clickBack", function_owner=self, scale = {1,1,1}, scale = {0.5,0.5,0.5},
780 position={1.3, 0.25, 1.32}, rotation={0,0,0}, width=450, height=150, font_size=80,
781 })
782 self.createButton({
783 label="Main Menu", click_function="clickMainMenu", function_owner=self, scale = {1,1,1}, scale = {0.5,0.5,0.5},
784 position={1.8, 0.25, 1.32}, rotation={0,0,0}, width=450, height=150, font_size=80,
785 })
786 end
787
788 -- Admin
789 self.createButton({
790 label="Admin Mode", click_function="clickAdminMode", function_owner=self, scale = {1,1,1}, scale = {0.3,0.3,0.3},
791 position={0.2, 0.25, -1.33}, rotation={0,0,0}, width=450, height=50, font_size=70,
792 color = AdminMode and {r=1,g=0,b=0} or {r=0.25,g=0.25,b=0.25},
793 })
794 self.createButton({
795 label="Reload", click_function="clickRefresh", function_owner=self, scale = {1,1,1}, scale = {0.3,0.3,0.3},
796 position={0.2, 0.25, -1.23}, rotation={0,0,0}, width=450, height=50, font_size=70,
797 color = {r=0.25,g=0.25,b=0.25},
798 })
799end
800
801
802-- Actions --
803-------------
804function doAction( index, c )
805 local ourColor = c and self.getName():lower():find(c:lower())
806 if not (c and (Player[c].admin or ourColor)) then
807 broadcastToColor( "This does not belong to you.", c, {1,0.2,0.2} )
808 return
809 end
810
811 local trueIndex = index + (ListPage-1)*10
812 local data = ListData[trueIndex]
813 local ref = data and ListReference[data]
814
815 if not ref then
816 broadcastToColor( "Something went wrong! (Button reference is missing)", c, {1,0.2,0.2} )
817 mainMenu()
818 return
819 end
820
821 if ref.IsTraderItem then
822 buyItem( ref, c )
823
824 return
825 end
826
827 table.insert(DirectoryPath, data)
828 ListReference = ref
829 ListPage = 0
830 ListTitle = data
831 ListData = {}
832
833 doListData()
834
835 doMenu(1)
836end
837for i=1,10 do
838 _G["doAction"..i] = function(o,c) return doAction(i,c) end
839end
840
841function clickBack(o,c)
842 local ourColor = c and self.getName():lower():find(c:lower())
843 if not (c and (Player[c].admin or ourColor)) then
844 broadcastToColor( "This does not belong to you.", c, {1,0.2,0.2} )
845 return
846 end
847
848 table.remove(DirectoryPath)
849 if #DirectoryPath==0 then
850 mainMenu()
851 return
852 end
853
854 local workingDir = TradeItems
855 for i=1,#DirectoryPath do
856 local newDir = workingDir[DirectoryPath[i]]
857 if newDir and not newDir.IsTraderItem then
858 workingDir = newDir
859 else
860 while #DirectoryPath>=i do
861 table.remove(DirectoryPath)
862 end
863 break
864 end
865 end
866 if #DirectoryPath==0 then
867 mainMenu()
868 return
869 end
870
871 ListReference = workingDir
872 ListPage = 0
873 ListTitle = DirectoryPath[#DirectoryPath]
874 ListData = {}
875
876 doListData()
877
878 doMenu(1)
879end
880
881function NextPage(o,c)
882 local ourColor = c and self.getName():lower():find(c:lower())
883 if not (c and (Player[c].admin or ourColor)) then
884 broadcastToColor( "This does not belong to you.", c, {1,0.2,0.2} )
885 return
886 end
887
888 local maxPage = math.max( math.ceil(#ListData/10), 1 )
889
890 doMenu( math.min(ListPage+1, maxPage) )
891end
892function PrevPage(o,c)
893 local ourColor = c and self.getName():lower():find(c:lower())
894 if not (c and (Player[c].admin or ourColor)) then
895 broadcastToColor( "This does not belong to you.", c, {1,0.2,0.2} )
896 return
897 end
898
899 doMenu( math.max(ListPage-1, 1) )
900end
901
902-- Util --
903----------
904
905function CopyTable(from)
906 local to = {}
907 for k,v in pairs(from) do
908 to[k]=v
909 end
910 return to
911end
912function TranslateSetsToItems( tbl )
913 for setName,setCount in pairs(tbl) do
914 if TradeSets[setName] then
915 for objName,objCount in pairs(TradeSets[setName]) do
916 tbl[objName] = (tbl[objName] or 0) + ((objCount or 1) * (setCount or 1))
917 end
918 tbl[setName] = nil
919 end
920 end
921
922 return tbl
923end
924
925function PrintTable( tbl, indent, skipTables )
926 indent = indent or 0
927 skipTables = skipTables or {[tbl]=true}
928
929 for k,v in pairs(tbl) do
930 if type(v)=="table" and not skipTables[v] then
931 skipTables[v]=true
932 print( (" "):rep(indent+1), "\"",k,"\" = {" )
933 PrintTable(v, indent+1, skipTables)
934 print( (" "):rep(indent+1), "}" )
935 else
936 print( (" "):rep(indent+1), "\"", k, "\" = ", v )
937 end
938 end
939
940 end
941
942RAW Paste Data
943------------------------
944-- Collectable Trader --
945------------------------
946--- by my_hat_stinks ---
947------------------------
948
949-- If you're looking in this file, you probably want to know
950-- all the possible formats for collectable item descriptions.
951--
952--
953-- Details
954-- Collectable <append> - This is REQURIED on the first line of every collectable.
955-- `Collectible` is also acceptable.
956-- If you use the <append> value, it will be added to the end
957-- of the collectable's name in the trade menu. This allows you
958-- two have two separate listings for one item.
959--
960-- Cost <quantity> <name> - The cost for the item. If <quantity> is excluded, it will default
961-- to one of the listed item. <name> must match the required item
962-- name exactly, including formatting.
963-- Multiple Cost lines are allowed, all items will be required.
964-- If <name> matches a set, all items in that set are added to cost.
965--
966-- CostType <type> - Cost type, defaults to "all" if excluded. Only one CostType can be listed.
967-- All - All listed Cost items (including sets) are required to purchase
968-- this item.
969-- Any - Any listed Cost items (matching <quantity>) can be used to purchase
970-- this item.
971-- If a set is listed in Cost, <quantity> is the number of items from the
972-- set required to purchase this item.
973--
974-- Requires <name> - Items that are required, but NOT consumed, when purchasing this listing.
975-- Completely optional. <name> must match the required item name exactly,
976-- including formatting.
977-- `Require` is also acceptable.
978--
979-- Limit <quantity> - The user can't purchase another of this item if they already have <quantity>.
980-- If the item is part of a set, the limit counts for the entire set.
981--
982--
983-- SpawnAs <name> - Optional. Renames this item when it is spawned. Can include additional variables
984-- for dynamic names, case sensitive:
985-- {name} - Changes to the Steam name of the user.
986-- {id} - Changes to the Steam ID of the user.
987-- {color} - Changes to the color of the user at time of purchase.
988-- os.date() formatting is also available, eg "%Y-%b-%d" to mark the purchase date.
989--
990-- Category <Directory> - The menu this item should appear under. `>` indicates a sub-menu.
991-- Items without a Category will be listed on the main menu.
992-- Only one Category can be listed per item. Use Collectable <append>
993-- for additional listings.
994--
995-- Set <set name> - Optional. Marks this item as part of a set. Items do not need to be purchasable
996-- to be part of a set.
997--
998--
999-- Complete Example:
1000--
1001-- Collectable
1002-- CostType: All
1003-- Cost: 20 Collectable token
1004-- Cost: Reward token
1005-- Requires: [DEB444]Prestige 8[-]
1006-- Require: Bankruptcy token
1007-- Category: Main Directory > Sub Directory > Bottom Directory
1008--
1009
1010
1011TradeItems = {}
1012
1013DirectoryPath = {}
1014
1015ListData = {}
1016ListReference = {}
1017ListPage = 0
1018ListTitle = ""
1019
1020AdminMode = false
1021
1022SpawnPos = { 1.168, 3.01, 0.02 }
1023
1024COST_ALL = 0
1025COST_ANY = 1
1026
1027function onLoad()
1028 refreshAllItems()
1029
1030 mainMenu()
1031end
1032function doNull() end
1033
1034
1035-- Buy Item --
1036--------------
1037
1038function spawnObject( item, c, spawnAs )
1039 local ourColor = c and self.getName():lower():find(c:lower())
1040
1041 local params = {}
1042 params.position = self.positionToWorld(SpawnPos)
1043
1044 local clone
1045 if item.tag=="Infinite" then
1046 clone = item.takeObject(params)
1047 else
1048 clone = item.clone(params)
1049 end
1050 clone.interactable = true
1051 clone.setLock(false)
1052 clone.setPosition(params.position)
1053 clone.setDescription( ourColor and ("%s - %s"):format( Player[c].steam_id, Player[c].steam_name) or "" )
1054
1055 Wait.frames(function()
1056 if (not clone) or clone==nil then return end
1057
1058 if clone.tag=="Bag" then
1059 clone.reset()
1060 end
1061
1062 if spawnAs and ourColor and Player[c].seated then
1063 local newStr = os.date(spawnAs, os.time()):gsub("{name}", Player[c].steam_name):gsub("{id}", Player[c].steam_id):gsub("{color}", c)
1064
1065 clone.setName( newStr )
1066 end
1067 end, 0)
1068end
1069function buyItem( data, c )
1070 if CooldownTime and CooldownTime>os.time() then return end
1071
1072 if not data.item then
1073 broadcastToColor( "Something went wrong! (Item no longer exists)", c, {1,0.2,0.2} )
1074 return
1075 end
1076
1077 local ourColor = c and self.getName():lower():find(c:lower())
1078
1079 if ourColor then
1080 if (not AdminMode) and Global.getVar("findObjectSetFromColor") then -- TODO: Support for non-blackjack tables?
1081 local set = Global.call( "forwardFunction", {function_name="findObjectSetFromColor", data={c}} )
1082
1083 if not set then
1084 broadcastToColor( "Something went wrong! (Your zones do not exist)", c, {1,0.2,0.2} )
1085 return
1086 end
1087
1088 local zoneObjects = set.zone.getObjects()
1089 local tableObjects = set.tbl.getObjects()
1090 local prestigeObjects = set.prestige.getObjects()
1091
1092 if data.req then
1093 local req = {}
1094 for i=1,#data.req do
1095 req[data.req[i]] = true
1096 end
1097 for _,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
1098 for _, obj in ipairs(zone) do
1099 req[obj.getName():match("^%s*(.-)%s*$") or obj.getName() ] = nil
1100 end
1101 end
1102
1103 for missing in pairs(req) do
1104 broadcastToColor( ("You need a %s on your table to buy this item."):format(tostring(missing)), c, {1,0.2,0.2} )
1105 return
1106 end
1107 end
1108
1109 if data.cost then
1110 if data.costType==COST_ANY then
1111 if not processCostAny(c, data, set) then return end
1112 else
1113 if not processCostAll(c, data, set) then return end
1114 end
1115 end
1116 end
1117 elseif not AdminMode then
1118 broadcastToColor( "You can't spawn items from other people's Traders. Toggle Admin Mode first.", c, {1,0.2,0.2} )
1119 return
1120 end
1121
1122 -- Cooldown to give objects a chance to be destroyed
1123 CooldownTime = os.time() + 0.25
1124 Wait.frames(function() CooldownTime = nil end, 1) -- Clear cooldown after 1 frames, time value is a failsafe
1125
1126 spawnObject( data.item, c, data.spawnAs )
1127end
1128
1129function processCostAll( c, data, set )
1130 local costData = data.cost
1131
1132 local missingCost = TranslateSetsToItems( CopyTable(costData) )
1133 local foundStacks = {}
1134
1135 local sort = function(a,b)
1136 return self.positionToLocal(a.getPosition()).z > self.positionToLocal(b.getPosition()).z
1137 end
1138 local zoneObjects = set.zone.getObjects() table.sort(zoneObjects, sort)
1139 local tableObjects = set.tbl.getObjects() table.sort(tableObjects, sort)
1140 local prestigeObjects = set.prestige.getObjects() table.sort(prestigeObjects, sort)
1141
1142 for _,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
1143 -- for j, item in ipairs(zone) do
1144 for i=1,#zone do
1145 local item = zone[i]
1146 local name = item.getName():match("^%s*(.-)%s*$") or item.getName()
1147 if item and not (item==nil) and missingCost[name] and missingCost[name]>0 and item.interactable and not (item.getLock()) then
1148 local count = item.getQuantity()
1149 if count==-1 then count = 1 end
1150
1151 if item.tag=="Bag" then
1152 count = 1
1153 end
1154
1155 if count>missingCost[name] then
1156 table.insert(foundStacks, {item, missingCost[name]})
1157
1158 missingCost[name] = nil
1159 elseif count==missingCost[name] then
1160 table.insert(foundStacks, {item})
1161
1162 missingCost[name] = nil
1163 else
1164 table.insert(foundStacks, {item})
1165
1166 missingCost[name] = (missingCost[name] or 0) - count
1167 end
1168 end
1169 end
1170 end
1171
1172 for missing,cost in pairs(missingCost) do -- Should only run if there's values left
1173 broadcastToColor( ("You need %i more %s on your table to buy this item."):format(tonumber(cost) or 0, tostring(missing)), c, {1,0.2,0.2} )
1174 return false
1175 end
1176
1177 if exeedsLimits( data, {zoneObjects, tableObjects, prestigeObjects}, foundStacks ) then
1178 broadcastToColor( "You have already reached your limit for this item.", c, {1,0.2,0.2} )
1179 return false
1180 end
1181
1182 local pos = self.getPosition()
1183 pos.y = pos.y + 5
1184
1185 for i=1,#foundStacks do
1186 local tbl = foundStacks[i]
1187
1188 if tbl[2] then
1189 for i=1,tbl[2] do
1190 local taken = tbl[1].takeObject( {position=pos, rotation={0,0,0}} )
1191 destroyObject(taken)
1192 end
1193 else
1194 destroyObject(tbl[1])
1195 end
1196 end
1197
1198 return true
1199end
1200function processCostAny( c, data, set )
1201 local tblCost = data.cost
1202
1203 local missingFromSets = {}
1204 local foundInSets = {}
1205
1206 for i=1,#tblCost do
1207 local setName = tblCost[i][1]
1208 local setCount = tblCost[i][2] or 1
1209
1210 if TradeSets[setName] then
1211 missingFromSets[i] = {
1212 Required = setCount,
1213 Objects = {}
1214 }
1215
1216 local tbl = missingFromSets[i].Objects
1217 for objName,objCount in pairs(TradeSets[setName]) do
1218 tbl[objName] = true
1219 end
1220 else
1221 missingFromSets[i] = {
1222 Required = setCount,
1223 Objects = {
1224 [setName] = true,
1225 }
1226 }
1227 end
1228 end
1229
1230 local foundStacks
1231
1232 local sort = function(a,b)
1233 return self.positionToLocal(a.getPosition()).z > self.positionToLocal(b.getPosition()).z
1234 end
1235
1236 local zoneObjects = set.zone.getObjects() table.sort(zoneObjects, sort)
1237 local tableObjects = set.tbl.getObjects() table.sort(tableObjects, sort)
1238 local prestigeObjects = set.prestige.getObjects() table.sort(prestigeObjects, sort)
1239 local done = false
1240
1241 for _,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
1242 -- for j, item in ipairs(zone) do
1243 for i=1,#zone do
1244 local item = zone[i]
1245 local name = item.getName():match("^%s*(.-)%s*$") or item.getName()
1246
1247 for i=1,#missingFromSets do
1248 local missingCost = missingFromSets[i]
1249 foundInSets[i] = foundInSets[i] or {}
1250
1251 if missingCost.Objects[name] and missingCost.Required>0 and item.interactable and not (item.getLock()) then
1252 local count = item.getQuantity()
1253 if count==-1 then count = 1 end
1254
1255 if count>missingCost.Required then
1256 table.insert(foundInSets[i], {item, missingCost.Required})
1257
1258 missingCost.Required = nil
1259 elseif count==missingCost.Required then
1260 table.insert(foundInSets[i], {item})
1261
1262 missingCost.Required = nil
1263 else
1264 table.insert(foundInSets[i], {item})
1265
1266 missingCost.Required = (missingCost.Required or 0) - count
1267 end
1268
1269 if (not missingCost.Required) or missingCost.Required<=0 then
1270 done = true
1271
1272 foundStacks = foundInSets[i] or {}
1273
1274 break
1275 end
1276 end
1277 end
1278 if done then break end
1279 end
1280 if done then break end
1281 end
1282
1283 if not foundStacks then
1284 broadcastToColor( "You don't have the necessary items on your table to buy this item.", c, {1,0.2,0.2} )
1285 return false
1286 end
1287 if exeedsLimits( data, {zoneObjects, tableObjects, prestigeObjects}, foundStacks ) then
1288 broadcastToColor( "You have already reached your limit for this item.", c, {1,0.2,0.2} )
1289 return false
1290 end
1291
1292 local pos = self.getPosition()
1293 pos.y = pos.y + 5
1294
1295 for i=1,#foundStacks do
1296 local tbl = foundStacks[i]
1297
1298 if tbl[2] then
1299 for i=1,tbl[2] do
1300 local taken = tbl[1].takeObject( {position=pos, rotation={0,0,0}} )
1301 destroyObject(taken)
1302 end
1303 else
1304 destroyObject(tbl[1])
1305 end
1306 end
1307
1308 return true
1309end
1310
1311function exeedsLimits( data, zones, skipObjects )
1312 if not data.limit then return false end
1313
1314 local restrictedObjects = {}
1315
1316 if data.item.tag=="Infinite" then
1317 local clone = data.item.takeObject(params)
1318 if clone then
1319 restrictedObjects[clone.getName() or "[ITEM]"] = true
1320 end
1321 destroyObject(clone)
1322 else
1323 restrictedObjects[data.item.getName() or "[ITEM]"] = true
1324 end
1325
1326 local limitLeft = data.limit
1327 if data.sets then
1328 for i=1,#data.sets do
1329 for name in pairs(TradeSets[data.sets[i]] or {}) do
1330 restrictedObjects[name] = true
1331 end
1332 end
1333 end
1334
1335 for _,zone in pairs(zones) do
1336 for j, item in ipairs(zone) do
1337 local name = item.getName()
1338
1339 if restrictedObjects[name] then
1340 local count = item.getQuantity()
1341 if count==-1 then count = 1 end
1342
1343 if item.tag=="Bag" then
1344 count = 1
1345 end
1346
1347 for i=1,#skipObjects do
1348 local tbl = skipObjects[i]
1349
1350 if tbl[1]==item then
1351 if tbl[2] then
1352 count = count - tbl[2]
1353 else
1354 count = count - 1
1355 end
1356 end
1357 end
1358
1359 if count>0 then
1360 limitLeft = limitLeft - count
1361
1362 if limitLeft<=0 then return true end
1363 end
1364 end
1365 end
1366 end
1367 if limitLeft<= 0 then return true end
1368
1369 return false
1370end
1371
1372-- Register Items --
1373--------------------
1374
1375function clickAdminMode(o,c)
1376 if not Player[c].admin then
1377 printToColor( "You can't do this.", c, {1,0,0} )
1378 return
1379 end
1380
1381 AdminMode = not AdminMode
1382 doMenu( ListPage )
1383end
1384function clickRefresh(o,c)
1385 if not Player[c].admin then
1386 printToColor( "You can't do this.", c, {1,0,0} )
1387 return
1388 end
1389
1390 refreshAllItems()
1391end
1392function refreshAllItems()
1393 TradeItems = {}
1394 TradeSets = {}
1395
1396 DirectoryPath = {}
1397
1398 ListData = {}
1399 ListReference = {}
1400 ListPage = 0
1401
1402 for _,obj in pairs(getAllObjects()) do
1403 if obj.getDescription():match("^[Cc]ollect[ai]ble") then
1404 registerItem( obj, obj.getDescription():match("^[Cc]ollect[ai]ble *([^\n]*)") )
1405 end
1406 end
1407
1408 mainMenu()
1409end
1410
1411local TextToCostType = {
1412 any = COST_ANY,
1413 all = COST_ALL,
1414}
1415function registerItem( obj, appendName )
1416 local desc = obj.getDescription()
1417 local name = obj.getName() or "[ITEM]"
1418
1419 if obj.tag=="Infinite" then
1420 local clone = obj.takeObject(params)
1421 if clone then
1422 name = clone.getName() or name
1423 end
1424 destroyObject(clone)
1425 end
1426
1427 if appendName then
1428 name = name .. " " .. tostring(appendName)
1429 end
1430
1431
1432 local CostType = COST_ALL
1433 local hasCost = false
1434 for foundType in desc:gmatch("[Cc]ost[Tt]ype:? *([^\n]+)") do
1435 foundType = foundType:match("^%s*(.-)%s*$") or foundType
1436
1437 CostType = TextToCostType[ foundType:lower() ] or CostType
1438 end
1439
1440 local cost = {}
1441 local hasCost = false
1442 for num,item in desc:gmatch("[Cc]ost:? +(%d*)x? *([^\n]+)") do
1443 num = tonumber(num) or 1
1444 if item then
1445 hasCost = true
1446 item = item:match("^%s*(.-)%s*$") or item
1447
1448 if CostType==COST_ALL then
1449 cost[item] = (cost[item] or 0) + num
1450 elseif CostType==COST_ANY then
1451 table.insert(cost, {item,num})
1452 end
1453 end
1454 end
1455 if not hasCost then -- No cost, can't buy
1456 registerSet( obj )
1457 return
1458 end
1459
1460 local req = {}
1461 for foundReq in desc:gmatch("[Rr]equires?:? *([^\n]+)") do
1462 foundReq = foundReq:match("^%s*(.-)%s*$") or foundReq
1463 table.insert(req, foundReq)
1464 end
1465 if #req==0 then
1466 req = nil
1467 end
1468
1469 local spawnAs = ""
1470 for foundName in desc:gmatch("[Ss]pawn[Aa]s?:? *([^\n]+)") do
1471 spawnAs = foundName:match("^%s*(.-)%s*$") or foundName
1472 break
1473 end
1474 if #spawnAs==0 then
1475 spawnAs = nil
1476 end
1477
1478 local limit = nil
1479 for foundLimit in desc:gmatch("[Ll]imit:? *(%d+)") do
1480 limit = tonumber(foundLimit) or 0
1481 break
1482 end
1483
1484 local workingDir = TradeItems
1485
1486 local cat = desc:match("[Cc]ategory:? *([^\n]+)")
1487 if cat then
1488 local exploded = {}
1489
1490 local str = cat
1491 local s,e,before,after = str:find("^([^>]*)>(.*)$")
1492 while s and e do
1493 before = before:match( "^%s*(.+)$" ) or before
1494
1495 -- before = before:match( "^(.-)%s*$" ) or before -- "Too complex", apparently.
1496 local posTrailingSpaces = before:find("%s*$")
1497 if posTrailingSpaces then
1498 before = before:sub(1,posTrailingSpaces-1)
1499 end
1500 if #before>0 then table.insert(exploded, before) end
1501
1502 str = after
1503 s,e,before,after = str:find("^([^>]*)>(.*)$")
1504 end
1505
1506 str = str:match( "^%s*(.+)$" ) or str
1507 local posTrailingSpaces = str:find("%s*$")
1508 if posTrailingSpaces then
1509 str = str:sub(1,posTrailingSpaces-1)
1510 end
1511 if #str>0 then table.insert(exploded, str) end
1512
1513 for i=1,#exploded do
1514 if not exploded[i] then break end
1515
1516 if (not workingDir[exploded[i]]) or (workingDir[exploded[i]].IsTraderItem) then -- Empty or an item, replace with category
1517 workingDir[exploded[i]] = {}
1518 end
1519 workingDir = workingDir[exploded[i]]
1520 end
1521 end
1522
1523 workingDir[ name ] = {
1524 IsTraderItem = true,
1525 item = obj,
1526
1527 costType = CostType,
1528 cost = cost,
1529
1530 req = req,
1531
1532 spawnAs = spawnAs,
1533 limit = limit,
1534 sets = registerSet( obj ),
1535 }
1536end
1537function registerSet( obj )
1538 local desc = obj.getDescription()
1539 local name = obj.getName() or "[ITEM]"
1540
1541 if obj.tag=="Infinite" then
1542 local clone = obj.takeObject(params)
1543 if clone then
1544 name = clone.getName() or name
1545 end
1546 destroyObject(clone)
1547 end
1548
1549 local sets = {}
1550 local hasSets = false
1551 for num,setName in desc:gmatch("Set:? *(%d*)x? *([^\n]+)") do
1552 num = tonumber(num) or 1
1553 if setName then
1554 sets[setName] = (sets[setName] or 0) + num
1555 hasSets = true
1556 end
1557 end
1558 if not hasSets then return end -- Not part of a set
1559
1560 local inSets = {}
1561 for setName,num in pairs(sets) do
1562 TradeSets[setName] = TradeSets[setName] or {}
1563
1564 TradeSets[setName][name] = num
1565 table.insert(inSets, setName)
1566 end
1567
1568 return inSets
1569end
1570
1571
1572-- Cost To String --
1573--------------------
1574
1575function getCostString( costTable, costType )
1576 if not costTable then return "" end
1577
1578 local str = ""
1579 local orderedCost = {}
1580 if costType==COST_ANY then
1581 orderedCost = CopyTable(costTable)
1582 else
1583 for item,num in pairs(costTable) do
1584 table.insert( orderedCost, {item,num} )
1585 end
1586 end
1587 table.sort( orderedCost, function(a,b)
1588 if a[2]==b[2] then
1589 return a[1]<b[1]
1590 end
1591 return a[2]<b[2]
1592 end)
1593
1594 for i=1,#orderedCost do
1595 str = str .. ("%s%i %s[b]%s[/b]"):format(
1596 (i==1 and "") or (i==#orderedCost and (costType==COST_ANY and ", or " or ", and ")) or ", ",
1597 orderedCost[i][2],
1598 costType==COST_ANY and TradeSets[ orderedCost[i][1] ] and "from " or "",
1599 orderedCost[i][1]
1600 )
1601 end
1602
1603 return str
1604end
1605
1606
1607-- Menu --
1608----------
1609
1610function doListData()
1611 for k in pairs(ListReference) do
1612 table.insert(ListData, k)
1613 end
1614 table.sort(ListData, function(a,b)
1615 if ListReference[a].IsTraderItem and not ListReference[b].IsTraderItem then return false end
1616 if ListReference[b].IsTraderItem and not ListReference[a].IsTraderItem then return true end
1617
1618 return a<b
1619 end)
1620end
1621
1622function clickMainMenu(o,c)
1623 local ourColor = c and self.getName():lower():find(c:lower())
1624 if not (c and (Player[c].admin or ourColor)) then
1625 broadcastToColor( "This does not belong to you.", c, {1,0.2,0.2} )
1626 return
1627 end
1628
1629 mainMenu()
1630end
1631function mainMenu()
1632 ListTitle = "Collectable Trader"
1633 ListReference = TradeItems
1634 ListData = {}
1635
1636 DirectoryPath = {}
1637
1638 doListData()
1639
1640 doMenu( 1 )
1641end
1642
1643function doMenu(page)
1644 self.clearButtons()
1645 self.clearInputs()
1646
1647 ListPage = page or 1
1648
1649 -- Title
1650 self.createButton({
1651 label=ListTitle, click_function="doNull", function_owner=self, scale = {0.5,0.5,0.5},
1652 position={1.2, 0.25, -1.23}, rotation={0,0,0}, width=0, height=0, font_size=170,
1653 font_color = {r=1,g=1,b=1},
1654 })
1655
1656 Targets = {}
1657
1658 local displayFrom = (ListPage-1)*10
1659 -- List Page
1660 for i=1,10 do
1661 local data = ListData[displayFrom + i]
1662
1663 if not (data and ListReference[data]) then break end
1664
1665 local zpos = -1.17 + (i * 0.21)
1666 local col = AdminMode and {r=1,g=0.1,b=0.1} or {r=1,b=1,g=1}
1667
1668 -- Button
1669 if ListReference[data].IsTraderItem then
1670 self.createButton({
1671 label= ("[b][u]%s[/u][/b]\n%s"):format( data, getCostString(ListReference[data].cost, ListReference[data].costType) ), click_function="doAction"..i, function_owner=self, scale = {0.5,0.5,0.5},
1672 position={1.2, 0.25, zpos}, rotation={0,0,0}, width=1800, height=220, font_size=80,
1673 color = col
1674 })
1675 else
1676 self.createButton({
1677 label= ("[b]%s[b] >"):format( data ), click_function="doAction"..i, function_owner=self, scale = {0.5,0.5,0.5},
1678 position={1.2, 0.25, zpos}, rotation={0,0,0}, width=1800, height=220, font_size=80,
1679 color = col
1680 })
1681 end
1682 end
1683
1684
1685 -- Page Navigaton
1686 local pageStr = ("Page %i of %i"):format( ListPage, math.ceil(#ListData/10) )
1687 self.createButton({
1688 label=pageStr, click_function="doNull", function_owner=self, scale = {0.5,0.5,0.5},
1689 position={1.2, 0.25, 1.12}, rotation={0,0,0}, width=0, height=0, font_size=100,
1690 font_color = {r=1,g=1,b=1},
1691 })
1692
1693 self.createButton({
1694 label="<", click_function="PrevPage", function_owner=self, scale = {1,1,1}, scale = {0.5,0.5,0.5},
1695 position={0.7, 0.25, 1.12}, rotation={0,0,0}, width=100, height=100, font_size=80,
1696 color = ListPage==1 and {0.5,0.5,0.5} or {1,1,1}
1697 })
1698 self.createButton({
1699 label=">", click_function="NextPage", function_owner=self, scale = {1,1,1}, scale = {0.5,0.5,0.5},
1700 position={1.7, 0.25, 1.12}, rotation={0,0,0}, width=100, height=100, font_size=80,
1701 color = ListPage>=math.ceil(#ListData/10) and {0.5,0.5,0.5} or {1,1,1}
1702 })
1703
1704
1705 if #DirectoryPath>0 then
1706 -- Return
1707 self.createButton({
1708 label="Back", click_function="clickBack", function_owner=self, scale = {1,1,1}, scale = {0.5,0.5,0.5},
1709 position={1.3, 0.25, 1.32}, rotation={0,0,0}, width=450, height=150, font_size=80,
1710 })
1711 self.createButton({
1712 label="Main Menu", click_function="clickMainMenu", function_owner=self, scale = {1,1,1}, scale = {0.5,0.5,0.5},
1713 position={1.8, 0.25, 1.32}, rotation={0,0,0}, width=450, height=150, font_size=80,
1714 })
1715 end
1716
1717 -- Admin
1718 self.createButton({
1719 label="Admin Mode", click_function="clickAdminMode", function_owner=self, scale = {1,1,1}, scale = {0.3,0.3,0.3},
1720 position={0.2, 0.25, -1.33}, rotation={0,0,0}, width=450, height=50, font_size=70,
1721 color = AdminMode and {r=1,g=0,b=0} or {r=0.25,g=0.25,b=0.25},
1722 })
1723 self.createButton({
1724 label="Reload", click_function="clickRefresh", function_owner=self, scale = {1,1,1}, scale = {0.3,0.3,0.3},
1725 position={0.2, 0.25, -1.23}, rotation={0,0,0}, width=450, height=50, font_size=70,
1726 color = {r=0.25,g=0.25,b=0.25},
1727 })
1728end
1729
1730
1731-- Actions --
1732-------------
1733function doAction( index, c )
1734 local ourColor = c and self.getName():lower():find(c:lower())
1735 if not (c and (Player[c].admin or ourColor)) then
1736 broadcastToColor( "This does not belong to you.", c, {1,0.2,0.2} )
1737 return
1738 end
1739
1740 local trueIndex = index + (ListPage-1)*10
1741 local data = ListData[trueIndex]
1742 local ref = data and ListReference[data]
1743
1744 if not ref then
1745 broadcastToColor( "Something went wrong! (Button reference is missing)", c, {1,0.2,0.2} )
1746 mainMenu()
1747 return
1748 end
1749
1750 if ref.IsTraderItem then
1751 buyItem( ref, c )
1752
1753 return
1754 end
1755
1756 table.insert(DirectoryPath, data)
1757 ListReference = ref
1758 ListPage = 0
1759 ListTitle = data
1760 ListData = {}
1761
1762 doListData()
1763
1764 doMenu(1)
1765end
1766for i=1,10 do
1767 _G["doAction"..i] = function(o,c) return doAction(i,c) end
1768end
1769
1770function clickBack(o,c)
1771 local ourColor = c and self.getName():lower():find(c:lower())
1772 if not (c and (Player[c].admin or ourColor)) then
1773 broadcastToColor( "This does not belong to you.", c, {1,0.2,0.2} )
1774 return
1775 end
1776
1777 table.remove(DirectoryPath)
1778 if #DirectoryPath==0 then
1779 mainMenu()
1780 return
1781 end
1782
1783 local workingDir = TradeItems
1784 for i=1,#DirectoryPath do
1785 local newDir = workingDir[DirectoryPath[i]]
1786 if newDir and not newDir.IsTraderItem then
1787 workingDir = newDir
1788 else
1789 while #DirectoryPath>=i do
1790 table.remove(DirectoryPath)
1791 end
1792 break
1793 end
1794 end
1795 if #DirectoryPath==0 then
1796 mainMenu()
1797 return
1798 end
1799
1800 ListReference = workingDir
1801 ListPage = 0
1802 ListTitle = DirectoryPath[#DirectoryPath]
1803 ListData = {}
1804
1805 doListData()
1806
1807 doMenu(1)
1808end
1809
1810function NextPage(o,c)
1811 local ourColor = c and self.getName():lower():find(c:lower())
1812 if not (c and (Player[c].admin or ourColor)) then
1813 broadcastToColor( "This does not belong to you.", c, {1,0.2,0.2} )
1814 return
1815 end
1816
1817 local maxPage = math.max( math.ceil(#ListData/10), 1 )
1818
1819 doMenu( math.min(ListPage+1, maxPage) )
1820end
1821function PrevPage(o,c)
1822 local ourColor = c and self.getName():lower():find(c:lower())
1823 if not (c and (Player[c].admin or ourColor)) then
1824 broadcastToColor( "This does not belong to you.", c, {1,0.2,0.2} )
1825 return
1826 end
1827
1828 doMenu( math.max(ListPage-1, 1) )
1829end
1830
1831-- Util --
1832----------
1833
1834function CopyTable(from)
1835 local to = {}
1836 for k,v in pairs(from) do
1837 to[k]=v
1838 end
1839 return to
1840end
1841function TranslateSetsToItems( tbl )
1842 for setName,setCount in pairs(tbl) do
1843 if TradeSets[setName] then
1844 for objName,objCount in pairs(TradeSets[setName]) do
1845 tbl[objName] = (tbl[objName] or 0) + ((objCount or 1) * (setCount or 1))
1846 end
1847 tbl[setName] = nil
1848 end
1849 end
1850
1851 return tbl
1852end
1853
1854function PrintTable( tbl, indent, skipTables )
1855 indent = indent or 0
1856 skipTables = skipTables or {[tbl]=true}
1857
1858 for k,v in pairs(tbl) do
1859 if type(v)=="table" and not skipTables[v] then
1860 skipTables[v]=true
1861 print( (" "):rep(indent+1), "\"",k,"\" = {" )
1862 PrintTable(v, indent+1, skipTables)
1863 print( (" "):rep(indent+1), "}" )
1864 else
1865 print( (" "):rep(indent+1), "\"", k, "\" = ", v )
1866 end
1867 end
1868end
1869We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
1870create new paste / dealsnew! / syntax languages / archive / faq / tools / night mode / api / scraping api / go
1871privacy statement / cookies policy / terms of service / security disclosure / dmca / contact
1872
1873By using Pastebin.com you agree to our cookies policy to enhance your experience.
1874Site design & logo © 2018 Pastebin; user contributions (pastes) licensed under cc by-sa 3.0 -- Dedicated Server Hosting by Steadfast
1875Top