Updated campaign exporter and option panel

This commit is contained in:
Chr1Z93 2024-04-29 11:25:41 +02:00
parent 7ad53e2192
commit e1428547b5
2 changed files with 112 additions and 133 deletions

View File

@ -56,13 +56,13 @@ function onLoad()
})
end
function onObjectLeaveContainer(container, _)
function onObjectLeaveContainer(container)
if container.hasTag("ImporterToken") then
broadcastToAll("Removing objects from the Save Coin bag will break functionality. Please return the removed objects.", "Yellow")
end
end
function onObjectEnterContainer(container, _)
function onObjectEnterContainer(container)
if container.hasTag("ImporterToken") then
broadcastToAll("Adding objects to the Save Coin bag will break functionality. Please remove the objects.", "Yellow")
end
@ -78,7 +78,7 @@ function onCollisionEnter(info)
end
end
-- Identifies import token, determines campaign box and downloads it (if needed)
-- identifies import token, determines campaign box and downloads it (if needed)
function importFromToken(coin)
broadcastToAll("Campaign Import Initiated")
local importData = JSON.decode(coin.getGMNotes())
@ -115,7 +115,7 @@ function importFromToken(coin)
)
end
-- After box has been downloaded, places content on table
-- after box has been downloaded, places content on table
function placeCampaignFromToken(importData, coin)
getObjectFromGUID(importData["box"]).call("buttonClick_place")
Wait.condition(
@ -126,31 +126,28 @@ function placeCampaignFromToken(importData, coin)
)
end
-- After content is placed on table, conducts all the other import operations
-- after content is placed on table, conducts all the other import operations
function restoreCampaignData(importData, coin)
-- destroy existing campaign log
findUniqueObjectWithTag("CampaignLog").destruct()
-- go over internal items and respawn them (only storing campaign log and additional player cards)
for _, objData in ipairs(coin.getData().ContainedObjects) do
objData.Locked = true
local spawnData = { data = objData }
-- destroy existing "additional player cards" bag
if importData["additionalIndex"] then
guidReferenceApi.getObjectByOwnerAndType("Mythos", "AdditionalPlayerCardsBag").destruct()
end
if coin.type == "Bag" then
-- go over internal items and spawn them at the original position
for _, objData in ipairs(coin.getData().ContainedObjects) do
objData["Locked"] = true
spawnObjectData({data = objData})
-- maybe restore position of item and destroy duplicate
if objData.Nickname == "Additional Player Cards" then
local additionalIndex = guidReferenceApi.getObjectByOwnerAndType("Mythos", "AdditionalPlayerCardsBag")
spawnData.position = additionalIndex.getPosition()
additionalIndex.destruct()
else
local campaignLog = findUniqueObjectWithTag("CampaignLog")
if campaignLog then
spawnData.position = campaignLog.getPosition()
campaignLog.destruct()
end
end
else
-- support for older save coins that stored the data serialized
if importData["additionalIndex"] then
spawnObjectJSON({json = importData["additionalIndex"]})
end
spawnObjectData({data = importData["log"]})
end
coin.destruct()
spawnObjectData(spawnData)
end
chaosBagApi.setChaosBagState(importData["bag"])
@ -164,21 +161,21 @@ function restoreCampaignData(importData, coin)
deckImporterApi.setUiState(importData["decks"])
end
playAreaApi.setInvestigatorCount(importData["clueCount"])
-- set campaign guide page
local guide = findUniqueObjectWithTag("CampaignGuide")
if guide then
Wait.condition(
-- Called after the condition function returns true
function() printToAll("Campaign Guide import successful!") end,
-- Condition function that is called continuously until it returns true or timeout is reached
function() return guide.Book.setPage(importData["guide"]) end,
-- Amount of time in seconds until the Wait times out
2,
-- Called if the Wait times out
function() printToAll("Campaign Guide import failed!") end
)
-- maybe set campaign guide page
if importData["guide"] then
local campaignGuide = findUniqueObjectWithTag("CampaignGuide")
if campaignGuide then
Wait.condition(
-- Called after the condition function returns true
function() printToAll("Campaign Guide import successful!") end,
-- Condition function that is called continuously until it returns true or timeout is reached
function() return campaignGuide.Book.setPage(importData["guide"]) end,
-- Amount of time in seconds until the Wait times out
2,
-- Called if the Wait times out
function() printToAll("Campaign Guide import failed!") end
)
end
end
Wait.time(function() optionPanelApi.loadSettings(importData["options"]) end, 0.5)
@ -189,14 +186,21 @@ function restoreCampaignData(importData, coin)
tourStarter.destruct()
end
-- restore PlayArea image
-- restore PlayArea image and player count
playAreaApi.updateSurface(importData["playarea"])
playAreaApi.setInvestigatorCount(importData["clueCount"])
coin.destruct()
broadcastToAll("Campaign successfully imported!", "Green")
end
-- Creates a campaign token with save data encoded into GM Notes based on the current state of the table
-- creates a campaign token with save data encoded into GM Notes based on the current state of the table
function createCampaignToken(_, playerColor, _)
local campaignData = {}
-- need to reset the contained objects to support multiple exports
campaignTokenData.ContainedObjects = {}
-- find active campaign
local campaignBox
for _, obj in ipairs(getObjectsWithTag("CampaignBox")) do
@ -204,7 +208,7 @@ function createCampaignToken(_, playerColor, _)
if not campaignBox then
campaignBox = obj
else
broadcastToAll("Multiple empty campaign box detected; delete all but one.", "Red")
broadcastToAll("Multiple empty campaign boxes detected; delete all but one.", "Red")
return
end
end
@ -215,60 +219,55 @@ function createCampaignToken(_, playerColor, _)
return
end
local campaignLog = findUniqueObjectWithTag("CampaignLog")
if campaignLog == nil then
broadcastToAll("Campaign log not found!", "Red")
return
end
local additionalIndex = guidReferenceApi.getObjectByOwnerAndType("Mythos", "AdditionalPlayerCardsBag")
local traumaValues = { }
local trauma = campaignLog.getVar("returnTrauma")
if trauma ~= nil then
printToAll("Trauma values found in campaign log!", "Green")
trauma = campaignLog.call("returnTrauma")
for _, val in ipairs(trauma) do
table.insert(traumaValues, val)
end
else
traumaValues = nil
printToAll("Trauma values could not be found in campaign log!", "Yellow")
end
local campaignGuide = findUniqueObjectWithTag("CampaignGuide")
if campaignGuide == nil then
broadcastToAll("Campaign guide not found!", "Red")
return
end
-- clean up chaos tokens
-- clean up chaos tokens (needs to happen before saving chaos bag state)
blessCurseApi.removeAll(playerColor)
chaosBagApi.releaseAllSealedTokens(playerColor)
local campaignData = {
box = campaignBox.getGUID(),
log = campaignLog.getPosition(),
bag = chaosBagApi.getChaosBagState(),
trauma = traumaValues,
decks = deckImporterApi.getUiState(),
clueCount = playAreaApi.getInvestigatorCount(),
playarea = playAreaApi.getSurface(),
options = optionPanelApi.getOptions(),
guide = campaignGuide.Book.getPage(),
additionalIndex = additionalIndex.getPosition()
}
-- main data collection
campaignData.box = campaignBox.getGUID()
campaignData.bag = chaosBagApi.getChaosBagState()
campaignData.decks = deckImporterApi.getUiState()
campaignData.clueCount = playAreaApi.getInvestigatorCount()
campaignData.playarea = playAreaApi.getSurface()
campaignData.options = optionPanelApi.getOptions()
-- save campaign log if present
local campaignLog = findUniqueObjectWithTag("CampaignLog")
if campaignLog then
local logData = campaignLog.getData()
logData.Locked = false
table.insert(campaignTokenData.ContainedObjects, logData)
-- maybe also extract the trauma values
local trauma = campaignLog.getVar("returnTrauma")
if trauma then
printToAll("Trauma values found in campaign log!", "Green")
campaignData.trauma = {}
for _, val in ipairs(campaignLog.call("returnTrauma")) do
table.insert(campaignData.trauma, val)
end
else
printToAll("Trauma values could not be found in campaign log!", "Yellow")
end
end
-- store campaign guide page if present
local campaignGuide = findUniqueObjectWithTag("CampaignGuide")
if campaignGuide then
campaignData.guide = campaignGuide.Book.getPage()
end
-- store the additional index if there are any cards in it
local additionalIndex = guidReferenceApi.getObjectByOwnerAndType("Mythos", "AdditionalPlayerCardsBag")
if additionalIndex and #additionalIndex.getObjects() > 0 then
local indexData = additionalIndex.getData()
indexData.Locked = false
table.insert(campaignTokenData.ContainedObjects, indexData)
end
-- finish the data for the campaign token
campaignTokenData.GMNotes = JSON.encode(campaignData)
campaignTokenData.Nickname = campaignBox.getName() .. os.date(" %b %d") .. " Save"
campaignTokenData.ContainedObjects = { }
local indexData = additionalIndex.getData()
indexData.Locked = false
table.insert(campaignTokenData.ContainedObjects, indexData)
local logData = campaignLog.getData()
logData.Locked = false
table.insert(campaignTokenData.ContainedObjects, logData)
spawnObjectData({ data = campaignTokenData })
broadcastToAll("Campaign successfully exported! Save coin object to import on a different save.", "Green")

