Merge branch 'helpers' into playermats

This commit is contained in:
Chr1Z93 2024-06-26 12:54:03 +02:00
commit b668146ba4
19 changed files with 344 additions and 362 deletions

View File

@ -33,7 +33,7 @@
"IgnoreFoW": false, "IgnoreFoW": false,
"LayoutGroupSortIndex": 0, "LayoutGroupSortIndex": 0,
"Locked": false, "Locked": false,
"LuaScript": "require(\"playercards/cards/TheChthonianStone3\")", "LuaScript": "require(\"playercards/cards/TheChthonianStone\")",
"LuaScriptState": "", "LuaScriptState": "",
"MeasureMovement": false, "MeasureMovement": false,
"Name": "Card", "Name": "Card",

View File

@ -1 +1 @@
{"acknowledgedUpgradeVersions":[],"chaosTokensGUID":[],"optionPanel":{"cardLanguage":"en","changePlayAreaImage":false,"playAreaConnectionColor":{"a":1,"b":0.4,"g":0.4,"r":0.4},"playAreaConnections":true,"playAreaSnapTags":true,"showAttachmentHelper":false,"showCleanUpHelper":false,"showCYOA":false,"showDisplacementTool":false,"showDrawButton":false,"showHandHelper":false,"showSearchAssistant":false,"showTitleSplash":true,"useClassTexture":true,"useClueClickers":false,"useResourceCounters":"disabled","useSnapTags":true}} {"acknowledgedUpgradeVersions":[],"chaosTokensGUID":[],"optionPanel":{"cardLanguage":"en","changePlayAreaImage":false,"enableCardHelpers":false,"playAreaConnectionColor":{"a":1,"b":0.4,"g":0.4,"r":0.4},"playAreaConnections":true,"playAreaSnapTags":true,"showAttachmentHelper":false,"showCleanUpHelper":false,"showCYOA":false,"showDisplacementTool":false,"showDrawButton":false,"showHandHelper":false,"showSearchAssistant":false,"showTitleSplash":true,"useClassTexture":true,"useClueClickers":false,"useResourceCounters":"disabled","useSnapTags":true}}

View File

