Merge branch 'main' into global-api
This commit is contained in:
commit
2cb7bf7781
@ -157,7 +157,7 @@
|
||||
"TokenSource.124381",
|
||||
"GameData.3dbe47",
|
||||
"SCEDTour.0e5aa8",
|
||||
"InstructionGenerator.240522",
|
||||
"DeckInstructionGenerator.240522",
|
||||
"PlayerCards.2d30ee",
|
||||
"TokenRemover.39b175",
|
||||
"TokenRemover.2ba7a5",
|
||||
@ -218,7 +218,8 @@
|
||||
"Neutral.06ee01",
|
||||
"Neutral.88d9ff",
|
||||
"Neutral.42ec66",
|
||||
"Neutral.f94579"
|
||||
"Neutral.f94579",
|
||||
"CardBackEnhancer.87450c"
|
||||
],
|
||||
"PlayArea": 1,
|
||||
"PlayerCounts": [
|
||||
|
70
objects/CardBackEnhancer.87450c.json
Normal file
70
objects/CardBackEnhancer.87450c.json
Normal file
@ -0,0 +1,70 @@
|
||||
{
|
||||
"AltLookAngle": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"AttachedSnapPoints": [
|
||||
{
|
||||
"Position": {
|
||||
"x": 0,
|
||||
"y": 0.1,
|
||||
"z": 0.2
|
||||
}
|
||||
}
|
||||
],
|
||||
"Autoraise": true,
|
||||
"ColorDiffuse": {
|
||||
"b": 0,
|
||||
"g": 0,
|
||||
"r": 0
|
||||
},
|
||||
"CustomImage": {
|
||||
"CustomTile": {
|
||||
"Stackable": false,
|
||||
"Stretch": true,
|
||||
"Thickness": 0.1,
|
||||
"Type": 3
|
||||
},
|
||||
"ImageScalar": 1,
|
||||
"ImageSecondaryURL": "",
|
||||
"ImageURL": "https://steamusercontent-a.akamaihd.net/ugc/2466368617700253137/69CF42FB33A6CDDD8A84191FBCB27637E1A7699D/",
|
||||
"WidthScale": 0
|
||||
},
|
||||
"Description": "This tool applies the correct (high resolution) PlayerCard or ScenarioCard back to cards / decks that are dropped on it. It requires the respective tag on each card.\n\nWhy would you need this?\na) You're creating custom content and some cards have the wrong back for some reason.\nb) You're playing custom content and noticed that a card uses an old (low resolution) PlayerCard or ScenarioCard back.",
|
||||
"DragSelectable": true,
|
||||
"GMNotes": "",
|
||||
"GUID": "87450c",
|
||||
"Grid": true,
|
||||
"GridProjection": false,
|
||||
"Hands": false,
|
||||
"HideWhenFaceDown": false,
|
||||
"IgnoreFoW": false,
|
||||
"LayoutGroupSortIndex": 0,
|
||||
"Locked": true,
|
||||
"LuaScriptState": "",
|
||||
"LuaScript": "require(\"accessories/CardBackEnhancer\")",
|
||||
"MeasureMovement": false,
|
||||
"Name": "Custom_Tile",
|
||||
"Nickname": "Card Back Enhancer",
|
||||
"Snap": true,
|
||||
"Sticky": true,
|
||||
"Tags": [
|
||||
"PlayerCard",
|
||||
"ScenarioCard"
|
||||
],
|
||||
"Tooltip": true,
|
||||
"Transform": {
|
||||
"posX": -17.5,
|
||||
"posY": 1.481,
|
||||
"posZ": 89,
|
||||
"rotX": 0,
|
||||
"rotY": 270,
|
||||
"rotZ": 0,
|
||||
"scaleX": 2.667,
|
||||
"scaleY": 1,
|
||||
"scaleZ": 2.667
|
||||
},
|
||||
"Value": 0,
|
||||
"XmlUI": ""
|
||||
}
|
@ -15,23 +15,23 @@
|
||||
],
|
||||
"Autoraise": true,
|
||||
"ColorDiffuse": {
|
||||
"b": 1,
|
||||
"g": 1,
|
||||
"r": 1
|
||||
"b": 0,
|
||||
"g": 0,
|
||||
"r": 0
|
||||
},
|
||||
"CustomImage": {
|
||||
"CustomToken": {
|
||||
"MergeDistancePixels": 15,
|
||||
"CustomTile": {
|
||||
"Stackable": false,
|
||||
"StandUp": false,
|
||||
"Thickness": 0.1
|
||||
"Stretch": true,
|
||||
"Thickness": 0.1,
|
||||
"Type": 3
|
||||
},
|
||||
"ImageScalar": 1,
|
||||
"ImageSecondaryURL": "",
|
||||
"ImageURL": "https://steamusercontent-a.akamaihd.net/ugc/2280574378890547614/63FE6CDF23322B6C4001514E2B8891BA998FAD71/",
|
||||
"ImageURL": "https://steamusercontent-a.akamaihd.net/ugc/2466368617700119071/AB8294EEBA3A219CDCE287323B764D13E2A43822/",
|
||||
"WidthScale": 0
|
||||
},
|
||||
"Description": "This tool can generate a description for your deck on ArkhamDB that will instruct the deck importer to add the specified cards.\nThe cards need to be available (either from the AllCardsBag or the 'Additional Playercards Bag'.",
|
||||
"Description": "This tool can generate a description for your deck on ArkhamDB that will instruct the Deck Importer to add the specified cards.\nThe cards need to be available (either from the AllCardsBag or the 'Additional Playercards Bag'.",
|
||||
"DragSelectable": true,
|
||||
"GMNotes": "",
|
||||
"GUID": "240522",
|
||||
@ -42,25 +42,25 @@
|
||||
"IgnoreFoW": false,
|
||||
"LayoutGroupSortIndex": 0,
|
||||
"Locked": true,
|
||||
"LuaScript": "require(\"arkhamdb/InstructionGenerator\")",
|
||||
"LuaScript": "require(\"arkhamdb/DeckInstructionGenerator\")",
|
||||
"LuaScriptState": "",
|
||||
"MeasureMovement": false,
|
||||
"Name": "Custom_Token",
|
||||
"Nickname": "Instruction Generator",
|
||||
"Name": "Custom_Tile",
|
||||
"Nickname": "Deck Instruction Generator",
|
||||
"Snap": true,
|
||||
"Sticky": true,
|
||||
"Tooltip": true,
|
||||
"Transform": {
|
||||
"posX": -17.5,
|
||||
"posY": 1.531,
|
||||
"posY": 1.481,
|
||||
"posZ": 83,
|
||||
"rotX": 0,
|
||||
"rotY": 270,
|
||||
"rotZ": 0,
|
||||
"scaleX": 1.25,
|
||||
"scaleX": 3,
|
||||
"scaleY": 1,
|
||||
"scaleZ": 1.35
|
||||
"scaleZ": 3
|
||||
},
|
||||
"Value": 0,
|
||||
"XmlUI": ""
|
||||
}
|
||||
}
|
80
src/accessories/CardBackEnhancer.ttslua
Normal file
80
src/accessories/CardBackEnhancer.ttslua
Normal file
@ -0,0 +1,80 @@
|
||||
local backUrl = {
|
||||
ScenarioCard =
|
||||
"https://steamusercontent-a.akamaihd.net/ugc/2342503777940351785/F64D8EFB75A9E15446D24343DA0A6EEF5B3E43DB/",
|
||||
PlayerCard =
|
||||
"https://steamusercontent-a.akamaihd.net/ugc/2342503777940352139/A2D42E7E5C43D045D72CE5CFC907E4F886C8C690/"
|
||||
}
|
||||
|
||||
local deckChanges = {}
|
||||
local lastObjGuid
|
||||
|
||||
function onCollisionEnter(collisionInfo)
|
||||
local obj = collisionInfo.collision_object
|
||||
if obj.guid == lastObjGuid then return end
|
||||
lastObjGuid = obj.guid
|
||||
Wait.time(function() lastObjGuid = nil end, 0.5)
|
||||
|
||||
if obj.type ~= "Card" and obj.type ~= "Deck" then return end
|
||||
|
||||
local data = obj.getData()
|
||||
local count = 0
|
||||
if obj.type == "Card" then
|
||||
local result = processCard(data)
|
||||
if result then count = count + 1 end
|
||||
elseif obj.type == "Deck" then
|
||||
for _, cardData in ipairs(data["ContainedObjects"]) do
|
||||
local result = processCard(cardData)
|
||||
if result then count = count + 1 end
|
||||
end
|
||||
|
||||
-- update top-level custom deck data
|
||||
for customDeckId, customDeckData in pairs(data["CustomDeck"]) do
|
||||
if deckChanges[customDeckId] then
|
||||
customDeckData["BackURL"] = deckChanges[customDeckId]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if count == 1 then
|
||||
broadcastToAll("Enhanced the back of 1 card.")
|
||||
else
|
||||
broadcastToAll("Enhanced the back of " .. count .. " cards.")
|
||||
end
|
||||
|
||||
obj.destruct()
|
||||
spawnObjectData({ data = data })
|
||||
end
|
||||
|
||||
function processCard(cardData)
|
||||
-- determine card type
|
||||
local tags = {}
|
||||
for _, tag in ipairs(cardData["Tags"] or {}) do
|
||||
tags[tag] = true
|
||||
end
|
||||
|
||||
-- has both or neither tag, can't work out back
|
||||
if tags.PlayerCard == tags.ScenarioCard then
|
||||
printToAll("Missing or double tag for '" .. cardData["Nickname"] .. "'.")
|
||||
return false
|
||||
end
|
||||
|
||||
local newBack
|
||||
if tags.PlayerCard then
|
||||
newBack = backUrl.PlayerCard
|
||||
elseif tags.ScenarioCard then
|
||||
newBack = backUrl.ScenarioCard
|
||||
end
|
||||
|
||||
local customDeckId, customDeckData = next(cardData["CustomDeck"])
|
||||
|
||||
-- if this card already has the correct back
|
||||
if customDeckData["BackURL"] == newBack then return false end
|
||||
|
||||
-- skip cards with decksheets as back
|
||||
if (customDeckData["NumHeight"] == 1 and customDeckData["NumWidth"] == 1)
|
||||
or customDeckData["UniqueBack"] == false then
|
||||
customDeckData["BackURL"] = newBack
|
||||
deckChanges[customDeckId] = newBack
|
||||
end
|
||||
return true
|
||||
end
|
@ -7,11 +7,11 @@ function onLoad()
|
||||
local buttonParameters = {}
|
||||
buttonParameters.function_owner = self
|
||||
buttonParameters.height = 200
|
||||
buttonParameters.width = 1200
|
||||
buttonParameters.font_size = 75
|
||||
buttonParameters.width = 800
|
||||
buttonParameters.click_function = "generate"
|
||||
buttonParameters.label = "Generate instructions!"
|
||||
buttonParameters.position = { 0, 0.06, 1.55 }
|
||||
buttonParameters.color = { 0, 0, 0, 0 }
|
||||
buttonParameters.position = { 0, 0.11, 0.74 }
|
||||
buttonParameters.scale = { 0.5, 1, 0.5 }
|
||||
self.createButton(buttonParameters)
|
||||
|
||||
-- "output" text field
|
||||
@ -19,14 +19,15 @@ function onLoad()
|
||||
inputParameters.label = "Click button above"
|
||||
inputParameters.input_function = "none"
|
||||
inputParameters.function_owner = self
|
||||
inputParameters.position = { 0, 0.05, 1.95 }
|
||||
inputParameters.position = { 0, 0.11, 1.1 }
|
||||
inputParameters.width = 1200
|
||||
inputParameters.height = 130
|
||||
inputParameters.font_size = 107
|
||||
inputParameters.scale = { 0.4, 1, 0.4 }
|
||||
self.createInput(inputParameters)
|
||||
end
|
||||
|
||||
-- generates a string for the ArkhamDB deck notes that will instruct the deck import to add the specified cards
|
||||
-- generates a string for the deck notes that will instruct the Deck Importer to add the specified cards
|
||||
function generate(_, playerColor)
|
||||
idList = {}
|
||||
for _, obj in ipairs(searchLib.onObject(self, "isCardOrDeck")) do
|
||||
@ -43,7 +44,8 @@ function generate(_, playerColor)
|
||||
broadcastToColor("Didn't find any valid cards.", playerColor, "Red")
|
||||
return
|
||||
else
|
||||
broadcastToColor("Created deck instruction for " .. #idList .. " card(s). Copy it from the input field.", playerColor, "Green")
|
||||
broadcastToColor("Created deck instruction for " .. #idList .. " card(s). Copy it from the input field.", playerColor,
|
||||
"Green")
|
||||
end
|
||||
|
||||
-- sort the idList
|
||||
@ -55,7 +57,7 @@ function generate(_, playerColor)
|
||||
description = description .. "\n- add: " .. entry.id .. " (**" .. entry.name .. "**)"
|
||||
end
|
||||
|
||||
self.editInput({index = 0, value = description})
|
||||
self.editInput({ index = 0, value = description })
|
||||
end
|
||||
|
||||
-- use the ZoopGuid as fallback if no id present
|
||||
@ -70,7 +72,7 @@ end
|
||||
function processCard(notes, name, playerColor)
|
||||
local id = getIdFromData(JSON.decode(notes) or {})
|
||||
if id then
|
||||
table.insert(idList, {id = id, name = name})
|
||||
table.insert(idList, { id = id, name = name })
|
||||
else
|
||||
broadcastToColor("Couldn't get ID for " .. name .. ".", playerColor, "Red")
|
||||
end
|
@ -55,33 +55,48 @@ function onCollisionEnter(collisionInfo)
|
||||
-- early exit for better performance
|
||||
if object.type ~= "Card" then return end
|
||||
|
||||
-- get scenario name and maybe fire followup event
|
||||
if object.getName() == "Scenario" then
|
||||
local description = object.getDescription()
|
||||
|
||||
-- detect if a new scenario card is placed down
|
||||
if currentScenario ~= description then
|
||||
currentScenario = description
|
||||
fireScenarioChangedEvent()
|
||||
end
|
||||
|
||||
local metadata = JSON.decode(object.getGMNotes()) or {}
|
||||
if not metadata["tokens"] then
|
||||
tokenData = {}
|
||||
return
|
||||
end
|
||||
|
||||
-- detect orientation of scenario card (for difficulty)
|
||||
useFrontData = not object.is_face_down
|
||||
tokenData = metadata["tokens"][(useFrontData and "front" or "back")]
|
||||
fireTokenDataChangedEvent()
|
||||
end
|
||||
|
||||
-- reset spawned tokens and remove tokens from cards in encounter deck / discard area
|
||||
local localPos = self.positionToLocal(object.getPosition())
|
||||
if inArea(localPos, ENCOUNTER_DECK_AREA) or inArea(localPos, ENCOUNTER_DISCARD_AREA) then
|
||||
Wait.frames(function() tokenSpawnTrackerApi.resetTokensSpawned(object) end, 1)
|
||||
removeTokensFromObject(object)
|
||||
return
|
||||
end
|
||||
|
||||
-- get metadata
|
||||
local md = JSON.decode(object.getGMNotes()) or {}
|
||||
|
||||
-- get scenario name and maybe fire followup event
|
||||
local cardName = object.getName()
|
||||
if object.getName() == "Scenario" or md.type == "ScenarioReference" then
|
||||
getDataFromReferenceCard(object, cardName, md)
|
||||
end
|
||||
end
|
||||
|
||||
-- maybe load data from reference card
|
||||
function getDataFromReferenceCard(card, cardName, md)
|
||||
local newScenarioName
|
||||
if cardName == "Scenario" then
|
||||
newScenarioName = card.getDescription()
|
||||
else
|
||||
newScenarioName = cardName
|
||||
end
|
||||
|
||||
-- detect if a new scenario card is placed down
|
||||
if currentScenario ~= newScenarioName then
|
||||
currentScenario = newScenarioName
|
||||
fireScenarioChangedEvent()
|
||||
end
|
||||
|
||||
if not md["tokens"] then
|
||||
tokenData = {}
|
||||
return
|
||||
end
|
||||
|
||||
-- detect orientation of scenario card (for difficulty)
|
||||
useFrontData = not card.is_face_down
|
||||
tokenData = md["tokens"][(useFrontData and "front" or "back")]
|
||||
fireTokenDataChangedEvent()
|
||||
end
|
||||
|
||||
-- TTS event handler. Handles scenario name event triggering
|
||||
|
Loading…
Reference in New Issue
Block a user