-- Bundled by luabundle {"version":"1.6.0"} local __bundle_require, __bundle_loaded, __bundle_register, __bundle_modules = (function(superRequire) local loadingPlaceholder = {[{}] = true} local register local modules = {} local require local loaded = {} register = function(name, body) if not modules[name] then modules[name] = body end end require = function(name) local loadedModule = loaded[name] if loadedModule then if loadedModule == loadingPlaceholder then return nil end else if not modules[name] then if not superRequire then local identifier = type(name) == 'string' and '\"' .. name .. '\"' or tostring(name) error('Tried to require ' .. identifier .. ', but no such module has been registered') else return superRequire(name) end end loaded[name] = loadingPlaceholder loadedModule = modules[name](require, loaded, register, modules) loaded[name] = loadedModule end return loadedModule end return require, loaded, register, modules end)(nil) __bundle_register("__root", function(require, _LOADED, __bundle_register, __bundle_modules) require("accessories/HandHelper") end) __bundle_register("accessories/HandHelper", function(require, _LOADED, __bundle_register, __bundle_modules) local playmatAPI = require("playermat/PlaymatApi") local buttonParamaters = {} buttonParamaters.function_owner = self -- saving "playerColor" and "des" function onSave() return JSON.encode({ playerColor, des}) end function onLoad(saved_data) -- loading saved data local loaded_data = JSON.decode(saved_data) playerColor = loaded_data[1] or Player.getAvailableColors()[1] des = loaded_data[2] or false -- index 0: button as hand size label buttonParamaters.hover_color = "White" buttonParamaters.click_function = "none" buttonParamaters.position = { 0, 0.11, -0.4 } buttonParamaters.height = 0 buttonParamaters.width = 0 buttonParamaters.font_size = 500 buttonParamaters.font_color = "White" self.createButton(buttonParamaters) -- index 1: button to toggle "des" buttonParamaters.label = "DES: " .. (des and "✓" or "✗") buttonParamaters.click_function = "toggleDES" buttonParamaters.position = { 0.475, 0.11, 0.25 } buttonParamaters.height = 175 buttonParamaters.width = 440 buttonParamaters.font_size = 90 buttonParamaters.font_color = "Black" self.createButton(buttonParamaters) -- index 2: button to discard a card buttonParamaters.label = "discard random card" buttonParamaters.click_function = "discardRandom" buttonParamaters.position = { 0, 0.11, 0.7 } buttonParamaters.width = 900 self.createButton(buttonParamaters) -- index 3: button to select color buttonParamaters.label = playerColor buttonParamaters.color = playerColor buttonParamaters.hover_color = playerColor buttonParamaters.click_function = "changeColor" buttonParamaters.tooltip = "change color" buttonParamaters.position = { -0.475, 0.11, 0.25 } buttonParamaters.width = 440 self.createButton(buttonParamaters) -- start loop to update card count loopId = Wait.time(||updateValue(), 1, -1) -- context menu to quickly bind color self.addContextMenuItem("Bind to my color", function(color) changeColor(_, _, _, color) end) -- context menu to display additional information self.addContextMenuItem("More Information", function() printToAll("------------------------------", "White") printToAll("Hand Helper by Chr1Z", "Orange") printToAll("original by Tikatoy", "White") printToAll("Note: 'Hidden' cards can't be randomly discarded.", "Yellow") printToAll("Set them aside beforehand!", "Yellow") end) -- initialize the pseudo random number generator math.randomseed(os.time()) end function onObjectHover(hover_color, obj) -- only continue if correct player hovers over "self" if obj ~= self or hover_color ~= playerColor then return end -- stop loop, toggle "des" and displayed value briefly, then start new loop Wait.stop(loopId) des = not des updateValue() des = not des loopId = Wait.time(||updateValue(), 1, -1) end -- toggle "des" and update button label function toggleDES() des = not des self.editButton({index = 1, label = "DES: " .. (des and "✓" or "✗")}) updateValue() end -- count cards in hand (by name for DES) function updateValue() if not playerExists(playerColor) then return end local hand = Player[playerColor].getHandObjects() local size = 0 if des then local cardHash = {} for _, obj in pairs(hand) do if obj.tag == "Card" then local name = obj.getName() local title = string.match(name, '(.+)(%s%(%d+%))') or name cardHash[title] = obj end end for _, obj in pairs(cardHash) do size = size + 1 end else for _, obj in pairs(hand) do if obj.tag == "Card" then size = size + 1 end end end -- change button label and color self.editButton({index = 0, font_color = des and "Green" or "White", label = size}) end -- allows change of color via external call function externalColorChange(newColor) changeColor(_, _, _, newColor) end -- get index of current color and move up one step (or down for right-click) function changeColor(_, _, isRightClick, color) if color then playerColor = color else local COLORS = Player.getAvailableColors() local pos = indexOf(COLORS, playerColor) if isRightClick then if pos == nil or pos == 1 then pos = #COLORS else pos = pos - 1 end else if pos == nil or pos == #COLORS then pos = 1 else pos = pos + 1 end end -- update playerColor playerColor = COLORS[pos] end -- update "change color" button (note: remove and create instantly updates hover_color) buttonParamaters.label = playerColor buttonParamaters.color = playerColor buttonParamaters.hover_color = playerColor self.removeButton(3) self.createButton(buttonParamaters) end --------------------------------------------------------- -- discards a random card from hand --------------------------------------------------------- function discardRandom() if not playerExists(playerColor) then return end -- error handling: hand is empty local hand = Player[playerColor].getHandObjects() if #hand == 0 then broadcastToAll("Cannot discard from empty hand!", "Red") else local searchPos = Player[playerColor].getHandTransform().position local discardPos = playmatAPI.getDiscardPosition(playmatAPI.getMatColorByPosition(searchPos)) if discardPos == nil then broadcastToAll("Couldn't retrieve discard position from playermat!", "Red") return end local num = math.random(1, #hand) hand[num].setPosition(discardPos) broadcastToAll(playerColor .. " randomly discarded card " .. num .. "/" .. #hand .. ".", "White") end end --------------------------------------------------------- -- helper functions --------------------------------------------------------- -- helper to search array function indexOf(array, value) for i, v in ipairs(array) do if v == value then return i end end end -- helper to check if player exists function playerExists(color) local COLORS = Player.getAvailableColors() return indexOf(COLORS, color) and true or false end end) __bundle_register("playermat/PlaymatApi", function(require, _LOADED, __bundle_register, __bundle_modules) do local PlaymatApi = { } local internal = { } local MAT_IDS = { White = "8b081b", Orange = "bd0ff4", Green = "383d8b", Red = "0840d5" } local CLUE_COUNTER_GUIDS = { White = "37be78", Orange = "1769ed", Green = "032300", Red = "d86b7c" } local CLUE_CLICKER_GUIDS = { White = "db85d6", Orange = "3f22e5", Green = "891403", Red = "4111de" } -- Returns the color of the by position requested playermat as string ---@param startPos Table Position of the search, table get's roughly cut into 4 quarters to assign a playermat PlaymatApi.getMatColorByPosition = function(startPos) if startPos.x < -42 then if startPos.z > 0 then return "White" else return "Orange" end else if startPos.z > 0 then return "Green" else return "Red" end end end -- Returns the draw deck of the requested playmat ---@param matColor String Color of the playermat PlaymatApi.getDrawDeck = function(matColor) local mat = getObjectFromGUID(MAT_IDS[matColor]) mat.call("getDrawDiscardDecks") return mat.getVar("drawDeck") end -- Returns the position of the discard pile of the requested playmat ---@param matColor String Color of the playermat PlaymatApi.getDiscardPosition = function(matColor) local mat = getObjectFromGUID(MAT_IDS[matColor]) return mat.call("returnGlobalDiscardPosition") end -- Sets the requested playermat's snap points to limit snapping to matching card types or not. If -- matchTypes is true, the main card slot snap points will only snap assets, while the -- investigator area point will only snap Investigators. If matchTypes is false, snap points will -- be reset to snap all cards. ---@param matchCardTypes Boolean. Whether snap points should only snap for the matching card -- types. ---@param matColor String for one of the active player colors - White, Orange, Green, Red. Also -- accepts "All" as a special value which will apply the setting to all four mats. PlaymatApi.setLimitSnapsByType = function(matchCardTypes, matColor) for _, mat in ipairs(internal.getMatForColor(matColor)) do mat.call("setLimitSnapsByType", matchCardTypes) end end -- Sets the requested playermat's draw 1 button to visible ---@param isDrawButtonVisible Boolean. Whether the draw 1 button should be visible or not ---@param matColor String for one of the active player colors - White, Orange, Green, Red. Also -- accepts "All" as a special value which will apply the setting to all four mats. PlaymatApi.showDrawButton = function(isDrawButtonVisible, matColor) for _, mat in ipairs(internal.getMatForColor(matColor)) do mat.call("showDrawButton", isDrawButtonVisible) end end -- Shows or hides the clickable clue counter for the requested playermat ---@param showCounter Boolean. Whether the clickable counter should be present or not ---@param matColor String for one of the active player colors - White, Orange, Green, Red. Also -- accepts "All" as a special value which will apply the setting to all four mats. PlaymatApi.clickableClues = function(showCounter, matColor) for _, mat in ipairs(internal.getMatForColor(matColor)) do mat.call("clickableClues", showCounter) end end -- Removes all clues (to the trash for tokens and counters set to 0) for the requested playermat ---@param matColor String for one of the active player colors - White, Orange, Green, Red. Also -- accepts "All" as a special value which will apply the setting to all four mats. PlaymatApi.removeClues = function(matColor) for _, mat in ipairs(internal.getMatForColor(matColor)) do mat.call("removeClues") end end -- Reports the clue count for the requested playermat ---@param useClickableCounters Boolean Controls which type of counter is getting checked PlaymatApi.getClueCount = function(useClickableCounters, matColor) local count = 0 for _, mat in ipairs(internal.getMatForColor(matColor)) do count = count + tonumber(mat.call("getClueCount", useClickableCounters)) end return count end -- Convenience function to look up a mat's object by color, or get all mats. ---@param matColor String for one of the active player colors - White, Orange, Green, Red. Also -- accepts "All" as a special value which will return all four mats. ---@return: Array of playermat objects. If a single mat is requested, will return a single-element -- array to simplify processing by consumers. internal.getMatForColor = function(matColor) local targetMatGuid = MAT_IDS[matColor] if targetMatGuid != nil then return { getObjectFromGUID(targetMatGuid) } end if matColor == "All" then return { getObjectFromGUID(MAT_IDS.White), getObjectFromGUID(MAT_IDS.Orange), getObjectFromGUID(MAT_IDS.Green), getObjectFromGUID(MAT_IDS.Red), } end end return PlaymatApi end end) return __bundle_require("__root")