From c785baa4be357a636ab016b7e3ec9d2d975b3f23 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Tue, 6 Aug 2024 13:40:14 +0200 Subject: [PATCH] improved custom card support --- src/playercards/AllCardsBag.ttslua | 127 ++++++++++++++----------- src/playercards/AllCardsBagApi.ttslua | 9 +- src/playercards/PlayerCardPanel.ttslua | 10 +- 3 files changed, 87 insertions(+), 59 deletions(-) diff --git a/src/playercards/AllCardsBag.ttslua b/src/playercards/AllCardsBag.ttslua index 94ae9466..f97f7939 100644 --- a/src/playercards/AllCardsBag.ttslua +++ b/src/playercards/AllCardsBag.ttslua @@ -64,51 +64,22 @@ end -- and creating the keyed lookup tables for the cards. This is a coroutine which will -- spread the workload by processing 20 cards before yielding. function buildIndex() - local cardCount = 0 + cardCount = 0 indexingDone = false otherCardsDetected = false -- process the allcardsbag itself - for _, cardData in ipairs(self.getData().ContainedObjects) do - addCardToIndex(cardData) - cardCount = cardCount + 1 - if cardCount > 19 then - cardCount = 0 - coroutine.yield(0) - end + local selfData = self.getData() + if selfData.ContainedObjects then + processContainedObjects(selfData.ContainedObjects) end -- process hotfix bags (and the additional playercards bag) for _, hotfixBag in ipairs(getObjectsWithTag("AllCardsHotfix")) do local hotfixData = hotfixBag.getData() - - -- if the bag is empty, continue with the next bag - if not hotfixData.ContainedObjects then - goto nextBag + if hotfixData.ContainedObjects then + processContainedObjects(hotfixData.ContainedObjects, hotfixData.CustomDeck) end - - for _, cardData in ipairs(hotfixData.ContainedObjects) do - if cardData.ContainedObjects then - -- process containers - for _, deepCardData in ipairs(cardData.ContainedObjects) do - addCardToIndex(deepCardData) - cardCount = cardCount + 1 - if cardCount > 19 then - cardCount = 0 - coroutine.yield(0) - end - end - else - -- process single cards - addCardToIndex(cardData) - cardCount = cardCount + 1 - if cardCount > 19 then - cardCount = 0 - coroutine.yield(0) - end - end - end - ::nextBag:: end buildSupplementalIndexes() @@ -117,6 +88,43 @@ function buildIndex() return 1 end +-- Processes the contained objects for cards to add to the index +function processContainedObjects(containedObjects, customDeck) + for _, objData in ipairs(containedObjects) do + if objData.ContainedObjects then + -- recursively process nested containers + processContainedObjects(objData.ContainedObjects, objData.CustomDeck) + else + -- we might need to fix the "CustomDeck" entry for cards inside decks since TTS doesn't update it while they are in bags + if customDeck then + local wantedCustomDeckIdStr = tostring(objData.CardID):sub(1, -3) + local presentCustomDeckIdNum = next(objData.CustomDeck) + + -- type conversion (TTS seems to store these as strings, but reads them as numbers) + local wantedCustomDeckIdNum = tonumber(wantedCustomDeckIdStr) + + if wantedCustomDeckIdNum ~= presentCustomDeckIdNum then + if customDeck[wantedCustomDeckIdNum] then + objData.CustomDeck = {} + objData.CustomDeck[wantedCustomDeckIdStr] = customDeck[wantedCustomDeckIdNum] + log("Correct CustomDeckData for " .. objData.Nickname) + else + log("Could not correct CustomDeckData for " .. objData.Nickname) + return + end + end + end + + addCardToIndex(objData) + cardCount = cardCount + 1 + if cardCount > 19 then + cardCount = 0 + coroutine.yield(0) + end + end + end +end + -- Adds a card to any indexes it should be a part of, based on its metadata ---@param cardData table TTS object data for the card function addCardToIndex(cardData) @@ -178,6 +186,17 @@ function buildSupplementalIndexes() -- add to cycle index local cycleName = card.metadata.cycle + + -- if this is a minicard without cycle, check the parent card for cycle data + if not cycleName and card.metadata.type == "Minicard" then + -- TO-DO: use a more robust detection instead of 5 characters + local parentId = string.match(card.metadata.id, ".....") + local parent = cardIdIndex[parentId] + if parent and parent.metadata.cycle then + cycleName = parent.metadata.cycle + end + end + if cycleName then cycleName = string.lower(cycleName) @@ -189,18 +208,14 @@ function buildSupplementalIndexes() else -- track cards without defined cycle (should only be fan-made cards) cycleName = "other" - log(card.metadata.id) otherCardsDetected = true end - -- only add official cards with level to cycle index, but all fan-made cards - if card.metadata.level or cycleName == "other" then - -- maybe initialize table - if cycleIndex[cycleName] == nil then - cycleIndex[cycleName] = {} - end - table.insert(cycleIndex[cycleName], card.metadata.id) + -- maybe initialize table + if cycleIndex[cycleName] == nil then + cycleIndex[cycleName] = {} end + table.insert(cycleIndex[cycleName], card.metadata.id) end end @@ -278,8 +293,9 @@ end -- Returns a list of cards from the bag matching a cycle ---@param params table --- cycle: String cycle to retrieve ("The Scarlet Keys" etc.) --- sortByMetadata: true to sort the table by metadata instead of ID +-- cycle: string Name of the cycle to retrieve ("The Scarlet Keys" etc.) +-- sortByMetadata: boolean If true, sorts the table by metadata instead of ID +-- includeNoLevelCards: boolean If true, includes cards without level ---@return table: If the indexes are still being constructed, returns an empty table. -- Otherwise, a list of tables, each with the following fields -- data: TTS object data, suitable for spawning the card @@ -288,17 +304,18 @@ function getCardsByCycle(params) if not isIndexReady() then return {} end local cycleData = cycleIndex[string.lower(params.cycle)] or {} - if not params.sortByMetadata then - return cycleData + + -- create a copy of the data to not change the source + local cardList = {} + for _, id in ipairs(cycleData) do + -- only include cards without level if requested + if cardIdIndex[id].metadata.level or params.includeNoLevelCards then + table.insert(cardList, id) + end end -- sort list by metadata (useful for custom cards without proper IDs) - local cardList = {} - for _, id in ipairs(cycleData) do - table.insert(cardList, id) - end - - if #cardList > 0 then + if params.sortByMetadata and #cardList > 0 then table.sort(cardList, metadataSortFunction) end return cardList @@ -340,13 +357,15 @@ end -- helper function to calculate the class value for sorting from the "|" separated string function getClassValueFromString(s) + s = s or "NoClass" local classValueList = { Guardian = 1, Seeker = 2, Rogue = 3, Mystic = 4, Survivor = 5, - Neutral = 6 + Neutral = 6, + NoClass = 7 } local classValue = 0 for str in s:gmatch("([^|]+)") do diff --git a/src/playercards/AllCardsBagApi.ttslua b/src/playercards/AllCardsBagApi.ttslua index 2a69145b..12f36643 100644 --- a/src/playercards/AllCardsBagApi.ttslua +++ b/src/playercards/AllCardsBagApi.ttslua @@ -77,12 +77,17 @@ do -- Returns a list of cards from the bag matching a cycle ---@param cycle string Cycle to retrieve ("The Scarlet Keys" etc.) ---@param sortByMetadata boolean If true, sorts the table by metadata instead of ID + ---@param includeNoLevelCards boolean If true, includes cards without level ---@return table: If the indexes are still being constructed, returns an empty table. -- Otherwise, a list of tables, each with the following fields -- data: TTS object data, suitable for spawning the card -- metadata: Table of parsed metadata - AllCardsBagApi.getCardsByCycle = function(cycle, sortByMetadata) - return returnCopyOfList(getAllCardsBag().call("getCardsByCycle", { cycle = cycle, sortByMetadata = sortByMetadata })) + AllCardsBagApi.getCardsByCycle = function(cycle, sortByMetadata, includeNoLevelCards) + return returnCopyOfList(getAllCardsBag().call("getCardsByCycle", { + cycle = cycle, + sortByMetadata = sortByMetadata, + includeNoLevelCards = includeNoLevelCards + })) end -- Constructs a list of available basic weaknesses by starting with the full pool of basic diff --git a/src/playercards/PlayerCardPanel.ttslua b/src/playercards/PlayerCardPanel.ttslua index 20bbd0ad..a4d76f0f 100644 --- a/src/playercards/PlayerCardPanel.ttslua +++ b/src/playercards/PlayerCardPanel.ttslua @@ -493,7 +493,9 @@ end ---@param groupName string Name of the group to spawn, matching a key in InvestigatorPanelData function spawnInvestigators(groupName) if INVESTIGATOR_GROUPS[groupName] == nil then - printToAll("No investigator data for " .. groupName .. " yet") + if groupName ~= "Other" then + printToAll("No investigator data for '" .. groupName .. "' yet") + end return end @@ -693,15 +695,17 @@ function spawnCycle(cycle) prepareToPlaceCards() spawnInvestigators(cycle) - -- sort custom cards + -- sort custom cards and include cards without level local sortByMetadata = false + local includeNoLevelCards = false if cycle == "Other" then sortByMetadata = true + includeNoLevelCards = true end spawnBag.spawn({ name = "cycle" .. cycle, - cards = allCardsBagApi.getCardsByCycle(cycle, sortByMetadata), + cards = allCardsBagApi.getCardsByCycle(cycle, sortByMetadata, includeNoLevelCards), globalPos = self.positionToWorld(startPositions.cycle), rotation = FACE_UP_ROTATION, spread = true,