-- 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("core/GameKeyHandler") end) __bundle_register("chaosbag/BlessCurseManagerApi", function(require, _LOADED, __bundle_register, __bundle_modules) do local BlessCurseManagerApi = {} local guidReferenceApi = require("core/GUIDReferenceApi") local function getManager() return guidReferenceApi.getObjectByOwnerAndType("Mythos", "BlessCurseManager") end -- removes all taken tokens and resets the counts BlessCurseManagerApi.removeTakenTokensAndReset = function() local BlessCurseManager = getManager() Wait.time(function() BlessCurseManager.call("removeTakenTokens", "Bless") end, 0.05) Wait.time(function() BlessCurseManager.call("removeTakenTokens", "Curse") end, 0.10) Wait.time(function() BlessCurseManager.call("doReset", "White") end, 0.15) end -- updates the internal count (called by cards that seal bless/curse tokens) ---@param type string Type of chaos token ("Bless" or "Curse") ---@param guid string GUID of the token BlessCurseManagerApi.sealedToken = function(type, guid) getManager().call("sealedToken", { type = type, guid = guid }) end -- updates the internal count (called by cards that seal bless/curse tokens) ---@param type string Type of chaos token ("Bless" or "Curse") ---@param guid string GUID of the token BlessCurseManagerApi.releasedToken = function(type, guid) getManager().call("releasedToken", { type = type, guid = guid }) end -- updates the internal count (called by cards that seal bless/curse tokens) ---@param type string Type of chaos token ("Bless" or "Curse") ---@param guid string GUID of the token BlessCurseManagerApi.returnedToken = function(type, guid) getManager().call("returnedToken", { type = type, guid = guid }) end -- broadcasts the current status for bless/curse tokens ---@param playerColor string Color of the player to show the broadcast to BlessCurseManagerApi.broadcastStatus = function(playerColor) getManager().call("broadcastStatus", playerColor) end -- removes all bless / curse tokens from the chaos bag and play ---@param playerColor string Color of the player to show the broadcast to BlessCurseManagerApi.removeAll = function(playerColor) getManager().call("doRemove", playerColor) end -- adds bless / curse sealing to the hovered card ---@param playerColor string Color of the player to show the broadcast to ---@param hoveredObject tts__Object Hovered object BlessCurseManagerApi.addBlurseSealingMenu = function(playerColor, hoveredObject) getManager().call("addMenuOptions", { playerColor = playerColor, hoveredObject = hoveredObject }) end return BlessCurseManagerApi end end) __bundle_register("core/GUIDReferenceApi", function(require, _LOADED, __bundle_register, __bundle_modules) do local GUIDReferenceApi = {} local function getGuidHandler() return getObjectFromGUID("123456") end ---@param owner string Parent object for this search ---@param type string Type of object to search for ---@return any: Object reference to the matching object GUIDReferenceApi.getObjectByOwnerAndType = function(owner, type) return getGuidHandler().call("getObjectByOwnerAndType", { owner = owner, type = type }) end -- returns all matching objects as a table with references ---@param type string Type of object to search for ---@return table: List of object references to matching objects GUIDReferenceApi.getObjectsByType = function(type) return getGuidHandler().call("getObjectsByType", type) end -- returns all matching objects as a table with references ---@param owner string Parent object for this search ---@return table: List of object references to matching objects GUIDReferenceApi.getObjectsByOwner = function(owner) return getGuidHandler().call("getObjectsByOwner", owner) end -- sends new information to the reference handler to edit the main index ---@param owner string Parent of the object ---@param type string Type of the object ---@param guid string GUID of the object GUIDReferenceApi.editIndex = function(owner, type, guid) return getGuidHandler().call("editIndex", { owner = owner, type = type, guid = guid }) end return GUIDReferenceApi end end) __bundle_register("core/GameKeyHandler", function(require, _LOADED, __bundle_register, __bundle_modules) local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi") local guidReferenceApi = require("core/GUIDReferenceApi") local navigationOverlayApi = require("core/NavigationOverlayApi") local optionPanelApi = require("core/OptionPanelApi") local playmatApi = require("playermat/PlaymatApi") local searchLib = require("util/SearchLib") local victoryDisplayApi = require("core/VictoryDisplayApi") function onLoad() addHotkey("Add doom to agenda", addDoomToAgenda) addHotkey("Add Bless/Curse context menu", addBlurseSealingMenu) addHotkey("Discard object", discardObject) addHotkey("Discard top card", discardTopDeck) addHotkey("Display Bless/Curse status", showBlessCurseStatus) addHotkey("Move card to Victory Display", moveCardToVictoryDisplay) addHotkey("Remove a use", removeOneUse) addHotkey("Switch seat clockwise", switchSeatClockwise) addHotkey("Switch seat counter-clockwise", switchSeatCounterClockwise) addHotkey("Take clue from location", takeClueFromLocation) addHotkey("Take clue from location (White)", takeClueFromLocationWhite) addHotkey("Take clue from location (Orange)", takeClueFromLocationOrange) addHotkey("Take clue from location (Green)", takeClueFromLocationGreen) addHotkey("Take clue from location (Red)", takeClueFromLocationRed) addHotkey("Upkeep", triggerUpkeep) addHotkey("Upkeep (Multi-handed)", triggerUpkeepMultihanded) end -- triggers the "Upkeep" function of the calling player's playmat function triggerUpkeep(playerColor) if playerColor == "Black" then broadcastToColor("Triggering 'Upkeep (Multihanded)' instead", playerColor, "Yellow") triggerUpkeepMultihanded(playerColor) return end local matColor = playmatApi.getMatColor(playerColor) playmatApi.doUpkeepFromHotkey(matColor, playerColor) end -- triggers the "Upkeep" function of the calling player's playmat AND -- for all playmats that don't have a seated player, but a investigator card function triggerUpkeepMultihanded(playerColor) if playerColor ~= "Black" then triggerUpkeep(playerColor) end local colors = Player.getAvailableColors() for _, handColor in ipairs(colors) do local matColor = playmatApi.getMatColor(handColor) if playmatApi.returnInvestigatorId(matColor) ~= "00000" and Player[handColor].seated == false then playmatApi.doUpkeepFromHotkey(matColor, playerColor) end end end -- adds 1 doom to the agenda function addDoomToAgenda() local doomCounter = guidReferenceApi.getObjectByOwnerAndType("Mythos", "DoomCounter") doomCounter.call("addVal", 1) end -- discard the hovered object to the respective trashcan and discard tokens on it if it was a card function discardObject(playerColor, hoveredObject) -- only continue if an unlocked card, deck or tile was hovered if hoveredObject == nil or (hoveredObject.type ~= "Card" and hoveredObject.type ~= "Deck" and hoveredObject.type ~= "Tile") or hoveredObject.locked then broadcastToColor("Hover a token/tile or a card/deck and try again.", playerColor, "Yellow") return end -- warning for locations since these are usually not meant to be discarded if hoveredObject.hasTag("Location") then broadcastToAll("Watch out: A location was discarded.", "Yellow") end -- initialize list of objects to discard local discardTheseObjects = { hoveredObject } -- discard tokens / tiles on cards / decks if hoveredObject.type ~= "Tile" then for _, obj in ipairs(searchLib.onObject(hoveredObject, "isTileOrToken")) do table.insert(discardTheseObjects, obj) end end local discardForMatColor = getColorToDiscardFor(hoveredObject, playerColor) playmatApi.discardListOfObjects(discardForMatColor, discardTheseObjects) end -- discard the top card of hovered deck, calling discardObject function function discardTopDeck(playerColor, hoveredObject) -- only continue if an unlocked card or deck was hovered if hoveredObject == nil or (hoveredObject.type ~= "Card" and hoveredObject.type ~= "Deck") or hoveredObject.locked then broadcastToColor("Hover a deck/card and try again.", playerColor, "Yellow") return end if hoveredObject.type == "Deck" then takenCard = hoveredObject.takeObject({index = 0}) else takenCard = hoveredObject end Wait.frames(function() discardObject(playerColor, takenCard) end, 1) end -- helper function to get the player to trigger the discard function for function getColorToDiscardFor(hoveredObject, playerColor) local pos = hoveredObject.getPosition() local closestMatColor = playmatApi.getMatColorByPosition(pos) -- check if actually on the closest playmat local closestMat = guidReferenceApi.getObjectByOwnerAndType(closestMatColor, "Playermat") local bounds = closestMat.getBounds() -- define the area "near" the playmat local bufferAroundPlaymat = 2 local areaNearPlaymat = {} areaNearPlaymat.minX = bounds.center.x - bounds.size.x / 2 - bufferAroundPlaymat areaNearPlaymat.maxX = bounds.center.x + bounds.size.x / 2 + bufferAroundPlaymat areaNearPlaymat.minZ = bounds.center.z - bounds.size.z / 2 - bufferAroundPlaymat areaNearPlaymat.maxZ = bounds.center.z + bounds.size.z / 2 + bufferAroundPlaymat -- discard to closest mat if near it, use triggering playmat if not local discardForMatColor if inArea(pos, areaNearPlaymat) then return closestMatColor elseif pos.y > (Player[playerColor].getHandTransform().position.y - (Player[playerColor].getHandTransform().scale.y / 2)) then -- discard to closest mat if card is in a hand return closestMatColor else return playmatApi.getMatColor(playerColor) end end -- moves the hovered card to the victory display function moveCardToVictoryDisplay(_, hoveredObject) victoryDisplayApi.placeCard(hoveredObject) end -- removes a use from a card (or a token if hovered) function removeOneUse(playerColor, hoveredObject) -- only continue if an unlocked card or tile was hovered if hoveredObject == nil or (hoveredObject.type ~= "Card" and hoveredObject.type ~= "Tile") or hoveredObject.locked then broadcastToColor("Hover a token/tile or a card and try again.", playerColor, "Yellow") return end local targetObject = nil -- discard hovered token / tile if hoveredObject.type == "Tile" then targetObject = hoveredObject elseif hoveredObject.type == "Card" then -- grab the first use type from the metadata (or nil) local notes = JSON.decode(hoveredObject.getGMNotes()) or {} local usesData = notes.uses or {} local useInfo = usesData[1] or {} local searchForType = useInfo.type if searchForType then searchForType = searchForType:lower() end for _, obj in ipairs(searchLib.onObject(hoveredObject, "isTileOrToken")) do if not obj.locked and obj.memo ~= "resourceCounter" then -- check for matching object, otherwise use the first hit if obj.memo == searchForType then targetObject = obj break elseif not targetObject then targetObject = obj end end end end -- error handling if not targetObject then broadcastToColor("No tokens found!", playerColor, "Yellow") return end -- handling for stacked tokens if targetObject.getQuantity() > 1 then targetObject = targetObject.takeObject() end -- feedback message local tokenName = targetObject.getName() if tokenName == "" then if targetObject.memo ~= "" then -- name handling for clue / doom if targetObject.memo == "clueDoom" then if targetObject.is_face_down then tokenName = "Doom" else tokenName = "Clue" end else tokenName = titleCase(targetObject.memo) end else tokenName = "Unknown" end end local playerName = Player[playerColor].steam_name broadcastToAll(playerName .. " removed a token: " .. tokenName, playerColor) local discardForMatColor = getColorToDiscardFor(hoveredObject, playerColor) playmatApi.discardListOfObjects(discardForMatColor, { targetObject }) end -- switches the triggering player to the next seat (clockwise) function switchSeatClockwise(playerColor) switchSeat(playerColor, "clockwise") end -- switches the triggering player to the next seat (counter-clockwise) function switchSeatCounterClockwise(playerColor) switchSeat(playerColor, "counter-clockwise") end -- handles seat switching in the given direction function switchSeat(playerColor, direction) if playerColor == "Black" or playerColor == "Grey" then broadcastToColor("This hotkey is only available to seated players.", playerColor, "Orange") return end -- sort function for matcolors based on hand position (Green, White, Orange, Red) local function sortByHandPosition(color1, color2) local pos1 = Player[color1].getHandTransform().position local pos2 = Player[color2].getHandTransform().position return pos1.z > pos2.z end -- get used playermats local usedColors = playmatApi.getUsedMatColors() table.sort(usedColors, sortByHandPosition) -- get current seat index local index for i, color in ipairs(usedColors) do if color == playerColor then index = i break end end if not index then broadcastToColor("Couldn't detect investigator.", playerColor, "Orange") return end -- get next color index = index + ((direction == "clockwise") and -1 or 1) if index == 0 then index = #usedColors elseif index > #usedColors then index = 1 end -- swap color navigationOverlayApi.loadCamera(Player[playerColor], usedColors[index]) end function takeClueFromLocationWhite(_, hoveredObject) takeClueFromLocation("White", hoveredObject) end function takeClueFromLocationOrange(_, hoveredObject) takeClueFromLocation("Orange", hoveredObject) end function takeClueFromLocationGreen(_, hoveredObject) takeClueFromLocation("Green", hoveredObject) end function takeClueFromLocationRed(_, hoveredObject) takeClueFromLocation("Red", hoveredObject) end -- takes a clue from a location, player needs to hover the clue directly or the location function takeClueFromLocation(playerColor, hoveredObject) local cardName, clue if hoveredObject == nil then broadcastToColor("Hover a clue or card with clues and try again.", playerColor, "Yellow") return elseif hoveredObject.type == "Card" then cardName = hoveredObject.getName() local searchResult = searchLib.onObject(hoveredObject, "isClue") if #searchResult == 0 then broadcastToColor("This card does not have any clues on it.", playerColor, "Yellow") return else clue = searchResult[1] end elseif hoveredObject.memo == "clueDoom" then if hoveredObject.is_face_down then broadcastToColor("This is a doom token and not a clue.", playerColor, "Yellow") return end clue = hoveredObject local searchResult = searchLib.belowPosition(clue.getPosition(), "isCard") if #searchResult ~= 0 then cardName = searchResult[1].getName() end elseif hoveredObject.type == "Infinite" and hoveredObject.getName() == "Clue tokens" then clue = hoveredObject.takeObject() cardName = "token pool" else broadcastToColor("Hover a clue or card with clues and try again.", playerColor, "Yellow") return end local clickableClues = optionPanelApi.getOptions()["useClueClickers"] local playerName = Player[playerColor].steam_name local matColor = playmatApi.getMatColor(playerColor) local pos = nil if clickableClues then pos = {x = 0.49, y = 2.66, z = 0.00} playmatApi.updateCounter(matColor, "ClickableClueCounter", _, 1) else pos = playmatApi.transformLocalPosition({x = -1.12, y = 0.05, z = 0.7}, matColor) end local rot = playmatApi.returnRotation(matColor) -- check if found clue is a stack or single token if clue.getQuantity() > 1 then clue.takeObject({position = pos, rotation = rot}) else clue.setPositionSmooth(pos) clue.setRotation(rot) end if cardName then broadcastToAll(playerName .. " took one clue from " .. cardName .. ".", "White") else broadcastToAll(playerName .. " took one clue.", "White") end victoryDisplayApi.update() end -- broadcasts the bless/curse status to the calling player function showBlessCurseStatus(playerColor) blessCurseManagerApi.broadcastStatus(playerColor) end -- adds Wendy's menu to the hovered card function addBlurseSealingMenu(playerColor, hoveredObject) blessCurseManagerApi.addBlurseSealingMenu(playerColor, hoveredObject) end -- Simple method to check if the given point is in a specified area ---@param point tts__Vector Point to check, only x and z values are relevant ---@param bounds table Defined area to see if the point is within function inArea(point, bounds) return (point.x > bounds.minX and point.x < bounds.maxX and point.z > bounds.minZ and point.z < bounds.maxZ) end -- capitalizes the first letter function titleCase(str) local first = str:sub(1, 1) local rest = str:sub(2) return first:upper() .. rest:lower() end end) __bundle_register("core/NavigationOverlayApi", function(require, _LOADED, __bundle_register, __bundle_modules) do local NavigationOverlayApi = {} local guidReferenceApi = require("core/GUIDReferenceApi") local function getNOHandler() return guidReferenceApi.getObjectByOwnerAndType("Mythos", "NavigationOverlayHandler") end -- copies the visibility for the Navigation overlay ---@param startColor string Color of the player to copy from ---@param targetColor string Color of the targeted player NavigationOverlayApi.copyVisibility = function(startColor, targetColor) getNOHandler().call("copyVisibility", { startColor = startColor, targetColor = targetColor }) end -- changes the Navigation Overlay view ("Full View" --> "Play Areas" --> "Closed" etc.) ---@param playerColor string Color of the player to update the visibility for NavigationOverlayApi.cycleVisibility = function(playerColor) getNOHandler().call("cycleVisibility", playerColor) end -- loads the specified camera for a player ---@param player tts__Player Player whose camera should be moved ---@param camera number|string If number: Index of the camera view to load | If string: Color of the playermat to swap to NavigationOverlayApi.loadCamera = function(player, camera) getNOHandler().call("loadCameraFromApi", { player = player, camera = camera }) end return NavigationOverlayApi end end) __bundle_register("core/OptionPanelApi", function(require, _LOADED, __bundle_register, __bundle_modules) do local OptionPanelApi = {} -- loads saved options ---@param options table Set a new state for the option table OptionPanelApi.loadSettings = function(options) return Global.call("loadSettings", options) end ---@return any: Table of option panel state OptionPanelApi.getOptions = function() return Global.getTable("optionPanel") end return OptionPanelApi end end) __bundle_register("core/VictoryDisplayApi", function(require, _LOADED, __bundle_register, __bundle_modules) do local VictoryDisplayApi = {} local guidReferenceApi = require("core/GUIDReferenceApi") local function getVictoryDisplay() return guidReferenceApi.getObjectByOwnerAndType("Mythos", "VictoryDisplay") end -- triggers an update of the victory count ---@param delay? number Delay in seconds after which the update call is executed VictoryDisplayApi.update = function(delay) getVictoryDisplay().call("startUpdate", delay) end -- moves a card to the victory display (in the first empty spot) ---@param object tts__Object Object that should be checked and potentially moved VictoryDisplayApi.placeCard = function(object) if object ~= nil and object.tag == "Card" then getVictoryDisplay().call("placeCard", object) end end return VictoryDisplayApi end end) __bundle_register("playermat/PlaymatApi", function(require, _LOADED, __bundle_register, __bundle_modules) do local PlaymatApi = {} local guidReferenceApi = require("core/GUIDReferenceApi") local searchLib = require("util/SearchLib") -- Convenience function to look up a mat's object by color, or get all mats. ---@param matColor string Color of the playmat - White, Orange, Green, Red or All ---@return table: Single-element if only single playmat is requested local function getMatForColor(matColor) if matColor == "All" then return guidReferenceApi.getObjectsByType("Playermat") else return { matColor = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat") } end end -- Returns the color of the closest playmat ---@param startPos table Starting position to get the closest mat from PlaymatApi.getMatColorByPosition = function(startPos) local result, smallestDistance for matColor, mat in pairs(getMatForColor("All")) do local distance = Vector.between(startPos, mat.getPosition()):magnitude() if smallestDistance == nil or distance < smallestDistance then smallestDistance = distance result = matColor end end return result end -- Returns the color of the player's hand that is seated next to the playmat ---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All") PlaymatApi.getPlayerColor = function(matColor) for _, mat in pairs(getMatForColor(matColor)) do return mat.getVar("playerColor") end end -- Returns the color of the playmat that owns the playercolor's hand ---@param handColor string Color of the playmat PlaymatApi.getMatColor = function(handColor) for matColor, mat in pairs(getMatForColor("All")) do local playerColor = mat.getVar("playerColor") if playerColor == handColor then return matColor end end end -- Returns if there is the card "Dream-Enhancing Serum" on the requested playmat ---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All") PlaymatApi.isDES = function(matColor) for _, mat in pairs(getMatForColor(matColor)) do return mat.getVar("isDES") end end -- Performs a search of the deck area of the requested playmat and returns the result as table ---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All") PlaymatApi.getDeckAreaObjects = function(matColor) for _, mat in pairs(getMatForColor(matColor)) do return mat.call("getDeckAreaObjects") end end -- Flips the top card of the deck (useful after deck manipulation for Norman Withers) ---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All") PlaymatApi.flipTopCardFromDeck = function(matColor) for _, mat in pairs(getMatForColor(matColor)) do return mat.call("flipTopCardFromDeck") end end -- Returns the position of the discard pile of the requested playmat ---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All") PlaymatApi.getDiscardPosition = function(matColor) for _, mat in pairs(getMatForColor(matColor)) do return mat.call("returnGlobalDiscardPosition") end end -- Transforms a local position into a global position ---@param localPos table Local position to be transformed ---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All") PlaymatApi.transformLocalPosition = function(localPos, matColor) for _, mat in pairs(getMatForColor(matColor)) do return mat.positionToWorld(localPos) end end -- Returns the rotation of the requested playmat ---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All") PlaymatApi.returnRotation = function(matColor) for _, mat in pairs(getMatForColor(matColor)) do return mat.getRotation() end end -- Returns a table with spawn data (position and rotation) for a helper object ---@param matColor string Color of the playmat - White, Orange, Green, Red or All ---@param helperName string Name of the helper object PlaymatApi.getHelperSpawnData = function(matColor, helperName) local resultTable = {} local localPositionTable = { ["Hand Helper"] = {0.05, 0, -1.182}, ["Search Assistant"] = {-0.3, 0, -1.182} } for color, mat in pairs(getMatForColor(matColor)) do resultTable[color] = { position = mat.positionToWorld(localPositionTable[helperName]), rotation = mat.getRotation() } end return resultTable end -- Triggers the Upkeep for the requested playmat ---@param matColor string Color of the playmat - White, Orange, Green, Red or All ---@param playerColor string Color of the calling player (for messages) PlaymatApi.doUpkeepFromHotkey = function(matColor, playerColor) for _, mat in pairs(getMatForColor(matColor)) do mat.call("doUpkeepFromHotkey", playerColor) end end -- Handles discarding for the requested playmat for the provided list of objects ---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All") ---@param objList table List of objects to discard PlaymatApi.discardListOfObjects = function(matColor, objList) for _, mat in pairs(getMatForColor(matColor)) do mat.call("discardListOfObjects", objList) end end -- Returns the active investigator id ---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All") PlaymatApi.returnInvestigatorId = function(matColor) for _, mat in pairs(getMatForColor(matColor)) do return mat.getVar("activeInvestigatorId") end end -- Sets the requested playmat'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 Color of the playmat - White, Orange, Green, Red or All PlaymatApi.setLimitSnapsByType = function(matchCardTypes, matColor) for _, mat in pairs(getMatForColor(matColor)) do mat.call("setLimitSnapsByType", matchCardTypes) end end -- Sets the requested playmat's draw 1 button to visible ---@param isDrawButtonVisible boolean Whether the draw 1 button should be visible or not ---@param matColor string Color of the playmat - White, Orange, Green, Red or All PlaymatApi.showDrawButton = function(isDrawButtonVisible, matColor) for _, mat in pairs(getMatForColor(matColor)) do mat.call("showDrawButton", isDrawButtonVisible) end end -- Shows or hides the clickable clue counter for the requested playmat ---@param showCounter boolean Whether the clickable counter should be present or not ---@param matColor string Color of the playmat - White, Orange, Green, Red or All PlaymatApi.clickableClues = function(showCounter, matColor) for _, mat in pairs(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 playmat ---@param matColor string Color of the playmat - White, Orange, Green, Red or All PlaymatApi.removeClues = function(matColor) for _, mat in pairs(getMatForColor(matColor)) do mat.call("removeClues") end end -- Reports the clue count for the requested playmat ---@param useClickableCounters boolean Controls which type of counter is getting checked PlaymatApi.getClueCount = function(useClickableCounters, matColor) local count = 0 for _, mat in pairs(getMatForColor(matColor)) do count = count + mat.call("getClueCount", useClickableCounters) end return count end -- updates the specified owned counter ---@param matColor string Color of the playmat - White, Orange, Green, Red or All ---@param type string Counter to target ---@param newValue number Value to set the counter to ---@param modifier number If newValue is not provided, the existing value will be adjusted by this modifier PlaymatApi.updateCounter = function(matColor, type, newValue, modifier) for _, mat in pairs(getMatForColor(matColor)) do mat.call("updateCounter", { type = type, newValue = newValue, modifier = modifier }) end end -- triggers the draw function for the specified playmat ---@param matColor string Color of the playmat - White, Orange, Green, Red or All ---@param number number Amount of cards to draw PlaymatApi.drawCardsWithReshuffle = function(matColor, number) for _, mat in pairs(getMatForColor(matColor)) do mat.call("drawCardsWithReshuffle", number) end end -- returns the resource counter amount ---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All") ---@param type string Counter to target PlaymatApi.getCounterValue = function(matColor, type) for _, mat in pairs(getMatForColor(matColor)) do return mat.call("getCounterValue", type) end end -- returns a list of mat colors that have an investigator placed PlaymatApi.getUsedMatColors = function() local localInvestigatorPosition = { x = -1.17, y = 1, z = -0.01 } local usedColors = {} for matColor, mat in pairs(getMatForColor("All")) do local searchPos = mat.positionToWorld(localInvestigatorPosition) local searchResult = searchLib.atPosition(searchPos, "isCardOrDeck") if #searchResult > 0 then table.insert(usedColors, matColor) end end return usedColors end -- resets the specified skill tracker to "1, 1, 1, 1" ---@param matColor string Color of the playmat - White, Orange, Green, Red or All PlaymatApi.resetSkillTracker = function(matColor) for _, mat in pairs(getMatForColor(matColor)) do mat.call("resetSkillTracker") end end -- finds all objects on the playmat and associated set aside zone and returns a table ---@param matColor string Color of the playmat - White, Orange, Green, Red or All ---@param filter string Name of the filte function (see util/SearchLib) PlaymatApi.searchAroundPlaymat = function(matColor, filter) local objList = {} for _, mat in pairs(getMatForColor(matColor)) do for _, obj in ipairs(mat.call("searchAroundSelf", filter)) do table.insert(objList, obj) end end return objList end -- Discard a non-hidden card from the corresponding player's hand ---@param matColor string Color of the playmat - White, Orange, Green, Red or All PlaymatApi.doDiscardOne = function(matColor) for _, mat in pairs(getMatForColor(matColor)) do mat.call("doDiscardOne") end end -- Triggers the metadata sync for all playmats PlaymatApi.syncAllCustomizableCards = function() for _, mat in pairs(getMatForColor("All")) do mat.call("syncAllCustomizableCards") end end return PlaymatApi end end) __bundle_register("util/SearchLib", function(require, _LOADED, __bundle_register, __bundle_modules) do local SearchLib = {} local filterFunctions = { isActionToken = function(x) return x.getDescription() == "Action Token" end, isCard = function(x) return x.type == "Card" end, isDeck = function(x) return x.type == "Deck" end, isCardOrDeck = function(x) return x.type == "Card" or x.type == "Deck" end, isClue = function(x) return x.memo == "clueDoom" and x.is_face_down == false end, isTileOrToken = function(x) return x.type == "Tile" end } -- performs the actual search and returns a filtered list of object references ---@param pos tts__Vector Global position ---@param rot? tts__Vector Global rotation ---@param size table Size ---@param filter? string Name of the filter function ---@param direction? table Direction (positive is up) ---@param maxDistance? number Distance for the cast local function returnSearchResult(pos, rot, size, filter, direction, maxDistance) local filterFunc if filter then filterFunc = filterFunctions[filter] end local searchResult = Physics.cast({ origin = pos, direction = direction or { 0, 1, 0 }, orientation = rot or { 0, 0, 0 }, type = 3, size = size, max_distance = maxDistance or 0 }) -- filtering the result local objList = {} for _, v in ipairs(searchResult) do if not filter or filterFunc(v.hit_object) then table.insert(objList, v.hit_object) end end return objList end -- searches the specified area SearchLib.inArea = function(pos, rot, size, filter) return returnSearchResult(pos, rot, size, filter) end -- searches the area on an object SearchLib.onObject = function(obj, filter) pos = obj.getPosition() size = obj.getBounds().size:setAt("y", 1) return returnSearchResult(pos, _, size, filter) end -- searches the specified position (a single point) SearchLib.atPosition = function(pos, filter) size = { 0.1, 2, 0.1 } return returnSearchResult(pos, _, size, filter) end -- searches below the specified position (downwards until y = 0) SearchLib.belowPosition = function(pos, filter) direction = { 0, -1, 0 } maxDistance = pos.y return returnSearchResult(pos, _, size, filter, direction, maxDistance) end return SearchLib end end) return __bundle_require("__root")