Merge branch 'main' into redclock
This commit is contained in:
commit
16948afebe
@ -19,7 +19,6 @@
|
|||||||
"LuckyPenny.2ab443",
|
"LuckyPenny.2ab443",
|
||||||
"SecretObjectivesUltimatums.b2077d",
|
"SecretObjectivesUltimatums.b2077d",
|
||||||
"UnderworldMarketHelper.3650ea",
|
"UnderworldMarketHelper.3650ea",
|
||||||
"Subject5U-21Helper.1335e8",
|
|
||||||
"Auto-failCounter.a9a321",
|
"Auto-failCounter.a9a321",
|
||||||
"ElderSignCounter.e62cb5",
|
"ElderSignCounter.e62cb5",
|
||||||
"AdditionalVictoryPoints.958bc0"
|
"AdditionalVictoryPoints.958bc0"
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"CYOACampaignGuides.e87ea2",
|
"CYOACampaignGuides.e87ea2",
|
||||||
"AttachmentHelper.7f4976",
|
"AttachmentHelper.7f4976",
|
||||||
"SearchAssistant.17aed0",
|
"SearchAssistant.17aed0",
|
||||||
|
"Subject5U-21Helper.1335e8",
|
||||||
"HandHelper.450688",
|
"HandHelper.450688",
|
||||||
"DisplacementTool.0f1374",
|
"DisplacementTool.0f1374",
|
||||||
"CleanUpHelper.26cf4b"
|
"CleanUpHelper.26cf4b"
|
||||||
|
@ -1,128 +1,5 @@
|
|||||||
-- data for difficulty selector scripts to set up chaos bag
|
-- data for difficulty selector scripts to set up chaos bag
|
||||||
modeData = {
|
modeData = {
|
||||||
-----------------The Forgotten Age
|
|
||||||
['The Forgotten Age'] = {
|
|
||||||
easy = { token = { 'p1', 'p1', '0', '0', '0', 'm1', 'm1', 'm2', 'm3', 'skull', 'skull', 'elder', 'red', 'blue' } },
|
|
||||||
normal = { token = { 'p1', '0', '0', '0', 'm1', 'm2', 'm2', 'm3', 'm5', 'skull', 'skull', 'elder', 'red', 'blue' } },
|
|
||||||
hard = { token = { 'p1', '0', '0', 'm1', 'm2', 'm3', 'm3', 'm4', 'm6', 'skull', 'skull', 'elder', 'red', 'blue' } },
|
|
||||||
expert = { token = { '0', 'm1', 'm2', 'm2', 'm3', 'm3', 'm4', 'm4', 'm6', 'm8', 'skull', 'skull', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['The Doom of Eztli'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', '0','m1', 'm2', 'm2', 'm3', 'm5', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['Threads of Fate'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', '0','m1', 'm2', 'm2', 'm3', 'm5', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['The Boundary Beyond'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', '0','m1', 'm2', 'm2', 'm3', 'm5', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['The City of Archives'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', '0','m1', 'm2', 'm2', 'm3', 'm5', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['The Depths of Yoth'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', '0','m1', 'm2', 'm2', 'm3', 'm5', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['Heart of the Elders'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', '0','m1', 'm2', 'm2', 'm3', 'm5', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['Shattered Aeons'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', '0','m1', 'm2', 'm2', 'm3', 'm4', 'm5', 'skull', 'skull', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
|
|
||||||
-----------------The Circle Undone
|
|
||||||
['The Circle Undone'] = {
|
|
||||||
easy = { token = { 'p1', 'p1', '0', '0', '0', 'm1', 'm1', 'm2', 'm3', 'skull', 'skull', 'red', 'blue' } },
|
|
||||||
normal = { token = { 'p1', '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'red', 'blue' } },
|
|
||||||
hard = { token = { '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'm5', 'skull', 'skull', 'red', 'blue' } },
|
|
||||||
expert = { token = { '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'm6', 'm8', 'skull', 'skull', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
["At Death's Doorstep"] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1','m1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['The Secret Name'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1','m1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['The Wages of Sin'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1','m1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['For the Greater Good'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1','m1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['Union and Disillusion'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1','m1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['In the Clutches of Chaos'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1','m1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['Before the Black Throne'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1','m1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
|
|
||||||
-----------------The Dream-Eaters
|
|
||||||
['TDE_A'] = {
|
|
||||||
easy = { token = { 'p1', 'p1', '0', '0', '0', 'm1', 'm1', 'm2', 'm2', 'cultist', 'tablet', 'tablet', 'red', 'blue' } },
|
|
||||||
normal = { token = { 'p1', '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'cultist', 'tablet', 'tablet', 'red', 'blue' } },
|
|
||||||
hard = { token = { '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm3', 'm4', 'm5', 'cultist', 'tablet', 'tablet', 'red', 'blue' } },
|
|
||||||
expert = { token = { '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'm4', 'm5', 'm6', 'm8', 'cultist', 'tablet', 'tablet', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['TDE_B'] = {
|
|
||||||
easy = { token = { 'p1', 'p1', '0', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'skull', 'skull', 'cultist', 'elder', 'elder', 'red', 'blue' } },
|
|
||||||
normal = { token = { 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'cultist', 'elder', 'elder', 'red', 'blue' } },
|
|
||||||
hard = { token = { '0', '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm3', 'm4', 'm5', 'skull', 'skull', 'cultist', 'elder', 'elder', 'red', 'blue' } },
|
|
||||||
expert = { token = { '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm3', 'm4', 'm4', 'm5', 'm6', 'm8', 'skull', 'skull', 'cultist', 'elder', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['The Search For Kadath'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'skull', 'cultist', 'tablet', 'tablet', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['A Thousand Shapes of Horror'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'cultist', 'elder', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['Dark Side of the Moon'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'skull', 'cultist', 'tablet', 'tablet', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['Point of No Return'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'skull', 'cultist', 'elder', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['Where the Gods Dwell'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'skull', 'cultist', 'tablet', 'tablet', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['Weaver of the Cosmos'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'skull', 'cultist', 'elder', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
|
|
||||||
-----------------The Innsmouth Conspiracy
|
|
||||||
['The Innsmouth Conspiracy'] = {
|
|
||||||
easy = { token = { 'p1', 'p1', '0', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'skull', 'skull', 'cultist', 'cultist', 'tablet', 'tablet', 'elder', 'elder', 'red', 'blue' } },
|
|
||||||
normal = { token = { 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'cultist', 'cultist', 'tablet', 'tablet', 'elder', 'elder', 'red', 'blue' } },
|
|
||||||
hard = { token = { '0', '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm3', 'm4', 'm5', 'skull', 'skull', 'cultist', 'cultist', 'tablet', 'tablet', 'elder', 'elder', 'red', 'blue' } } ,
|
|
||||||
expert = { token = { '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm3', 'm4', 'm4', 'm5', 'm6', 'm8', 'skull', 'skull', 'cultist', 'cultist', 'tablet', 'tablet', 'elder', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['TIC_Standalone'] = {
|
|
||||||
standalone = { token = { 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'cultist', 'cultist', 'tablet', 'tablet', 'elder', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
|
|
||||||
-----------------Edge of the Earth
|
|
||||||
['Edge of the Earth'] = {
|
|
||||||
easy = { token = { 'p1', 'p1', 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'skull', 'skull', 'cultist', 'tablet', 'red', 'blue' } },
|
|
||||||
normal = { token = { 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'frost', 'skull', 'skull', 'cultist', 'tablet', 'red', 'blue' } },
|
|
||||||
hard = { token = { '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'm4', 'm5', 'frost', 'frost', 'skull', 'skull', 'cultist', 'tablet', 'red', 'blue' } },
|
|
||||||
expert = { token = { '0', 'm1', 'm2', 'm2', 'm3', 'm4', 'm4', 'm5', 'm7', 'frost', 'frost', 'frost', 'skull', 'skull', 'cultist', 'tablet', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
['City of the Elder Things'] = {
|
|
||||||
easy = { token = { 'p1', 'p1', 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } },
|
|
||||||
normal = { token = { 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'frost', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } },
|
|
||||||
hard = { token = { '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'm4', 'm5', 'frost', 'frost', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } },
|
|
||||||
expert = { token = { '0', 'm1', 'm2', 'm2', 'm3', 'm4', 'm4', 'm5', 'm7', 'frost', 'frost', 'frost', 'skull', 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
|
|
||||||
-----------------The Scarlet Keys
|
|
||||||
['The Scarlet Keys'] = {
|
|
||||||
easy = { token = { 'p1', 'p1', '0', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'skull', 'skull', 'tablet', 'elder', 'red', 'blue' } },
|
|
||||||
normal = { token = { 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'tablet', 'elder', 'red', 'blue' } },
|
|
||||||
hard = { token = { '0', '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm3', 'm4', 'm5', 'skull', 'skull', 'tablet', 'elder', 'red', 'blue' } },
|
|
||||||
expert = { token = { '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm3', 'm4', 'm4', 'm5', 'm6', 'm8', 'skull', 'skull', 'tablet', 'elder', 'red', 'blue' } }
|
|
||||||
},
|
|
||||||
|
|
||||||
-----------------The Side Missions
|
-----------------The Side Missions
|
||||||
--official
|
--official
|
||||||
['Curse of the Rougarou'] = {
|
['Curse of the Rougarou'] = {
|
||||||
|
@ -2525,6 +2525,53 @@ function TokenManager.addUseToCard(params)
|
|||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- generates the data to spawn an infinite bag of a specific type of resources
|
||||||
|
function TokenManager.getDataForInfiniteBag(params)
|
||||||
|
-- re-assign parameters for convenience
|
||||||
|
local tokenType = params.tokenType
|
||||||
|
local position = params.position
|
||||||
|
local rotation = params.rotation
|
||||||
|
|
||||||
|
-- make sure the token templates are initialized
|
||||||
|
TokenManager.initTokenTemplates()
|
||||||
|
|
||||||
|
-- create a copy of the resource token (to not modify the source)
|
||||||
|
local template = deepCopy(tokenTemplates["resource"])
|
||||||
|
local subTypeStateId = stateTable[tokenType]
|
||||||
|
local subTypeData = template["States"][subTypeStateId]
|
||||||
|
|
||||||
|
-- add states to data
|
||||||
|
subTypeData["States"] = template["States"]
|
||||||
|
|
||||||
|
-- add "1" state and remove the current state
|
||||||
|
subTypeData["States"][1] = template
|
||||||
|
subTypeData["States"][1]["States"] = nil
|
||||||
|
subTypeData["States"][subTypeStateId] = nil
|
||||||
|
|
||||||
|
-- update rotation of the main state
|
||||||
|
subTypeData["Transform"].rotX = 0
|
||||||
|
subTypeData["Transform"].rotY = 0
|
||||||
|
subTypeData["Transform"].rotZ = 0
|
||||||
|
|
||||||
|
-- generate and return data for the infinite bag
|
||||||
|
local properTypeName = tokenType:gsub("^%l", string.upper)
|
||||||
|
return {
|
||||||
|
Name = "Infinite_Bag",
|
||||||
|
Nickname = properTypeName .. " Bag",
|
||||||
|
ContainedObjects = { subTypeData },
|
||||||
|
Transform = {
|
||||||
|
posX = position.x,
|
||||||
|
posY = position.y,
|
||||||
|
posZ = position.z,
|
||||||
|
rotX = rotation.x,
|
||||||
|
rotY = rotation.y,
|
||||||
|
rotZ = rotation.z,
|
||||||
|
scaleX = 1,
|
||||||
|
scaleY = 1,
|
||||||
|
scaleZ = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
@ -2596,3 +2643,17 @@ function getColoredName(playerColor)
|
|||||||
-- add bb-code
|
-- add bb-code
|
||||||
return "[" .. Color.fromString(playerColor):toHex() .. "]" .. displayName .. "[-]"
|
return "[" .. Color.fromString(playerColor):toHex() .. "]" .. displayName .. "[-]"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- creates a deep copy of a table
|
||||||
|
function deepCopy(data)
|
||||||
|
if type(data) ~= "table" then return data end
|
||||||
|
local copiedList = {}
|
||||||
|
for key, value in pairs(data) do
|
||||||
|
if type(value) == "table" then
|
||||||
|
copiedList[key] = deepCopy(value)
|
||||||
|
else
|
||||||
|
copiedList[key] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return copiedList
|
||||||
|
end
|
||||||
|
@ -50,7 +50,7 @@ do
|
|||||||
---@param playerColor string Color of the player that needs the visibility toggled
|
---@param playerColor string Color of the player that needs the visibility toggled
|
||||||
---@param handColor string Color of the hand to toggle the visibility for
|
---@param handColor string Color of the hand to toggle the visibility for
|
||||||
function GlobalApi.handVisibilityToggle(playerColor, handColor)
|
function GlobalApi.handVisibilityToggle(playerColor, handColor)
|
||||||
Global.call("handVisibilityToggle", { playerColor = playerColor, handColor = handColor})
|
Global.call("handVisibilityToggle", { playerColor = playerColor, handColor = handColor })
|
||||||
end
|
end
|
||||||
|
|
||||||
-- loads saved options
|
-- loads saved options
|
||||||
|
@ -91,9 +91,18 @@ do
|
|||||||
function TokenManagerApi.maybeReplenishCard(card, uses)
|
function TokenManagerApi.maybeReplenishCard(card, uses)
|
||||||
Global.call("callTable", {
|
Global.call("callTable", {
|
||||||
{ "TokenManager", "maybeReplenishCard" },
|
{ "TokenManager", "maybeReplenishCard" },
|
||||||
|
{ card = card, uses = uses }
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Generates the data to spawn an infinite bag of a specific type of resources
|
||||||
|
function TokenManagerApi.getDataForInfiniteBag(tokenType, position, rotation)
|
||||||
|
return Global.call("callTable", {
|
||||||
|
{ "TokenManager", "getDataForInfiniteBag" },
|
||||||
{
|
{
|
||||||
card = card,
|
tokenType = tokenType,
|
||||||
uses = uses
|
position = position,
|
||||||
|
rotation = rotation
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
@ -268,6 +268,9 @@ function buildSupplementalIndexes()
|
|||||||
if OFFICIAL_CYCLE_LIST[cycleName] ~= true then
|
if OFFICIAL_CYCLE_LIST[cycleName] ~= true then
|
||||||
otherCardsDetected = true
|
otherCardsDetected = true
|
||||||
|
|
||||||
|
-- overwrite the cycle for easier handling by the playercard panel
|
||||||
|
cycleName = "other"
|
||||||
|
|
||||||
-- maybe add to special investigator / minicard index
|
-- maybe add to special investigator / minicard index
|
||||||
if card.metadata.type == "Investigator" then
|
if card.metadata.type == "Investigator" then
|
||||||
writeToNestedTable(customInvestigatorData, "InvestigatorGroup", cardId)
|
writeToNestedTable(customInvestigatorData, "InvestigatorGroup", cardId)
|
||||||
|
@ -103,6 +103,13 @@ function startSearch()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- if the search string is a number, assume it's an ID and spawn the card directly
|
||||||
|
if tonumber(inputParameters.value) then
|
||||||
|
local singleCard = allCardsBagApi.getCardById(inputParameters.value)
|
||||||
|
spawnCardList({ singleCard })
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- search all objects in bag
|
-- search all objects in bag
|
||||||
local cardList = allCardsBagApi.getCardsByName(inputParameters.value, searchExact)
|
local cardList = allCardsBagApi.getCardsByName(inputParameters.value, searchExact)
|
||||||
if cardList == nil or #cardList == 0 then
|
if cardList == nil or #cardList == 0 then
|
||||||
@ -117,6 +124,10 @@ function startSearch()
|
|||||||
-- sort table by name (reverse for multiple results, because bottom card spawns first)
|
-- sort table by name (reverse for multiple results, because bottom card spawns first)
|
||||||
table.sort(cardList, function(k1, k2) return spawnAll == (k1.data.Nickname > k2.data.Nickname) end)
|
table.sort(cardList, function(k1, k2) return spawnAll == (k1.data.Nickname > k2.data.Nickname) end)
|
||||||
|
|
||||||
|
spawnCardList(cardList)
|
||||||
|
end
|
||||||
|
|
||||||
|
function spawnCardList(cardList)
|
||||||
local rot = self.getRotation()
|
local rot = self.getRotation()
|
||||||
local pos = self.positionToWorld(Vector(0, 2, -0.08))
|
local pos = self.positionToWorld(Vector(0, 2, -0.08))
|
||||||
Spawner.spawnCards(cardList, pos, rot, true)
|
Spawner.spawnCards(cardList, pos, rot, true)
|
||||||
|
@ -8,6 +8,7 @@ local searchLib = require("util/SearchLib")
|
|||||||
local tokenChecker = require("core/token/TokenChecker")
|
local tokenChecker = require("core/token/TokenChecker")
|
||||||
local tokenManagerApi = require("core/token/TokenManagerApi")
|
local tokenManagerApi = require("core/token/TokenManagerApi")
|
||||||
local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi")
|
local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi")
|
||||||
|
local zones = require("playermat/Zones")
|
||||||
|
|
||||||
-- option panel data
|
-- option panel data
|
||||||
local availableOptions = {
|
local availableOptions = {
|
||||||
@ -271,9 +272,15 @@ function round(num, numDecimalPlaces)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- updates the internal "messageColor" which is used for print/broadcast statements if no player is seated
|
-- updates the internal "messageColor" which is used for print/broadcast statements if no player is seated
|
||||||
---@param clickedByColor string Colorstring of player who clicked a button
|
---@param clickedByColor? string Colorstring of player who clicked a button
|
||||||
function updateMessageColor(clickedByColor)
|
function updateMessageColor(clickedByColor)
|
||||||
messageColor = Player[playerColor].seated and playerColor or clickedByColor
|
if Player[playerColor].seated then
|
||||||
|
messageColor = playerColor
|
||||||
|
elseif clickedByColor and Player[clickedByColor].seated then
|
||||||
|
messageColor = clickedByColor
|
||||||
|
else
|
||||||
|
messageColor = Player.getPlayers()[1].color
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
@ -341,19 +348,19 @@ function doUpkeep(_, clickedByColor, isRightClick)
|
|||||||
local forcedLearning = false
|
local forcedLearning = false
|
||||||
local rot = self.getRotation()
|
local rot = self.getRotation()
|
||||||
for _, obj in ipairs(searchAroundSelf()) do
|
for _, obj in ipairs(searchAroundSelf()) do
|
||||||
if obj.hasTag("Temporary") == true then
|
if obj.hasTag("Temporary") then
|
||||||
discardListOfObjects({ obj })
|
discardListOfObjects({ obj })
|
||||||
elseif obj.hasTag("UniversalToken") == true and obj.is_face_down then
|
elseif obj.hasTag("UniversalToken") and obj.is_face_down then
|
||||||
obj.flip()
|
obj.flip()
|
||||||
elseif obj.type == "Card" then
|
|
||||||
if obj.hasTag("DoInUpkeep") then
|
|
||||||
obj.call("doInUpkeep")
|
|
||||||
end
|
|
||||||
-- do not rotate, replenish, etc. on cards in investigator card area
|
|
||||||
if inArea(self.positionToLocal(obj.getPosition()), INVESTIGATOR_AREA) then
|
|
||||||
break
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- call the 'doInUpkeep' function for face-up objects with the respective tag
|
||||||
|
if obj.hasTag("DoInUpkeep") and not obj.is_face_down then
|
||||||
|
obj.call("doInUpkeep")
|
||||||
|
end
|
||||||
|
|
||||||
|
if obj.type == "Card" and not inArea(self.positionToLocal(obj.getPosition()), INVESTIGATOR_AREA) then
|
||||||
|
-- do not continue for cards in investigator card area
|
||||||
local cardMetadata = JSON.decode(obj.getGMNotes()) or {}
|
local cardMetadata = JSON.decode(obj.getGMNotes()) or {}
|
||||||
|
|
||||||
if not (obj.getVar("do_not_ready") or obj.hasTag("DoNotReady")) then
|
if not (obj.getVar("do_not_ready") or obj.hasTag("DoNotReady")) then
|
||||||
@ -384,8 +391,8 @@ function doUpkeep(_, clickedByColor, isRightClick)
|
|||||||
if cardMetadata.uses ~= nil and self.positionToLocal(obj.getPosition()).x > -1 and not obj.is_face_down then
|
if cardMetadata.uses ~= nil and self.positionToLocal(obj.getPosition()).x > -1 and not obj.is_face_down then
|
||||||
tokenManagerApi.maybeReplenishCard(obj, cardMetadata.uses, self)
|
tokenManagerApi.maybeReplenishCard(obj, cardMetadata.uses, self)
|
||||||
end
|
end
|
||||||
elseif obj.type == "Deck" and forcedLearning == false then
|
elseif obj.type == "Deck" and not obj.is_face_down and not forcedLearning then
|
||||||
-- check decks for forced learning
|
-- check face up decks for forced learning
|
||||||
for _, deepObj in ipairs(obj.getObjects()) do
|
for _, deepObj in ipairs(obj.getObjects()) do
|
||||||
local cardMetadata = JSON.decode(deepObj.gm_notes) or {}
|
local cardMetadata = JSON.decode(deepObj.gm_notes) or {}
|
||||||
if cardMetadata.id == "08031" then
|
if cardMetadata.id == "08031" then
|
||||||
@ -1265,20 +1272,25 @@ end
|
|||||||
-- investigator ID grabbing and skill tracker
|
-- investigator ID grabbing and skill tracker
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
|
|
||||||
-- updates the internal investigator id and action tokens if an investigator card is detected
|
-- updates the internal investigator data and performs additional operations if an investigator card is detected
|
||||||
---@param card tts__Object Card that might be an investigator
|
---@param card tts__Object Card that might be an investigator
|
||||||
function maybeUpdateActiveInvestigator(card)
|
function maybeUpdateActiveInvestigator(card)
|
||||||
|
-- don't continue if this card is not in the investigator area
|
||||||
if not inArea(self.positionToLocal(card.getPosition()), INVESTIGATOR_AREA) then return end
|
if not inArea(self.positionToLocal(card.getPosition()), INVESTIGATOR_AREA) then return end
|
||||||
|
|
||||||
local notes = JSON.decode(card.getGMNotes())
|
-- get metadata
|
||||||
local extraToken
|
local notes = JSON.decode(card.getGMNotes()) or {}
|
||||||
|
|
||||||
if notes ~= nil and notes.type == "Investigator" and notes.id ~= nil then
|
-- don't continue for cards without proper metadata
|
||||||
|
if notes.type ~= "Investigator" or notes.id == nil then return end
|
||||||
|
|
||||||
|
-- don't continue if this is already the active investigator
|
||||||
if notes.id == activeInvestigatorData.id then return end
|
if notes.id == activeInvestigatorData.id then return end
|
||||||
|
|
||||||
|
-- extract relevant data from the metadata
|
||||||
activeInvestigatorData.class = notes.class
|
activeInvestigatorData.class = notes.class
|
||||||
activeInvestigatorData.id = notes.id
|
activeInvestigatorData.id = notes.id
|
||||||
activeInvestigatorData.miniId = getMiniId(notes.id)
|
activeInvestigatorData.miniId = getMiniId(notes.id)
|
||||||
extraToken = notes.extraToken
|
|
||||||
ownedObjects.InvestigatorSkillTracker.call("updateStats", {
|
ownedObjects.InvestigatorSkillTracker.call("updateStats", {
|
||||||
notes.willpowerIcons,
|
notes.willpowerIcons,
|
||||||
notes.intellectIcons,
|
notes.intellectIcons,
|
||||||
@ -1286,15 +1298,8 @@ function maybeUpdateActiveInvestigator(card)
|
|||||||
notes.agilityIcons
|
notes.agilityIcons
|
||||||
})
|
})
|
||||||
updateTexture()
|
updateTexture()
|
||||||
elseif activeInvestigatorData.id ~= "00000" then
|
|
||||||
activeInvestigatorData.class = "Neutral"
|
newInvestigatorCallback(notes.id)
|
||||||
activeInvestigatorData.id = "00000"
|
|
||||||
activeInvestigatorData.miniId = "00000-m"
|
|
||||||
ownedObjects.InvestigatorSkillTracker.call("updateStats", { 1, 1, 1, 1 })
|
|
||||||
updateTexture()
|
|
||||||
else
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set proper scale for investigators
|
-- set proper scale for investigators
|
||||||
local cardData = card.getData()
|
local cardData = card.getData()
|
||||||
@ -1322,10 +1327,10 @@ function maybeUpdateActiveInvestigator(card)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- spawn additional token (maybe specific for investigator)
|
-- spawn additional token (maybe specific for investigator)
|
||||||
if extraToken and extraToken ~= "None" then
|
if notes.extraToken and notes.extraToken ~= "None" then
|
||||||
-- spawn tokens (split string by "|")
|
-- spawn tokens (split string by "|")
|
||||||
local count = { action = 0, ability = 0 }
|
local count = { action = 0, ability = 0 }
|
||||||
for str in string.gmatch(extraToken, "([^|]+)") do
|
for str in string.gmatch(notes.extraToken, "([^|]+)") do
|
||||||
local type = "action"
|
local type = "action"
|
||||||
if str == "FreeTrigger" or str == "Reaction" then
|
if str == "FreeTrigger" or str == "Reaction" then
|
||||||
type = "ability"
|
type = "ability"
|
||||||
@ -1344,6 +1349,53 @@ function maybeUpdateActiveInvestigator(card)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- does something for specific investigators when they are loaded
|
||||||
|
function newInvestigatorCallback(newId)
|
||||||
|
updateMessageColor()
|
||||||
|
|
||||||
|
-- remove existing object that was placed for a specific investigator
|
||||||
|
local obj = guidReferenceApi.getObjectByOwnerAndType(playerColor, "InvestigatorSpecifics")
|
||||||
|
if obj ~= nil then
|
||||||
|
obj.destruct()
|
||||||
|
guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics")
|
||||||
|
end
|
||||||
|
|
||||||
|
if newId == "01005-p" or newId == "01005-pf" then -- parallel Wendy Adams
|
||||||
|
printToColor("Wendy Adams: There's a Game Key to add sealing options to any card:" ..
|
||||||
|
" Top menu bar > Options > Game Keys", messageColor)
|
||||||
|
elseif newId == "06003" then -- Tony Morgan
|
||||||
|
spawnInfiniteTokenBag("bounty")
|
||||||
|
printToColor("Tony Morgan: Spawned bounty tokens near your playermat.", messageColor)
|
||||||
|
elseif newId == "08004" then -- Norman Withers
|
||||||
|
printToColor("Norman Withers: At the start of the game flip the top card of your deck manually " ..
|
||||||
|
"and then the mod should keep it flipped throughout the game.", messageColor)
|
||||||
|
elseif newId == "09015" then -- Darrell Simmons
|
||||||
|
spawnInfiniteTokenBag("evidence")
|
||||||
|
printToColor("Darrell Simmons: Spawned evidence tokens near your playermat.", messageColor)
|
||||||
|
elseif newId == "89001" then -- Subject 5U-21
|
||||||
|
local pos = zones.getZonePosition(playerColor, "BelowSetAside")
|
||||||
|
local rot = self.getRotation()
|
||||||
|
local sourceBag = guidReferenceApi.getObjectByOwnerAndType("Mythos", "OptionPanelSource")
|
||||||
|
for _, objData in ipairs(sourceBag.getData().ContainedObjects) do
|
||||||
|
if objData["Nickname"] == "Subject 5U-21 Helper" then
|
||||||
|
local spawnedObj = spawnObjectData({ data = objData, position = pos, rotation = rot })
|
||||||
|
guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID())
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
printToColor("Subject 5U-21: Spawned a helper to track the classes of devoured cards near your playermat. " ..
|
||||||
|
"Note that this and 'Ravenous' will work with the Attachment Helper from the option panel.", messageColor)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- spawns an infinite token bag of the specified type near the set aside area
|
||||||
|
function spawnInfiniteTokenBag(tokenType)
|
||||||
|
local pos = zones.getZonePosition(playerColor, "AboveSetAside")
|
||||||
|
local rot = self.getRotation()
|
||||||
|
local spawnedObj = spawnObjectData({ data = tokenManagerApi.getDataForInfiniteBag(tokenType, pos, rot) })
|
||||||
|
guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID())
|
||||||
|
end
|
||||||
|
|
||||||
-- returns the mini ID for the currently placed investigator
|
-- returns the mini ID for the currently placed investigator
|
||||||
function getMiniId(baseId)
|
function getMiniId(baseId)
|
||||||
if #baseId < 16 then
|
if #baseId < 16 then
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
-- SetAside4: Upgrade sheets for customizable cards
|
-- SetAside4: Upgrade sheets for customizable cards
|
||||||
-- SetAside5: Hunch Deck for Joe Diamond
|
-- SetAside5: Hunch Deck for Joe Diamond
|
||||||
-- SetAside6: currently unused
|
-- SetAside6: currently unused
|
||||||
|
-- AboveSetAside: Investigator specific object
|
||||||
|
-- BelowSetAside: Investigator specific object
|
||||||
|
|
||||||
do
|
do
|
||||||
local playermatApi = require("playermat/PlayermatApi")
|
local playermatApi = require("playermat/PlayermatApi")
|
||||||
local Zones = { }
|
local Zones = { }
|
||||||
@ -78,6 +81,8 @@ do
|
|||||||
zoneData["White"]["SetAside5"] = { 2.78, 0, 0.042 }
|
zoneData["White"]["SetAside5"] = { 2.78, 0, 0.042 }
|
||||||
zoneData["White"]["SetAside6"] = { 2.78, 0, 0.605 }
|
zoneData["White"]["SetAside6"] = { 2.78, 0, 0.605 }
|
||||||
zoneData["White"]["UnderSetAside6"] = { 2.93, 0, 0.805 }
|
zoneData["White"]["UnderSetAside6"] = { 2.93, 0, 0.805 }
|
||||||
|
zoneData["White"]["AboveSetAside"] = { 2.35, 0, -1.069 }
|
||||||
|
zoneData["White"]["BelowSetAside"] = { 2.85, 0, 1.650 }
|
||||||
|
|
||||||
zoneData["Orange"] = {}
|
zoneData["Orange"] = {}
|
||||||
zoneData["Orange"]["Investigator"] = commonZones["Investigator"]
|
zoneData["Orange"]["Investigator"] = commonZones["Investigator"]
|
||||||
@ -110,6 +115,8 @@ do
|
|||||||
zoneData["Orange"]["SetAside5"] = { -2.78, 0, 0.042 }
|
zoneData["Orange"]["SetAside5"] = { -2.78, 0, 0.042 }
|
||||||
zoneData["Orange"]["SetAside6"] = { -2.78, 0, 0.605 }
|
zoneData["Orange"]["SetAside6"] = { -2.78, 0, 0.605 }
|
||||||
zoneData["Orange"]["UnderSetAside6"] = { -2.93, 0, 0.805 }
|
zoneData["Orange"]["UnderSetAside6"] = { -2.93, 0, 0.805 }
|
||||||
|
zoneData["Orange"]["AboveSetAside"] = { -2.35, 0, -1.069 }
|
||||||
|
zoneData["Orange"]["BelowSetAside"] = { -2.85, 0, 1.650 }
|
||||||
|
|
||||||
-- Green positions are the same as White and Red the same as Orange
|
-- Green positions are the same as White and Red the same as Orange
|
||||||
zoneData["Red"] = zoneData["Orange"]
|
zoneData["Red"] = zoneData["Orange"]
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
color="clear"/>
|
color="clear"/>
|
||||||
<VerticalLayout class="navbar"
|
<VerticalLayout class="navbar"
|
||||||
width="800"
|
width="800"
|
||||||
padding="70 70 70 70"
|
height="1600"
|
||||||
|
padding="75 75 75 75"
|
||||||
scale="0.05 0.05 1"
|
scale="0.05 0.05 1"
|
||||||
color="#000000"
|
color="#000000"
|
||||||
outlineSize="20 20"
|
outlineSize="20 20"
|
||||||
@ -14,15 +15,23 @@
|
|||||||
rectAlignment="LowerRight"/>
|
rectAlignment="LowerRight"/>
|
||||||
</Defaults>
|
</Defaults>
|
||||||
|
|
||||||
<!-- Buttons at the bottom right (height: n * width) -->
|
<!-- Navigation Overlay + Bless / Curse Manager (height: n * width) -->
|
||||||
<VerticalLayout class="navbar"
|
<VerticalLayout class="navbar"
|
||||||
visibility="Admin"
|
offsetXY="-1 160">
|
||||||
height="2400"
|
|
||||||
offsetXY="-1 120">
|
|
||||||
<Button class="navbar"
|
<Button class="navbar"
|
||||||
icon="blurse"
|
icon="blurse"
|
||||||
tooltip="Bless/Curse Manager"
|
tooltip="Bless/Curse Manager"
|
||||||
onClick="onClick_toggleUi(blessCurseManager)"/>
|
onClick="onClick_toggleUi(blessCurseManager)"/>
|
||||||
|
<Button class="navbar"
|
||||||
|
icon="NavigationOverlayIcon"
|
||||||
|
tooltip="Navigation Overlay"
|
||||||
|
onClick="onClick_toggleUi(Navigation Overlay)"/>
|
||||||
|
</VerticalLayout>
|
||||||
|
|
||||||
|
<!-- Download Menu + Option Panel (height: n * width) -->
|
||||||
|
<VerticalLayout class="navbar"
|
||||||
|
visibility="Admin"
|
||||||
|
offsetXY="-1 80">
|
||||||
<Button class="navbar"
|
<Button class="navbar"
|
||||||
icon="devourer"
|
icon="devourer"
|
||||||
tooltip="Downloadable Content"
|
tooltip="Downloadable Content"
|
||||||
@ -32,13 +41,3 @@
|
|||||||
tooltip="Options"
|
tooltip="Options"
|
||||||
onClick="onClick_toggleUi(optionPanel)"/>
|
onClick="onClick_toggleUi(optionPanel)"/>
|
||||||
</VerticalLayout>
|
</VerticalLayout>
|
||||||
|
|
||||||
<!-- Navigation Overlay button -->
|
|
||||||
<VerticalLayout class="navbar"
|
|
||||||
height="800"
|
|
||||||
offsetXY="-1 80">
|
|
||||||
<Button class="navbar"
|
|
||||||
icon="NavigationOverlayIcon"
|
|
||||||
tooltip="Navigation Overlay"
|
|
||||||
onClick="onClick_toggleUi(Navigation Overlay)"/>
|
|
||||||
</VerticalLayout>
|
|
||||||
|
Loading…
Reference in New Issue
Block a user