View File

@ -54,7 +54,7 @@ local tabIdTable = {
tab5 = "fanmadePlayerCards"
}
-- optionPanel data
-- optionPanel data (intentionally not local!)
optionPanel = {}
local LANGUAGES = {
{ code = "zh_CN", name = "简体中文" },
@ -762,7 +762,6 @@ end
-- returns all sealed tokens on cards to the chaos bag
function releaseAllSealedTokens(playerColor)
local chaosBag = findChaosBag()
for _, obj in ipairs(getObjectsWithTag("CardThatSeals")) do
obj.call("releaseAllTokens", playerColor)
end
@ -1331,17 +1330,16 @@ end
-- called by toggling an option
function onClick_toggleOption(_, id)
local state = self.UI.getAttribute(id, "isOn")
local toggleState = self.UI.getAttribute(id, "isOn")
-- flip state (and handle stupid "False" value)
if state == "False" then
state = true
-- flip state (and handle stupid "False" values)
if toggleState == "False" then
self.UI.setAttribute(id, "isOn", true)
applyOptionPanelChange(id, true)
else
state = false
self.UI.setAttribute(id, "isOn", "False")
applyOptionPanelChange(id, false)
end
self.UI.setAttribute(id, "isOn", state)
applyOptionPanelChange(id, state)
end
-- color selection for playArea
@ -1439,24 +1437,23 @@ function updateOptionPanelState()
end
end
-- handles the applying of option selections and calls the respective functions based
-- handles the applying of option selections and calls the respective functions based on the id
---@param id string ID of the option that was selected or deselected
---@param state boolean|any State of the option (true = enabled)
function applyOptionPanelChange(id, state)
optionPanel[id] = state
-- option: Snap tags
if id == "useSnapTags" then
playmatApi.setLimitSnapsByType(state, "All")
optionPanel[id] = state
-- option: Draw 1 button
elseif id == "showDrawButton" then
playmatApi.showDrawButton(state, "All")
optionPanel[id] = state
-- option: Clickable clue counters
elseif id == "useClueClickers" then
playmatApi.clickableClues(state, "All")
optionPanel[id] = state
-- update master clue counter
local counter = guidReferenceApi.getObjectByOwnerAndType("Mythos", "MasterClueCounter")
@ -1465,52 +1462,39 @@ function applyOptionPanelChange(id, state)
-- option: Play area snap tags
elseif id == "playAreaConnections" then
playAreaApi.setConnectionDrawState(state)
optionPanel[id] = state
-- option: Play area connection color
elseif id == "playAreaConnectionColor" then
playAreaApi.setConnectionColor(state)
UI.setAttribute(id, "color", "#" .. Color.new(state):toHex())
optionPanel[id] = state
-- option: Play area snap tags
elseif id == "playAreaSnapTags" then
playAreaApi.setLimitSnapsByType(state)
optionPanel[id] = state
-- option: Show Title on placing scenarios
elseif id == "showTitleSplash" then
optionPanel[id] = state
-- option: Change custom playarea image on setup
elseif id == "changePlayAreaImage" then
optionPanel[id] = state
-- option: Show clean up helper
elseif id == "showCleanUpHelper" then
optionPanel[id] = spawnOrRemoveHelper(state, "Clean Up Helper", { -66, 1.6, 46 })
spawnOrRemoveHelper(state, "Clean Up Helper", { -66, 1.6, 46 })
-- option: Show hand helper for each player
elseif id == "showHandHelper" then
spawnOrRemoveHelperForPlayermats("Hand Helper", state)
optionPanel[id] = state
-- option: Show search assistant for each player
elseif id == "showSearchAssistant" then
spawnOrRemoveHelperForPlayermats("Search Assistant", state)
optionPanel[id] = state
-- option: Show attachment helper
elseif id == "showAttachmentHelper" then
optionPanel[id] = spawnOrRemoveHelper(state, "Attachment Helper", { -62, 1.4, 0 })
spawnOrRemoveHelper(state, "Attachment Helper", { -62, 1.4, 0 })
-- option: Show CYOA campaign guides
elseif id == "showCYOA" then
optionPanel[id] = spawnOrRemoveHelper(state, "CYOA Campaign Guides", { 39, 1.3, -20 })
spawnOrRemoveHelper(state, "CYOA Campaign Guides", { 39, 1.3, -20 })
-- option: Show displacement tool
elseif id == "showDisplacementTool" then
optionPanel[id] = spawnOrRemoveHelper(state, "Displacement Tool", { -57, 1.6, 46 })
spawnOrRemoveHelper(state, "Displacement Tool", { -57, 1.6, 46 })
end
end
@ -1537,7 +1521,7 @@ function spawnOrRemoveHelper(state, name, position, rotation, owner)
local cleanName = name:gsub("%s+", "")
guidReferenceApi.editIndex(owner or "Mythos", cleanName, spawnedGUID)
else
return removeHelperObject(name)
removeHelperObject(name)
end
end
@ -1597,15 +1581,6 @@ end
-- loads the default options
function onClick_defaultSettings()
for id, _ in pairs(optionPanel) do
local state = false
-- override for settings that are enabled by default
if id == "useSnapTags" or id == "showTitleSplash" then
state = true
end
applyOptionPanelChange(id, state)
end
-- clean reset of variables
optionPanel = {
cardLanguage = "en",
@ -1626,6 +1601,11 @@ function onClick_defaultSettings()
useSnapTags = true
}
-- applying changes
for id, state in pairs(optionPanel) do
applyOptionPanelChange(id, state)
end
-- update UI
updateOptionPanelState()
end