From a23c3d8150394748ee319c1ec1ec03e371414d0b Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Tue, 28 Feb 2023 01:24:00 +0100 Subject: [PATCH 1/3] first part of token arranger updates --- .../TokenArranger.022907.json | 3 ++ src/accessories/TokenArranger.ttslua | 45 ++++++++++++----- src/accessories/TokenArrangerApi.ttslua | 13 +++++ src/core/MythosArea.ttslua | 50 ++++++++++++++----- 4 files changed, 86 insertions(+), 25 deletions(-) create mode 100644 src/accessories/TokenArrangerApi.ttslua diff --git a/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json b/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json index c5c2ddad..951952de 100644 --- a/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json +++ b/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json @@ -40,6 +40,9 @@ "Nickname": "Token Arranger", "Snap": true, "Sticky": true, + "Tags": [ + "TokenArranger" + ], "Tooltip": true, "Transform": { "posX": 22.951, diff --git a/src/accessories/TokenArranger.ttslua b/src/accessories/TokenArranger.ttslua index b47dede3..b0d6d217 100644 --- a/src/accessories/TokenArranger.ttslua +++ b/src/accessories/TokenArranger.ttslua @@ -49,9 +49,9 @@ updating = false function onSave() return JSON.encode(TOKEN_PRECEDENCE) end -function onLoad(save_state) - if save_state ~= nil then - TOKEN_PRECEDENCE = JSON.decode(save_state) +function onLoad(saveState) + if saveState ~= nil then + TOKEN_PRECEDENCE = JSON.decode(saveState) end -- create UI @@ -85,26 +85,22 @@ function onLoad(save_state) buttonParameters.width = 675 buttonParameters.height = 175 self.createButton(buttonParameters) - - self.addContextMenuItem("More Information", function() - printToAll("------------------------------", "White") - printToAll("Token Arranger by Chr1Z", "Orange") - printToAll("original concept by Whimsical", "White") - end) - -- send object reference to bless/curse manager Wait.time(function() getObjectFromGUID("5933fb").setVar("tokenArranger", self) end, 1) end +-- delete tokens and remove reference from bless/curse manager function onDestroy() deleteCopiedTokens() -- remove object reference from bless/curse manager getObjectFromGUID("5933fb").setVar("tokenArranger", nil) end -function onPickUp() - deleteCopiedTokens() -end +-- layout tokens when dropped (after 2 seconds) +function onDrop() Wait.time(layout, 2) end + +-- delete tokens when picked up +function onPickUp() deleteCopiedTokens() end -- helper functions to carry index function attachIndex(click_function, index) @@ -245,3 +241,26 @@ function layout(_, _, isRightClick) end updating = false end + +-- called from outside to set default values for tokens +function onTokenDataChanged(tokenData) + -- Skull + local table = tokenData["Skull"] or {} + local skullModifier = table.modifier or "" + print("Skull: " .. skullModifier) + + -- Cultist + local table = tokenData.Cultist or {} + local cultistModifier = table.modifier or "" + print("Cultist: " .. cultistModifier) + + -- Tablet + local table = tokenData.Tablet or {} + local tabletModifier = table.modifier or "" + print("Tablet: " .. tabletModifier) + + -- Elder Thing + local table = tokenData.ElderThing or {} + local elderThingModifier = table.modifier or "" + print("Elder Thing: " .. elderThingModifier) +end diff --git a/src/accessories/TokenArrangerApi.ttslua b/src/accessories/TokenArrangerApi.ttslua new file mode 100644 index 00000000..dab706a5 --- /dev/null +++ b/src/accessories/TokenArrangerApi.ttslua @@ -0,0 +1,13 @@ +do + local TokenArrangerApi = {} + + TokenArrangerApi.onTokenDataChanged = function(tokenData) + local tokenArranger = getObjectsWithTag("TokenArranger")[1] + + if tokenArranger ~= nil then + tokenArranger.call("onTokenDataChanged", tokenData) + end + end + + return TokenArrangerApi +end diff --git a/src/core/MythosArea.ttslua b/src/core/MythosArea.ttslua index 5877a4fa..adc8d9d6 100644 --- a/src/core/MythosArea.ttslua +++ b/src/core/MythosArea.ttslua @@ -1,5 +1,6 @@ -local playArea = require("core/PlayAreaApi") -local tokenSpawnTracker = require("core/token/TokenSpawnTrackerApi") +local playAreaApi = require("core/PlayAreaApi") +local tokenArrangerApi = require("accessories/TokenArrangerApi") +local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi") local ENCOUNTER_DECK_AREA = { upperLeft = { x = 0.9, z = 0.42 }, @@ -11,39 +12,60 @@ local ENCOUNTER_DISCARD_AREA = { } local currentScenario +local useFrontData -- we use this to turn off collision handling until onLoad() is complete -local COLLISION_ENABLED = false +local collisionEnabled = false function onLoad(saveState) if saveState ~= nil then local loadedState = JSON.decode(saveState) or { } - currentScenario = loadedState.currentScenario + currentScenario = loadedState.currentScenario or "" + useFrontData = loadedState.useFrontData or true end - COLLISION_ENABLED = true + collisionEnabled = true end function onSave() return JSON.encode({ - currentScenario = currentScenario + currentScenario = currentScenario, + useFrontData = useFrontData }) end -- TTS event handler. Handles scenario name event triggering and encounter card token resets. function onCollisionEnter(collisionInfo) - if not COLLISION_ENABLED then + if not collisionEnabled then return end local object = collisionInfo.collision_object if object.getName() == "Scenario" then - if currentScenario ~= object.getDescription() then - currentScenario = object.getDescription() + local updateNeeded = false + local description = object.getDescription() + + -- detect if orientation of scenario card changed (flipped to other side) + if object.is_face_down == useFrontData then + useFrontData = not useFrontData + updateNeeded = true + end + + -- detect if another scenario card is placed down + if currentScenario ~= description then + currentScenario = description + updateNeeded = true fireScenarioChangedEvent() end + -- trigger update if a change was detected and push new data + if updateNeeded then + local metadata = JSON.decode(object.getGMNotes()) or {} + if not metadata["tokens"] then return end + local tokenData = metadata["tokens"][(useFrontData and "front" or "back")] + fireTokenDataChangedEvent(tokenData) + end end local localPos = self.positionToLocal(object.getPosition()) if inArea(localPos, ENCOUNTER_DECK_AREA) or inArea(localPos, ENCOUNTER_DISCARD_AREA) then - tokenSpawnTracker.resetTokensSpawned(object.getGUID()) + tokenSpawnTrackerApi.resetTokensSpawned(object.getGUID()) end end @@ -52,13 +74,17 @@ end function onObjectEnterContainer(container, object) local localPos = self.positionToLocal(container.getPosition()) if inArea(localPos, ENCOUNTER_DECK_AREA) or inArea(localPos, ENCOUNTER_DISCARD_AREA) then - tokenSpawnTracker.resetTokensSpawned(object.getGUID()) + tokenSpawnTrackerApi.resetTokensSpawned(object.getGUID()) end end function fireScenarioChangedEvent() Wait.frames(function() Global.call('titleSplash', currentScenario) end, 20) - playArea.onScenarioChanged(currentScenario) + playAreaApi.onScenarioChanged(currentScenario) +end + +function fireTokenDataChangedEvent(tokenData) + tokenArrangerApi.onTokenDataChanged(tokenData) end -- Simple method to check if the given point is in a specified area. Local use only, From b9fe13b658b436c5e1f411c04e094bde77b7d501 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Tue, 28 Feb 2023 12:35:35 +0100 Subject: [PATCH 2/3] second part of updates --- modsettings/ComponentTags.json | 4 +- .../TokenArranger.022907.json | 8 +- src/accessories/TokenArranger.ttslua | 158 ++++++++---------- src/accessories/TokenArrangerApi.ttslua | 24 ++- src/chaosbag/BlessCurseManager.ttslua | 45 +---- src/core/Global.ttslua | 3 - 6 files changed, 106 insertions(+), 136 deletions(-) diff --git a/modsettings/ComponentTags.json b/modsettings/ComponentTags.json index a30f8e1a..e3183d95 100644 --- a/modsettings/ComponentTags.json +++ b/modsettings/ComponentTags.json @@ -49,8 +49,8 @@ "normalized": "location" }, { - "displayed": "to_be_deleted", - "normalized": "to_be_deleted" + "displayed": "tempToken", + "normalized": "temptoken" }, { "displayed": "Minicard", diff --git a/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json b/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json index 951952de..61f9dd5d 100644 --- a/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json +++ b/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json @@ -45,10 +45,10 @@ ], "Tooltip": true, "Transform": { - "posX": 22.951, - "posY": 5.242, - "posZ": -30.295, - "rotX": 1, + "posX": -42.3, + "posY": 1.53, + "posZ": -46.5, + "rotX": 0, "rotY": 270, "rotZ": 0, "scaleX": 2, diff --git a/src/accessories/TokenArranger.ttslua b/src/accessories/TokenArranger.ttslua index b0d6d217..10a0b39a 100644 --- a/src/accessories/TokenArranger.ttslua +++ b/src/accessories/TokenArranger.ttslua @@ -1,4 +1,4 @@ --- names of tokens in order +local TOKEN_PRECEDENCE = {} local TOKEN_NAMES = { "Elder Sign", "Skull", @@ -12,21 +12,6 @@ local TOKEN_NAMES = { "" } --- token modifiers for sorting (and order for same modifier) --- order starts at 2 because there is a "+1" token -local TOKEN_PRECEDENCE = { - ["Elder Sign"] = { 100, 2 }, - ["Skull"] = { -1, 3 }, - ["Cultist"] = { -2, 4 }, - ["Tablet"] = { -3, 5 }, - ["Elder Thing"] = { -4, 6 }, - ["Auto-fail"] = { -100, 7 }, - ["Bless"] = { 101, 8 }, - ["Curse"] = { -101, 9 }, - ["Frost"] = { -99, 10 }, - [""] = { 0, 11 } -} - -- common parameters local buttonParameters = {} buttonParameters.function_owner = self @@ -52,13 +37,15 @@ function onSave() return JSON.encode(TOKEN_PRECEDENCE) end function onLoad(saveState) if saveState ~= nil then TOKEN_PRECEDENCE = JSON.decode(saveState) + else + loadDefaultValues() end -- create UI local offset = 0.725 local pos = { x = { -1.067, 0.377 }, z = -2.175 } - -- button and inputs index 1-10 + -- button and inputs index 0-9 for i = 1, 10 do if i < 6 then buttonParameters.position = { pos.x[1], 0, pos.z + i * offset } @@ -76,7 +63,7 @@ function onLoad(saveState) self.createInput(inputParameters) end - -- index 11: "Update / Hide" button + -- index 10: "Update / Hide" button buttonParameters.label = "Update / Hide" buttonParameters.click_function = "layout" buttonParameters.tooltip = "Left-Click: Update!\nRight-Click: Hide Tokens!" @@ -85,55 +72,52 @@ function onLoad(saveState) buttonParameters.width = 675 buttonParameters.height = 175 self.createButton(buttonParameters) - -- send object reference to bless/curse manager - Wait.time(function() getObjectFromGUID("5933fb").setVar("tokenArranger", self) end, 1) + + -- reset context menu + self.addContextMenuItem("Load default values", function() + loadDefaultValues() + updateUI() + layout() + end) end --- delete tokens and remove reference from bless/curse manager -function onDestroy() - deleteCopiedTokens() - -- remove object reference from bless/curse manager - getObjectFromGUID("5933fb").setVar("tokenArranger", nil) -end +-- delete temporary tokens when destroyed +function onDestroy() deleteCopiedTokens() end -- layout tokens when dropped (after 2 seconds) function onDrop() Wait.time(layout, 2) end --- delete tokens when picked up +-- delete temporary tokens when picked up function onPickUp() deleteCopiedTokens() end -- helper functions to carry index function attachIndex(click_function, index) local fn_name = click_function .. index - _G[fn_name] = function(obj, player_color, isRightClick) - _G[click_function](obj, player_color, isRightClick, index) + _G[fn_name] = function(_, _, isRightClick) + _G[click_function](isRightClick, index) end return fn_name end function attachIndex2(input_function, index) local fn_name = input_function .. index - _G[fn_name] = function(obj, player_color, input, selected) - _G[input_function](obj, player_color, input, selected, index) + _G[fn_name] = function(_, _, input, selected) + _G[input_function](input, selected, index) end return fn_name end -- click_function for buttons on chaos tokens -function tokenClick(_, _, isRightClick, index) - if not updating then - updating = true - local change = tonumber(isRightClick and "-1" or "1") - TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] = TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] + change - self.editInput({ index = index - 1, value = TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] }) - layout() - end +function tokenClick(isRightClick, index) + local change = tonumber(isRightClick and "-1" or "1") + TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] = TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] + change + self.editInput({ index = index - 1, value = TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] }) + layout() end -- input_function for input_boxes -function tokenInput(_, _, input, selected, index) - if selected == false and not updating then - updating = true +function tokenInput(input, selected, index) + if selected == false then local num = tonumber(input) if num ~= nil then TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] = num @@ -142,6 +126,31 @@ function tokenInput(_, _, input, selected, index) end end +-- loads the default precedence table +function loadDefaultValues() + -- token modifiers for sorting (and order for same modifier) + -- order starts at 2 because there is a "+1" token + TOKEN_PRECEDENCE = { + ["Elder Sign"] = { 100, 2 }, + ["Skull"] = { -1, 3 }, + ["Cultist"] = { -2, 4 }, + ["Tablet"] = { -3, 5 }, + ["Elder Thing"] = { -4, 6 }, + ["Auto-fail"] = { -100, 7 }, + ["Bless"] = { 101, 8 }, + ["Curse"] = { -101, 9 }, + ["Frost"] = { -99, 10 }, + [""] = { 0, 11 } + } +end + +-- update input fields +function updateUI() + for i = 1, 10 do + self.editInput({ index = i-1, value = TOKEN_PRECEDENCE[TOKEN_NAMES[i]][1] }) + end +end + -- order function for data sorting function token_value_comparator(left, right) if left.value > right.value then return true @@ -152,49 +161,35 @@ function token_value_comparator(left, right) end end --- get chaos bag from scripting zone and description -function getChaosBag() - local chaosbag = nil - local chaosbag_zone = getObjectFromGUID("83ef06") - - -- error handling: scripting zone not found - if chaosbag_zone == nil then - printToAll("Zone for chaos bag detection couldn't be found.", "Red") - return nil - end - - for _, v in ipairs(chaosbag_zone.getObjects()) do - if v.getDescription() == "Chaos Bag" then - chaosbag = getObjectFromGUID(v.getGUID()) - break +-- checks scripting zone for chaos bag +function findChaosBag() + for _, item in ipairs(getObjectFromGUID("83ef06").getObjects()) do + if item.getDescription() == "Chaos Bag" then + return item end end - - -- error handling: chaos bag not found - if chaosbag == nil then - printToAll("Chaos bag couldn't be found.", "Red") - end - return chaosbag end -- deletes previously placed tokens function deleteCopiedTokens() - for _, token in ipairs(getObjectsWithTag("to_be_deleted")) do token.destruct() end + for _, token in ipairs(getObjectsWithTag("tempToken")) do token.destruct() end end -- main function (delete old tokens, clone chaos bag content, sort it and position it) function layout(_, _, isRightClick) + if updating then return end + updating = true deleteCopiedTokens() -- stop here if right-clicked if isRightClick then return end - local chaosBag = getChaosBag() + local chaosBag = findChaosBag() local data = {} -- clone tokens from chaos bag (default position above trash can) for i, obj in ipairs(chaosBag.getData().ContainedObjects) do - obj["Tags"] = { "to_be_deleted" } + obj["Tags"] = { "tempToken" } local spawnedObj = spawnObjectData({ data = obj, position = { 0.49, 3, 0 } @@ -220,7 +215,7 @@ function layout(_, _, isRightClick) -- error handling for removal of token arranger if self == nil then - for _, token in ipairs(getObjectsWithTag("to_be_deleted")) do token.destruct() end + for _, token in ipairs(getObjectsWithTag("tempToken")) do token.destruct() end return end @@ -239,28 +234,17 @@ function layout(_, _, isRightClick) item.token.setRotation(self.getRotation()) location.z = location.z - 1.75 end - updating = false + Wait.time(function() updating = false end, 0.1) end -- called from outside to set default values for tokens function onTokenDataChanged(tokenData) - -- Skull - local table = tokenData["Skull"] or {} - local skullModifier = table.modifier or "" - print("Skull: " .. skullModifier) - - -- Cultist - local table = tokenData.Cultist or {} - local cultistModifier = table.modifier or "" - print("Cultist: " .. cultistModifier) - - -- Tablet - local table = tokenData.Tablet or {} - local tabletModifier = table.modifier or "" - print("Tablet: " .. tabletModifier) - - -- Elder Thing - local table = tokenData.ElderThing or {} - local elderThingModifier = table.modifier or "" - print("Elder Thing: " .. elderThingModifier) + -- update token precedence + for key, table in pairs(tokenData) do + local modifier = table.modifier + if modifier == -999 then modifier = 0 end + TOKEN_PRECEDENCE[key][1] = modifier + end + updateUI() + layout() end diff --git a/src/accessories/TokenArrangerApi.ttslua b/src/accessories/TokenArrangerApi.ttslua index dab706a5..c0edba77 100644 --- a/src/accessories/TokenArrangerApi.ttslua +++ b/src/accessories/TokenArrangerApi.ttslua @@ -1,13 +1,31 @@ do local TokenArrangerApi = {} - TokenArrangerApi.onTokenDataChanged = function(tokenData) + -- local function to call the token arranger, if it is on the table + ---@param functionName String Name of the function to cal + ---@param argument Variant Parameter to pass + local function callIfExistent(functionName, argument) local tokenArranger = getObjectsWithTag("TokenArranger")[1] - if tokenArranger ~= nil then - tokenArranger.call("onTokenDataChanged", tokenData) + tokenArranger.call(functionName, argument) end end + -- updates the token modifiers with the provided data + ---@param tokenData Table Contains the chaos token metadata + TokenArrangerApi.onTokenDataChanged = function(tokenData) + callIfExistent("onTokenDataChanged", tokenData) + end + + -- deletes already laid out tokens + TokenArrangerApi.deleteCopiedTokens = function() + callIfExistent("deleteCopiedTokens") + end + + -- updates the laid out tokens + TokenArrangerApi.layout = function() + callIfExistent("layout") + end + return TokenArrangerApi end diff --git a/src/chaosbag/BlessCurseManager.ttslua b/src/chaosbag/BlessCurseManager.ttslua index 84ab3f55..d7e64786 100644 --- a/src/chaosbag/BlessCurseManager.ttslua +++ b/src/chaosbag/BlessCurseManager.ttslua @@ -1,11 +1,4 @@ --- Bless / Curse Manager --- updated by: Chr1Z --- made by: Tikatoy --- description: helps with adding / removing and sealing of bless and curse tokens -information = { - version = "3.5", - last_updated = "12.11.2022" -} +local tokenArrangerApi = require("accessories/TokenArrangerApi") local IMAGE_URL = { Bless = "http://cloud-3.steamusercontent.com/ugc/1655601092778627699/339FB716CB25CA6025C338F13AFDFD9AC6FA8356/", @@ -25,9 +18,6 @@ local BUTTON_COLOR = { [false] = { 0.4, 0.4, 0.4 }, [true] = { 0.9, 0.9, 0.9 } } local FONT_COLOR = { [false] = { 1, 1, 1 }, [true] = { 0, 0, 0 } } local whitespace = " " --- variable will be set by outside call -tokenArranger = nil - --------------------------------------------------------- -- creating buttons and menus + initializing tables --------------------------------------------------------- @@ -67,12 +57,6 @@ function onLoad(saved_state) -- context menu self.addContextMenuItem("Remove all", doRemove) self.addContextMenuItem("Reset", doReset) - self.addContextMenuItem("More Information", function() - printToAll("------------------------------", "White") - printToAll("Bless / Curse Manager v" .. information["version"] .. " by Chr1Z", "Orange") - printToAll("last updated: " .. information["last_updated"], "White") - printToAll("original by Tikatoy", "White") - end) -- hotkeys addHotkey("Bless Curse Status", printStatus, false) @@ -173,15 +157,13 @@ end -- context menu function 2 function doReset(color) -- delete previously pulled out tokens by the token arranger - if tokenArranger then - tokenArranger.call("deleteCopiedTokens") - end + tokenArrangerApi.deleteCopiedTokens() playerColor = color numInPlay = { Bless = 0, Curse = 0 } tokensTaken = { Bless = {}, Curse = {} } initializeState() - updateTokenArranger() + tokenArrangerApi.layout() end --------------------------------------------------------- @@ -263,18 +245,7 @@ function callFunctions(token, isRightClick) success = takeToken(token, false) end end - if success ~= 0 then updateTokenArranger() end -end - -UPDATING = false -function updateTokenArranger() - if tokenArranger and not UPDATING then - UPDATING = true - Wait.time(function() - UPDATING = false - tokenArranger.call("layout") - end, 1.5) - end + if success ~= 0 then tokenArrangerApi.layout() end end function getChaosBag() @@ -405,22 +376,22 @@ function addMenuOptions(playerColor, hoveredObject) hoveredObject.addContextMenuItem("Seal Bless", function(color) sealToken("Bless", color, hoveredObject) - updateTokenArranger() + tokenArrangerApi.layout() end, true) hoveredObject.addContextMenuItem("Release Bless", function(color) releaseToken("Bless", color, hoveredObject) - updateTokenArranger() + tokenArrangerApi.layout() end, true) hoveredObject.addContextMenuItem("Seal Curse", function(color) sealToken("Curse", color, hoveredObject) - updateTokenArranger() + tokenArrangerApi.layout() end, true) hoveredObject.addContextMenuItem("Release Curse", function(color) releaseToken("Curse", color, hoveredObject) - updateTokenArranger() + tokenArrangerApi.layout() end, true) broadcastToColor("Right-click seal options added to " .. hoveredObject.getName(), playerColor) diff --git a/src/core/Global.ttslua b/src/core/Global.ttslua index 0234bbd5..f6fa758c 100644 --- a/src/core/Global.ttslua +++ b/src/core/Global.ttslua @@ -845,9 +845,6 @@ function applyOptionPanelChange(id, state) -- option: Show token arranger elseif id == "showTokenArranger" then - -- delete previously pulled out tokens - for _, token in ipairs(getObjectsWithTag("to_be_deleted")) do token.destruct() end - optionPanel[id] = spawnOrRemoveHelper(state, "Token Arranger", {-42.3, 1.6, -46.5}) -- option: Show clean up helper From 5850a81d6899f437913e3d4b8564857536266dad Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Wed, 1 Mar 2023 14:42:10 +0100 Subject: [PATCH 3/3] also grab data onLoad --- .../TokenArranger.022907.json | 2 +- .../TokenArranger.022907.luascriptstate | 1 - src/accessories/TokenArranger.ttslua | 366 ++++++++++-------- src/accessories/TokenArrangerApi.ttslua | 8 +- src/core/Global.ttslua | 11 +- src/core/MythosArea.ttslua | 19 +- 6 files changed, 220 insertions(+), 187 deletions(-) delete mode 100644 objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.luascriptstate diff --git a/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json b/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json index 61f9dd5d..6c12cf42 100644 --- a/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json +++ b/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.json @@ -34,7 +34,7 @@ "LayoutGroupSortIndex": 0, "Locked": false, "LuaScript": "require(\"accessories/TokenArranger\")", - "LuaScriptState_path": "Fan-MadeAccessories.aa8b38/TokenArranger.022907.luascriptstate", + "LuaScriptState": "", "MeasureMovement": false, "Name": "Custom_Token", "Nickname": "Token Arranger", diff --git a/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.luascriptstate b/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.luascriptstate deleted file mode 100644 index 56ab1542..00000000 --- a/objects/Fan-MadeAccessories.aa8b38/TokenArranger.022907.luascriptstate +++ /dev/null @@ -1 +0,0 @@ -{"":[0,11],"Auto-fail":[-100,7],"Bless":[101,8],"Cultist":[-2,4],"Curse":[-101,9],"Elder Sign":[100,2],"Elder Thing":[-4,6],"Frost":[-99,10],"Skull":[-1,3],"Tablet":[-3,5]} diff --git a/src/accessories/TokenArranger.ttslua b/src/accessories/TokenArranger.ttslua index 10a0b39a..0fef4e24 100644 --- a/src/accessories/TokenArranger.ttslua +++ b/src/accessories/TokenArranger.ttslua @@ -1,17 +1,3 @@ -local TOKEN_PRECEDENCE = {} -local TOKEN_NAMES = { - "Elder Sign", - "Skull", - "Cultist", - "Tablet", - "Elder Thing", - "Auto-fail", - "Bless", - "Curse", - "Frost", - "" -} - -- common parameters local buttonParameters = {} buttonParameters.function_owner = self @@ -21,64 +7,92 @@ buttonParameters.color = { 0, 0, 0, 0 } buttonParameters.width = 325 buttonParameters.height = 325 -local inputParameters = {} -inputParameters.function_owner = self -inputParameters.font_size = 100 -inputParameters.width = 250 -inputParameters.height = inputParameters.font_size + 23 -inputParameters.alignment = 3 -inputParameters.validation = 2 -inputParameters.tab = 2 +local inputParameters = {} +inputParameters.function_owner = self +inputParameters.font_size = 100 +inputParameters.width = 250 +inputParameters.height = inputParameters.font_size + 23 +inputParameters.alignment = 3 +inputParameters.validation = 2 +inputParameters.tab = 2 -updating = false +local latestLoad = "XXX" +local updating = false +local tokenPrecedence = {} +local TOKEN_NAMES = { + "Elder Sign", + "Skull", + "Cultist", + "Tablet", + "Elder Thing", + "Auto-fail", + "Bless", + "Curse", + "Frost", + "" +} -function onSave() return JSON.encode(TOKEN_PRECEDENCE) end +-- saving the precedence settings and information on the most recently loaded data +function onSave() + return JSON.encode({ + tokenPrecedence = tokenPrecedence, + latestLoad = latestLoad + }) +end function onLoad(saveState) - if saveState ~= nil then - TOKEN_PRECEDENCE = JSON.decode(saveState) + if saveState ~= nil and saveState ~= "" then + local loadedData = JSON.decode(saveState) + tokenPrecedence = loadedData.tokenPrecedence + latestLoad = loadedData.latestLoad or "XXX" + else + loadDefaultValues() + end + + -- create UI + local offset = 0.725 + local pos = { x = { -1.067, 0.377 }, z = -2.175 } + + -- button and inputs index 0-9 + for i = 1, 10 do + if i < 6 then + buttonParameters.position = { pos.x[1], 0, pos.z + i * offset } + inputParameters.position = { pos.x[1] + offset, 0.1, pos.z + i * offset } else - loadDefaultValues() + buttonParameters.position = { pos.x[2], 0, pos.z + (i - 5) * offset } + inputParameters.position = { pos.x[2] + offset, 0.1, pos.z + (i - 5) * offset } end - -- create UI - local offset = 0.725 - local pos = { x = { -1.067, 0.377 }, z = -2.175 } + buttonParameters.click_function = attachIndex("tokenClick", i) + inputParameters.input_function = attachIndex2("tokenInput", i) + inputParameters.value = tokenPrecedence[TOKEN_NAMES[i]][1] - -- button and inputs index 0-9 - for i = 1, 10 do - if i < 6 then - buttonParameters.position = { pos.x[1], 0, pos.z + i * offset } - inputParameters.position = { pos.x[1] + offset, 0.1, pos.z + i * offset } - else - buttonParameters.position = { pos.x[2], 0, pos.z + (i - 5) * offset } - inputParameters.position = { pos.x[2] + offset, 0.1, pos.z + (i - 5) * offset } - end - - buttonParameters.click_function = attachIndex("tokenClick", i) - inputParameters.input_function = attachIndex2("tokenInput", i) - inputParameters.value = TOKEN_PRECEDENCE[TOKEN_NAMES[i]][1] - - self.createButton(buttonParameters) - self.createInput(inputParameters) - end - - -- index 10: "Update / Hide" button - buttonParameters.label = "Update / Hide" - buttonParameters.click_function = "layout" - buttonParameters.tooltip = "Left-Click: Update!\nRight-Click: Hide Tokens!" - buttonParameters.position = { 0.725, 0.1, 2.025 } - buttonParameters.color = { 1, 1, 1 } - buttonParameters.width = 675 - buttonParameters.height = 175 self.createButton(buttonParameters) + self.createInput(inputParameters) + end - -- reset context menu - self.addContextMenuItem("Load default values", function() - loadDefaultValues() - updateUI() - layout() - end) + -- index 10: "Update / Hide" button + buttonParameters.label = "Update / Hide" + buttonParameters.click_function = "layout" + buttonParameters.tooltip = "Left-Click: Update!\nRight-Click: Hide Tokens!" + buttonParameters.position = { 0.725, 0.1, 2.025 } + buttonParameters.color = { 1, 1, 1 } + buttonParameters.width = 675 + buttonParameters.height = 175 + self.createButton(buttonParameters) + + -- reset context menu + self.addContextMenuItem("Load default values", function() + loadDefaultValues() + updateUI() + layout() + end) + + -- grab token metadata from mythos area + local mythosArea = getObjectFromGUID("9f334f") + Wait.time(function() mythosArea.call("fireTokenDataChangedEvent") end, 0.5) + + Wait.time(layout, 2) end -- delete temporary tokens when destroyed @@ -92,159 +106,177 @@ function onPickUp() deleteCopiedTokens() end -- helper functions to carry index function attachIndex(click_function, index) - local fn_name = click_function .. index - _G[fn_name] = function(_, _, isRightClick) - _G[click_function](isRightClick, index) - end - return fn_name + local fn_name = click_function .. index + _G[fn_name] = function(_, _, isRightClick) + _G[click_function](isRightClick, index) + end + return fn_name end function attachIndex2(input_function, index) - local fn_name = input_function .. index - _G[fn_name] = function(_, _, input, selected) - _G[input_function](input, selected, index) - end - return fn_name + local fn_name = input_function .. index + _G[fn_name] = function(_, _, input, selected) + _G[input_function](input, selected, index) + end + return fn_name end -- click_function for buttons on chaos tokens function tokenClick(isRightClick, index) - local change = tonumber(isRightClick and "-1" or "1") - TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] = TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] + change - self.editInput({ index = index - 1, value = TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] }) - layout() + local change = tonumber(isRightClick and "-1" or "1") + tokenPrecedence[TOKEN_NAMES[index]][1] = tokenPrecedence[TOKEN_NAMES[index]][1] + change + self.editInput({ index = index - 1, value = tokenPrecedence[TOKEN_NAMES[index]][1] }) + layout() end -- input_function for input_boxes function tokenInput(input, selected, index) - if selected == false then - local num = tonumber(input) - if num ~= nil then - TOKEN_PRECEDENCE[TOKEN_NAMES[index]][1] = num - end - layout() + if selected == false then + local num = tonumber(input) + if num ~= nil then + tokenPrecedence[TOKEN_NAMES[index]][1] = num end + layout() + end end -- loads the default precedence table function loadDefaultValues() - -- token modifiers for sorting (and order for same modifier) - -- order starts at 2 because there is a "+1" token - TOKEN_PRECEDENCE = { - ["Elder Sign"] = { 100, 2 }, - ["Skull"] = { -1, 3 }, - ["Cultist"] = { -2, 4 }, - ["Tablet"] = { -3, 5 }, - ["Elder Thing"] = { -4, 6 }, - ["Auto-fail"] = { -100, 7 }, - ["Bless"] = { 101, 8 }, - ["Curse"] = { -101, 9 }, - ["Frost"] = { -99, 10 }, - [""] = { 0, 11 } - } + -- token modifiers for sorting (and order for same modifier) + -- order starts at 2 because there is a "+1" token + tokenPrecedence = { + ["Elder Sign"] = { 100, 2 }, + ["Skull"] = { -1, 3 }, + ["Cultist"] = { -2, 4 }, + ["Tablet"] = { -3, 5 }, + ["Elder Thing"] = { -4, 6 }, + ["Auto-fail"] = { -100, 7 }, + ["Bless"] = { 101, 8 }, + ["Curse"] = { -101, 9 }, + ["Frost"] = { -99, 10 }, + [""] = { 0, 11 } + } end -- update input fields function updateUI() - for i = 1, 10 do - self.editInput({ index = i-1, value = TOKEN_PRECEDENCE[TOKEN_NAMES[i]][1] }) - end + for i = 1, 10 do + self.editInput({ index = i - 1, value = tokenPrecedence[TOKEN_NAMES[i]][1] }) + end end -- order function for data sorting function token_value_comparator(left, right) - if left.value > right.value then return true - elseif right.value > left.value then return false - elseif left.order < right.order then return true - elseif right.order < left.order then return false - else return left.token.getGUID() > right.token.getGUID() - end + if left.value > right.value then + return true + elseif right.value > left.value then + return false + elseif left.order < right.order then + return true + elseif right.order < left.order then + return false + else + return left.token.getGUID() > right.token.getGUID() + end end -- checks scripting zone for chaos bag function findChaosBag() - for _, item in ipairs(getObjectFromGUID("83ef06").getObjects()) do - if item.getDescription() == "Chaos Bag" then - return item - end + for _, item in ipairs(getObjectFromGUID("83ef06").getObjects()) do + if item.getDescription() == "Chaos Bag" then + return item end + end end -- deletes previously placed tokens function deleteCopiedTokens() - for _, token in ipairs(getObjectsWithTag("tempToken")) do token.destruct() end + for _, token in ipairs(getObjectsWithTag("tempToken")) do token.destruct() end end -- main function (delete old tokens, clone chaos bag content, sort it and position it) function layout(_, _, isRightClick) - if updating then return end - updating = true - deleteCopiedTokens() + if updating then return end + updating = true + deleteCopiedTokens() - -- stop here if right-clicked - if isRightClick then return end + -- stop here if right-clicked + if isRightClick then + updating = false + return + end - local chaosBag = findChaosBag() - local data = {} + local chaosBag = findChaosBag() + local data = {} - -- clone tokens from chaos bag (default position above trash can) - for i, obj in ipairs(chaosBag.getData().ContainedObjects) do - obj["Tags"] = { "tempToken" } - local spawnedObj = spawnObjectData({ - data = obj, - position = { 0.49, 3, 0 } - }) + -- clone tokens from chaos bag (default position above trash can) + for i, obj in ipairs(chaosBag.getData().ContainedObjects) do + obj["Tags"] = { "tempToken" } + local spawnedObj = spawnObjectData({ + data = obj, + position = { 0.49, 3, 0 } + }) - local value = tonumber(obj["Nickname"]) - local precedence = TOKEN_PRECEDENCE[obj["Nickname"]] + local value = tonumber(obj["Nickname"]) + local precedence = tokenPrecedence[obj["Nickname"]] - data[i] = { - token = spawnedObj, - value = value or precedence[1] - } + data[i] = { + token = spawnedObj, + value = value or precedence[1] + } - if precedence ~= nil then - data[i].order = precedence[2] - else - data[i].order = value - end + if precedence ~= nil then + data[i].order = precedence[2] + else + data[i].order = value end + end - -- sort table by value (symbols last if same value) - table.sort(data, token_value_comparator) + -- sort table by value (symbols last if same value) + table.sort(data, token_value_comparator) - -- error handling for removal of token arranger - if self == nil then - for _, token in ipairs(getObjectsWithTag("tempToken")) do token.destruct() end - return + -- error handling for removal of token arranger + if self == nil then + for _, token in ipairs(getObjectsWithTag("tempToken")) do token.destruct() end + return + end + + -- laying out the tokens + local pos = self.getPosition() + Vector(3.55, -0.05, -3.95) + local location = { x = pos.x, y = pos.y, z = pos.z } + local current_value = data[1].value + + for _, item in ipairs(data) do + if item.value ~= current_value then + location.x = location.x - 1.75 + location.z = pos.z + current_value = item.value end - - -- laying out the tokens - local pos = self.getPosition() + Vector(3.55, -0.05, -3.95) - local location = { x = pos.x, y = pos.y, z = pos.z } - local current_value = data[1].value - - for _, item in ipairs(data) do - if item.value ~= current_value then - location.x = location.x - 1.75 - location.z = pos.z - current_value = item.value - end - item.token.setPosition(location) - item.token.setRotation(self.getRotation()) - location.z = location.z - 1.75 - end - Wait.time(function() updating = false end, 0.1) + item.token.setPosition(location) + item.token.setRotation(self.getRotation()) + location.z = location.z - 1.75 + end + Wait.time(function() updating = false end, 0.1) end -- called from outside to set default values for tokens -function onTokenDataChanged(tokenData) - -- update token precedence - for key, table in pairs(tokenData) do - local modifier = table.modifier - if modifier == -999 then modifier = 0 end - TOKEN_PRECEDENCE[key][1] = modifier - end - updateUI() - layout() +function onTokenDataChanged(parameters) + local tokenData = parameters.tokenData or {} + local currentScenario = parameters.currentScenario or "" + local useFrontData = parameters.useFrontData or "true" + + -- only update if this data is new + local info = currentScenario .. useFrontData + if latestLoad == info then return end + latestLoad = info + + -- update token precedence + for key, table in pairs(tokenData) do + local modifier = table.modifier + if modifier == -999 then modifier = 0 end + tokenPrecedence[key][1] = modifier + end + + updateUI() + layout() end diff --git a/src/accessories/TokenArrangerApi.ttslua b/src/accessories/TokenArrangerApi.ttslua index c0edba77..6df8298c 100644 --- a/src/accessories/TokenArrangerApi.ttslua +++ b/src/accessories/TokenArrangerApi.ttslua @@ -13,8 +13,12 @@ do -- updates the token modifiers with the provided data ---@param tokenData Table Contains the chaos token metadata - TokenArrangerApi.onTokenDataChanged = function(tokenData) - callIfExistent("onTokenDataChanged", tokenData) + TokenArrangerApi.onTokenDataChanged = function(tokenData, currentScenario, useFrontData) + callIfExistent("onTokenDataChanged", { + tokenData = tokenData, + currentScenario = currentScenario, + useFrontData = useFrontData + }) end -- deletes already laid out tokens diff --git a/src/core/Global.ttslua b/src/core/Global.ttslua index f6fa758c..1cbfe8b7 100644 --- a/src/core/Global.ttslua +++ b/src/core/Global.ttslua @@ -919,16 +919,7 @@ function spawnHelperObject(name, position, rotation, color) return end - local spawnTable = { - position = position, - callback_function = function(object) - if name == "Hand Helper" then - Wait.time(function() object.call("externalColorChange", color) end, 0.1) - elseif name == "Token Arranger" then - Wait.time(function() object.call("layout") end, 0.1) - end - end - } + local spawnTable = {position = position} -- only overrride rotation if there is one provided (object's rotation used instead) if rotation then diff --git a/src/core/MythosArea.ttslua b/src/core/MythosArea.ttslua index adc8d9d6..1bf037e1 100644 --- a/src/core/MythosArea.ttslua +++ b/src/core/MythosArea.ttslua @@ -13,14 +13,17 @@ local ENCOUNTER_DISCARD_AREA = { local currentScenario local useFrontData +local tokenData + -- we use this to turn off collision handling until onLoad() is complete local collisionEnabled = false function onLoad(saveState) if saveState ~= nil then - local loadedState = JSON.decode(saveState) or { } + local loadedState = JSON.decode(saveState) or {} currentScenario = loadedState.currentScenario or "" useFrontData = loadedState.useFrontData or true + tokenData = loadedState.tokenData or {} end collisionEnabled = true end @@ -28,7 +31,8 @@ end function onSave() return JSON.encode({ currentScenario = currentScenario, - useFrontData = useFrontData + useFrontData = useFrontData, + tokenData = tokenData }) end @@ -54,12 +58,13 @@ function onCollisionEnter(collisionInfo) updateNeeded = true fireScenarioChangedEvent() end + -- trigger update if a change was detected and push new data if updateNeeded then local metadata = JSON.decode(object.getGMNotes()) or {} if not metadata["tokens"] then return end - local tokenData = metadata["tokens"][(useFrontData and "front" or "back")] - fireTokenDataChangedEvent(tokenData) + tokenData = metadata["tokens"][(useFrontData and "front" or "back")] + fireTokenDataChangedEvent() end end @@ -78,13 +83,15 @@ function onObjectEnterContainer(container, object) end end +-- fires if the scenario title changes function fireScenarioChangedEvent() Wait.frames(function() Global.call('titleSplash', currentScenario) end, 20) playAreaApi.onScenarioChanged(currentScenario) end -function fireTokenDataChangedEvent(tokenData) - tokenArrangerApi.onTokenDataChanged(tokenData) +-- fires if the scenario title or the difficulty changes +function fireTokenDataChangedEvent() + tokenArrangerApi.onTokenDataChanged(tokenData, currentScenario, tostring(useFrontData)) end -- Simple method to check if the given point is in a specified area. Local use only,