foundation for custom cards

This commit is contained in:
Chr1Z93 2024-05-24 21:54:29 +02:00
parent 831a4fd4c9
commit afff593874
6 changed files with 174 additions and 191 deletions

View File

@ -150,11 +150,8 @@ end
-- Event handlers for deck ID change -- Event handlers for deck ID change
function redDeckChanged(_, _, inputValue) redDeckId = inputValue end function redDeckChanged(_, _, inputValue) redDeckId = inputValue end
function orangeDeckChanged(_, _, inputValue) orangeDeckId = inputValue end function orangeDeckChanged(_, _, inputValue) orangeDeckId = inputValue end
function whiteDeckChanged(_, _, inputValue) whiteDeckId = inputValue end function whiteDeckChanged(_, _, inputValue) whiteDeckId = inputValue end
function greenDeckChanged(_, _, inputValue) greenDeckId = inputValue end function greenDeckChanged(_, _, inputValue) greenDeckId = inputValue end
-- Event handlers for toggle buttons -- Event handlers for toggle buttons
@ -174,14 +171,7 @@ function loadInvestigatorsChanged()
end end
function loadDecks() function loadDecks()
-- testLoadLotsOfDecks() if not allCardsBagApi.isIndexReady() then return end
-- Method in DeckImporterMain, visible due to inclusion
local indexReady = allCardsBagApi.isIndexReady()
if (not indexReady) then
broadcastToAll("Still loading player cards, please try again in a few seconds", {0.9, 0.2, 0.2})
return
end
if (redDeckId ~= nil and redDeckId ~= "") then if (redDeckId ~= nil and redDeckId ~= "") then
buildDeck("Red", redDeckId) buildDeck("Red", redDeckId)
end end

View File

@ -18,7 +18,7 @@ end
-- 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()
if (indexingDone) then if indexingDone then
startIndexBuild() startIndexBuild()
end end
end end
@ -210,6 +210,9 @@ function cardComparator(id1, id2)
end end
function isIndexReady() function isIndexReady()
if not indexingDone then
broadcastToAll("Still loading player cards, please try again in a few seconds", {0.9, 0.2, 0.2})
end
return indexingDone return indexingDone
end end
@ -221,10 +224,7 @@ end
-- 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)
if (not indexingDone) then if not isIndexReady() then return {} end
broadcastToAll("Still loading player cards, please try again in a few seconds", {0.9, 0.2, 0.2})
return { }
end
return cardIdIndex[params.id] return cardIdIndex[params.id]
end end
@ -237,10 +237,8 @@ end
-- 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 getCardsByClassAndLevel(params) function getCardsByClassAndLevel(params)
if (not indexingDone) then if not isIndexReady() then return {} end
broadcastToAll("Still loading player cards, please try again in a few seconds", {0.9, 0.2, 0.2})
return { }
end
local upgradeKey local upgradeKey
if (params.upgraded) then if (params.upgraded) then
upgradeKey = "-upgrade" upgradeKey = "-upgrade"
@ -251,10 +249,7 @@ function getCardsByClassAndLevel(params)
end end
function getCardsByCycle(cycleName) function getCardsByCycle(cycleName)
if (not indexingDone) then if not isIndexReady() then return {} end
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)] return cycleIndex[string.lower(cycleName)]
end end

View File

@ -6,6 +6,14 @@ do
return guidReferenceApi.getObjectByOwnerAndType("Mythos", "AllCardsBag") return guidReferenceApi.getObjectByOwnerAndType("Mythos", "AllCardsBag")
end end
local function returnCopyOfList(data)
local copiedList = {}
for _, id in ipairs(data) do
table.insert(copiedList, id)
end
return copiedList
end
-- Returns a specific card from the bag, based on ArkhamDB ID -- Returns a specific card from the bag, based on ArkhamDB ID
---@param id table String ID of the card to retrieve ---@param id table String ID of the card to retrieve
---@return table table ---@return table table
@ -36,7 +44,7 @@ do
-- 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.
AllCardsBagApi.rebuildIndexForHotfix = function() AllCardsBagApi.rebuildIndexForHotfix = function()
return getAllCardsBag().call("rebuildIndexForHotfix") getAllCardsBag().call("rebuildIndexForHotfix")
end end
-- Searches the bag for cards which match the given name and returns a list. Note that this is -- Searches the bag for cards which match the given name and returns a list. Note that this is
@ -44,7 +52,7 @@ do
---@param name string or string fragment to search for names ---@param name string or string fragment to search for names
---@param exact boolean Whether the name match should be exact ---@param exact boolean Whether the name match should be exact
AllCardsBagApi.getCardsByName = function(name, exact) AllCardsBagApi.getCardsByName = function(name, exact)
return getAllCardsBag().call("getCardsByName", {name = name, exact = exact}) return returnCopyOfList(getAllCardsBag().call("getCardsByName", { name = name, exact = exact }))
end end
AllCardsBagApi.isBagPresent = function() AllCardsBagApi.isBagPresent = function()
@ -59,15 +67,15 @@ do
-- 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
AllCardsBagApi.getCardsByClassAndLevel = function(class, upgraded) AllCardsBagApi.getCardsByClassAndLevel = function(class, upgraded)
return 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)
return getAllCardsBag().call("getCardsByCycle", cycle) return returnCopyOfList(getAllCardsBag().call("getCardsByCycle", cycle))
end end
AllCardsBagApi.getUniqueWeaknesses = function() AllCardsBagApi.getUniqueWeaknesses = function()
return getAllCardsBag().call("getUniqueWeaknesses") return returnCopyOfList(getAllCardsBag().call("getUniqueWeaknesses"))
end end
return AllCardsBagApi return AllCardsBagApi

