-- 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("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 TTSPlayerInstance Player whose camera should be moved ---@param camera Variant 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("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 array 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 Table Global position ---@param rot Table 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) if filter then filter = 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 filter(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) __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) 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) 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) 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 TTSObject Hovered object BlessCurseManagerApi.addBlurseSealingMenu = function(playerColor, hoveredObject) getManager().call("addMenuOptions", { playerColor = playerColor, hoveredObject = hoveredObject }) end return BlessCurseManagerApi end end) __bundle_register("core/OptionPanelApi", function(require, _LOADED, __bundle_register, __bundle_modules) do local OptionPanelApi = {} -- loads saved options ---@param options Table New options table OptionPanelApi.loadSettings = function(options) return Global.call("loadSettings", options) end -- returns option panel table 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 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("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("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 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 -- 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 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 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/GUIDReferenceApi", function(require, _LOADED, __bundle_register, __bundle_modules) do local GUIDReferenceApi = {} local function getGuidHandler() return getObjectFromGUID("123456") end -- returns all matching objects as a table with references ---@param owner String Parent object for this search ---@param type String Type of object to search for 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 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 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) return __bundle_require("__root")