SCED/src/playercards/CardsThatSealTokens.ttslua
2024-01-16 00:06:55 +01:00

265 lines
8.5 KiB
Plaintext

--[[ Library for cards that seal tokens
This file is used to add sealing option to cards' context menu.
Valid options (set before requiring this file):
UPDATE_ON_HOVER --@type: boolean
- automatically updates the context menu options when the card is hovered
- the "Read Bag" function reads the content of the chaos bag to update the context menu
- example usage: "Unrelenting" (to only display valid tokens)
KEEP_OPEN --@type: boolean
- meant for cards that seal single tokens multiple times (one by one)
- makes the context menu stay open after selecting an option
- example usage: "Unrelenting"
SHOW_SINGLE_RELEASE --@type: boolean
- enables an entry in the context menu
- this entry allows releasing a single token
- example usage: "Holy Spear" (to keep the other tokens and just release one)
SHOW_MULTI_RELEASE --@type: number (amount of tokens to release at once)
- enables an entry in the context menu
- this entry allows releasing of multiple tokens at once
- example usage: "Nephthys" (to release 3 bless tokens at once)
SHOW_MULTI_RETURN --@type: number (amount of tokens to return to pool at once)
- enables an entry in the context menu
- this entry allows returning tokens to the token pool
- example usage: "Nephthys" (to return 3 bless tokens at once)
SHOW_MULTI_SEAL --@type: number (amount of tokens to seal at once)
- enables an entry in the context menu
- this entry allows sealing of multiple tokens at once
- example usage: "Holy Spear" (to seal two bless tokens at once)
VALID_TOKENS --@type: table ([tokenName] = true)
- this table defines which tokens should be abled to be sealed
- needs to be defined for each card -> even if empty
- example usage: "The Chthonian Stone"
> VALID_TOKENS = {
> ["Skull"] = true,
> ["Cultist"] = true,
> ["Tablet"] = true,
> ["Elder Thing"] = true,
> }
INVALID_TOKENS --@type: table ([tokenName] = true)
- this table defines which tokens are invalid for sealing
- only needs to be defined if needed
- usually combined with empty "VALID_TOKENS" table
- example usage: "Protective Incantation" (not allowed to seal Auto-fail)
----------------------------------------------------------
Example 1: Crystalline Elder Sign
This card can only seal the "+1" or "Elder Sign" token,
it does not need specific options for multi-sealing or releasing.
Thus it should be implemented like this:
> VALID_TOKENS = {
> ["+1"] = true,
> ["Elder Sign"] = true
> }
> require...
----------------------------------------------------------
Example 2: Holy Spear
This card features the following abilities (just listing the relevant parts):
- releasing a single bless token
- sealing two bless tokens
Thus it should be implemented like this:
> VALID_TOKENS = {
> ["Bless"] = true
> }
> SHOW_SINGLE_RELEASE = true
> SHOW_MULTI_SEAL = 2
> require...
----------------------------------------------------------]]
local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
local chaosBagApi = require("chaosbag/ChaosBagApi")
local tokenArrangerApi = require("accessories/TokenArrangerApi")
local sealedTokens = {}
local ID_URL_MAP = {}
local tokensInBag = {}
function onSave() return JSON.encode(sealedTokens) end
function onLoad(savedData)
sealedTokens = JSON.decode(savedData) or {}
ID_URL_MAP = chaosBagApi.getIdUrlMap()
generateContextMenu()
self.addTag("CardThatSeals")
end
-- builds the context menu
function generateContextMenu()
-- conditional single or multi release options
if SHOW_SINGLE_RELEASE then
self.addContextMenuItem("Release token", releaseOneToken)
elseif SHOW_MULTI_RELEASE then
self.addContextMenuItem("Release " .. SHOW_MULTI_RELEASE .. " token(s)", releaseMultipleTokens)
else
self.addContextMenuItem("Release token(s)", releaseAllTokens)
end
-- conditional release option
if SHOW_MULTI_RETURN then
self.addContextMenuItem("Return " .. SHOW_MULTI_RETURN .. " token(s)", returnMultipleTokens)
end
-- main context menu options to seal tokens
for _, map in pairs(ID_URL_MAP) do
if (VALID_TOKENS[map.name] ~= nil) or (UPDATE_ON_HOVER and tokensInBag[map.name] and not INVALID_TOKENS[map.name]) then
if not SHOW_MULTI_SEAL then
self.addContextMenuItem("Seal " .. map.name, function(playerColor)
sealToken(map.name, playerColor)
end, KEEP_OPEN)
else
self.addContextMenuItem("Seal " .. SHOW_MULTI_SEAL .. " " .. map.name, function(playerColor)
readBag()
local allowed = true
local notFound
for name, _ in pairs(VALID_TOKENS) do
if (tokensInBag[name] or 0) < SHOW_MULTI_SEAL then
allowed = false
notFound = name
end
end
if allowed then
for i = 1, SHOW_MULTI_SEAL do
sealToken(map.name, playerColor)
end
else
printToColor("Not enough " .. notFound .. " tokens in the chaos bag.", playerColor)
end
end)
end
end
end
end
-- generates a list of chaos tokens that is in the chaos bag
function readBag()
local chaosbag = chaosBagApi.findChaosBag()
tokensInBag = {}
for _, token in ipairs(chaosbag.getObjects()) do
tokensInBag[token.name] = (tokensInBag[token.name] or 0) + 1
end
end
function resetSealedTokens()
sealedTokens = {}
end
-- native event from TTS - used to update the context menu for cards like "Unrelenting"
function onHover()
if UPDATE_ON_HOVER then
readBag()
self.clearContextMenu()
generateContextMenu()
end
end
-- seals the named token on this card
function sealToken(name, playerColor)
if not chaosBagApi.canTouchChaosTokens() then return end
local chaosbag = chaosBagApi.findChaosBag()
for i, obj in ipairs(chaosbag.getObjects()) do
if obj.name == name then
chaosbag.takeObject({
position = self.getPosition() + Vector(0, 0.5 + 0.1 * #sealedTokens, 0),
rotation = self.getRotation(),
index = i - 1,
smooth = false,
callback_function = function(token)
local guid = token.getGUID()
table.insert(sealedTokens, guid)
tokenArrangerApi.layout()
if name == "Bless" or name == "Curse" then
blessCurseManagerApi.sealedToken(name, guid)
end
end
})
return
end
end
printToColor(name .. " token not found in chaos bag", playerColor)
end
-- release the last sealed token
function releaseOneToken(playerColor)
if not chaosBagApi.canTouchChaosTokens() then return end
if #sealedTokens == 0 then
printToColor("No sealed token(s) found", playerColor)
else
printToColor("Releasing token", playerColor)
putTokenAway(table.remove(sealedTokens))
end
end
-- release multiple tokens at once
function releaseMultipleTokens(playerColor)
if SHOW_MULTI_RELEASE <= #sealedTokens then
for i = 1, SHOW_MULTI_RELEASE do
putTokenAway(table.remove(sealedTokens))
end
printToColor("Releasing " .. SHOW_MULTI_RELEASE .. " tokens", playerColor)
else
printToColor("Not enough tokens sealed.", playerColor)
end
end
-- releases all sealed tokens
function releaseAllTokens(playerColor)
if not chaosBagApi.canTouchChaosTokens() then return end
if #sealedTokens == 0 then
printToColor("No sealed token(s) found", playerColor)
else
printToColor("Releasing token(s)", playerColor)
for _, guid in ipairs(sealedTokens) do
putTokenAway(guid)
end
sealedTokens = {}
end
end
-- returns multiple tokens at once to the token pool
function returnMultipleTokens(playerColor)
if SHOW_MULTI_RETURN <= #sealedTokens then
for i = 1, SHOW_MULTI_RETURN do
returnToken(table.remove(sealedTokens))
end
printToColor("Returning " .. SHOW_MULTI_RETURN .. " tokens", playerColor)
else
printToColor("Not enough tokens sealed.", playerColor)
end
end
-- returns the token (referenced by GUID) to the chaos bag
function putTokenAway(guid)
local token = getObjectFromGUID(guid)
if not token then return end
local name = token.getName()
local chaosbag = chaosBagApi.findChaosBag()
chaosbag.putObject(token)
tokenArrangerApi.layout()
if name == "Bless" or name == "Curse" then
blessCurseManagerApi.releasedToken(name, guid)
end
end
-- returns the token to the pool (== removes it)
function returnToken(guid)
local token = getObjectFromGUID(guid)
if not token then return end
local name = token.getName()
token.destruct()
if name == "Bless" or name == "Curse" then
blessCurseManagerApi.returnedToken(name, guid)
end
end