Merge branch 'main' into playermat-xml

This commit is contained in:
Chr1Z93 2024-07-03 22:50:02 +02:00
commit 757e818450
34 changed files with 566 additions and 238 deletions

View File

@ -27,6 +27,8 @@
"HandTrigger.be2f17",
"HandTrigger.0285cc",
"HandTrigger.a70eee",
"ScriptingTrigger.a2f932",
"FogOfWarTrigger.3aab97",
"TableLegBottomRight.afc863",
"TableLegBottomLeft.c8edca",
"TableLegTopLeft.393bf7",
@ -97,7 +99,6 @@
"Damagetokens.480bda",
"Resourcetokens.9fadf9",
"Connectionmarkers.170f10",
"FogOfWarTrigger.3aab97",
"ChaosTokenReserve.106418",
"ClueCounter.37be78",
"ClueCounter.1769ed",
@ -127,7 +128,6 @@
"ChaosBag.fea079",
"DataHelper.708279",
"BlessCurseManager.5933fb",
"ScriptingTrigger.a2f932",
"EdgeoftheEarth.895eaa",
"TheDream-Eaters.a16a1a",
"TheFeastofHemlockVale.c740af",

View File

@ -30,12 +30,12 @@
"URL": "http://cloud-3.steamusercontent.com/ugc/2026086584372569912/5CB461AEAE2E59D3064D90A776EB86C46081EC78/"
},
{
"Name": "option-on",
"Name": "option_on",
"Type": 0,
"URL": "http://cloud-3.steamusercontent.com/ugc/2462982115668997008/2178787B67B3C96F3419EDBAB8420E39893756BC/"
},
{
"Name": "option-off",
"Name": "option_off",
"Type": 0,
"URL": "http://cloud-3.steamusercontent.com/ugc/2462982115668996901/D6438ECBB11DECC6DB9987589FF526FBAD4D2368/"
},
@ -69,16 +69,6 @@
"Type": 0,
"URL": "http://cloud-3.steamusercontent.com/ugc/2280574378889753733/F67B7B37FF7AA253B6D697E577DF54A3E76030C2/"
},
{
"Name": "option_on",
"Type": 0,
"URL": "http://cloud-3.steamusercontent.com/ugc/2024962321889555728/22ABD35CBB49A001F3A5318E4AFCFB22D24FEA39/"
},
{
"Name": "option_off",
"Type": 0,
"URL": "http://cloud-3.steamusercontent.com/ugc/2024962321889555661/6643E5CC9160FF4624672C255D0DF7B313DA00A5/"
},
{
"Name": "SpeechBubble",
"Type": 0,
@ -244,6 +234,11 @@
"Type": 0,
"URL": "http://cloud-3.steamusercontent.com/ugc/2510267932886739653/CB7AA2D73777EF5938A6E6CD664B2ABA52B6E20A/"
},
{
"Name": "token-eldersign",
"Type": 0,
"URL": "http://cloud-3.steamusercontent.com/ugc/2540675016035917168/C0D6F531A85FD94C2F54825DFC50781B5B499A1D/"
},
{
"Name": "token-custom-token",
"Type": 0,

View File

@ -33,7 +33,7 @@
"IgnoreFoW": false,
"LayoutGroupSortIndex": 0,
"Locked": false,
"LuaScript": "",
"LuaScript": "require(\"playercards/cards/KohakuNarukami\")",
"LuaScriptState": "",
"MeasureMovement": false,
"Name": "Card",
@ -58,5 +58,5 @@
"scaleZ": 1.15
},
"Value": 0,
"XmlUI": ""
"XmlUI": "\u003cInclude src=\"playercards/KohakuNarukami.xml\"/\u003e"
}

View File

@ -31,12 +31,12 @@
{
"Name": "option_on",
"Type": 0,
"URL": "http://cloud-3.steamusercontent.com/ugc/2024962321889555728/22ABD35CBB49A001F3A5318E4AFCFB22D24FEA39/"
"URL": "http://cloud-3.steamusercontent.com/ugc/2462982115668997008/2178787B67B3C96F3419EDBAB8420E39893756BC/"
},
{
"Name": "option_off",
"Type": 0,
"URL": "http://cloud-3.steamusercontent.com/ugc/2024962321889555661/6643E5CC9160FF4624672C255D0DF7B313DA00A5/"
"URL": "http://cloud-3.steamusercontent.com/ugc/2462982115668996901/D6438ECBB11DECC6DB9987589FF526FBAD4D2368/"
}
],
"Description": "Cleans up the table for the next scenario during campaign play.\n\nThis includes moving cards and tokens into the trashcans, resetting counters and removing bless/curse tokens from the chaos bag.",

View File

@ -369,8 +369,8 @@ function tidyPlayerMatCoroutine()
if tekeliliHelper then
tekeliliHelper.call("spawnStoredTekelili", color)
end
::continue::
end
::continue::
end
-- mythos area cleanup

View File

@ -42,10 +42,11 @@ function onLoad(savedData)
color = { r = 0, g = 0, b = 0, a = 0 }
})
self.addContextMenuItem("toggle broadcasting", updateBroadcast)
self.addContextMenuItem("Toggle Broadcasting", updateBroadcast)
end
function updateBroadcast()
function updateBroadcast(playerColor)
Player[playerColor].clearSelectedObjects()
for _, tracker in ipairs(getObjectsWithTag("LinkedPhaseTracker")) do
tracker.setVar("broadcastChange", not broadcastChange)
end

View File

