updated attachment helper handling

This commit is contained in:
Chr1Z93 2024-10-29 22:45:26 +01:00
parent 591661b9fc
commit a40960457d
4 changed files with 214 additions and 198 deletions

View File

@ -164,28 +164,47 @@ function onDrop(playerColor)
-- assume the first eligible object as intended sync object
local syncObj = searchResult[1]
local syncName = syncObj.getName()
local notes = syncObj.getGMNotes()
local md = JSON.decode(notes) or {}
local md = JSON.decode(syncObj.getGMNotes()) or {}
local found = loadDataFromMetadata({
md = md,
playerColor = playerColor,
syncName = syncName,
syncRotation = syncObj.getRotation()
})
if not found then
printToColor("Didn't find background for '" .. syncName .. "'!", playerColor, "Orange")
end
end
function loadDataFromMetadata(params)
local md = params.md
local syncRotation = params.syncRotation
local playerColor = params.playerColor
local syncName = params.syncName
-- loop through background table
for _, bgInfo in ipairs(BACKGROUNDS) do
if bgInfo.id == md.id or bgInfo.id2 == md.id then
if syncName and playerColor then
printToColor("Background for '" .. syncName .. "' loaded!", playerColor, "Green")
end
showIcons = bgInfo.icons
-- update rotation
local syncRotY = syncObj.getRotation().y
-- maybe update rotation
if syncRotation then
if md.type == "Investigator" then
syncRotY = syncRotY + 90
syncRotation.y = syncRotation.y + 90
end
self.setRotation(self.getRotation():setAt("y", syncRotation.y))
end
self.setRotation(self.getRotation():setAt("y", syncRotY))
-- update the image
updateImage(bgInfo.url)
return
return true
end
end
printToColor("Didn't find background for '" .. syncName .. "'!", playerColor, "Orange")
return false
end
-- called by context menu to change background image

View File

@ -193,7 +193,11 @@ do
for _, weaknessId in ipairs(weaknessIds) do
slots[weaknessId] = (slots[weaknessId] or 0) + 1
end
internal.maybePrint("Added " .. #weaknessIds .. " random basic weakness(es) to deck", playerColor)
if #weaknessIds == 1 then
internal.maybePrint("Added 1 random basic weakness to deck", playerColor)
else
internal.maybePrint("Added " .. #weaknessIds .. " random basic weaknesses to deck", playerColor)
end
end
end

View File

@ -205,7 +205,7 @@ function loadDecksCoroutine()
local deckId = _G[string.lower(matColor) .. "DeckId"]
if deckId ~= nil and deckId ~= "" then
buildDeck(matColor, deckId)
coroutine.yield()
coWaitFrames(3)
end
end
end
@ -224,14 +224,17 @@ end
function getDefaultCardZone(cardMetadata, bondedList)
if cardMetadata.id == "09080-m" then
-- Have to check the Servitor before other minicards
return "SetAside6"
return "SetAside5"
elseif cardMetadata.id == "09006" or cardMetadata.id == "06233" or cardMetadata.id == "06275"
or cardMetadata.id == "71052" or bondedList[cardMetadata.id] then
-- On The Mend, False Awakening, Jewel of Sarnath and bonded cards are set aside
return "SetAside2"
elseif cardMetadata.id == "07303" or cardMetadata.id == "09077" then
-- Ancestral Knowledge / Underworld Market
elseif cardMetadata.id == "07303" then
-- Ancestral Knowledge
return "SetAside3"
elseif cardMetadata.id == "09077" then
-- Underworld Market
return "SetAside6"
elseif cardMetadata.type == "Investigator" then
return "Investigator"
elseif cardMetadata.type == "Minicard" then
@ -292,26 +295,29 @@ function loadCards(slots, investigatorId, bondedList, customizations, playerColo
["09077"] = true,
["10079"] = true
}
local zoneWithAttachments = {}
-- reset the startsInPlayCount
startsInPlayCount = 0
-- reserve slots for cards with attachments
-- reserve slots for cards with attachments (not for Underworld Market)
for cardId, _ in pairs(cardsWithAttachments) do
if slotsCopy[cardId] and slotsCopy[cardId] > 0 then
if cardId ~= "09077" and slotsCopy[cardId] and slotsCopy[cardId] > 0 then
-- increase startsInPlayCount by 1 and reserve slot for this card
startsInPlayCount = startsInPlayCount + 1
cardsWithAttachments[cardId] = startsInPlayCount
-- reserve an additional slot for the attachments
startsInPlayCount = startsInPlayCount + 1
zoneWithAttachments["Blank" .. startsInPlayCount] = true
end
end
for cardId, cardCount in pairs(slots) do
local card = allCardsBagApi.getCardById(cardId)
if card ~= nil then
if cardsWithAttachments[cardId] and cardsWithAttachments[cardId] < 6 then
local reservedSlot = cardsWithAttachments[cardId]
if type(reservedSlot) == "number" and reservedSlot < 6 then
cardZone = "Blank" .. cardsWithAttachments[cardId]
else
cardZone = getDefaultCardZone(card.metadata, bondedList)
@ -347,25 +353,35 @@ function loadCards(slots, investigatorId, bondedList, customizations, playerColo
-- Check for existing cards in zones and maybe skip them
removeBusyZones(playerColor, zoneDecks)
-- Spawn attachment helpers if option is enabled
if GlobalApi.getOptionPanelState()["showAttachmentHelper"] then
local objs = getObjectsWithTag("AttachmentHelperBag")
if #objs > 0 then
local helperRot = zones.getDefaultCardRotation(playerColor, "Blank1")
for cardId, reservedSlot in pairs(cardsWithAttachments) do
if type(reservedSlot) == "number" and reservedSlot < 6 then
local helper = objs[1].takeObject({
position = zones.getZonePosition(playerColor, "Blank" .. (reservedSlot + 1)):setAt("y", 1.8),
rotation = helperRot,
smooth = false
})
coWaitFrames(3)
helper.call("loadDataFromMetadata", { md = { id = cardId } })
coWaitFrames(3)
end
end
end
end
-- Spawn the list for each zone
for zone, zoneCards in pairs(zoneDecks) do
local deckPos = zones.getZonePosition(playerColor, zone):setAt("y", 3)
local deckRot = zones.getDefaultCardRotation(playerColor, zone)
local callback = nil
-- spawn attachment helpers if option is enabled
if GlobalApi.getOptionPanelState()["showAttachmentHelper"] then
local objs = getObjectsWithTag("AttachmentHelperBag")
if #objs > 0 then
for cardId, reservedSlot in pairs(cardsWithAttachments) do
if reservedSlot < 7 then
objs[1].takeObject({
position = zones.getZonePosition(playerColor, "Blank" .. reservedSlot):setAt("y", 1.6),
rotation = deckRot
})
end
end
end
-- if this is a zone with attachments, spawn cards facedown and add additional delay
if zoneWithAttachments[zone] then
deckRot = deckRot:setAt("z", 180)
end
-- If cards are spread too close together TTS groups them weirdly, selecting multiples
@ -388,7 +404,7 @@ function loadCards(slots, investigatorId, bondedList, customizations, playerColo
callback = function(card) loadAltArt(card, loadAltInvestigator) end
end
Spawner.spawnCards(zoneCards, deckPos, deckRot, true, callback)
coroutine.yield(0)
coWaitFrames(3)
end
-- Look for any cards which haven't been loaded
@ -529,6 +545,7 @@ function removeBusyZones(playerColor, zoneDecks)
zoneDecks["Blank" .. i] = nil
end
zoneDecks["UnderSetAside3"] = nil
zoneDecks["UnderSetAside6"] = nil
zoneDecks["Deck"] = nil
printToAll("Skipped deck import", playerColor)
end
@ -548,7 +565,6 @@ function handleAncestralKnowledge(cardsToSpawn)
for i = 1, 5 do
local skillListIndex = math.random(#skillList)
cardsToSpawn[skillList[skillListIndex]].zone = "UnderSetAside3"
table.remove(skillList, skillListIndex)
end
end
@ -556,10 +572,10 @@ end
function handleAllAttachments(cardsToSpawn, slotsCopy, bondedList, customizations, playerColor)
for cardId, reservedSlot in pairs(cardsWithAttachments) do
if slotsCopy[cardId] and slotsCopy[cardId] > 0 then
if customizations["attachments_" .. cardId] and reservedSlot < 6 then
if customizations["attachments_" .. cardId] and type(reservedSlot) == "number" and reservedSlot < 6 then
handleAttachment(cardId, cardsToSpawn, customizations)
elseif cardId == "09077" then
handleUnderworldMarket(cardsToSpawn, slotsCopy, playerColor)
handleUnderworldMarket(cardsToSpawn, customizations, playerColor)
elseif cardId == "05002" then
handleHunchDeck(cardsToSpawn, bondedList, playerColor)
elseif cardId == "07303" then
@ -580,7 +596,7 @@ function handleAttachment(parentId, cardsToSpawn, customizations)
local zone = "Blank" .. (cardsWithAttachments[parentId] + 1)
for i = #attachmentList, 1, -1 do
for j = #cardsToSpawn, 1, -1 do
if cardsToSpawn[j].metadata.id == attachmentList[i] and cardsToSpawn[j].zone ~= zone then
if cardsToSpawn[j].metadata.id == attachmentList[i] and cardsToSpawn[j].zone == "Deck" then
cardsToSpawn[j].zone = zone
break
end
@ -588,16 +604,34 @@ function handleAttachment(parentId, cardsToSpawn, customizations)
end
end
-- Check for and handle Underworld Market by moving all Illicit cards to UnderSetAside3
---@param cardList table Deck list being created
-- Check for and handle Underworld Market by moving all Illicit cards to UnderSetAside6
---@param cardsToSpawn table Deck list being created
---@param playerColor string Color this deck is being loaded for
function handleUnderworldMarket(cardList, slotsCopy, playerColor)
if not slotsCopy["09077"] or slotsCopy["09077"] == 0 then return end
function handleUnderworldMarket(cardsToSpawn, customizations, playerColor)
local attachmentList = {}
if customizations["attachments_09077"] then
-- get list of cards that are attached (split by ",")
for str in string.gmatch(customizations["attachments_09077"], "([^,]+)") do
table.insert(attachmentList, str)
end
end
if #attachmentList == 10 then
-- handling for 10 cards selected in deck data
for i = #attachmentList, 1, -1 do
for j = #cardsToSpawn, 1, -1 do
if cardsToSpawn[j].metadata.id == attachmentList[i] and cardsToSpawn[j].zone == "Deck" then
cardsToSpawn[j].zone = "UnderSetAside6"
break
end
end
end
else
-- regular handling
local illicitList = {}
-- get all possible Illicit cards
for i, card in ipairs(cardList) do
for i, card in ipairs(cardsToSpawn) do
if card.metadata.traits ~= nil and string.find(card.metadata.traits, "Illicit", 1, true) and card.zone == "Deck" then
table.insert(illicitList, i)
end
@ -606,14 +640,8 @@ function handleUnderworldMarket(cardList, slotsCopy, playerColor)
if #illicitList < 10 then
printToAll("Only " .. #illicitList .. " Illicit cards in your deck, you can't trigger Underworld Market's ability.", playerColor)
else
-- Process cards to move them to the market deck. This is done in reverse order because the sorting needs
-- to be reversed (deck sorts for face down). Performance here may be an issue, as table.remove() is an O(n)
-- operation which makes the full shift O(n^2). But keep it simple unless it becomes a problem
for i = #illicitList, 1, -1 do
local moving = cardList[illicitList[i]]
moving.zone = "UnderSetAside3"
table.remove(cardList, illicitList[i])
table.insert(cardList, moving)
cardsToSpawn[illicitList[i]].zone = "UnderSetAside6"
end
if #illicitList > 10 then
@ -622,6 +650,7 @@ function handleUnderworldMarket(cardList, slotsCopy, playerColor)
printToAll("Built the Market deck", playerColor)
end
end
end
end
-- Extract all Insight events to SetAside5 to build the Hunch Deck for Joe Diamond
@ -630,10 +659,10 @@ end
function handleHunchDeck(cardList, bondedList, playerColor)
local insightList = {}
for i, card in ipairs(cardList) do
if (card.metadata.type == "Event"
if card.metadata.type == "Event"
and card.metadata.traits ~= nil
and string.match(card.metadata.traits, "Insight")
and bondedList[card.metadata.id] == nil) then
and bondedList[card.metadata.id] == nil then
table.insert(insightList, i)
end
end
@ -696,11 +725,9 @@ function handleSpiritDeck(cardList, playerColor, customizations)
end
if #spiritList < 10 then
printToAll("Jim's spirit deck must have 9 Ally assets but the deck only has " ..
(#spiritList - 1) .. " Ally assets.", playerColor)
printToAll("Jim's spirit deck must have 9 Ally assets but the deck only has " .. (#spiritList - 1) .. " Ally assets.", playerColor)
elseif #spiritList > 11 then
printToAll("Moved all " .. (#spiritList - 1) ..
" Ally assets to the spirit deck, reduce it to 10 (including Vengeful Shade).", playerColor)
printToAll("Moved all " .. (#spiritList - 1) .. " Ally assets to the spirit deck, reduce it to 10 (including Vengeful Shade).", playerColor)
else
printToAll("Built Jim's spirit deck", playerColor)
end
@ -835,3 +862,10 @@ function deepCopy(data)
end
return copiedList
end
-- pauses the current coroutine for 'frameCount' frames
function coWaitFrames(frameCount)
for k = 1, frameCount do
coroutine.yield(0)
end
end

View File

@ -15,108 +15,70 @@
-- SetAside[4-6]: Column farther away from the mat, with 4 at the top and 6 at the bottom.
-- SetAside1: Permanent cards
-- SetAside2: Bonded cards
-- SetAside3: Ancestral Knowledge / Underworld Market
-- SetAside3: Ancestral Knowledge
-- SetAside4: Upgrade sheets for customizable cards
-- SetAside5: Hunch Deck for Joe Diamond
-- SetAside6: currently unused
-- SetAside5: Hunch Deck for Joe Diamond // Summoned Servitor Minicard
-- SetAside6: Underworld Market
-- AboveSetAside: Investigator specific object
-- BelowSetAside: Investigator specific object
do
local playermatApi = require("playermat/PlayermatApi")
local Zones = { }
local Zones = {}
-- local coordinates for each playermat
local commonZones = {}
commonZones["Investigator"] = { -1.177, 0, 0.002 }
commonZones["Deck"] = { -1.82, 0, 0 }
commonZones["Discard"] = { -1.82, 0, 0.61 }
commonZones["Ally"] = { -0.615, 0, 0.024 }
commonZones["Body"] = { -0.630, 0, 0.553 }
commonZones["Hand1"] = { 0.215, 0, 0.042 }
commonZones["Hand2"] = { -0.180, 0, 0.037 }
commonZones["Arcane1"] = { 0.212, 0, 0.559 }
commonZones["Arcane2"] = { -0.171, 0, 0.557 }
commonZones["Tarot"] = { 0.602, 0, 0.033 }
commonZones["Accessory"] = { 0.602, 0, 0.555 }
commonZones["Blank1"] = { 1.758, 0, 0.040 }
commonZones["Blank2"] = { 1.754, 0, 0.563 }
commonZones["Blank3"] = { 1.371, 0, 0.038 }
commonZones["Blank4"] = { 1.371, 0, 0.558 }
commonZones["Blank5"] = { 0.98, 0, 0.035 }
commonZones["Blank6"] = { 0.977, 0, 0.556 }
commonZones["Threat1"] = { -0.911, 0, -0.625 }
commonZones["Threat2"] = { -0.454, 0, -0.625 }
commonZones["Threat3"] = { 0.002, 0, -0.625 }
commonZones["Threat4"] = { 0.459, 0, -0.625 }
commonZones["Investigator"] = Vector(-1.177, 0, 0.002)
commonZones["Deck"] = Vector(-1.82, 0, 0)
commonZones["Discard"] = Vector(-1.82, 0, 0.61)
commonZones["Ally"] = Vector(-0.616, 0, 0.024)
commonZones["Body"] = Vector(-0.631, 0, 0.551)
commonZones["Hand1"] = Vector(0.217, 0, 0.035)
commonZones["Hand2"] = Vector(-0.177, 0, 0.032)
commonZones["Arcane1"] = Vector(0.212, 0, 0.559)
commonZones["Arcane2"] = Vector(-0.174, 0, 0.551)
commonZones["Tarot"] = Vector(0.602, 0, 0.033)
commonZones["Accessory"] = Vector(0.605, 0, 0.555)
commonZones["Blank1"] = Vector(1.758, 0, 0.040)
commonZones["Blank2"] = Vector(1.754, 0, 0.563)
commonZones["Blank3"] = Vector(1.371, 0, 0.038)
commonZones["Blank4"] = Vector(1.371, 0, 0.558)
commonZones["Blank5"] = Vector(0.98, 0, 0.035)
commonZones["Blank6"] = Vector(0.977, 0, 0.556)
commonZones["Threat1"] = Vector(-0.911, 0, -0.625)
commonZones["Threat2"] = Vector(-0.454, 0, -0.625)
commonZones["Threat3"] = Vector(0.002, 0, -0.625)
commonZones["Threat4"] = Vector(0.459, 0, -0.625)
-- local coordinates for white / green (inverted X for orange / red)
local mirrorZones = {}
mirrorZones["Minicard"] = Vector(-1, 0, -1.45)
mirrorZones["SetAside1"] = Vector(2.35, 0, -0.520)
mirrorZones["SetAside2"] = Vector(2.35, 0, 0.042)
mirrorZones["SetAside3"] = Vector(2.35, 0, 0.605)
mirrorZones["UnderSetAside3"] = Vector(2.50, 0, 0.805)
mirrorZones["SetAside4"] = Vector(2.78, 0, -0.520)
mirrorZones["SetAside5"] = Vector(2.78, 0, 0.042)
mirrorZones["SetAside6"] = Vector(2.78, 0, 0.605)
mirrorZones["UnderSetAside6"] = Vector(2.93, 0, 0.805)
mirrorZones["AboveSetAside"] = Vector(2.35, 0, -1.069)
mirrorZones["BelowSetAside"] = Vector(2.85, 0, 1.650)
local zoneData = {}
zoneData["White"] = {}
zoneData["White"]["Investigator"] = commonZones["Investigator"]
zoneData["White"]["Deck"] = commonZones["Deck"]
zoneData["White"]["Discard"] = commonZones["Discard"]
zoneData["White"]["Ally"] = commonZones["Ally"]
zoneData["White"]["Body"] = commonZones["Body"]
zoneData["White"]["Hand1"] = commonZones["Hand1"]
zoneData["White"]["Hand2"] = commonZones["Hand2"]
zoneData["White"]["Arcane1"] = commonZones["Arcane1"]
zoneData["White"]["Arcane2"] = commonZones["Arcane2"]
zoneData["White"]["Tarot"] = commonZones["Tarot"]
zoneData["White"]["Accessory"] = commonZones["Accessory"]
zoneData["White"]["Blank1"] = commonZones["Blank1"]
zoneData["White"]["Blank2"] = commonZones["Blank2"]
zoneData["White"]["Blank3"] = commonZones["Blank3"]
zoneData["White"]["Blank4"] = commonZones["Blank4"]
zoneData["White"]["Blank5"] = commonZones["Blank5"]
zoneData["White"]["Blank6"] = commonZones["Blank6"]
zoneData["White"]["Threat1"] = commonZones["Threat1"]
zoneData["White"]["Threat2"] = commonZones["Threat2"]
zoneData["White"]["Threat3"] = commonZones["Threat3"]
zoneData["White"]["Threat4"] = commonZones["Threat4"]
zoneData["White"]["Minicard"] = { -1, 0, -1.45 }
zoneData["White"]["SetAside1"] = { 2.35, 0, -0.520 }
zoneData["White"]["SetAside2"] = { 2.35, 0, 0.042 }
zoneData["White"]["SetAside3"] = { 2.35, 0, 0.605 }
zoneData["White"]["UnderSetAside3"] = { 2.50, 0, 0.805 }
zoneData["White"]["SetAside4"] = { 2.78, 0, -0.520 }
zoneData["White"]["SetAside5"] = { 2.78, 0, 0.042 }
zoneData["White"]["SetAside6"] = { 2.78, 0, 0.605 }
zoneData["White"]["UnderSetAside6"] = { 2.93, 0, 0.805 }
zoneData["White"]["AboveSetAside"] = { 2.35, 0, -1.069 }
zoneData["White"]["BelowSetAside"] = { 2.85, 0, 1.650 }
zoneData["Orange"] = {}
zoneData["Orange"]["Investigator"] = commonZones["Investigator"]
zoneData["Orange"]["Deck"] = commonZones["Deck"]
zoneData["Orange"]["Discard"] = commonZones["Discard"]
zoneData["Orange"]["Ally"] = commonZones["Ally"]
zoneData["Orange"]["Body"] = commonZones["Body"]
zoneData["Orange"]["Hand1"] = commonZones["Hand1"]
zoneData["Orange"]["Hand2"] = commonZones["Hand2"]
zoneData["Orange"]["Arcane1"] = commonZones["Arcane1"]
zoneData["Orange"]["Arcane2"] = commonZones["Arcane2"]
zoneData["Orange"]["Tarot"] = commonZones["Tarot"]
zoneData["Orange"]["Accessory"] = commonZones["Accessory"]
zoneData["Orange"]["Blank1"] = commonZones["Blank1"]
zoneData["Orange"]["Blank2"] = commonZones["Blank2"]
zoneData["Orange"]["Blank3"] = commonZones["Blank3"]
zoneData["Orange"]["Blank4"] = commonZones["Blank4"]
zoneData["Orange"]["Blank5"] = commonZones["Blank5"]
zoneData["Orange"]["Blank6"] = commonZones["Blank6"]
zoneData["Orange"]["Threat1"] = commonZones["Threat1"]
zoneData["Orange"]["Threat2"] = commonZones["Threat2"]
zoneData["Orange"]["Threat3"] = commonZones["Threat3"]
zoneData["Orange"]["Threat4"] = commonZones["Threat4"]
zoneData["Orange"]["Minicard"] = { 1, 0, -1.45 }
zoneData["Orange"]["SetAside1"] = { -2.35, 0, -0.520 }
zoneData["Orange"]["SetAside2"] = { -2.35, 0, 0.042}
zoneData["Orange"]["SetAside3"] = { -2.35, 0, 0.605 }
zoneData["Orange"]["UnderSetAside3"] = { -2.50, 0, 0.805 }
zoneData["Orange"]["SetAside4"] = { -2.78, 0, -0.520 }
zoneData["Orange"]["SetAside5"] = { -2.78, 0, 0.042 }
zoneData["Orange"]["SetAside6"] = { -2.78, 0, 0.605 }
zoneData["Orange"]["UnderSetAside6"] = { -2.93, 0, 0.805 }
zoneData["Orange"]["AboveSetAside"] = { -2.35, 0, -1.069 }
zoneData["Orange"]["BelowSetAside"] = { -2.85, 0, 1.650 }
-- copy common coordinates
for zoneName, zonePos in pairs(commonZones) do
zoneData["White"][zoneName] = zonePos
zoneData["Orange"][zoneName] = zonePos
end
-- copy mirrored coordinates
for zoneName, zonePos in pairs(mirrorZones) do
zoneData["White"][zoneName] = zonePos
zoneData["Orange"][zoneName] = zonePos * Vector(-1, 1, 1)
end
-- Green positions are the same as White and Red the same as Orange
zoneData["Red"] = zoneData["Orange"]
@ -127,14 +89,11 @@ do
---@param zoneName string Name of the zone to get the position for. See Zones object documentation for a list of valid zones.
---@return tts__Vector|nil: Global position table, or nil if an invalid player color or zone is specified
Zones.getZonePosition = function(playerColor, zoneName)
if (playerColor ~= "Red"
and playerColor ~= "Orange"
and playerColor ~= "White"
and playerColor ~= "Green") then
return nil
end
if zoneData[playerColor] then
return playermatApi.transformLocalPosition(zoneData[playerColor][zoneName], playerColor)
end
return nil
end
-- Return the global rotation for a card on the given player mat, based on its zone.
---@param playerColor string Color name of the player mat to get the rotation for (e.g. "Red")
@ -144,8 +103,8 @@ do
-- Z rotation to place the card face up or face down.
Zones.getDefaultCardRotation = function(playerColor, zoneName)
local cardRotation = playermatApi.returnRotation(playerColor)
if zoneName == "Deck" then
cardRotation = cardRotation + Vector(0, 0, 180)
if zoneName == "Deck" or zoneName == "UnderSetAside3" or zoneName == "UnderSetAside6" then
cardRotation = cardRotation:setAt("z", 180)
end
return cardRotation
end