added sorting for custom cards

This commit is contained in:
Chr1Z93 2024-05-25 00:40:18 +02:00
parent afff593874
commit 5b38ea1c02
3 changed files with 111 additions and 30 deletions

View File

@ -12,9 +12,9 @@ function onLoad()
Wait.frames(startIndexBuild, 30) Wait.frames(startIndexBuild, 30)
end end
-- Called by Hotfix bags when they load. If we are still loading indexes, then -- Called by Hotfix bags when they load. If we are still loading indexes, then
-- the all cards and hotfix bags are being loaded together, and we can ignore -- the all cards and hotfix bags are being loaded together, and we can ignore
-- this call as the hotfix will be included in the initial indexing. If it is -- this call as the hotfix will be included in the initial indexing. If it is
-- called once indexing is complete it means the hotfix bag has been added -- called once indexing is complete it means the hotfix bag has been added
-- later, and we should rebuild the index to integrate the hotfix bag. -- later, and we should rebuild the index to integrate the hotfix bag.
function rebuildIndexForHotfix() function rebuildIndexForHotfix()
@ -170,12 +170,16 @@ function buildSupplementalIndexes()
-- override cycle name for night of the zealot -- override cycle name for night of the zealot
cycleName = cycleName:gsub("the night of the zealot", "core") cycleName = cycleName:gsub("the night of the zealot", "core")
else
if cycleIndex[cycleName] == nil then -- track cards without defined cycle (should only be fan-made cards)
cycleIndex[cycleName] = { } cycleName = "other"
end
table.insert(cycleIndex[cycleName], cardMetadata.id)
end end
-- maybe initialize table
if cycleIndex[cycleName] == nil then
cycleIndex[cycleName] = { }
end
table.insert(cycleIndex[cycleName], cardMetadata.id)
end end
end end
end end
@ -220,7 +224,7 @@ end
-- Params table: -- Params table:
-- id: String ID of the card to retrieve -- id: String ID of the card to retrieve
-- Return: If the indexes are still being constructed, an empty table is -- Return: If the indexes are still being constructed, an empty table is
-- returned. Otherwise, a single table with the following fields -- returned. Otherwise, a single table with the following fields
-- cardData: TTS object data, suitable for spawning the card -- cardData: TTS object data, suitable for spawning the card
-- cardMetadata: Table of parsed metadata -- cardMetadata: Table of parsed metadata
function getCardById(params) function getCardById(params)
@ -240,21 +244,80 @@ function getCardsByClassAndLevel(params)
if not isIndexReady() then return {} end if not isIndexReady() then return {} end
local upgradeKey local upgradeKey
if (params.upgraded) then if params.upgraded then
upgradeKey = "-upgrade" upgradeKey = "-upgrade"
else else
upgradeKey = "-level0" upgradeKey = "-level0"
end end
return classAndLevelIndex[params.class..upgradeKey]; return classAndLevelIndex[params.class..upgradeKey]
end end
function getCardsByCycle(cycleName) function getCardsByCycle(params)
if not isIndexReady() then return {} end if not isIndexReady() then return {} end
return cycleIndex[string.lower(cycleName)]
if not params.sortByMetadata then
return cycleIndex[string.lower(params.cycle)]
end
-- sort list by metadata (useful for custom cards without proper IDs)
local cardList = {}
for _, id in ipairs(cycleIndex[string.lower(params.cycle)]) do
table.insert(cardList, id)
end
table.sort(cardList, metadataSortFunction)
return cardList
end end
-- Searches the bag for cards which match the given name and returns a list. Note that this is -- sorts cards by metadata: class, type, level, name and then description
-- an O(n) search without index support. It may be slow. function metadataSortFunction(id1, id2)
local card1 = cardIdIndex[id1]
local card2 = cardIdIndex[id2]
-- extract class per card
local classValue1 = getClassValueFromString(card1.metadata.class)
local classValue2 = getClassValueFromString(card2.metadata.class)
-- conversion tables to simplify type sorting
local typeConversion = {
Asset = 1,
Event = 2,
Skill = 3
}
if classValue1 ~= classValue2 then
return classValue1 < classValue2
elseif typeConversion[card1.metadata.type] ~= typeConversion[card2.metadata.type] then
return typeConversion[card1.metadata.type] < typeConversion[card2.metadata.type]
elseif card1.metadata.level ~= card2.metadata.level then
return card1.metadata.level < card2.metadata.level
elseif card1.data.Nickname ~= card2.data.Nickname then
return card1.data.Nickname < card2.data.Nickname
else
return card1.data.Description < card2.data.Description
end
end
-- helper function to calculate the class value for sorting from the "|" separated string
function getClassValueFromString(s)
local classValueList = {
Guardian = 1,
Seeker = 2,
Rogue = 3,
Mystic = 4,
Survivor = 5,
Neutral = 6
}
local classValue = 0
for str in s:gmatch("([^|]+)") do
-- this sorts multiclass cards
classValue = classValue * 10 + classValueList[str]
end
return classValue
end
-- Searches the bag for cards which match the given name and returns a list. Note that this is
-- an O(n) search without index support. It may be slow.
-- Parameter array must contain these fields to define the search: -- Parameter array must contain these fields to define the search:
-- name String or string fragment to search for names -- name String or string fragment to search for names
-- exact Whether the name match should be exact -- exact Whether the name match should be exact
@ -276,14 +339,14 @@ function getCardsByName(params)
return results return results
end end
-- Gets a random basic weakness from the bag. Once a given ID has been returned -- Gets a random basic weakness from the bag. Once a given ID has been returned
-- it will be removed from the list and cannot be selected again until a reload -- it will be removed from the list and cannot be selected again until a reload
-- occurs or the indexes are rebuilt, which will refresh the list to include all -- occurs or the indexes are rebuilt, which will refresh the list to include all
-- weaknesses. -- weaknesses.
-- Return: String ID of the selected weakness. -- Return: String ID of the selected weakness.
function getRandomWeaknessId() function getRandomWeaknessId()
local availableWeaknesses = buildAvailableWeaknesses() local availableWeaknesses = buildAvailableWeaknesses()
if (#availableWeaknesses > 0) then if #availableWeaknesses > 0 then
return availableWeaknesses[math.random(#availableWeaknesses)] return availableWeaknesses[math.random(#availableWeaknesses)]
end end
end end
@ -295,14 +358,12 @@ function buildAvailableWeaknesses()
local weaknessesInPlay = { } local weaknessesInPlay = { }
local allObjects = getAllObjects() local allObjects = getAllObjects()
for _, object in ipairs(allObjects) do for _, object in ipairs(allObjects) do
if (object.name == "Deck") then if object.type == "Deck" then
for _, cardData in ipairs(object.getData().ContainedObjects) do for _, cardData in ipairs(object.getData().ContainedObjects) do
local cardMetadata = JSON.decode(cardData.GMNotes) incrementWeaknessCount(weaknessesInPlay, JSON.decode(cardData.GMNotes))
incrementWeaknessCount(weaknessesInPlay, cardMetadata)
end end
elseif (object.name == "Card") then elseif object.type == "Card" then
local cardMetadata = JSON.decode(object.getGMNotes()) incrementWeaknessCount(weaknessesInPlay, JSON.decode(object.getGMNotes()))
incrementWeaknessCount(weaknessesInPlay, cardMetadata)
end end
end end
@ -327,8 +388,8 @@ end
-- Helper function that adds one to the table entry for the number of weaknesses in play -- Helper function that adds one to the table entry for the number of weaknesses in play
function incrementWeaknessCount(table, cardMetadata) function incrementWeaknessCount(table, cardMetadata)
if (isBasicWeakness(cardMetadata)) then if isBasicWeakness(cardMetadata) then
if (table[cardMetadata.id] == nil) then if table[cardMetadata.id] == nil then
table[cardMetadata.id] = 1 table[cardMetadata.id] = 1
else else
table[cardMetadata.id] = table[cardMetadata.id] + 1 table[cardMetadata.id] = table[cardMetadata.id] + 1

View File

@ -70,8 +70,8 @@ do
return returnCopyOfList(getAllCardsBag().call("getCardsByClassAndLevel", { class = class, upgraded = upgraded })) return returnCopyOfList(getAllCardsBag().call("getCardsByClassAndLevel", { class = class, upgraded = upgraded }))
end end
AllCardsBagApi.getCardsByCycle = function(cycle) AllCardsBagApi.getCardsByCycle = function(cycle, sortByMetadata)
return returnCopyOfList(getAllCardsBag().call("getCardsByCycle", cycle)) return returnCopyOfList(getAllCardsBag().call("getCardsByCycle", { cycle = cycle, sortByMetadata = sortByMetadata }))
end end
AllCardsBagApi.getUniqueWeaknesses = function() AllCardsBagApi.getUniqueWeaknesses = function()

View File

@ -425,7 +425,7 @@ end
---@param groupName string Name of the group to spawn, matching a key in InvestigatorPanelData ---@param groupName string Name of the group to spawn, matching a key in InvestigatorPanelData
function spawnInvestigators(groupName) function spawnInvestigators(groupName)
if INVESTIGATOR_GROUPS[groupName] == nil then if INVESTIGATOR_GROUPS[groupName] == nil then
printToAll("No " .. groupName .. " data yet") printToAll("No investigator data for " .. groupName .. " yet")
return return
end end
@ -434,7 +434,7 @@ function spawnInvestigators(groupName)
local investigatorCount = #INVESTIGATOR_GROUPS[groupName] local investigatorCount = #INVESTIGATOR_GROUPS[groupName]
local position = getInvestigatorRowStartPos(investigatorCount, row) local position = getInvestigatorRowStartPos(investigatorCount, row)
for i, investigatorName in ipairs(INVESTIGATOR_GROUPS[groupName]) do for _, investigatorName in ipairs(INVESTIGATOR_GROUPS[groupName]) do
for _, spawnSpec in ipairs(buildInvestigatorSpawnSpec(investigatorName, INVESTIGATORS[investigatorName], position)) do for _, spawnSpec in ipairs(buildInvestigatorSpawnSpec(investigatorName, INVESTIGATORS[investigatorName], position)) do
spawnBag.spawn(spawnSpec) spawnBag.spawn(spawnSpec)
end end
@ -625,9 +625,15 @@ function spawnCycle(cycle)
prepareToPlaceCards() prepareToPlaceCards()
spawnInvestigators(cycle) spawnInvestigators(cycle)
-- sort custom cards
local sortByMetadata = false
if cycle == "Other" then
sortByMetadata = true
end
spawnBag.spawn({ spawnBag.spawn({
name = "cycle" .. cycle, name = "cycle" .. cycle,
cards = allCardsBagApi.getCardsByCycle(cycle), cards = allCardsBagApi.getCardsByCycle(cycle, sortByMetadata),
globalPos = self.positionToWorld(startPositions.cycle), globalPos = self.positionToWorld(startPositions.cycle),
rotation = FACE_UP_ROTATION, rotation = FACE_UP_ROTATION,
spread = true, spread = true,
@ -635,6 +641,20 @@ function spawnCycle(cycle)
}) })
end end
-- Comparison function used to sort the class card bag indexes. Sorts by card level, then name, then subname.
function cardComparator(id1, id2)
local card1 = cardIdIndex[id1]
local card2 = cardIdIndex[id2]
if card1.metadata.level ~= card2.metadata.level then
return card1.metadata.level < card2.metadata.level
elseif card1.data.Nickname ~= card2.data.Nickname then
return card1.data.Nickname < card2.data.Nickname
else
return card1.data.Description < card2.data.Description
end
end
function spawnBonded() function spawnBonded()
prepareToPlaceCards() prepareToPlaceCards()
spawnBag.spawn({ spawnBag.spawn({