Advertisement
Guest User

Untitled

a guest
Apr 24th, 2019
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 131.62 KB | None | 0 0
  1. --TODO: Make Slot Machine Tokens as powerups
  2. --------------------------------------------------------------------------------
  3. --[[ MrStump's Blackjack Table ]]--
  4. --------------------------------------------------------------------------------
  5. -- Heavy automation and modification by my_hat_stinks
  6. --[[Table of Contents:
  7. 1. Configuration
  8. 2. Powerup Detection
  9. 3. Powerup effects
  10. 4. Card Zone Counting/display
  11. 5. Deck Finding/Tracking
  12. 6. Card Dealing
  13. 7. Functions to find data
  14. 8. Button click Functions
  15. 9. Button creation
  16. ]]
  17. function onload()
  18. --[[The powerupEffectTable allows you to attach an effect to figurines as well as
  19. limit who they can be used on. Combine these factors to make custom powerups.
  20. The name field is the name of your powerup. Powerups can only be figurines
  21. On custom models, that means you need to have it set. right click > custom > figurine
  22. Available Options:
  23. WHO - the 'who' field must have one of the below entries
  24. "Anyone" = usuable on anyone
  25. "Any Player" = usable on any play, but not the dealer
  26. "Other Player" = only usuable on other players, not dealer or self
  27. "Self Only" = only usuable on your own hand zone
  28. "Dealer Only" = only usable on the dealer hand zone
  29. "Colorname" = only usable on that color space, by anyone (ex: "Yellow")
  30. EFFECT - the 'effect' field must have one of the below entries
  31. "Clear" - Removes any cards or powerups in the target zone
  32. "Alt. Clear" - Removes any cards or powerups in the target zone, respawns powerup played
  33. "Redraw" - Removes cards and deals 2 new cards
  34. "Redraw All" - Removes cards and deals 2 new cards to every betting player
  35. "Swap" - Exchanges cards in one zone with those in another
  36. "Clone" - Replaces player's own cards with those from another, leaving the origionals
  37. "Destroy" - Destroys the last dealt card (any player), can only be played mid-round
  38. "Reveal" - Flips over any face-down card
  39. "Stand" - Reveals second card and hides the following cards
  40. "Draw 1" - Forces individual powerup is played on to draw a card. Only works with 1
  41. "Powerup Draw" - Draws 1 random powerup from the powerupTable
  42. "Rupee Pull" - Pulls 1 random rupee from the rupeeWallet
  43. "Reset Timer" - Reduces the bonus round timer to 3 seconds
  44. ]]--
  45. powerupEffectTable = {
  46. ["Force the dealer to reveal their facedown card"] = {who="Dealer Only", effect="Reveal"},
  47. ["Force the dealer to stand on two cards"] = {who="Dealer Only", effect="Stand"},
  48. ["Force the dealer to draw an additional card"] = {who="Dealer Only", effect="Draw 1"},
  49. ["Copy another player's hand"] = {who="Other Player", effect="Clone"},
  50. ["Exit from the round"] = {who="Self Only", effect="Clear"},
  51. ["Help another player exit from the round"] = {who="Other Player", effect="Clear"},
  52. ["Discard your hand and stand on 19"] = {who="Self Only", effect="Alt. Clear"},
  53. ["Swap hands with another player"] = {who="Other Player", effect="Swap"},
  54. ["Swap hands with the dealer"] = {who="Dealer Only", effect="Swap"},
  55. ["Random powerup draw"] = {who="Self Only", effect="Powerup Draw"},
  56. ["Random rupee pull"] = {who="Self Only", effect="Rupee Pull"},
  57. ["Reward token"] = {who="Self Only", effect="Reward Token"},
  58. ["Royal token"] = {who="Self Only", effect="Royal Token"},
  59. ["Prestige token"] = {who="Self Only", effect="Prestige Token"},
  60.  
  61. -- Card numbers only
  62. ["+1 to anyone's hand"] = {who="Anyone", effect="Card Mod"}, ["+1 to any player's hand"] = {who="Any Player", effect="Card Mod"},
  63. ["-1 from anyone's hand"] = {who="Anyone", effect="Card Mod"},
  64. ["+3 to anyone's hand"] = {who="Anyone", effect="Card Mod"}, ["+3 to any player's hand"] = {who="Any Player", effect="Card Mod"},
  65. ["-3 from anyone's hand"] = {who="Anyone", effect="Card Mod"},
  66. ["+10 to your own hand"] = {who="Self Only", effect="Card Mod"},
  67. ["Joker Powerup"] = {who="Self Only", effect="Card Mod"},
  68.  
  69. ["Force the dealer to bust"] = {who="Dealer Only", effect="Card Mod"},
  70.  
  71. -- Internal - Do not use
  72. ["Fifth Card"] = {who="", effect="FifthCard"},
  73. }
  74.  
  75. --Powerups that are locked on the table
  76. powerupTable = {}
  77. for _,id in pairs({ "2c564b", "432519", "cd6cd1", "a4883c", "7b7031", "4a8de2", "fcaebe", "48ae1d", "3bf915", "b5851f", "81121a", "60a985", "c663e1", "f0150d", "84928d","7f70a2","5e7da3","7aade8","6516b6" }) do --last 3 GUID might not be used
  78. local obj = getObjectFromGUID(id)
  79. if obj then
  80. table.insert(powerupTable, {id, obj.getName()})
  81. end
  82. end
  83.  
  84. prestigeTable = {}
  85.  
  86. rewards = {
  87. Help = getObjectFromGUID("ef72b4"),
  88. GiveJokers = getObjectFromGUID("4dbf75"),
  89. StealJokers = getObjectFromGUID("395ece"),
  90. CopyJokers = getObjectFromGUID("aad1be"),
  91.  
  92. FiveCardWin = getObjectFromGUID("890842"),
  93. FiveCardTwentyOne = getObjectFromGUID("37085e"),
  94. SixCardWin = getObjectFromGUID("68a101"),
  95. SixCardTwentyOne = getObjectFromGUID("fe17c6"),
  96.  
  97. Blackjack = getObjectFromGUID("7c99c4"),
  98. DoubleJoker = getObjectFromGUID("887ef8"),
  99. TripleSeven = getObjectFromGUID("fa1dc7"),
  100. Unused = getObjectFromGUID("9b7f31"),
  101. }
  102.  
  103. --The names (in quotes) should all match the names on your cards.
  104. --The values should match the value of those cards.
  105. --If you have powerup modifies (ex: +1 to score), it could be added here (again, figurine required)
  106. --0 is reserved for Aces.
  107. cardNameTable = {
  108. ["Two"]=2, ["Three"]=3, ["Four"]=4, ["Five"]=5,
  109. ["Six"]=6, ["Seven"]=7, ["Eight"]=8, ["Nine"]=9, ["Ten"]=10,
  110. ["Jack"]=10, ["Queen"]=10, ["King"]=10, ["Ace"]=0, ["Joker"]=12,
  111. ["+1 to anyone's hand"]=1, ["+1 to any player's hand"]=1, ["-1 from anyone's hand"]=-1,
  112. ["+3 to anyone's hand"]=3, ["+3 to any player's hand"]=3, ["-3 from anyone's hand"]=-3,
  113. ["+10 to your own hand"]=10, ["Discard your hand and stand on 19"]=19,
  114. ["Force the dealer to bust"]=-69,["Joker Powerup"]=12,
  115. }
  116.  
  117. --This is what ties a scripting zone to a player/dealer
  118. --color is the player's color, z is the player's scripting zone
  119. --Dealer comes first!
  120. objectSets = {
  121. {color="Dealer", zone=getObjectFromGUID("275a5d"), value=0, count=0, container=getObjectFromGUID("df8d40"), prestige=getObjectFromGUID("885bf4"), btnHandler=getObjectFromGUID("355712"), tbl=getObjectFromGUID("758fe9")},
  122. {color="Pink", zone=getObjectFromGUID("44f05e"), value=0, count=0, container=getObjectFromGUID("7c4eb9"), prestige=getObjectFromGUID("0b4a58"), btnHandler=getObjectFromGUID("4503f9"), tbl=getObjectFromGUID("bb54b1")},
  123. {color="Purple", zone=getObjectFromGUID("63ef4e"), value=0, count=0, container=getObjectFromGUID("54d217"), prestige=getObjectFromGUID("17ddfd"), btnHandler=getObjectFromGUID("2a52f9"), tbl=getObjectFromGUID("b2ab0b")},
  124. {color="Blue", zone=getObjectFromGUID("423ae1"), value=0, count=0, container=getObjectFromGUID("f2e64b"), prestige=getObjectFromGUID("f87e7b"), btnHandler=getObjectFromGUID("5d5e85"), tbl=getObjectFromGUID("7a414f")},
  125. {color="Teal", zone=getObjectFromGUID("5c2692"), value=0, count=0, container=getObjectFromGUID("54cc65"), prestige=getObjectFromGUID("3484cc"), btnHandler=getObjectFromGUID("925380"), tbl=getObjectFromGUID("d21b66")},
  126. {color="Green", zone=getObjectFromGUID("595fa9"), value=0, count=0, container=getObjectFromGUID("579f2e"), prestige=getObjectFromGUID("a7bb1b"), btnHandler=getObjectFromGUID("031d13"), tbl=getObjectFromGUID("2612ed")},
  127. {color="Yellow", zone=getObjectFromGUID("5b82fd"), value=0, count=0, container=getObjectFromGUID("486212"), prestige=getObjectFromGUID("944b87"), btnHandler=getObjectFromGUID("ab82ca"), tbl=getObjectFromGUID("a7596f")},
  128. {color="Orange", zone=getObjectFromGUID("38b2d7"), value=0, count=0, container=getObjectFromGUID("b179e0"), prestige=getObjectFromGUID("844d3d"), btnHandler=getObjectFromGUID("ef0906"), tbl=getObjectFromGUID("efae07")},
  129. {color="Red", zone=getObjectFromGUID("8b37f7"), value=0, count=0, container=getObjectFromGUID("82aca4"), prestige=getObjectFromGUID("d8cd49"), btnHandler=getObjectFromGUID("9fd676"), tbl=getObjectFromGUID("b54e19")},
  130. {color="Brown", zone=getObjectFromGUID("1c13af"), value=0, count=0, container=getObjectFromGUID("cee112"), prestige=getObjectFromGUID("6c29ce"), btnHandler=getObjectFromGUID("5b2fc0"), tbl=getObjectFromGUID("688678")},
  131. {color="White", zone=getObjectFromGUID("a751f4"), value=0, count=0, container=getObjectFromGUID("8144bb"), prestige=getObjectFromGUID("88482c"), btnHandler=getObjectFromGUID("0a3126"), tbl=getObjectFromGUID("33b903")},
  132.  
  133. -- Split zones - Code cycles through this table backwards, so zone 1 is last
  134. {color="Split6", zone=getObjectFromGUID("43d808"), value=0, count=0, container=getObjectFromGUID("b5effd"), prestige=getObjectFromGUID("43d808"), btnHandler=getObjectFromGUID("1f100d"), tbl=getObjectFromGUID("43d808")},
  135. {color="Split5", zone=getObjectFromGUID("39f2dd"), value=0, count=0, container=getObjectFromGUID("0232e3"), prestige=getObjectFromGUID("39f2dd"), btnHandler=getObjectFromGUID("9a5313"), tbl=getObjectFromGUID("39f2dd")},
  136. {color="Split4", zone=getObjectFromGUID("df3fa1"), value=0, count=0, container=getObjectFromGUID("1c1194"), prestige=getObjectFromGUID("df3fa1"), btnHandler=getObjectFromGUID("0f078a"), tbl=getObjectFromGUID("df3fa1")},
  137. {color="Split3", zone=getObjectFromGUID("391dea"), value=0, count=0, container=getObjectFromGUID("5f8f1e"), prestige=getObjectFromGUID("391dea"), btnHandler=getObjectFromGUID("a356c5"), tbl=getObjectFromGUID("391dea")},
  138. {color="Split2", zone=getObjectFromGUID("e527cb"), value=0, count=0, container=getObjectFromGUID("3e331e"), prestige=getObjectFromGUID("e527cb"), btnHandler=getObjectFromGUID("c84a39"), tbl=getObjectFromGUID("e527cb")},
  139. {color="Split1", zone=getObjectFromGUID("f673d7"), value=0, count=0, container=getObjectFromGUID("b2bf24"), prestige=getObjectFromGUID("f673d7"), btnHandler=getObjectFromGUID("35ea56"), tbl=getObjectFromGUID("f673d7")},
  140. }
  141.  
  142. --Object on which buttons are placed for things like "deal cards"
  143. cardHandler = getObjectFromGUID("77a0c3")
  144. bonusTimer = getObjectFromGUID("3cce5b")
  145.  
  146. betBags = getObjectFromGUID("697122")
  147.  
  148. hostSettings = {
  149. iDealerStand = getObjectFromGUID("f87906"),
  150.  
  151. bRupeeLimit = getObjectFromGUID("dbdb45"),
  152. iRupeeMax = getObjectFromGUID("b1adba"),
  153.  
  154. bTurnLimit = getObjectFromGUID("f7ae23"),
  155. iTurnTime = getObjectFromGUID("a478bf"),
  156. bTurnLimitEndsEarly = getObjectFromGUID("bd42ce"),
  157.  
  158. bHostilePowerups = getObjectFromGUID("0cfeee"),
  159. bPrestigeClearChip = getObjectFromGUID("d22476"),
  160. bPrestigeClearPower = getObjectFromGUID("ee4f48"),
  161.  
  162. bBankruptClearChip = getObjectFromGUID("176215"),
  163. bBankruptClearPower = getObjectFromGUID("d507ce"),
  164. bBankruptClearPrestige = getObjectFromGUID("420f3e"),
  165.  
  166. bPowerupsAlwaysFifthCard = getObjectFromGUID("6e42d2"),
  167. bSplitOnValue = getObjectFromGUID("ee7eef"),
  168. bRevealIsHelp = getObjectFromGUID("17c020"),
  169. bMultiHelpRewards = getObjectFromGUID("47c99e"),
  170.  
  171. iTimeBet = getObjectFromGUID("e6f539"),
  172. iTimePowerup = getObjectFromGUID("4e2af5"),
  173.  
  174. bAutoMinigames = getObjectFromGUID("c756e3"),
  175.  
  176. bAllowChipTrading = getObjectFromGUID("3bac86"),
  177. iMultiplyPayouts = getObjectFromGUID("fed1d0"),
  178.  
  179. bDealerAceIsOne = getObjectFromGUID("1ab0a8"),
  180. }
  181.  
  182. deckBag = getObjectFromGUID("eaa77b")
  183. minigameBag = getObjectFromGUID("5b38f8")
  184. bonusBag = getObjectFromGUID("91fe78")
  185.  
  186. bonusObjects = {}
  187.  
  188. --A zone where the deck is placed. Also used in tagging the deck for identification
  189. deckZone = getObjectFromGUID("885bf4")
  190. bonusZone = getObjectFromGUID("3c31e1")
  191.  
  192. --A list of objects that we want to disable interaction for
  193. objectLockdown = {
  194. getObjectFromGUID("16f87e"), getObjectFromGUID("8e0429"), -- Dealer area
  195.  
  196. -- Player tables
  197. getObjectFromGUID("9871fe"), getObjectFromGUID("8eafbb"), -- Pink
  198. getObjectFromGUID("d5d7c5"), getObjectFromGUID("32da09"), -- Purple
  199. getObjectFromGUID("b92ec5"), getObjectFromGUID("51086b"), getObjectFromGUID("981767"), -- Blue
  200. getObjectFromGUID("51aacb"), getObjectFromGUID("60b260"), getObjectFromGUID("5a0955"), -- Teal
  201. getObjectFromGUID("b01343"), getObjectFromGUID("704082"), getObjectFromGUID("653add"), -- Green
  202. getObjectFromGUID("2cc362"), getObjectFromGUID("51690f"), getObjectFromGUID("63c8aa"), -- Yellow
  203. getObjectFromGUID("fddcfc"), getObjectFromGUID("8ea777"), getObjectFromGUID("54895c"), -- Orange
  204. getObjectFromGUID("f12fe3"), getObjectFromGUID("9f466e"), getObjectFromGUID("a3c6db"), -- Red
  205. getObjectFromGUID("ac9b82"), getObjectFromGUID("b2883b"), -- Brown
  206. getObjectFromGUID("a82b72"), getObjectFromGUID("4211a7"), -- White
  207.  
  208. getObjectFromGUID("9ac0b7"),
  209.  
  210. -- Button handlers
  211. getObjectFromGUID("4503f9"), -- Pink
  212. getObjectFromGUID("2a52f9"), -- Purple
  213. getObjectFromGUID("5d5e85"), -- Blue
  214. getObjectFromGUID("925380"), -- Teal
  215. getObjectFromGUID("031d13"), -- Green
  216. getObjectFromGUID("ab82ca"), -- Yellow
  217. getObjectFromGUID("ef0906"), -- Orange
  218. getObjectFromGUID("9fd676"), -- Red
  219. getObjectFromGUID("5b2fc0"), -- Brown
  220. getObjectFromGUID("0a3126"), -- White
  221.  
  222. -- Rupee trophies
  223. getObjectFromGUID("1feed0"), -- Green
  224. getObjectFromGUID("533f81"), -- Blue
  225. getObjectFromGUID("b8bf89"), -- Yellow
  226. getObjectFromGUID("038e19"), -- Red
  227. getObjectFromGUID("02eb77"), -- Purple
  228. getObjectFromGUID("5e2f09"), -- Orange
  229. getObjectFromGUID("df5ce7"), -- Silver
  230. getObjectFromGUID("dc1fe2"), -- Rupoor
  231. getObjectFromGUID("0b6e51"), -- Gold
  232. }
  233.  
  234. -- Chips list
  235. chipConverter = getObjectFromGUID("ad770c")
  236. chipList = chipConverter and chipConverter.getTable("chipList") or {}
  237. chipListIndex = {}
  238. for i=1,#chipList do
  239. chipListIndex[chipList[i].name or ""] = i
  240. end
  241.  
  242. -- Round timer
  243. roundStateTable = {"1fe5da","bf6cbd","fd2298","aefae6"} -- Bets, Play, Powerups, Paused
  244. for _,id in ipairs(roundStateTable) do
  245. roundState = getObjectFromGUID(id)
  246. if roundState then break end
  247. end
  248. if roundState and roundState.getGUID()~=roundStateTable[1] then roundState = roundState.setState(1) end
  249.  
  250. roundTimer = getObjectFromGUID("8f93ac")
  251. if roundTimer then
  252. roundTimer.setValue( 180 )
  253. roundTimer.Clock.paused = false
  254.  
  255. roundStateID = 1
  256. end
  257.  
  258. -- Other vars
  259. dealersTurn = false
  260. dealingDealersCards = false
  261. lockout = false
  262. timerTick = 0
  263.  
  264. lockObjects()
  265. createButtons()
  266. checkForDeck()
  267. findCardsToCount()
  268. clearBonus()
  269. end
  270.  
  271. function lockObjects()
  272. for i, list in ipairs(objectLockdown) do
  273. list.interactable = false
  274. end
  275. end
  276.  
  277. function GetSetting( var, default )
  278. if type(var)=="table" then -- Set up var (request from other object)
  279. default = var.default
  280. if default==nil then default = var[2] end
  281.  
  282. var = var.index or var.id or var.setting or var[1]
  283. end
  284. if not (var and type(var)=="string") then return default end -- No var, return default
  285.  
  286. if (not BlackjackSettingsObject) or (BlackjackSettingsObject==nil) then
  287. for _,obj in pairs(getAllObjects()) do
  288. if obj.getLock() and obj.getName()=="Blackjack Settings" and obj.getVar("getSetting") and not (obj==nil) then
  289. BlackjackSettingsObject = obj
  290. break
  291. end
  292. end
  293.  
  294. if (not BlackjackSettingsObject) or (BlackjackSettingsObject==nil) then
  295. return default -- No settings object, return default
  296. end
  297. end
  298.  
  299. local value = BlackjackSettingsObject.Call("getSetting", {index=var})
  300. if value==nil then return default end -- Unset, return default
  301.  
  302. return value -- Return value
  303. end
  304.  
  305. objectHasLeftContainer = {}
  306. objectForceDropped = {}
  307. function onObjectLeaveContainer(bag, obj)
  308. if obj.getPosition()[3] < -16 then
  309. objectHasLeftContainer[obj] = bag
  310. Wait.frames(function()
  311. objectHasLeftContainer[obj] = nil
  312. end, 2)
  313. end
  314. end
  315. function onObjectPickedUp(color, object)
  316. if color ~= "Black" and not (Player[color].admin) then
  317. if object.getPosition()[3] < -16 then
  318. object.translate({0,0.15,0})
  319. print(color .. ' picked up a ' .. object.tag .. ' titled "' .. object.getName() .. '" from the hidden zone!')
  320.  
  321. if objectHasLeftContainer[object] then
  322. if objectHasLeftContainer[object].tag=="Infinite" then
  323. destroyObject(object)
  324. else
  325. objectHasLeftContainer[object].putObject(object)
  326. end
  327. else
  328. objectForceDropped[object] = true
  329. Wait.frames(function()
  330. objectForceDropped[object] = nil
  331. end, 2)
  332. end
  333. end
  334. for i, set in ipairs(objectSets) do
  335. local objectsInZone = set.zone.getObjects()
  336. for i, found in ipairs(objectsInZone) do
  337. if found.tag == "Deck" or found.tag == "Card" then
  338. if found == object then
  339. object.translate({0,0.15,0})
  340. end
  341. end
  342. end
  343. end
  344. end
  345. end
  346.  
  347. function giveRewardCallback(obj, data)
  348. if not (obj and data and data.set) then return end
  349.  
  350. if obj.tag=="Bag" then
  351. obj.reset()
  352.  
  353. obj.setName("Player save: " .. Player[data.set.color].steam_name)
  354. obj.setDescription(Player[data.set.color].steam_id)
  355. end
  356.  
  357. local p = {data.pos.x, data.pos.y+0.5, data.pos.z}
  358. obj.setPosition( p )
  359. end
  360. function giveReward( id, zone )
  361. if not rewards[id] then return end
  362.  
  363. local set = findObjectSetFromZone(zone)
  364. if set.UserColor then
  365. set = findObjectSetFromColor(set.UserColor) or set
  366. zone = set.zone
  367. end
  368.  
  369. local params = {}
  370. -- params.position = zone.getPosition()
  371. params.position = zone.positionToWorld({0.5,0,-0.5})
  372. params.callback = "giveRewardCallback"
  373. params.callback_owner = Global
  374. params.params = {set=set}
  375.  
  376. for _,item in pairs( rewards[id].getObjects()) do
  377. params.position.y = params.position.y+0.1
  378. params.params.pos = params.position
  379.  
  380. local obj
  381. if item.tag=="Infinite" then
  382. obj = item.takeObject(params)
  383. elseif obj.tag=="Bag" then
  384. obj = item.clone(params)
  385. obj.reset()
  386.  
  387. obj.setName("Player save: " .. Player[set.color].steam_name)
  388. obj.setDescription(Player[set.color].steam_id)
  389. else
  390. obj = item.clone(params)
  391.  
  392. obj.setDescription( ("%s - %s\n\n%s"):format(Player[set.color].steam_id, Player[set.color].steam_name, obj.getDescription()) )
  393. end
  394.  
  395. if obj then
  396. obj.interactable = true
  397. obj.setLock( false )
  398. end
  399. end
  400. end
  401.  
  402.  
  403.  
  404.  
  405.  
  406. --POWERUP DETECTION SECTION
  407.  
  408.  
  409.  
  410.  
  411.  
  412. --When an object is dropped by a player, we check if its name is on a powerup list
  413. function onObjectDropped(colorOfDropper, droppedObject)
  414. -- Dealer zone protections
  415. if objectForceDropped[droppedObject] then
  416. return
  417. elseif droppedObject.getPosition()[3] < -16 and colorOfDropper~="Black" and not Player[colorOfDropper].admin then
  418. local trash = getObjectFromGUID("df8d40")
  419. if trash and not (trash==nil) then
  420. trash.putObject(droppedObject)
  421. if colorOfDropper then
  422. printToColor( "You dropped an item in the dealer zone; it has ben placed in Trash.", colorOfDropper, {0.75,0.45,0.35} )
  423. end
  424. end
  425.  
  426. return
  427. end
  428.  
  429. -- Powerup use
  430. local power = powerupEffectTable[droppedObject.getName()]
  431. if power and bonusCanUsePowerup(droppedObject) then
  432. return checkPowerupDropZone(colorOfDropper, droppedObject, power.who, power.effect)
  433. end
  434.  
  435. -- Chip protections
  436. if droppedObject.tag=="Chip" and droppedObject.getDescription():find(Player[colorOfDropper].steam_id, 0, true) then
  437. local inOwnZone = false
  438. for i=2,#objectSets do
  439. for _,v in pairs({"zone","tbl","prestige"}) do
  440. for _,obj in pairs(objectSets[i][v].getObjects()) do
  441. if obj==droppedObject then
  442. local setCol = objectSets[i].color
  443. if setCol==colorOfDropper then -- If there's an overlap, we prioritise our own zone
  444. inOwnZone = true
  445. obj.setDescription( Player[colorOfDropper].steam_id .." - ".. Player[colorOfDropper].steam_name )
  446. break
  447. end
  448.  
  449. if setCol:sub(1,5):lower()~="split" and Player[setCol] and Player[setCol].seated then
  450. if GetSetting("Chips.AllowTrading", false) then
  451. obj.setDescription( Player[setCol].steam_id .." - ".. Player[setCol].steam_name )
  452. elseif not Player[colorOfDropper].admin then
  453. local ownSet = findObjectSetFromColor(colorOfDropper)
  454. if ownSet then
  455. obj.setPosition(ownSet.tbl.getPosition())
  456. end
  457. broadcastToColor("You may not trade chips. Chips have been returned to your table.", colorOfDropper, {1,0,0})
  458.  
  459. return
  460. end
  461. end
  462. end
  463. end
  464. if inOwnZone then break end
  465. end
  466. end
  467. end
  468.  
  469.  
  470. end
  471.  
  472. local preventEnterContainer = {}
  473. function onObjectPickUp(col, obj)
  474. if col~="Black" and obj.getPosition()[3] >= -16 then
  475. local desc = obj.getDescription()
  476. if desc=="" and obj.tag=="Chip" then --obj.getDescription():find("^%$([%d,])+ ?%s*$")
  477. obj.setDescription( ("%s - %s"):format(Player[col].steam_id, Player[col].steam_name) )
  478. elseif desc:find(Player[col].steam_id, 0, true) then
  479. local id, oldDesc = desc:match("^(%d+) %- [^\n]*\n\n(.*)")
  480. if oldDesc then
  481. obj.setDescription( ("%s - %s\n\n%s"):format(Player[col].steam_id, Player[col].steam_name, oldDesc) )
  482. else
  483. obj.setDescription( ("%s - %s"):format(Player[col].steam_id, Player[col].steam_name) )
  484. end
  485. elseif (not Player[col].admin) and desc:find("^(%d+) %- .*") then
  486. local guid = obj.getGUID()
  487. preventEnterContainer[obj.getGUID()] = obj.reload()
  488. Wait.frames(function()
  489. preventEnterContainer[obj.getGUID()] = nil
  490. end, 1)
  491.  
  492. for k,adminCol in pairs(getSeatedPlayers()) do
  493. if Player[adminCol].admin then
  494. broadcastToColor( tostring(Player[col].steam_name).." attempted to lift another player's \""..tostring(obj.getName()).."\".", adminCol, {1,0,0} )
  495. end
  496. end
  497. end
  498. end
  499. end
  500. function onObjectEnterContainer(bag, obj)
  501. if preventEnterContainer[obj.getGUID()] and preventEnterContainer[obj.getGUID()]==obj then
  502. destroyObject(obj)
  503. end
  504. end
  505.  
  506. --Triggered by above function, this determines if the powerup was dropped in a card zone (objectSets z fields)
  507. function checkPowerupDropZone(colorOfDropper, droppedObject, who, effect)
  508. for i, set in ipairs(objectSets) do
  509. local objectsInZone = set.zone.getObjects()
  510. for j, zoneObject in ipairs(objectsInZone) do
  511. if zoneObject == droppedObject then
  512. checkPowerupEffect(colorOfDropper, droppedObject, who, effect, set)
  513. break
  514. end
  515. end
  516. end
  517. end
  518.  
  519. --Checks the logic of who should be able to utilize a powerup and its effect
  520. --This function is what enforces the "who" field, so powerups only trigger in the correct zones
  521. function checkPowerupEffect(colorOfDropper, droppedObject, who, effect, setTarget)
  522. local setUser = findObjectSetFromColor(colorOfDropper)
  523. if not setUser then return end
  524.  
  525. if inMinigame then
  526. if minigame and (not (minigame==nil)) and minigame.getVar("blackjackCanUsePowerup") and minigame.Call("blackjackCanUsePowerup", {setUser=setUser, setTarget=setTarget, object=droppedObject, who=who, effect=effect}) then
  527. else
  528. printToColor( "You can't use this powerup during this minigame. Try again later.", colorOfDropper, {1,0.25,0.25} )
  529. return
  530. end
  531. end
  532.  
  533. if (setTarget == objectSets[1]) and dealingDealersCards then
  534. broadcastToColor("You can't use a powerup on the dealer while their cards are being dealt.", setUser.color, {1,0.5,0.5})
  535.  
  536. return
  537. end
  538.  
  539. if who == "Anyone" then
  540. activatePowerupEffect(effect, setTarget, droppedObject, setUser)
  541. elseif who == "Any Player" and setTarget ~= objectSets[1] then
  542. activatePowerupEffect(effect, setTarget, droppedObject, setUser)
  543. elseif who == "Other Player" and colorOfDropper ~= setTarget.color and setTarget ~= objectSets[1] and setTarget.UserColor~=colorOfDropper then
  544. activatePowerupEffect(effect, setTarget, droppedObject, setUser)
  545. elseif who == "Self Only" and (colorOfDropper == setTarget.color or setTarget.UserColor==colorOfDropper) then
  546. activatePowerupEffect(effect, setTarget, droppedObject, setUser)
  547. elseif who == "Dealer Only" and setTarget == objectSets[1] then
  548. activatePowerupEffect(effect, setTarget, droppedObject, setUser)
  549. elseif who == setTarget.color or (setTarget.UserColor and who == setTarget.UserColor) then
  550. activatePowerupEffect(effect, setTarget, droppedObject, setUser)
  551. else -- No valid target
  552. activatePowerupFailedCallback( {obj=droppedObject, user=setUser, target=setTarget} )
  553. end
  554. end
  555.  
  556. function unlockPrestigeDestructionBag(data)
  557. if data and data.bag and not (data.bag and data.bag==nil) then
  558. data.bag.unlock()
  559.  
  560. if data and data.container and not (data.container and data.container==nil) then
  561. data.container.putObject( data.bag )
  562. elseif data and data.setContainer and not (data.setContainer and data.setContainer==nil) then
  563. data.setContainer.putObject( data.bag )
  564. end
  565. end
  566. end
  567. function doPrestigeDestructionBagCallback(obj, data)
  568. if data.destroyPowerups and powerupEffectTable[obj.getName()] then return obj.destruct() end
  569. if data.destroyChips and obj.tag=="Chip" and not powerupEffectTable[obj.getName()] then return obj.destruct() end
  570.  
  571. local name = obj.getVar("__trader_ObjectName") or obj.getName()
  572. if data.destroyPrestige and (newObj.getVar("PrestigeLevel") or ((string.match(name(), "New player") or string.match(name, "Prestige %d+")) and not string.find(name, "Trophy"))) then
  573. return obj.destruct()
  574. end
  575.  
  576. if obj.getVar("onBlackjackDestroyItems") then
  577. obj.Call("onBlackjackDestroyItems", {destroyChips=data.destroyChips, destroyPowerups=data.destroyPowerups, destroyPrestige=data.destroyPrestige} )
  578.  
  579. obj.unlock()
  580. if data and data.container and not (data.container and data.container==nil) then -- I've not checked if a != operator returns as expected for null objects, so I'm using not ==
  581. data.container.putObject( obj )
  582. elseif data and data.setContainer and not (data.setContainer and data.setContainer==nil) then
  583. data.setContainer.putObject( obj )
  584. end
  585. elseif obj.tag=="Bag" then
  586. local params = {}
  587. params.position = obj.getPosition()
  588. params.params = {destroyChips=data.destroyChips, destroyPowerups=data.destroyPowerups, container=obj, setContainer=data.setContainer}
  589. params.position.y = params.position.y + 8
  590. params.callback = "doPrestigeDestructionBagCallback"
  591. if params.position.y>=35 then
  592. params.position.y = 5
  593. params.position.z = params.position.z + 1.5
  594. end
  595. params.callback_owner = Global
  596.  
  597. for i=1, obj.getQuantity() do
  598. local taken = obj.takeObject(params)
  599.  
  600. taken.lock()
  601. params.position.y = params.position.y + 2
  602. if params.position.y>=35 then
  603. params.position.y = 5
  604. params.position.z = params.position.z + 1.5
  605. end
  606. end
  607.  
  608. delayedCallback('unlockPrestigeDestructionBag', {bag=obj, container=data.container, setContainer=data.setContainer}, 2)
  609. else
  610. obj.unlock()
  611. if data and data.container and not (data.container and data.container==nil) then -- I've not checked if a != operator returns as expected for null objects, so I'm using not ==
  612. data.container.putObject( obj )
  613. elseif data and data.setContainer and not (data.setContainer and data.setContainer==nil) then
  614. data.setContainer.putObject( obj )
  615. end
  616. end
  617. end
  618. function doPrestigeDestruction(set)
  619. local destroyChips = GetSetting("Prestige.ClearChips", true)
  620. local destroyPowerups = GetSetting("Prestige.ClearPowerups", true)
  621.  
  622. return doChipDestruction( set, destroyChips, destroyPowerups, true )
  623. end
  624. function doBankruptDestruction(set)
  625. local destroyChips = GetSetting("Bankruptcy.ClearChips", true)
  626. local destroyPowerups = GetSetting("Bankruptcy.ClearPowerups", true)
  627. local destroyPrestige = GetSetting("Bankruptcy.ClearPrestige", false)
  628.  
  629. return doChipDestruction( set, destroyChips, destroyPowerups, destroyPrestige )
  630. end
  631. function doChipDestruction( set, destroyChips, destroyPowerups, destroyPrestige )
  632. if destroyChips or destroyPowerups or destroyPrestige then
  633. local zoneObjects = set.zone.getObjects()
  634. local tableObjects = set.tbl.getObjects()
  635. local prestigeObjects = set.prestige.getObjects()
  636.  
  637. for _,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
  638. for _, obj in ipairs(zone) do
  639. local name = obj.getVar("__trader_ObjectName") or obj.getName()
  640. if obj.getVar("onBlackjackDestroyItems") then
  641. obj.Call("onBlackjackDestroyItems", {destroyChips=destroyChips, destroyPowerups=destroyPowerups, destroyPrestige=destroyPrestige} )
  642. elseif destroyChips and obj.tag == "Chip" then
  643. if destroyPowerups or (not powerupEffectTable[obj.getName()]) then
  644. destroyObject(obj)
  645. end
  646. elseif destroyPowerups and powerupEffectTable[obj.getName()] then
  647. destroyObject(obj)
  648. elseif destroyPrestige and (obj.getVar("PrestigeLevel") or ((string.match(name, "New player") or string.match(name, "Prestige %d+")) and not string.find(name, "Trophy"))) then
  649. destroyObject(obj)
  650. elseif obj.tag=="Bag" then
  651. local params = {}
  652. params.position = obj.getPosition()
  653. params.params = {destroyChips=destroyChips, destroyPowerups=destroyPowerups, destroyPrestige=destroyPrestige, container=obj, setContainer=set.container}
  654. params.position.y = params.position.y + 8
  655. params.callback = "doPrestigeDestructionBagCallback"
  656. params.callback_owner = Global
  657.  
  658. for i=1, obj.getQuantity() do
  659. local taken = obj.takeObject(params)
  660.  
  661. taken.lock()
  662. params.position.y = params.position.y + 2
  663. end
  664. end
  665. end
  666. end
  667.  
  668. local plyID = Player[set.color].seated and Player[set.color].steam_id
  669. for _,obj in pairs(getAllObjects()) do -- Simpler destruction here, only check first layer
  670. local name = obj.getVar("__trader_ObjectName") or obj.getName()
  671. local objID = obj.getDescription():match("^(%d+) %- .*")
  672. if objID and objID==plyID then
  673. if obj.getVar("onBlackjackDestroyItems") then
  674. obj.Call("onBlackjackDestroyItems", {destroyChips=destroyChips, destroyPowerups=destroyPowerups, destroyPrestige=destroyPrestige} )
  675. elseif destroyChips and obj.tag=="Chip" then
  676. if destroyPowerups or (not powerupEffectTable[obj.getName()]) then
  677. destroyObject(obj)
  678. end
  679. elseif destroyPowerups and powerupEffectTable[obj.getName()] then
  680. destroyObject(obj)
  681. elseif destroyPrestige and (obj.getVar("PrestigeLevel") or ((string.match(name, "New player") or string.match(name, "Prestige %d+")) and not string.find(name, "Trophy"))) then
  682. destroyObject(obj)
  683. end
  684. end
  685. end
  686. end
  687. end
  688.  
  689. -- Activates a given effect. setTarget is the objectSets entry for where it was dropped. setUser is the set of the dropper
  690. powerupEffectFunctions = { -- So much cleaner and more efficient than the huge elseif chain
  691. Clear = function( setTarget, powerup, setUser )
  692. if roundStateID~=2 and roundStateID~=3 then return end
  693.  
  694. local cardsInZone = findCardsInZone(setTarget.zone)
  695. local decksInZone = findDecksInZone(setTarget.zone)
  696. local dlr = objectSets[1].value
  697. if (#cardsInZone>0 or #decksInZone>0) and (setTarget.value<=21 and setTarget.value<dlr and (dlr<=21 or dlr==69)) then
  698. if setTarget.color~=setUser.color and setTarget.UserColor~=setUser.color then
  699. giveReward( "Help", setUser.zone )
  700. end
  701.  
  702. destroyObject(powerup)
  703. clearCards(setTarget.zone)
  704.  
  705. -- Unlock Chips
  706. local zoneObjectList = setTarget.zone.getObjects()
  707. for j, bet in ipairs(zoneObjectList) do
  708. if (bet.tag == "Chip" and not powerupEffectTable[bet.getName()]) or (bet.tag == "Bag" and bet.getName():sub(1,11)~="Player save") then
  709. bet.interactable = true
  710. bet.setLock(false)
  711. end
  712. end
  713.  
  714. return true
  715. else
  716. broadcastToColor("Must use powerup on a zone with cards in it, also the targeted player must be losing and not busted.", setUser.color, {1,0.5,0.5})
  717. end
  718. end,
  719. ["Alt. Clear"] = function( setTarget, powerup, setUser )
  720. if roundStateID~=2 and roundStateID~=3 then return end
  721.  
  722. local cardsInZone = findCardsInZone(setTarget.zone)
  723. local decksInZone = findDecksInZone(setTarget.zone)
  724. if (#cardsInZone>0 or #decksInZone>0) and (setTarget.value <= 21 or (setTarget.value>=68 and setTarget.value<=72)) then
  725. if setTarget.color~=setUser.color and setTarget.UserColor~=setUser.color then
  726. local dealerValue = objectSets[1].value
  727. local v = cardNameTable[powerup.getName()] or 0
  728.  
  729. if (setTarget.value>dealerValue and v<=dealerValue) or (setTarget.value==dealerValue and v<dealerValue) then
  730. if setUser.value<setTarget.value and not GetSetting("Powerups.AllowHostile", true) then
  731. broadcastToColor("This powerup cannot be used to make another player lose.", setUser.color, {1,0.5,0.5})
  732.  
  733. return false
  734. end
  735. elseif dealerValue<=21 and v>0 and (v<=21 and ((v>dealerValue and setTarget.value<=dealerValue) or (v>=dealerValue and setTarget.value<dealerValue))) or (setTarget.value<=dealerValue and v>=68 and v<=72) then
  736. giveReward( "Help", setUser.zone )
  737. end
  738. end
  739.  
  740. clearCards(setTarget.zone)
  741. if currentPlayerTurn==setTarget.color then playerStand(setTarget.btnHandler,"Black") end
  742.  
  743. return true
  744. else
  745. broadcastToColor("Must use powerup on a zone with cards in it, cannot be played on a busted player.", setUser.color, {1,0.5,0.5})
  746. end
  747. end,
  748. Redraw = function( setTarget, powerup, setUser )
  749. if roundStateID~=2 and roundStateID~=3 then return end
  750.  
  751. local cardsInZone = findCardsInZone(setTarget.zone)
  752. local decksInZone = findDecksInZone(setTarget.zone)
  753. if (#cardsInZone>0 or #decksInZone>0) and (setTarget.value<=21 or (setTarget.value>=68 and setTarget.value<=72)) then
  754. destroyObject(powerup)
  755. clearCards(setTarget.zone)
  756. if setTarget == objectSets[1] then
  757. dealDealer({1,2})
  758. else
  759. dealPlayer(setTarget.color, {1,2})
  760. end
  761.  
  762. if setTarget.color=="Dealer" and dealersTurn then
  763. startLuaCoroutine( Global, "DoDealersCards" )
  764. end
  765.  
  766. return true
  767. else
  768. broadcastToColor("Must use powerup on a zone with cards in it, cannot be played on a busted player.", setUser.color, {1,0.5,0.5})
  769. end
  770. end,
  771. ["Redraw All"] = function( setTarget, powerup, setUser )
  772. if roundStateID~=2 and roundStateID~=3 then return end
  773.  
  774. local cardsInZone = findCardsInZone(setUser.zone)
  775. local decksInZone = findDecksInZone(setTarget.zone)
  776. if (#cardsInZone>0 or #decksInZone>0) then
  777. for hand, set in ipairs(objectSets) do
  778. local cardsInZone = findCardsInZone(set.zone)
  779. local decksInZone = findDecksInZone(set.zone)
  780. if (#cardsInZone>0 or #decksInZone>0) then
  781. destroyObject(powerup)
  782. clearCards(set.zone)
  783. if set == objectSets[1] then
  784. dealDealer({1,2})
  785. else
  786. dealPlayer(set.color, {1,2})
  787. end
  788. end
  789. end
  790.  
  791. if dealersTurn then
  792. startLuaCoroutine( Global, "DoDealersCards" )
  793. end
  794.  
  795. return true
  796. else
  797. broadcastToColor("Must use powerup on a zone with cards in it.", setUser.color, {1,0.5,0.5})
  798. end
  799. end,
  800. Swap = function( setTarget, powerup, setUser )
  801. if roundStateID~=2 and roundStateID~=3 then return end
  802.  
  803. local tableZ1 = findCardsInZone(setTarget.zone)
  804. local tableZ2 = findCardsInZone(setUser.zone)
  805.  
  806. local decksZ1 = findDecksInZone(setTarget.zone) for i=1,#decksZ1 do table.insert(tableZ1, decksZ1[i]) end
  807. local decksZ2 = findDecksInZone(setUser.zone) for i=1,#decksZ2 do table.insert(tableZ2, decksZ2[i]) end
  808. if #tableZ1 ~= 0 and #tableZ2 ~= 0 and (setUser.value<=21 or (setUser.value==68) or (setUser.value==69 and setUser.count==2) or (setUser.value==71 and setUser.count==2) or (setUser.value==70 and setUser.count==3)) then
  809. if setTarget.color~="Dealer" and setTarget.color~=setUser.color and setTarget.UserColor~=setUser.color then
  810. if (setTarget.value==71 and setTarget.count==2) or (setTarget.value==70 and setTarget.count==3) then -- Triple seven/Double joker stolen
  811. giveReward( "StealJokers", setUser.zone )
  812. elseif (setUser.value==71 and setUser.count==2) or (setUser.value==70 and setUser.count==3) then -- Triple seven/Double joker given away
  813. giveReward( "GiveJokers", setUser.zone )
  814. elseif setUser.value>setTarget.value then
  815. local dealerValue = objectSets[1].value
  816. if dealerValue>0 and dealerValue<=21 and (setUser.value>dealerValue and setTarget.value<=dealerValue) or (setUser.value==dealerValue and setTarget.value<dealerValue) then
  817. giveReward( "Help", setUser.zone )
  818. end
  819. elseif setUser.value<setTarget.value and not GetSetting("Powerups.AllowHostile", true) then
  820. broadcastToColor("This powerup cannot be used to make another player lose.", setUser.color, {1,0.5,0.5})
  821.  
  822. return false
  823. end
  824. end
  825.  
  826. swapHandZones(setTarget.zone, setUser.zone, tableZ1, tableZ2)
  827. destroyObject(powerup)
  828.  
  829. if setTarget.color=="Dealer" and dealersTurn then
  830. startLuaCoroutine( Global, "DoDealersCards" )
  831. end
  832.  
  833. return true
  834. else
  835. broadcastToColor("Must use powerup on a zone with cards in it while you also have cards, cannot be played while busted.", setUser.color, {1,0.5,0.5})
  836. end
  837. end,
  838. Clone = function( setTarget, powerup, setUser )
  839. if roundStateID~=2 and roundStateID~=3 then return end
  840.  
  841. local tableZ1 = findCardsInZone(setTarget.zone)
  842. local tableZ2 = findCardsInZone(setUser.zone)
  843.  
  844. local decksZ1 = findDecksInZone(setTarget.zone) for i=1,#decksZ1 do table.insert(tableZ1, decksZ1[i]) end
  845. local decksZ2 = findDecksInZone(setUser.zone) for i=1,#decksZ2 do table.insert(tableZ2, decksZ2[i]) end
  846. if #tableZ1 ~= 0 and #tableZ2 ~= 0 and (setUser.value <= 21 or (setUser.value>=68 and setUser.value<=72)) then
  847. if setTarget.color~="Dealer" then
  848. if (setTarget.value==71 and setTarget.count==2) or (setTarget.value==70 and setTarget.count==3) then -- Triple seven/Double joker cloned
  849. giveReward( "CopyJokers", setUser.zone )
  850. end
  851. end
  852.  
  853. clearCardsOnly(setUser.zone)
  854. cloneHandZone(setTarget.zone, setUser.zone)
  855. destroyObject(powerup)
  856. return true
  857. else
  858. broadcastToColor("Must use powerup on a zone with cards in it while you also have cards, cannot be played while busted.", setUser.color, {1,0.5,0.5})
  859. end
  860. end,
  861. Destroy = function( setTarget, powerup, setUser )
  862. local cards = findCardsInZone(setTarget.zone)
  863.  
  864. table.sort( cards, function(a,b)
  865. local aStarter = a.getTable("blackjack_playerSet")
  866. local bStarter = b.getTable("blackjack_playerSet")
  867.  
  868. if aStarter and not bStarter then
  869. return true
  870. elseif bStarter and not aStarter then
  871. return false
  872. end
  873.  
  874. local aPos = a.getPosition()
  875. local bPos = b.getPosition()
  876.  
  877. if math.abs(aPos.z-bPos.z)<0.25 then -- Allow for a small variance in position, if we're too strict cards might re-order
  878. if math.abs(aPos.x-bPos.x)<0.25 then
  879. return aPos.y<bPos.y
  880. end
  881. return aPos.x>bPos.x
  882. end
  883.  
  884. return aPos.z<bPos.z
  885. end)
  886.  
  887. if cards[#cards] and not (cards[#cards]==nil) then
  888. cards[#cards].destruct()
  889. destroyObject(powerup)
  890.  
  891. if dealersTurn and setTarget.color=="Dealer" then
  892. startLuaCoroutine( Global, "DoDealersCards" )
  893. end
  894.  
  895. return true
  896. end
  897. end,
  898. Reveal = function( setTarget, powerup, setUser )
  899. if roundStateID~=2 and roundStateID~=3 then return end
  900.  
  901. local cardsInZone = findCardsInZone(setTarget.zone)
  902. if #cardsInZone == 2 then
  903. if setTarget.color=="Dealer" and GetSetting("Powerups.RevealIsHelp", true) then
  904. giveReward( "Help", setUser.zone )
  905. end
  906.  
  907. revealHandZone(setTarget.zone)
  908. destroyObject(powerup)
  909. return true
  910. end
  911. end,
  912. Stand = function( setTarget, powerup, setUser )
  913. if roundStateID~=2 and roundStateID~=3 then return end
  914.  
  915. local cardsInZone = findCardsInZone(setTarget.zone)
  916. if #cardsInZone < 2 then
  917. broadcastToColor("This powerup can only be used on a hand with more than two cards.", setUser.color, {1,0.5,0.5})
  918. return
  919. end
  920.  
  921. local newValue = 0
  922. for i, card in ipairs(findCardsInZone(setTarget.zone) or {}) do
  923. x = card.getPosition().x
  924. if x < 3 then
  925. card.destruct()
  926. else
  927. local cardValue = (card.getName()=="Ace" and 1) or cardNameTable[card.getName()] or 0
  928. newValue = newValue + cardValue
  929. end
  930. end
  931.  
  932. if setTarget.color=="Dealer" and (setTarget.value<=21 or (setTarget.value>=68 and setTarget.value<=72)) then
  933. for i=2,#objectSets do
  934. local s = objectSets[i]
  935. if s~=setUser and s.UserColor~=setUser.color and (s.value>0 or s.count>0) and s.value<=21 and ((s.value<setTarget.value and s.value>=newValue) or (s.value==setTarget.value and s.value>newValue)) then -- Helped someone
  936. giveReward( "Help", setUser.zone )
  937.  
  938. if not GetSetting("Powerups.MultiHelp", true) then break end
  939. end
  940. end
  941. end
  942.  
  943. destroyObject(powerup)
  944. return true
  945. end,
  946. ["Draw 1"] = function( setTarget, powerup, setUser )
  947. if roundStateID~=2 and roundStateID~=3 then return end
  948.  
  949. local cardsInZone = findCardsInZone(setTarget.zone)
  950. local decksInZone = findCardsInZone(setTarget.zone)
  951. if #cardsInZone>0 or #decksInZone>0 then
  952. local nextCard = (mainDeck.getObjects()[1] or {}).nickname or ""
  953. local nextCardValue = (nextCard=="Ace" and 1) or cardNameTable[nextCard] or 0 -- Counts joker as 12, but whatever
  954.  
  955. if setTarget.color=="Dealer" then
  956. if (setTarget.value<=21 and setTarget.value+nextCardValue>21) or (setTarget.value>=68 and setTarget.value<=72) then
  957. for i=2,#objectSets do
  958. local s = objectSets[i]
  959. if s~=setUser and s.UserColor~=setUser.color and (s.value>0 or s.count>0) and s.value<=21 and s.value<=setTarget.value then -- Helped someone
  960. giveReward( "Help", setUser.zone )
  961.  
  962. if not GetSetting("Powerups.MultiHelp", true) then break end
  963. end
  964. end
  965. end
  966.  
  967. forcedCardDraw(setTarget.zone)
  968.  
  969. while lastCard.getName() == "Joker" do
  970. lastCard.destruct()
  971. forcedCardDraw(setTarget.zone, "Black")
  972. resetTimer(3)
  973. end
  974. else
  975. local dealerValue = objectSets[1].value
  976. if dealerValue<=21 and dealerValue<setTarget.value and (setTarget.value<=21 or setTarget.value>=67 and setTarget.value<=72) then
  977. if not GetSetting("Powerups.AllowHostile", true) then
  978. broadcastToColor("This powerup cannot be used on a winning player.", setUser.color, {1,0.5,0.5})
  979.  
  980. return false
  981. end
  982. end
  983.  
  984. local newValue = setTarget.value+nextCardValue
  985.  
  986. if nextCard=="Joker" or (newValue<=21 and ((setTarget.value<dealerValue and newValue>=dealerValue) or (setTarget.value==dealerValue and newValue>dealerValue))) then
  987. giveReward( "Help", setUser.zone )
  988. end
  989.  
  990. forcedCardDraw(setTarget.zone)
  991. end
  992.  
  993. destroyObject(powerup)
  994. return true
  995. end
  996. end,
  997. ["Powerup Draw"] = function( setTarget, powerup, setUser )
  998. if spawnRandomPowerup(setUser.zone) then
  999. destroyObject(powerup)
  1000. else
  1001. print( "WARNING: Failed to draw powerup for "..setUser.color.."! Are there powerups available on this table?" )
  1002. broadcastToColor("Error: Failed to draw powerup. Are there powerups available on this table?", setUser.color, {1,0.25,0.25})
  1003. end
  1004. end,
  1005. ["Rupee Pull"] = function( setTarget, powerup, setUser )
  1006. local betsInZone = findBetsInZone(setTarget.zone)
  1007. local cardsInZone = findCardsInZone(setTarget.zone)
  1008. local decksInZone = findCardsInZone(setTarget.zone)
  1009. if #betsInZone ~= 0 and #cardsInZone == 0 and #decksInZone == 0 then
  1010. if rupeePull(setTarget.zone) then
  1011. destroyObject(powerup)
  1012. end
  1013. else
  1014. broadcastToColor("To use: between rounds, place a bet and then drop into your own zone.", setUser.color, {1,0.5,0.5})
  1015. end
  1016. end,
  1017. ["Reward Token"] = function( setTarget, powerup, setUser )
  1018. if powerup.getQuantity() == 2 then
  1019. takeObjectFromContainer(setUser.zone, "737b2a")
  1020. destroyObject(powerup)
  1021. elseif powerup.getQuantity() == 5 then
  1022. takeObjectFromContainer(setUser.zone, "ea79f0")
  1023. destroyObject(powerup)
  1024. else
  1025. broadcastToColor("To use: group together the exact amount based on chosen reward and then drop into your own zone.", setUser.color, {1,0.5,0.5})
  1026. end
  1027. end,
  1028. ["Royal Token"] = function( setTarget, powerup, setUser )
  1029. if powerup.getQuantity() == -1 then
  1030. takeObjectFromContainer(setUser.zone, "737b2a")
  1031. destroyObject(powerup)
  1032. elseif powerup.getQuantity() == 2 then
  1033. takeObjectFromContainer(setUser.zone, "ea79f0")
  1034. destroyObject(powerup)
  1035. else
  1036. broadcastToColor("To use: group together the exact amount based on chosen reward and then drop into your own zone.", setUser.color, {1,0.5,0.5})
  1037. end
  1038. end,
  1039. ["Prestige Token"] = function( setTarget, powerup, setUser )
  1040. local prestigeObj
  1041. local set = findObjectSetFromZone(setUser.zone)
  1042. local zoneObjects = set.prestige.getObjects()
  1043.  
  1044. local level = 0
  1045. for i, object in ipairs(zoneObjects) do
  1046. local findLevel = object.getVar("PrestigeLevel")
  1047. if findLevel then
  1048. if findLevel>=level then
  1049. level = findLevel
  1050. prestigeObj = object
  1051. end
  1052. else
  1053. local findMatch = string.match(object.getVar("__trader_ObjectName") or object.getName(), "Prestige (%d+)")
  1054. if findMatch and tonumber(findMatch)>=level and not string.find(object.getName(), "Trophy") then
  1055. level = tonumber(findMatch) or 0
  1056. prestigeObj = object
  1057. elseif level<=0 and string.find(object.getName(), "New player") and not string.find(object.getName(), "Trophy") then
  1058. level = 0
  1059. prestigeObj = object
  1060. end
  1061. end
  1062. end
  1063.  
  1064. if prestigeObj and level then
  1065. if doPrestige(set, level+1) then
  1066. destroyObject(powerup)
  1067. else
  1068. broadcastToColor("Error: Prestige failed.", setUser.color, {1,0.5,0.5})
  1069. end
  1070. else
  1071. broadcastToColor("To use: place your current prestige rupee above your hand then drop into your own zone.", setUser.color, {1,0.5,0.5})
  1072. end
  1073. end,
  1074. ["Reset Timer"] = function( setTarget, powerup, setUser )
  1075. resetTimer(3)
  1076. destroyObject(powerup)
  1077.  
  1078. return true
  1079. end,
  1080. ["Card Mod"] = function( setTarget, powerup, setUser )
  1081. if roundStateID~=2 and roundStateID~=3 then return end
  1082.  
  1083. if (#findCardsInZone(setTarget.zone)>0 or #findDecksInZone(setTarget.zone)>0 or #findFigurinesInZone(setTarget.zone)>1) then
  1084. local powerupValue = cardNameTable[powerup.getName()] or 0
  1085. -- findCardsToCount() -- Recount
  1086. updateHandCounter( setTarget )
  1087.  
  1088. if setTarget.color=="Dealer" then
  1089. if setTarget.count==4 and setTarget.value<=21 and setTarget.value>0 then -- This makes 5 card bust
  1090. for i=2,#objectSets do
  1091. local s = objectSets[i]
  1092. if (s~=setUser and s.SplitUser~=setUser) and (s.value>0 or s.count>0) and s.value<=setTarget.value then
  1093. giveReward( "Help", setUser.zone )
  1094. if not GetSetting("Powerups.MultiHelp", true) then break end
  1095. end
  1096. end
  1097. elseif setTarget.count<4 and setTarget.value<=21 and setTarget.value>0 then -- Not bust before this powerup
  1098. local newValue = setTarget.value+powerupValue
  1099.  
  1100. if newValue>21 or newValue<=0 then -- Bust after this powerup
  1101. for i=2,#objectSets do
  1102. local s = objectSets[i]
  1103. if (s~=setUser and s.SplitUser~=setUser) and (s.value>0 or s.count>0) and s.value<=setTarget.value then
  1104. giveReward( "Help", setUser.zone )
  1105. if not GetSetting("Powerups.MultiHelp", true) then break end
  1106. end
  1107. end
  1108. else
  1109. for i=2,#objectSets do
  1110. local s = objectSets[i]
  1111. if (s~=setUser and s.SplitUser~=setUser) and (s.value>0 or s.count>0) and s.value<=21 and ((s.value<setTarget.value and s.value>=newValue) or (s.value==setTarget.value and s.value>newValue)) then -- Helped someone
  1112. giveReward( "Help", setUser.zone )
  1113. if not GetSetting("Powerups.MultiHelp", true) then break end
  1114. end
  1115. end
  1116. end
  1117. elseif setTarget.value==69 then -- Dealer blackjack
  1118. local newValue = 11+powerupValue
  1119.  
  1120. for i=2,#objectSets do
  1121. local s = objectSets[i]
  1122. if (s~=setUser and s.SplitUser~=setUser) and (s.value>0 or s.count>0) and s.value<=21 and s.value>=newValue then -- Helped someone
  1123. giveReward( "Help", setUser.zone )
  1124. if not GetSetting("Powerups.MultiHelp", true) then break end
  1125. end
  1126. end
  1127. end
  1128. else
  1129. local dealer = objectSets[1]
  1130. local newValue = setTarget.value + powerupValue
  1131. if newValue>21 and setTarget.value<=21 and string.find(powerup.getDescription(), "[Cc]an%'?n?o?t be used to bust ?a?n?o?t?h?e?r? player") then
  1132. broadcastToColor("This powerup cannot be used to bust another player.", setUser.color, {1,0.5,0.5})
  1133. return false
  1134. end
  1135. if setTarget.color~=setUser.color and setTarget.UserColor~=setUser.color then
  1136. if not GetSetting("Powerups.AllowHostile", true) then
  1137. if setTarget.value>=dealer.value and setTarget.value<=21 and newValue<dealer.value then
  1138. broadcastToColor("This powerup cannot be used to make another player lose.", setUser.color, {1,0.5,0.5})
  1139.  
  1140. return false
  1141. elseif newValue>21 and setTarget.value<=21 and setTarget.value>=dealer.value and dealer.value<=21 and dealer.value>0 then
  1142. broadcastToColor("This powerup cannot be used to make another player lose.", setUser.color, {1,0.5,0.5})
  1143.  
  1144. return false
  1145. end
  1146. end
  1147.  
  1148. if newValue<=21 and (dealer.value>21 or newValue>=dealer.value or dealer.count>=5) then
  1149. if (setTarget.value<dealer.value and newValue>=dealer.value and dealer.count<5) or -- Was less than dealer (dealer not bust) OR
  1150. (setTarget.value==dealer.value and newValue>dealer.value and dealer.count<5) or (setTarget.value>21) then -- Was equal to dealer, now over (dealer not bust) OR Was bust
  1151. giveReward( "Help", setUser.zone )
  1152. end
  1153. elseif setTarget.value>21 and newValue>21 and setTarget.count==4 then -- From bust to 5-card push
  1154. giveReward( "Help", setUser.zone )
  1155. end
  1156. end
  1157. end
  1158.  
  1159. if setTarget.color=="Dealer" and dealersTurn then
  1160. startLuaCoroutine( Global, "DoDealersCards" )
  1161. end
  1162.  
  1163. return true
  1164. else
  1165. broadcastToColor("Must use powerup on a zone with cards in it.", setUser.color, {1,0.5,0.5})
  1166. end
  1167. end,
  1168. }
  1169. function activatePowerupFailedCallback(data)
  1170. if not (data.obj and data.obj==nil) then -- No specific null check I know of, but this check seems to work
  1171. if data.obj.getName():lower()=="royal token" or data.obj.getName():lower()=="reward token" then return end
  1172.  
  1173. if GetSetting("Powerups.FifthCard", true) then
  1174. if data.target.count~=4 then return end
  1175. if (data.target.value<=21 and data.target.value>=objectSets[1].value) or (data.target.value>=68 and data.target.value<=72) then return end -- No effect
  1176. if data.user.color~=data.target.color and data.user.color~=data.target.UserColor then
  1177. giveReward( "Help", data.user.zone )
  1178. end
  1179.  
  1180. local target = data.target.color
  1181. if data.target.color == data.user.color then target = "themself" elseif data.target.color == "Dealer" then target = "the dealer" end
  1182.  
  1183. if data.target.UserColor then
  1184. if data.target.UserColor == data.user.color then
  1185. target = target.." (themself)"
  1186. elseif data.target.color == "Dealer" then
  1187. target = target.." (the dealer)"
  1188. else
  1189. target = target.." ("..data.target.UserColor..")"
  1190. end
  1191. end
  1192.  
  1193. printToAll("Powerup event: " ..data.user.color.. " used " ..data.obj.getName().. " as a fifth card for " ..target.. ".", {0.5,0.5,1})
  1194.  
  1195. data.obj.setPosition( findPowerupPlacement(data.target.zone, #findFigurinesInZone(data.target.zone)+1) )
  1196. data.obj.setRotation( {0,0,0} )
  1197. data.obj.setName("Fifth Card")
  1198. data.obj.setDescription("This powerup has been used as a fifth card to give this hand bust immunity.")
  1199. data.obj.lock()
  1200. cardNameTable["Fifth Card"] = nil
  1201.  
  1202. data.obj.setColorTint( stringColorToRGB(data.user.color) or {1,1,1} )
  1203.  
  1204. if roundStateID==3 and roundTimer and roundTimer.getValue()<10 then
  1205. roundTimer.setValue( 10 )
  1206. roundTimer.Clock.paused = false
  1207. end
  1208. end
  1209. end
  1210. end
  1211. function activatePowerupEffect(effect, setTarget, powerup, setUser)
  1212. findCardsToCount() -- Make sure our hand value is up to date
  1213. Wait.frames(function() findCardsToCount() end, 2) -- Recount after delay, so we're up to date afterwards too
  1214.  
  1215. if powerupEffectFunctions[effect] then
  1216. if not powerupEffectFunctions[effect](setTarget, powerup, setUser) then
  1217. local timerID = "PowerupFailed"..tostring(powerup.getGUID())
  1218. Timer.destroy(timerID)
  1219. Timer.create( {identifier=timerID, function_name="activatePowerupFailedCallback", parameters={obj=powerup, user=setUser, target=setTarget}, delay=0} )
  1220. return
  1221. end
  1222. elseif powerup.getVar("powerupUsed") then
  1223. if not powerup.call("powerupUsed", {setTarget=setTarget, powerup=powerup, setUser=setUser}) then
  1224. local timerID = "PowerupFailed"..tostring(powerup.getGUID())
  1225. Timer.destroy(timerID)
  1226. Timer.create( {identifier=timerID, function_name="activatePowerupFailedCallback", parameters={obj=powerup, user=setUser, target=setTarget}, delay=0} )
  1227. return
  1228. end
  1229. else
  1230. local timerID = "PowerupFailed"..tostring(powerup.getGUID())
  1231. Timer.destroy(timerID)
  1232. Timer.create( {identifier=timerID, function_name="activatePowerupFailedCallback", parameters={obj=powerup, user=setUser, target=setTarget}, delay=0} )
  1233. return
  1234. end
  1235.  
  1236. local target = setTarget.color
  1237. if setTarget.color == setUser.color then target = "themself" elseif setTarget.color == "Dealer" then target = "the dealer" end
  1238.  
  1239. if setTarget.UserColor then
  1240. if setTarget.UserColor == setUser.color then
  1241. target = target.." (themself)"
  1242. elseif setTarget.color == "Dealer" then
  1243. target = target.." (the dealer)"
  1244. else
  1245. target = target.." ("..setTarget.UserColor..")"
  1246. end
  1247. end
  1248.  
  1249. printToAll("Powerup event: " ..setUser.color.. " used " ..powerup.getName().. " on " ..target.. ".", {0.5,0.5,1})
  1250.  
  1251. powerup.setPosition( findPowerupPlacement(setTarget.zone, #findFigurinesInZone(setTarget.zone)+1) )
  1252. powerup.setRotation( {0,0,0} )
  1253. powerup.lock()
  1254.  
  1255. powerup.setColorTint( stringColorToRGB(setUser.color) or {1,1,1} )
  1256.  
  1257. if roundStateID==3 and roundTimer and roundTimer.getValue()<10 then
  1258. preventRoundEnd = os.time() + 1
  1259. roundTimer.setValue( 10 )
  1260. roundTimer.Clock.paused = false
  1261. end
  1262. end
  1263.  
  1264. function AddPowerup(data) -- If TTS devs ever get over their weird phobia of using functions as variables (How Lua was DESIGNED) this function will be more useful. For now, on the object use `Global.call("AddPowerup", dataTable)` and have a global `powerupUsed` function.
  1265. if not (data.obj and data.who) then return end
  1266.  
  1267. local name = data.obj.getName()
  1268. if (not name) or name=="" or powerupEffectTable[name] then return end
  1269.  
  1270. local effectName = data.effectName or name -- Failsafe
  1271.  
  1272. powerupEffectTable[name] = {who=data.who, effect=data.effectName}
  1273. powerupEffectFunctions[effectName] = powerupEffectFunctions[effectName] or data.func -- If we already have a function here, use that instead
  1274. table.insert(powerupTable, {data.obj.getGUID(), name})
  1275. end
  1276.  
  1277.  
  1278.  
  1279.  
  1280.  
  1281. --POWERUP EFFECTS SECTION
  1282.  
  1283.  
  1284.  
  1285.  
  1286.  
  1287. --Triggerd by powerup, this switches the cards in 2 zones (zone1 and zone2)
  1288. function swapHandZones(zone1, zone2, tableZ1, tableZ2)
  1289. for i, card in ipairs(tableZ1) do
  1290. local pos = findCardPlacement(zone2, i)
  1291. card.setPosition(pos)
  1292.  
  1293. Wait.frames(function()
  1294. if (not card) or card==nil then return end
  1295. cardPlacedCallback(card, {targetPos=pos, set=findObjectSetFromZone(zone2), isStarter=card.getTable("blackjack_playerSet"), flip=true})
  1296. end, 1)
  1297. end
  1298. for i, card in ipairs(tableZ2) do
  1299. local pos = findCardPlacement(zone1, i)
  1300. card.setPosition(pos)
  1301.  
  1302. Wait.frames(function()
  1303. if (not card) or card==nil then return end
  1304. cardPlacedCallback(card, {targetPos=pos, set=findObjectSetFromZone(zone1), isStarter=card.getTable("blackjack_playerSet"), flip=true})
  1305. end, 1)
  1306. end
  1307. end
  1308.  
  1309. --Clones (copies and pastes) cards from targetZone to the zone of colorUser
  1310. function cloneHandZone(targetZone, userZone)
  1311. local targetCardList = findCardsInZone(targetZone)
  1312. local targetDeckList = findDecksInZone(targetZone) for i=1,#targetDeckList do table.insert(targetCardList, targetDeckList[i]) end
  1313. if #targetCardList ~= 0 then
  1314. for i, card in ipairs(targetCardList) do
  1315. local pos = findCardPlacement(userZone, i)
  1316. local clone = card.clone({position=pos}) -- Why is there no callback for this function?
  1317. clone.setPosition(pos)
  1318.  
  1319. cardPlacedCallback(clone, {targetPos=pos, set=findObjectSetFromZone(userZone), isStarter=card.getTable("blackjack_playerSet"), flip=true})
  1320. end
  1321. else
  1322. printToAll("ERROR: You cannot copy and empty hand. Copy Canceled.", {1,0.1,0.1})
  1323. end
  1324. end
  1325.  
  1326. --Reveals any face-down cards
  1327. function DoDealersCards()
  1328. if dealingDealersCards or (not dealersTurn) then return 1 end
  1329. dealingDealersCards = true -- Make sure this coroutine doesn't start while it's already running
  1330.  
  1331. local set = objectSets[1]
  1332.  
  1333. waitTime(0.5)
  1334. local targetCardList = findCardsInZone(set.zone)
  1335. if #targetCardList ~= 0 then
  1336. for i, card in ipairs(targetCardList) do
  1337. if not dealingDealersCards then return end
  1338.  
  1339. local z = card.getRotation().z
  1340. if z > 15 and z < 345 then
  1341. local pos = card.getPosition()
  1342. card.setRotation({0,0,0})
  1343. card.setPosition(pos)
  1344.  
  1345. waitTime(0.5)
  1346. end
  1347. end
  1348. end
  1349.  
  1350. -- findCardsToCount()
  1351. updateHandCounter( set[1] )
  1352. waitTime(0.05)
  1353.  
  1354. local standValue = GetSetting("Hands.DealerStandValue", 17)
  1355.  
  1356. while (set.value<standValue and set.value<=21 and set.value>0 and set.count<5) do
  1357. if not dealingDealersCards then return end
  1358. updateHandCounter( set[1] )
  1359.  
  1360. if set.value>=0 then
  1361. hitCard(set.btnHandler, "Black")
  1362.  
  1363. while lastCard.getName() == "Joker" do
  1364. lastCard.destruct()
  1365. hitCard(set.btnHandler, "Black")
  1366. resetTimer(3)
  1367. end
  1368. end
  1369.  
  1370. waitTime(0.5)
  1371. -- findCardsToCount()
  1372. updateHandCounter( set[1] )
  1373. updateAllDisplays()
  1374. waitTime(0.05)
  1375. end
  1376. if not dealingDealersCards then return end
  1377.  
  1378. if set.count>=5 then
  1379. printToAll("Dealer: 5-card bust.", {0.1,0.1,0.1})
  1380. elseif set.value>=67 or set.value<0 then -- Out of standard range - Special values
  1381. printToAll("Dealer: Stand.", {0.1,0.1,0.1})
  1382. elseif set.value>21 then
  1383. printToAll("Dealer: Bust.", {0.1,0.1,0.1})
  1384. else
  1385. printToAll("Dealer: Stand on ".. tostring(set.value) ..".", {0.1,0.1,0.1})
  1386. end
  1387. updateAllDisplays()
  1388.  
  1389. dealingDealersCards = false
  1390.  
  1391. setRoundState( 3, GetSetting("Rounds.PowerupsTime", 20) )
  1392.  
  1393. return 1
  1394. end
  1395. function revealHandZone(targetZone)
  1396. local targetCardList = findCardsInZone(targetZone)
  1397. if #targetCardList ~= 0 then
  1398. for i, card in ipairs(targetCardList) do
  1399. local z = card.getRotation().z
  1400. if z > 15 and z < 345 then
  1401. -- card.flip()
  1402.  
  1403. card.setRotation({0,0,0})
  1404.  
  1405. local pos = card.getPosition()
  1406. pos.y = pos.y + 0.2
  1407. card.setPosition(pos)
  1408. end
  1409. end
  1410.  
  1411. if targetZone==objectSets[1].zone then -- Dealer
  1412. startLuaCoroutine( Global, "DoDealersCards" )
  1413. end
  1414.  
  1415. updateHandCounter( findObjectSetFromZone(targetZone) )
  1416. else
  1417. printToAll("ERROR: No cards to reveal. Powerup devoured anyway.", {1,0.1,0.1})
  1418. end
  1419. end
  1420.  
  1421. --Draws a card, forced by powerup
  1422. function forcedCardDraw(targetZone)
  1423. local targetCardList = findCardsInZone(targetZone)
  1424. local cardToDraw = #targetCardList + 1
  1425. local pos = findCardPlacement(targetZone, cardToDraw)
  1426. placeCard(pos, true, findObjectSetFromZone(targetZone), false)
  1427. end
  1428.  
  1429. local spawnPowerupPosModifier = {}
  1430. function spawnRandomPowerup(targetZone)
  1431. if #powerupTable==0 then return false end
  1432.  
  1433. local chosenIndex = math.random(1, #powerupTable)
  1434. local chosenPowerup = powerupTable[chosenIndex]
  1435. local chosenObject = getObjectFromGUID(chosenPowerup[1])
  1436. if not chosenObject then
  1437. table.remove(powerupTable, chosenIndex)
  1438.  
  1439. local found = false
  1440. for _,obj in pairs(getAllObjects()) do
  1441. if obj.getLock() and obj.getName()==chosenPowerup[2] then
  1442. found = true
  1443.  
  1444. table.insert(powerupTable, {obj.getGUID(), chosenPowerup[2]})
  1445.  
  1446. break
  1447. end
  1448. end
  1449.  
  1450. return spawnRandomPowerup(targetZone)
  1451. end
  1452.  
  1453.  
  1454. local params = {}
  1455. params.position = targetZone.positionToWorld({0.5,0 + (spawnPowerupPosModifier[targetZone] or 0),-0.5})
  1456. local clone = chosenObject.clone(params)
  1457. clone.unlock()
  1458.  
  1459. spawnPowerupPosModifier[targetZone] = (spawnPowerupPosModifier[targetZone] or 0) + 0.04
  1460. Wait.frames(function()
  1461. spawnPowerupPosModifier[targetZone] = nil
  1462. end, 2)
  1463.  
  1464. local plyCol = (findObjectSetFromZone(targetZone) or {}).color
  1465. if plyCol=="Dealer" or plyCol:sub(1,5)=="Split" then plyCol = nil end
  1466. if plyCol and Player[plyCol].seated then
  1467. clone.setDescription( ("%s - %s\n\n%s"):format( Player[plyCol].steam_id, Player[plyCol].steam_name, clone.getDescription() ) )
  1468. end
  1469.  
  1470. return true
  1471. end
  1472.  
  1473. function takeRandomObjectFromContainer(targetZone, takeFrom)
  1474. local params = {}
  1475. -- params.position = targetZone.getPosition()
  1476. params.position = targetZone.positionToWorld({0.5,0 + (spawnPowerupPosModifier[targetZone] or 0),-0.5})
  1477. container = getObjectFromGUID(takeFrom).takeObject(params)
  1478. container.shuffle()
  1479. takenObject = container.takeObject(params)
  1480. container.destruct()
  1481.  
  1482.  
  1483. spawnPowerupPosModifier[targetZone] = (spawnPowerupPosModifier[targetZone] or 0) + 0.04
  1484. Wait.frames(function()
  1485. spawnPowerupPosModifier[targetZone] = nil
  1486. end, 2)
  1487. end
  1488.  
  1489. function takeObjectFromContainer(targetZone, takeFrom, posOverride)
  1490. local params = {}
  1491. -- params.position = targetZone.getPosition()
  1492. params.position = targetZone.positionToWorld(posOverride or {0.5,0 + (spawnPowerupPosModifier[targetZone] or 0),-0.5})
  1493. takenObject = getObjectFromGUID(takeFrom).takeObject(params)
  1494.  
  1495.  
  1496. spawnPowerupPosModifier[targetZone] = (spawnPowerupPosModifier[targetZone] or 0) + 0.04
  1497. Wait.frames(function()
  1498. spawnPowerupPosModifier[targetZone] = nil
  1499. end, 2)
  1500.  
  1501. return takenObject
  1502. end
  1503.  
  1504. local function withinChipLimit( zone, limit )
  1505. local zoneObjects = zone.getObjects()
  1506.  
  1507. local toFind = limit
  1508. for j, bet in ipairs(zoneObjects) do
  1509. if (bet.tag == "Chip" and not powerupEffectTable[bet.getName()]) then
  1510. local num = bet.getQuantity()
  1511. if num==-1 then num=1 end
  1512.  
  1513. if num<=toFind then
  1514. toFind = toFind - num
  1515. elseif num==toFind then
  1516. toFind = 0
  1517. elseif num>toFind then
  1518. return false
  1519. end
  1520. elseif (bet.tag == "Bag" and bet.getName():sub(1,11)~="Player save") then
  1521. return false
  1522. end
  1523. end
  1524.  
  1525. return true
  1526. end
  1527. function rupeePull(targetZone)
  1528. local set = findObjectSetFromZone(targetZone)
  1529.  
  1530. local rupeeLimit = GetSetting("Rupee.MaxChips", 0)
  1531. if rupeeLimit>0 and not withinChipLimit(targetZone, rupeeLimit) then
  1532. broadcastToColor("Error: Could not pull rupee. Chip limit is "..tostring(rupeeLimit).." and bet bags cannot be used.", set.color, {1,0.25,0.25})
  1533.  
  1534. return false
  1535. end
  1536.  
  1537. takeRandomObjectFromContainer(set.zone, "2e08d6")
  1538. local name = takenObject.getName()
  1539. local description = takenObject.getDescription()
  1540. destroyObject(takenObject)
  1541. if string.find(name, "prestige") then
  1542. takeObjectFromContainer(set.zone, "a65636")
  1543. elseif string.find(name, "bust") then
  1544. clearBets(set.zone)
  1545. end
  1546. takeObjectFromContainer(set.zone, string.sub(description, 1, 6))
  1547. printToAll("Rupee event: " .. set.color .. " pulled a " .. name .. ".", {0.5,1,0.5})
  1548. processPayout(set.zone, tonumber(string.sub(description, 8)) or 0)
  1549.  
  1550. return true
  1551. end
  1552.  
  1553. function resetTimer(time)
  1554. bonusTimer.setValue(time)
  1555. bonusTimer.Clock.pauseStart()
  1556. end
  1557.  
  1558.  
  1559.  
  1560.  
  1561.  
  1562. --CARD ZONE COUNTING SECTION
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568. local displayCol = {
  1569. ["Safe"] = {r=1, g=1, b=0.75},
  1570. ["Win"] = {r=0.75,g=1, b=0.75},
  1571. ["Lose"] = {r=1, g=0.75,b=0.75},
  1572.  
  1573. ["Bust"] = {r=0.75, g=0.5,b=0.5},
  1574.  
  1575. ["Clear"] = {r=1, g=1, b=1},
  1576. }
  1577. --Looks for any cards in the scripting zones and sends them on to obtainCardValue
  1578. --Looks for any decks in the scripting zones and sends them on to obtainDeckValue
  1579. --Triggers next step, addValues(), after that
  1580. local nextAutoCardCount = 0
  1581. function findCardsToCount()
  1582. nextAutoCardCount = os.time() + 5 -- Push back auto count
  1583.  
  1584. if minigame and not (minigame==nil) and minigame.getVar("blackjackCountCards") and minigame.Call("blackjackCountCards") then -- Minigame override
  1585. -- Should something happen here?
  1586. else
  1587. for hand, set in ipairs(objectSets) do
  1588. updateHandCounter( set )
  1589. end
  1590. end
  1591. timerStart()
  1592. end
  1593. function updateHandCounter( set )
  1594. if not set then return end
  1595.  
  1596. local cardList = findCardsInZone(set.zone)
  1597. local deckList = findDecksInZone(set.zone)
  1598. local figurineList = findFigurinesInZone(set.zone)
  1599. if #cardList ~= 0 or #deckList ~= 0 or #figurineList ~= 0 then
  1600. obtainCardNames(set, cardList, deckList, figurineList)
  1601. return
  1602. end
  1603.  
  1604. set.value = 0
  1605. set.count = 0
  1606.  
  1607. local override = false
  1608. if minigame and not (minigame==nil) and minigame.getVar("blackjackDisplayResult") then -- Override
  1609. local str, col = minigame.Call("blackjackDisplayResult", {set=set, value=value, soft=soft})
  1610. if str then
  1611. set.btnHandler.editButton({
  1612. index=0, label=str, color = (col and {r=col.r,g=col.g,b=col.b} or displayCol.Clear) -- Can't use the colour directly, causes errors
  1613. })
  1614.  
  1615. override = true
  1616. end
  1617. end
  1618.  
  1619. if not override then
  1620. set.btnHandler.editButton({index=0, label="0", color=displayCol.Clear})
  1621. end
  1622. end
  1623.  
  1624. --Gets a list of names from the card if they are face up
  1625. function obtainCardNames(set, cardList, deckList, figurineList)
  1626. local cardNames = {}
  1627. local facedownCount = 0
  1628. local facedownCard = nil
  1629. for i, card in ipairs(cardList) do
  1630. local z = card.getRotation().z
  1631. if z > 270 or z < 90 then
  1632. if set.color=="Dealer" and card.getName()=="Joker" then
  1633. resetTimer(3)
  1634. card.destruct()
  1635. end
  1636. table.insert(cardNames, card.getName())
  1637. elseif set.color=="Dealer" then
  1638. facedownCount = facedownCount + 1
  1639. facedownCard = card
  1640. end
  1641. end
  1642. for i, deck in ipairs(deckList) do
  1643. local z = deck.getRotation().z
  1644. if z > 270 or z < 90 then
  1645. for j, card in ipairs(deck.getObjects()) do
  1646. table.insert(cardNames, card.nickname)
  1647. end
  1648. end
  1649. end
  1650. for i, figurine in ipairs(figurineList) do
  1651. table.insert(cardNames, figurine.getName())
  1652. end
  1653. set.count = #cardNames
  1654. addCardValues(set, cardNames, facedownCount, facedownCard)
  1655. end
  1656.  
  1657. --Adds card values from their names
  1658. function addCardValues(set, cardNames, facedownCount, facedownCard)
  1659. local value = 0
  1660. local aceCount = 0
  1661. local sevenCount = 0
  1662. local tenCount = 0
  1663. local jokerCount = 0
  1664. local dealerBust = 0
  1665. local stopCount = false
  1666. for i, card in ipairs(cardNames) do
  1667. local v = cardNameTable[card]
  1668. if v then
  1669. if v == 0 then
  1670. aceCount = aceCount + 1
  1671. elseif v == 7 then
  1672. sevenCount = sevenCount + 1
  1673. elseif v == 10 then
  1674. tenCount = tenCount + 1
  1675. elseif v == 69 then
  1676. aceCount = aceCount + 1
  1677. tenCount = tenCount + 1
  1678. v = 10
  1679. elseif (v==12 or v==68) then
  1680. jokerCount = jokerCount + 1
  1681. elseif (v==71) then
  1682. jokerCount = jokerCount + 2
  1683. elseif (v==70) then
  1684. if set.count==1 then
  1685. sevenCount = sevenCount + 3
  1686. end
  1687. v = 21
  1688. elseif v == -69 then
  1689. dealerBust = dealerBust + 1
  1690. end
  1691.  
  1692. if set.color=="Dealer" then
  1693. if set.count > 4 or dealerBust > 0 then
  1694. stopCount = true
  1695. value = -69
  1696. end
  1697. else
  1698. if jokerCount > 0 then
  1699. if jokerCount == 2 and set.count <= 2 then
  1700. value = 71
  1701. else
  1702. value = 68
  1703. end
  1704. stopCount = true
  1705. elseif sevenCount == 3 and set.count <= 3 then
  1706. value = 70
  1707. stopCount = true
  1708. end
  1709. end
  1710. if not stopCount then
  1711. value = value + v
  1712. end
  1713. end
  1714. end
  1715.  
  1716. local soft = false
  1717. if aceCount > 0 and not stopCount then
  1718. for i=1, aceCount do
  1719. if i==aceCount and value <= 10 then
  1720. if aceCount == 1 and tenCount==1 and set.count<=2 then
  1721. value = 69
  1722. stopCount = true
  1723. elseif set.color=="Dealer" and facedownCount<1 and GetSetting("Hands.DealerAceIsOne", true) then
  1724. value = value + 1
  1725. else
  1726. value = value + 11
  1727. soft = true
  1728. end
  1729. else
  1730. value = value + 1
  1731. end
  1732. end
  1733. end
  1734. if value>50 and not (stopCount or set.count==1) then value=100 end
  1735.  
  1736. displayResult(set, value, soft)
  1737. --Checks for blackjack
  1738. if set.color=="Dealer" then
  1739. if #cardNames == 1 and facedownCount == 1 then
  1740. checkForBlackjack(value, facedownCard)
  1741. end
  1742. end
  1743. end
  1744.  
  1745. --Sends the card count results to the displays
  1746. --If you wanted special symbols to show up on 21, 21+ etc, you would add it here
  1747. local SoftHandDisplay = {
  1748. [1] = "①", [2] = "②", [3] = "③", [4] = "④", [5] = "⑤", [6] = "⑥", [7] = "⑦", [8] = "⑧", [9] = "⑨", [10] = "⑩",
  1749. [11] = "⑪", [12] = "⑫", [13] = "⑬", [14] = "⑭", [15] = "⑮", [16] = "⑯", [17] = "⑰", [18] = "⑱", [19] = "⑲", [20] = "⑳",
  1750. [21] = "㉑",
  1751. }
  1752. local specialHandDisplay = {
  1753. [-69] = "\u{2620}", [100] = "\u{2620}", -- Bust
  1754. [68] = "\u{2661}", -- Joker
  1755. [69] = "\u{2664}", -- Blackjack
  1756. [70] = "\u{277C}", -- Triple Seven
  1757. [71] = "\u{2665}", -- Double Joker
  1758. }
  1759. function displayResult(set, value, soft)
  1760. set.value = value
  1761. set.soft = soft
  1762.  
  1763. updateHandDisplay( set )
  1764. end
  1765.  
  1766. function updateAllDisplays()
  1767. for i=1,#objectSets do
  1768. updateHandDisplay( objectSets[i] )
  1769. end
  1770. end
  1771. function updateHandDisplay( set )
  1772. if minigame and not (minigame==nil) and minigame.getVar("blackjackDisplayResult") then -- Override
  1773. local str, col = minigame.Call("blackjackDisplayResult", {set=set, value=set.value, soft=set.soft})
  1774. if str then
  1775. set.btnHandler.editButton({
  1776. index=0, label=str, color = (col and {r=col.r,g=col.g,b=col.b} or displayCol.Clear)
  1777. })
  1778. return
  1779. end
  1780. end
  1781.  
  1782. if specialHandDisplay[set.value] then
  1783. valueLabel = specialHandDisplay[set.value]
  1784. else
  1785. valueLabel = set.value
  1786. end
  1787. if set.soft then valueLabel=SoftHandDisplay[valueLabel] or valueLabel end
  1788.  
  1789. set.btnHandler.editButton({
  1790. index=0, label=valueLabel,
  1791. color = getHandDisplayColor(set),
  1792. })
  1793. end
  1794.  
  1795. function getHandDisplayColor(set)
  1796. local val = set.value
  1797. if set.color=="Dealer" or val==0 then return displayCol.Clear end -- Dealer or not in play
  1798.  
  1799. if val==68 or val==71 then return displayCol.Win end -- Joker always wins
  1800. if val>21 and (val<68 or val>72) then -- Bust
  1801. return (set.count>=5 and displayCol.Safe) or displayCol.Bust
  1802. end
  1803.  
  1804. local dealerValue = objectSets[1].value
  1805. if dealerValue==69 then -- Dealer blackjack
  1806. return ((val==69 or set.count>=5) and displayCol.Safe) or displayCol.Lose
  1807. end
  1808.  
  1809. if dealerValue<=21 then -- Dealer not bust
  1810. if dealerValue==val then -- Push
  1811. return displayCol.Safe
  1812. elseif dealerValue>val then -- Lose
  1813. return (set.count>=5 and displayCol.Safe) or displayCol.Lose
  1814. end
  1815. end
  1816.  
  1817. return displayCol.Win
  1818. end
  1819.  
  1820. --Guess what THIS does.
  1821. function checkForBlackjack(value, facedownCard)
  1822. local facedownValue = nil
  1823. for name, v in pairs(cardNameTable) do
  1824. if name == facedownCard.getName() then
  1825. facedownValue = v
  1826. end
  1827. end
  1828. if (facedownValue==0 and value==10) or (facedownValue==10 and value==11) then
  1829. facedownCard.setRotation({0,0,0})
  1830.  
  1831. local pos = facedownCard.getPosition()
  1832. pos.y = pos.y + 0.2
  1833. facedownCard.setPosition(pos)
  1834.  
  1835. broadcastToAll("Dealer has Blackjack!", {0.9,0.2,0.2})
  1836.  
  1837. Wait.frames(function()
  1838. updateHandCounter( objectSets[1] )
  1839. updateAllDisplays()
  1840. end, 2)
  1841. end
  1842. end
  1843.  
  1844. --Restarts loop back up at countCards
  1845. function timerStart()
  1846. Timer.destroy('blackjack_timer')
  1847. Timer.create({identifier='blackjack_timer', function_name='timerStart', delay=0.5})
  1848. if bonusTimer.getValue() < 1 then
  1849. resetTimer(1200)
  1850. bonusRound()
  1851. end
  1852.  
  1853. if os.time()>=nextAutoCardCount then -- Recount cards. This updates displays if a card was manually locked in place.
  1854. findCardsToCount()
  1855. end
  1856.  
  1857. if roundTimer and roundStateID then
  1858. if roundTimer.getValue()<=0 and ((not preventRoundEnd) or os.time()>preventRoundEnd) then
  1859. preventRoundEnd = nil
  1860. if roundStateID==1 then
  1861. dealButtonPressed( nil, "Lua" )
  1862. elseif roundStateID==3 then
  1863. payButtonPressed( nil, "Lua" )
  1864. elseif roundStateID==2 and (not (inMinigame or dealersTurn)) and GetSetting("Rounds.TurnTimeLimit", 0)>0 and not turnActive then
  1865. turnActive = true -- Failsafe
  1866. if currentPlayerTurn then
  1867. local set = findObjectSetFromColor(currentPlayerTurn)
  1868.  
  1869. if set then
  1870. clearPlayerActions(set.zone)
  1871. passPlayerActions(set.zone)
  1872. end
  1873. end
  1874. end
  1875. end
  1876.  
  1877. if roundTimer.Clock.paused and (roundStateID==1 or roundStateID==3) then
  1878. setRoundStateObject( 4 ) -- Paused state
  1879. else
  1880. local objID = getRoundStateID()
  1881. if objID~=(-1) and objID~=roundStateID then
  1882. setRoundStateObject(roundStateID)
  1883. end
  1884. end
  1885.  
  1886. if roundStateID==2 and inMinigame and ((not minigame) or minigame==nil) then
  1887. printToAll("Minigame controller dissapeared! Resuming normal play...", {1,0,0})
  1888. setRoundState( 1, GetSetting("Rounds.BetTime", 30) )
  1889.  
  1890. for i, set in pairs(objectSets) do
  1891. -- Unlock Chips
  1892. local zoneObjects = set.zone.getObjects()
  1893. local tableObjects = set.tbl.getObjects()
  1894. local prestigeObjects = set.prestige.getObjects()
  1895.  
  1896. for _,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
  1897. for j, bet in ipairs(zone) do
  1898. if (bet.tag == "Chip" and not powerupEffectTable[bet.getName()]) or (bet.tag == "Bag" and bet.getName():sub(1,11)~="Player save") and not bet.interactable then
  1899. bet.interactable = true
  1900. bet.setLock(false)
  1901. end
  1902. end
  1903. end
  1904. end
  1905. end
  1906. end
  1907. end
  1908. function getRoundStateID()
  1909. if roundState then return roundState.getStateId() end
  1910.  
  1911. for _,id in ipairs(roundStateTable) do
  1912. roundState = getObjectFromGUID(id)
  1913. if roundState then return roundState.getStateId() end
  1914. end
  1915.  
  1916. return -1
  1917. end
  1918. function setRoundStateObject( stateID )
  1919. for _,id in ipairs(roundStateTable) do
  1920. roundState = getObjectFromGUID(id)
  1921. if roundState then break end
  1922. end
  1923. if roundState and roundState.getStateId()~=(-1) and roundState.getStateId()~=stateID then roundState = roundState.setState(stateID) end
  1924. end
  1925. function setRoundState( stateID, roundTime )
  1926. if not roundTimer then return end
  1927. roundStateID = stateID
  1928.  
  1929. setRoundStateObject( stateID )
  1930.  
  1931. roundTimer.setValue( roundTime or 0 )
  1932. roundTimer.Clock.paused = (roundTimer.getValue()==0)
  1933.  
  1934. if stateID==1 then inMinigame = false end
  1935. end
  1936.  
  1937. function onObjectDestroy( obj )
  1938. if obj==roundTimer then
  1939. roundTimer = nil
  1940. elseif obj==roundState then
  1941. roundState = nil
  1942. end
  1943. end
  1944.  
  1945.  
  1946.  
  1947.  
  1948.  
  1949. -- BONUS
  1950.  
  1951.  
  1952.  
  1953.  
  1954. function addBonus( pos )
  1955. if not pos then
  1956. pos = bonusZone.getPosition()
  1957. pos.y = pos.y - 1.7
  1958. end
  1959.  
  1960. local params = {}
  1961. params.position = pos
  1962.  
  1963. local autoBonuses = bonusBag.takeObject(params)
  1964. autoBonuses.shuffle()
  1965.  
  1966. params.callback_function = activateBonus
  1967.  
  1968. local chosenBonus
  1969. repeat
  1970. chosenBonus = autoBonuses.takeObject( params )
  1971. chosenBonus.setColorTint({r=0.25,g=0.25,b=0.25})
  1972.  
  1973. for i=1,#bonusObjects do
  1974. if bonusObjects[i].getName()==chosenBonus.getName() then
  1975. destroyObject( chosenBonus )
  1976. chosenBonus = nil
  1977. break
  1978. end
  1979. end
  1980. until (chosenBonus~=nil) or (#autoBonuses.getObjects()==0)
  1981.  
  1982. if chosenBonus then
  1983. table.insert( bonusObjects, chosenBonus )
  1984. end
  1985.  
  1986. autoBonuses.destruct()
  1987. end
  1988. function bonusRound()
  1989. local playerList = getSeatedPlayers()
  1990. for i, player in ipairs(playerList) do
  1991. local set = findObjectSetFromColor(player)
  1992. if set then
  1993. spawnRandomPowerup(set.zone)
  1994. end
  1995. end
  1996. if not isBonusActive() then
  1997. clearBonus()
  1998. addBonus()
  1999. end
  2000. end
  2001.  
  2002. function activateBonus( obj )
  2003. local inTable = false
  2004. for i=1,#bonusObjects do
  2005. if bonusObjects[i]==obj then
  2006. inTable = true
  2007. break
  2008. end
  2009. end
  2010. if not inTable then
  2011. table.insert( bonusObjects, obj )
  2012. end
  2013.  
  2014. obj.lock()
  2015.  
  2016. if obj.getVar("onDeploy") then
  2017. obj.call("onDeploy")
  2018. else
  2019. obj.setColorTint({r=1,g=1,b=1})
  2020. end
  2021. end
  2022.  
  2023. function clearBonus()
  2024. if #bonusObjects == 0 then
  2025. local objectList = bonusZone.getObjects()
  2026. for i, object in ipairs(objectList) do
  2027. if object.tag == "Figurine" and object.getLock() then
  2028. object.destruct()
  2029. end
  2030. end
  2031. else
  2032. for i=#bonusObjects,1,-1 do
  2033. bonusObjects[i].destruct()
  2034. bonusObjects[i] = nil
  2035. end
  2036. end
  2037. end
  2038.  
  2039. local function RunBonusFunc( funcName, data, returnFunc )
  2040. local ret = {}
  2041.  
  2042. for i=#bonusObjects,1,-1 do
  2043. local obj = bonusObjects[i]
  2044. if obj and obj~=nil then
  2045. if obj.getVar(funcName) then
  2046. local newValue = obj.call(funcName, data)
  2047.  
  2048. if newValue~=nil then
  2049. table.insert( ret, newValue )
  2050. end
  2051.  
  2052. if obj==nil then -- Does this check work on the same frame as removal?
  2053. table.remove(bonusObjects, i)
  2054. end
  2055. end
  2056. else
  2057. table.remove(bonusObjects, i)
  2058. end
  2059. end
  2060.  
  2061. if returnFunc then
  2062. return returnFunc(ret) -- Let the call decide which it value wants
  2063. else
  2064. return ret[#ret] -- Last entry in table is from the oldest bonus
  2065. end
  2066. end
  2067.  
  2068. -- Active
  2069. function isBonusActive()
  2070. return RunBonusFunc( "isActive")
  2071. end
  2072.  
  2073. -- Bool Checks
  2074. function bonusShouldDealerReveal()
  2075. return RunBonusFunc( "shouldDealerReveal" )==true
  2076. end
  2077. function bonusCanUsePowerup( powerup )
  2078. return RunBonusFunc( "canUsePowerup", {powerup=powerup} )~=false
  2079. end
  2080. function bonusCanFlip( )
  2081. return RunBonusFunc( "canFlip" )==true
  2082. end
  2083. function bonusShouldBust( set )
  2084. return RunBonusFunc( "shouldBust", {set=set} )~=false
  2085. end
  2086.  
  2087. -- Numbers
  2088. function bonusGetPayoutMultiplier( set, mult )
  2089. return RunBonusFunc( "payoutMultiplier", {set=set, betMultiplier=mult}, function(data)
  2090. -- This function ensures we always return the largest multiplier
  2091. -- Useful when there's multiple bonuses
  2092. local value
  2093.  
  2094. for i=1,#data do
  2095. if (not value) or data[i]>value then
  2096. value = data[i]
  2097. end
  2098. end
  2099.  
  2100. return value
  2101. end)
  2102. end
  2103.  
  2104. -- Bonus Round Hooks
  2105. function bonusPreRound() return RunBonusFunc( "preRoundStart" ) end
  2106. function bonusOnRoundStart() return RunBonusFunc( "onRoundStart" ) end
  2107. function bonusOnRoundEnd() return RunBonusFunc( "onRoundEnd" ) end
  2108.  
  2109.  
  2110. function beginMiniGame()
  2111. local autoMinigames = minigameBag.takeObject(params)
  2112. autoMinigames.shuffle()
  2113.  
  2114. minigame = autoMinigames.takeObject(params)
  2115. inMinigame = true
  2116.  
  2117. autoMinigames.destruct()
  2118. end
  2119.  
  2120. function deployRupees(o, color)
  2121. local playerList = getSeatedPlayers()
  2122. for i, player in ipairs(playerList) do
  2123. local set = findObjectSetFromColor(player)
  2124. if set then
  2125. local bet = #findBetsInZone(set.zone)
  2126. if bet ~= 0 then
  2127. rupeePull(set.zone)
  2128. end
  2129. end
  2130. end
  2131. end
  2132.  
  2133.  
  2134.  
  2135.  
  2136.  
  2137. --DECK FINDING/TRACKING SECTION
  2138.  
  2139.  
  2140.  
  2141.  
  2142.  
  2143. --checks for current deck when the tool loads, triggered by onload
  2144. function checkForDeck()
  2145. local objectsInZone = deckZone.getObjects()
  2146. for i, deck in ipairs(objectsInZone) do
  2147. if deck.tag == "Deck" then
  2148. if mainDeck~=nil and mainDeck~=deck then
  2149. destroyObject(mainDeck)
  2150. end
  2151.  
  2152. mainDeck = deck
  2153. break
  2154. end
  2155. end
  2156. end
  2157.  
  2158. --marks a deck in tool's logic as "mainDeck", which is the deck dealt from
  2159. function onObjectEnterScriptingZone(zone, object)
  2160. if zone == deckZone and object.tag == "Deck" then
  2161. if mainDeck~=nil and mainDeck~=object then
  2162. destroyObject(mainDeck)
  2163. end
  2164.  
  2165. mainDeck = object
  2166. end
  2167.  
  2168. -- Prevent people messing with rewards
  2169. for _,rewardZone in pairs(rewards) do
  2170. if zone==rewardZone then
  2171. local col = object.held_by_color
  2172.  
  2173. if (not col) then
  2174. object.setPosition( {0,10,0} )
  2175. elseif (col~="Black" and not Player[col].admin) then -- Someone adding to the zone that shouldn't be
  2176. object.destruct()
  2177. end
  2178.  
  2179. return
  2180. end
  2181. end
  2182. end
  2183.  
  2184. --Activated by click function, pulls out a deck from a set of possible bags
  2185. function obtainDeck()
  2186. local deckPos = deckZone.getPosition()
  2187. local params = {}
  2188. params.position = {deckPos.x, deckPos.y, deckPos.z}
  2189. local decks = deckBag.takeObject(params)
  2190. decks.shuffle()
  2191.  
  2192. params.rotation = {0,0,180}
  2193. params.callback = "shuffleNewDeck"
  2194. params.callback_owner = Global
  2195.  
  2196. local taken = decks.takeObject(params)
  2197. taken.shuffle()
  2198. taken.setPosition(params.position)
  2199. taken.setRotation(params.rotation)
  2200. mainDeck = taken
  2201.  
  2202. decks.destruct()
  2203. end
  2204.  
  2205. function shuffleNewDeck()
  2206. mainDeck.shuffle()
  2207. mainDeck.lock()
  2208. mainDeck.interactable = false
  2209. end
  2210.  
  2211.  
  2212.  
  2213.  
  2214.  
  2215. --CARD DEALING SECTION
  2216.  
  2217.  
  2218.  
  2219.  
  2220.  
  2221. --Used to clear all cards and figurines out of a zone
  2222. function clearCards(zoneToClear)
  2223. local override = RunBonusFunc( "clearCards", {zone=zoneToClear} )
  2224. if override==true then return end
  2225.  
  2226. local objectsInZone = zoneToClear.getObjects()
  2227. for i, object in ipairs(objectsInZone) do
  2228. local tag = object.tag
  2229. if tag == "Card" or tag == "Deck" or (tag == "Figurine" and object.getLock()) or (object.tag == "Chip" and powerupEffectTable[object.getName()] and object.getLock()) then
  2230. destroyObject(object)
  2231. end
  2232. end
  2233.  
  2234. displayResult( findObjectSetFromZone(zoneToClear), 0, false )
  2235. end
  2236.  
  2237. function clearCardsOnly(zoneToClear)
  2238. local override = RunBonusFunc( "clearCardsOnly", {zone=zoneToClear} )
  2239. if override==true then return end
  2240.  
  2241. local objectsInZone = zoneToClear.getObjects()
  2242. for i, object in ipairs(objectsInZone) do
  2243. local tag = object.tag
  2244. if tag == "Card" or tag == "Deck" then
  2245. destroyObject(object)
  2246. end
  2247. end
  2248. end
  2249.  
  2250. --Used to clear all chips out of a zone
  2251. function clearBets(zoneToClear, lockedOnly)
  2252. local override = RunBonusFunc( "clearBets", {zone=zoneToClear, lockedOnly=lockedOnly} )
  2253. if override==true then return end
  2254.  
  2255. local objectsInZone = zoneToClear.getObjects()
  2256.  
  2257. local badBagObjects = 0
  2258. local set = findObjectSetFromZone(zoneToClear)
  2259.  
  2260. for i, object in ipairs(objectsInZone) do
  2261. if ((object.tag == "Chip" and not powerupEffectTable[object.getName()]) or (object.tag == "Bag" and object.getName():sub(1,11)~="Player save")) and not (lockedOnly and object.interactable) then
  2262. if object.tag == "Bag" then -- Remove anything that shouldn't be here
  2263. local goodIDs = object.getTable("Blackjack_BetBagContents") or {}
  2264. local contents = object.getObjects()
  2265.  
  2266. -----
  2267. local params = {}
  2268. params.position = set.container.getPosition()
  2269. params.position.y = params.position.y + 0.25
  2270.  
  2271. for i=1,#contents do
  2272. if lockedOnly and (not goodIDs[contents[i].guid]) or goodIDs[contents[i].guid]<=0 then
  2273. local taken = object.takeObject(params)
  2274. set.container.putObject(taken)
  2275.  
  2276. badBagObjects = badBagObjects + 1
  2277. else
  2278. local taken = object.takeObject(params)
  2279. destroyObject(taken)
  2280.  
  2281. goodIDs[contents[i].guid] = (goodIDs[contents[i].guid] or 0) - 1
  2282. end
  2283. params.position.y = math.min(params.position.y + 0.5, 20)
  2284. end
  2285. -----
  2286. else
  2287. destroyObject(object)
  2288. end
  2289. end
  2290. end
  2291.  
  2292. if badBagObjects>0 then
  2293. broadcastToColor( string.format("Refunded %i bad objects in bet bag(s). Did you attempt to alter your bet?", badBagObjects), set.color, {1,0.25,0.25})
  2294.  
  2295. for k,adminCol in pairs(getSeatedPlayers()) do
  2296. if Player[adminCol].admin then
  2297. printToColor( string.format("Refunded %i bad object(s) in bet bag of player %s (%s).", badBagObjects, set.color, Player[set.color].steam_name), adminCol, {1,0,0} )
  2298. end
  2299. end
  2300. end
  2301. end
  2302.  
  2303. --Deals cards to the player. whichCard is a table with which # cards to deal
  2304. function dealDealer(whichCard)
  2305. local override = RunBonusFunc( "dealDealer", {whichCard=whichCard or {}} )
  2306. if override==true then return end
  2307.  
  2308. for i, v in ipairs(whichCard or {}) do
  2309. local pos = findCardPlacement(objectSets[1].zone, v)
  2310. if v ~= 2 or (bonusShouldDealerReveal()) then
  2311. placeCard(pos, true, objectSets[1], v<=2, true)
  2312. else
  2313. placeCard(pos, false, objectSets[1], v<=2, true)
  2314. end
  2315. end
  2316. end
  2317.  
  2318. --Deals to player using same method as dealDealer
  2319. function dealPlayer(color, whichCard)
  2320. local override = RunBonusFunc( "dealPlayer", {color=color or "Black", whichCard=whichCard or {}} )
  2321. if override==true then return end
  2322.  
  2323. for i, v in ipairs(whichCard or {}) do
  2324. local set = findObjectSetFromColor(color)
  2325. if set then
  2326. local pos = findCardPlacement(set.zone, v)
  2327. placeCard(pos, true, set, true)
  2328. end
  2329. end
  2330. end
  2331.  
  2332.  
  2333. function updateCardPositions( set )
  2334. local zone = set.zone
  2335. local cards = findCardsInZone(zone)
  2336.  
  2337. table.sort( cards, function(a,b)
  2338. local aStarter = a.getTable("blackjack_playerSet")
  2339. local bStarter = b.getTable("blackjack_playerSet")
  2340.  
  2341. if aStarter and not bStarter then
  2342. return true
  2343. elseif bStarter and not aStarter then
  2344. return false
  2345. end
  2346.  
  2347. local aPos = a.getPosition()
  2348. local bPos = b.getPosition()
  2349.  
  2350. if math.abs(aPos.z-bPos.z)<0.25 then -- Allow for a small variance in position, if we're too strict cards might re-order
  2351. if math.abs(aPos.x-bPos.x)<0.25 then
  2352. return aPos.y<bPos.y
  2353. end
  2354. return aPos.x>bPos.x
  2355. end
  2356.  
  2357. return aPos.z<bPos.z
  2358. end)
  2359.  
  2360. local zoneRot = zone.getRotation()
  2361. for i=1,#cards do
  2362. cards[i].setPosition( findCardPlacement(zone, i) )
  2363.  
  2364. local rot = cards[i].getRotation()
  2365. rot.x = zoneRot.x
  2366. rot.y = zoneRot.y + 180
  2367. rot.z = (rot.z>15 and rot.z<275) and 180 or 0
  2368. cards[i].setRotation(rot)
  2369. end
  2370. end
  2371.  
  2372. --Called by other functions to actually take the card needed
  2373. function btnFlipCard(card, col)
  2374. local canFlip = RunBonusFunc( "onCardFlip", {card=card, col=col} )
  2375. if canFlip==false then return end
  2376.  
  2377. local set = card.getTable("blackjack_playerSet")
  2378. if set and col~=set.color and col~=set.UserColor and not Player[col].admin then
  2379. broadcastToColor( "This does not belong to you!", col, {1,0.2,0.2} )
  2380. return
  2381. end
  2382.  
  2383. local rot = card.getRotation()
  2384. rot.z = rot.z + 180
  2385. card.setRotation(rot)
  2386.  
  2387. if set then
  2388. local targetRot = {0,0,0}
  2389. for _,obj in pairs(findCardsInZone(set.zone)) do
  2390. if obj~=card then
  2391. obj.setRotation(targetRot)
  2392. end
  2393. end
  2394.  
  2395. updateHandCounter( set )
  2396. end
  2397. end
  2398. function cardPlacedCallback(obj, data)
  2399. if (not obj) or obj==nil then return end -- card gone
  2400.  
  2401. obj.setLock(true)
  2402. obj.interactable = false
  2403. obj.clearButtons()
  2404.  
  2405. obj.setPosition(data.targetPos)
  2406.  
  2407. local flippable = true
  2408.  
  2409. if dealersTurn then
  2410. for _,dlrCard in pairs(findCardsInZone(objectSets[1].zone)) do
  2411. if dlrCard==obj then
  2412. flippable = false
  2413. break
  2414. end
  2415. end
  2416. end
  2417.  
  2418. if flippable then
  2419. local rot = obj.getRotation()
  2420. rot.z = data.flip and 0 or 180
  2421. obj.setRotation(rot)
  2422. end
  2423.  
  2424. if data.isStarter and bonusCanFlip() then
  2425. obj.setTable("blackjack_playerSet", data.set)
  2426.  
  2427. if data.set.color~="Dealer" then
  2428. obj.createButton({
  2429. label="Flip", click_function="btnFlipCard", function_owner=nil,
  2430. position={-0.4, 1.1, -0.95}, rotation={0,0,0}, width=300, height=350, font_size=130
  2431. })
  2432. obj.createButton({
  2433. label="Flip", click_function="btnFlipCard", function_owner=nil,
  2434. position={0.4, -1.1, -0.95}, rotation={0,0,180}, width=300, height=350, font_size=130
  2435. })
  2436. end
  2437. else
  2438. obj.setTable("blackjack_playerSet", nil)
  2439. end
  2440.  
  2441. if data.set then
  2442. updateCardPositions( data.set )
  2443. updateHandCounter( data.set )
  2444. else
  2445. findCardsToCount()
  2446. end
  2447.  
  2448. if obj.held_by_color then
  2449. local new = obj.reload()
  2450. new.interactable = false
  2451. end
  2452. end
  2453. function placeCard(pos, flipBool, set, isStarter, fastDraw)
  2454. if (not mainDeck) or (mainDeck==nil) or mainDeck.getQuantity()<40 then
  2455. newDeck()
  2456. end
  2457.  
  2458. -- Small adjustment should fix clientside issues with position/rotation
  2459. local targetPos = pos
  2460. if pos.y then
  2461. targetPos = {x=pos.x, y=pos.y, z=pos.z}
  2462. pos.y = pos.y+0.1
  2463. elseif pos[2] then
  2464. targetPos = {pos[1], pos[2], pos[3]}
  2465. pos[2] = pos[2]+0.1
  2466. end
  2467.  
  2468. lastCard = mainDeck.takeObject({position=pos, flip=flipBool, callback_function=function(o)
  2469. cardPlacedCallback(o, {targetPos=targetPos, flip=flipBool, set=set, isStarter=isStarter})
  2470. end, smooth = (not fastDraw)})
  2471. lastCard.interactable = false
  2472.  
  2473. if fastDraw then
  2474. lastCard.setLock(true)
  2475. lastCard.setPosition(targetPos)
  2476.  
  2477. local rot = lastCard.getRotation()
  2478. rot.z = flipBool and 0 or 180
  2479. lastCard.setRotation(rot)
  2480. end
  2481. end
  2482.  
  2483.  
  2484.  
  2485.  
  2486. --FIND FUNCTION SECTION
  2487.  
  2488.  
  2489.  
  2490.  
  2491. --Returns the objectSets entry for a given color
  2492. function findObjectSetFromColor(color)
  2493. for i, set in ipairs(objectSets) do
  2494. if color == set.color then
  2495. return set
  2496. end
  2497. end
  2498. end
  2499.  
  2500. function findObjectSetFromKey(obj, key)
  2501. if (not obj) or obj==nil then return end
  2502.  
  2503. for i, set in ipairs(objectSets) do
  2504. if obj == set[key] then
  2505. return set
  2506. end
  2507. end
  2508. end
  2509. function findObjectSetFromZone(zone)
  2510. for i, set in ipairs(objectSets) do
  2511. if zone == set.zone then
  2512. return set
  2513. end
  2514. end
  2515. end
  2516. function findObjectSetFromButtons(btnHandler)
  2517. for i, set in ipairs(objectSets) do
  2518. if btnHandler == set.btnHandler then
  2519. return set
  2520. end
  2521. end
  2522. end
  2523.  
  2524. --Returns any cards found in a scripting zone (zone)
  2525. function findCardsInZone(zone)
  2526. local zoneObjectList = zone.getObjects()
  2527. local foundCards = {}
  2528. for i, object in ipairs(zoneObjectList) do
  2529. if object.tag == "Card" and object.getLock() then
  2530. table.insert(foundCards, object)
  2531. end
  2532. end
  2533. return foundCards
  2534. end
  2535.  
  2536. --Returns any decks in a scripting zone (zone)
  2537. function findDecksInZone(zone)
  2538. local zoneObjectList = zone.getObjects()
  2539. local foundDecks = {}
  2540. for i, object in ipairs(zoneObjectList) do
  2541. if object.tag == "Deck" and object.getLock() then
  2542. table.insert(foundDecks, object)
  2543. end
  2544. end
  2545. return foundDecks
  2546. end
  2547.  
  2548. --Returns any powerups in a scripting zone (zone)
  2549. function findFigurinesInZone(zone)
  2550. local zoneObjectList = zone.getObjects()
  2551. local foundFigurines = {}
  2552. for i, object in ipairs(zoneObjectList) do
  2553. if (object.tag == "Figurine" and object.getLock()) or (object.tag == "Chip" and powerupEffectTable[object.getName()] and object.getLock()) then
  2554. table.insert(foundFigurines, object)
  2555. end
  2556. end
  2557. return foundFigurines
  2558. end
  2559.  
  2560. --Returns any bettable objects in a scripting zone (zone)
  2561. function findBetsInZone(zone)
  2562. local zoneObjectList = zone.getObjects()
  2563. local foundChips = {}
  2564. for i, object in ipairs(zoneObjectList) do
  2565. if (object.tag == "Chip" and not powerupEffectTable[object.getName()]) or (object.tag == "Bag" and object.getName():sub(1,11)~="Player save") then
  2566. table.insert(foundChips, object)
  2567. end
  2568. end
  2569. return foundChips
  2570. end
  2571.  
  2572. --Used to find card dealing positions, based on zone and which position the card should be in
  2573. function findCardPlacement(zone, spot)
  2574. local override = RunBonusFunc( "findCardPlacement", {zone=zone, spot=spot} )
  2575. if type(override)=="table" then return override end
  2576.  
  2577. if zone == objectSets[1].zone then
  2578. return {6.5 - 2.6 * (spot-1), 1.8, -4.84}
  2579. else
  2580. local pos = zone.getPosition()
  2581. local scale = zone.getScale()
  2582. if spot <= 3 then
  2583. return {pos.x+1-(1*(spot-1)), pos.y-(scale.y/2)+0.1+(0.1*(spot-1)), pos.z-0.5}
  2584. else
  2585. return {pos.x+1-(1*(math.min(spot, 6)-4)), pos.y-(scale.y/2)+0.4+(0.1*(math.min(spot, 20)-4)), pos.z+0.5}
  2586. end
  2587. end
  2588. end
  2589. function findPowerupPlacement(zone, spot)
  2590. local override = RunBonusFunc( "findPowerupPlacement", {zone=zone, spot=spot} )
  2591. if type(override)=="table" then return override end
  2592.  
  2593. if zone == objectSets[1].zone then -- Dealer
  2594. return {-8, 1.8, -8 + (1.5 * math.min(spot,3))}
  2595. else
  2596. local pos = zone.getPosition()
  2597. local column = math.min( math.floor((spot-1)/4)+1, 13 )
  2598. local row = (spot-1)%4
  2599. return {pos.x-2.5, pos.y-3 + (0.5*column), pos.z+2.5-(1.5*row)}
  2600. end
  2601. end
  2602.  
  2603.  
  2604.  
  2605.  
  2606. --MISC FUNCTION SECTION
  2607.  
  2608.  
  2609.  
  2610.  
  2611.  
  2612. function lockoutTimer(time)
  2613. lockout = true
  2614. Timer.destroy('lockout_timer')
  2615. Timer.create({identifier='lockout_timer', function_name='concludeLockout', delay=time})
  2616. end
  2617.  
  2618. function concludeLockout()
  2619. lockout = false
  2620. end
  2621.  
  2622. function delayedCallback(func, table, time)
  2623. local params = table
  2624. params.id = 'timer_' ..timerTick
  2625. Timer.create({identifier=params.id, function_name=func, parameters=params, delay=time})
  2626. timerTick = timerTick + 1
  2627. end
  2628.  
  2629. function reverseTable(table)
  2630. local length = #table
  2631. local reverse = {}
  2632. for i, v in ipairs(table) do
  2633. reverse[length + 1 - i] = v
  2634. end
  2635. return reverse
  2636. end
  2637.  
  2638. function waitTime(tm)
  2639. local endTime = os.clock() + tm -- Using os.clock in this way seems... Dirty. Better than locking speed to FPS, though.
  2640. while os.clock() < endTime do
  2641. coroutine.yield(0)
  2642. end
  2643. end
  2644.  
  2645.  
  2646.  
  2647.  
  2648. --BUTTON CLICK FUNCTION SECTION
  2649.  
  2650.  
  2651.  
  2652.  
  2653.  
  2654. function hitCard(handler, color)
  2655. local set = findObjectSetFromButtons(handler)
  2656. local zone = set.zone
  2657.  
  2658. if zone and (color == "Black" or Player[color].promoted or Player[color].host) then
  2659. local override = RunBonusFunc( "onHit", {zone=zone} )
  2660. if override==true then return end
  2661.  
  2662. local cardsInZone = #findCardsInZone(zone)
  2663. local decksInZone = #findDecksInZone(zone)
  2664. local pos = findCardPlacement(zone, cardsInZone + decksInZone + 1)
  2665. placeCard(pos, true, set, cardsInZone<2 and decksInZone==0, set.color=="Dealer")
  2666. end
  2667. end
  2668.  
  2669. local bankruptData = {}
  2670. function playerBankrupt(handler, color)
  2671. local set = findObjectSetFromKey(handler, "tbl")
  2672.  
  2673. if set and color == set.color then
  2674. local count = 0
  2675.  
  2676. local zoneObjects = set.zone.getObjects()
  2677. local tableObjects = set.tbl.getObjects()
  2678. local prestigeObjects = set.prestige.getObjects()
  2679.  
  2680. for _,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
  2681. for _, obj in ipairs(zone) do
  2682. if obj.tag == "Chip" and obj.getName()=="Bankruptcy token" then
  2683. count = count + (obj.getQuantity()==-1 and 1 or obj.getQuantity())
  2684. end
  2685. end
  2686. end
  2687.  
  2688. if count>=12 then
  2689. doChipDestruction(set, true, false)
  2690.  
  2691. local destroyPrestige = GetSetting("Bankruptcy.ClearPrestige", false)
  2692.  
  2693. local starter = takeObjectFromContainer( set.tbl, "f3ea0f" )
  2694. local starterObjects = starter.getObjects()
  2695. local params = {position = set.tbl.getPosition()}
  2696. for i, object in ipairs(starterObjects) do
  2697. params.position.y = params.position.y + 1.5
  2698. local newObj = starter.takeObject(params)
  2699.  
  2700. local oldDesc = newObj.getDescription()
  2701. newObj.setDescription( ("%s - %s\n\n%s"):format(Player[color].steam_id, Player[color].steam_name, oldDesc) )
  2702.  
  2703. if not destroyPrestige then -- Keeping our old prestige, ignore any in the bag
  2704. local name = newObj.getVar("__trader_ObjectName") or newObj.getName()
  2705. if newObj.getVar("PrestigeLevel") or (string.match(name, "New player") or string.match(name, "Prestige %d+")) and not string.find(name, "Trophy") then
  2706. params.position.y = params.position.y - 1.5
  2707. destroyObject(newObj)
  2708. end
  2709. end
  2710. end
  2711. starter.destruct()
  2712.  
  2713. printToAll("Bankruptcy: " ..set.color.. " has returned to the game!", {0.25,1,0.25})
  2714.  
  2715. return
  2716. elseif count>0 then
  2717. broadcastToColor( "Bankruptcy: Collect 12 Bankruptcy tokens to continue.", color, {0.75,0.5,0.5})
  2718.  
  2719. return
  2720. end
  2721.  
  2722.  
  2723. local curTime = os.time()
  2724. if bankruptData[color] and (bankruptData[color].cooldown or 0)>curTime then
  2725. broadcastToColor( "Bankruptcy: Busy, please wait...", color, {1,0.25,0.25})
  2726. elseif (not bankruptData[color]) or bankruptData[color].id~=Player[color].steam_id or (bankruptData[color].time + 10 <= curTime) then -- First press
  2727. broadcastToColor( "Bankruptcy: Are you sure you want to do this? You may lose your current items! Press again to confirm.", color, {1,0.25,0.25})
  2728.  
  2729. bankruptData[color] = {id=Player[color].steam_id, time=curTime}
  2730. elseif not (bankruptData[color].lastDeclared and bankruptData[color].lastDeclared+20>curTime) then
  2731. bankruptData[color].cooldown = curTime+5
  2732.  
  2733. doBankruptDestruction(set)
  2734.  
  2735. local newObj = takeObjectFromContainer( set.tbl, "15a03a" )
  2736. if newObj then
  2737. local oldDesc = newObj.getDescription()
  2738. newObj.setDescription( ("%s - %s\n\n%s"):format(Player[color].steam_id, Player[color].steam_name, oldDesc) )
  2739. end
  2740.  
  2741. bankruptData[color].lastDeclared = curTime
  2742.  
  2743. if not (bankruptData[color].lastAnnouncement and bankruptData[color].lastAnnouncement+300>curTime) then
  2744. printToAll("Bankruptcy: " ..set.color.. " has declared bankruptcy!", {1,0.25,0.25})
  2745. broadcastToColor( "Bankruptcy: Collect 12 Bankruptcy tokens then press this button again to return to the game.", color, {0.75,0.5,0.5})
  2746.  
  2747. bankruptData[color].lastAnnouncement = curTime
  2748. end
  2749. end
  2750. end
  2751. end
  2752.  
  2753. -- Prestige
  2754. -----------
  2755. local prestigeData = {}
  2756. function playerPrestige(handler, color)
  2757. local set = findObjectSetFromKey(handler, "tbl")
  2758.  
  2759. if set and color == set.color then
  2760. local chips = {}
  2761. local prestigeObject
  2762. local prestigeLevel
  2763.  
  2764. local zoneObjects = set.zone.getObjects()
  2765. local tableObjects = set.tbl.getObjects()
  2766. local prestigeObjects = set.prestige.getObjects()
  2767.  
  2768. local plyID = Player[set.color].steam_id
  2769.  
  2770. for _,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
  2771. for _, obj in ipairs(zone) do
  2772. local objID = obj.getDescription():match("^(%d+) %- .*")
  2773. if (not objID) or objID==plyID then
  2774. if obj.tag=="Chip" and chipListIndex[obj.getName()] then
  2775. table.insert(chips, obj.getName())
  2776. else
  2777. local level = obj.getVar("PrestigeLevel") or tonumber((not string.find(obj.getName(), "Trophy")) and string.match(obj.getVar("__trader_ObjectName") or obj.getName(), "Prestige (%d+)") or "")
  2778. if level then
  2779. if (not prestigeObject) or level>prestigeLevel then
  2780. prestigeObject = obj
  2781. prestigeLevel = level
  2782. end
  2783. prestigeObject = obj
  2784. elseif string.match(obj.getName(), "New player") then
  2785. if not prestigeObject then
  2786. prestigeObject = obj
  2787. prestigeLevel = 0
  2788. end
  2789. end
  2790. end
  2791. end
  2792. end
  2793. end
  2794.  
  2795. local hasRequired = false
  2796. local requiredChip
  2797. if prestigeLevel then
  2798. if not prestigeTable[prestigeLevel+1] then
  2799. local found = false
  2800. for _,obj in pairs(getAllObjects()) do
  2801. if obj.getLock() and obj.getVar("PrestigeLevel")==(prestigeLevel+1) then
  2802. found = true
  2803.  
  2804. table.insert(powerupTable, {obj.getGUID(), chosenPowerup[2]})
  2805.  
  2806. break
  2807. end
  2808. end
  2809.  
  2810. if not found then
  2811. broadcastToColor( "Prestige: You have reached the maximum prestige level.", color, {0.25,1,0.25})
  2812.  
  2813. return
  2814. end
  2815. end
  2816.  
  2817. local targetObject = prestigeTable[prestigeLevel+1]
  2818. requiredChip = targetObject.getVar("PrestigeChip")
  2819.  
  2820. if chipListIndex[requiredChip] then
  2821. local target = chipListIndex[requiredChip]
  2822.  
  2823. for i=1,#chips do
  2824. if chipListIndex[chips[i]] and chipListIndex[chips[i]]>=target then
  2825. hasRequired = true
  2826. break
  2827. end
  2828. end
  2829. else
  2830. for i=1,#chips do
  2831. if chips[i]==requiredChip then
  2832. hasRequired = true
  2833. break
  2834. end
  2835. end
  2836. end
  2837. end
  2838.  
  2839. if not hasRequired then
  2840. if prestigeLevel and requiredChip then
  2841. broadcastToColor( "Prestige: Prestige failed. You need at least "..tostring(requiredChip).." to reach Prestige "..tostring(prestigeLevel + 1)..".", color, {0.25,1,0.25})
  2842. else
  2843. broadcastToColor( "Prestige: Prestige failed. Ensure you have the appopriate chip and prestige gem on your table.", color, {0.25,1,0.25})
  2844. end
  2845.  
  2846. return
  2847. end
  2848.  
  2849. local curTime = os.time()
  2850. if prestigeData[color] and (prestigeData[color].cooldown or 0)>curTime then
  2851. broadcastToColor( "Prestige: Busy, please wait...", color, {1,0.25,0.25})
  2852. elseif (not prestigeData[color]) or prestigeData[color].id~=Player[color].steam_id or (prestigeData[color].time + 10 <= curTime) then -- First press
  2853. broadcastToColor( "Prestige: Do you want to advance to Prestige "..tostring(prestigeLevel+1).."? You may lose your current items! Press again to confirm.", color, {1,0.25,0.25})
  2854.  
  2855. prestigeData[color] = {id=Player[color].steam_id, time=curTime}
  2856. elseif not (prestigeData[color].lastDeclared and prestigeData[color].lastDeclared+20>curTime) then
  2857. prestigeData[color].cooldown = curTime+5
  2858. doPrestige(set, prestigeLevel+1)
  2859. end
  2860. end
  2861. end
  2862.  
  2863. function doPrestige(set, targetLevel)
  2864. if not (set and targetLevel) then return end
  2865.  
  2866. local targetObj = prestigeTable[targetLevel]
  2867. if not targetObj then return false end
  2868.  
  2869. if targetObj.Call("doPrestige", {set=set} ) then
  2870. doPrestigeDestruction( set )
  2871.  
  2872. takeObjectFromContainer( set.tbl, "996d26", {0,0.5,0.45} )
  2873.  
  2874. return true
  2875. end
  2876.  
  2877. return false
  2878. end
  2879.  
  2880. function AddPrestige(data)
  2881. if not (data.obj) then return end
  2882.  
  2883. local name = data.obj.getName()
  2884. if (not name) or name=="" then return end
  2885.  
  2886. local level = data.obj.getVar("PrestigeLevel")
  2887. if (not level) or type(level)~="number" or level<1 then return end -- Not a valid prestige
  2888. level = math.floor(level)
  2889.  
  2890. prestigeTable[level] = data.obj
  2891. end
  2892. -----------
  2893.  
  2894. function dealButtonPressed(o, color)
  2895. if (color == "Lua" or color == "Black" or Player[color].promoted or Player[color].host) then
  2896. setRoundState( 2 )
  2897.  
  2898. local override = bonusPreRound()
  2899. if override then return end
  2900.  
  2901. inMinigame = false
  2902. if minigame and not (minigame==nil) then
  2903. destroyObject(minigame)
  2904. end
  2905.  
  2906. if color == "Lua" or (not lockout) then
  2907. dealersTurn = false
  2908. dealingDealersCards = false
  2909.  
  2910. for _,splitSet in ipairs(objectSets) do
  2911. if splitSet.color:sub(1,5)=="Split" then
  2912. if splitSet.container.getQuantity()>0 then -- Someone forgot to claim their stuff
  2913. local targetSet = nil
  2914. for i=2,#objectSets do
  2915. if splitSet.UserColor==objectSets[i].color then
  2916. targetSet = objectSets[i]
  2917. break
  2918. end
  2919. end
  2920. if targetSet and targetSet.container then
  2921. local params = {}
  2922. params.position = targetSet.container.getPosition()
  2923. params.position.y = params.position.y+0.15
  2924.  
  2925. for i=1,splitSet.container.getQuantity() do
  2926. splitSet.container.takeObject(params)
  2927. end
  2928. end
  2929. end
  2930.  
  2931. splitSet.SplitUser = nil
  2932. splitSet.UserColor = nil
  2933. splitSet.prestige = splitSet.zone
  2934. splitSet.tbl = splitSet.zone
  2935.  
  2936. splitSet.container.setColorTint({0.25,0.25,0.25})
  2937. end
  2938. end
  2939.  
  2940. lockoutTimer(10)
  2941. if mainDeck == nil or mainDeck.getQuantity() < 80 then
  2942. newDeck()
  2943. deckBool = true
  2944. end
  2945. for i, set in pairs(objectSets) do
  2946. clearPlayerActions(set.zone)
  2947. clearCardsOnly(set.zone)
  2948. end
  2949.  
  2950. bonusOnRoundStart()
  2951.  
  2952. local playerList = getSeatedPlayers()
  2953. dealOrder = {}
  2954. for i, player in ipairs(playerList) do
  2955. local set = findObjectSetFromColor(player)
  2956. if set then
  2957. local zoneObjectList = set.zone.getObjects()
  2958. for j, bet in ipairs(zoneObjectList) do
  2959. if (bet.tag == "Chip" and not powerupEffectTable[bet.getName()]) or (bet.tag == "Bag" and bet.getName():sub(1,11)~="Player save" and bet.getQuantity()>0) then
  2960. table.insert(dealOrder, player)
  2961. break
  2962. end
  2963. end
  2964. end
  2965. end
  2966. startLuaCoroutine(Global, "dealInOrder")
  2967. else
  2968. broadcastToColor("Error: Button delay is active.\nWait a moment then try again.", color, {1,0.25,0.25})
  2969. end
  2970. end
  2971. end
  2972.  
  2973. function newDeck()
  2974. if mainDeck ~= nil then
  2975. destroyObject(mainDeck)
  2976. end
  2977. obtainDeck()
  2978. end
  2979.  
  2980. function dealInOrder()
  2981. -- Setup Hand
  2982. local firstToGo = nil
  2983. if deckBool then
  2984. waitTime( 1 )
  2985. deckBool = false
  2986. end
  2987. findCardsToCount()
  2988.  
  2989. -- Lock Chips
  2990. for i=#dealOrder,1,-1 do
  2991. local set = findObjectSetFromColor(dealOrder[i])
  2992. if set then
  2993. local zoneObjectList = set.zone.getObjects()
  2994.  
  2995. local foundBets = false
  2996. for j, bet in ipairs(zoneObjectList) do
  2997. if ((bet.tag == "Chip" and not powerupEffectTable[bet.getName()]) or (bet.tag == "Bag" and bet.getName():sub(1,11)~="Player save")) and bet.held_by_color==nil then
  2998. foundBets = true
  2999. bet.interactable = false
  3000. bet.setLock(true)
  3001.  
  3002. if bet.tag == "Bag" then -- Additional bag protections
  3003. local fullContents = bet.getObjects()
  3004. local guids = {}
  3005.  
  3006. for i=1,#fullContents do
  3007. guids[fullContents[i].guid] = (guids[fullContents[i].guid] or 0) + 1 -- Account for multiple instances of a single guid
  3008. end
  3009.  
  3010. bet.setTable("Blackjack_BetBagContents", guids)
  3011. end
  3012. end
  3013. end
  3014.  
  3015. if not foundBets then table.remove(dealOrder, i) end
  3016. end
  3017. end
  3018.  
  3019. -- Begin Dealing
  3020. for i=1, 2 do
  3021. for o, set in ipairs(reverseTable(objectSets)) do
  3022. if set.color == "Dealer" then
  3023. dealDealer({i})
  3024. while lastCard.getName() == "Joker" do
  3025. lastCard.destruct()
  3026. dealDealer({i})
  3027. resetTimer(3)
  3028. end
  3029. waitTime(0.1)
  3030. else
  3031. for j, player in ipairs(dealOrder) do
  3032. if set.color == player then
  3033. if firstToGo == nil then firstToGo = set end
  3034. dealPlayer(player, {i})
  3035. waitTime(0.1)
  3036. break
  3037. end
  3038. end
  3039. end
  3040. end
  3041. end
  3042. if firstToGo ~= nil then
  3043. delayedCallback('whoGoesFirst', {set=firstToGo}, 1)
  3044. else
  3045. concludeLockout()
  3046.  
  3047. waitTime(0.6)
  3048.  
  3049. dealersTurn = true
  3050. revealHandZone( objectSets[1].zone, true )
  3051. end
  3052. return 1
  3053. end
  3054.  
  3055. function whoGoesFirst(table)
  3056. for i=#objectSets,1,-1 do
  3057. if objectSets[i].color==table.set.color then -- For some reason timers create a copy of the table, not referencing the table itself. Does TTS do ANYTHING right?
  3058. if objectSets[i].value>21 then
  3059. passPlayerActions(table.set.zone)
  3060. else
  3061. currentPlayerTurn = table.set.color
  3062. createPlayerActions(table.set.btnHandler)
  3063.  
  3064. beginTurnTimer(objectSets[i])
  3065. end
  3066. end
  3067. end
  3068. Timer.destroy(table.id)
  3069. concludeLockout()
  3070. end
  3071.  
  3072. function beginTurnTimer(set, supressMessage)
  3073. if GetSetting("Rounds.TurnTimeLimit", 0)>0 then
  3074. turnActive = false
  3075.  
  3076. local turnTime = GetSetting("Rounds.TurnTimeLimit", 30)
  3077.  
  3078. setRoundState( 2, turnTime )
  3079.  
  3080. if Player[set.UserColor or set.color].seated and not supressMessage then
  3081. broadcastToColor( ("It's your turn. You have %i seconds to take an action or you will be forced to stand."):format(turnTime), set.UserColor or set.color, {0.25,1,0.25})
  3082. end
  3083. end
  3084. end
  3085. function endTurnTimer(set, force)
  3086. if force or GetSetting("Rounds.TurnTimeLimitEnds", false) then
  3087. turnActive = true
  3088.  
  3089. if roundTimer and roundTimer.getValue()>0 then
  3090. setRoundState( 2, 0 )
  3091. end
  3092. else
  3093. beginTurnTimer(set, true)
  3094. end
  3095. end
  3096.  
  3097. -- Player actions --
  3098.  
  3099. function validateBetBag(data)
  3100. if not (data.bag and data.bag==nil) then -- null check
  3101. local fullContents = data.bag.getObjects()
  3102. local guids = {}
  3103.  
  3104. for i=1,#fullContents do
  3105. guids[fullContents[i].guid] = (guids[fullContents[i].guid] or 0) + 1 -- Account for multiple instances of a single guid
  3106. end
  3107.  
  3108. data.bag.setTable("Blackjack_BetBagContents", guids)
  3109. end
  3110. end
  3111. local function repeatBet( color, set, setTarget, addHeight )
  3112. setTarget = setTarget or set
  3113.  
  3114. local zoneObjects = set.zone.getObjects()
  3115. local currentBet = {}
  3116.  
  3117. local container
  3118. local badBagObjects = 0
  3119.  
  3120. local refundParams = {}
  3121. refundParams.position = set.container.getPosition()
  3122. refundParams.position.y = refundParams.position.y + 0.25
  3123. for j, bet in ipairs(zoneObjects) do
  3124. if not bet.interactable then
  3125. if (bet.tag == "Chip" and not powerupEffectTable[bet.getName()]) then
  3126. local count = bet.getQuantity()
  3127. if count==-1 then count = 1 end -- Just... Why?
  3128.  
  3129. currentBet[bet.getName()] = (currentBet[bet.getName()] or 0) + count
  3130. elseif (bet.tag == "Bag" and bet.getName():sub(1,11)~="Player save") then
  3131. container = bet
  3132. local contents = bet.getObjects()
  3133.  
  3134. bet.setRotation({0,0,0})
  3135. local pos = bet.getPosition()
  3136. pos.y = pos.y + 2
  3137.  
  3138. local objs = {}
  3139. local goodIDs = bet.getTable("Blackjack_BetBagContents")
  3140.  
  3141. for i=1,#contents do
  3142. if goodIDs[contents[i].guid] and goodIDs[contents[i].guid]>0 then
  3143. local obj = bet.takeObject( {position=pos, rotation={0,0,0}} )
  3144.  
  3145. pos.y = pos.y + 8
  3146.  
  3147. if ((obj.tag == "Chip" or obj.tag == "Generic") and not powerupEffectTable[obj.getName()]) then
  3148. local count = obj.getQuantity()
  3149. if count==-1 then count = 1 end
  3150.  
  3151. currentBet[obj.getName()] = (currentBet[obj.getName()] or 0) + count
  3152. end
  3153.  
  3154. table.insert(objs, obj)
  3155. else
  3156. local taken = bet.takeObject(refundParams)
  3157.  
  3158. refundParams.position.y = math.min(refundParams.position.y + 0.5, 20)
  3159. set.container.putObject(taken)
  3160.  
  3161. badBagObjects = badBagObjects + 1
  3162. end
  3163.  
  3164. goodIDs[contents[i].guid] = (goodIDs[contents[i].guid] or 0) - 1
  3165. end
  3166.  
  3167. for i=1,#objs do
  3168. bet.putObject(objs[i])
  3169. end
  3170. delayedCallback('validateBetBag', {bag=bet}, 0.1)
  3171. end
  3172. end
  3173. end
  3174.  
  3175. if badBagObjects>0 then
  3176. broadcastToColor( string.format("Refunded %i bad object(s) in bet bag. Did you attempt to alter your bet?", badBagObjects), set.color, {1,0.25,0.25})
  3177.  
  3178. for k,adminCol in pairs(getSeatedPlayers()) do
  3179. if Player[adminCol].admin then
  3180. printToColor( string.format("Refunded %i bad object(s) in bet bag of player %s (%s).", badBagObjects, set.color, Player[set.color].steam_name), adminCol, {1,0,0} )
  3181. end
  3182. end
  3183. end
  3184.  
  3185. local tableObjects = set.tbl.getObjects()
  3186. local foundStacks = {}
  3187. for j, chip in ipairs(tableObjects) do
  3188. if chip.tag == "Chip" then
  3189. local name = chip.getName()
  3190. if currentBet[name] and currentBet[name]>0 then
  3191. local count = chip.getQuantity()
  3192. if count==-1 then count = 1 end
  3193.  
  3194. if count>currentBet[name] then
  3195. table.insert(foundStacks, {chip, currentBet[name]})
  3196.  
  3197. currentBet[name] = nil
  3198. elseif count==currentBet[name] then
  3199. table.insert(foundStacks, {chip})
  3200.  
  3201. currentBet[name] = nil
  3202. else
  3203. table.insert(foundStacks, {chip})
  3204.  
  3205. currentBet[name] = (currentBet[name] or 0) - count
  3206. end
  3207. end
  3208. end
  3209. end
  3210.  
  3211. for _,v in pairs(currentBet) do -- Should only run if there's values left
  3212. broadcastToColor( "Error: You don't have enough matching chips on your table.", color, {1,0.25,0.25} )
  3213. return false
  3214. end
  3215.  
  3216. local zonePos = setTarget.zone.getPosition()
  3217.  
  3218. if container and set==setTarget then
  3219. zonePos = container.getPosition()
  3220. zonePos.y = zonePos.y + 2
  3221. else
  3222. if addHeight then zonePos.y = zonePos.y + addHeight end
  3223.  
  3224. zonePos.z = zonePos.z + 3.1
  3225. zonePos.y = zonePos.y - 2
  3226. end
  3227.  
  3228.  
  3229. local placedBag = nil
  3230. local chipIDs = {}
  3231. if betBags and #foundStacks>1 then
  3232. placedBag = betBags.takeObject( {position=zonePos, rotation={0,0,0}} )
  3233. zonePos.y = zonePos.y+3
  3234.  
  3235. placedBag.interactable = false
  3236. placedBag.setLock(true)
  3237. end
  3238.  
  3239. for i=1,#foundStacks do
  3240. local tbl = foundStacks[i]
  3241.  
  3242. if tbl[2] then
  3243. for i=1,tbl[2] do
  3244. local taken = tbl[1].takeObject( {position=zonePos, rotation={0,0,0}} )
  3245. zonePos.y = zonePos.y + 0.1
  3246.  
  3247. if placedBag then
  3248. placedBag.putObject( taken )
  3249. else
  3250. taken.interactable = false
  3251. taken.setLock(true)
  3252. end
  3253. end
  3254. zonePos.y = zonePos.y+0.6
  3255. else
  3256. tbl[1].setPositionSmooth( zonePos )
  3257. tbl[1].setRotation( {0,0,0} )
  3258.  
  3259. zonePos.y = zonePos.y + (math.max(tbl[1].getQuantity(), 1)*0.6)
  3260.  
  3261. if placedBag then
  3262. placedBag.putObject( tbl[1] )
  3263. else
  3264. tbl[1].interactable = false
  3265. tbl[1].setLock(true)
  3266. end
  3267. end
  3268. end
  3269.  
  3270. if placedBag then
  3271. delayedCallback('validateBetBag', {bag=placedBag}, 0.1)
  3272. end
  3273.  
  3274. return true
  3275. end
  3276.  
  3277. function createPlayerActions(btnHandler, simpleOnly)
  3278. btnHandler.createButton({
  3279. label="Stand", click_function="playerStand", function_owner=nil,
  3280. position={-1, 0.25, 0}, rotation={0,0,0}, width=400, height=350, font_size=130
  3281. })
  3282. btnHandler.createButton({
  3283. label="Hit", click_function="playerHit", function_owner=nil,
  3284. position={1, 0.25, 0}, rotation={0,0,0}, width=400, height=350, font_size=130
  3285. })
  3286.  
  3287. if simpleOnly then return end
  3288.  
  3289. local set = findObjectSetFromButtons( btnHandler )
  3290. local cards = findCardsInZone(set.zone)
  3291. if #cards==2 and cardNameTable[cards[1].getName()]==cardNameTable[cards[2].getName()] then
  3292. if cards[1].getName()==cards[2].getName() or GetSetting("Hands.SplitOnValue", false) then
  3293. btnHandler.createButton({
  3294. label="Split", click_function="playerSplit", function_owner=nil,
  3295. position={-1, 0.25, -0.65}, rotation={0,0,0}, width=400, height=250, font_size=100
  3296. })
  3297. end
  3298. end
  3299.  
  3300. if #cards==2 then
  3301. btnHandler.createButton({
  3302. label="Double", click_function="playerDouble", function_owner=nil,
  3303. position={1, 0.25, -0.65}, rotation={0,0,0}, width=400, height=250, font_size=100
  3304. })
  3305. end
  3306. end
  3307. function delayedCreatePlayerActions(tbl)
  3308. local set = tbl.set
  3309.  
  3310. local betsInZone = #findBetsInZone(set.zone)
  3311. local cardsInZone = #findCardsInZone(set.zone)
  3312. local decksInZone = #findDecksInZone(set.zone)
  3313. if betsInZone ~= 0 and (cardsInZone ~= 0 or decksInZone ~= 0) and set.value <= 21 then
  3314. currentPlayerTurn = set.color
  3315. return createPlayerActions(set.btnHandler)
  3316. end
  3317.  
  3318. return passPlayerActions(set.zone)
  3319. end
  3320.  
  3321. function clearPlayerActions(zone, ExtraOnly)
  3322. local set = findObjectSetFromZone(zone)
  3323. local handler = set.btnHandler
  3324.  
  3325. handler.clearButtons()
  3326. handler.createButton({
  3327. label="0", click_function="hitCard", function_owner=nil, color={r=1,g=1,b=1},
  3328. position={0, 0.25, 0}, rotation={0,0,0}, width=450, height=450, font_size=300
  3329. }, true)
  3330. createPlayerMetaActions(set)
  3331.  
  3332. if ExtraOnly then
  3333. createPlayerActions(handler, true)
  3334. end
  3335.  
  3336. -- findCardsToCount()
  3337. updateHandCounter( set )
  3338. end
  3339. function createPlayerMetaActions(set)
  3340. if set.tbl and set.tbl~=set.zone and set.color~="Dealer" then
  3341. set.tbl.clearButtons()
  3342.  
  3343. local scaleTable = set.tbl.getScale()
  3344.  
  3345. set.tbl.createButton({
  3346. click_function='playerPrestige', label='Prestige', function_owner=nil,
  3347. position={ -0.13, -0.435, -0.48 }, rotation={0,180,0}, scale = {2/scaleTable.x, 2/scaleTable.y, 2/scaleTable.z},
  3348. width=650, height=190, font_size=110, color = {r=0.5,g=0.5,b=0.5}
  3349. })
  3350. set.tbl.createButton({
  3351. click_function='playerBankrupt', label='Bankrupt', function_owner=nil,
  3352. position={ 0.13, -0.435, -0.48 }, rotation={0,180,0}, scale = {2/scaleTable.x, 2/scaleTable.y, 2/scaleTable.z},
  3353. width=650, height=190, font_size=110, color = {r=0.5,g=0.5,b=0.5}
  3354. })
  3355. end
  3356. end
  3357.  
  3358. function passPlayerActions(zone)
  3359. local nextInLine = nil
  3360. for i, set in ipairs(reverseTable(objectSets)) do
  3361. if set.color == "Dealer" then
  3362. dealersTurn = true
  3363. currentPlayerTurn = "None"
  3364. revealHandZone(set.zone, true)
  3365.  
  3366. if GetSetting("Rounds.TurnTimeLimit", 0)>0 and roundTimer then
  3367. roundTimer.setValue(0)
  3368. roundTimer.Clock.paused = false
  3369. end
  3370. break
  3371. elseif set.zone == zone then
  3372. if set.color:sub(1,5)=="Split" and set.SplitUser then
  3373. local originalSet = set.SplitUser
  3374.  
  3375. local betsInZone = #findBetsInZone(originalSet.zone)
  3376. local cardsInZone = #findCardsInZone(originalSet.zone)
  3377. local decksInZone = #findDecksInZone(originalSet.zone)
  3378. if betsInZone ~= 0 and (cardsInZone ~= 0 or decksInZone ~= 0) and originalSet.value <= 21 then
  3379. currentPlayerTurn = originalSet.color
  3380. createPlayerActions(originalSet.btnHandler)
  3381. break
  3382. end
  3383.  
  3384. return passPlayerActions(originalSet.zone)
  3385. end
  3386.  
  3387. nextInLine = i + 1
  3388. elseif i == nextInLine then
  3389. local betsInZone = #findBetsInZone(set.zone)
  3390. local cardsInZone = #findCardsInZone(set.zone)
  3391. local decksInZone = #findDecksInZone(set.zone)
  3392. if betsInZone ~= 0 and (cardsInZone ~= 0 or decksInZone ~= 0) and set.value <= 21 then
  3393. currentPlayerTurn = set.color
  3394. createPlayerActions(set.btnHandler)
  3395.  
  3396. beginTurnTimer(set)
  3397.  
  3398. break
  3399. end
  3400. nextInLine = nextInLine + 1
  3401. end
  3402. end
  3403. end
  3404. function delayedPassPlayerActions(data)
  3405. if currentPlayerTurn==data.color then
  3406. passPlayerActions(data.zone)
  3407. end
  3408. end
  3409.  
  3410. function playerHit(btnHandler, color)
  3411. local set = findObjectSetFromButtons(btnHandler)
  3412. if color==set.color or color=="Black" or Player[color].promoted or Player[color].host or (set.color:sub(1,5)=="Split" and set.UserColor==color) then
  3413. if set.color~=currentPlayerTurn then
  3414. clearPlayerActions(set.zone)
  3415.  
  3416. return broadcastToColor("Error: It's not your turn.", color, {1,0.25,0.25})
  3417. end
  3418. if not lockout then
  3419. local override = RunBonusFunc( "onPlayerHit", {set=set, color=color} )
  3420. if override==true then return end
  3421.  
  3422. endTurnTimer(set)
  3423. clearPlayerActions(set.zone, true)
  3424. lockoutTimer(1)
  3425. if set.value > 21 then
  3426. clearPlayerActions(set.zone)
  3427. passPlayerActions(set.zone)
  3428. else
  3429. checkForBust(set, (mainDeck and (not (mainDeck==nil)) and mainDeck.getObjects()[1] or {}).nickname or "")
  3430. forcedCardDraw(set.zone)
  3431. end
  3432. else
  3433. broadcastToColor("Error: Button delay is active.\nWait a moment then try again.", color, {1,0.25,0.25})
  3434. end
  3435. end
  3436. end
  3437. function playerDouble(btnHandler, color)
  3438. local set = findObjectSetFromButtons(btnHandler)
  3439.  
  3440. if color == set.color or color == "Black" or Player[color].promoted or Player[color].host or (set.color:sub(1,5)=="Split" and set.UserColor==color) then
  3441. if set.color~=currentPlayerTurn then
  3442. clearPlayerActions(set.zone)
  3443.  
  3444. return broadcastToColor("Error: It's not your turn.", color, {1,0.25,0.25})
  3445. end
  3446.  
  3447. if set.value > 21 then
  3448. clearPlayerActions(set.zone)
  3449. passPlayerActions(set.zone)
  3450. return
  3451. end
  3452.  
  3453. local cards = findCardsInZone(set.zone)
  3454. if #cards~=2 then clearPlayerActions(set.zone, true) return end
  3455.  
  3456. if not lockout then
  3457. local override = RunBonusFunc( "prePlayerDouble", {set=set, color=color} )
  3458. if override==true then return end
  3459.  
  3460. endTurnTimer(set)
  3461. if not repeatBet(color,set,splitSet) then return end
  3462.  
  3463. local override = RunBonusFunc( "onPlayerDouble", {set=set, color=color} )
  3464. if override==true then return end
  3465.  
  3466. lockoutTimer(1.5)
  3467. forcedCardDraw(set.zone)
  3468. clearPlayerActions(set.zone)
  3469. passPlayerActions(set.zone)
  3470. else
  3471. broadcastToColor("Error: Button delay is active.\nWait a moment then try again.", color, {1,0.25,0.25})
  3472. end
  3473. end
  3474. end
  3475.  
  3476. function checkForBust(set, addCard)
  3477. if set.value > 21 then
  3478. clearPlayerActions(set.zone)
  3479. lockoutTimer(0.75)
  3480.  
  3481. delayedCallback('delayedPassPlayerActions', {zone=set.zone, color=set.color}, 0.5)
  3482. elseif addCard and cardNameTable[addCard] then
  3483. local val = cardNameTable[addCard]
  3484. if val==0 then val=1 end
  3485. if set.soft then val=val-10 end
  3486.  
  3487. if set.value+val>21 then
  3488. clearPlayerActions(set.zone)
  3489. lockoutTimer(0.75)
  3490.  
  3491. delayedCallback('delayedPassPlayerActions', {zone=set.zone, color=set.color}, 0.5)
  3492. end
  3493. end
  3494. end
  3495.  
  3496. function playerStand(btnHandler, color)
  3497. local set = findObjectSetFromButtons(btnHandler)
  3498. if color == set.color or color == "Black" or Player[color].promoted or Player[color].host or (set.color:sub(1,5)=="Split" and set.UserColor==color) then
  3499. if set.color~=currentPlayerTurn then
  3500. clearPlayerActions(set.zone)
  3501.  
  3502. return broadcastToColor("Error: It's not your turn.", color, {1,0.25,0.25})
  3503. end
  3504.  
  3505. if color=="Black" or not lockout then
  3506. endTurnTimer(set, true)
  3507. clearPlayerActions(set.zone)
  3508. lockoutTimer(0.5)
  3509.  
  3510. delayedCallback('delayedPassPlayerActions', {zone=set.zone, color=set.color}, 0.25)
  3511.  
  3512. RunBonusFunc( "onPlayerStand", {set=set, color=color} )
  3513. else
  3514. broadcastToColor("Error: Button delay is active.\nWait a moment then try again.", color, {1,0.25,0.25})
  3515. end
  3516. end
  3517. end
  3518.  
  3519. function playerSplit(btnHandler, color)
  3520. local set = findObjectSetFromButtons(btnHandler)
  3521. if color == set.color or color == "Black" or Player[color].promoted or Player[color].host or (set.color:sub(1,5)=="Split" and set.UserColor==color) then
  3522. if set.color~=currentPlayerTurn then
  3523. clearPlayerActions(set.zone)
  3524.  
  3525. return broadcastToColor("Error: It's not your turn.", color, {1,0.25,0.25})
  3526. end
  3527.  
  3528. local cards = findCardsInZone(set.zone)
  3529. if #cards~=2 or cardNameTable[cards[1].getName()]~=cardNameTable[cards[2].getName()] then return end
  3530. if (not GetSetting("Hands.SplitOnValue", false)) and cards[1].getName()~=cards[2].getName() then return end
  3531.  
  3532. if not lockout then
  3533. endTurnTimer(set)
  3534. for _,splitSet in ipairs(reverseTable(objectSets)) do
  3535. if splitSet.color:sub(1,5)=="Split" and not splitSet.SplitUser then
  3536. local override = RunBonusFunc( "prePlayerSplit", {set=set, color=color} )
  3537. if override==true then return end
  3538.  
  3539. if not repeatBet(color,set,splitSet) then return end -- Could not get chips for split
  3540.  
  3541. local override = RunBonusFunc( "onPlayerSplit", {set=set, color=color} )
  3542. if override==true then return end
  3543.  
  3544. lockoutTimer(2)
  3545.  
  3546. splitSet.SplitUser = set
  3547. splitSet.UserColor = set.UserColor or set.color
  3548. splitSet.prestige = set.prestige
  3549. splitSet.tbl = set.tbl
  3550. splitSet.container.setColorTint( stringColorToRGB(set.UserColor or set.color) or {1,1,1} )
  3551.  
  3552. cards[1].setPosition( findCardPlacement(splitSet.zone,1) )
  3553. cards[1].setTable("blackjack_playerSet", splitSet) -- Sets zone to split zone, for flipping
  3554.  
  3555. cards[2].setPosition( findCardPlacement(set.zone,1) )
  3556.  
  3557. placeCard(findCardPlacement(set.zone,2), true, set, true)
  3558. placeCard(findCardPlacement(splitSet.zone,2), true, splitSet, true)
  3559.  
  3560. clearPlayerActions(set.zone)
  3561. currentPlayerTurn = splitSet.color
  3562.  
  3563. delayedCallback('delayedCreatePlayerActions', {set=splitSet}, 1.5)
  3564.  
  3565. return
  3566. end
  3567. end
  3568.  
  3569. broadcastToColor("Error: No free Split zones!", color, {1,0.25,0.25})
  3570. else
  3571. broadcastToColor("Error: Button delay is active.\nWait a moment then try again.", color, {1,0.25,0.25})
  3572. end
  3573. end
  3574. end
  3575.  
  3576. function payButtonPressed(o, color)
  3577. if (color == "Lua" or color == "Black" or Player[color].promoted or Player[color].host) then
  3578. if minigame and not (minigame==nil) and minigame.getVar("blackjackEndRound") and minigame.Call("blackjackEndRound", {color=color}) then -- Override
  3579. return
  3580. end
  3581.  
  3582. setRoundState( 1, GetSetting("Rounds.BetTime", 30) )
  3583.  
  3584. if minigame and not (minigame==nil) then
  3585. destroyObject(minigame)
  3586. end
  3587.  
  3588. if color == "Lua" or (not lockout) then
  3589. dealersTurn = false
  3590. dealingDealersCards = false
  3591.  
  3592. findCardsToCount() -- Update values
  3593.  
  3594. lockoutTimer(10)
  3595. local dealerValue = objectSets[1].value
  3596. local dealerCount = objectSets[1].count
  3597. for i, set in pairs(objectSets) do
  3598. local value = set.value
  3599. local count = set.count
  3600. if i ~= 1 and value ~= 0 and count ~= 0 then
  3601. if value<=21 and (value>dealerValue or dealerValue>21 and dealerValue~=69) or (value>=69 and value<=72 and dealerValue~=69) or (value==68 or value==71) then
  3602. local betsInZone = #findBetsInZone(set.zone)
  3603. if betsInZone ~= 0 then processPayout(set.zone, calculatePayout(set.zone), true) end
  3604. elseif ((dealerValue<=21 or dealerValue==69) and value == dealerValue) or count >= 5 or (value>=68 and value<=72) then
  3605. -- Unlock Chips
  3606. local zoneObjectList = set.zone.getObjects()
  3607. for j, bet in ipairs(zoneObjectList) do
  3608. if (bet.tag == "Chip" and not powerupEffectTable[bet.getName()]) or (bet.tag == "Bag" and bet.getName():sub(1,11)~="Player save") then
  3609. bet.interactable = true
  3610. bet.setLock(false)
  3611.  
  3612. if set.UserColor then
  3613. local targetSet = findObjectSetFromColor(set.UserColor) or set.SplitUser
  3614. if targetSet and targetSet.container then
  3615. targetSet.container.putObject(bet)
  3616. end
  3617. end
  3618. end
  3619. end
  3620. else
  3621. if value > 21 and not bonusShouldBust(set) then
  3622. -- Unlock Chips
  3623. local zoneObjectList = set.zone.getObjects()
  3624. for j, bet in ipairs(zoneObjectList) do
  3625. if (bet.tag == "Chip" and not powerupEffectTable[bet.getName()]) or (bet.tag == "Bag" and bet.getName():sub(1,11)~="Player save") then
  3626. bet.interactable = true
  3627. bet.setLock(false)
  3628.  
  3629. if set.UserColor then
  3630. local targetSet = findObjectSetFromColor(set.UserColor) or set.SplitUser
  3631. if targetSet and targetSet.container then
  3632. targetSet.container.putObject(bet)
  3633. end
  3634. end
  3635. end
  3636. end
  3637. else
  3638. clearBets(set.zone, true)
  3639. end
  3640. end
  3641. end
  3642. clearPlayerActions(set.zone)
  3643. clearCards(set.zone)
  3644.  
  3645. -- Unlock Chips
  3646. local zoneObjects = set.zone.getObjects()
  3647. local tableObjects = set.tbl.getObjects()
  3648. local prestigeObjects = set.prestige.getObjects()
  3649.  
  3650. for zid,zone in pairs({zoneObjects, tableObjects, prestigeObjects}) do
  3651. for j, bet in ipairs(zone) do
  3652. if (bet.tag == "Chip" and not powerupEffectTable[bet.getName()]) or (bet.tag == "Bag" and bet.getName():sub(1,11)~="Player save") and not bet.interactable then
  3653. bet.interactable = true
  3654. bet.setLock(false)
  3655.  
  3656. if zid==1 and set.UserColor then -- Only affects bet zone
  3657. local cont = (findObjectSetFromColor(set.UserColor) or set.SplitUser or {}).container
  3658. if cont then
  3659. Wait.frames(function()
  3660. if bet and cont and not (bet==nil or cont==nil) then
  3661. cont.putObject(bet)
  3662. end
  3663. end, 1)
  3664. end
  3665. end
  3666. end
  3667. end
  3668. end
  3669. end
  3670. concludeLockout()
  3671.  
  3672. if not inMinigame then
  3673. bonusOnRoundEnd()
  3674. end
  3675.  
  3676. inMinigame = false
  3677. else
  3678. broadcastToColor("Error: Button delay is active.\nWait a moment then try again.", color, {1,0.25,0.25})
  3679. end
  3680. end
  3681. end
  3682.  
  3683. -- --
  3684.  
  3685. function calculatePayout(zone)
  3686. local set = findObjectSetFromZone(zone)
  3687. local value = set.value
  3688. local count = set.count
  3689. local betMultiplier = 1
  3690. if value == 71 and count == 2 then
  3691. --double joker
  3692. giveReward( "DoubleJoker", zone )
  3693. betMultiplier = 14
  3694. elseif value == 70 and count == 3 then
  3695. --triple sevens
  3696. giveReward( "TripleSeven", zone )
  3697. betMultiplier = 7
  3698. elseif (value <= 21 or value == 68) and count >= 5 then
  3699. if (value == 21 or value == 68) and count >= 6 then
  3700. --six card 21
  3701. giveReward( "SixCardTwentyOne", zone )
  3702. betMultiplier = 5
  3703. elseif count >= 6 then
  3704. --six card win
  3705. giveReward( "SixCardWin", zone )
  3706. betMultiplier = 4
  3707. elseif (value == 21 or value == 68) and count == 5 then
  3708. --five card 21
  3709. giveReward( "FiveCardTwentyOne", zone )
  3710. betMultiplier = 4
  3711. elseif count == 5 then
  3712. --five card win
  3713. giveReward( "FiveCardWin", zone )
  3714. betMultiplier = 3
  3715. end
  3716. elseif value == 69 then
  3717. --natural blackjack
  3718. giveReward( "Blackjack", zone )
  3719. betMultiplier = 3
  3720. elseif value == 68 or value == 21 then
  3721. --joker or 21
  3722. if value == 68 then
  3723. betMultiplier = (getPrestige(zone) + 2)
  3724. else
  3725. betMultiplier = 2
  3726. end
  3727. end
  3728.  
  3729. local globalMultiplier = math.max(GetSetting("Bet.Multiplier", 1), 1)
  3730. betMultiplier = (bonusGetPayoutMultiplier( set, betMultiplier ) or betMultiplier) * globalMultiplier
  3731.  
  3732. return betMultiplier
  3733. end
  3734.  
  3735. function getPrestige(zone)
  3736. local set = findObjectSetFromZone(zone)
  3737. local zoneObjects = set.prestige.getObjects()
  3738. for i, object in ipairs(zoneObjects) do
  3739. -- local findStart, findEnd, findNumber = string.find(object.getVar("__trader_ObjectName") or object.getName(), "Prestige (%d+)")
  3740. -- if findStart and not string.find(object.getName(), "Trophy") then
  3741. -- return (tonumber(findNumber) or 0)
  3742. -- end
  3743. local level = object.getVar("PrestigeLevel")
  3744. if level then return level end
  3745. end
  3746. return 0
  3747. end
  3748.  
  3749. local selfDestructScript = [[
  3750. function onLoad()
  3751. expireTime = os.time() + %i
  3752. end
  3753. function onUpdate()
  3754. if expireTime and os.time()>expireTime then destroyObject(self) end
  3755. end]]
  3756. function processPayout(zone, iterations, lockedOnly)
  3757. local set = findObjectSetFromZone(zone)
  3758. local zoneObjects = zone.getObjects()
  3759. local badBagObjects = 0
  3760.  
  3761. local plyID = Player[set.UserColor or set.color].seated and Player[set.UserColor or set.color].steam_id
  3762.  
  3763. for j, bet in ipairs(zoneObjects) do
  3764. local wasLocked = {}
  3765. if ((bet.tag == "Chip" and not powerupEffectTable[bet.getName()]) or (bet.tag == "Bag" and bet.getName():sub(1,11)~="Player save")) then
  3766. if (not lockedOnly) or (not bet.interactable) or wasLocked[bet.getGUID()] then
  3767. if (lockedOnly and bet.tag == "Bag") then -- Remove anything that shouldn't be here
  3768. local goodIDs = bet.getTable("Blackjack_BetBagContents")
  3769. local contents = bet.getObjects()
  3770.  
  3771. -----
  3772. local params = {}
  3773. params.position = set.container.getPosition()
  3774. params.position.y = params.position.y + 0.25
  3775.  
  3776. for n=1,#contents do
  3777. if (not goodIDs[contents[n].guid]) or goodIDs[contents[n].guid]<=0 then
  3778. local taken = bet.takeObject(params)
  3779.  
  3780. params.position.y = math.min(params.position.y + 0.5, 20)
  3781. set.container.putObject(taken)
  3782.  
  3783. badBagObjects = badBagObjects + 1
  3784. end
  3785. goodIDs[contents[n].guid] = (goodIDs[contents[n].guid] or 0) - 1
  3786. end
  3787. -----
  3788. end
  3789.  
  3790. wasLocked[bet.getGUID()] = true
  3791. bet.interactable = true
  3792. bet.setLock(false)
  3793.  
  3794.  
  3795. local params = {}
  3796. params.position = bet.getPosition()
  3797. params.position.y = params.position.y - 10
  3798.  
  3799. local clone = bet.clone(params)
  3800. clone.setLock(true)
  3801. clone.setPosition(params.position)
  3802.  
  3803. clone.setLuaScript( selfDestructScript:format(((iterations/10)+2)*1.25) )
  3804.  
  3805.  
  3806. local betID = bet.getDescription():match("^(%d+) %- .*")
  3807. if betID and betID~=plyID then
  3808. local foundPly = false
  3809. local playerList = getSeatedPlayers()
  3810. for _, col in ipairs(playerList) do
  3811. local targetSet = findObjectSetFromColor(col)
  3812. if Player[col].seated and Player[col].steam_id==betID and targetSet then
  3813. foundPly = true
  3814. for i=1, iterations do
  3815. delayedCallback('payBet', {set=targetSet, bet=clone, final=(i==iterations)}, (i/10))
  3816. end
  3817.  
  3818. local setPos = targetSet.zone.getPosition()
  3819. bet.setPosition( setPos )
  3820.  
  3821. break
  3822. end
  3823. end
  3824.  
  3825. if not foundPly then
  3826. -- TODO: Push objects to autosave
  3827. destroyObject(bet)
  3828. destroyObject(clone)
  3829. end
  3830. else
  3831. for i=1, iterations do
  3832. delayedCallback('payBet', {set=set, bet=clone, final=(i==iterations)}, (i/10))
  3833. end
  3834.  
  3835. if set.UserColor and bet.tag=="Bag" then
  3836. local targetSet = findObjectSetFromColor(set.UserColor)
  3837. if targetSet then
  3838. targetSet.container.putObject(bet)
  3839. end
  3840. end
  3841. end
  3842. end
  3843. end
  3844. end
  3845.  
  3846. if badBagObjects>0 then
  3847. broadcastToColor( string.format("Refunded %i bad object(s) in bet bag. Did you attempt to alter your bet?", badBagObjects), set.color, {1,0.25,0.25})
  3848.  
  3849. for k,adminCol in pairs(getSeatedPlayers()) do
  3850. if Player[adminCol].admin then
  3851. printToColor( string.format("Refunded %i bad object(s) in bet bag of player %s (%s).", badBagObjects, set.color, Player[set.color].steam_name), adminCol, {1,0,0} )
  3852. end
  3853. end
  3854. end
  3855. end
  3856.  
  3857. function validatePayoutObject(obj, data)
  3858. if obj.tag~="Chip" or powerupEffectTable[obj.getName()] then return obj.destruct() end
  3859.  
  3860. obj.unlock()
  3861.  
  3862. if data.container then
  3863. data.container.putObject( obj )
  3864. end
  3865. end
  3866. function payBet(table)
  3867. local params = {}
  3868. params.position = table.set.container.getPosition()
  3869. params.position.y = params.position.y + 0.25
  3870.  
  3871. params.params = {container=table.set.container}
  3872. params.callback = "validatePayoutObject"
  3873. params.callback_owner = Global
  3874.  
  3875. if table.bet.tag == "Chip" and not powerupEffectTable[table.bet.getName()] then
  3876. local payout = table.bet.clone(params)
  3877. payout.setPosition(params.position)
  3878.  
  3879. payout.interactable = true
  3880. payout.setLock(false)
  3881. payout.setLuaScript( "" )
  3882.  
  3883. table.set.container.putObject( payout )
  3884.  
  3885. payout.destruct()
  3886. elseif table.bet.tag == "Bag" and table.bet.getName():sub(1,11)~="Player save" then
  3887. local payout = table.bet.clone(params)
  3888.  
  3889. for l=1, table.bet.getQuantity() do
  3890. local taken = payout.takeObject(params)
  3891. taken.setPosition(params.position)
  3892.  
  3893. taken.lock()
  3894. params.position.y = math.min(params.position.y + 0.5, 20) -- Exact position doesn't matter too much, as long as it doesn't get sucked into another bag before we can validate.
  3895. end
  3896. payout.destruct()
  3897. end
  3898. Timer.destroy(table.id)
  3899. if table.final then
  3900. table.bet.destruct()
  3901. end
  3902. end
  3903.  
  3904.  
  3905.  
  3906.  
  3907.  
  3908. --BUTTON CREATION SECTION
  3909.  
  3910.  
  3911.  
  3912.  
  3913. --Button creation, trigger is in onload()
  3914. function createButtons()
  3915. --Card count displays, get created first so they have index of 0 on their zones
  3916. for i, v in ipairs(objectSets) do
  3917. v.btnHandler.createButton({
  3918. label="0", click_function="hitCard", function_owner=nil,
  3919. position={0, 0.25, 0}, rotation={0,0,0}, width=450, height=450, font_size=300
  3920. }, true)
  3921.  
  3922. createPlayerMetaActions(v)
  3923. end
  3924.  
  3925. cardHandler.createButton({
  3926. label="Deal\ncards", click_function="dealButtonPressed", function_owner=nil,
  3927. position={-0.46,0.19,-0.19}, rotation={0,0,0}, width=450, height=450, font_size=150
  3928. })
  3929. cardHandler.createButton({
  3930. label="End\nround", click_function="payButtonPressed", function_owner=nil,
  3931. position={0.46,0.19,-0.19}, rotation={0,0,0}, width=450, height=450, font_size=150
  3932. })
  3933. end
  3934.  
  3935.  
  3936. -- Forward functions from third parties
  3937. function forwardFunction(params)
  3938. if _G[params.function_name or ""] then -- Normally I'd use boolean logic instead of an if statement here, but we may have more than one return value
  3939. return _G[params.function_name or ""]( unpack(params.data or {}) )
  3940. end
  3941. end
  3942.  
  3943. function onChat(str, ply)
  3944. if ply.admin and str:lower():sub(1,7)=="!debug " then
  3945. printToColor( ("Debug: %s = %s"):format(str:sub(8,-1), tostring(_G[str:sub(8,-1)])), ply.color, {1,1,1})
  3946.  
  3947. if type(_G[str:sub(8,-1)])=="table" then
  3948. for k,v in pairs(_G[str:sub(8,-1)]) do
  3949. printToColor( (" - %s = %s"):format(k, v), ply.color, {1,1,1})
  3950. end
  3951. end
  3952.  
  3953. return false
  3954. end
  3955. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement