deck importer update

This commit is contained in:
Chr1Z93 2024-08-01 20:59:22 +02:00
parent 4071545d96
commit 8a8293d1a2
9 changed files with 174 additions and 116 deletions

View File

@ -138,7 +138,7 @@
"Playermat3Green.383d8b", "Playermat3Green.383d8b",
"Playermat4Red.0840d5", "Playermat4Red.0840d5",
"LeadInvestigator.acaa93", "LeadInvestigator.acaa93",
"ArkhamDBDeckImporter.a28140", "DeckImporter.a28140",
"Configuration.03804b", "Configuration.03804b",
"DrawingTool.280086", "DrawingTool.280086",
"PlayAreaImageSwapper.b7b45b", "PlayAreaImageSwapper.b7b45b",

View File

@ -1 +0,0 @@
{"greenDeck":"","investigators":true,"loadNewest":true,"orangeDeck":"","privateDeck":true,"redDeck":"","whiteDeck":""}

View File

@ -19,7 +19,7 @@
}, },
"ImageScalar": 1, "ImageScalar": 1,
"ImageSecondaryURL": "", "ImageSecondaryURL": "",
"ImageURL": "https://i.imgur.com/wDp1Woo.jpg", "ImageURL": "https://steamusercontent-a.akamaihd.net/ugc/2466368617690977900/DCFE14F204C4038FA382741683862B95DC892F8E/",
"WidthScale": 0 "WidthScale": 0
}, },
"Description": "", "Description": "",
@ -34,10 +34,10 @@
"LayoutGroupSortIndex": 0, "LayoutGroupSortIndex": 0,
"Locked": true, "Locked": true,
"LuaScript": "require(\"arkhamdb/DeckImporter\")", "LuaScript": "require(\"arkhamdb/DeckImporter\")",
"LuaScriptState_path": "ArkhamDBDeckImporter.a28140.luascriptstate", "LuaScriptState_path": "DeckImporter.a28140.luascriptstate",
"MeasureMovement": false, "MeasureMovement": false,
"Name": "Custom_Tile", "Name": "Custom_Tile",
"Nickname": "ArkhamDB Deck Importer", "Nickname": "Deck Importer",
"Snap": false, "Snap": false,
"Sticky": true, "Sticky": true,
"Tooltip": false, "Tooltip": false,

View File

@ -0,0 +1,9 @@
{
"greenDeck": "",
"loadNewest": true,
"orangeDeck": "",
"privateDeck": true,
"redDeck": "",
"standalone": false,
"whiteDeck": ""
}

View File

@ -34,19 +34,19 @@ do
end) end)
end end
-- Start the deck build process for the given player color and deck ID. This -- Start the deck build process for the given player color and deck ID. This
-- will retrieve the deck from ArkhamDB, and pass to a callback for processing. -- will retrieve the deck from ArkhamDB, and pass to a callback for processing.
---@param playerColor string Color name of the player mat to place this deck on (e.g. "Red"). ---@param playerColor string Color name of the player mat to place this deck on (e.g. "Red").
---@param deckId string ArkhamDB deck id to be loaded ---@param deckId string ArkhamDB deck id to be loaded
---@param isPrivate boolean Whether this deck is published or private on ArkhamDB ---@param isPrivate boolean Whether this deck is published or private on ArkhamDB
---@param loadNewest boolean Whether the newest version of this deck should be loaded ---@param loadNewest boolean Whether the newest version of this deck should be loaded
---@param loadInvestigators boolean Whether investigator cards should be loaded as part of this deck ---@param standalone boolean Whether 'Campaign only' weaknesses should be exluded
---@param callback function Callback which will be sent the results of this load ---@param callback function Callback which will be sent the results of this load
--- Parameters to the callback will be: --- Parameters to the callback will be:
--- slots table A map of card ID to count in the deck --- slots table A map of card ID to count in the deck
--- investigatorCode String. ID of the investigator in this deck --- investigatorCode String. ID of the investigator in this deck
--- customizations table The decoded table of customization upgrades in this deck --- customizations table The decoded table of customization upgrades in this deck
--- playerColor String. Color this deck is being loaded for --- playerColor String. Color this deck is being loaded for
---@return boolean ---@return boolean
---@return string ---@return string
ArkhamDb.getDecklist = function( ArkhamDb.getDecklist = function(
@ -54,7 +54,7 @@ do
deckId, deckId,
isPrivate, isPrivate,
loadNewest, loadNewest,
loadInvestigators, standalone,
callback) callback)
-- Get a simple card to see if the bag indexes are complete. If not, abort -- Get a simple card to see if the bag indexes are complete. If not, abort
-- the deck load. The called method will handle player notification. -- the deck load. The called method will handle player notification.
@ -90,11 +90,11 @@ do
return true, json return true, json
end) end)
deck:with(internal.onDeckResult, playerColor, loadNewest, loadInvestigators, callback) deck:with(internal.onDeckResult, playerColor, loadNewest, standalone, callback)
end end
-- Logs that a card could not be loaded in the mod by printing it to the console in the given -- Logs that a card could not be loaded in the mod by printing it to the console in the given
-- color of the player owning the deck. Attempts to look up the name on ArkhamDB for clarity, -- color of the player owning the deck. Attempts to look up the name on ArkhamDB for clarity,
-- but prints the card ID if the name cannot be retrieved. -- but prints the card ID if the name cannot be retrieved.
---@param cardId string ArkhamDB ID of the card that could not be found ---@param cardId string ArkhamDB ID of the card that could not be found
---@param playerColor string Color of the player's deck that had the problem ---@param playerColor string Color of the player's deck that had the problem
@ -118,23 +118,23 @@ do
end) end)
end end
-- Callback when the deck information is received from ArkhamDB. Parses the -- Callback when the deck information is received from ArkhamDB. Parses the
-- response then applies standard transformations to the deck such as adding -- response then applies standard transformations to the deck such as adding
-- random weaknesses and checking for taboos. Once the deck is processed, -- random weaknesses and checking for taboos. Once the deck is processed,
-- passes to loadCards to actually spawn the defined deck. -- passes to loadCards to actually spawn the defined deck.
---@param deck table ArkhamImportDeck ---@param deck table ArkhamImportDeck
---@param playerColor string Color name of the player mat to place this deck on (e.g. "Red") ---@param playerColor string Color name of the player mat to place this deck on (e.g. "Red")
---@param loadNewest boolean Whether the newest version of this deck should be loaded ---@param loadNewest boolean Whether the newest version of this deck should be loaded
---@param loadInvestigators boolean Whether investigator cards should be loaded as part of this deck ---@param standalone boolean Whether 'Campaign only' weaknesses should be exluded
---@param callback function Callback which will be sent the results of this load. ---@param callback function Callback which will be sent the results of this load.
--- Parameters to the callback will be: --- Parameters to the callback will be:
--- slots table A map of card ID to count in the deck --- slots table A map of card ID to count in the deck
--- investigatorCode String. ID of the investigator in this deck --- investigatorCode String. ID of the investigator in this deck
--- bondedList A table of cardID keys to meaningless values. Card IDs in this list were --- bondedList A table of cardID keys to meaningless values. Card IDs in this list were
--- added from a parent bonded card. --- added from a parent bonded card.
--- customizations table The decoded table of customization upgrades in this deck --- customizations table The decoded table of customization upgrades in this deck
--- playerColor String. Color this deck is being loaded for --- playerColor String. Color this deck is being loaded for
internal.onDeckResult = function(deck, playerColor, loadNewest, loadInvestigators, callback) internal.onDeckResult = function(deck, playerColor, loadNewest, standalone, callback)
-- Load the next deck in the upgrade path if the option is enabled -- Load the next deck in the upgrade path if the option is enabled
if (loadNewest and deck.next_deck ~= nil and deck.next_deck ~= "") then if (loadNewest and deck.next_deck ~= nil and deck.next_deck ~= "") then
buildDeck(playerColor, deck.next_deck) buildDeck(playerColor, deck.next_deck)
@ -143,17 +143,20 @@ do
internal.maybePrint(table.concat({ "Found decklist: ", deck.name }), playerColor) internal.maybePrint(table.concat({ "Found decklist: ", deck.name }), playerColor)
-- Initialize deck slot table and perform common transformations. The order of these should not -- Initialize deck slot table and perform common transformations. The order of these should not
-- be changed, as later steps may act on cards added in each. For example, a random weakness or -- be changed, as later steps may act on cards added in each. For example, a random weakness or
-- investigator may have bonded cards or taboo entries, and should be present -- investigator may have bonded cards or taboo entries, and should be present
local slots = deck.slots local slots = deck.slots
internal.maybeDrawRandomWeakness(slots, playerColor)
-- get class for investigator to handle specific weaknesses
local class
local card = allCardsBagApi.getCardById(deck.investigator_code)
if card and card.metadata then class = card.metadata.class end
local restrictions = { class = class, standalone = standalone }
internal.maybeDrawRandomWeakness(slots, playerColor, restrictions)
-- handles alternative investigators (parallel, promo or revised art) -- handles alternative investigators (parallel, promo or revised art)
local loadAltInvestigator = "normal" local loadAltInvestigator = internal.addInvestigatorCards(deck, slots)
if loadInvestigators then
loadAltInvestigator = internal.addInvestigatorCards(deck, slots)
end
internal.maybeModifyDeckFromDescription(slots, deck.description_md, playerColor) internal.maybeModifyDeckFromDescription(slots, deck.description_md, playerColor)
internal.maybeAddSummonedServitor(slots) internal.maybeAddSummonedServitor(slots)
@ -179,13 +182,17 @@ do
--- of those cards which will be spawned --- of those cards which will be spawned
---@param playerColor string Color of the player this deck is being loaded for. Used for broadcast ---@param playerColor string Color of the player this deck is being loaded for. Used for broadcast
--- if a weakness is added. --- if a weakness is added.
internal.maybeDrawRandomWeakness = function(slots, playerColor) ---@param restrictions table Additional restrictions:
--- class string Class to restrict weakness to
--- standalone boolean Whether 'Campaign only' weaknesses should be exluded
--- traits? string Trait(s) to use as filter
internal.maybeDrawRandomWeakness = function(slots, playerColor, restrictions)
local randomWeaknessAmount = slots[RANDOM_WEAKNESS_ID] or 0 local randomWeaknessAmount = slots[RANDOM_WEAKNESS_ID] or 0
slots[RANDOM_WEAKNESS_ID] = nil slots[RANDOM_WEAKNESS_ID] = nil
if randomWeaknessAmount > 0 then if randomWeaknessAmount > 0 then
for i = 1, randomWeaknessAmount do for i = 1, randomWeaknessAmount do
local weaknessId = allCardsBagApi.getRandomWeaknessId() local weaknessId = allCardsBagApi.getRandomWeaknessId(restrictions)
slots[weaknessId] = (slots[weaknessId] or 0) + 1 slots[weaknessId] = (slots[weaknessId] or 0) + 1
end end
internal.maybePrint("Added " .. randomWeaknessAmount .. " random basic weakness(es) to deck", playerColor) internal.maybePrint("Added " .. randomWeaknessAmount .. " random basic weakness(es) to deck", playerColor)
@ -194,7 +201,7 @@ do
-- Adds both the investigator (XXXXX) and minicard (XXXXX-m) slots with one copy each -- Adds both the investigator (XXXXX) and minicard (XXXXX-m) slots with one copy each
---@param deck table The processed ArkhamDB deck response ---@param deck table The processed ArkhamDB deck response
---@param slots table The slot list for cards in this deck. Table key is the cardId, value is the ---@param slots table The slot list for cards in this deck. Table key is the cardId, value is the
--- number of those cards which will be spawned --- number of those cards which will be spawned
---@return string: Contains the name of the art that should be loaded ("normal", "promo" or "revised") ---@return string: Contains the name of the art that should be loaded ("normal", "promo" or "revised")
internal.addInvestigatorCards = function(deck, slots) internal.addInvestigatorCards = function(deck, slots)
@ -271,7 +278,7 @@ do
end end
end end
-- On the Mend should have 1-per-investigator copies set aside, but ArkhamDB always sends 1. Update -- On the Mend should have 1-per-investigator copies set aside, but ArkhamDB always sends 1. Update
-- the count based on the investigator count -- the count based on the investigator count
---@param slots table The slot list for cards in this deck. Table key is the cardId, value is the number ---@param slots table The slot list for cards in this deck. Table key is the cardId, value is the number
-- of those cards which will be spawned -- of those cards which will be spawned

View File

@ -21,9 +21,9 @@ local UPGRADED_TOGGLE_LABELS = {}
UPGRADED_TOGGLE_LABELS[true] = "Upgraded" UPGRADED_TOGGLE_LABELS[true] = "Upgraded"
UPGRADED_TOGGLE_LABELS[false] = "Specific" UPGRADED_TOGGLE_LABELS[false] = "Specific"
local LOAD_INVESTIGATOR_TOGGLE_LABELS = {} local STANDALONE_TOGGLE_LABELS = {}
LOAD_INVESTIGATOR_TOGGLE_LABELS[true] = "Yes" STANDALONE_TOGGLE_LABELS[true] = "Yes"
LOAD_INVESTIGATOR_TOGGLE_LABELS[false] = "No" STANDALONE_TOGGLE_LABELS[false] = "No"
local redDeckId = "" local redDeckId = ""
local orangeDeckId = "" local orangeDeckId = ""
@ -32,7 +32,7 @@ local greenDeckId = ""
local privateDeck = true local privateDeck = true
local loadNewestDeck = true local loadNewestDeck = true
local loadInvestigators = false local standalone = false
function onLoad(script_state) function onLoad(script_state)
initializeUi(JSON.decode(script_state)) initializeUi(JSON.decode(script_state))
@ -53,7 +53,7 @@ function getUiState()
greenDeck = greenDeckId, greenDeck = greenDeckId,
privateDeck = privateDeck, privateDeck = privateDeck,
loadNewest = loadNewestDeck, loadNewest = loadNewestDeck,
investigators = loadInvestigators standalone = standalone
} }
end end
@ -74,7 +74,7 @@ function initializeUi(savedUiState)
greenDeckId = savedUiState.greenDeck greenDeckId = savedUiState.greenDeck
privateDeck = savedUiState.privateDeck privateDeck = savedUiState.privateDeck
loadNewestDeck = savedUiState.loadNewest loadNewestDeck = savedUiState.loadNewest
loadInvestigators = savedUiState.investigators standalone = savedUiState.standalone
end end
makeOptionToggles() makeOptionToggles()
@ -84,72 +84,74 @@ end
function makeOptionToggles() function makeOptionToggles()
-- common parameters -- common parameters
local checkboxParameters = {} local cParams = {}
checkboxParameters.function_owner = self cParams.function_owner = self
checkboxParameters.width = INPUT_FIELD_WIDTH cParams.width = 1750
checkboxParameters.height = INPUT_FIELD_HEIGHT cParams.height = INPUT_FIELD_HEIGHT
checkboxParameters.scale = { 0.1, 0.1, 0.1 } cParams.position = Vector( 0.22, 0.1, -0.102)
checkboxParameters.font_size = 240 cParams.scale = { 0.1, 0.1, 0.1 }
checkboxParameters.hover_color = { 0.4, 0.6, 0.8 } cParams.font_size = 240
checkboxParameters.color = FIELD_COLOR cParams.hover_color = { 0.4, 0.6, 0.8 }
cParams.color = FIELD_COLOR
-- public / private deck -- public / private deck
checkboxParameters.click_function = "publicPrivateChanged" cParams.click_function = "publishedPrivateChanged"
checkboxParameters.position = { 0.25, 0.1, -0.102 } cParams.tooltip = "Published or private deck?\n\nPLEASE USE A PRIVATE DECK IF JUST FOR TTS TO AVOID FLOODING ARKHAMDB PUBLISHED DECK LISTS!\n\nMake sure to enable deck sharing in your account settings.\n\nKeep this on 'Private' for arkham.build."
checkboxParameters.tooltip = "Published or private deck?\n\nPLEASE USE A PRIVATE DECK IF JUST FOR TTS TO AVOID FLOODING ARKHAMDB PUBLISHED DECK LISTS!" cParams.label = PRIVATE_TOGGLE_LABELS[privateDeck]
checkboxParameters.label = PRIVATE_TOGGLE_LABELS[privateDeck] self.createButton(cParams)
self.createButton(checkboxParameters)
-- load upgraded? -- load upgraded?
checkboxParameters.click_function = "loadUpgradedChanged" cParams.click_function = "loadUpgradedChanged"
checkboxParameters.position = { 0.25, 0.1, -0.01 } cParams.position.z = -0.01
checkboxParameters.tooltip = "Load newest upgrade or exact deck?" cParams.tooltip = "Load newest upgrade or exact deck?"
checkboxParameters.label = UPGRADED_TOGGLE_LABELS[loadNewestDeck] cParams.label = UPGRADED_TOGGLE_LABELS[loadNewestDeck]
self.createButton(checkboxParameters) self.createButton(cParams)
-- load investigators? -- standalone mode?
checkboxParameters.click_function = "loadInvestigatorsChanged" cParams.click_function = "standaloneChanged"
checkboxParameters.position = { 0.25, 0.1, 0.081 } cParams.position.z = 0.081
checkboxParameters.tooltip = "Spawn investigator cards?" cParams.tooltip = "Are you playing standalone mode? Enabling this will make all 'Campaign Only' weaknesses ineligible when determining the random basic weakness(es)."
checkboxParameters.label = LOAD_INVESTIGATOR_TOGGLE_LABELS[loadInvestigators] cParams.label = STANDALONE_TOGGLE_LABELS[standalone]
self.createButton(checkboxParameters) self.createButton(cParams)
end end
-- Create the four deck ID entry fields -- Create the four deck ID entry fields
function makeDeckIdFields() function makeDeckIdFields()
local inputParameters = {} local iParams = {}
-- Parameters common to all entry fields iParams.function_owner = self
inputParameters.function_owner = self iParams.scale = { 0.1, 0.1, 0.1 }
inputParameters.scale = { 0.1, 0.1, 0.1 } iParams.width = INPUT_FIELD_WIDTH
inputParameters.width = INPUT_FIELD_WIDTH iParams.height = INPUT_FIELD_HEIGHT
inputParameters.height = INPUT_FIELD_HEIGHT iParams.font_size = 320
inputParameters.font_size = 320 iParams.tooltip = "Deck ID from ArkhamDB URL of the deck\nPublic URL: 'https://arkhamdb.com/decklist/view/101/knowledge-overwhelming-solo-deck-1.0' = '101'\nPrivate URL: 'https://arkhamdb.com/deck/view/102' = '102'\n\nAlso supports the deck ID from shared decks from arkham.build!"
inputParameters.tooltip = "Deck ID from ArkhamDB URL of the deck\nPublic URL: 'https://arkhamdb.com/decklist/view/101/knowledge-overwhelming-solo-deck-1.0' = '101'\nPrivate URL: 'https://arkhamdb.com/deck/view/102' = '102'\n\nAlso supports the deck ID from shared decks from arkham.build!" iParams.alignment = 3 -- Center
inputParameters.alignment = 3 -- Center iParams.color = FIELD_COLOR
inputParameters.color = FIELD_COLOR iParams.font_color = { 0, 0, 0 }
inputParameters.font_color = { 0, 0, 0 } iParams.validation = 4 -- alphanumeric (to support arkham.build IDs)
inputParameters.validation = 4 -- alphanumeric (to support arkham.build IDs)
-- Green -- Green
inputParameters.input_function = "greenDeckChanged" iParams.input_function = "greenDeckChanged"
inputParameters.position = { -0.166, 0.1, 0.385 } iParams.position = { -0.16, 0.1, 0.385 }
inputParameters.value = greenDeckId iParams.value = greenDeckId
self.createInput(inputParameters) self.createInput(iParams)
-- Red -- Red
inputParameters.input_function = "redDeckChanged" iParams.input_function = "redDeckChanged"
inputParameters.position = { 0.171, 0.1, 0.385 } iParams.position = { 0.165, 0.1, 0.385 }
inputParameters.value = redDeckId iParams.value = redDeckId
self.createInput(inputParameters) self.createInput(iParams)
-- White -- White
inputParameters.input_function = "whiteDeckChanged" iParams.input_function = "whiteDeckChanged"
inputParameters.position = { -0.166, 0.1, 0.474 } iParams.position = { -0.16, 0.1, 0.474 }
inputParameters.value = whiteDeckId iParams.value = whiteDeckId
self.createInput(inputParameters) self.createInput(iParams)
-- Orange -- Orange
inputParameters.input_function = "orangeDeckChanged" iParams.input_function = "orangeDeckChanged"
inputParameters.position = { 0.171, 0.1, 0.474 } iParams.position = { 0.165, 0.1, 0.474 }
inputParameters.value = orangeDeckId iParams.value = orangeDeckId
self.createInput(inputParameters) self.createInput(iParams)
end end
-- Create the Build All button. This is a transparent button which covers the Build All portion of the background graphic -- Create the Build All button. This is a transparent button which covers the Build All portion of the background graphic
@ -172,7 +174,7 @@ 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
function publicPrivateChanged() function publishedPrivateChanged()
privateDeck = not privateDeck privateDeck = not privateDeck
self.editButton({ index = 0, label = PRIVATE_TOGGLE_LABELS[privateDeck] }) self.editButton({ index = 0, label = PRIVATE_TOGGLE_LABELS[privateDeck] })
end end
@ -182,9 +184,9 @@ function loadUpgradedChanged()
self.editButton({ index = 1, label = UPGRADED_TOGGLE_LABELS[loadNewestDeck] }) self.editButton({ index = 1, label = UPGRADED_TOGGLE_LABELS[loadNewestDeck] })
end end
function loadInvestigatorsChanged() function standaloneChanged()
loadInvestigators = not loadInvestigators standalone = not standalone
self.editButton({ index = 2, label = LOAD_INVESTIGATOR_TOGGLE_LABELS[loadInvestigators] }) self.editButton({ index = 2, label = STANDALONE_TOGGLE_LABELS[standalone] })
end end
function loadDecks() function loadDecks()
@ -247,7 +249,7 @@ function buildDeck(playerColor, deckId)
deckId, deckId,
uiState.privateDeck, uiState.privateDeck,
uiState.loadNewest, uiState.loadNewest,
uiState.investigators, uiState.standalone,
loadCards) loadCards)
end end

View File

@ -370,19 +370,29 @@ end
-- Gets a random basic weakness from the bag. Once a given ID has been returned it will be -- 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 -- 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. -- are rebuilt, which will refresh the list to include all weaknesses.
---@param restrictions? table Additional restrictions:
--- class string Class to restrict weakness to
--- standalone boolean Whether 'Campaign only' weaknesses should be exluded
--- traits? string Trait(s) to use as filter
---@return string: ID of the selected weakness ---@return string: ID of the selected weakness
function getRandomWeaknessId() function getRandomWeaknessId(restrictions)
local availableWeaknesses = buildAvailableWeaknesses() local availableWeaknesses = buildAvailableWeaknesses(restrictions)
if #availableWeaknesses > 0 then if #availableWeaknesses > 0 then
return availableWeaknesses[math.random(#availableWeaknesses)] return availableWeaknesses[math.random(#availableWeaknesses)]
else
broadcastToAll("No basic weakness available!", { 0.9, 0.2, 0.2 })
end end
end end
-- Constructs a list of available basic weaknesses by starting with the full pool of basic -- 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 -- weaknesses then removing any which are currently in the play or deck construction areas
---@param traits? string Trait(s) to use as filter ---@param restrictions? table Additional restrictions:
--- class string Class to restrict weakness to
--- standalone boolean Whether 'Campaign only' weaknesses should be exluded
--- traits? string Trait(s) to use as filter
---@return table: Array of weakness IDs which are valid to choose from ---@return table: Array of weakness IDs which are valid to choose from
function buildAvailableWeaknesses(traits) function buildAvailableWeaknesses(restrictions)
restrictions = restrictions or {}
local weaknessesInPlay = {} local weaknessesInPlay = {}
local allObjects = getAllObjects() local allObjects = getAllObjects()
for _, object in ipairs(allObjects) do for _, object in ipairs(allObjects) do
@ -400,10 +410,29 @@ function buildAvailableWeaknesses(traits)
if (weaknessesInPlay[weaknessId] ~= nil and weaknessesInPlay[weaknessId] > 0) then if (weaknessesInPlay[weaknessId] ~= nil and weaknessesInPlay[weaknessId] > 0) then
weaknessesInPlay[weaknessId] = weaknessesInPlay[weaknessId] - 1 weaknessesInPlay[weaknessId] = weaknessesInPlay[weaknessId] - 1
else else
if traits then local eligible = true
-- disable 'Campaign only' weaknesses in standalone mode
if restrictions.standalone then
local card = cardIdIndex[weaknessId]
if card.metadata.modeRestriction == "Campaign" then
eligible = false
end
end
-- disable class restricted weaknesses
if restrictions.class then
local card = cardIdIndex[weaknessId]
if card.metadata.classRestriction ~= restrictions.class then
eligible = false
end
end
-- disable non-matching traits
if restrictions.traits then
-- split the string into separate traits (separated by "|") -- split the string into separate traits (separated by "|")
local allowedTraits = {} local allowedTraits = {}
for str in traits:gmatch("([^|]+)") do for str in restrictions.traits:gmatch("([^|]+)") do
-- remove dots -- remove dots
str = str:gsub("[%.]", "") str = str:gsub("[%.]", "")
@ -415,15 +444,24 @@ function buildAvailableWeaknesses(traits)
table.insert(allowedTraits, str) table.insert(allowedTraits, str)
end end
local match = false
-- make sure the trait is present on the weakness -- make sure the trait is present on the weakness
local card = cardIdIndex[weaknessId] local card = cardIdIndex[weaknessId]
for _, allowedTrait in ipairs(allowedTraits) do for _, allowedTrait in ipairs(allowedTraits) do
if string.contains(string.lower(card.metadata.traits), allowedTrait) then if string.contains(string.lower(card.metadata.traits), allowedTrait) then
table.insert(availableWeaknesses, weaknessId) match = true
break break
end end
end end
else
if not match then
eligible = false
end
end
-- add weakness to list if eligible
if eligible then
table.insert(availableWeaknesses, weaknessId) table.insert(availableWeaknesses, weaknessId)
end end
end end

View File

@ -28,9 +28,13 @@ do
-- Gets a random basic weakness from the bag. Once a given ID has been returned it -- 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 -- 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. -- or the indexes are rebuilt, which will refresh the list to include all weaknesses.
---@param restrictions table Additional restrictions:
--- class string Class to restrict weakness to
--- standalone boolean Whether 'Campaign only' weaknesses should be exluded
--- traits? string Trait(s) to use as filter
---@return string: ID of the selected weakness ---@return string: ID of the selected weakness
AllCardsBagApi.getRandomWeaknessId = function() AllCardsBagApi.getRandomWeaknessId = function(restrictions)
return getAllCardsBag().call("getRandomWeaknessId") return getAllCardsBag().call("getRandomWeaknessId", restrictions)
end end
AllCardsBagApi.isIndexReady = function() AllCardsBagApi.isIndexReady = function()
@ -82,10 +86,13 @@ do
-- Constructs a list of available basic weaknesses by starting with the full pool of basic -- 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 -- weaknesses then removing any which are currently in the play or deck construction areas
---@param traits? string Trait(s) to use as filter ---@param restrictions table Additional restrictions:
--- class string Class to restrict weakness to
--- standalone boolean Whether 'Campaign only' weaknesses should be exluded
--- traits? string Trait(s) to use as filter
---@return table: Array of weakness IDs which are valid to choose from ---@return table: Array of weakness IDs which are valid to choose from
AllCardsBagApi.buildAvailableWeaknesses = function(traits) AllCardsBagApi.buildAvailableWeaknesses = function(restrictions)
return returnCopyOfList(getAllCardsBag().call("buildAvailableWeaknesses", traits)) return returnCopyOfList(getAllCardsBag().call("buildAvailableWeaknesses", restrictions))
end end
AllCardsBagApi.getUniqueWeaknesses = function() AllCardsBagApi.getUniqueWeaknesses = function()

View File

@ -783,20 +783,16 @@ function spawnRandomWeakness(_, playerColor, isRightClick)
if not isRightClick then if not isRightClick then
local weaknessId = allCardsBagApi.getRandomWeaknessId() local weaknessId = allCardsBagApi.getRandomWeaknessId()
if weaknessId == nil then if weaknessId then
broadcastToAll("All basic weaknesses are in play!", { 0.9, 0.2, 0.2 })
else
spawnSingleWeakness(weaknessId) spawnSingleWeakness(weaknessId)
end end
else else
Player[playerColor].showInputDialog("Specify a trait for the weakness (split multiple eligible traits with '|'):", lastWeaknessTrait, Player[playerColor].showInputDialog("Specify a trait for the weakness (split multiple eligible traits with '|'):", lastWeaknessTrait,
function(text) function(text)
lastWeaknessTrait = text lastWeaknessTrait = text
local availableWeaknesses = allCardsBagApi.buildAvailableWeaknesses(text) local weaknessId = allCardsBagApi.getRandomWeaknessId({ traits = text })
if #availableWeaknesses > 0 then if weaknessId then
spawnSingleWeakness(availableWeaknesses[math.random(#availableWeaknesses)]) spawnSingleWeakness(weaknessId)
else
broadcastToAll("No matching weakness available!", { 0.9, 0.2, 0.2 })
end end
end) end)
end end
@ -808,6 +804,6 @@ function spawnSingleWeakness(weaknessId)
name = "randomWeakness", name = "randomWeakness",
cards = { weaknessId }, cards = { weaknessId },
globalPos = self.positionToWorld(startPositions.randomWeakness), globalPos = self.positionToWorld(startPositions.randomWeakness),
rotation = FACE_UP_ROTATION, rotation = FACE_UP_ROTATION
}) })
end end