View File

@ -26,8 +26,6 @@ local CYCLE_BUTTONS_Z_OFFSET = 0.2665
local STARTER_DECK_MODE_SELECTED_COLOR = { 0.2, 0.2, 0.2, 0.8 } local STARTER_DECK_MODE_SELECTED_COLOR = { 0.2, 0.2, 0.2, 0.8 }
local TRANSPARENT = { 0, 0, 0, 0 } local TRANSPARENT = { 0, 0, 0, 0 }
local STARTER_DECK_MODE_STARTERS = "starters"
local STARTER_DECK_MODE_CARDS_ONLY = "cards"
local FACE_UP_ROTATION = { x = 0, y = 270, z = 0 } local FACE_UP_ROTATION = { x = 0, y = 270, z = 0 }
local FACE_DOWN_ROTATION = { x = 0, y = 270, z = 180 } local FACE_DOWN_ROTATION = { x = 0, y = 270, z = 180 }
@ -78,7 +76,14 @@ local investigatorPositionShiftCol
local investigatorCardOffset local investigatorCardOffset
local investigatorSignatureOffset local investigatorSignatureOffset
local CLASS_LIST = { "Guardian", "Seeker", "Rogue", "Mystic", "Survivor", "Neutral" } local CLASS_LIST = {
"Guardian",
"Seeker",
"Rogue",
"Mystic",
"Survivor",
"Neutral"
}
local CYCLE_LIST = { local CYCLE_LIST = {
"Core", "Core",
"The Dunwich Legacy", "The Dunwich Legacy",
@ -94,8 +99,7 @@ local CYCLE_LIST = {
} }
local excludedNonBasicWeaknesses local excludedNonBasicWeaknesses
local spawnStarterDecks = false
local starterDeckMode = STARTER_DECK_MODE_CARDS_ONLY
local helpVisibleToPlayers = {} local helpVisibleToPlayers = {}
function onSave() function onSave()
@ -274,9 +278,8 @@ function createCycleButtons()
if rowCount == 3 then if rowCount == 3 then
-- Account for two centered buttons on the final row -- Account for two centered buttons on the final row
buttonPos.x = buttonPos.x + CYCLE_BUTTONS_X_OFFSET / 2 buttonPos.x = buttonPos.x + CYCLE_BUTTONS_X_OFFSET / 2
--[[ Account for centered button on the final row -- Account for centered button on the final row
buttonPos.x = buttonPos.x + CYCLE_BUTTONS_X_OFFSET -- buttonPos.x = buttonPos.x + CYCLE_BUTTONS_X_OFFSET
]]
end end
else else
buttonPos.x = buttonPos.x + CYCLE_BUTTONS_X_OFFSET buttonPos.x = buttonPos.x + CYCLE_BUTTONS_X_OFFSET
@ -297,8 +300,6 @@ function createClearButton()
end end
function createInvestigatorModeButtons() function createInvestigatorModeButtons()
local starterMode = starterDeckMode == STARTER_DECK_MODE_STARTERS
self.createButton({ self.createButton({
function_owner = self, function_owner = self,
click_function = "setCardsOnlyMode", click_function = "setCardsOnlyMode",
@ -306,18 +307,18 @@ function createInvestigatorModeButtons()
height = 170, height = 170,
width = 760, width = 760,
scale = Vector(0.25, 1, 0.25), scale = Vector(0.25, 1, 0.25),
color = starterMode and TRANSPARENT or STARTER_DECK_MODE_SELECTED_COLOR color = spawnStarterDecks and TRANSPARENT or STARTER_DECK_MODE_SELECTED_COLOR
}) })
self.createButton({ self.createButton({
function_owner = self, function_owner = self,
click_function = "setStarterDeckMode", click_function = "setspawnStarterDecks",
position = Vector(0.66, 0.1, -0.322), position = Vector(0.66, 0.1, -0.322),
height = 170, height = 170,
width = 760, width = 760,
scale = Vector(0.25, 1, 0.25), scale = Vector(0.25, 1, 0.25),
color = starterMode and STARTER_DECK_MODE_SELECTED_COLOR or TRANSPARENT color = spawnStarterDecks and STARTER_DECK_MODE_SELECTED_COLOR or TRANSPARENT
}) })
local checkX = starterMode and 0.52 or 0.11 local checkX = spawnStarterDecks and 0.52 or 0.11
self.createButton({ self.createButton({
function_owner = self, function_owner = self,
label = "✓", label = "✓",
@ -325,7 +326,8 @@ function createInvestigatorModeButtons()
position = Vector(checkX, 0.11, -0.317), position = Vector(checkX, 0.11, -0.317),
height = 0, height = 0,
width = 0, width = 0,
scale = Vector(0.3, 1, 0.3), font_size = 300,
scale = Vector(0.1, 1, 0.1),
font_color = { 0, 0, 0 }, font_color = { 0, 0, 0 },
color = { 1, 1, 1 } color = { 1, 1, 1 }
}) })
@ -354,13 +356,13 @@ function updateHelpVisibility()
self.UI.setAttribute("helpPanel", "active", string.len(visibility) > 0) self.UI.setAttribute("helpPanel", "active", string.len(visibility) > 0)
end end
function setStarterDeckMode() function setspawnStarterDecks()
starterDeckMode = STARTER_DECK_MODE_STARTERS spawnStarterDecks = true
updateStarterModeButtons() updateStarterModeButtons()
end end
function setCardsOnlyMode() function setCardsOnlyMode()
starterDeckMode = STARTER_DECK_MODE_CARDS_ONLY spawnStarterDecks = false
updateStarterModeButtons() updateStarterModeButtons()
end end
@ -405,14 +407,12 @@ function deleteAll()
spawnBag.recall(true) spawnBag.recall(true)
end end
-- Spawn an investigator group, based on the current UI setting for either investigators or starter -- Spawn an investigator group, based on the current UI setting for either investigators or starter decks
-- decks.
---@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 spawnInvestigatorGroup(groupName) function spawnInvestigatorGroup(groupName)
local starterMode = starterDeckMode == STARTER_DECK_MODE_STARTERS
prepareToPlaceCards() prepareToPlaceCards()
Wait.frames(function() Wait.frames(function()
if starterMode then if spawnStarterDecks then
spawnStarters(groupName) spawnStarters(groupName)
else else
spawnInvestigators(groupName) spawnInvestigators(groupName)
@ -547,6 +547,7 @@ function spawnStarterDeck(investigatorName, investigatorData, position)
}) })
end) end)
end end
-- Clears the currently placed cards, then places cards for the given class and level spread -- Clears the currently placed cards, then places cards for the given class and level spread
---@param cardClass string Class to place ("Guardian", "Seeker", etc) ---@param cardClass string Class to place ("Guardian", "Seeker", etc)
---@param isUpgraded boolean If true, spawn the Level 1-5 cards. Otherwise, Level 0. ---@param isUpgraded boolean If true, spawn the Level 1-5 cards. Otherwise, Level 0.
@ -559,11 +560,8 @@ end
---@param cardClass string Class to place ("Guardian", "Seeker", etc) ---@param cardClass string Class to place ("Guardian", "Seeker", etc)
---@param isUpgraded boolean If true, spawn the Level 1-5 cards. Otherwise, Level 0. ---@param isUpgraded boolean If true, spawn the Level 1-5 cards. Otherwise, Level 0.
function placeClassCards(cardClass, isUpgraded) function placeClassCards(cardClass, isUpgraded)
local indexReady = allCardsBagApi.isIndexReady() if not allCardsBagApi.isIndexReady() then return end
if (not indexReady) then
broadcastToAll("Still loading player cards, please try again in a few seconds", {0.9, 0.2, 0.2})
return
end
local cardIdList = allCardsBagApi.getCardsByClassAndLevel(cardClass, isUpgraded) local cardIdList = allCardsBagApi.getCardsByClassAndLevel(cardClass, isUpgraded)
local skillList = {} local skillList = {}
@ -614,24 +612,22 @@ function placeClassCards(cardClass, isUpgraded)
end end
end end
-- called by the XML UI to spawn cards from fan-made camnpaigns
function spawnOtherCards()
spawnCycle("Other")
end
-- Spawns the investigator sets and all cards for the given cycle -- Spawns the investigator sets and all cards for the given cycle
---@param cycle string Name of a cycle, should match the standard used in card metadata ---@param cycle string Name of a cycle, should match the standard used in card metadata
function spawnCycle(cycle) function spawnCycle(cycle)
if not allCardsBagApi.isIndexReady() then return end
prepareToPlaceCards() prepareToPlaceCards()
spawnInvestigators(cycle) spawnInvestigators(cycle)
local indexReady = allCardsBagApi.isIndexReady()
if (not indexReady) then
broadcastToAll("Still loading player cards, please try again in a few seconds", {0.9, 0.2, 0.2})
return
end
local cycleCardList = allCardsBagApi.getCardsByCycle(cycle)
local copiedList = { }
for i, id in ipairs(cycleCardList) do
copiedList[i] = id
end
spawnBag.spawn({ spawnBag.spawn({
name = "cycle" .. cycle, name = "cycle" .. cycle,
cards = copiedList, cards = allCardsBagApi.getCardsByCycle(cycle),
globalPos = self.positionToWorld(startPositions.cycle), globalPos = self.positionToWorld(startPositions.cycle),
rotation = FACE_UP_ROTATION, rotation = FACE_UP_ROTATION,
spread = true, spread = true,
@ -671,16 +667,13 @@ end
-- Clears the current cards, and places all basic weaknesses on the table. -- Clears the current cards, and places all basic weaknesses on the table.
function spawnWeaknesses() function spawnWeaknesses()
if not allCardsBagApi.isIndexReady() then return end
prepareToPlaceCards() prepareToPlaceCards()
local indexReady = allCardsBagApi.isIndexReady()
if (not indexReady) then
broadcastToAll("Still loading player cards, please try again in a few seconds", {0.9, 0.2, 0.2})
return
end
local weaknessIdList = allCardsBagApi.getUniqueWeaknesses()
local basicWeaknessList = {} local basicWeaknessList = {}
local otherWeaknessList = {} local otherWeaknessList = {}
for i, id in ipairs(weaknessIdList) do for _, id in ipairs(allCardsBagApi.getUniqueWeaknesses()) do
local cardMetadata = allCardsBagApi.getCardById(id).metadata local cardMetadata = allCardsBagApi.getCardById(id).metadata
if cardMetadata.basicWeaknessCount ~= nil and cardMetadata.basicWeaknessCount > 0 then if cardMetadata.basicWeaknessCount ~= nil and cardMetadata.basicWeaknessCount > 0 then
table.insert(basicWeaknessList, id) table.insert(basicWeaknessList, id)

View File

@ -81,21 +81,13 @@ do
-- Places the given spawnSpec on the table. See comment at the start of the file for spawnSpec table data and examples -- Places the given spawnSpec on the table. See comment at the start of the file for spawnSpec table data and examples
SpawnBag.spawn = function(spawnSpec) SpawnBag.spawn = function(spawnSpec)
-- Limit to one placement at a time -- Limit to one placement at a time
if (placedSpecs[spawnSpec.name]) then if placedSpecs[spawnSpec.name] or spawnSpec == nil then return end
return
end
if (spawnSpec == nil) then
-- TODO: error here
return
end
local cardsToSpawn = {} local cardsToSpawn = {}
local cardList = spawnSpec.cards for _, cardId in ipairs(spawnSpec.cards) do
for _, cardId in ipairs(cardList) do
local cardData = allCardsBagApi.getCardById(cardId) local cardData = allCardsBagApi.getCardById(cardId)
if (cardData ~= nil) then if cardData ~= nil then
table.insert(cardsToSpawn, cardData) table.insert(cardsToSpawn, cardData)
else
-- TODO: error here
end end
end end
if (spawnSpec.spread) then if (spawnSpec.spread) then
@ -120,14 +112,13 @@ do
internal.recallSpawned() internal.recallSpawned()
end end
-- We've recalled everything we can, some cards may have been moved out of the -- We've recalled everything we can, some cards may have been moved out of the card area. Just reset at this point.
-- card area. Just reset at this point.
placedSpecs = {} placedSpecs = {}
placedObjectGuids = {} placedObjectGuids = {}
recallZone = nil recallZone = nil
end end
-- Deleted all spawned cards. -- Delete all spawned cards
internal.deleteSpawned = function() internal.deleteSpawned = function()
for guid, _ in pairs(placedObjectGuids) do for guid, _ in pairs(placedObjectGuids) do
local obj = getObjectFromGUID(guid) local obj = getObjectFromGUID(guid)
@ -140,7 +131,7 @@ do
end end
end end
-- Recalls spawned cards with a fake bag that replicates the memory bag recall style. -- Recalls spawned cards with a fake bag that replicates the memory bag recall style
internal.recallSpawned = function() internal.recallSpawned = function()
local trash = spawnObjectData({ data = RECALL_BAG, position = self.getPosition() }) local trash = spawnObjectData({ data = RECALL_BAG, position = self.getPosition() })
for guid, _ in pairs(placedObjectGuids) do for guid, _ in pairs(placedObjectGuids) do
@ -156,9 +147,7 @@ do
trash.destruct() trash.destruct()
end end
-- Callback for when an object has been spawned. Tracks the object for later recall and updates the recall zone.
-- Callback for when an object has been spawned. Tracks the object for later recall and updates the
-- recall zone.
internal.recordPlacedObject = function(spawned) internal.recordPlacedObject = function(spawned)
placedObjectGuids[spawned.getGUID()] = true placedObjectGuids[spawned.getGUID()] = true
internal.expandRecallZone(spawned) internal.expandRecallZone(spawned)
@ -174,21 +163,22 @@ do
recallZone.upperLeft = { x = pos.x + RECALL_BUFFER_X, z = pos.z + RECALL_BUFFER_Z } recallZone.upperLeft = { x = pos.x + RECALL_BUFFER_X, z = pos.z + RECALL_BUFFER_Z }
recallZone.lowerRight = { x = pos.x - RECALL_BUFFER_X, z = pos.z - RECALL_BUFFER_Z } recallZone.lowerRight = { x = pos.x - RECALL_BUFFER_X, z = pos.z - RECALL_BUFFER_Z }
return return
else end
if (pos.x > recallZone.upperLeft.x) then
if pos.x > recallZone.upperLeft.x then
recallZone.upperLeft.x = pos.x + RECALL_BUFFER_X recallZone.upperLeft.x = pos.x + RECALL_BUFFER_X
end end
if (pos.x < recallZone.lowerRight.x) then if pos.x < recallZone.lowerRight.x then
recallZone.lowerRight.x = pos.x - RECALL_BUFFER_X recallZone.lowerRight.x = pos.x - RECALL_BUFFER_X
end end
if (pos.z > recallZone.upperLeft.z) then if pos.z > recallZone.upperLeft.z then
recallZone.upperLeft.z = pos.z + RECALL_BUFFER_Z recallZone.upperLeft.z = pos.z + RECALL_BUFFER_Z
end end
if (pos.z < recallZone.lowerRight.z) then if pos.z < recallZone.lowerRight.z then
recallZone.lowerRight.z = pos.z - RECALL_BUFFER_Z recallZone.lowerRight.z = pos.z - RECALL_BUFFER_Z
end end
end
if (SHOW_RECALL_ZONE) then if SHOW_RECALL_ZONE then
local y = 1.5 local y = 1.5
local thick = 0.05 local thick = 0.05
Global.setVectorLines({ Global.setVectorLines({

View File

@ -1,24 +1,31 @@
<Panel <Panel active="false"
active="false"
id="helpPanel" id="helpPanel"
position="-165 -60 -2" position="-165 -70 -2"
rotation="0 0 180" rotation="0 0 180"
height="55" height="50"
width="107" width="107"
color="#00000099"> color="#00000099">
<Text <Text id="helpText"
id="helpText"
rectAlignment="MiddleCenter" rectAlignment="MiddleCenter"
height="490" height="480"
width="1000" width="1000"
scale="0.1 0.1 1" scale="0.1 0.1 1"
fontSize="66" fontSize="66"
color="#F5F5F5" color="#F5F5F5"
backgroundColor="#FF0000" backgroundColor="#FF0000"
alignment="UpperLeft" alignment="MiddleLeft"
horizontalOverflow="wrap"> horizontalOverflow="wrap">
• Select a group to place cards • Select a group to place cards
• Copy the cards you want for your deck • Copy the cards you want for your deck
• Select a new group to clear the placed cards and see new ones • Select a new group to clear the placed cards and see new ones
• Clear to remove all cards</Text> • Clear to remove all cards</Text>
</Panel> </Panel>
<Panel position="45 65 -11"
rotation="0 0 180"
height="200"
width="200"
scale="0.1 0.1 1"
color="#FFFFFF"
onClick="spawnOtherCards">
</Panel>