ah_sce_unpacked/unpacked/Bag All Player Cards 15bb07...

419 lines
14 KiB
Plaintext

-- Bundled by luabundle {"version":"1.6.0"}
local __bundle_require, __bundle_loaded, __bundle_register, __bundle_modules = (function(superRequire)
local loadingPlaceholder = {[{}] = true}
local register
local modules = {}
local require
local loaded = {}
register = function(name, body)
if not modules[name] then
modules[name] = body
end
end
require = function(name)
local loadedModule = loaded[name]
if loadedModule then
if loadedModule == loadingPlaceholder then
return nil
end
else
if not modules[name] then
if not superRequire then
local identifier = type(name) == 'string' and '\"' .. name .. '\"' or tostring(name)
error('Tried to require ' .. identifier .. ', but no such module has been registered')
else
return superRequire(name)
end
end
loaded[name] = loadingPlaceholder
loadedModule = modules[name](require, loaded, register, modules)
loaded[name] = loadedModule
end
return loadedModule
end
return require, loaded, register, modules
end)(nil)
__bundle_register("__root", function(require, _LOADED, __bundle_register, __bundle_modules)
require("playercards/AllCardsBag")
end)
__bundle_register("playercards/AllCardsBag", function(require, _LOADED, __bundle_register, __bundle_modules)
local cardIdIndex = { }
local classAndLevelIndex = { }
local basicWeaknessList = { }
local uniqueWeaknessList = { }
local cycleIndex = { }
local indexingDone = false
function onLoad()
self.addContextMenuItem("Rebuild Index", startIndexBuild)
math.randomseed(os.time())
Wait.frames(startIndexBuild, 30)
end
-- 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
-- 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
-- later, and we should rebuild the index to integrate the hotfix bag.
function rebuildIndexForHotfix()
if (indexingDone) then
startIndexBuild()
end
end
-- Resets all current bag indexes
function clearIndexes()
indexingDone = false
cardIdIndex = { }
classAndLevelIndex = { }
classAndLevelIndex["Guardian-upgrade"] = { }
classAndLevelIndex["Seeker-upgrade"] = { }
classAndLevelIndex["Mystic-upgrade"] = { }
classAndLevelIndex["Survivor-upgrade"] = { }
classAndLevelIndex["Rogue-upgrade"] = { }
classAndLevelIndex["Neutral-upgrade"] = { }
classAndLevelIndex["Guardian-level0"] = { }
classAndLevelIndex["Seeker-level0"] = { }
classAndLevelIndex["Mystic-level0"] = { }
classAndLevelIndex["Survivor-level0"] = { }
classAndLevelIndex["Rogue-level0"] = { }
classAndLevelIndex["Neutral-level0"] = { }
cycleIndex = { }
basicWeaknessList = { }
uniqueWeaknessList = { }
end
-- Clears the bag indexes and starts the coroutine to rebuild the indexes
function startIndexBuild()
clearIndexes()
startLuaCoroutine(self, "buildIndex")
end
function onObjectLeaveContainer(container, _)
if container == self then
broadcastToAll("Removing cards from the All Player Cards bag may break some functions.", "Red")
end
end
-- Create the card indexes by iterating all cards in the bag, parsing their
-- metadata, and creating the keyed lookup tables for the cards. This is a
-- coroutine which will spread the workload by processing 20 cards before
-- yielding. Based on the current count of cards this will require
-- approximately 60 frames to complete.
function buildIndex()
local cardCount = 0
indexingDone = false
if (self.getData().ContainedObjects == nil) then
return 1
end
for i, cardData in ipairs(self.getData().ContainedObjects) do
local cardMetadata = JSON.decode(cardData.GMNotes)
if (cardMetadata ~= nil) then
addCardToIndex(cardData, cardMetadata)
cardCount = cardCount + 1
if cardCount > 9 then
cardCount = 0
coroutine.yield(0)
end
end
end
local hotfixBags = getObjectsWithTag("AllCardsHotfix")
for _, hotfixBag in ipairs(hotfixBags) do
if (#hotfixBag.getObjects() > 0) then
for i, cardData in ipairs(hotfixBag.getData().ContainedObjects) do
if cardData.ContainedObjects then
for j, deepCardData in ipairs(cardData.ContainedObjects) do
local deepCardMetadata = JSON.decode(deepCardData.GMNotes)
if deepCardMetadata ~= nil then
addCardToIndex(deepCardData, deepCardMetadata)
cardCount = cardCount + 1
if cardCount > 9 then
cardCount = 0
coroutine.yield(0)
end
end
end
else
local cardMetadata = JSON.decode(cardData.GMNotes)
if cardMetadata ~= nil then
addCardToIndex(cardData, cardMetadata)
cardCount = cardCount + 1
if cardCount > 9 then
cardCount = 0
coroutine.yield(0)
end
end
end
end
end
end
buildSupplementalIndexes()
indexingDone = true
return 1
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
---@param cardMetadata table SCED metadata for the card
function addCardToIndex(cardData, cardMetadata)
-- use the ZoopGuid as fallback if no id present
if cardMetadata.id == nil and cardMetadata.TtsZoopGuid then
cardMetadata.id = cardMetadata.TtsZoopGuid
end
cardIdIndex[cardMetadata.id] = { data = cardData, metadata = cardMetadata }
if (cardMetadata.alternate_ids ~= nil) then
for _, alternateId in ipairs(cardMetadata.alternate_ids) do
cardIdIndex[alternateId] = { data = cardData, metadata = cardMetadata }
end
end
end
function buildSupplementalIndexes()
for cardId, card in pairs(cardIdIndex) do
local cardMetadata = card.metadata
-- If the ID key and the metadata ID don't match this is a duplicate card created by an
-- alternate_id, and we should skip it
if cardId == cardMetadata.id then
-- Add card to the basic weakness list, if appropriate. Some weaknesses have
-- multiple copies, and are added multiple times
if cardMetadata.weakness then
table.insert(uniqueWeaknessList, cardMetadata.id)
if cardMetadata.basicWeaknessCount ~= nil then
for i = 1, cardMetadata.basicWeaknessCount do
table.insert(basicWeaknessList, cardMetadata.id)
end
end
end
-- Add the card to the appropriate class and level indexes
local isGuardian = false
local isSeeker = false
local isMystic = false
local isRogue = false
local isSurvivor = false
local isNeutral = false
local upgradeKey
-- Excludes signature cards (which have no class or level) and alternate
-- ID entries
if (cardMetadata.class ~= nil and cardMetadata.level ~= nil) then
isGuardian = string.match(cardMetadata.class, "Guardian")
isSeeker = string.match(cardMetadata.class, "Seeker")
isMystic = string.match(cardMetadata.class, "Mystic")
isRogue = string.match(cardMetadata.class, "Rogue")
isSurvivor = string.match(cardMetadata.class, "Survivor")
isNeutral = string.match(cardMetadata.class, "Neutral")
if (cardMetadata.level > 0) then
upgradeKey = "-upgrade"
else
upgradeKey = "-level0"
end
if (isGuardian) then
table.insert(classAndLevelIndex["Guardian"..upgradeKey], cardMetadata.id)
end
if (isSeeker) then
table.insert(classAndLevelIndex["Seeker"..upgradeKey], cardMetadata.id)
end
if (isMystic) then
table.insert(classAndLevelIndex["Mystic"..upgradeKey], cardMetadata.id)
end
if (isRogue) then
table.insert(classAndLevelIndex["Rogue"..upgradeKey], cardMetadata.id)
end
if (isSurvivor) then
table.insert(classAndLevelIndex["Survivor"..upgradeKey], cardMetadata.id)
end
if (isNeutral) then
table.insert(classAndLevelIndex["Neutral"..upgradeKey], cardMetadata.id)
end
local cycleName = cardMetadata.cycle
if cycleName ~= nil then
cycleName = string.lower(cycleName)
if string.match(cycleName, "return") then
cycleName = string.sub(cycleName, 11)
end
if cycleName == "the night of the zealot" then
cycleName = "core"
end
if cycleIndex[cycleName] == nil then
cycleIndex[cycleName] = { }
end
table.insert(cycleIndex[cycleName], cardMetadata.id)
end
end
end
end
for _, indexTable in pairs(classAndLevelIndex) do
table.sort(indexTable, cardComparator)
end
for _, indexTable in pairs(cycleIndex) do
table.sort(indexTable)
end
table.sort(basicWeaknessList, cardComparator)
table.sort(uniqueWeaknessList, cardComparator)
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
end
if (card1.data.Nickname ~= card2.data.Nickname) then
return card1.data.Nickname < card2.data.Nickname
end
return card1.data.Description < card2.data.Description
end
function isIndexReady()
return indexingDone
end
-- Returns a specific card from the bag, based on ArkhamDB ID
-- Params table:
-- id: String ID of the card to retrieve
-- Return: If the indexes are still being constructed, an empty table is
-- returned. Otherwise, a single table with the following fields
-- cardData: TTS object data, suitable for spawning the card
-- cardMetadata: Table of parsed metadata
function getCardById(params)
if (not indexingDone) then
broadcastToAll("Still loading player cards, please try again in a few seconds", {0.9, 0.2, 0.2})
return { }
end
return cardIdIndex[params.id]
end
-- Returns a list of cards from the bag matching a class and level (0 or upgraded)
-- Params table:
-- class: String class to retrieve ("Guardian", "Seeker", etc)
-- isUpgraded: true for upgraded cards (Level 1-5), false for Level 0
-- Return: If the indexes are still being constructed, returns an empty table.
-- Otherwise, a list of tables, each with the following fields
-- cardData: TTS object data, suitable for spawning the card
-- cardMetadata: Table of parsed metadata
function getCardsByClassAndLevel(params)
if (not indexingDone) then
broadcastToAll("Still loading player cards, please try again in a few seconds", {0.9, 0.2, 0.2})
return { }
end
local upgradeKey
if (params.upgraded) then
upgradeKey = "-upgrade"
else
upgradeKey = "-level0"
end
return classAndLevelIndex[params.class..upgradeKey];
end
function getCardsByCycle(cycleName)
if (not indexingDone) then
broadcastToAll("Still loading player cards, please try again in a few seconds", {0.9, 0.2, 0.2})
return { }
end
return cycleIndex[string.lower(cycleName)]
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:
-- name String or string fragment to search for names
-- exact Whether the name match should be exact
function getCardsByName(params)
local name = params.name
local exact = params.exact
local results = { }
-- Track cards (by ID) that we've added to avoid duplicates that may come from alternate IDs
local addedCards = { }
for _, cardData in pairs(cardIdIndex) do
if (not addedCards[cardData.metadata.id]) then
if (exact and (string.lower(cardData.data.Nickname) == string.lower(name)))
or (not exact and string.find(string.lower(cardData.data.Nickname), string.lower(name), 1, true)) then
table.insert(results, cardData)
addedCards[cardData.metadata.id] = true
end
end
end
return results
end
-- 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
-- occurs or the indexes are rebuilt, which will refresh the list to include all
-- weaknesses.
-- Return: String ID of the selected weakness.
function getRandomWeaknessId()
local availableWeaknesses = buildAvailableWeaknesses()
if (#availableWeaknesses > 0) then
return availableWeaknesses[math.random(#availableWeaknesses)]
end
end
-- Constructs a list of available basic weaknesses by starting with the full pool of basic
-- weaknesses then removing any which are currently in the play or deck construction areas
-- Return: Table array of weakness IDs which are valid to choose from
function buildAvailableWeaknesses()
local weaknessesInPlay = { }
local allObjects = getAllObjects()
for _, object in ipairs(allObjects) do
if (object.name == "Deck") then
for _, cardData in ipairs(object.getData().ContainedObjects) do
local cardMetadata = JSON.decode(cardData.GMNotes)
incrementWeaknessCount(weaknessesInPlay, cardMetadata)
end
elseif (object.name == "Card") then
local cardMetadata = JSON.decode(object.getGMNotes())
incrementWeaknessCount(weaknessesInPlay, cardMetadata)
end
end
local availableWeaknesses = { }
for _, weaknessId in ipairs(basicWeaknessList) do
if (weaknessesInPlay[weaknessId] ~= nil and weaknessesInPlay[weaknessId] > 0) then
weaknessesInPlay[weaknessId] = weaknessesInPlay[weaknessId] - 1
else
table.insert(availableWeaknesses, weaknessId)
end
end
return availableWeaknesses
end
function getBasicWeaknesses()
return basicWeaknessList
end
function getUniqueWeaknesses()
return uniqueWeaknessList
end
-- Helper function that adds one to the table entry for the number of weaknesses in play
function incrementWeaknessCount(table, cardMetadata)
if (isBasicWeakness(cardMetadata)) then
if (table[cardMetadata.id] == nil) then
table[cardMetadata.id] = 1
else
table[cardMetadata.id] = table[cardMetadata.id] + 1
end
end
end
function isBasicWeakness(cardMetadata)
return cardMetadata ~= nil
and cardMetadata.weakness
and cardMetadata.basicWeaknessCount ~= nil
and cardMetadata.basicWeaknessCount > 0
end
end)
return __bundle_require("__root")