From 35103763b43105581e86f773f32571cbf67cf640 Mon Sep 17 00:00:00 2001 From: canonelis <86532940+Canonelis@users.noreply.github.com> Date: Mon, 13 Dec 2021 06:35:02 -0500 Subject: [PATCH 1/4] fix voting squares that stick around made a function clearAllVotes() that removes all votes in the array as well as all the votes from the GUI(if the card object exists) -call clearAllVotes() inside toggleTurns(), resetGame() and endGame() -check if card object guid exists inside updateVoteUI -when a player changes colour, their vote didn't get zeroed. fixed that. --- src/Global.-1.ttslua | 58 +++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/src/Global.-1.ttslua b/src/Global.-1.ttslua index 65d6c30..bf831d5 100644 --- a/src/Global.-1.ttslua +++ b/src/Global.-1.ttslua @@ -790,7 +790,7 @@ function onPlayerChangeColor(color) for playerColor, voteData in pairs(votes[gameState.turnTracker]) do if not Player[playerColor].seated and voteData ~= 0 then local card = voteData - voteData = 0 + votes[gameState.turnTracker][playerColor] = 0 updateVoteUI(card) end end @@ -865,6 +865,21 @@ function setDeck(deckID) end end +function clearAllVotes() + local cardsToUpdate = {} + for turnNum, team in pairs(votes) do + for seatColor, vote in pairs(team) do + if vote != 0 then + cardsToUpdate[vote] = true + votes[turnNum][seatColor] = 0 + end + end + end + for card, _ in pairs(cardsToUpdate) do + updateVoteUI(card) + end +end + -- Restrict newGame permissions to Red/Blue/Promoted/Host function startGame(player) -- Check to see whether a new game is currently being set up @@ -934,11 +949,7 @@ function resetGame() end -- Reset team votes - for turnNum, team in pairs(votes) do - for seatColor, vote in pairs(team) do - votes[turnNum][seatColor] = 0 - end - end + clearAllVotes() -- Reset game state variables gameState.firstTurn = true @@ -1214,20 +1225,8 @@ function playerVote(color, card) end if votePassed then - -- Remove all vote indicators and reset votes - local cardsToClear = {} - for playerColor, voteData in pairs(votes[gameState.turnTracker]) do - -- Update the vote UI first - if voteData ~= 0 then - table.insert(cardsToClear, voteData) - votes[gameState.turnTracker][playerColor] = 0 - end - end - - for _, card in ipairs(cardsToClear) do - updateVoteUI(card) - end - + clearAllVotes() + -- Vote passed to pass turn if card == 26 then toggleTurns() @@ -1345,6 +1344,9 @@ end function updateVoteUI(card) local uiObject = card == 26 and tableObject or getObjectFromGUID(cards[card].guid) + if uiObject == nil then + return + end local votesToAdd = {} for playerColor, voteData in pairs(votes[gameState.turnTracker]) do @@ -1505,6 +1507,8 @@ function isCard(guid) end function endGame() + clearAllVotes() + -- Disable voting for any teams gameState.canVote = false @@ -1628,19 +1632,7 @@ function toggleTurns() -- Diable voting for the current team gameState.canVote = false - -- Remove all vote indicators and reset votes - local cardsToClear = {} - for playerColor, voteData in pairs(votes[gameState.turnTracker]) do - -- Update the vote UI first - if voteData ~= 0 then - table.insert(cardsToClear, voteData) - votes[gameState.turnTracker][playerColor] = 0 - end - end - - for _, card in ipairs(cardsToClear) do - updateVoteUI(card) - end + clearAllVotes() -- Disable card tilting for _, card in ipairs(cards) do From 27264924674e8e1f24af729773d8a3dde0efca29 Mon Sep 17 00:00:00 2001 From: canonelis <86532940+Canonelis@users.noreply.github.com> Date: Thu, 13 Jan 2022 00:51:38 -0500 Subject: [PATCH 2/4] Initial changes for multivoting Initial changes for multivoting --- src/Global.-1.ttslua | 278 +++++++++++++++++++++++++------------------ 1 file changed, 160 insertions(+), 118 deletions(-) diff --git a/src/Global.-1.ttslua b/src/Global.-1.ttslua index bf831d5..f56908b 100644 --- a/src/Global.-1.ttslua +++ b/src/Global.-1.ttslua @@ -110,16 +110,16 @@ agents = { votes = { [0] = { - ["Orange"] = 0, - ["Yellow"] = 0, - ["Pink"] = 0, - ["Brown"] = 0 + ["Orange"] = {}, + ["Yellow"] = {}, + ["Pink"] = {}, + ["Brown"] = {} }, [1] = { - ["Teal"] = 0, - ["Purple"] = 0, - ["Green"] = 0, - ["White"] = 0 + ["Teal"] = {}, + ["Purple"] = {}, + ["Green"] = {}, + ["White"] = {} } } @@ -232,6 +232,36 @@ analytics = sessions = {} } +function findInArray(val,arr,cmp_func) --cmp_func is optional, a function with two arguments that returns a boolean value + -- returns the index of the value in the table + if type(arr) ~= "table" then + return nil + end + if cmp_func ~= nil then + if type(cmp_func) == "function" then + for i, v in pairs(arr) do + success, res = pcall(cmp_func,v,val) + if success then + if res == true then + return i + end + else + error("findInArray:custom compare function failed with error:"..tostring(res)) + end + end + else + error("findInArray:custom compare function is not a function or does not have 2 arguments.") + end + else + for i, v in pairs(arr) do + if v == val then + return i + end + end + end + return nil +end + function onload(saveState) -- Codenames script version @@ -271,7 +301,7 @@ function onload(saveState) position={0,-0.15,0}, rotation={0,90,0}, height=1000, width=2000, font_size=10 }) - buttonRed.createButton({ + buttonRed.createButton({ label="[END TURN]", click_function="endTurn", function_owner=self, position={0,-0.15,0}, rotation={0,90,0}, height=1000, width=2000, font_size=10 }) @@ -787,13 +817,18 @@ function onPlayerChangeColor(color) -- Reset the player's vote (if necessary) if gameState.status == 1 then + local cardsToUpdate = {} for playerColor, voteData in pairs(votes[gameState.turnTracker]) do - if not Player[playerColor].seated and voteData ~= 0 then - local card = voteData - votes[gameState.turnTracker][playerColor] = 0 - updateVoteUI(card) + if Player[playerColor].steam_id == nil and #voteData ~= 0 then + for _, card in pairs(voteData) do + cardsToUpdate[card] = true + end + votes[gameState.turnTracker][playerColor] = {} end end + for card, _ in pairs(cardsToUpdate) do + updateVoteUI(card) + end end local endSession = {} @@ -868,11 +903,11 @@ end function clearAllVotes() local cardsToUpdate = {} for turnNum, team in pairs(votes) do - for seatColor, vote in pairs(team) do - if vote != 0 then - cardsToUpdate[vote] = true - votes[turnNum][seatColor] = 0 + for seatColor, voteData in pairs(team) do + for _, v in pairs(voteData) do + cardsToUpdate[v] = true end + votes[turnNum][seatColor] = {} end end for card, _ in pairs(cardsToUpdate) do @@ -1192,124 +1227,131 @@ function playerVote(color, card) return end - if votes[gameState.turnTracker][color] == 0 then - votes[gameState.turnTracker][color] = card + local ind = findInArray(card,votes[gameState.turnTracker][color]) + if ind != nil then + -- Remove this player's vote + table.remove(votes[gameState.turnTracker][color],ind) updateVoteUI(card) else - if votes[gameState.turnTracker][color] == card then - -- Remove this player's vote - votes[gameState.turnTracker][color] = 0 - updateVoteUI(card) - else - -- Switch the player's current vote to this card - local previous = votes[gameState.turnTracker][color] - votes[gameState.turnTracker][color] = card - updateVoteUI(previous) - updateVoteUI(card) - end - end - - -- Check to see if a vote has passed - local votePassed = false - local voteCard = nil - for playerColor, voteData in pairs(votes[gameState.turnTracker]) do + -- Add the player's vote + table.insert(votes[gameState.turnTracker][color],card) + updateVoteUI(card) + + -- Check to see if the card now has a passing vote + local votePassed = false + for playerColor, voteData in pairs(votes[gameState.turnTracker]) do if Player[playerColor].seated and not Player[playerColor].blindfolded then - if (voteCard == nil and voteData ~= 0) or voteData == voteCard then - votePassed = true - voteCard = voteData - else - votePassed = false - break + votePassed = findInArray(card,voteData) != nil + if votePassed == false then + break + end end end - end - if votePassed then - clearAllVotes() - - -- Vote passed to pass turn - if card == 26 then - toggleTurns() - return - end - - -- Card has been marked correctly - gameState.guessesLeft = gameState.guessesLeft - 1 - cards[card].covered = true + if votePassed then + -- Remove votes on the card + for playerColor, voteData in pairs(votes[gameState.turnTracker]) do + ind = findInArray(card,voteData) + if ind != nil then + table.remove(votes[gameState.turnTracker][playerColor],ind) + end + end - -- Cover the card - coverCard(card, nil) + updateVoteUI(card) - -- Send analytics data for the guess - local players = "" - local correct = ((gameState.turnTracker == 0 and cards[card].color == "Red") or (gameState.turnTracker == 1 and cards[card].color == "Blue")) and "TRUE" or "FALSE" - for color,_ in pairs(votes[gameState.turnTracker]) do - if Player[color].seated then - players = players .. ((players == "") and Player[color].steam_id or (',' .. Player[color].steam_id)) + -- Vote passed to pass turn + if card == 26 then + toggleTurns() + return end - end - api_clueGuess(players, cards[card].id, correct, cards[card].color:upper()) - local messageColor = { - ["Red"] = "da1918", - ["Blue"] = "1f87ff", - ["White"] = "ffffff", - ["Black"] = "191919" - } + -- Card has been marked correctly + gameState.guessesLeft = gameState.guessesLeft - 1 + cards[card].covered = true - if correct == "TRUE" then - -- Play the correct sound effect - tableObject.AssetBundle.playTriggerEffect(0) - printToAll("[a020f0]» [31b32b][✓] [" .. messageColor[cards[card].color] .. "]" .. cards[card].color:upper() .. " [ffffff]team has correctly guessed: [" .. messageColor[cards[card].color] .."]" .. cards[card].value:upper() .. " [a020f0]«") - else - -- Play the wrong sound effect - tableObject.AssetBundle.playTriggerEffect(1) - local guessingTeam = gameState.turnTracker == 0 and "Red" or "Blue" - printToAll("[a020f0]» [da1918][✗] [" .. messageColor[guessingTeam] .. "]" .. guessingTeam:upper() .. " [ffffff]team has incorrectly guessed: [" .. messageColor[cards[card].color] .."]" .. cards[card].value:upper() .. " [a020f0]«") - end + -- Cover the card + coverCard(card, nil) - -- Check to see if either red or blue won - local redWon = true - local blueWon = true - for i = 1, 25, 1 do - if cards[i].color == "Red" and not cards[i].covered then - redWon = false - elseif cards[i].color == "Blue" and not cards[i].covered then - blueWon = false + -- Send analytics data for the guess + local players = "" + local correct = ((gameState.turnTracker == 0 and cards[card].color == "Red") or (gameState.turnTracker == 1 and cards[card].color == "Blue")) and "TRUE" or "FALSE" + for color,_ in pairs(votes[gameState.turnTracker]) do + if Player[color].seated then + players = players .. ((players == "") and Player[color].steam_id or (',' .. Player[color].steam_id)) + end end - - if not redWon and not blueWon then - -- Skip unnecessary iterations - break + api_clueGuess(players, cards[card].id, correct, cards[card].color:upper()) + + local messageColor = { + ["Red"] = "da1918", + ["Blue"] = "1f87ff", + ["White"] = "ffffff", + ["Black"] = "191919" + } + if correct == "TRUE" then + -- Play the correct sound effect + tableObject.AssetBundle.playTriggerEffect(0) + printToAll("[a020f0]» [31b32b][✓] [" .. messageColor[cards[card].color] .. "]" .. cards[card].color:upper() .. " [ffffff]team has correctly guessed: [" .. messageColor[cards[card].color] .."]" .. cards[card].value:upper() .. " [a020f0]«") + else + -- Play the wrong sound effect + tableObject.AssetBundle.playTriggerEffect(1) + local guessingTeam = gameState.turnTracker == 0 and "Red" or "Blue" + printToAll("[a020f0]» [da1918][✗] [" .. messageColor[guessingTeam] .. "]" .. guessingTeam:upper() .. " [ffffff]team has incorrectly guessed: [" .. messageColor[cards[card].color] .."]" .. cards[card].value:upper() .. " [a020f0]«") end - end - if cards[card].color == "Black" or blueWon or redWon then - -- End game scenario + -- Check to see if either red or blue won + local redWon = true + local blueWon = true + for i = 1, 25, 1 do + if cards[i].color == "Red" and not cards[i].covered then + redWon = false + elseif cards[i].color == "Blue" and not cards[i].covered then + blueWon = false + end - if (cards[card].color == "Black" and gameState.turnTracker == 0) or blueWon then - -- Red placed black card, blue wins - -- or blue placed all of their cards - broadcastToAll("[a020f0]» [1f87ff]BLUE [ffffff]team wins! [a020f0]«") - api_gameEnd("BLUE") - elseif (cards[card].color == "Black" and gameState.turnTracker == 1) or redWon then - -- Blue placed black card, red wins - -- or red placed all of their cards - broadcastToAll("[a020f0]» [da1918]RED [ffffff]team wins! [a020f0]«") - api_gameEnd("RED") + if not redWon and not blueWon then + -- Skip unnecessary iterations + break + end end - -- Move the remaining agents to their codes - endGame() + if cards[card].color == "Black" or blueWon or redWon then + -- End game scenario + + if (cards[card].color == "Black" and gameState.turnTracker == 0) or blueWon then + -- Red placed black card, blue wins + -- or blue placed all of their cards + broadcastToAll("[a020f0]» [1f87ff]BLUE [ffffff]team wins! [a020f0]«") + api_gameEnd("BLUE") + elseif (cards[card].color == "Black" and gameState.turnTracker == 1) or redWon then + -- Blue placed black card, red wins + -- or red placed all of their cards + broadcastToAll("[a020f0]» [da1918]RED [ffffff]team wins! [a020f0]«") + api_gameEnd("RED") + end - elseif gameState.guessesLeft == 0 or cards[card].color == "White" or (cards[card].color == "Red" and gameState.turnTracker == 1) or (cards[card].color == "Blue" and gameState.turnTracker == 0) then - toggleTurns() - else - -- Show the pass turn button and change color - tableObject.UI.setAttributes("passTurn", { - color = gameState.turnTracker == 0 and "#da1918" or "#1f87ff", - active = true - }) + -- Move the remaining agents to their codes + endGame() + + elseif gameState.guessesLeft == 0 or cards[card].color == "White" or (cards[card].color == "Red" and gameState.turnTracker == 1) or (cards[card].color == "Blue" and gameState.turnTracker == 0) then + toggleTurns() + local cardsToClear = {} + for playerColor, voteData in pairs(votes[gameState.turnTracker]) do + for _, card in pairs(voteData) do + cardsToClear[card] = true + end + votes[gameState.turnTracker][playerColor] = {} + end + for card, _ in pairs(cardsToClear) do + updateVoteUI(card) + end + else + -- Show the pass turn button and change color + tableObject.UI.setAttributes("passTurn", { + color = gameState.turnTracker == 0 and "#da1918" or "#1f87ff", + active = true + }) + end end end end @@ -1350,7 +1392,7 @@ function updateVoteUI(card) local votesToAdd = {} for playerColor, voteData in pairs(votes[gameState.turnTracker]) do - if voteData == card then + if findInArray(card,voteData) != nil then votesToAdd[playerColor] = true end end @@ -1366,7 +1408,7 @@ function updateVoteUI(card) -- Keep the order of the current votes for voteIndex, voteColor in ipairs(votesOnCard) do if voteColor ~= "Black" then - if votes[gameState.turnTracker][voteColor] == card then + if findInArray(card,votes[gameState.turnTracker][voteColor]) != nil then table.insert(newVotes, voteColor) votesToAdd[voteColor] = nil end From a8df8da092034eb4e1aa4857c6b765fbda4862b3 Mon Sep 17 00:00:00 2001 From: canonelis <86532940+Canonelis@users.noreply.github.com> Date: Thu, 13 Jan 2022 01:39:35 -0500 Subject: [PATCH 3/4] remove votes on guessed card remove votes on guessed card --- src/Global.-1.ttslua | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Global.-1.ttslua b/src/Global.-1.ttslua index f56908b..064de3b 100644 --- a/src/Global.-1.ttslua +++ b/src/Global.-1.ttslua @@ -1136,6 +1136,15 @@ function onObjectDrop(color, agent) coverCard(cardIndex, agent.guid) + -- Remove votes on the card + for playerColor, voteData in pairs(votes[gameState.turnTracker]) do + local ind = findInArray(cardIndex,voteData) + if ind != nil then + table.remove(votes[gameState.turnTracker][playerColor],ind) + end + end + updateVoteUI(cardIndex) + -- Send analytics data for the guess local players = "" local correct = ((gameState.turnTracker == 0 and cardColor == "Red") or (gameState.turnTracker == 1 and cardColor == "Blue")) and "TRUE" or "FALSE" @@ -1249,15 +1258,6 @@ function playerVote(color, card) end if votePassed then - -- Remove votes on the card - for playerColor, voteData in pairs(votes[gameState.turnTracker]) do - ind = findInArray(card,voteData) - if ind != nil then - table.remove(votes[gameState.turnTracker][playerColor],ind) - end - end - - updateVoteUI(card) -- Vote passed to pass turn if card == 26 then @@ -1272,6 +1272,15 @@ function playerVote(color, card) -- Cover the card coverCard(card, nil) + -- Remove votes on the card + for playerColor, voteData in pairs(votes[gameState.turnTracker]) do + local ind = findInArray(card,voteData) + if ind != nil then + table.remove(votes[gameState.turnTracker][playerColor],ind) + end + end + updateVoteUI(card) + -- Send analytics data for the guess local players = "" local correct = ((gameState.turnTracker == 0 and cards[card].color == "Red") or (gameState.turnTracker == 1 and cards[card].color == "Blue")) and "TRUE" or "FALSE" @@ -1379,6 +1388,7 @@ function coverCard(cardIndex, agentGUID) cardObject.setPositionSmooth(position) agentObject.setPositionSmooth(position) + break end end From 7e3247c55f55ad2eee6188214f4c78095aa0d4b9 Mon Sep 17 00:00:00 2001 From: canonelis <86532940+Canonelis@users.noreply.github.com> Date: Thu, 13 Jan 2022 03:09:07 -0500 Subject: [PATCH 4/4] Adding UI integration for multivoting Adding UI integration for multivoting --- src/Custom Assetbundle.0a61c6.ttslua | 34 ++++++++++++++++++++++++++++ src/Custom Assetbundle.0a61c6.xml | 5 ++++ src/Global.-1.ttslua | 30 ++++++++++++++++++------ 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/Custom Assetbundle.0a61c6.ttslua b/src/Custom Assetbundle.0a61c6.ttslua index b1b1303..c0be416 100644 --- a/src/Custom Assetbundle.0a61c6.ttslua +++ b/src/Custom Assetbundle.0a61c6.ttslua @@ -110,6 +110,7 @@ function updateSettings() queues(nil, Global.call("getQueue") == true and "True" or "False") switcher(nil, Global.call("getSwitcher") == true and "True" or "False") tilting(nil, Global.call("getTilting") == true and "True" or "False") + multivoting(nil, Global.call("getMultivoting") == true and "True" or "False") --afk(player) --afkTime(player) timer(nil, Global.call("getTimer") == true and "True" or "False") @@ -343,6 +344,39 @@ function tilting(player, enabled) self.UI.setAttribute("tilting", "isOn", toboolean(enabled)) end +function multivoting(player, enabled) + if player ~= nil and not player.admin then + self.UI.setAttribute("multivoting", "isOn", self.UI.getAttribute("multivoting", "isOn")) + player.broadcast("[a020f0]» [da1918]ERROR: [ffffff]Only promoted players may change game settings! [a020f0]«") + return + end + + -- Handle in the Global script + Global.call("setMultivoting", toboolean(enabled)) + + -- Update the view for everyone + self.UI.setAttribute("multivoting", "isOn", toboolean(enabled)) + + -- Put or remove multivoting message on the table + if toboolean(enabled) then + local text = spawnObject({ + position = {x=0, y=0.961133063, z=-4.9}, + rotation = {90.0,0,0.0}, + type = "3DText" + }) + text.TextTool.setValue("MULTIVOTING ENABLED") + text.TextTool.setFontColor("Orange") + text.TextTool.setFontSize(80) + else + for _, o in pairs(getObjects()) do + if o.type == "3D Text" and o.TextTool.getValue() == "MULTIVOTING ENABLED" then + o.destruct() + end + end + end + +end + function afk(player) if player ~= nil and not player.admin then self.UI.setAttribute("afk", "isOn", self.UI.getAttribute("afk", "isOn")) diff --git a/src/Custom Assetbundle.0a61c6.xml b/src/Custom Assetbundle.0a61c6.xml index f84fc59..09dff65 100644 --- a/src/Custom Assetbundle.0a61c6.xml +++ b/src/Custom Assetbundle.0a61c6.xml @@ -879,6 +879,11 @@ + + Multiple Votes Per Player + + + AFK Settings diff --git a/src/Global.-1.ttslua b/src/Global.-1.ttslua index 064de3b..72efed4 100644 --- a/src/Global.-1.ttslua +++ b/src/Global.-1.ttslua @@ -163,6 +163,9 @@ settings = -- Disable/Enable "inf meta" cardTilting = false, + -- Allow multiple votes per player + multivoting = false, + -- Show shooting star background starBackground = true, @@ -333,7 +336,6 @@ function onload(saveState) local decodedSaveState = JSON.decode(saveState) -- TODO: - -- votes -- currently selected decks -- table ui elements @@ -407,11 +409,12 @@ function getQueue() return settings.codemasterQueue end function setSwitcher(enabled) settings.colorSwitcher = enabled end function getSwitcher() return settings.colorSwitcher end -function setTilting(enabled) - settings.cardTilting = enabled -end +function setTilting(enabled) settings.cardTilting = enabled end function getTilting() return settings.cardTilting end +function setMultivoting(enabled) settings.multivoting = enabled end +function getMultivoting() return settings.multivoting end + function setAfk(enabled) settings.afkDetection.enabled = enabled Timer.destroy("afkLoop") @@ -1237,10 +1240,23 @@ function playerVote(color, card) end local ind = findInArray(card,votes[gameState.turnTracker][color]) + if not settings.multivoting then + -- Remove all of player's other votes + local cardsToUpdate = {} + for _, card in pairs(votes[gameState.turnTracker][color]) do + cardsToUpdate[card] = true + end + votes[gameState.turnTracker][color] = {} + for card, _ in pairs(cardsToUpdate) do + updateVoteUI(card) + end + end if ind != nil then - -- Remove this player's vote - table.remove(votes[gameState.turnTracker][color],ind) - updateVoteUI(card) + if settings.multivoting then + -- Remove this player's vote + table.remove(votes[gameState.turnTracker][color],ind) + updateVoteUI(card) + end else -- Add the player's vote table.insert(votes[gameState.turnTracker][color],card)