@ -124,22 +124,17 @@ function startSearch(messageColor, number)
end
-- get position and rotation for set aside cards
local handData = Player[handColor].getHandTransform()
local handCards = Player[handColor].getHandObjects()
setAsidePosition = handData.position + offset * handData.right
setAsideRotation = { handData.rotation.x, handData.rotation.y + 180, 180 }
local handData = Player[handColor].getHandTransform()
local handCards = Player[handColor].getHandObjects()
setAsidePosition = (handData.position + offset * handData.right):setAt("y", 1.5)
setAsideRotation = { handData.rotation.x, handData.rotation.y + 180, 180 }
-- set y-value
setAsidePosition.y = 1.5
for i = #handCards, 1, -1 do
handCards[i].setPosition(setAsidePosition + Vector(0, (#handCards - i) * 0.1, 0))
handCards[i].setRotation(setAsideRotation)
end
-- place hand cards set aside
deckLib.placeOrMergeIntoDeck(handCards, setAsidePosition, setAsideRotation)
-- handling for Norman Withers
if deckAreaObjects.topCard then
deckAreaObjects.topCard.flip()
deckAreaObjects.topCard.setRotation(setAsideRotation)
topCardDetected = true
end
@ -155,35 +150,36 @@ end
function endSearch(_, _, isRightClick)
local handCards = Player[handColor].getHandObjects()
local j = 0
for i = #handCards, 1, -1 do
j = j + 1
Wait.time(function() deckLib.placeOrMergeIntoDeck(handCards[i], drawDeckPosition, setAsideRotation) end, j * 0.1)
end
-- place cards on deck
deckLib.placeOrMergeIntoDeck(handCards, drawDeckPosition, setAsideRotation)
-- draw set aside cards (from the ground!)
Wait.time(drawSetAsideCards, 0.5 + #handCards * 0.1)
normalView()
Wait.time(function()
-- maybe shuffle deck
if not isRightClick then
local deckAreaObjects = playermatApi.getDeckAreaObjects(matColor)
if deckAreaObjects.draw then
deckAreaObjects.draw.shuffle()
end
end
-- Norman Withers handling
if topCardDetected then
playermatApi.flipTopCardFromDeck(matColor)
end
end, 1 + #handCards * 0.1)
end
function drawSetAsideCards()
for _, obj in ipairs(searchLib.atPosition(setAsidePosition, "isCardOrDeck")) do
local count = 1
if obj.type == "Deck" then
count = #obj.getObjects()
end
Wait.time(function() obj.deal(count, handColor) end, 1)
end
normalView()
-- delay is to wait for cards to enter deck
if not isRightClick then
Wait.time(function()
local deckAreaObjects = playermatApi.getDeckAreaObjects(matColor)
if deckAreaObjects.draw then
deckAreaObjects.draw.shuffle()
end
end, #handCards * 0.3 + 0.5)
end
-- Norman Withers handling
if topCardDetected then
Wait.time(function() playermatApi.flipTopCardFromDeck(matColor) end, #handCards * 0.3 + 0.75)
obj.deal(count, handColor)
end
end

View File

@ -32,7 +32,7 @@ function onload(savedData)
isSetup = false
movingCards = false
self.addContextMenuItem('Reset helper', resetHelper)
self.addContextMenuItem('Reset Helper', resetHelper)
if savedData and savedData ~= '' then
local loaded_data = JSON.decode(savedData)
@ -242,7 +242,8 @@ function finish()
0.75)
end
function resetHelper()
function resetHelper(playerColor)
Player[playerColor].clearSelectedObjects()
for i, card in ipairs(self.getObjects()) do
self.takeObject({
index = 0,
@ -269,7 +270,5 @@ function resetHelper()
isSetup = false
movingCards = false
self.reset()
print('Underworld Market Helper: Helper has been reset.')
end

View File

@ -266,6 +266,19 @@ function updateDisplayAndBroadcast(type)
end
end
function getBlessCurseInBag()
local numInBag = { Bless = 0, Curse = 0 }
local chaosBag = chaosBagApi.findChaosBag()
for _, v in ipairs(chaosBag.getObjects()) do
if v.name == "Bless" or v.name == "Curse" then
numInBag[v.name] = numInBag[v.name] + 1
end
end
return numInBag
end
---------------------------------------------------------
-- main functions: add and remove
---------------------------------------------------------

View File

@ -67,5 +67,9 @@ do
getManager().call("removeToken", type)
end
BlessCurseManagerApi.getBlessCurseInBag = function()
return getManager().call("getBlessCurseInBag", {})
end
return BlessCurseManagerApi
end

View File

@ -1,5 +1,6 @@
local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
local guidReferenceApi = require("core/GUIDReferenceApi")
local mythosAreaApi = require("core/MythosAreaApi")
local navigationOverlayApi = require("core/NavigationOverlayApi")
local optionPanelApi = require("core/OptionPanelApi")
local playermatApi = require("playermat/PlayermatApi")
@ -15,6 +16,7 @@ function onLoad()
addHotkey("Move card to Victory Display", moveCardToVictoryDisplay)
addHotkey("Place card into threat area", takeCardIntoThreatArea)
addHotkey("Remove a use", removeOneUse)
addHotkey("Reshuffle encounter deck", mythosAreaApi.reshuffleEncounterDeck)
addHotkey("Switch seat clockwise", switchSeatClockwise)
addHotkey("Switch seat counter-clockwise", switchSeatCounterClockwise)
addHotkey("Take clue from location", takeClueFromLocation)
@ -122,10 +124,15 @@ function takeCardIntoThreatArea(playerColor, hoveredObject)
end
end
-- discard the hovered object to the respective trashcan and discard tokens on it if it was a card
-- discard the hovered or selected objects to the respective trashcan and discard tokens on it if it was a card
function discardObject(playerColor, hoveredObject)
-- if more than one object is selected, discard them all, one at a time
local selectedObjects = Player[playerColor].getSelectedObjects()
if #selectedObjects > 0 then
discardGroup(playerColor, selectedObjects)
return
-- only continue if an unlocked card, deck or tile was hovered
if hoveredObject == nil
elseif 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")
@ -133,11 +140,15 @@ function discardObject(playerColor, hoveredObject)
end
-- These should probably not be discarded normally. Ask player for confirmation.
if hoveredObject.type == "Deck" or hoveredObject.hasTag("Location") then
local suspect = (hoveredObject.type == "Deck") and "Deck" or "Location"
Player[playerColor].showConfirmDialog("Discard " .. suspect .. "?",
function() performDiscard(playerColor, hoveredObject) end)
return
local tokenData = mythosAreaApi.returnTokenData()
local scenarioName = tokenData.currentScenario
if scenarioName ~= "Lost in Time and Space" and scenarioName ~= "The Secret Name" then
if hoveredObject.type == "Deck" or hoveredObject.hasTag("Location") then
local suspect = (hoveredObject.type == "Deck") and "Deck" or "Location"
Player[playerColor].showConfirmDialog("Discard " .. suspect .. "?",
function() performDiscard(playerColor, hoveredObject) end)
return
end
end
performDiscard(playerColor, hoveredObject)
@ -159,6 +170,18 @@ function performDiscard(playerColor, hoveredObject)
playermatApi.discardListOfObjects(discardForMatColor, discardTheseObjects)
end
function discardGroup(playerColor, selectedObjects)
local count = #selectedObjects
-- discarding one at a time avoids an error with cards in the discard pile losing the 'hands' toggle and uses multiple mats
for i = count, 1, -1 do
Wait.time(function()
if (selectedObjects[i].type == "Card" or selectedObjects[i].type ~= "Deck" or selectedObjects[i].type == "Tile") then
performDiscard(playerColor, selectedObjects[i])
end
end, (count - i + 1) * 0.1)
end
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
@ -282,8 +305,7 @@ function removeOneUse(playerColor, hoveredObject)
end
end
local playerName = Player[playerColor].steam_name
broadcastToAll(playerName .. " removed a token: " .. tokenName, playerColor)
broadcastToAll(getColoredName(playerColor) .. " removed a token: " .. tokenName, playerColor)
local discardForMatColor = getColorToDiscardFor(hoveredObject, playerColor)
playermatApi.discardListOfObjects(discardForMatColor, { targetObject })
@ -404,12 +426,10 @@ function takeClueFromLocation(playerColor, hoveredObject)
local clickableClues = optionPanelApi.getOptions()["useClueClickers"]
-- handling for calling this for a specific mat via hotkey
local playerName, matColor, pos
local matColor, pos
if Player[playerColor] and Player[playerColor].seated then
playerName = Player[playerColor].steam_name
matColor = playermatApi.getMatColor(playerColor)
else
playerName = playerColor
matColor = playerColor
end
@ -431,9 +451,9 @@ function takeClueFromLocation(playerColor, hoveredObject)
end
if cardName then
broadcastToAll(playerName .. " took one clue from " .. cardName .. ".", "White")
broadcastToAll(getColoredName(playerColor) .. " took one clue from " .. cardName .. ".", "White")
else
broadcastToAll(playerName .. " took one clue.", "White")
broadcastToAll(getColoredName(playerColor) .. " took one clue.", "White")
end
victoryDisplayApi.update()
@ -472,3 +492,14 @@ function getFirstSeatedPlayer()
return color
end
end
-- returns the colored steam name or color
function getColoredName(playerColor)
local displayName = playerColor
if Player[playerColor].steam_name then
displayName = Player[playerColor].steam_name
end
-- add bb-code
return "[" .. Color.fromString(playerColor):toHex() .. "]" .. displayName .. "[-]"
end

View File

@ -199,14 +199,20 @@ function onObjectEnterZone(zone, object)
local matcolor = playermatApi.getMatColorByPosition(object.getPosition())
local trash = guidReferenceApi.getObjectByOwnerAndType(matcolor, "Trash")
trash.putObject(object)
elseif zone.type == "Hand" and object.hasTag("CardWithHelper") then
object.clearContextMenu()
object.call("shutOff")
elseif zone.type == "Hand" and object.type == "Card" then
if object.is_face_down then
object.flip()
end
if object.hasTag("CardWithHelper") then
object.clearContextMenu()
object.call("shutOff")
end
end
end
-- TTS event for objects that leave zones
function onObjectLeaveZone(zone, object)
if zone.isDestroyed() or object.isDestroyed() then return end
if zone.type == "Hand" and object.hasTag("CardWithHelper") then
object.call("updateDisplay")
end
@ -238,6 +244,23 @@ function onObjectNumberTyped(hoveredObject, playerColor, number)
end
end
-- TTS event, used to redraw the playermat slot symbols after a small delay to account for the custom font loading
function onPlayerConnect()
Wait.time(function() playermatApi.redrawSlotSymbols("All") end, 0.2)
end
function onPlayerAction(player, action, targets)
if action == Player.Action.Delete and player.admin == false then
for _, target in ipairs(targets) do
local matColor = playermatApi.getMatColorByPosition(target.getPosition())
local trash = guidReferenceApi.getObjectByOwnerAndType(matColor, "Trash")
trash.putObject(target)
end
return false
end
return true
end
---------------------------------------------------------
-- chaos token drawing
---------------------------------------------------------
@ -1443,7 +1466,7 @@ function onClick_toggleOption(_, _, id)
local currentState = optionPanel[id]
local newState = not currentState
applyOptionPanelChange(id, newState)
UI.setAttribute(id, "image", newState and "option-on" or "option-off")
UI.setAttribute(id, "image", newState and "option_on" or "option_off")
end
-- color selection for playArea
@ -1537,9 +1560,9 @@ function updateOptionPanelState()
elseif (type(optionValue) == "boolean" and optionValue)
or (type(optionValue) == "string" and optionValue)
or (type(optionValue) == "table" and #optionValue ~= 0) then
UI.setAttribute(id, "image", "option-on")
UI.setAttribute(id, "image", "option_on")
else
UI.setAttribute(id, "image", "option-off")
UI.setAttribute(id, "image", "option_off")
end
end
end

View File

@ -78,7 +78,7 @@ function onCollisionEnter(collisionInfo)
local localPos = self.positionToLocal(object.getPosition())
if inArea(localPos, ENCOUNTER_DECK_AREA) or inArea(localPos, ENCOUNTER_DISCARD_AREA) then
Wait.frames(function() tokenSpawnTrackerApi.resetTokensSpawned(object.getGUID()) end, 1)
Wait.frames(function() tokenSpawnTrackerApi.resetTokensSpawned(object) end, 1)
removeTokensFromObject(object)
end
end
@ -100,7 +100,7 @@ end
function onObjectEnterContainer(container, object)
local localPos = self.positionToLocal(container.getPosition())
if inArea(localPos, ENCOUNTER_DECK_AREA) or inArea(localPos, ENCOUNTER_DISCARD_AREA) then
tokenSpawnTrackerApi.resetTokensSpawned(object.getGUID())
tokenSpawnTrackerApi.resetTokensSpawned(object)
removeTokensFromObject(object)
end
end

View File

@ -202,6 +202,7 @@ end
function addContextMenu()
self.addContextMenuItem("Change color", function(playerColor)
Player[playerColor].clearSelectedObjects()
local currentClassDisplayName = listOfClassDisplayNames[getIndexOfValue(listOfClasses, class)]
Player[playerColor].showOptionsDialog("Choose color", listOfClassDisplayNames, currentClassDisplayName,
function(_, selectedIndex)
@ -210,6 +211,7 @@ function addContextMenu()
end)
self.addContextMenuItem("Change 1st symbol", function(playerColor)
Player[playerColor].clearSelectedObjects()
local symbolList = getSymbolList()
Player[playerColor].showOptionsDialog("Choose symbol", listOfSymbols, symbolList[1], function(newSymbol)
if newSymbol == "None" then
@ -229,6 +231,7 @@ function addContextMenu()
end)
self.addContextMenuItem("Change 2nd symbol", function(playerColor)
Player[playerColor].clearSelectedObjects()
local symbolList = getSymbolList()
Player[playerColor].showOptionsDialog("Choose 2nd symbol", listOfSymbols, symbolList[2] or symbolList[1],
function(newSymbol)

View File

@ -1,7 +1,8 @@
local searchLib = require("util/SearchLib")
local chaosBagApi = require("chaosbag/ChaosBagApi")
local deckLib = require("util/DeckLib")
local guidReferenceApi = require("core/GUIDReferenceApi")
local playAreaApi = require("core/PlayAreaApi")
local searchLib = require("util/SearchLib")
local tokenChecker = require("core/token/TokenChecker")
local pendingCall = false
@ -234,28 +235,30 @@ end
-- places the provided card in the first empty spot
function placeCard(card)
local trash = guidReferenceApi.getObjectByOwnerAndType("Mythos", "Trash")
local name = card.getName() or "Unnamed card"
-- check snap point states
-- get sorted list of snap points to check slots
local snaps = self.getSnapPoints()
table.sort(snaps, function(a, b) return a.position.x > b.position.x end)
table.sort(snaps, function(a, b) return a.position.z < b.position.z end)
-- get first empty slot
local fullSlots = {}
local positions = {}
local emptyIndex, emptyPos
for i, snap in ipairs(snaps) do
positions[i] = self.positionToWorld(snap.position)
local searchResult = searchLib.atPosition(positions[i], "isCardOrDeck")
fullSlots[i] = #searchResult > 0
local snapPos = self.positionToWorld(snap.position)
local searchResult = searchLib.atPosition(snapPos, "isCardOrDeck")
if #searchResult == 0 then
emptyPos = snapPos
emptyIndex = i
break
end
end
-- remove tokens from the card
for _, obj in ipairs(searchLib.onObject(card)) do
-- don't touch decks / cards
if obj.type == "Deck" or obj.type == "Card" then
local trash = guidReferenceApi.getObjectByOwnerAndType("Mythos", "Trash")
for _, obj in ipairs(searchLib.onObject(card, "isTileOrToken")) do
if tokenChecker.isChaosToken(obj) then
-- put chaos tokens back into bag
elseif tokenChecker.isChaosToken(obj) then
local chaosBag = chaosBagApi.findChaosBag()
chaosBag.putObject(obj)
elseif obj.memo ~= nil and obj.getLock() == false then
@ -263,18 +266,15 @@ function placeCard(card)
end
end
-- place the card
local name = card.getName() or "Unnamed card"
for i = 1, 10 do
if fullSlots[i] ~= true then
local rot = { 0, 270, card.getRotation().z }
card.setPositionSmooth(positions[i], false, true)
card.setRotation(rot)
broadcastToAll("Victory Display: " .. name .. " placed into slot " .. i .. ".", "Green")
return
end
end
-- use the first snap position in case all slots are full
local pos = emptyPos or self.positionToWorld(snaps[1].position)
local rot = card.getRotation():setAt("x", 0):setAt("y", 270)
deckLib.placeOrMergeIntoDeck(card, pos, rot)
broadcastToAll("Victory Display is full! " .. name .. " placed into slot 1.", "Orange")
card.setPositionSmooth(positions[1], false, true)
-- give a feedback message
if emptyPos then
broadcastToAll("Victory Display: " .. name .. " placed into slot " .. emptyIndex .. ".", "Green")
else
broadcastToAll("Victory Display is full! " .. name .. " placed into slot 1.", "Orange")
end
end

View File

@ -211,10 +211,11 @@ do
if tokenType == "clue" then
offsets = internal.buildClueOffsets(card, tokenCount)
else
-- only up to 12 offset tables defined (TODO: stack more than 12 tokens and generate offsets dynamically)
-- only up to 12 offset tables defined
if tokenCount > 12 then
printToAll("Spawning maximum of 12 tokens.")
tokenCount = 12
printToAll("Attempting to spawn " .. tokenCount .. " tokens. Spawning clickable counter instead.")
TokenManager.spawnResourceCounterToken(card, tokenCount)
return
end
for i = 1, tokenCount do
offsets[i] = card.positionToWorld(PLAYER_CARD_TOKEN_OFFSETS[tokenCount][i])
@ -297,20 +298,13 @@ do
-- Checks a card for metadata to maybe replenish it
---@param card tts__Object Card object to be replenished
---@param uses table The already decoded metadata.uses (to avoid decoding again)
---@param mat tts__Object The playermat the card is placed on (for rotation and casting)
TokenManager.maybeReplenishCard = function(card, uses, mat)
TokenManager.maybeReplenishCard = function(card, uses)
-- TODO: support for cards with multiple uses AND replenish (as of yet, no official card needs that)
if uses[1].count and uses[1].replenish then
internal.replenishTokens(card, uses, mat)
internal.replenishTokens(card, uses)
end
end
-- Delegate function to the token spawn tracker. Exists to avoid circular dependencies in some callers
---@param card tts__Object Card object to reset the tokens for
TokenManager.resetTokensSpawned = function(card)
tokenSpawnTrackerApi.resetTokensSpawned(card.getGUID())
end
-- Pushes new player card data into the local copy of the Data Helper player data.
---@param dataTable table Key/Value pairs following the DataHelper style
TokenManager.addPlayerCardData = function(dataTable)
@ -483,16 +477,16 @@ do
---@param card tts__Object Card object to be replenished
---@param uses table The already decoded metadata.uses (to avoid decoding again)
---@param mat tts__Object The playermat the card is placed on (for rotation and casting)
internal.replenishTokens = function(card, uses, mat)
-- get current amount of resource tokens on the card
internal.replenishTokens = function(card, uses)
-- get current amount of matching resource tokens on the card
local clickableResourceCounter = nil
local foundTokens = 0
local searchType = string.lower(uses[1].type)
for _, obj in ipairs(searchLib.onObject(card, "isTileOrToken")) do
local memo = obj.getMemo()
if (stateTable[memo] or 0) > 0 then
if searchType == memo then
foundTokens = foundTokens + math.abs(obj.getQuantity())
obj.destruct()
elseif memo == "resourceCounter" then

View File

@ -22,8 +22,8 @@ function markTokensSpawned(cardGuid)
spawnedCardGuids[cardGuid] = true
end
function resetTokensSpawned(cardGuid)
spawnedCardGuids[cardGuid] = nil
function resetTokensSpawned(card)
spawnedCardGuids[card.getGUID()] = nil
end
function resetAll() spawnedCardGuids = {} end
@ -52,6 +52,6 @@ end
-- Listener to reset card token spawns when they enter a hand.
function onObjectEnterZone(zone, enterObject)
if zone.type == "Hand" and enterObject.type == "Card" then
resetTokensSpawned(enterObject.getGUID())
resetTokensSpawned(enterObject)
end
end

View File

@ -14,8 +14,8 @@ do
return getSpawnTracker().call("markTokensSpawned", cardGuid)
end
TokenSpawnTracker.resetTokensSpawned = function(cardGuid)
return getSpawnTracker().call("resetTokensSpawned", cardGuid)
TokenSpawnTracker.resetTokensSpawned = function(card)
return getSpawnTracker().call("resetTokensSpawned", card)
end
TokenSpawnTracker.resetAllAssetAndEvents = function()

View File

@ -63,9 +63,8 @@ function onLoad(savedData)
local loadedData = JSON.decode(savedData)
isHelperEnabled = loadedData.isHelperEnabled
end
checkOptionPanel()
createHelperXML()
updateDisplay()
checkOptionPanel()
end
function createHelperXML()

View File

@ -5,6 +5,8 @@ function checkOptionPanel()
local options = optionPanelApi.getOptions()
if options.enableCardHelpers then
setHelperState(true)
else
updateDisplay()
end
end

View File

@ -5,7 +5,8 @@ function onLoad()
end
-- rotates the alt_view_angle
function rotatePreview()
function rotatePreview(playerColor)
Player[playerColor].clearSelectedObjects()
local angle = self.alt_view_angle
if angle.y == 0 then
angle.y = 180
@ -16,7 +17,7 @@ function rotatePreview()
end
-- rotates this card and the preview
function rotateSelfAndPreview()
function rotateSelfAndPreview(playerColor)
self.setRotationSmooth(self.getRotation() + Vector(0, 180, 0))
rotatePreview()
rotatePreview(playerColor)
end

View File

@ -1,9 +1,11 @@
require("playercards/CardsWithHelper")
local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
local chaosBagApi = require("chaosbag/ChaosBagApi")
local guidReferenceApi = require("core/GUIDReferenceApi")
local playermatApi = require("playermat/PlayermatApi")
local isHelperEnabled = false
local updated
function updateSave()
self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled })
@ -16,7 +18,6 @@ function onLoad(savedData)
isHelperEnabled = loadedData.isHelperEnabled
end
checkOptionPanel()
updateDisplay()
end
-- hide buttons and stop monitoring
@ -35,6 +36,7 @@ function initialize()
end
function resolveToken(player, _, tokenType)
if not updated then return end
local matColor
if player.color == "Black" then
matColor = playermatApi.getMatColorByPosition(self.getPosition())
@ -44,11 +46,13 @@ function resolveToken(player, _, tokenType)
local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")
chaosBagApi.drawChaosToken(mat, true, tokenType)
updated = false
Wait.frames(maybeUpdateButtonState, 2)
end
-- count tokens in the bag and show appropriate buttons
function maybeUpdateButtonState()
local numInBag = getBlessCurseInBag()
local numInBag = blessCurseManagerApi.getBlessCurseInBag()
local state = { Bless = false, Curse = false }
if numInBag.Bless >= numInBag.Curse and numInBag.Bless > 0 then
@ -60,19 +64,7 @@ function maybeUpdateButtonState()
end
setUiState(state)
end
function getBlessCurseInBag()
local numInBag = { Bless = 0, Curse = 0 }
local chaosBag = chaosBagApi.findChaosBag()
for _, v in ipairs(chaosBag.getObjects()) do
if v.name == "Bless" or v.name == "Curse" then
numInBag[v.name] = numInBag[v.name] + 1
end
end
return numInBag
updated = true
end
function setUiState(params)
@ -88,7 +80,7 @@ function setUiState(params)
end
function errorMessage()
local numInBag = getBlessCurseInBag()
local numInBag = blessCurseManagerApi.getBlessCurseInBag()
if numInBag.Bless == 0 and numInBag.Curse == 0 then
broadcastToAll("There are no Bless or Curse tokens in the chaos bag.", "Red")

View File

@ -46,7 +46,6 @@ function onLoad(savedData)
activeButtonIndex = loadedData.activeButtonIndex
end
checkOptionPanel()
updateDisplay()
if activeButtonIndex > 0 then
selectButton(activeButtonIndex)
@ -89,6 +88,7 @@ function createButtons()
local upgradeSheet = findUpgradeSheet()
if upgradeSheet then
for i = 1, 4 do
log(4)
if upgradeSheet.call("isUpgradeActive", i) then
table.insert(hypothesisList, customizableList[i])
end
@ -110,7 +110,7 @@ end
function findUpgradeSheet()
local matColor = playermatApi.getMatColorByPosition(self.getPosition())
local result = playermatApi.searchAroundPlaymat(matColor, "isCard")
local result = playermatApi.searchAroundPlayermat(matColor, "isCard")
for j, card in ipairs(result) do
local metadata = JSON.decode(card.getGMNotes()) or {}
if metadata.id == "09041-c" then

View File

@ -6,9 +6,21 @@ local clickableResourceCounter = nil
local foundTokens = 0
function onLoad()
self.addContextMenuItem("Add 4 resources", function(playerColor) add4(playerColor) end)
self.addContextMenuItem("Take all resources", function(playerColor) takeAll(playerColor) end)
self.addContextMenuItem("Discard all resources", function(playerColor) loseAll(playerColor) end)
self.addContextMenuItem("Add 4 resources",
function(playerColor)
Player[playerColor].clearSelectedObjects()
add4(playerColor)
end)
self.addContextMenuItem("Take all resources",
function(playerColor)
Player[playerColor].clearSelectedObjects()
takeAll(playerColor)
end)
self.addContextMenuItem("Discard all resources",
function(playerColor)
Player[playerColor].clearSelectedObjects()
loseAll(playerColor)
end)
end
function searchSelf()
@ -35,12 +47,7 @@ function add4(playerColor)
if clickableResourceCounter then
clickableResourceCounter.call("updateVal", newCount)
else
if newCount > 12 then
printToColor("Count increased to " .. newCount .. " resources. Spawning clickable counter instead.", playerColor)
tokenManager.spawnResourceCounterToken(self, newCount)
else
tokenManager.spawnTokenGroup(self, "resource", newCount)
end
tokenManager.spawnTokenGroup(self, "resource", newCount)
end
end

View File

@ -0,0 +1,147 @@
require("playercards/CardsWithHelper")
local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
local guidReferenceApi = require("core/GUIDReferenceApi")
local playermatApi = require("playermat/PlayermatApi")
local searchLib = require("util/SearchLib")
local tokenManager = require("core/token/TokenManager")
local isHelperEnabled = false
local updated
local xmlData = {
Action = { color = "#6D202CE6", onClick = "removeAndExtraAction" },
Bless = { color = "#9D702CE6", onClick = "addTokenToBag" },
Curse = { color = "#633A84E6", onClick = "addTokenToBag" },
ElderSign = { color = "#50A8CEE6", onClick = "elderSignAbility" }
}
function updateSave()
self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled })
end
function onLoad(savedData)
self.addTag("CardWithHelper")
if savedData and savedData ~= "" then
local loadedData = JSON.decode(savedData)
isHelperEnabled = loadedData.isHelperEnabled
end
checkOptionPanel()
end
-- hide buttons and stop monitoring
function shutOff()
self.UI.hide("Helper")
Wait.stopAll()
updateSave()
end
-- show buttons and begin monitoring chaos bag for curse and bless tokens
function initialize()
self.UI.show("Helper")
maybeUpdateButtonState()
Wait.time(maybeUpdateButtonState, 1, -1)
updateSave()
end
function addTokenToBag(_, _, tokenType)
if not updated then return end
blessCurseManagerApi.addToken(tokenType)
updated = false
Wait.frames(maybeUpdateButtonState, 2)
end
function removeAndExtraAction()
if not updated then return end
blessCurseManagerApi.removeToken("Bless")
blessCurseManagerApi.removeToken("Bless")
blessCurseManagerApi.removeToken("Curse")
blessCurseManagerApi.removeToken("Curse")
updated = false
Wait.frames(maybeUpdateButtonState, 2)
local position = self.getPosition()
local matColor = playermatApi.getMatColorByPosition(position)
local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")
local rotation = mat.getRotation()
-- find empty action token slots by checking snap points
local snaps = mat.getSnapPoints()
-- get first empty slot in the top row (so the second empty slot because of the ability token)
local emptyPos = position -- default to card position
for i, snap in ipairs(snaps) do
if i > 1 then
if snap.tags[1] == "UniversalToken" then
local snapPos = mat.positionToWorld(snap.position)
local searchResult = searchLib.atPosition(snapPos, "isUniversalToken")
if #searchResult == 0 then
emptyPos = snapPos
break
end
end
end
end
callback = function(spawned)
spawned.call("updateClassAndSymbol", { class = "Mystic", symbol = "Mystic" })
spawned.addTag("Temporary")
end
tokenManager.spawnToken(emptyPos + Vector(0, 0.7, 0), "universalActionAbility", rotation, callback)
end
function elderSignAbility()
blessCurseManagerApi.addToken("Bless")
blessCurseManagerApi.addToken("Curse")
updated = false
Wait.frames(maybeUpdateButtonState, 2)
end
-- count tokens in the bag and show appropriate buttons
function maybeUpdateButtonState()
local numInBag = blessCurseManagerApi.getBlessCurseInBag()
local state = { Bless = false, Curse = false, Action = false, ElderSign = false }
if numInBag.Bless <= numInBag.Curse and numInBag.Bless < 10 then
state.Bless = true
state.ElderSign = true
end
if numInBag.Curse <= numInBag.Bless and numInBag.Curse < 10 then
state.Curse = true
state.ElderSign = true
end
if numInBag.Curse >= 2 and numInBag.Bless >= 2 then
state.Action = true
end
setUiState(state)
updated = true
end
function setUiState(params)
for buttonId, state in pairs(params) do
if state then
self.UI.setAttribute(buttonId, "color", xmlData[buttonId].color)
self.UI.setAttribute(buttonId, "onClick", xmlData[buttonId].onClick)
self.UI.setAttribute(buttonId, "textColor", "white")
else
self.UI.setAttribute(buttonId, "color", "#353535E6")
self.UI.setAttribute(buttonId, "onClick", "errorMessage")
self.UI.setAttribute(buttonId, "textColor", "#A0A0A0")
end
end
end
function errorMessage(_, _, triggeringButton)
local numInBag = blessCurseManagerApi.getBlessCurseInBag()
if triggeringButton == "Action" then
broadcastToAll("There are not enough Blesses and/or Curses in the chaos bag.", "Red")
elseif numInBag.Bless == 10 and numInBag.Curse == 10 then
broadcastToAll("No more tokens can be added to the chaos bag.", "Red")
elseif numInBag.Bless < numInBag.Curse then
broadcastToAll("There are more Bless tokens than Curse tokens in the chaos bag.", "Red")
else
broadcastToAll("There are more Curse tokens than Bless tokens in the chaos bag.", "Red")
end
end

View File

@ -61,6 +61,7 @@ end
-- Create dialog window to choose sigil and create sigil-drawing button
function chooseSigil(playerColor)
Player[playerColor].clearSelectedObjects()
self.clearContextMenu()
self.addContextMenuItem("Clear Helper", deleteButtons)
@ -80,7 +81,8 @@ function chooseSigil(playerColor)
end
-- Delete button and remove sigil
function deleteButtons()
function deleteButtons(playerColor)
Player[playerColor].clearSelectedObjects()
self.clearContextMenu()
self.addContextMenuItem("Enable Helper", chooseSigil)
self.UI.setXml("")

View File

@ -17,6 +17,7 @@ function onLoad()
end
function contextFunc(playerColor, amount)
Player[playerColor].clearSelectedObjects()
deckData = {}
local options = {}

View File

@ -5,7 +5,8 @@ function onLoad()
end
-- called by context menu entry
function shortSupply(color)
function shortSupply(playerColor)
Player[playerColor].clearSelectedObjects()
local matColor = playermatApi.getMatColorByPosition(self.getPosition())
-- get draw deck and discard position
@ -15,20 +16,20 @@ function shortSupply(color)
-- error handling
if discardPos == nil then
broadcastToColor("Couldn't retrieve discard position from playermat!", color, "Red")
broadcastToColor("Couldn't retrieve discard position from playermat!", playerColor, "Red")
return
end
if drawDeck == nil then
broadcastToColor("Deck not found!", color, "Yellow")
broadcastToColor("Deck not found!", playerColor, "Yellow")
return
elseif drawDeck.type ~= "Deck" then
broadcastToColor("Deck only contains a single card!", color, "Yellow")
broadcastToColor("Deck only contains a single card!", playerColor, "Yellow")
return
end
-- discard cards, waiting 0.7 seconds between each discard to give players visiblity of the cards
broadcastToColor("Discarding top 10 cards for player color '" .. matColor .. "'.", color, "White")
broadcastToColor("Discarding top 10 cards for player color '" .. matColor .. "'.", playerColor, "White")
for i = 1, 10 do
Wait.time(function() drawDeck.takeObject({ flip = true, position = { discardPos.x, 2 + 0.075 * i, discardPos.z } }) end, .7 * (i - 1))
end

View File

@ -7,7 +7,8 @@ function onLoad()
end
-- uses the tekeli-li helper to place this card at the bottom of the deck
function returnSelf()
function returnSelf(playerColor)
Player[playerColor].clearSelectedObjects()
local helper = getTekeliliHelper()
if helper == nil then
printToAll("Couldn't find Tekeli-li Helper!")
@ -18,6 +19,7 @@ end
-- places this card below the deck of the player that triggered it
function placeBelowDeck(playerColor)
Player[playerColor].clearSelectedObjects()
local matColor = playermatApi.getMatColor(playerColor)
local deckPos = playermatApi.getDrawPosition(matColor)
local deckRot = playermatApi.returnRotation(matColor)

View File

@ -6,6 +6,7 @@ local navigationOverlayApi = require("core/NavigationOverlayApi")
local searchLib = require("util/SearchLib")
local tokenChecker = require("core/token/TokenChecker")
local tokenManager = require("core/token/TokenManager")
local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi")
-- option panel data
local availableOptions = {
@ -75,12 +76,12 @@ local buttonParameters = {
-- table of texture URLs
local nameToTexture = {
Guardian = "http://cloud-3.steamusercontent.com/ugc/2444972799638881117/169F4520A94FB186B54E0F2BF4BAC809844C923E/",
Mystic = "http://cloud-3.steamusercontent.com/ugc/2444972799638880413/B59966123EA41649EDCBD614167E590C8C105582/",
Guardian = "http://cloud-3.steamusercontent.com/ugc/2501268517203536128/853B9CD08FC14A8B2A08C73D8ED77E0FE235CCCB/",
Mystic = "http://cloud-3.steamusercontent.com/ugc/2501268517203536470/11C99488B9CA9236059A5F02E4A852A7C77B42A6/",
Neutral = "http://cloud-3.steamusercontent.com/ugc/2462982115659543571/5D778EA4BC682DAE97E8F59A991BCF8CB3979B04/",
Rogue = "http://cloud-3.steamusercontent.com/ugc/2444972799638880905/CFC02BF5A6140B9B4B92312AD6DC74D8DD61180B/",
Seeker = "http://cloud-3.steamusercontent.com/ugc/2444972799638881117/169F4520A94FB186B54E0F2BF4BAC809844C923E/",
Survivor = "http://cloud-3.steamusercontent.com/ugc/2444972799638880687/EEDF8F8BC3266069FECB09775845BE2501310C17/"
Rogue = "http://cloud-3.steamusercontent.com/ugc/2501268517203536767/587791B327255DB8F953B27BB9E4DE602FA32B64/",
Seeker = "http://cloud-3.steamusercontent.com/ugc/2501268517203537098/EFD9FC4CCDB105EFFDFF7A57C915CD984865760D/",
Survivor = "http://cloud-3.steamusercontent.com/ugc/2501268517203537426/14EF780606D9A449F31A007226CB48D05AA820FF/"
}
-- translation table for slot names to characters for special font
@ -325,7 +326,9 @@ function doUpkeep(_, clickedByColor, isRightClick)
local forcedLearning = false
local rot = self.getRotation()
for _, obj in ipairs(searchAroundSelf()) do
if obj.hasTag("UniversalToken") == true and obj.is_face_down then
if obj.hasTag("Temporary") == true then
discardListOfObjects({ obj })
elseif obj.hasTag("UniversalToken") == true and obj.is_face_down then
obj.flip()
elseif obj.type == "Card" and not inArea(self.positionToLocal(obj.getPosition()), INVESTIGATOR_AREA) then
local cardMetadata = JSON.decode(obj.getGMNotes()) or {}
@ -355,7 +358,7 @@ function doUpkeep(_, clickedByColor, isRightClick)
end
-- maybe replenish uses on certain cards (don't continue for cards on the deck (Norman) or in the discard pile)
if cardMetadata.uses ~= nil and self.positionToLocal(obj.getPosition()).x < -1 then
if cardMetadata.uses ~= nil and self.positionToLocal(obj.getPosition()).x > -1 then
tokenManager.maybeReplenishCard(obj, cardMetadata.uses, self)
end
elseif obj.type == "Deck" and forcedLearning == false then
@ -399,34 +402,29 @@ function doUpkeep(_, clickedByColor, isRightClick)
local handCards = Player[playerColor].getHandObjects()
local cardsToDiscard = {}
for i = 1, #handCards do
local metadata = JSON.decode(handCards[i].getGMNotes())
if metadata ~= nil and (not metadata.weakness and not metadata.hidden) then
table.insert(cardsToDiscard, handCards[i])
for _, card in ipairs(handCards) do
local md = JSON.decode(card.getGMNotes())
if md ~= nil and (not md.weakness and not md.hidden and md.type ~= "Enemy") then
table.insert(cardsToDiscard, card)
end
end
-- perform discarding 1 by 1
local pos = returnGlobalDiscardPosition()
local count = #cardsToDiscard
for i = count, 1, -1 do
Wait.time(function() deckLib.placeOrMergeIntoDeck(cardsToDiscard[i], pos, rot) end, (count - i + 1) * 0.1)
end
deckLib.placeOrMergeIntoDeck(cardsToDiscard, pos, self.getRotation())
-- add some time if there are any cards to discard, if not, draw up to 5 immediately
local k = 0
if count > 0 then
k = 0.7 + (count * 0.1)
end
-- draw up to 5 cards
local cardsToDraw = 5 - #handCards + #cardsToDiscard
if cardsToDraw > 0 then
printToColor("Discarding " .. #cardsToDiscard .. " and drawing " .. cardsToDraw .. " card(s). (Patrice)", messageColor)
Wait.time(function()
local handSize = #Player[playerColor].getHandObjects()
if handSize < 5 then
local cardsToDraw = 5 - handSize
printToColor("Drawing " .. cardsToDraw .. " cards (Patrice)", messageColor)
drawCardsWithReshuffle(cardsToDraw)
-- add some time if there are any cards to discard
local k = 0
if #cardsToDiscard > 0 then
k = 0.8 + (#cardsToDiscard * 0.1)
end
end, k)
Wait.time(function() drawCardsWithReshuffle(cardsToDraw) end, k)
end
end
elseif forcedLearning then
printToColor("Drawing 2 cards, discard 1 (Forced Learning)", messageColor)
@ -585,9 +583,8 @@ function doDiscardOne()
-- get a random non-hidden card (from the "choices" table)
local num = math.random(1, #choices)
deckLib.placeOrMergeIntoDeck(hand[choices[num]], returnGlobalDiscardPosition(), self.getRotation())
local playerName = Player[playerColor].steam_name or playerColor
broadcastToAll(playerName .. " randomly discarded card " .. choices[num] .. "/" .. #hand .. ".", "White")
broadcastToAll(getColoredName(playerColor) .. " randomly discarded card "
.. choices[num] .. "/" .. #hand .. ".", "White")
end
end
@ -974,7 +971,7 @@ function onCollisionEnter(collisionInfo)
local localCardPos = self.positionToLocal(object.getPosition())
if inArea(localCardPos, DECK_DISCARD_AREA) then
tokenManager.resetTokensSpawned(object)
tokenSpawnTrackerApi.resetTokensSpawned(object)
removeTokensFromObject(object)
elseif shouldSpawnTokens(object) then
spawnTokensFor(object)
@ -1018,7 +1015,7 @@ function onObjectEnterContainer(container, object)
local localCardPos = self.positionToLocal(object.getPosition())
if inArea(localCardPos, DECK_DISCARD_AREA) then
tokenManager.resetTokensSpawned(object)
tokenSpawnTrackerApi.resetTokensSpawned(object)
removeTokensFromObject(object)
end
end
@ -1397,3 +1394,14 @@ function updatePlayerCards(args)
local playerCardData = customDataHelper.getTable("PLAYER_CARD_DATA")
tokenManager.addPlayerCardData(playerCardData)
end
-- returns the colored steam name or color
function getColoredName(playerColor)
local displayName = playerColor
if Player[playerColor].steam_name then
displayName = Player[playerColor].steam_name
end
-- add bb-code
return "[" .. Color.fromString(playerColor):toHex() .. "]" .. displayName .. "[-]"
end

View File

@ -2,23 +2,33 @@ do
local DeckLib = {}
local searchLib = require("util/SearchLib")
-- places a card/deck at a position or merges into an existing deck
---@param obj tts__Object Object to move
-- places a card/deck at a position or merges into an existing deck below
---@param objOrTable tts__Object|table Object or table of objects to move
---@param pos table New position for the object
---@param rot? table New rotation for the object
---@param below? boolean Should the object be placed below an existing deck?
DeckLib.placeOrMergeIntoDeck = function(obj, pos, rot, below)
if obj == nil or pos == nil then return end
DeckLib.placeOrMergeIntoDeck = function(objOrTable, pos, rot, below)
if objOrTable == nil or pos == nil then return end
-- handle 'objOrTable' parameter
local objects = {}
if type(objOrTable) == "table" then
objects = objOrTable
else
table.insert(objects, objOrTable)
end
-- search the new position for existing card/deck
local searchResult = searchLib.atPosition(pos, "isCardOrDeck")
local targetObj
-- get new position
local offset = 0.5
local newPos = Vector(pos) + Vector(0, offset, 0)
if #searchResult == 1 then
local bounds = searchResult[1].getBounds()
targetObj = searchResult[1]
local bounds = targetObj.getBounds()
if below then
newPos = Vector(pos):setAt("y", bounds.center.y - bounds.size.y / 2)
else
@ -26,25 +36,39 @@ do
end
end
-- allow moving the objects smoothly out of the hand
obj.use_hands = false
-- process objects in reverse order
for i = #objects, 1, -1 do
local obj = objects[i]
-- add a 0.1 delay for each object (for animation purposes)
Wait.time(function()
-- allow moving smoothly out of hand and temporarily lock it
obj.setLock(true)
obj.use_hands = false
if rot then
obj.setRotationSmooth(rot, false, true)
if rot then
obj.setRotationSmooth(rot, false, true)
end
obj.setPositionSmooth(newPos, false, true)
-- wait for object to finish movement (or 2 seconds)
Wait.condition(
function()
-- revert toggles
obj.setLock(false)
obj.use_hands = true
-- use putObject to avoid a TTS bug that merges unrelated cards that are not resting
if #searchResult == 1 and targetObj ~= obj and not targetObj.isDestroyed() and not obj.isDestroyed() then
targetObj = targetObj.putObject(obj)
else
targetObj = obj
end
end,
-- check state of the object (make sure it's not moving)
function() return obj.isDestroyed() or not obj.isSmoothMoving() end,
2)
end, (#objects- i) * 0.1)
end
obj.setPositionSmooth(newPos, false, true)
-- continue if the card stops smooth moving
Wait.condition(
function()
obj.use_hands = true
-- this avoids a TTS bug that merges unrelated cards that are not resting
if #searchResult == 1 and searchResult[1] ~= obj then
-- call this with avoiding errors (physics is sometimes too fast so the object doesn't exist for the put)
pcall(function() searchResult[1].putObject(obj) end)
end
end,
function() return not obj.isSmoothMoving() end, 3)
end
return DeckLib

View File

@ -62,7 +62,7 @@
<Panel class="doubleColumn-wrapper"
padding="0 17 3 3"/>
<Button class="optionToggle"
image="option-off"
image="option_off"
rectAlignment="MiddleRight"
offsetXY="-30 0"
colors="#FFFFFF|#dfdfdf"

View File

@ -1,25 +1,54 @@
<!-- Default formatting -->
<Defaults>
<Text color="black" alignment="MiddleLeft"/>
<Text class="h1" fontSize="160" font="font_teutonic-arkham"/>
<Text class="h2" fontSize="120" font="font_teutonic-arkham"/>
<Text class="p" fontSize="60" alignment="UpperLeft"/>
<Text color="black"
alignment="MiddleLeft"/>
<Text class="h1"
fontSize="160"
font="font_teutonic-arkham"/>
<Text class="h2"
fontSize="120"
font="font_teutonic-arkham"/>
<Text class="p"
fontSize="60"
alignment="UpperLeft"/>
<Panel rotation="0 0 180"/>
<Panel class="window" width="1500" height="1500" color="white" outline="white" outlineSize="10 10"/>
<Panel class="window"
width="1500"
height="1500"
color="white"
outline="white"
outlineSize="10 10"/>
<Row dontUseTableRowBackground="true"/>
<Row class="header" color="#707070"/>
<Row class="option" preferredHeight="200" color="#9e9e9e"/>
<Row class="header"
color="#707070"/>
<Row class="option"
preferredHeight="200"
color="#9e9e9e"/>
<!-- row heights: 70 x lines + 50 -->
<Row class="description" color="#cfcfcf"/>
<Row class="description"
color="#cfcfcf"/>
<Button class="optionToggle" rectAlignment="MiddleRight" offsetXY="-30 0" colors="#FFFFFF|#dfdfdf" height="160" width="288" ignoreLayout="True" fontSize="60"/>
<Button class="optionToggle"
rectAlignment="MiddleRight"
offsetXY="-30 0"
colors="#FFFFFF|#dfdfdf"
height="160"
width="288"
ignoreLayout="True"
fontSize="60"/>
</Defaults>
<!-- Option window -->
<Panel id="options" class="window" offsetXY="-580 200" scale="0.5 0.5" active="false" showAnimation="FadeIn" hideAnimation="FadeOut">
<Panel id="options"
class="window"
offsetXY="-580 200"
scale="0.5 0.5"
active="false"
showAnimation="FadeIn"
hideAnimation="FadeOut">
<TableLayout cellPadding="25 25 15 15">
<!-- Header -->
<Row class="header">
@ -32,10 +61,14 @@
<Row class="option">
<Cell>
<Text class="h2">Import trauma</Text>
<Button class="optionToggle" id="importTrauma" onClick="optionButtonClick(importTrauma)" image="option_on"/>
<Button class="optionToggle"
id="importTrauma"
onClick="optionButtonClick(importTrauma)"
image="option_on"/>
</Cell>
</Row>
<Row class="description" preferredHeight="330">
<Row class="description"
preferredHeight="330">
<Cell>
<Text class="p">Enables importing trauma values from the campaign log (custom content might give wrong values!).&#xA;Enter players in the campaign log in this order:&#xA;White, Orange, Green, Red.</Text>
</Cell>
@ -45,10 +78,14 @@
<Row class="option">
<Cell>
<Text class="h2">Tidy playermats</Text>
<Button class="optionToggle" id="tidyPlayermats" onClick="optionButtonClick(tidyPlayermats)" image="option_on"/>
<Button class="optionToggle"
id="tidyPlayermats"
onClick="optionButtonClick(tidyPlayermats)"
image="option_on"/>
</Cell>
</Row>
<Row class="description" preferredHeight="190">
<Row class="description"
preferredHeight="190">
<Cell>
<Text class="p">Controls whether the playermats should get tidied (removal of all cards and tokens).</Text>
</Cell>
@ -58,10 +95,14 @@
<Row class="option">
<Cell>
<Text class="h2">Remove drawn lines</Text>
<Button class="optionToggle" id="removeDrawnLines" onClick="optionButtonClick(removeDrawnLines)" image="option_off"/>
<Button class="optionToggle"
id="removeDrawnLines"
onClick="optionButtonClick(removeDrawnLines)"
image="option_off"/>
</Cell>
</Row>
<Row class="description" preferredHeight="120">
<Row class="description"
preferredHeight="120">
<Cell>
<Text class="p">Controls whether all drawn lines should be removed.</Text>
</Cell>

View File

@ -0,0 +1,42 @@
<Defaults>
<Button padding="50 50 50 50"
font="font_teutonic-arkham"
fontSize="200"
iconWidth="300"
iconAlignment="Right"/>
<TableLayout position="0 188 -22"
rotation="0 0 90"
height="1800"
width="700"
scale="0.1 0.1 1"
cellSpacing="80"
cellBackgroundColor="rgba(1,1,1,0)"/>
</Defaults>
<TableLayout id="Helper"
active="false">
<Row>
<Cell>
<Button id="Bless"
icon="token-bless"/>
</Cell>
</Row>
<Row>
<Cell>
<Button id="Curse"
icon="token-curse"/>
</Cell>
</Row>
<Row>
<Cell>
<Button id="Action"
text="Remove tokens"/>
</Cell>
</Row>
<Row>
<Cell>
<Button id="ElderSign"
icon="token-eldersign"/>
</Cell>
</Row>
</TableLayout>