@ -61,17 +61,18 @@ do
-- are drawn or replaced a TTS bug can cause those tokens to vanish. Any functions which change the -- are drawn or replaced a TTS bug can cause those tokens to vanish. Any functions which change the
-- contents of the bag should check this method before doing so. -- contents of the bag should check this method before doing so.
-- This method will broadcast a message to all players if the bag is being searched. -- This method will broadcast a message to all players if the bag is being searched.
---@return any canTouch True if the bag is manipulated, false if it should be blocked. ---@return any: True if the bag is manipulated, false if it should be blocked.
ChaosBagApi.canTouchChaosTokens = function() ChaosBagApi.canTouchChaosTokens = function()
return Global.call("canTouchChaosTokens") return Global.call("canTouchChaosTokens")
end end
-- called by playermats (by the "Draw chaos token" button) -- draws a chaos token to a playermat
---@param mat tts__Object Playermat that triggered this ---@param mat tts__Object Playermat that triggered this
---@param drawAdditional boolean Controls whether additional tokens should be drawn ---@param drawAdditional boolean Controls whether additional tokens should be drawn
---@param tokenType? string Name of token (e.g. "Bless") to be drawn from the bag ---@param tokenType? string Name of token (e.g. "Bless") to be drawn from the bag
---@param guidToBeResolved? string GUID of the sealed token to be resolved instead of drawing a token from the bag ---@param guidToBeResolved? string GUID of the sealed token to be resolved instead of drawing a token from the bag
---@param takeParameters? table Position and rotation of the location where the new token should be drawn to, usually to replace a returned token ---@param takeParameters? table Position and rotation of the location where the new token should be drawn to, usually to replace a returned token
---@return tts__Object: Object reference to the token that was drawn
ChaosBagApi.drawChaosToken = function(mat, drawAdditional, tokenType, guidToBeResolved, takeParameters) ChaosBagApi.drawChaosToken = function(mat, drawAdditional, tokenType, guidToBeResolved, takeParameters)
return Global.call("drawChaosToken", { return Global.call("drawChaosToken", {
mat = mat, mat = mat,

View File

@ -155,6 +155,7 @@ function onLoad(savedData)
end, 1) end, 1)
end end
-- provides a random seed (from 1 to 999) to be used by "linked" objects like the action tokens
function getRandomSeed() function getRandomSeed()
return math.random(999) return math.random(999)
end end
@ -255,6 +256,7 @@ function findChaosBag()
printToAll("Chaos bag couldn't be found.", "Red") printToAll("Chaos bag couldn't be found.", "Red")
end end
-- returns all chaos tokens to the bag
function returnChaosTokens() function returnChaosTokens()
local chaosBag = findChaosBag() local chaosBag = findChaosBag()
for _, token in pairs(chaosTokens) do for _, token in pairs(chaosTokens) do
@ -267,15 +269,15 @@ end
-- returns a single chaos token to the bag and calls respective functions -- returns a single chaos token to the bag and calls respective functions
function returnChaosTokenToBag(token) function returnChaosTokenToBag(token)
local name = token.getName() local name = token.getName()
local guid = token.getGUID()
local chaosBag = findChaosBag() local chaosBag = findChaosBag()
chaosBag.putObject(token) chaosBag.putObject(token)
tokenArrangerApi.layout() tokenArrangerApi.layout()
if name == "Bless" or name == "Curse" then if name == "Bless" or name == "Curse" then
blessCurseManagerApi.releasedToken(name, guid, true) blessCurseManagerApi.releasedToken(name, token.getGUID(), true)
end end
end end
-- returns the index of a token in the chaosTokens table
function getTokenIndex(token) function getTokenIndex(token)
for i, obj in ipairs(chaosTokens) do for i, obj in ipairs(chaosTokens) do
if obj == token then if obj == token then
@ -284,12 +286,10 @@ function getTokenIndex(token)
end end
end end
function activeRedrawEffect(originParams) -- starts a redraw effect and displays buttons for a choice if needed
redrawData = originParams function activeRedrawEffect(params)
makeButtonsToRedraw() redrawData = params
end
function makeButtonsToRedraw()
if isTokenXMLActive == true then if isTokenXMLActive == true then
broadcastToAll("Clear already active buttons first, then try again", "Red") broadcastToAll("Clear already active buttons first, then try again", "Red")
return return
@ -300,38 +300,38 @@ function makeButtonsToRedraw()
return return
end end
local matchingTokensInPlay = {}
-- nil handling -- nil handling
redrawData.VALID_TOKENS = redrawData.VALID_TOKENS or {} redrawData.VALID_TOKENS = redrawData.VALID_TOKENS or {}
redrawData.INVALID_TOKENS = redrawData.INVALID_TOKENS or {} redrawData.INVALID_TOKENS = redrawData.INVALID_TOKENS or {}
-- determine if only some tokens are able to be returned to the bag -- determine if only some tokens are able to be returned to the bag
local matchingTokensInPlay = {}
for _, token in ipairs(chaosTokens) do for _, token in ipairs(chaosTokens) do
local tokenName = getReadableTokenName(token.getName()) local tokenName = getReadableTokenName(token.getName())
-- allow valid tokens or not invalid tokens, also allow any token if both lists empty -- allow valid tokens or not invalid tokens, also allow any token if both lists empty
if (redrawData.VALID_TOKENS[tokenName] ~= nil and isTableEmpty(redrawData.INVALID_TOKENS)) or (isTableEmpty(redrawData.VALID_TOKENS) and not redrawData.INVALID_TOKENS[tokenName]) or if (redrawData.VALID_TOKENS[tokenName] ~= nil and isTableEmpty(redrawData.INVALID_TOKENS)) or
(isTableEmpty(redrawData.VALID_TOKENS) and not redrawData.INVALID_TOKENS[tokenName]) or
(isTableEmpty(redrawData.VALID_TOKENS) and isTableEmpty(redrawData.INVALID_TOKENS)) then (isTableEmpty(redrawData.VALID_TOKENS) and isTableEmpty(redrawData.INVALID_TOKENS)) then
table.insert(matchingTokensInPlay, token) table.insert(matchingTokensInPlay, token)
end end
end end
-- proceed according to number of matching tokens
if #matchingTokensInPlay == 0 then if #matchingTokensInPlay == 0 then
broadcastToAll("No eligible token found in play area", "Red") broadcastToAll("No eligible token found in play area", "Red")
return elseif #matchingTokensInPlay == 1 then
end returnAndRedraw(_, matchingTokensInPlay[1].getGUID())
else
if #matchingTokensInPlay > 1 then -- draw XML to allow choosing the token to return to bag
isTokenXMLActive = true
for _, token in ipairs(matchingTokensInPlay) do for _, token in ipairs(matchingTokensInPlay) do
-- draw XML to return token to bag
token.UI.setXmlTable({ token.UI.setXmlTable({
{ {
tag = "VerticalLayout", tag = "VerticalLayout",
attributes = { attributes = {
height = 275, height = 275,
width = 275, width = 275,
spacing = 0,
padding = "0 0 20 25", padding = "0 0 20 25",
scale = "0.4 0.4 1", scale = "0.4 0.4 1",
rotation = "0 0 180", rotation = "0 0 180",
@ -362,43 +362,51 @@ function makeButtonsToRedraw()
} }
}) })
end end
isTokenXMLActive = true
-- no need to make buttons if there is only one eligible token to return and redraw
else
returnAndRedraw(_, matchingTokensInPlay[1].getGUID())
end end
end end
-- returns a chaos token to the chaos bag and redraws another, always called by an XML button through makeButtonsToRedraw() above -- returns a chaos token to the chaos bag and redraws another
function returnAndRedraw(_, tokenGUID) function returnAndRedraw(_, tokenGUID)
local takeParameters = {}
local returnedToken = getObjectFromGUID(tokenGUID) local returnedToken = getObjectFromGUID(tokenGUID)
local tokenName = returnedToken.getName()
local indexOfReturnedToken = getTokenIndex(returnedToken)
local matColor = playermatApi.getMatColorByPosition(returnedToken.getPosition()) local matColor = playermatApi.getMatColorByPosition(returnedToken.getPosition())
local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat") local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")
isTokenXMLActive = false local takeParameters = {
trackChaosToken(returnedToken.getName(), mat.getGUID(), true) position = returnedToken.getPosition(),
local indexOfReturnedToken = getTokenIndex(returnedToken) rotation = returnedToken.getRotation()
takeParameters.position = returnedToken.getPosition() }
if #chaosTokens > indexOfReturnedToken then if #chaosTokens > indexOfReturnedToken then
takeParameters.rotation = mat.getRotation() + Vector(0, 0, -8) takeParameters.rotation = takeParameters.rotation + Vector(0, 0, -8)
else
takeParameters.rotation = returnedToken.getRotation()
end end
-- perform the actual token replacing
trackChaosToken(tokenName, mat.getGUID(), true)
returnChaosTokenToBag(returnedToken) returnChaosTokenToBag(returnedToken)
local params = { mat = mat, drawAdditional = true, takeParameters = takeParameters }
if redrawData.redrawnTokenType ~= "random" then
params.tokenType = redrawData.redrawnTokenType
end
chaosTokens[indexOfReturnedToken] = drawChaosToken(params)
if redrawData.triggeringCard == "FalseCovenant" then chaosTokens[indexOfReturnedToken] = drawChaosToken({
blessCurseManagerApi.removeToken("Curse") mat = mat,
drawAdditional = true,
tokenType = redrawData.DRAW_SPECIFIC_TOKEN, -- currently only used for Nkosi Mabati
takeParameters = takeParameters
})
-- remove these tokens from the bag
if redrawData.RETURN_TO_POOL then
-- let the bless/curse manager handle these
if tokenName == "Bless" or tokenName == "Curse" then
blessCurseManagerApi.removeToken(tokenName)
else
local invertedTable = createChaosTokenNameLookupTable()
removeChaosToken(invertedTable[tokenName])
end
end end
-- remove XML from tokens in play -- remove XML from tokens in play
for _, token in ipairs(getChaosTokensinPlay()) do isTokenXMLActive = false
for _, token in ipairs(chaosTokens) do
token.UI.setXml("") token.UI.setXml("")
end end
@ -440,7 +448,6 @@ end
function drawChaosToken(params) function drawChaosToken(params)
if not canTouchChaosTokens() then return end if not canTouchChaosTokens() then return end
local tokenOffset = { -1.55, 0.25, -0.58 }
local matGUID = params.mat.getGUID() local matGUID = params.mat.getGUID()
-- return token(s) on other playermat first -- return token(s) on other playermat first
@ -458,30 +465,23 @@ function drawChaosToken(params)
if #chaosBag.getObjects() == 0 then return end if #chaosBag.getObjects() == 0 then return end
chaosBag.shuffle() chaosBag.shuffle()
local takeParameters = {}
-- add the token to the list, compute new position based on list length -- add the token to the list, compute new position based on list length
if params.takeParameters then local tokenOffset = Vector(-1.55 + 0.17 * #chaosTokens, 0.25, -0.58)
takeParameters.position = params.takeParameters.position local takeParameters = params.takeParameters or {}
takeParameters.rotation = params.takeParameters.rotation takeParameters.position = takeParameters.position or params.mat.positionToWorld(tokenOffset)
else takeParameters.rotation = takeParameters.rotation or params.mat.getRotation()
tokenOffset[1] = tokenOffset[1] + (0.17 * #chaosTokens)
takeParameters.position = params.mat.positionToWorld(tokenOffset)
takeParameters.rotation = params.mat.getRotation()
end
local token local token
if params.guidToBeResolved then if params.guidToBeResolved then
-- resolve a sealed token from a card -- resolve a sealed token from a card
token = getObjectFromGUID(params.guidToBeResolved) token = getObjectFromGUID(params.guidToBeResolved)
token.setPositionSmooth(takeParameters.position) token.setPositionSmooth(takeParameters.position)
local guid = token.getGUID()
local tokenType = token.getName()
if tokenType == "Bless" or tokenType == "Curse" then
blessCurseManagerApi.releasedToken(tokenType, guid)
end
tokenArrangerApi.layout() tokenArrangerApi.layout()
local tokenName = token.getName()
if tokenName == "Bless" or tokenName == "Curse" then
blessCurseManagerApi.releasedToken(tokenName, token.getGUID())
end
else else
-- take a token from the bag, either specified or random -- take a token from the bag, either specified or random
if params.tokenType then if params.tokenType then
@ -501,12 +501,10 @@ function drawChaosToken(params)
token.setDescription(specificData.description or "") token.setDescription(specificData.description or "")
trackChaosToken(name, matGUID) trackChaosToken(name, matGUID)
if params.takeParameters then if not params.takeParameters then
return token
else
table.insert(chaosTokens, token) table.insert(chaosTokens, token)
return token
end end
return token
else else
returnChaosTokens() returnChaosTokens()
end end
@ -533,8 +531,7 @@ function trackChaosToken(tokenName, matGUID, subtract)
-- increase stats by 1 (or decrease if token is returned) -- increase stats by 1 (or decrease if token is returned)
local modifier = (subtract and -1 or 1) local modifier = (subtract and -1 or 1)
tokenName = getReadableTokenName(tokenName)
local tokenName = getReadableTokenName(tokenName)
tokenDrawingStats["Overall"][tokenName] = (tokenDrawingStats["Overall"][tokenName] or 0) + modifier tokenDrawingStats["Overall"][tokenName] = (tokenDrawingStats["Overall"][tokenName] or 0) + modifier
tokenDrawingStats[matGUID][tokenName] = (tokenDrawingStats[matGUID][tokenName] or 0) + modifier tokenDrawingStats[matGUID][tokenName] = (tokenDrawingStats[matGUID][tokenName] or 0) + modifier
end end
@ -555,7 +552,6 @@ function handleStatTrackerClick(_, _, isRightClick)
playerColor = "White" playerColor = "White"
playerName = "Overall" playerName = "Overall"
else else
-- get mat color
local matColor = playermatApi.getMatColorByPosition(getObjectFromGUID(key).getPosition()) local matColor = playermatApi.getMatColorByPosition(getObjectFromGUID(key).getPosition())
playerColor = playermatApi.getPlayerColor(matColor) playerColor = playermatApi.getPlayerColor(matColor)
playerName = Player[playerColor].steam_name or playerColor playerName = Player[playerColor].steam_name or playerColor
@ -750,7 +746,7 @@ function getChaosTokensinPlay()
return chaosTokens return chaosTokens
end end
-- returns a Table List of chaos token ids in the current chaos bag -- returns a table of chaos token ids in the current chaos bag
---@api ChaosBag / ChaosBagApi ---@api ChaosBag / ChaosBagApi
function getChaosBagState() function getChaosBagState()
local tokens = {} local tokens = {}
@ -1491,9 +1487,10 @@ function playermatRemovalSelected(player, selectedIndex, id)
if mat then if mat then
-- confirmation dialog about deletion -- confirmation dialog about deletion
player.pingTable(mat.getPosition()) player.pingTable(mat.getPosition())
player.showConfirmDialog( player.showConfirmDialog("Do you really want to remove " .. matColor .. "'s playermat and related objects? This can't be reversed.",
"Do you really want to remove " .. matColor .. "'s playermat and related objects? This can't be reversed.", function()
function() removePlayermat(matColor) end) removePlayermat(matColor)
end)
else else
-- info dialog that it is already deleted -- info dialog that it is already deleted
player.showInfoDialog(matColor .. "'s playermat has already been removed.") player.showInfoDialog(matColor .. "'s playermat has already been removed.")
@ -1568,6 +1565,9 @@ function applyOptionPanelChange(id, state)
local counter = guidReferenceApi.getObjectByOwnerAndType("Mythos", "MasterClueCounter") local counter = guidReferenceApi.getObjectByOwnerAndType("Mythos", "MasterClueCounter")
counter.setVar("useClickableCounters", state) counter.setVar("useClickableCounters", state)
elseif id == "enableCardHelpers" then
toggleCardHelpers(state)
-- option: Play area connection drawing -- option: Play area connection drawing
elseif id == "playAreaConnections" then elseif id == "playAreaConnections" then
playAreaApi.setConnectionDrawState(state) playAreaApi.setConnectionDrawState(state)
@ -1692,6 +1692,7 @@ function onClick_defaultSettings()
optionPanel = { optionPanel = {
cardLanguage = "en", cardLanguage = "en",
changePlayAreaImage = false, changePlayAreaImage = false,
enableCardHelpers = false,
playAreaConnectionColor = { a = 1, b = 0.4, g = 0.4, r = 0.4 }, playAreaConnectionColor = { a = 1, b = 0.4, g = 0.4, r = 0.4 },
playAreaConnections = true, playAreaConnections = true,
playAreaSnapTags = true, playAreaSnapTags = true,
@ -1741,6 +1742,13 @@ function titleSplash(scenarioName)
end end
end end
-- instructs all card helpers to update their visibility
function toggleCardHelpers(state)
for _, obj in ipairs(getObjectsWithTag("CardWithHelper")) do
obj.call("setHelperState", state)
end
end
--------------------------------------------------------- ---------------------------------------------------------
-- Update notification related functionality -- Update notification related functionality
--------------------------------------------------------- ---------------------------------------------------------
@ -1813,6 +1821,7 @@ end
-- Utility functions -- Utility functions
--------------------------------------------------------- ---------------------------------------------------------
-- removes a value from a table
function removeValueFromTable(t, val) function removeValueFromTable(t, val)
for i, v in ipairs(t) do for i, v in ipairs(t) do
if v == val then if v == val then
@ -1822,6 +1831,7 @@ function removeValueFromTable(t, val)
end end
end end
-- checks if a table is empty
function isTableEmpty(tbl) function isTableEmpty(tbl)
if next(tbl) == nil then if next(tbl) == nil then
return true return true

View File

@ -3,30 +3,27 @@ This file is used to add an XML button to a card, turned on via context menu.
Valid options modify the appearance of the XML button, as well as the Valid options modify the appearance of the XML button, as well as the
behavior of the return and redraw function. Set options before requiring this file. behavior of the return and redraw function. Set options before requiring this file.
originParams{} --@type table Parameters for the return and redraw functions. Typically set VALID_TOKENS or INVALID_TOKENS, not both.
- includes parameters for the return and redraw functions. Typically set VALID_TOKENS If there are no restrictions on which tokens can be redrawn (e.g. Wendy Adams), keep both empty.
or INVALID_TOKENS, not both. If there are no restrictions on which tokens can be redrawn * VALID_TOKENS --@type table
(e.g. Wendy Adams), do not include either parameter. - keyed table which lists all tokens that can be redrawn by the card
* VALID_TOKENS --@type table - example usage: "False Covenant"
- keyed table which lists all tokens that can be redrawn by the card > VALID_TOKENS = {
- example usage: "False Covenant" > ["Curse"] = true
> VALID_TOKENS = { > }
> ["Curse"] = true
> }
* INVALID_TOKENS --@type table
- keyed table which lists all tokens that cannot be redrawn by the card
- example usage: "Custom Ammunition"
> INVALID_TOKENS = {
> ["Auto-fail"] = true
> }
* redrawnTokenType --@type string ("random" or name of token) * INVALID_TOKENS --@type table
- determines which kind of token is drawn from the bag. Typically "random" - keyed table which lists all tokens that cannot be redrawn by the card
but could be a set token name (e.g. Nkosi Mabati) - example usage: "Custom Ammunition"
> INVALID_TOKENS = {
> ["Auto-fail"] = true
> }
* triggeringCard --@type string (name of card button is on) * DRAW_SPECIFIC_TOKEN --@type string (name of token or nil)
- allows for the name of the card to be passed onto Global for any special handling - if set, will attempt to draw that specific token
* RETURN_TO_POOL --@type string
- allows for the name of the card to be passed onto Global for any special handling
The following parameters modify the appearence of the XML button and are not listed as part of a table. The following parameters modify the appearence of the XML button and are not listed as part of a table.
- buttonHeight (default is 450) - buttonHeight (default is 450)
@ -34,7 +31,7 @@ The following parameters modify the appearence of the XML button and are not lis
- buttonPosition (default is "0 -55 -22") - buttonPosition (default is "0 -55 -22")
- buttonFontSize (default is 250) - buttonFontSize (default is 250)
- buttonRotation (change if button is placed on an investigator cards) - buttonRotation (change if button is placed on an investigator cards)
- buttonValue (to change the label of the button, default is "Redraw Token") - buttonLabel (default is "Redraw Token")
- buttonIcon (to add an icon to the right) - buttonIcon (to add an icon to the right)
- buttonColor (default is "#77674DE6") - buttonColor (default is "#77674DE6")
@ -47,70 +44,70 @@ As a nice reminder the XML button takes on the Frost color and icon with the tex
> buttonColor = "#404450E6" > buttonColor = "#404450E6"
> buttonFontSize = 300 > buttonFontSize = 300
> originParams = { > VALID_TOKENS = {
> triggeringCard = "ClaypoolsFurs", > ["Frost"] = true
> redrawnTokenType = "random",
> VALID_TOKENS = {
> ["Frost"] = true
> }
> } > }
>
> require... > require...
----------------------------------------------------------]] ----------------------------------------------------------]]
local turnOnHelper
function onSave() local isHelperEnabled = false
return JSON.encode(turnOnHelper)
function updateSave()
self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled })
end end
function onLoad(savedData) function onLoad(savedData)
self.addContextMenuItem("Enable Helper", makeXMLButton) self.addTag("CardWithHelper")
if savedData and savedData ~= "" then if savedData and savedData ~= "" then
turnOnHelper = JSON.decode(savedData) local loadedData = JSON.decode(savedData)
if turnOnHelper == true then isHelperEnabled = loadedData.isHelperEnabled
makeXMLButton()
end
end end
checkOptionPanel()
createHelperXML()
updateDisplay()
end end
function makeXMLButton() function createHelperXML()
turnOnHelper = true local xmlTable = { {
self.clearContextMenu() tag = "Button",
self.addContextMenuItem("Clear Helper", deleteButton) attributes = {
local xmlTable = {{ active = "false",
tag = "Button", id = "Helper",
attributes = { height = buttonHeight or 450,
height = buttonHeight or 450, width = buttonWidth or 1400,
width = buttonWidth or 1400, rotation = buttonRotation or "0 0 180",
rotation = buttonRotation or "0 0 180", scale = "0.1 0.1 1",
scale = "0.1 0.1 1", position = buttonPosition or "0 -55 -22",
position = buttonPosition or "0 -55 -22", padding = "50 50 50 50",
padding = "50 50 50 50", font = "font_teutonic-arkham",
font = "font_teutonic-arkham", fontSize = buttonFontSize or 250,
fontSize = buttonFontSize or 250, onClick = "triggerXMLTokenLabelCreation",
onClick = "triggerXMLTokenLabelCreation()", color = buttonColor or "#77674DE6",
color = buttonColor or "#77674DE6", textColor = "White"
textColor = "White" },
}, value = buttonLabel or "Redraw Token"
value = buttonValue or "Redraw Token" } }
}}
if buttonIcon then if buttonIcon then
xmlTable[1].attributes.iconWidth = "400" xmlTable[1].attributes.iconWidth = "400"
xmlTable[1].attributes.iconAlignment = "Right" xmlTable[1].attributes.iconAlignment = "Right"
xmlTable[1].attributes.icon = buttonIcon xmlTable[1].attributes.icon = buttonIcon
end end
self.UI.setXmlTable(xmlTable) self.UI.setXmlTable(xmlTable)
end end
function triggerXMLTokenLabelCreation() function shutOff()
-- needs to be its own function in order to pass originParams as a table self.UI.hide("Helper")
Global.call("activeRedrawEffect", originParams)
end end
-- Delete button function initialize()
function deleteButton() self.UI.show("Helper")
self.clearContextMenu() end
self.addContextMenuItem("Enable Helper", makeXMLButton)
self.UI.setXml("") function triggerXMLTokenLabelCreation()
turnOnHelper = false Global.call("activeRedrawEffect", {
end VALID_TOKENS = VALID_TOKENS,
INVALID_TOKENS = INVALID_TOKENS,
RETURN_TO_POOL = RETURN_TO_POOL
})
end

View File

@ -0,0 +1,40 @@
local optionPanelApi = require("core/OptionPanelApi")
-- if the respective option is enabled in onLoad(), enable the helper
function checkOptionPanel()
local options = optionPanelApi.getOptions()
if options.enableCardHelpers then
setHelperState(true)
end
end
-- forces a new state
function setHelperState(newState)
isHelperEnabled = newState
updateSave()
updateDisplay()
end
-- toggles the current state
function toggleHelper()
isHelperEnabled = not isHelperEnabled
updateSave()
updateDisplay()
end
-- updates the visibility and calls events (after a small delay to allow XML being set)
function updateDisplay()
Wait.frames(actualDisplayUpdate, 5)
end
function actualDisplayUpdate()
if isHelperEnabled then
self.clearContextMenu()
self.addContextMenuItem("Disable Helper", toggleHelper)
if initialize then initialize() end
else
self.clearContextMenu()
self.addContextMenuItem("Enable Helper", toggleHelper)
if shutOff then shutOff() end
end
end

View File

@ -1,35 +1,42 @@
require("playercards/CardsWithHelper")
local chaosBagApi = require("chaosbag/ChaosBagApi") local chaosBagApi = require("chaosbag/ChaosBagApi")
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local playermatApi = require("playermat/PlayermatApi") local playermatApi = require("playermat/PlayermatApi")
function onLoad(savedData) local isHelperEnabled = false
self.addContextMenuItem("Enable Helper", createButtons) local loopId
if savedData ~= "" then
local loadedData = JSON.decode(savedData) function updateSave()
if loadedData.loopId then self.script_state = JSON.encode({
createButtons() isHelperEnabled = isHelperEnabled,
end loopId = loopId
end })
end end
function deleteButtons() function onLoad(savedData)
self.clearContextMenu() self.addTag("CardWithHelper")
self.addContextMenuItem("Enable Helper", createButtons) if savedData and savedData ~= "" then
self.UI.setAttribute("inactives", "active", false) local loadedData = JSON.decode(savedData)
self.UI.setAttribute("actives", "active", false) isHelperEnabled = loadedData.isHelperEnabled
loopId = loadedData.loopId
end
checkOptionPanel()
updateDisplay()
end
-- hide buttons and stop monitoring
function shutOff()
self.UI.hide("Helper")
if loopId then Wait.stop(loopId) end if loopId then Wait.stop(loopId) end
loopId = nil loopId = nil
self.script_state = JSON.encode({ loopId = loopId }) updateSave()
end end
-- create buttons and begin monitoring chaos bag for curse and bless tokens -- show buttons and begin monitoring chaos bag for curse and bless tokens
function createButtons() function initialize()
self.clearContextMenu() self.UI.show("Helper")
self.addContextMenuItem("Clear Helper", deleteButtons)
self.UI.setAttribute("inactives", "active", true)
self.UI.setAttribute("actives", "active", true)
loopId = Wait.time(maybeUpdateButtonState, 1, -1) loopId = Wait.time(maybeUpdateButtonState, 1, -1)
self.script_state = JSON.encode({ loopId = loopId }) updateSave()
end end
function resolveToken(player, _, tokenType) function resolveToken(player, _, tokenType)

View File

@ -1,14 +1,11 @@
buttonValue = "Cancel" buttonLabel = "Cancel"
buttonIcon = "token-frost" buttonIcon = "token-frost"
buttonColor = "#404450E6" buttonColor = "#404450E6"
buttonFontSize = 300 buttonFontSize = 300
originParams = { VALID_TOKENS = {
triggeringCard = "ClaypoolsFurs", ["Frost"] = true
redrawnTokenType = "random",
VALID_TOKENS = {
["Frost"] = true
}
} }
require("playercards/CardsThatRedrawTokens") require("playercards/CardsWithHelper")
require("playercards/CardsThatRedrawTokens")

View File

@ -1,10 +1,6 @@
originParams = { INVALID_TOKENS = {
triggeringCard = "CustomModifications", ["Auto-fail"] = true
redrawnTokenType = "random",
VALID_TOKENS = {},
INVALID_TOKENS = {
["Auto-fail"] = true
}
} }
require("playercards/CardsThatRedrawTokens") require("playercards/CardsWithHelper")
require("playercards/CardsThatRedrawTokens")

View File

@ -1,7 +1,5 @@
-- this helper creates buttons to help the user track which hypothesis has been chosen each round require("playercards/CardsWithHelper")
-- (if user forgot to choose one at round start, the old one stays active)
local playermatApi = require("playermat/PlayermatApi") local playermatApi = require("playermat/PlayermatApi")
local upgradeSheetLibrary = require("playercards/customizable/UpgradeSheetLibrary")
-- common button parameters -- common button parameters
local buttonParameters = {} local buttonParameters = {}
@ -21,7 +19,7 @@ initialButtonPosition = buttonParameters.position.z
local verticalOffset = 0.325 local verticalOffset = 0.325
-- list of customizable labels -- list of customizable labels
local customizableList = { local customizableList = {
'Run out of cards in hand', 'Run out of cards in hand',
'Take damage/horror', 'Take damage/horror',
'Discard treachery/enemy', 'Discard treachery/enemy',
@ -29,24 +27,41 @@ local customizableList = {
} }
-- index of the currently selected button (0-indexed from the top) -- index of the currently selected button (0-indexed from the top)
local activeButtonIndex local activeButtonIndex = -1
local isHelperEnabled = false
local hypothesisList = {}
function onSave() function updateSave()
return JSON.encode(activeButtonIndex) self.script_state = JSON.encode({
isHelperEnabled = isHelperEnabled,
activeButtonIndex = activeButtonIndex
})
end end
function onLoad(savedData) function onLoad(savedData)
self.addContextMenuItem("Enable Helper", createButtons) self.addTag("CardWithHelper")
self.addContextMenuItem("Clear Helper", deleteButtons) if savedData and savedData ~= "" then
local loadedData = JSON.decode(savedData)
activeButtonIndex = JSON.decode(savedData) isHelperEnabled = loadedData.isHelperEnabled
if activeButtonIndex and activeButtonIndex ~= "" then activeButtonIndex = loadedData.activeButtonIndex
local tempButtonIndex = activeButtonIndex
createButtons()
if tempButtonIndex >= 0 then
selectButton(tempButtonIndex)
end
end end
checkOptionPanel()
updateDisplay()
if activeButtonIndex > 0 then
selectButton(activeButtonIndex)
end
end
function initialize()
createButtons()
end
function shutOff()
self.clearButtons()
-- reset the z position
buttonParameters.position.z = initialButtonPosition
end end
-- marks a button as active -- marks a button as active
@ -54,32 +69,19 @@ end
function selectButton(index) function selectButton(index)
local lastindex = #hypothesisList - 1 local lastindex = #hypothesisList - 1
for i = 0, lastindex do for i = 0, lastindex do
local color = Color.Black local buttonColor = Color.Black
if i == index then if i == index then
color = Color.Red buttonColor = Color.Red
activeButtonIndex = i activeButtonIndex = i
end end
self.editButton({ index = i, color = color }) self.editButton({ index = i, color = buttonColor })
end end
end end
function deleteButtons()
self.clearButtons()
self.clearContextMenu()
self.addContextMenuItem("Enable Helper", createButtons)
buttonParameters.position.z = initialButtonPosition -- reset the z position
end
-- Create buttons based on the button parameters -- Create buttons based on the button parameters
function createButtons() function createButtons()
self.clearContextMenu()
self.addContextMenuItem("Clear Helper", deleteButtons)
-- reset the list in case of addition of checkboxes or Refine -- reset the list in case of addition of checkboxes or Refine
hypothesisList = { hypothesisList = { 'Succeed by 3 or more', 'Fail by 2 or more' }
'Succeed by 3 or more',
'Fail by 2 or more'
}
-- set activeButtonIndex to restore state onLoad ("-1" -> nothing selected) -- set activeButtonIndex to restore state onLoad ("-1" -> nothing selected)
activeButtonIndex = -1 activeButtonIndex = -1
@ -95,9 +97,9 @@ function createButtons()
end end
for i, label in ipairs(hypothesisList) do for i, label in ipairs(hypothesisList) do
buttonParameters.label = label
buttonParameters.click_function = "selectButton" .. i buttonParameters.click_function = "selectButton" .. i
self.setVar(buttonParameters.click_function, function() selectButton(i - 1) end) self.setVar(buttonParameters.click_function, function() selectButton(i - 1) end)
buttonParameters.label = label
self.createButton(buttonParameters) self.createButton(buttonParameters)
buttonParameters.position.z = buttonParameters.position.z + verticalOffset buttonParameters.position.z = buttonParameters.position.z + verticalOffset
end end
@ -105,7 +107,7 @@ end
function findUpgradeSheet() function findUpgradeSheet()
local matColor = playermatApi.getMatColorByPosition(self.getPosition()) local matColor = playermatApi.getMatColorByPosition(self.getPosition())
local result = playermatApi.searchAroundPlayermat(matColor, "isCard") local result = playermatApi.searchAroundPlaymat(matColor, "isCard")
for j, card in ipairs(result) do for j, card in ipairs(result) do
local metadata = JSON.decode(card.getGMNotes()) or {} local metadata = JSON.decode(card.getGMNotes()) or {}
if metadata.id == "09041-c" then if metadata.id == "09041-c" then

View File

@ -1,14 +1,12 @@
buttonValue = "Cancel" buttonLabel = "Cancel"
buttonIcon = "token-curse" buttonIcon = "token-curse"
buttonColor = "#633A84E6" buttonColor = "#633A84E6"
buttonFontSize = 300 buttonFontSize = 300
originParams = { RETURN_TO_POOL = true
triggeringCard = "FalseCovenant", VALID_TOKENS = {
redrawnTokenType = "random", ["Curse"] = true
VALID_TOKENS = {
["Curse"] = true
}
} }
require("playercards/CardsThatRedrawTokens") require("playercards/CardsWithHelper")
require("playercards/CardsThatRedrawTokens")

View File

@ -1,17 +1,14 @@
originParams = { VALID_TOKENS = {
triggeringCard = "HeavyFurs", ["Skull"] = true,
redrawnTokenType = "random", ["Tablet"] = true,
VALID_TOKENS = { ["Elder Thing"] = true,
["Skull"] = true, ["Cultist"] = true,
["Tablet"] = true, ["Frost"] = true,
["Elder Thing"] = true, ["Custom Token"] = true,
["Cultist"] = true, ["Elder Sign"] = true,
["Frost"] = true, ["Bless"] = true,
["Custom Token"] = true, ["Curse"] = true
["Elder Sign"] = true,
["Bless"] = true,
["Curse"] = true
},
} }
require("playercards/CardsThatRedrawTokens") require("playercards/CardsWithHelper")
require("playercards/CardsThatRedrawTokens")

View File

@ -1,9 +1,8 @@
local chaosBagApi = require("chaosbag/ChaosBagApi") require("playercards/CardsWithHelper")
local guidReferenceApi = require("core/GUIDReferenceApi") local chaosBagApi = require("chaosbag/ChaosBagApi")
local playermatApi = require("playermat/PlayermatApi")
-- XML background color for each token -- XML background color for each token
local tokenColor = { local tokenColor = {
["Skull"] = "#4A0400E6", ["Skull"] = "#4A0400E6",
["Cultist"] = "#173B0BE6", ["Cultist"] = "#173B0BE6",
["Tablet"] = "#1D2238E6", ["Tablet"] = "#1D2238E6",
@ -89,11 +88,8 @@ function deleteButtons()
end end
function resolveSigil() function resolveSigil()
local tokensInPlay = chaosBagApi.getTokensInPlay()
local chaosbag = chaosBagApi.findChaosBag()
local match = false local match = false
for _, obj in ipairs(chaosbag.getObjects()) do for _, obj in ipairs(chaosBagApi.findChaosBag().getObjects()) do
-- if there are any sigils in the bag -- if there are any sigils in the bag
if obj.nickname == sigil then if obj.nickname == sigil then
match = true match = true
@ -106,77 +102,12 @@ function resolveSigil()
return return
end end
local matchingSymbolsInPlay = {} Global.call("activeRedrawEffect", {
DRAW_SPECIFIC_TOKEN = sigil,
for _, token in ipairs(tokensInPlay) do VALID_TOKENS = {
if (token.getName() == "Cultist" ["Tablet"] = true,
or token.getName() == "Tablet" ["Elder Thing"] = true,
or token.getName() == "Elder Thing") ["Cultist"] = true
and token.getName() ~= sigil then }
matchingSymbolsInPlay[#matchingSymbolsInPlay + 1] = token })
end
end
if #matchingSymbolsInPlay == 0 then
broadcastToAll("No eligible symbol token found in play area", "Red")
return
elseif #matchingSymbolsInPlay > 1 then
for _, token in ipairs(matchingSymbolsInPlay) do
-- draw XML to return token to bag
token.UI.setXmlTable({
{
tag = "VerticalLayout",
attributes = {
height = 275,
width = 275,
spacing = 0,
padding = "0 0 20 25",
scale = "0.4 0.4 1",
rotation = "0 0 180",
position = "0 0 -15",
color = "rgba(0,0,0,0.7)",
onClick = self.getGUID() .. "/drawSigil(" .. token.getGUID() .. ")"
},
children = {
{
tag = "Text",
attributes = {
fontSize = "100",
font = "font_teutonic-arkham",
color = "#ffffff",
text = "Nkosi"
}
},
{
tag = "Text",
attributes = {
fontSize = "125",
font = "font_arkhamicons",
color = "#ffffff",
text = "u"
}
}
}
}
})
end
else
drawSigil(_, matchingSymbolsInPlay[1].getGUID())
end
end
function drawSigil(player, tokenGUID)
local returnedToken = getObjectFromGUID(tokenGUID)
local matColor = playermatApi.getMatColorByPosition(returnedToken.getPosition())
local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")
chaosBagApi.drawChaosToken(mat, true, sigil, _, returnedToken)
-- remove XML from tokens in play
for _, token in ipairs(chaosBagApi.getTokensInPlay()) do
if token.getName() == "Cultist"
or token.getName() == "Tablet"
or token.getName() == "Elder Thing" then
token.UI.setXml("")
end
end
end end

View File

@ -1,8 +0,0 @@
VALID_TOKENS = {
["Skull"] = true,
["Cultist"] = true,
["Tablet"] = true,
["Elder Thing"] = true,
}
require("playercards/CardsThatSealTokens")

View File

@ -1,10 +1,8 @@
-- this script is shared between both the level 0 and the upgraded level 3 version of the card require("playercards/CardsWithHelper")
local playermatApi = require("playermat/PlayermatApi") local playermatApi = require("playermat/PlayermatApi")
local modValue, loopId
local buttonParameters = { local buttonParameters = {
click_function = "toggleCounter", click_function = "shutOff",
tooltip = "disable counter",
function_owner = self, function_owner = self,
position = { 0.88, 0.5, -1.33 }, position = { 0.88, 0.5, -1.33 },
font_size = 150, font_size = 150,
@ -12,7 +10,14 @@ local buttonParameters = {
height = 175 height = 175
} }
function onSave() return JSON.encode({ loopId = loopId }) end local modValue, loopId
function updateSave()
self.script_state = JSON.encode({
isHelperEnabled = isHelperEnabled,
loopId = loopId
})
end
function onLoad(savedData) function onLoad(savedData)
-- use metadata to detect level and adjust modValue accordingly -- use metadata to detect level and adjust modValue accordingly
@ -22,30 +27,31 @@ function onLoad(savedData)
modValue = 4 modValue = 4
end end
if savedData ~= "" then self.addTag("CardWithHelper")
if savedData and savedData ~= "" then
local loadedData = JSON.decode(savedData) local loadedData = JSON.decode(savedData)
if loadedData.loopId then isHelperEnabled = loadedData.isHelperEnabled
self.createButton(buttonParameters) loopId = loadedData.loopId
loopId = Wait.time(updateDisplay, 2, -1)
end
end end
checkOptionPanel()
self.addContextMenuItem("Toggle Counter", toggleCounter) updateDisplay()
end end
function toggleCounter() function initialize()
if loopId ~= nil then self.createButton(buttonParameters)
updateButton()
loopId = Wait.time(updateButton, 2, -1)
end
function shutOff()
if loopId then
Wait.stop(loopId) Wait.stop(loopId)
loopId = nil loopId = nil
self.clearButtons()
else
self.createButton(buttonParameters)
updateDisplay()
loopId = Wait.time(updateDisplay, 2, -1)
end end
self.clearButtons()
end end
function updateDisplay() function updateButton()
local matColor = playermatApi.getMatColorByPosition(self.getPosition()) local matColor = playermatApi.getMatColorByPosition(self.getPosition())
local resources = playermatApi.getCounterValue(matColor, "ResourceCounter") local resources = playermatApi.getCounterValue(matColor, "ResourceCounter")
local count = tostring(math.floor(resources / modValue)) local count = tostring(math.floor(resources / modValue))

View File

@ -4,9 +4,5 @@ buttonPosition = "70 -70 -22"
buttonFontSize = 200 buttonFontSize = 200
buttonRotation = "0 0 90" buttonRotation = "0 0 90"
originParams = { require("playercards/CardsWithHelper")
triggeringCard = "Wendy",
redrawnTokenType = "random",
}
require("playercards/CardsThatRedrawTokens") require("playercards/CardsThatRedrawTokens")

View File

@ -256,11 +256,11 @@ function discardListOfObjects(objList)
deckLib.placeOrMergeIntoDeck(obj, ENCOUNTER_DISCARD_POSITION, { x = 0, y = -90, z = 0 }) deckLib.placeOrMergeIntoDeck(obj, ENCOUNTER_DISCARD_POSITION, { x = 0, y = -90, z = 0 })
end end
-- put chaos tokens back into bag (e.g. Unrelenting) -- put chaos tokens back into bag (e.g. Unrelenting)
elseif tokenChecker.isChaosToken(obj) then elseif tokenChecker.isChaosToken(obj) then
chaosBagApi.returnChaosTokenToBag(obj) chaosBagApi.returnChaosTokenToBag(obj)
-- don't touch locked objects (like the table etc.) or specific objects (like key tokens) -- don't touch locked objects (like the table etc.) or specific objects (like key tokens)
elseif not obj.getLock() and not obj.hasTag("DontDiscard") then elseif not obj.getLock() and not obj.hasTag("DontDiscard") then
ownedObjects.Trash.putObject(obj) ownedObjects.Trash.putObject(obj)
end end

View File

@ -161,6 +161,21 @@
</Cell> </Cell>
</Row> </Row>
<!-- Option: Enable all card helpers -->
<Row class="option-text"
tooltip="Enable all card helpers (usually enabled via context menu entries).&#xA;Examples: False Covenant and Book of Living Myths">
<Cell class="option-text">
<Panel class="singleColumn-wrapper">
<Text class="option-header">Enable all card helpers</Text>
</Panel>
</Cell>
<Cell class="option-button">
<Button class="optionToggle"
id="enableCardHelpers"
onClick="onClick_toggleOption"/>
</Cell>
</Row>
<!-- Group: play area settings --> <!-- Group: play area settings -->
<Row class="group-header"> <Row class="group-header">
<Cell class="group-header"> <Cell class="group-header">

View File

@ -13,18 +13,18 @@
onClick="resolveToken" onClick="resolveToken"
textColor="white" textColor="white"
active="false"/> active="false"/>
<Panel position="0 -55 -22" <TableLayout position="0 -55 -22"
rotation="0 0 180" rotation="0 0 180"
height="900" height="900"
width="1400" width="1400"
scale="0.1 0.1 1"/> scale="0.1 0.1 1"
<TableLayout active="false"
cellSpacing="80" cellSpacing="80"
cellBackgroundColor="rgba(1,1,1,0)"/> cellBackgroundColor="rgba(1,1,1,0)"/>
</Defaults> </Defaults>
<Panel> <Panel id="Helper"
<TableLayout id="actives"> active="false">
<TableLayout>
<Row> <Row>
<Cell> <Cell>
<Button id="Bless" <Button id="Bless"
@ -42,10 +42,7 @@
</Cell> </Cell>
</Row> </Row>
</TableLayout> </TableLayout>
</Panel> <TableLayout>
<Panel>
<TableLayout id="inactives">
<Row> <Row>
<Cell> <Cell>
<Button id="inactiveBless" <Button id="inactiveBless"