From 076ce45b9f6a748d7dad9f21ee50311cad19668e Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Mon, 30 Sep 2024 12:00:14 +0200 Subject: [PATCH 01/10] initial commit --- objects/Fan-MadeAccessories.aa8b38.json | 1 - objects/OptionPanelSource.830bd0.json | 1 + .../Subject5U-21Helper.1335e8.json | 0 src/core/Global.ttslua | 27 ++++ src/core/GlobalApi.ttslua | 2 +- src/core/token/TokenManagerApi.ttslua | 9 ++ src/playermat/Playermat.ttslua | 127 ++++++++++++------ src/playermat/Zones.ttslua | 4 + 8 files changed, 129 insertions(+), 42 deletions(-) rename objects/{Fan-MadeAccessories.aa8b38 => OptionPanelSource.830bd0}/Subject5U-21Helper.1335e8.json (100%) diff --git a/objects/Fan-MadeAccessories.aa8b38.json b/objects/Fan-MadeAccessories.aa8b38.json index 33b400c4..042ee175 100644 --- a/objects/Fan-MadeAccessories.aa8b38.json +++ b/objects/Fan-MadeAccessories.aa8b38.json @@ -19,7 +19,6 @@ "LuckyPenny.2ab443", "SecretObjectivesUltimatums.b2077d", "UnderworldMarketHelper.3650ea", - "Subject5U-21Helper.1335e8", "Auto-failCounter.a9a321", "ElderSignCounter.e62cb5", "AdditionalVictoryPoints.958bc0" diff --git a/objects/OptionPanelSource.830bd0.json b/objects/OptionPanelSource.830bd0.json index 56ede1b5..743e1af4 100644 --- a/objects/OptionPanelSource.830bd0.json +++ b/objects/OptionPanelSource.830bd0.json @@ -17,6 +17,7 @@ "CYOACampaignGuides.e87ea2", "AttachmentHelper.7f4976", "SearchAssistant.17aed0", + "Subject5U-21Helper.1335e8", "HandHelper.450688", "DisplacementTool.0f1374", "CleanUpHelper.26cf4b" diff --git a/objects/Fan-MadeAccessories.aa8b38/Subject5U-21Helper.1335e8.json b/objects/OptionPanelSource.830bd0/Subject5U-21Helper.1335e8.json similarity index 100% rename from objects/Fan-MadeAccessories.aa8b38/Subject5U-21Helper.1335e8.json rename to objects/OptionPanelSource.830bd0/Subject5U-21Helper.1335e8.json diff --git a/src/core/Global.ttslua b/src/core/Global.ttslua index ef9e0b83..f339ca44 100644 --- a/src/core/Global.ttslua +++ b/src/core/Global.ttslua @@ -2469,6 +2469,33 @@ function TokenManager.replenishTokens(card, useInfo) end end +-- generates the data to spawn an infinite bag of a specific type of resources +function TokenManager.getDataForInfiniteBag(tokenType) + TokenManager.initTokenTemplates() + local tokenTemplate = tokenTemplates["resource"] + local subTypeData + local subTypeStateId + + for stateId, objData in pairs(tokenTemplate["States"]) do + if tokenType == objData["Memo"] then + subTypeStateId = stateId + subTypeData = objData + break + end + end + + -- add states to data + subTypeData["States"] = tokenTemplate["States"] + + -- add "1" state and remove the current state + subTypeData["States"]["1"] = tokenTemplate + subTypeData["States"]["1"]["States"] = nil + subTypeData["States"][tostring(subTypeStateId)] = nil + + return subTypeData + --local spawnData = {} +end + --------------------------------------------------------- -- Callback functions for token spawning --------------------------------------------------------- diff --git a/src/core/GlobalApi.ttslua b/src/core/GlobalApi.ttslua index 0f55e584..1a15d394 100644 --- a/src/core/GlobalApi.ttslua +++ b/src/core/GlobalApi.ttslua @@ -50,7 +50,7 @@ do ---@param playerColor string Color of the player that needs the visibility toggled ---@param handColor string Color of the hand to toggle the visibility for function GlobalApi.handVisibilityToggle(playerColor, handColor) - Global.call("handVisibilityToggle", { playerColor = playerColor, handColor = handColor}) + Global.call("handVisibilityToggle", { playerColor = playerColor, handColor = handColor }) end -- loads saved options diff --git a/src/core/token/TokenManagerApi.ttslua b/src/core/token/TokenManagerApi.ttslua index 42b6e51c..0d6341d1 100644 --- a/src/core/token/TokenManagerApi.ttslua +++ b/src/core/token/TokenManagerApi.ttslua @@ -96,5 +96,14 @@ do }) end + function TokenManagerApi.getDataForInfiniteBag(tokenType) + Global.call("callTable", { + { "TokenManager", "getDataForInfiniteBag" }, + { + tokenType = tokenType + } + }) + end + return TokenManagerApi end diff --git a/src/playermat/Playermat.ttslua b/src/playermat/Playermat.ttslua index c2c0e74e..637670ec 100644 --- a/src/playermat/Playermat.ttslua +++ b/src/playermat/Playermat.ttslua @@ -8,6 +8,7 @@ local searchLib = require("util/SearchLib") local tokenChecker = require("core/token/TokenChecker") local tokenManagerApi = require("core/token/TokenManagerApi") local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi") +local zones = require("playermat/Zones") -- option panel data local availableOptions = { @@ -341,19 +342,14 @@ function doUpkeep(_, clickedByColor, isRightClick) local forcedLearning = false local rot = self.getRotation() for _, obj in ipairs(searchAroundSelf()) do - if obj.hasTag("Temporary") == true then + if obj.hasTag("Temporary") then 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() - 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 - + elseif obj.hasTag("DoInUpkeep") and obj.is_face_down then + obj.call("doInUpkeep") + elseif 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 {} if not (obj.getVar("do_not_ready") or obj.hasTag("DoNotReady")) then @@ -384,8 +380,8 @@ function doUpkeep(_, clickedByColor, isRightClick) if cardMetadata.uses ~= nil and self.positionToLocal(obj.getPosition()).x > -1 and not obj.is_face_down then tokenManagerApi.maybeReplenishCard(obj, cardMetadata.uses, self) end - elseif obj.type == "Deck" and forcedLearning == false then - -- check decks for forced learning + elseif obj.type == "Deck" and not obj.is_face_down and not forcedLearning then + -- check face up decks for forced learning for _, deepObj in ipairs(obj.getObjects()) do local cardMetadata = JSON.decode(deepObj.gm_notes) or {} if cardMetadata.id == "08031" then @@ -1265,36 +1261,34 @@ end -- 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 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 - local notes = JSON.decode(card.getGMNotes()) - local extraToken + -- get metadata + local notes = JSON.decode(card.getGMNotes()) or {} - if notes ~= nil and notes.type == "Investigator" and notes.id ~= nil then - if notes.id == activeInvestigatorData.id then return end - activeInvestigatorData.class = notes.class - activeInvestigatorData.id = notes.id - activeInvestigatorData.miniId = getMiniId(notes.id) - extraToken = notes.extraToken - ownedObjects.InvestigatorSkillTracker.call("updateStats", { - notes.willpowerIcons, - notes.intellectIcons, - notes.combatIcons, - notes.agilityIcons - }) - updateTexture() - elseif activeInvestigatorData.id ~= "00000" then - activeInvestigatorData.class = "Neutral" - activeInvestigatorData.id = "00000" - activeInvestigatorData.miniId = "00000-m" - ownedObjects.InvestigatorSkillTracker.call("updateStats", { 1, 1, 1, 1 }) - updateTexture() - else - return - end + -- 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 + + -- extract relevant data from the metadata + activeInvestigatorData.class = notes.class + activeInvestigatorData.id = notes.id + activeInvestigatorData.miniId = getMiniId(notes.id) + ownedObjects.InvestigatorSkillTracker.call("updateStats", { + notes.willpowerIcons, + notes.intellectIcons, + notes.combatIcons, + notes.agilityIcons + }) + updateTexture() + + newInvestigatorCallback(notes.id) -- set proper scale for investigators local cardData = card.getData() @@ -1322,10 +1316,10 @@ function maybeUpdateActiveInvestigator(card) end -- 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 "|") local count = { action = 0, ability = 0 } - for str in string.gmatch(extraToken, "([^|]+)") do + for str in string.gmatch(notes.extraToken, "([^|]+)") do local type = "action" if str == "FreeTrigger" or str == "Reaction" then type = "ability" @@ -1344,6 +1338,59 @@ function maybeUpdateActiveInvestigator(card) end end +-- does something for specific investigators when they are loaded +function newInvestigatorCallback(newId) + -- 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( + "There's a Game Key for parallel Wendy to add sealing options to any card:" .. + " Top menu bar > Options > Game Keys", messageColor) + elseif newId == "06003" then + -- Tony Morgan + local spawnedObj = spawnObjectData({ data = getDataForInfiniteBag("bounty") }) + guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) + printToColor("We've spawned an infinite bag of bounty tokens for convenience near your playermat.", messageColor) + elseif newId == "08004" then + -- Norman Withers + printToColor( + "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 + local spawnedObj = spawnObjectData({ data = getDataForInfiniteBag("evidence") }) + guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) + printToColor("We've spawned an infinite bag of evidence tokens for convenience near your playermat.", messageColor) + elseif newId == "89001" then + -- Subject 5U-21 + local sourceBag = guidReferenceApi.getObjectByOwnerAndType("Mythos", "OptionPanelSource") + for _, objData in ipairs(sourceBag.getData().ContainedObjects) do + if objData["Nickname"] == "Subject 5U-21 Helper" then + objData["Locked"] = true + local spawnedObj = spawnObjectData({ + data = objData, + position = zones.getZonePosition(playerColor, "SetAside7"), + rotation = self.getRotation() + }) + guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) + break + end + end + printToColor("We've 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 + +function getDataForInfiniteBag(tokenType) + local tokenData = tokenManagerApi.getDataForInfiniteBag(tokenType) +end + -- returns the mini ID for the currently placed investigator function getMiniId(baseId) if #baseId < 16 then diff --git a/src/playermat/Zones.ttslua b/src/playermat/Zones.ttslua index 36f4742b..1b56f136 100644 --- a/src/playermat/Zones.ttslua +++ b/src/playermat/Zones.ttslua @@ -19,6 +19,8 @@ -- SetAside4: Upgrade sheets for customizable cards -- SetAside5: Hunch Deck for Joe Diamond -- SetAside6: currently unused +-- SetAside7: Investigator specific object + do local playermatApi = require("playermat/PlayermatApi") local Zones = { } @@ -78,6 +80,7 @@ do zoneData["White"]["SetAside5"] = { 2.78, 0, 0.042 } zoneData["White"]["SetAside6"] = { 2.78, 0, 0.605 } zoneData["White"]["UnderSetAside6"] = { 2.93, 0, 0.805 } + zoneData["White"]["SetAside7"] = { 3.21, 0, 0.705 } zoneData["Orange"] = {} zoneData["Orange"]["Investigator"] = commonZones["Investigator"] @@ -110,6 +113,7 @@ do zoneData["Orange"]["SetAside5"] = { -2.78, 0, 0.042 } zoneData["Orange"]["SetAside6"] = { -2.78, 0, 0.605 } zoneData["Orange"]["UnderSetAside6"] = { -2.93, 0, 0.805 } + zoneData["Orange"]["SetAside7"] = { -3.21, 0, 0.705 } -- Green positions are the same as White and Red the same as Orange zoneData["Red"] = zoneData["Orange"] From dccf5daaccf24351ad63ad81ec45d000e3afa6ba Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Mon, 30 Sep 2024 12:46:53 +0200 Subject: [PATCH 02/10] some bugfixes --- src/core/Global.ttslua | 36 ++++++++++++++++----------- src/core/token/TokenManagerApi.ttslua | 11 +++----- src/playermat/Playermat.ttslua | 36 ++++++++++++++++++++------- src/playermat/Zones.ttslua | 4 +-- 4 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/core/Global.ttslua b/src/core/Global.ttslua index f339ca44..213d94ed 100644 --- a/src/core/Global.ttslua +++ b/src/core/Global.ttslua @@ -2472,25 +2472,17 @@ end -- generates the data to spawn an infinite bag of a specific type of resources function TokenManager.getDataForInfiniteBag(tokenType) TokenManager.initTokenTemplates() - local tokenTemplate = tokenTemplates["resource"] - local subTypeData - local subTypeStateId - - for stateId, objData in pairs(tokenTemplate["States"]) do - if tokenType == objData["Memo"] then - subTypeStateId = stateId - subTypeData = objData - break - end - end + local template = deepCopy(tokenTemplates["resource"]) + local subTypeStateId = stateTable[tokenType] + local subTypeData = template["States"][subTypeStateId] -- add states to data - subTypeData["States"] = tokenTemplate["States"] + subTypeData["States"] = template["States"] -- add "1" state and remove the current state - subTypeData["States"]["1"] = tokenTemplate - subTypeData["States"]["1"]["States"] = nil - subTypeData["States"][tostring(subTypeStateId)] = nil + subTypeData["States"][1] = template + subTypeData["States"][1]["States"] = nil + subTypeData["States"][subTypeStateId] = nil return subTypeData --local spawnData = {} @@ -2565,3 +2557,17 @@ function getColoredName(playerColor) -- add bb-code return "[" .. Color.fromString(playerColor):toHex() .. "]" .. displayName .. "[-]" 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 diff --git a/src/core/token/TokenManagerApi.ttslua b/src/core/token/TokenManagerApi.ttslua index 0d6341d1..4ad9c4b0 100644 --- a/src/core/token/TokenManagerApi.ttslua +++ b/src/core/token/TokenManagerApi.ttslua @@ -89,19 +89,14 @@ do function TokenManagerApi.maybeReplenishCard(card, uses) Global.call("callTable", { { "TokenManager", "maybeReplenishCard" }, - { - card = card, - uses = uses - } + { card = card, uses = uses } }) end function TokenManagerApi.getDataForInfiniteBag(tokenType) - Global.call("callTable", { + return Global.call("callTable", { { "TokenManager", "getDataForInfiniteBag" }, - { - tokenType = tokenType - } + tokenType }) end diff --git a/src/playermat/Playermat.ttslua b/src/playermat/Playermat.ttslua index 637670ec..7b616a0f 100644 --- a/src/playermat/Playermat.ttslua +++ b/src/playermat/Playermat.ttslua @@ -272,9 +272,15 @@ function round(num, numDecimalPlaces) end -- 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) - 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 --------------------------------------------------------- @@ -1340,6 +1346,8 @@ 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 @@ -1350,13 +1358,17 @@ function newInvestigatorCallback(newId) if newId == "01005-p" or newId == "01005-pf" then -- parallel Wendy Adams printToColor( - "There's a Game Key for parallel Wendy to add sealing options to any card:" .. + "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 - local spawnedObj = spawnObjectData({ data = getDataForInfiniteBag("bounty") }) + local spawnedObj = spawnObjectData({ + data = getDataForInfiniteBag("bounty"), + position = zones.getZonePosition(playerColor, "SetAside7"), + rotation = self.getRotation() + }) guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) - printToColor("We've spawned an infinite bag of bounty tokens for convenience near your playermat.", messageColor) + printToColor("Tony Morgan: Spawned an infinite bag of bounty tokens near your playermat.", messageColor) elseif newId == "08004" then -- Norman Withers printToColor( @@ -1364,9 +1376,13 @@ function newInvestigatorCallback(newId) "and then the mod should keep it flipped throughout the game.", messageColor) elseif newId == "09015" then -- Darrell Simmons - local spawnedObj = spawnObjectData({ data = getDataForInfiniteBag("evidence") }) + local spawnedObj = spawnObjectData({ + data = getDataForInfiniteBag("evidence"), + position = zones.getZonePosition(playerColor, "SetAside7"), + rotation = self.getRotation() + }) guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) - printToColor("We've spawned an infinite bag of evidence tokens for convenience near your playermat.", messageColor) + printToColor("Darrell Simons: Spawned an infinite bag of evidence tokens near your playermat.", messageColor) elseif newId == "89001" then -- Subject 5U-21 local sourceBag = guidReferenceApi.getObjectByOwnerAndType("Mythos", "OptionPanelSource") @@ -1382,13 +1398,15 @@ function newInvestigatorCallback(newId) break end end - printToColor("We've 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) + 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 function getDataForInfiniteBag(tokenType) local tokenData = tokenManagerApi.getDataForInfiniteBag(tokenType) + log(tokenData) + return tokenData end -- returns the mini ID for the currently placed investigator diff --git a/src/playermat/Zones.ttslua b/src/playermat/Zones.ttslua index 1b56f136..f9d4dc30 100644 --- a/src/playermat/Zones.ttslua +++ b/src/playermat/Zones.ttslua @@ -80,7 +80,7 @@ do zoneData["White"]["SetAside5"] = { 2.78, 0, 0.042 } zoneData["White"]["SetAside6"] = { 2.78, 0, 0.605 } zoneData["White"]["UnderSetAside6"] = { 2.93, 0, 0.805 } - zoneData["White"]["SetAside7"] = { 3.21, 0, 0.705 } + zoneData["White"]["SetAside7"] = { 2.85, 0, 1.650 } zoneData["Orange"] = {} zoneData["Orange"]["Investigator"] = commonZones["Investigator"] @@ -113,7 +113,7 @@ do zoneData["Orange"]["SetAside5"] = { -2.78, 0, 0.042 } zoneData["Orange"]["SetAside6"] = { -2.78, 0, 0.605 } zoneData["Orange"]["UnderSetAside6"] = { -2.93, 0, 0.805 } - zoneData["Orange"]["SetAside7"] = { -3.21, 0, 0.705 } + zoneData["Orange"]["SetAside7"] = { -2.85, 0, 1.650 } -- Green positions are the same as White and Red the same as Orange zoneData["Red"] = zoneData["Orange"] From 6104950046e1bfc72fa6d165524101a03e25135f Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Mon, 30 Sep 2024 13:34:25 +0200 Subject: [PATCH 03/10] finishing touch --- src/core/Global.ttslua | 35 ++++++++++++++++++++++++--- src/core/token/TokenManagerApi.ttslua | 9 +++++-- src/playermat/Playermat.ttslua | 34 +++++++------------------- 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/core/Global.ttslua b/src/core/Global.ttslua index 213d94ed..f416661b 100644 --- a/src/core/Global.ttslua +++ b/src/core/Global.ttslua @@ -2470,8 +2470,16 @@ function TokenManager.replenishTokens(card, useInfo) end -- generates the data to spawn an infinite bag of a specific type of resources -function TokenManager.getDataForInfiniteBag(tokenType) +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] @@ -2484,8 +2492,29 @@ function TokenManager.getDataForInfiniteBag(tokenType) subTypeData["States"][1]["States"] = nil subTypeData["States"][subTypeStateId] = nil - return subTypeData - --local spawnData = {} + -- 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 --------------------------------------------------------- diff --git a/src/core/token/TokenManagerApi.ttslua b/src/core/token/TokenManagerApi.ttslua index 4ad9c4b0..e2ec5050 100644 --- a/src/core/token/TokenManagerApi.ttslua +++ b/src/core/token/TokenManagerApi.ttslua @@ -93,10 +93,15 @@ do }) end - function TokenManagerApi.getDataForInfiniteBag(tokenType) + -- 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" }, - tokenType + { + tokenType = tokenType, + position = position, + rotation = rotation + } }) end diff --git a/src/playermat/Playermat.ttslua b/src/playermat/Playermat.ttslua index 7b616a0f..f25b99d2 100644 --- a/src/playermat/Playermat.ttslua +++ b/src/playermat/Playermat.ttslua @@ -1348,6 +1348,10 @@ end function newInvestigatorCallback(newId) updateMessageColor() + -- get position/rotation for maybe spawned object + local pos = zones.getZonePosition(playerColor, "SetAside7") + local rot = self.getRotation() + -- remove existing object that was placed for a specific investigator local obj = guidReferenceApi.getObjectByOwnerAndType(playerColor, "InvestigatorSpecifics") if obj ~= nil then @@ -1357,30 +1361,20 @@ function newInvestigatorCallback(newId) 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:" .. + 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 - local spawnedObj = spawnObjectData({ - data = getDataForInfiniteBag("bounty"), - position = zones.getZonePosition(playerColor, "SetAside7"), - rotation = self.getRotation() - }) + local spawnedObj = spawnObjectData({ data = tokenManagerApi.getDataForInfiniteBag("bounty", pos, rot) }) guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) printToColor("Tony Morgan: Spawned an infinite bag of bounty tokens near your playermat.", messageColor) elseif newId == "08004" then -- Norman Withers - printToColor( - "At the start of the game flip the top card of your deck manually " .. + printToColor("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 - local spawnedObj = spawnObjectData({ - data = getDataForInfiniteBag("evidence"), - position = zones.getZonePosition(playerColor, "SetAside7"), - rotation = self.getRotation() - }) + local spawnedObj = spawnObjectData({ data = tokenManagerApi.getDataForInfiniteBag("evidence", pos, rot) }) guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) printToColor("Darrell Simons: Spawned an infinite bag of evidence tokens near your playermat.", messageColor) elseif newId == "89001" then @@ -1389,11 +1383,7 @@ function newInvestigatorCallback(newId) for _, objData in ipairs(sourceBag.getData().ContainedObjects) do if objData["Nickname"] == "Subject 5U-21 Helper" then objData["Locked"] = true - local spawnedObj = spawnObjectData({ - data = objData, - position = zones.getZonePosition(playerColor, "SetAside7"), - rotation = self.getRotation() - }) + local spawnedObj = spawnObjectData({ data = objData, position = pos, rotation = rot }) guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) break end @@ -1403,12 +1393,6 @@ function newInvestigatorCallback(newId) end end -function getDataForInfiniteBag(tokenType) - local tokenData = tokenManagerApi.getDataForInfiniteBag(tokenType) - log(tokenData) - return tokenData -end - -- returns the mini ID for the currently placed investigator function getMiniId(baseId) if #baseId < 16 then From 659cc8e90b71948bcd8ea745f19b377606bbf52d Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Mon, 30 Sep 2024 20:25:41 +0200 Subject: [PATCH 04/10] Add ability to spawn cards by ID (does not support Zoop IDs yet) --- src/playercards/CardSearch.ttslua | 59 ++++++++++++++++++------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/src/playercards/CardSearch.ttslua b/src/playercards/CardSearch.ttslua index f5143f2e..2aca432e 100644 --- a/src/playercards/CardSearch.ttslua +++ b/src/playercards/CardSearch.ttslua @@ -1,37 +1,37 @@ require("playercards/PlayerCardSpawner") -local allCardsBagApi = require("playercards/AllCardsBagApi") +local allCardsBagApi = require("playercards/AllCardsBagApi") -local BUTTON_LABELS = {} -BUTTON_LABELS["spawn"] = {} -BUTTON_LABELS["spawn"][true] = "All matching cards" -BUTTON_LABELS["spawn"][false] = "First matching card" -BUTTON_LABELS["search"] = {} -BUTTON_LABELS["search"][true] = "Name equals search term" -BUTTON_LABELS["search"][false] = "Name contains search term" +local BUTTON_LABELS = {} +BUTTON_LABELS["spawn"] = {} +BUTTON_LABELS["spawn"][true] = "All matching cards" +BUTTON_LABELS["spawn"][false] = "First matching card" +BUTTON_LABELS["search"] = {} +BUTTON_LABELS["search"][true] = "Name equals search term" +BUTTON_LABELS["search"][false] = "Name contains search term" -local inputParameters = {} -inputParameters.label = "Click to enter card name" -inputParameters.input_function = "input_func" -inputParameters.function_owner = self -inputParameters.alignment = 2 -inputParameters.position = { x = 0, y = 0.1, z = -0.62 } -inputParameters.width = 3750 -inputParameters.height = 380 -inputParameters.font_size = 350 -inputParameters.scale = { 0.1, 1, 0.1 } -inputParameters.color = { 0.9, 0.7, 0.5 } -inputParameters.font_color = { 0, 0, 0 } +local inputParameters = {} +inputParameters.label = "Click to enter card name" +inputParameters.input_function = "input_func" +inputParameters.function_owner = self +inputParameters.alignment = 2 +inputParameters.position = { x = 0, y = 0.1, z = -0.62 } +inputParameters.width = 3750 +inputParameters.height = 380 +inputParameters.font_size = 350 +inputParameters.scale = { 0.1, 1, 0.1 } +inputParameters.color = { 0.9, 0.7, 0.5 } +inputParameters.font_color = { 0, 0, 0 } function onSave() return JSON.encode({ spawnAll, searchExact, inputParameters.value }) end function onLoad(savedData) - local loadedData = JSON.decode(savedData) - spawnAll = loadedData[1] or false - searchExact = loadedData[2] or false - inputParameters.value = loadedData[3] or "" + local loadedData = JSON.decode(savedData) + spawnAll = loadedData[1] or false + searchExact = loadedData[2] or false + inputParameters.value = loadedData[3] or "" self.createInput(inputParameters) -- shared parameters @@ -103,6 +103,13 @@ function startSearch() return 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 local cardList = allCardsBagApi.getCardsByName(inputParameters.value, searchExact) 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) 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 pos = self.positionToWorld(Vector(0, 2, -0.08)) Spawner.spawnCards(cardList, pos, rot, true) From 9a8a30f79f66b80336da9087ab8cba554e2e16d3 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Tue, 1 Oct 2024 16:11:11 +0200 Subject: [PATCH 05/10] keep 'doInUpkeep' separate --- src/playermat/Playermat.ttslua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/playermat/Playermat.ttslua b/src/playermat/Playermat.ttslua index f25b99d2..88be296b 100644 --- a/src/playermat/Playermat.ttslua +++ b/src/playermat/Playermat.ttslua @@ -352,9 +352,14 @@ function doUpkeep(_, clickedByColor, isRightClick) discardListOfObjects({ obj }) elseif obj.hasTag("UniversalToken") and obj.is_face_down then obj.flip() - elseif obj.hasTag("DoInUpkeep") and obj.is_face_down then + 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") - elseif obj.type == "Card" and not inArea(self.positionToLocal(obj.getPosition()), INVESTIGATOR_AREA) then + 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 {} From 14b4496172fe0f2efba87182ed9e5ba030d118e9 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Wed, 2 Oct 2024 19:17:02 +0200 Subject: [PATCH 06/10] added 2nd zone for token bags --- src/playermat/Playermat.ttslua | 42 ++++++++++++++++------------------ src/playermat/Zones.ttslua | 9 +++++--- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/playermat/Playermat.ttslua b/src/playermat/Playermat.ttslua index 88be296b..a955e187 100644 --- a/src/playermat/Playermat.ttslua +++ b/src/playermat/Playermat.ttslua @@ -1353,10 +1353,6 @@ end function newInvestigatorCallback(newId) updateMessageColor() - -- get position/rotation for maybe spawned object - local pos = zones.getZonePosition(playerColor, "SetAside7") - local rot = self.getRotation() - -- remove existing object that was placed for a specific investigator local obj = guidReferenceApi.getObjectByOwnerAndType(playerColor, "InvestigatorSpecifics") if obj ~= nil then @@ -1364,30 +1360,24 @@ function newInvestigatorCallback(newId) guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics") end - if newId == "01005-p" or newId == "01005-pf" then - -- parallel Wendy Adams + 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 - local spawnedObj = spawnObjectData({ data = tokenManagerApi.getDataForInfiniteBag("bounty", pos, rot) }) - guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) - printToColor("Tony Morgan: Spawned an infinite bag of bounty tokens near your playermat.", messageColor) - elseif newId == "08004" then - -- Norman Withers - printToColor("At the start of the game flip the top card of your deck manually " .. + 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 - local spawnedObj = spawnObjectData({ data = tokenManagerApi.getDataForInfiniteBag("evidence", pos, rot) }) - guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) - printToColor("Darrell Simons: Spawned an infinite bag of evidence tokens near your playermat.", messageColor) - elseif newId == "89001" then - -- Subject 5U-21 + 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 - objData["Locked"] = true local spawnedObj = spawnObjectData({ data = objData, position = pos, rotation = rot }) guidReferenceApi.editIndex(playerColor, "InvestigatorSpecifics", spawnedObj.getGUID()) break @@ -1398,6 +1388,14 @@ function newInvestigatorCallback(newId) 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 function getMiniId(baseId) if #baseId < 16 then diff --git a/src/playermat/Zones.ttslua b/src/playermat/Zones.ttslua index f9d4dc30..279edb0e 100644 --- a/src/playermat/Zones.ttslua +++ b/src/playermat/Zones.ttslua @@ -19,7 +19,8 @@ -- SetAside4: Upgrade sheets for customizable cards -- SetAside5: Hunch Deck for Joe Diamond -- SetAside6: currently unused --- SetAside7: Investigator specific object +-- AboveSetAside: Investigator specific object +-- BelowSetAside: Investigator specific object do local playermatApi = require("playermat/PlayermatApi") @@ -80,7 +81,8 @@ do zoneData["White"]["SetAside5"] = { 2.78, 0, 0.042 } zoneData["White"]["SetAside6"] = { 2.78, 0, 0.605 } zoneData["White"]["UnderSetAside6"] = { 2.93, 0, 0.805 } - zoneData["White"]["SetAside7"] = { 2.85, 0, 1.650 } + zoneData["White"]["AboveSetAside"] = { 2.35, 0, -1.132 } + zoneData["White"]["BelowSetAside"] = { 2.85, 0, 1.650 } zoneData["Orange"] = {} zoneData["Orange"]["Investigator"] = commonZones["Investigator"] @@ -113,7 +115,8 @@ do zoneData["Orange"]["SetAside5"] = { -2.78, 0, 0.042 } zoneData["Orange"]["SetAside6"] = { -2.78, 0, 0.605 } zoneData["Orange"]["UnderSetAside6"] = { -2.93, 0, 0.805 } - zoneData["Orange"]["SetAside7"] = { -2.85, 0, 1.650 } + zoneData["Orange"]["AboveSetAside"] = { -2.35, 0, -1.132 } + zoneData["Orange"]["BelowSetAside"] = { -2.85, 0, 1.650 } -- Green positions are the same as White and Red the same as Orange zoneData["Red"] = zoneData["Orange"] From f73f7fa0e9e168ddd2c00635e8fb1481fccd7b91 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Wed, 2 Oct 2024 19:22:38 +0200 Subject: [PATCH 07/10] updated bottom bar --- xml/Global/BottomBar.xml | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/xml/Global/BottomBar.xml b/xml/Global/BottomBar.xml index 5cdc3c87..d680540e 100644 --- a/xml/Global/BottomBar.xml +++ b/xml/Global/BottomBar.xml @@ -6,7 +6,8 @@ color="clear"/> - + + offsetXY="-1 160">