Merge branch 'main' into token-draw-dummy
This commit is contained in:
commit
5ec1659a8e
@ -1,17 +1,18 @@
|
||||
tableHeightOffset = -9
|
||||
|
||||
function onSave()
|
||||
return JSON.encode({ tid = tableImageData, cd = checkData })
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ tid = tableImageData, cd = checkData })
|
||||
end
|
||||
|
||||
function onload(saved_data)
|
||||
if saved_data ~= "" then
|
||||
local loaded_data = JSON.decode(saved_data)
|
||||
function onload(savedData)
|
||||
if savedData and savedData ~= "" then
|
||||
local loaded_data = JSON.decode(savedData)
|
||||
tableImageData = loaded_data.tid
|
||||
checkData = loaded_data.cd
|
||||
else
|
||||
tableImageData = {}
|
||||
checkData = { move = false, scale = false }
|
||||
updateSave()
|
||||
end
|
||||
|
||||
--Disables interactable status of objects with GUID in list
|
||||
@ -83,6 +84,7 @@ function click_saveSurface(_, color)
|
||||
if findInImageDataIndex(url, nickname) == nil then
|
||||
--Save doesn't exist already
|
||||
table.insert(tableImageData, { url = url, name = nickname })
|
||||
updateSave()
|
||||
broadcastToAll("Image URL saved to memory.", { 0.2, 0.9, 0.2 })
|
||||
--Refresh buttons
|
||||
self.clearButtons()
|
||||
@ -111,6 +113,7 @@ end
|
||||
function click_deleteMemory(_, color, index)
|
||||
if permissionCheck(color) then
|
||||
table.remove(tableImageData, index)
|
||||
updateSave()
|
||||
self.clearButtons()
|
||||
createOpenCloseButton()
|
||||
createSurfaceButtons()
|
||||
@ -166,28 +169,10 @@ function click_checkMove(_, color)
|
||||
local buttonEntry = findButton(self, find_func)
|
||||
self.editButton({ index = buttonEntry.index, label = string.char(10008) })
|
||||
end
|
||||
updateSave()
|
||||
end
|
||||
end
|
||||
|
||||
--Checks/unchecks scale box for hands
|
||||
--This button was disabled for technical reasons
|
||||
--[[
|
||||
function click_checkScale(_, color)
|
||||
if permissionCheck(color) then
|
||||
local find_func = function(o) return o.click_function=="click_checkScale" end
|
||||
if checkData.scale == true then
|
||||
checkData.scale = false
|
||||
local buttonEntry = findButton(self, find_func)
|
||||
self.editButton({index=buttonEntry.index, label=""})
|
||||
else
|
||||
checkData.scale = true
|
||||
local buttonEntry = findButton(self, find_func)
|
||||
self.editButton({index=buttonEntry.index, label=string.char(10008)})
|
||||
end
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
--Alters scale of elements and moves them
|
||||
function changeTableScale(width, depth)
|
||||
--Scaling factors used to translate scale to position offset
|
||||
@ -506,13 +491,6 @@ function createScaleButtons()
|
||||
font_size = 200,
|
||||
font_color = { 1, 1, 1 }
|
||||
})
|
||||
--Disabled due to me removing the feature for technical reasons
|
||||
--[[
|
||||
self.createButton({
|
||||
label="Scale Hands:", click_function="none",
|
||||
position={-8.3,0,4}, height=0, width=0, font_size=200, font_color={1,1,1}
|
||||
})
|
||||
]]
|
||||
--Checkboxes
|
||||
local label = ""
|
||||
if checkData.move == true then label = string.char(10008) end
|
||||
@ -526,15 +504,6 @@ function createScaleButtons()
|
||||
width = 224,
|
||||
font_size = 200,
|
||||
})
|
||||
--[[
|
||||
local label = ""
|
||||
if checkData.scale == true then label = string.char(10008) end
|
||||
self.createButton({
|
||||
label=label, click_function="click_checkScale",
|
||||
function_owner=self, tooltip="Check to scale the width of hands when table is rescaled",
|
||||
position={-6.8,0,4}, height=224, width=224, font_size=200,
|
||||
})
|
||||
]]
|
||||
--Apply button
|
||||
self.createButton({
|
||||
label = "Apply Scale",
|
||||
|
@ -4,8 +4,8 @@ local MIN_VALUE = -10
|
||||
local MAX_VALUE = 99
|
||||
local vp, notes
|
||||
|
||||
function onSave()
|
||||
return JSON.encode({ vp = vp, notes = notes })
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ vp = vp, notes = notes })
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
@ -16,6 +16,7 @@ function onLoad(savedData)
|
||||
else
|
||||
vp = 1
|
||||
notes = "Click to type"
|
||||
updateSave()
|
||||
end
|
||||
|
||||
createButtons()
|
||||
@ -52,17 +53,13 @@ function createTextbox()
|
||||
})
|
||||
end
|
||||
|
||||
function updateNotes()
|
||||
function updateMetadata()
|
||||
local md = JSON.decode(self.getGMNotes())
|
||||
md.victory = vp
|
||||
self.setGMNotes(JSON.encode(md))
|
||||
victoryDisplayApi.update()
|
||||
end
|
||||
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ vp = vp, notes = notes })
|
||||
end
|
||||
|
||||
function input_function(_, _, inputValue, selected)
|
||||
if selected == false then
|
||||
notes = inputValue
|
||||
@ -74,5 +71,5 @@ function click_function(_, _, isRightClick)
|
||||
vp = math.min(math.max(vp + (isRightClick and -1 or 1), MIN_VALUE), MAX_VALUE)
|
||||
self.editButton({ index = 0, label = tostring(vp) })
|
||||
updateSave()
|
||||
updateNotes()
|
||||
updateMetadata()
|
||||
end
|
||||
|
@ -63,12 +63,13 @@ function loadData(loadedData)
|
||||
includeDrawnTokens = loadedData.includeDrawnTokens
|
||||
|
||||
updateUI()
|
||||
updateSave()
|
||||
Wait.time(layout, 1.5)
|
||||
end
|
||||
|
||||
-- saving the precedence settings and information on the most recently loaded data
|
||||
function onSave()
|
||||
return JSON.encode(getSaveData())
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode(getSaveData())
|
||||
end
|
||||
|
||||
-- loading data, button creation and initial layouting
|
||||
@ -104,6 +105,7 @@ function onLoad(savedData)
|
||||
includeDrawnTokens = not includeDrawnTokens
|
||||
local text = includeDrawnTokens and " " or " not "
|
||||
broadcastToAll("Token Arranger will" .. text .. "include currently drawn chaos tokens.", "Orange")
|
||||
updateSave()
|
||||
layout()
|
||||
end)
|
||||
|
||||
@ -114,6 +116,7 @@ function onLoad(savedData)
|
||||
percentage = "basic"
|
||||
broadcastToAll("Percentages are unreliable when using tokens that draw other tokens (bless or curse for example).", "Yellow")
|
||||
end
|
||||
updateSave()
|
||||
layout()
|
||||
end)
|
||||
|
||||
@ -124,6 +127,7 @@ function onLoad(savedData)
|
||||
percentage = "cumulative"
|
||||
end
|
||||
broadcastToAll("Percentages are unreliable when using tokens that draw other tokens (bless or curse for example).", "Yellow")
|
||||
updateSave()
|
||||
layout()
|
||||
end)
|
||||
end
|
||||
@ -145,6 +149,7 @@ function tokenClick(isRightClick, index)
|
||||
index = index - 1,
|
||||
value = tokenPrecedence[TOKEN_NAMES[index]][1]
|
||||
})
|
||||
updateSave()
|
||||
layout()
|
||||
end
|
||||
|
||||
@ -154,8 +159,9 @@ function tokenInput(input, selected, index)
|
||||
local num = tonumber(input)
|
||||
if num ~= nil then
|
||||
tokenPrecedence[TOKEN_NAMES[index]][1] = num
|
||||
updateSave()
|
||||
layout()
|
||||
end
|
||||
layout()
|
||||
end
|
||||
end
|
||||
|
||||
@ -175,6 +181,7 @@ function loadDefaultValues()
|
||||
["Frost"] = { -105, 10},
|
||||
[""] = { 0, 11}
|
||||
}
|
||||
updateSave()
|
||||
end
|
||||
|
||||
-- creates buttons and inputs
|
||||
@ -422,5 +429,6 @@ function onTokenDataChanged(parameters)
|
||||
end
|
||||
|
||||
updateUI()
|
||||
updateSave()
|
||||
layout()
|
||||
end
|
||||
|
@ -85,38 +85,6 @@ modeData = {
|
||||
}
|
||||
}
|
||||
|
||||
function onSave()
|
||||
return JSON.encode(SPAWNED_PLAYER_CARD_GUIDS)
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
if savedData and savedData ~= '' then
|
||||
SPAWNED_PLAYER_CARD_GUIDS = JSON.decode(savedData)
|
||||
else
|
||||
SPAWNED_PLAYER_CARD_GUIDS = {}
|
||||
end
|
||||
end
|
||||
|
||||
function getSpawnedPlayerCardGuid(params)
|
||||
local guid = params[1]
|
||||
if SPAWNED_PLAYER_CARD_GUIDS == nil then
|
||||
return nil
|
||||
else
|
||||
return SPAWNED_PLAYER_CARD_GUIDS[guid]
|
||||
end
|
||||
end
|
||||
|
||||
function setSpawnedPlayerCardGuid(params)
|
||||
local guid = params[1]
|
||||
local value = params[2]
|
||||
if SPAWNED_PLAYER_CARD_GUIDS ~= nil then
|
||||
SPAWNED_PLAYER_CARD_GUIDS[guid] = value
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- called by "Global" during encounter card drawing
|
||||
function checkHiddenCard(name)
|
||||
for _, n in ipairs(HIDDEN_CARD_DATA) do
|
||||
|
@ -108,7 +108,9 @@ local editsToIndex = {
|
||||
}
|
||||
|
||||
-- save function to keep edits to the index
|
||||
function onSave() return JSON.encode({ editsToIndex = editsToIndex }) end
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ editsToIndex = editsToIndex })
|
||||
end
|
||||
|
||||
-- load function to restore edits to the index
|
||||
function onLoad(savedData)
|
||||
@ -162,6 +164,7 @@ end
|
||||
-- makes an edit to the main index
|
||||
function editIndex(params)
|
||||
editsToIndex[params.owner][params.type] = params.guid
|
||||
updateSave()
|
||||
updateMainIndex()
|
||||
end
|
||||
|
||||
|
@ -76,19 +76,6 @@ function takeCardIntoThreatArea(playerColor, hoveredObject)
|
||||
return
|
||||
end
|
||||
|
||||
-- initialize list of objects to move (and store local position + rotation)
|
||||
local additionalObjects = {}
|
||||
for _, obj in ipairs(searchLib.onObject(hoveredObject, "isTileOrToken")) do
|
||||
if not obj.locked then
|
||||
local data = {
|
||||
object = obj,
|
||||
localPos = hoveredObject.positionToLocal(obj.getPosition()),
|
||||
localRot = obj.getRotation() - cardRot
|
||||
}
|
||||
table.insert(additionalObjects, data)
|
||||
end
|
||||
end
|
||||
|
||||
-- get the rotation of the owning playermat (or Mythos)
|
||||
local cardOwner = guidReferenceApi.getOwnerOfObject(hoveredObject)
|
||||
local ownerRotation = Vector(0, 270, 0)
|
||||
@ -101,17 +88,7 @@ function takeCardIntoThreatArea(playerColor, hoveredObject)
|
||||
local newCardRot = cardRot:setAt("y", matRotation.y + cardRot.y - ownerRotation.y)
|
||||
|
||||
-- move the main card to threat area
|
||||
hoveredObject.setRotation(newCardRot)
|
||||
hoveredObject.setPosition(threatAreaPos)
|
||||
|
||||
-- move tokens/tiles (to new global position)
|
||||
for _, data in ipairs(additionalObjects) do
|
||||
data.object.setPosition(hoveredObject.positionToWorld(data.localPos))
|
||||
|
||||
local newRot = data.localRot + Vector(0, newCardRot.y, 0)
|
||||
newRot.y = roundToMultiple(newRot.y, 45)
|
||||
data.object.setRotation(newRot)
|
||||
end
|
||||
GlobalApi.moveCardWithTokens(hoveredObject, threatAreaPos, newCardRot)
|
||||
|
||||
-- contruct feedback message (hide name when face-down + enabled setting)
|
||||
local cardName = hoveredObject.getName()
|
||||
|
@ -73,8 +73,8 @@ local RESOURCE_OPTIONS = {
|
||||
local handVisibility = {}
|
||||
local blurseVisibility = {}
|
||||
|
||||
-- track cards' settings
|
||||
local cardSetting = {}
|
||||
-- track cards' tokens
|
||||
local cardTokens = {}
|
||||
|
||||
---------------------------------------------------------
|
||||
-- data for tokens
|
||||
@ -180,6 +180,12 @@ function getRandomSeed()
|
||||
return math.random(999)
|
||||
end
|
||||
|
||||
function onObjectDrop(_, object)
|
||||
if object.type == "Card" or object.type == "Deck" then
|
||||
moveCardWithTokens({ card = object })
|
||||
end
|
||||
end
|
||||
|
||||
-- Event hook for any object search. When chaos tokens are manipulated while the chaos bag
|
||||
-- container is being searched, a TTS bug can cause tokens to duplicate or vanish. We lock the
|
||||
-- chaos bag during search operations to avoid this.
|
||||
@ -208,8 +214,6 @@ function tryObjectEnterContainer(container, object)
|
||||
-- stop mini cards from forming decks
|
||||
if object.hasTag("Minicard") and container.hasTag("Minicard") then
|
||||
return false
|
||||
elseif object.type == "Card" and object.getName() ~= "Atlach-Nacha" then
|
||||
handleTokenDetaching({ card = object })
|
||||
end
|
||||
|
||||
playAreaApi.tryObjectEnterContainer(container, object)
|
||||
@ -303,19 +307,12 @@ function onPlayerAction(player, action, targets)
|
||||
end
|
||||
return false
|
||||
elseif action == Player.Action.PickUp then
|
||||
local pickedCards = {}
|
||||
for _, target in ipairs(targets) do
|
||||
if target.type == "Card" then
|
||||
table.insert(pickedCards, target)
|
||||
if target.type == "Card" or target.type == "Deck" then
|
||||
storeTokenTransform(target)
|
||||
end
|
||||
end
|
||||
if #pickedCards > 5 then return end
|
||||
|
||||
for _, pickedCard in ipairs(pickedCards) do
|
||||
handleTokenAttaching({ player = player, card = pickedCard })
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
---------------------------------------------------------
|
||||
@ -1780,7 +1777,7 @@ function applyOptionPanelChange(id, state)
|
||||
|
||||
-- update master clue counter
|
||||
local counter = guidReferenceApi.getObjectByOwnerAndType("Mythos", "MasterClueCounter")
|
||||
counter.setVar("useClickableCounters", state)
|
||||
counter.call("setClickableCounters", state)
|
||||
|
||||
-- option: Enable card helpers
|
||||
elseif id == "enableCardHelpers" then
|
||||
@ -2856,30 +2853,33 @@ function tableContains(thisTable, thisElement)
|
||||
return false
|
||||
end
|
||||
|
||||
function handleTokenAttaching(params)
|
||||
function moveCardWithTokens(params)
|
||||
local card = params.card
|
||||
local player = params.player
|
||||
local searchResult = searchLib.onObject(card, "isTileOrToken", 0.95)
|
||||
if card.is_face_down and next(searchResult) ~= nil then
|
||||
cardSetting[card] = {
|
||||
hideFacedown = card.hide_when_face_down,
|
||||
tooltip = card.tooltip
|
||||
}
|
||||
card.hide_when_face_down = false
|
||||
card.tooltip = false
|
||||
local position = params.position
|
||||
local rotation = params.rotation
|
||||
|
||||
if not cardTokens[card] then
|
||||
storeTokenTransform(card)
|
||||
end
|
||||
|
||||
for _, token in ipairs(searchResult) do
|
||||
if not token.locked then
|
||||
card.addAttachment(token)
|
||||
end
|
||||
if rotation then
|
||||
card.setRotation(rotation)
|
||||
end
|
||||
|
||||
if position then
|
||||
card.use_hands = false
|
||||
card.setPositionSmooth(position)
|
||||
end
|
||||
|
||||
if #cardTokens[card] == 0 then return end
|
||||
|
||||
-- wait for the card to finish moving, update token position/rotation regularly
|
||||
Wait.condition(
|
||||
function() handleTokenDetaching({ card = card }) end,
|
||||
function() stopTokenTransformUpdating(card) end,
|
||||
function()
|
||||
if card ~= nil and player ~= nil and player.seated then
|
||||
return card.resting and not tableContains(player.getHoldingObjects(), card)
|
||||
if card ~= nil and cardTokens[card] ~= nil and #cardTokens[card] ~= 0 then
|
||||
updateTokenTransform(card)
|
||||
return card.resting and not card.isSmoothMoving()
|
||||
else
|
||||
return true
|
||||
end
|
||||
@ -2887,35 +2887,49 @@ function handleTokenAttaching(params)
|
||||
)
|
||||
end
|
||||
|
||||
function handleTokenDetaching(params)
|
||||
local card = params.card
|
||||
if card == nil or next(card.getAttachments()) == nil then return end
|
||||
|
||||
-- restore card settings
|
||||
if cardSetting[card] ~= nil then
|
||||
card.hide_when_face_down = cardSetting[card]["hideFacedown"]
|
||||
card.tooltip = cardSetting[card]["tooltip"]
|
||||
cardSetting[card] = nil
|
||||
function storeTokenTransform(card)
|
||||
if cardTokens[card] ~= nil then
|
||||
stopTokenTransformUpdating(card)
|
||||
end
|
||||
|
||||
-- remove attachments
|
||||
local removedTokens = card.removeAttachments()
|
||||
for _, token in ipairs(removedTokens) do
|
||||
if token.getPosition().y < card.getPosition().y then
|
||||
local posY = card.getPosition().y + 0.05
|
||||
token.setPosition(token.getPosition():setAt("y", posY))
|
||||
cardTokens[card] = {}
|
||||
local cardRot = card.getRotation()
|
||||
for _, token in ipairs(searchLib.onObject(card, "isTileOrToken", 0.95)) do
|
||||
if not token.locked then
|
||||
-- offset to stop the token from colliding with the card
|
||||
local tokenPos = token.getPosition() + Vector(0, 0.05, 0)
|
||||
token.setPosition(tokenPos)
|
||||
|
||||
-- store local transform data
|
||||
table.insert(cardTokens[card], {
|
||||
token = token,
|
||||
localPos = card.positionToLocal(tokenPos),
|
||||
localRot = token.getRotation() - cardRot
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- redraw token xml
|
||||
if card.hasTag("CardThatSeals") then
|
||||
local func = card.getVar("updateStackSize") -- make sure function exists
|
||||
if func ~= nil then
|
||||
card.call("updateStackSize")
|
||||
function updateTokenTransform(card)
|
||||
for _, tokenData in ipairs(cardTokens[card] or {}) do
|
||||
if tokenData.token ~= nil then
|
||||
tokenData.token.setPosition(card.positionToWorld(tokenData.localPos))
|
||||
tokenData.token.setRotation(card.getRotation() + tokenData.localRot)
|
||||
tokenData.token.locked = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function stopTokenTransformUpdating(card)
|
||||
for _, tokenData in ipairs(cardTokens[card] or {}) do
|
||||
if tokenData.token ~= nil then
|
||||
tokenData.token.locked = false
|
||||
end
|
||||
end
|
||||
cardTokens[card] = nil
|
||||
card.use_hands = true
|
||||
end
|
||||
|
||||
-- removes tokens from the provided card/deck
|
||||
function removeTokensFromObject(params)
|
||||
local object = params.object
|
||||
@ -2928,14 +2942,30 @@ function removeTokensFromObject(params)
|
||||
end
|
||||
end
|
||||
|
||||
for _, obj in ipairs(searchLib.onObject(object, "isTileOrToken")) do
|
||||
if tokenChecker.isChaosToken(obj) then
|
||||
returnChaosTokenToBag( { token = obj, fromBag = false } )
|
||||
elseif obj.getGUID() ~= "4ee1f2" and -- table
|
||||
obj ~= self and
|
||||
obj.memo ~= nil and
|
||||
obj.getLock() == false then
|
||||
trash.putObject(obj)
|
||||
if cardTokens[object] then
|
||||
-- check if this card was moved with tokens on it
|
||||
for _, tokenData in ipairs(cardTokens[object]) do
|
||||
if tokenData.token ~= nil then
|
||||
tokenData.token.locked = false
|
||||
if tokenChecker.isChaosToken(tokenData.token) then
|
||||
returnChaosTokenToBag({ token = tokenData.token, fromBag = false })
|
||||
else
|
||||
trash.putObject(tokenData.token)
|
||||
end
|
||||
end
|
||||
end
|
||||
cardTokens[object] = nil
|
||||
else
|
||||
-- search area for tokens
|
||||
for _, obj in ipairs(searchLib.onObject(object, "isTileOrToken")) do
|
||||
if tokenChecker.isChaosToken(obj) then
|
||||
returnChaosTokenToBag({ token = obj, fromBag = false })
|
||||
elseif obj.getGUID() ~= "4ee1f2" and -- table
|
||||
obj ~= self and
|
||||
obj.memo ~= nil and
|
||||
obj.getLock() == false then
|
||||
trash.putObject(obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -53,12 +53,6 @@ do
|
||||
Global.call("handVisibilityToggle", { playerColor = playerColor, handColor = handColor })
|
||||
end
|
||||
|
||||
-- handles token detaching for cards
|
||||
---@param card tts__Object Card that should get tokens detached
|
||||
function GlobalApi.handleTokenDetaching(card)
|
||||
Global.call("handleTokenDetaching", { card = card })
|
||||
end
|
||||
|
||||
-- discards tokens from an object
|
||||
---@param object tts__Object Object that should get tokens removed
|
||||
---@param owner string Owner of this object (for discarding)
|
||||
@ -66,6 +60,14 @@ do
|
||||
Global.call("removeTokensFromObject", { object = object, owner = owner })
|
||||
end
|
||||
|
||||
-- moves a card with tokens on it
|
||||
---@param card tts__Object Card that should get moved
|
||||
---@param position? tts__Vector Target position
|
||||
---@param rotation? tts__Vector Target rotation
|
||||
function GlobalApi.moveCardWithTokens(card, position, rotation)
|
||||
Global.call("moveCardWithTokens", { card = card, position = position, rotation = rotation })
|
||||
end
|
||||
|
||||
-- loads saved options
|
||||
---@param options table Set a new state for the option table
|
||||
function GlobalApi.loadOptionPanelSettings(options)
|
||||
|
@ -2,9 +2,12 @@ local playermatApi = require("playermat/PlayermatApi")
|
||||
|
||||
-- variables are intentionally global to be accessible
|
||||
count = 0
|
||||
useClickableCounters = false
|
||||
|
||||
function onSave() return JSON.encode(useClickableCounters) end
|
||||
local useClickableCounters = false
|
||||
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode(useClickableCounters)
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
if savedData and savedData ~= "" then
|
||||
@ -28,6 +31,11 @@ function onLoad(savedData)
|
||||
Wait.time(sumClues, 2, -1)
|
||||
end
|
||||
|
||||
function setClickableCounters(state)
|
||||
useClickableCounters = state
|
||||
updateSave()
|
||||
end
|
||||
|
||||
-- removes all player clues by calling the respective function from the counting bowls / clickers
|
||||
function removeAllPlayerClues()
|
||||
printToAll(count .. " clue(s) from playermats removed.", "White")
|
||||
|
@ -105,7 +105,6 @@ function onCollisionEnter(collisionInfo)
|
||||
if inArea(localPos, ENCOUNTER_DECK_AREA) or inArea(localPos, ENCOUNTER_DISCARD_AREA) then
|
||||
-- reset spawned tokens and remove tokens from cards in encounter deck / discard area
|
||||
Wait.frames(function() tokenSpawnTrackerApi.resetTokensSpawned(object) end, 1)
|
||||
GlobalApi.handleTokenDetaching(object)
|
||||
GlobalApi.removeTokensFromObject(object, "Mythos")
|
||||
|
||||
elseif inArea(localPos, SCENARIO_REFERENCE_AREA) then
|
||||
|
@ -249,7 +249,7 @@ end
|
||||
|
||||
-- handles all button clicks
|
||||
function buttonClicked(player, _, id)
|
||||
local index = tonumber(id) or ""
|
||||
local index = tonumber(id)
|
||||
|
||||
if index == 19 then
|
||||
setVisibility("toggle", player.color)
|
||||
|
@ -50,8 +50,8 @@ local currentScenario, connectionsEnabled
|
||||
-- general code
|
||||
---------------------------------------------------------
|
||||
|
||||
function onSave()
|
||||
return JSON.encode({
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({
|
||||
trackedLocations = locations,
|
||||
currentScenario = currentScenario,
|
||||
connectionColor = connectionColor,
|
||||
@ -165,9 +165,11 @@ function onUpdate()
|
||||
-- Even if the last location left the play area, need one last draw to clear the lines
|
||||
needsConnectionDraw = true
|
||||
end
|
||||
|
||||
if needsConnectionRebuild then
|
||||
rebuildConnectionList()
|
||||
end
|
||||
|
||||
if needsConnectionDraw then
|
||||
drawDraggingConnections()
|
||||
end
|
||||
@ -222,6 +224,7 @@ function maybeTrackLocation(card)
|
||||
else
|
||||
locations[card.getGUID()] = metadata.locationFront
|
||||
end
|
||||
updateSave()
|
||||
|
||||
-- only draw connection lines for not-excluded scenarios
|
||||
if showLocationLinks() then
|
||||
@ -243,6 +246,7 @@ function maybeUntrackLocation(card)
|
||||
-- area. If the object is now locked, don't remove it.
|
||||
if locations[card.getGUID()] ~= nil and not card.locked then
|
||||
locations[card.getGUID()] = nil
|
||||
updateSave()
|
||||
rebuildConnectionList()
|
||||
drawBaseConnections()
|
||||
end
|
||||
@ -632,7 +636,7 @@ function updateSurface(newURL)
|
||||
guid = customDataHelper.getGUID()
|
||||
end
|
||||
|
||||
self.script_state = onSave()
|
||||
updateSave()
|
||||
self.reload()
|
||||
|
||||
if guid ~= nil then
|
||||
@ -664,6 +668,7 @@ function setConnectionDrawState(state)
|
||||
connectionsEnabled = state
|
||||
rebuildConnectionList()
|
||||
drawBaseConnections()
|
||||
updateSave()
|
||||
end
|
||||
|
||||
-- called by the option panel to edit the location connection color
|
||||
@ -671,6 +676,7 @@ function setConnectionColor(color)
|
||||
connectionColor = color
|
||||
rebuildConnectionList()
|
||||
drawBaseConnections()
|
||||
updateSave()
|
||||
end
|
||||
|
||||
function onScenarioChanged(scenarioName)
|
||||
@ -678,6 +684,7 @@ function onScenarioChanged(scenarioName)
|
||||
if not showLocationLinks() then
|
||||
broadcastToAll("Automatic location connections not available for this scenario")
|
||||
end
|
||||
updateSave()
|
||||
end
|
||||
|
||||
function getTrackedLocations()
|
||||
|
@ -3,8 +3,8 @@ local GlobalApi = require("core/GlobalApi")
|
||||
local playAreaApi = require("core/PlayAreaApi")
|
||||
local typeIndex, selectionIndex, plainNameCache
|
||||
|
||||
function onSave()
|
||||
return JSON.encode({
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({
|
||||
typeIndex = typeIndex,
|
||||
selectionIndex = selectionIndex
|
||||
})
|
||||
@ -103,11 +103,13 @@ end
|
||||
function onClick_imageTab(_, _, tabId)
|
||||
typeIndex = tonumber(tabId:sub(9))
|
||||
selectionIndex = 1
|
||||
updateSave()
|
||||
updatePlayAreaGallery()
|
||||
end
|
||||
|
||||
function onClick_listItem(_, _, listId)
|
||||
selectionIndex = tonumber(listId:sub(10))
|
||||
updateSave()
|
||||
updatePlayAreaGallery()
|
||||
end
|
||||
|
||||
|
@ -54,8 +54,8 @@ local colorsForClasses = {
|
||||
|
||||
local highlightColor = { 0, 0.7843, 0.7843 }
|
||||
|
||||
function onSave()
|
||||
return JSON.encode({ class = class, symbol = symbol })
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ class = class, symbol = symbol })
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
@ -258,6 +258,7 @@ function updateClass(newClass)
|
||||
symbol = newClass or "Neutral"
|
||||
end
|
||||
class = newClass or "Neutral"
|
||||
updateSave()
|
||||
updateDisplay()
|
||||
end
|
||||
|
||||
@ -267,6 +268,7 @@ function updateSymbol(newSymbol)
|
||||
if symbol == "Universal" then
|
||||
symbol = class
|
||||
end
|
||||
updateSave()
|
||||
updateDisplay()
|
||||
end
|
||||
|
||||
@ -277,6 +279,7 @@ function updateClassAndSymbol(params)
|
||||
if symbol == "Universal" then
|
||||
symbol = class
|
||||
end
|
||||
updateSave()
|
||||
updateDisplay()
|
||||
end
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
local spawnedCardGuids = {}
|
||||
|
||||
function onSave() return JSON.encode({ cards = spawnedCardGuids }) end
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ cards = spawnedCardGuids })
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
if savedData and savedData ~= "" then
|
||||
@ -20,13 +22,18 @@ end
|
||||
|
||||
function markTokensSpawned(cardGuid)
|
||||
spawnedCardGuids[cardGuid] = true
|
||||
updateSave()
|
||||
end
|
||||
|
||||
function resetTokensSpawned(card)
|
||||
spawnedCardGuids[card.getGUID()] = nil
|
||||
updateSave()
|
||||
end
|
||||
|
||||
function resetAll() spawnedCardGuids = {} end
|
||||
function resetAll()
|
||||
spawnedCardGuids = {}
|
||||
updateSave()
|
||||
end
|
||||
|
||||
function resetAllLocations() resetSpecificTypes("Location") end
|
||||
|
||||
@ -46,6 +53,7 @@ function resetSpecificTypes(type1, type2)
|
||||
end
|
||||
for cardGuid, _ in pairs(resetList) do
|
||||
spawnedCardGuids[cardGuid] = nil
|
||||
updateSave()
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -114,7 +114,14 @@ function updateSave()
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
sealedTokens = JSON.decode(savedData) or {}
|
||||
-- verify sealed tokens
|
||||
for _, guid in ipairs(JSON.decode(savedData) or {}) do
|
||||
local token = getObjectFromGUID(guid)
|
||||
if token ~= nil then
|
||||
table.insert(sealedTokens, guid)
|
||||
end
|
||||
end
|
||||
|
||||
ID_URL_MAP = chaosBagApi.getIdUrlMap()
|
||||
generateContextMenu()
|
||||
updateStackSize()
|
||||
@ -383,6 +390,12 @@ function updateStackSize()
|
||||
local topToken = getObjectFromGUID(sealedTokens[#sealedTokens])
|
||||
if topToken == nil then return end
|
||||
|
||||
-- handling for two-digit numbers
|
||||
local fontsize = 380
|
||||
if #sealedTokens > 9 then
|
||||
fontsize = 360
|
||||
end
|
||||
|
||||
topToken.UI.setXmlTable({
|
||||
{
|
||||
tag = "Panel",
|
||||
@ -397,7 +410,7 @@ function updateStackSize()
|
||||
children = {
|
||||
tag = "Text",
|
||||
attributes = {
|
||||
fontSize = "380",
|
||||
fontSize = fontsize,
|
||||
font = "font_teutonic-arkham",
|
||||
color = "#ffffff",
|
||||
outline = "#000000",
|
||||
|
@ -23,8 +23,8 @@ inputParameters.scale = { 0.12, 1, 0.12 }
|
||||
inputParameters.color = { 0.9, 0.7, 0.5 }
|
||||
inputParameters.font_color = { 0, 0, 0 }
|
||||
|
||||
function onSave()
|
||||
return JSON.encode({ spawnAll, searchExact, inputParameters.value })
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ spawnAll, searchExact, inputParameters.value })
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
@ -68,11 +68,13 @@ end
|
||||
function toggleSpawnMode()
|
||||
spawnAll = not spawnAll
|
||||
self.editButton({ index = 0, label = BUTTON_LABELS["spawn"][spawnAll] })
|
||||
updateSave()
|
||||
end
|
||||
|
||||
function toggleSearchMode()
|
||||
searchExact = not searchExact
|
||||
self.editButton({ index = 1, label = BUTTON_LABELS["search"][searchExact] })
|
||||
updateSave()
|
||||
end
|
||||
|
||||
-- if "Enter press" (\n) is found, start search and recreate input
|
||||
@ -84,6 +86,7 @@ function input_func(_, _, input, stillEditing)
|
||||
startSearch()
|
||||
self.removeInput(0)
|
||||
self.createInput(inputParameters)
|
||||
updateSave()
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -7,7 +7,9 @@ buttonParameters.color = { 0, 0, 0, 0 }
|
||||
buttonParameters.font_color = { 0, 0, 0, 100 }
|
||||
buttonParameters.font_size = 450
|
||||
|
||||
function onSave() return JSON.encode(stats) end
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode(stats)
|
||||
end
|
||||
|
||||
-- load stats and make buttons (left to right)
|
||||
function onLoad(savedData)
|
||||
@ -29,6 +31,7 @@ end
|
||||
|
||||
function buttonClick(isRightClick, index)
|
||||
stats[index] = math.min(math.max(stats[index] + (isRightClick and -1 or 1), 0), 99)
|
||||
updateSave()
|
||||
updateButtonLabel(index)
|
||||
end
|
||||
|
||||
@ -52,6 +55,7 @@ function updateStats(newStats)
|
||||
stats = newStats
|
||||
|
||||
for i = 1, 4 do updateButtonLabel(i) end
|
||||
updateSave()
|
||||
elseif newStats then
|
||||
printToAll("Provided new stats are incomplete or incorrectly formatted.", "Red")
|
||||
end
|
||||
|
@ -46,7 +46,7 @@ local collisionEnabled = false
|
||||
local currentlyEditingSlots = false
|
||||
|
||||
-- for stopping multiple collisions of the same object
|
||||
local collisionTable = {}
|
||||
local collisionTable = {}
|
||||
|
||||
-- x-Values for discard buttons
|
||||
local DISCARD_BUTTON_X_START = -1.365
|
||||
@ -308,11 +308,11 @@ end
|
||||
---@param id number Index of the discard button (from left to right, must be unique)
|
||||
function makeDiscardButton(id)
|
||||
local xValue = DISCARD_BUTTON_X_START + (id - 1) * DISCARD_BUTTON_X_OFFSET
|
||||
local position = { xValue, 0.1, -0.94 }
|
||||
local searchPosition = { -position[1], position[2], position[3] + 0.32 }
|
||||
local position = Vector(xValue, 0.1, -0.94)
|
||||
local searchPosition = Vector(-position[1], 1, position[3] + 0.32)
|
||||
local handlerName = 'handler' .. id
|
||||
self.setVar(handlerName, function()
|
||||
local cardSizeSearch = { 2, 1, 3.2 }
|
||||
local cardSizeSearch = Vector(2, 2, 3.2)
|
||||
local globalSearchPosition = self.positionToWorld(searchPosition)
|
||||
local searchResult = searchArea(globalSearchPosition, cardSizeSearch)
|
||||
return discardListOfObjects(searchResult)
|
||||
@ -331,13 +331,12 @@ end
|
||||
|
||||
-- build a hybrid button to discard from searchPosition or move a card/deck to empty threat area on right click
|
||||
function makeDrawAreaButton()
|
||||
local position = { -1.365, 0.1, -0.94 }
|
||||
self.createButton({
|
||||
label = "Discard / ➜",
|
||||
click_function = "discardOrMove",
|
||||
tooltip = "Right-click to move to threat area",
|
||||
function_owner = self,
|
||||
position = position,
|
||||
position = { -1.365, 0.1, -0.94 },
|
||||
scale = { 0.12, 0.12, 0.12 },
|
||||
width = 1190,
|
||||
height = 350,
|
||||
@ -346,8 +345,8 @@ function makeDrawAreaButton()
|
||||
end
|
||||
|
||||
function discardOrMove(_, playerColor, isRightClick)
|
||||
local searchPosition = { 1.365, 0.1, -0.62 }
|
||||
local cardSizeSearch = { 2, 1, 3.2 }
|
||||
local searchPosition = Vector(1.365, 1, -0.62)
|
||||
local cardSizeSearch = Vector(2, 2, 3.2)
|
||||
local globalSearchPosition = self.positionToWorld(searchPosition)
|
||||
local searchResult = searchArea(globalSearchPosition, cardSizeSearch)
|
||||
|
||||
@ -360,23 +359,7 @@ function discardOrMove(_, playerColor, isRightClick)
|
||||
|
||||
for _, obj in ipairs(searchResult) do
|
||||
if obj.type == "Card" or obj.type == "Deck" then
|
||||
-- initialize list of objects to move (and store local position + rotation)
|
||||
local additionalObjects = {}
|
||||
for _, tokenOnCard in ipairs(searchLib.onObject(obj, "isTileOrToken")) do
|
||||
if not tokenOnCard.locked then
|
||||
local data = {
|
||||
object = tokenOnCard,
|
||||
localPos = obj.positionToLocal(tokenOnCard.getPosition()),
|
||||
}
|
||||
table.insert(additionalObjects, data)
|
||||
end
|
||||
end
|
||||
|
||||
obj.setPosition(threatAreaPos)
|
||||
-- move tokens/tiles (to new global position)
|
||||
for _, data in ipairs(additionalObjects) do
|
||||
data.object.setPosition(obj.positionToWorld(data.localPos))
|
||||
end
|
||||
GlobalApi.moveCardWithTokens(obj, threatAreaPos)
|
||||
end
|
||||
end
|
||||
else
|
||||
@ -1098,9 +1081,8 @@ end
|
||||
-- instruct Global to update this mat's hand visibility
|
||||
function onClick_visibilitySelect(player)
|
||||
if player.color == playerColor then
|
||||
printToColor(
|
||||
"This is meant to be clicked by other players to be able to see your hand (primarily for multi-handed gameplay). It won't do anything for you.",
|
||||
playerColor)
|
||||
printToColor("This is meant to be clicked by other players to be able to see your hand " ..
|
||||
"(primarily for multi-handed gameplay). It won't do anything for you.", playerColor)
|
||||
return
|
||||
end
|
||||
|
||||
@ -1108,19 +1090,25 @@ function onClick_visibilitySelect(player)
|
||||
end
|
||||
|
||||
-- changes the UI state and the internal variable for the togglebuttons
|
||||
function onClick_toggleOption(player, _, id)
|
||||
local state = optionPanelData[id]
|
||||
local newState = not state
|
||||
applyOptionPanelChange(id, newState, player.color)
|
||||
self.UI.setAttribute(id, "image", newState and "option_on" or "option_off")
|
||||
function onClick_toggleOption(player, clickType, id)
|
||||
updateMessageColor(player.color)
|
||||
applyOptionPanelChange(id, not optionPanelData[id], clickType)
|
||||
end
|
||||
|
||||
function applyOptionPanelChange(id, state, clickedByColor)
|
||||
optionPanelData[id] = state
|
||||
updateSave()
|
||||
function applyOptionPanelChange(id, state, clickType)
|
||||
if clickType == "-1" then -- left-clicked
|
||||
optionPanelData[id] = state
|
||||
self.UI.setAttribute(id, "image", state and "option_on" or "option_off")
|
||||
end
|
||||
|
||||
if id == "slotEditing" then
|
||||
toggleSlotEditing(_, clickedByColor)
|
||||
if currentlyEditingSlots and clickType == "-2" then -- right-clicked
|
||||
resetSlotSymbols()
|
||||
elseif currentlyEditingSlots and clickType == "-3" then -- middle-clicked
|
||||
resetSlotSymbols(true)
|
||||
else
|
||||
toggleSlotEditing()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1139,20 +1127,15 @@ function updateSlotSymbols()
|
||||
end
|
||||
|
||||
-- toggle the "slot editing mode"
|
||||
function toggleSlotEditing(_, clickedByColor, isRightClick)
|
||||
if isRightClick then
|
||||
resetSlotSymbols()
|
||||
return
|
||||
end
|
||||
|
||||
updateMessageColor(clickedByColor)
|
||||
|
||||
-- toggle internal variable
|
||||
function toggleSlotEditing()
|
||||
currentlyEditingSlots = not currentlyEditingSlots
|
||||
updateSlotSymbols()
|
||||
|
||||
if currentlyEditingSlots then
|
||||
broadcastToColor("Click on a slot symbol (or an empty slot) to edit it.", messageColor, "Orange")
|
||||
broadcastToColor("Check chat for instructions", messageColor, "Orange")
|
||||
printToColor("Click on a slot symbol (or an empty slot) to edit it. " ..
|
||||
"Right-click the 'Slot-Edit' button to return to the default slots. " ..
|
||||
"Middle-click the 'Slot-Edit' button to remove all slot symbols.", messageColor, "White")
|
||||
else
|
||||
updateSave()
|
||||
end
|
||||
@ -1188,10 +1171,11 @@ function getSlotRotation(slotName)
|
||||
end
|
||||
|
||||
-- reset the slot symbols by making a deep copy of the default data and redrawing
|
||||
function resetSlotSymbols()
|
||||
---@param empty? boolean If true, will set the slot symbols to "any" (empty) instead of the defaults
|
||||
function resetSlotSymbols(empty)
|
||||
slotData = {}
|
||||
for _, slotName in ipairs(defaultSlotData) do
|
||||
table.insert(slotData, slotName)
|
||||
table.insert(slotData, empty and "any" or slotName)
|
||||
end
|
||||
updateSave()
|
||||
updateSlotSymbols()
|
||||
@ -1296,12 +1280,9 @@ function onCollisionEnter(collisionInfo)
|
||||
-- this is mostly for helpers like Stella and Kohaku
|
||||
spawnTokensOrShowHelper(object)
|
||||
end
|
||||
|
||||
elseif inArea(localCardPos, DECK_DISCARD_AREA) then
|
||||
GlobalApi.handleTokenDetaching(object)
|
||||
tokenSpawnTrackerApi.resetTokensSpawned(object)
|
||||
GlobalApi.removeTokensFromObject(object, matColor)
|
||||
|
||||
elseif object.is_face_down == false then
|
||||
-- main uses spawning
|
||||
if inArea(localCardPos, MAIN_PLAY_AREA) and (md.type == "Asset" or md.type == "Event") then
|
||||
|
@ -1,7 +1,7 @@
|
||||
local connections = {}
|
||||
|
||||
function onSave()
|
||||
return JSON.encode({ connections = connections })
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ connections = connections })
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
@ -13,6 +13,7 @@ function onLoad(savedData)
|
||||
|
||||
addHotkey("Drawing Tool: Reset", function()
|
||||
connections = {}
|
||||
updateSave()
|
||||
processLines()
|
||||
end)
|
||||
addHotkey("Drawing Tool: Redraw", processLines)
|
||||
@ -74,6 +75,7 @@ function addPair(obj1, obj2)
|
||||
|
||||
if not connections[guid1] then connections[guid1] = {} end
|
||||
connections[guid1][guid2] = not connections[guid1][guid2]
|
||||
updateSave()
|
||||
end
|
||||
|
||||
function processLines()
|
||||
|
@ -1,5 +1,5 @@
|
||||
function onSave()
|
||||
return JSON.encode(zone and zone.getGUID())
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode(zone and zone.getGUID())
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
@ -22,6 +22,7 @@ function enable()
|
||||
scale = { scale.x * 2, 7, scale.z * 2 }
|
||||
})
|
||||
zone.setName("TokenDiscardZone")
|
||||
updateSave()
|
||||
setMenu(false)
|
||||
end
|
||||
|
||||
@ -30,6 +31,7 @@ function disable()
|
||||
zone.destruct()
|
||||
zone = nil
|
||||
end
|
||||
updateSave()
|
||||
setMenu(true)
|
||||
end
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user