From 6dbaa6b611f589aae238e81d95cf045c47a8fedd Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Mon, 27 Feb 2023 00:25:31 +0100 Subject: [PATCH 1/7] updated code, added backpack image --- .../AttachmentHelper.d45664.json | 5 +- .../AttachmentHelper.d45664.ttslua | 202 ------------------ src/accessories/AttachmentHelper.ttslua | 138 +++++++----- 3 files changed, 92 insertions(+), 253 deletions(-) delete mode 100644 objects/Fan-MadeAccessories.aa8b38/AttachmentHelper.7f4976/AttachmentHelper.d45664.ttslua diff --git a/objects/Fan-MadeAccessories.aa8b38/AttachmentHelper.7f4976/AttachmentHelper.d45664.json b/objects/Fan-MadeAccessories.aa8b38/AttachmentHelper.7f4976/AttachmentHelper.d45664.json index 629ef166..6aa0a289 100644 --- a/objects/Fan-MadeAccessories.aa8b38/AttachmentHelper.7f4976/AttachmentHelper.d45664.json +++ b/objects/Fan-MadeAccessories.aa8b38/AttachmentHelper.7f4976/AttachmentHelper.d45664.json @@ -34,8 +34,8 @@ "IgnoreFoW": false, "LayoutGroupSortIndex": 0, "Locked": false, + "LuaScript": "require(\"accessories/AttachmentHelper\")", "LuaScriptState": "[[],true,true]", - "LuaScript_path": "Fan-MadeAccessories.aa8b38/AttachmentHelper.7f4976/AttachmentHelper.d45664.ttslua", "MaterialIndex": -1, "MeasureMovement": false, "MeshIndex": -1, @@ -45,8 +45,7 @@ "Snap": true, "Sticky": true, "Tags": [ - "Asset", - "scesetup_memory_object" + "Asset" ], "Tooltip": true, "Transform": { diff --git a/objects/Fan-MadeAccessories.aa8b38/AttachmentHelper.7f4976/AttachmentHelper.d45664.ttslua b/objects/Fan-MadeAccessories.aa8b38/AttachmentHelper.7f4976/AttachmentHelper.d45664.ttslua deleted file mode 100644 index de2c31a1..00000000 --- a/objects/Fan-MadeAccessories.aa8b38/AttachmentHelper.7f4976/AttachmentHelper.d45664.ttslua +++ /dev/null @@ -1,202 +0,0 @@ -local OPTION_TEXT = { - "Ancestral Knowledge", - "Astronomical Atlas", - "Crystallizer of Dreams", - "Diana Stanley", - "Gloria Goldberg", - "Sefina Rousseau", - "Wooden Sledge" -} - -local IMAGE_LIST = { - -- Ancestral Knowledge - "http://cloud-3.steamusercontent.com/ugc/1915746489207287888/2F9F6F211ED0F98E66C9D35D93221E4C7FB6DD3C/", - -- Astronomical Atlas - "http://cloud-3.steamusercontent.com/ugc/1754695853007989004/9153BC204FC707AE564ECFAC063A11CB8C2B5D1E/", - -- Crystallizer of Dreams - "http://cloud-3.steamusercontent.com/ugc/1915746489207280958/100F16441939E5E23818651D1EB5C209BF3125B9/", - -- Diana Stanley - "http://cloud-3.steamusercontent.com/ugc/1754695635919071208/1AB7222850201630826BFFBA8F2BD0065E2D572F/", - -- Gloria Goldberg - "http://cloud-3.steamusercontent.com/ugc/1754695635919102502/453D4426118C8A6DE2EA281184716E26CA924C84/", - -- Sefina Rousseau - "http://cloud-3.steamusercontent.com/ugc/1754695635919099826/3C3CBFFAADB2ACA9957C736491F470AE906CC953/", - -- Wooden Sledge - "http://cloud-3.steamusercontent.com/ugc/1750192233783143973/D526236AAE16BDBB98D3F30E27BAFC1D3E21F4AC/" -} - --- save state and options to restore onLoad -function onSave() return JSON.encode({ cardsInBag, showCost, showIcons }) end - --- load variables and create context menu -function onLoad(savedData) - local loadedData = JSON.decode(savedData) - cardsInBag = loadedData[1] or {} - showCost = loadedData[2] or true - showIcons = loadedData[3] or true - - recreateButtons() - - self.addContextMenuItem("Select image", selectImage) - self.addContextMenuItem("Toggle cost", function(color) - showCost = not showCost - printToColor("Show cost of cards: " .. tostring(showCost), color, "White") - refresh() - end) - - self.addContextMenuItem("Toggle skill icons", function(color) - showIcons = not showIcons - printToColor("Show skill icons of cards: " .. tostring(showIcons), color, "White") - refresh() - end) - - self.addContextMenuItem("More Information", function() - printToAll("------------------------------", "White") - printToAll("Attachment Helper by Chr1Z", "Orange") - printToAll("original by bankey", "White") - end) -end - -function selectImage(color) - Player[color].showOptionsDialog("Select image:", OPTION_TEXT, 1, function(_, option_index) - local customInfo = self.getCustomObject() - customInfo.diffuse = IMAGE_LIST[option_index] - self.setCustomObject(customInfo) - self.reload() - end) -end - --- called for every card that enters -function onObjectEnterContainer(container, object) - if container == self then - if object.tag ~= "Card" then - broadcastToAll("The 'Attachment Helper' is meant to be used for single cards.", "White") - else - findCard(object.getGUID(), object.getName(), object.getGMNotes()) - end - -- TODO: implement splitting of decks that get thrown in here - recreateButtons() - end -end - --- removes leaving cards from the "cardInBag" table -function onObjectLeaveContainer(container, object) - if container == self then - local guid = object.getGUID() - local found = false - for i, card in ipairs(cardsInBag) do - if card.id == guid then - table.remove(cardsInBag, i) - found = true - break - end - end - - if found ~= true then - local name = object.getName() - for i, card in ipairs(cardsInBag) do - if card.name == name then - table.remove(cardsInBag, i) - break - end - end - end - recreateButtons() - end -end - --- refreshes displayed buttons based on contained cards -function refresh() - cardsInBag = {} - for _, object in ipairs(self.getObjects()) do - findCard(object.guid, object.name, object.gm_notes) - end - recreateButtons() -end - --- gets cost and icons for a card -function findCard(guid, name, GMNotes) - local cost = "" - local icons = {} - local metadata = {} - local displayName = name - - if displayName == nil or displayName == "" then displayName = "unnamed" end - if showCost or showIcons then metadata = JSON.decode(GMNotes) end - - if showCost then - if GMNotes ~= "" then cost = metadata.cost end - if cost == nil or cost == "" then cost = "–" end - displayName = "[" .. cost .. "] " .. displayName - end - - if showIcons then - if GMNotes ~= "" then - icons[1] = metadata.wildIcons - icons[2] = metadata.willpowerIcons - icons[3] = metadata.intellectIcons - icons[4] = metadata.combatIcons - icons[5] = metadata.agilityIcons - end - - local IconTypes = { "Wild", "Willpower", "Intellect", "Combat", "Agility" } - local found = false - for i = 1, 5 do - if icons[i] ~= nil and icons[i] ~= "" then - if found == false then - displayName = displayName .. "\n" .. IconTypes[i] .. ": " .. icons[i] - found = true - else - displayName = displayName .. " " .. IconTypes[i] .. ": " .. icons[i] - end - end - end - end - table.insert(cardsInBag, { name = name, displayName = displayName, id = guid }) -end - --- recreates buttons with up-to-date labels -function recreateButtons() - self.clearButtons() - local verticalPosition = 1.65 - - for _, card in ipairs(cardsInBag) do - local id = card.id - local funcName = "removeCard" .. id - self.setVar(funcName, function() removeCard(id) end) - self.createButton({ - label = card.displayName, - click_function = funcName, - function_owner = self, - position = { 0, 0, verticalPosition }, - height = 200, - width = 1200, - font_size = string.len(card.displayName) > 20 and 75 or 100 - }) - verticalPosition = verticalPosition - 0.5 - end - - local countLabel = "Attachment\nHelper" - if #cardsInBag ~= 0 then countLabel = #cardsInBag end - - self.createButton({ - label = countLabel, - click_function = "none", - function_owner = self, - position = { 0, 0, -1.35 }, - height = 0, - width = 0, - font_size = 225, - font_color = { 1, 1, 1 } - }) -end - --- click-function for buttons to take a card out of the bag -function removeCard(cardGUID) - self.takeObject({ - guid = cardGUID, - rotation = self.getRotation(), - position = self.getPosition() + Vector(0, 0.25, 0), - callback_function = function(obj) obj.resting = true end - }) -end diff --git a/src/accessories/AttachmentHelper.ttslua b/src/accessories/AttachmentHelper.ttslua index de2c31a1..e786ca4c 100644 --- a/src/accessories/AttachmentHelper.ttslua +++ b/src/accessories/AttachmentHelper.ttslua @@ -1,28 +1,45 @@ -local OPTION_TEXT = { - "Ancestral Knowledge", - "Astronomical Atlas", - "Crystallizer of Dreams", - "Diana Stanley", - "Gloria Goldberg", - "Sefina Rousseau", - "Wooden Sledge" -} - -local IMAGE_LIST = { - -- Ancestral Knowledge - "http://cloud-3.steamusercontent.com/ugc/1915746489207287888/2F9F6F211ED0F98E66C9D35D93221E4C7FB6DD3C/", - -- Astronomical Atlas - "http://cloud-3.steamusercontent.com/ugc/1754695853007989004/9153BC204FC707AE564ECFAC063A11CB8C2B5D1E/", - -- Crystallizer of Dreams - "http://cloud-3.steamusercontent.com/ugc/1915746489207280958/100F16441939E5E23818651D1EB5C209BF3125B9/", - -- Diana Stanley - "http://cloud-3.steamusercontent.com/ugc/1754695635919071208/1AB7222850201630826BFFBA8F2BD0065E2D572F/", - -- Gloria Goldberg - "http://cloud-3.steamusercontent.com/ugc/1754695635919102502/453D4426118C8A6DE2EA281184716E26CA924C84/", - -- Sefina Rousseau - "http://cloud-3.steamusercontent.com/ugc/1754695635919099826/3C3CBFFAADB2ACA9957C736491F470AE906CC953/", - -- Wooden Sledge - "http://cloud-3.steamusercontent.com/ugc/1750192233783143973/D526236AAE16BDBB98D3F30E27BAFC1D3E21F4AC/" +local fontColor +local BACKGROUNDS = { + { + title = "Ancestral Knowledge", + url = "http://cloud-3.steamusercontent.com/ugc/1915746489207287888/2F9F6F211ED0F98E66C9D35D93221E4C7FB6DD3C/", + fontcolor = { 1, 1, 1 } + }, + { + title = "Astronomical Atlas", + url = "http://cloud-3.steamusercontent.com/ugc/1754695853007989004/9153BC204FC707AE564ECFAC063A11CB8C2B5D1E/", + fontcolor = { 1, 1, 1 } + }, + { + title = "Backpack", + url = "http://cloud-3.steamusercontent.com/ugc/2018212896278691928/F55BEFFC2540109C6333179532F583B367FF2EBC/", + fontcolor = { 0, 0, 0 } + }, + { + title = "Crystallizer of Dreams", + url = "http://cloud-3.steamusercontent.com/ugc/1915746489207280958/100F16441939E5E23818651D1EB5C209BF3125B9/", + fontcolor = { 1, 1, 1 } + }, + { + title = "Diana Stanley", + url = "http://cloud-3.steamusercontent.com/ugc/1754695635919071208/1AB7222850201630826BFFBA8F2BD0065E2D572F/", + fontcolor = { 1, 1, 1 } + }, + { + title = "Gloria Goldberg", + url = "http://cloud-3.steamusercontent.com/ugc/1754695635919102502/453D4426118C8A6DE2EA281184716E26CA924C84/", + fontcolor = { 1, 1, 1 } + }, + { + title = "Sefina Rousseau", + url = "http://cloud-3.steamusercontent.com/ugc/1754695635919099826/3C3CBFFAADB2ACA9957C736491F470AE906CC953/", + fontcolor = { 0, 0, 0 } + }, + { + title = "Wooden Sledge", + url = "http://cloud-3.steamusercontent.com/ugc/1750192233783143973/D526236AAE16BDBB98D3F30E27BAFC1D3E21F4AC/", + fontcolor = { 0, 0, 0 } + } } -- save state and options to restore onLoad @@ -34,7 +51,7 @@ function onLoad(savedData) cardsInBag = loadedData[1] or {} showCost = loadedData[2] or true showIcons = loadedData[3] or true - + fontColor = getFontColor() recreateButtons() self.addContextMenuItem("Select image", selectImage) @@ -49,36 +66,57 @@ function onLoad(savedData) printToColor("Show skill icons of cards: " .. tostring(showIcons), color, "White") refresh() end) - - self.addContextMenuItem("More Information", function() - printToAll("------------------------------", "White") - printToAll("Attachment Helper by Chr1Z", "Orange") - printToAll("original by bankey", "White") - end) end +-- gets the font color based on background url +function getFontColor() + local customInfo = self.getCustomObject() + for i = 1, #BACKGROUNDS do + if BACKGROUNDS[i].url == customInfo.diffuse then + return BACKGROUNDS[i].fontcolor + end + end + return { 1, 1, 1 } +end + +-- called by context menu to change background image function selectImage(color) - Player[color].showOptionsDialog("Select image:", OPTION_TEXT, 1, function(_, option_index) + -- generate list of options + local options = {} + for i = 1, #BACKGROUNDS do + options[i] = BACKGROUNDS[i].title + end + + -- prompt user to select option + Player[color].showOptionsDialog("Select image:", options, 1, function(_, optionIndex) local customInfo = self.getCustomObject() - customInfo.diffuse = IMAGE_LIST[option_index] + customInfo.diffuse = BACKGROUNDS[optionIndex].url self.setCustomObject(customInfo) self.reload() end) end --- called for every card that enters +-- only allow cards to enter, split decks and reject other objects function onObjectEnterContainer(container, object) - if container == self then - if object.tag ~= "Card" then - broadcastToAll("The 'Attachment Helper' is meant to be used for single cards.", "White") - else - findCard(object.getGUID(), object.getName(), object.getGMNotes()) - end - -- TODO: implement splitting of decks that get thrown in here + if container ~= self then return end + if object.tag == "Deck" then + takeDeckOut(object.getGUID(), self.getPosition() + Vector(0, 0.1, 0)) + elseif object.tag ~= "Card" then + broadcastToAll("The 'Attachment Helper' is meant to be used for cards.", "White") + else + findCard(object.getGUID(), object.getName(), object.getGMNotes()) recreateButtons() end end +-- takes the deck out and splits in into single cards +function takeDeckOut(guid, pos) + local deck = self.takeObject({ guid = guid, position = pos, smooth = false }) + for i = 1, #deck.getObjects() do + self.putObject(deck.takeObject({ position = pos + Vector(0, 0.1 * i, 0), smooth = false })) + end +end + -- removes leaving cards from the "cardInBag" table function onObjectLeaveContainer(container, object) if container == self then @@ -168,7 +206,7 @@ function recreateButtons() label = card.displayName, click_function = funcName, function_owner = self, - position = { 0, 0, verticalPosition }, + position = { 0, -0.1, verticalPosition }, height = 200, width = 1200, font_size = string.len(card.displayName) > 20 and 75 or 100 @@ -176,18 +214,22 @@ function recreateButtons() verticalPosition = verticalPosition - 0.5 end - local countLabel = "Attachment\nHelper" - if #cardsInBag ~= 0 then countLabel = #cardsInBag end + local countLabel = #cardsInBag + local fontSize = 250 + if #cardsInBag == 0 then + countLabel = "Attachment Helper" + fontSize = 150 + end self.createButton({ label = countLabel, click_function = "none", function_owner = self, - position = { 0, 0, -1.35 }, + position = { 0, -0.1, -1.7 }, height = 0, width = 0, - font_size = 225, - font_color = { 1, 1, 1 } + font_size = fontSize, + font_color = fontColor }) end From d86c6485e19ddc1f3eff8674349517376efed7d1 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Tue, 28 Feb 2023 13:03:33 +0100 Subject: [PATCH 2/7] redraw connections after movement --- src/core/PlayArea.ttslua | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/PlayArea.ttslua b/src/core/PlayArea.ttslua index 0151aeb2..d7b9073a 100644 --- a/src/core/PlayArea.ttslua +++ b/src/core/PlayArea.ttslua @@ -499,6 +499,7 @@ function shiftContents(playerColor, direction) object.translate(SHIFT_OFFSETS[direction]) end end + Wait.time(drawBaseConnections, 0.1) end -- Returns the current value of the investigator counter from the playmat From 4884899f30bfaafb2b3244c9f60b91ddd0888578 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Tue, 28 Feb 2023 15:00:28 +0100 Subject: [PATCH 3/7] discard function and color detection updates --- .../HandHelper.450688.json | 4 +- src/accessories/HandHelper.ttslua | 256 ++++++------------ src/core/Global.ttslua | 4 +- src/playermat/Playmat.ttslua | 66 ++++- src/playermat/PlaymatApi.ttslua | 21 ++ 5 files changed, 173 insertions(+), 178 deletions(-) diff --git a/objects/Fan-MadeAccessories.aa8b38/HandHelper.450688.json b/objects/Fan-MadeAccessories.aa8b38/HandHelper.450688.json index 24b5e802..3ee91e70 100644 --- a/objects/Fan-MadeAccessories.aa8b38/HandHelper.450688.json +++ b/objects/Fan-MadeAccessories.aa8b38/HandHelper.450688.json @@ -22,7 +22,7 @@ "ImageURL": "http://cloud-3.steamusercontent.com/ugc/1704036721123215146/E44A3B99EACF310E49E94977151A03C9A3DC7F17/", "WidthScale": 0 }, - "Description": "- Displays the hand size (total or by title for \"Dream Enhancing Serum\"), hover over it to briefly toggle counting method\n\n- Adds a context menu to \"Short Supply\" for the 1st turn\n\n- Allows you to randomly discard a card from your hand\n\nSee context menu for additional information.", + "Description": "Displays the hand size (total or by title for \"Dream Enhancing Serum\"), hover over it to briefly toggle counting method.\n\nAllows you to randomly discard a card from your hand.", "DragSelectable": true, "GMNotes": "", "GUID": "450688", @@ -34,7 +34,7 @@ "LayoutGroupSortIndex": 0, "Locked": false, "LuaScript": "require(\"accessories/HandHelper\")", - "LuaScriptState": "[\"Green\",false]", + "LuaScriptState": "", "MeasureMovement": false, "Name": "Custom_Tile", "Nickname": "Hand Helper", diff --git a/src/accessories/HandHelper.ttslua b/src/accessories/HandHelper.ttslua index d79dd093..3137a966 100644 --- a/src/accessories/HandHelper.ttslua +++ b/src/accessories/HandHelper.ttslua @@ -1,194 +1,110 @@ local playmatAPI = require("playermat/PlaymatApi") +local matColor +local handColor +local loopId -local buttonParamaters = {} -buttonParamaters.function_owner = self +function onLoad() + local buttonParamaters = {} + buttonParamaters.function_owner = self --- saving "playerColor" and "des" -function onSave() return JSON.encode({ playerColor, des}) end + -- index 0: button as hand size label + buttonParamaters.hover_color = "White" + buttonParamaters.click_function = "none" + buttonParamaters.position = { 0, 0.11, -0.4 } + buttonParamaters.height = 0 + buttonParamaters.width = 0 + buttonParamaters.font_size = 500 + buttonParamaters.font_color = "White" + self.createButton(buttonParamaters) -function onLoad(saved_data) - -- loading saved data - local loaded_data = JSON.decode(saved_data) - playerColor = loaded_data[1] or Player.getAvailableColors()[1] - des = loaded_data[2] or false + -- index 1: button to toggle "des" + buttonParamaters.label = "DES: ✗" + buttonParamaters.click_function = "none" + buttonParamaters.position = { 0, 0.11, 0.25 } + buttonParamaters.height = 0 + buttonParamaters.width = 0 + buttonParamaters.font_size = 120 + self.createButton(buttonParamaters) - -- index 0: button as hand size label - buttonParamaters.hover_color = "White" - buttonParamaters.click_function = "none" - buttonParamaters.position = { 0, 0.11, -0.4 } - buttonParamaters.height = 0 - buttonParamaters.width = 0 - buttonParamaters.font_size = 500 - buttonParamaters.font_color = "White" - self.createButton(buttonParamaters) + -- index 2: button to discard a card + buttonParamaters.label = "discard random card" + buttonParamaters.click_function = "discardRandom" + buttonParamaters.position = { 0, 0.11, 0.7 } + buttonParamaters.height = 175 + buttonParamaters.width = 900 + buttonParamaters.font_size = 90 + buttonParamaters.font_color = "Black" + self.createButton(buttonParamaters) - -- index 1: button to toggle "des" - buttonParamaters.label = "DES: " .. (des and "✓" or "✗") - buttonParamaters.click_function = "toggleDES" - buttonParamaters.position = { 0.475, 0.11, 0.25 } - buttonParamaters.height = 175 - buttonParamaters.width = 440 - buttonParamaters.font_size = 90 - buttonParamaters.font_color = "Black" - self.createButton(buttonParamaters) + updateColors() - -- index 2: button to discard a card - buttonParamaters.label = "discard random card" - buttonParamaters.click_function = "discardRandom" - buttonParamaters.position = { 0, 0.11, 0.7 } - buttonParamaters.width = 900 - self.createButton(buttonParamaters) - - -- index 3: button to select color - buttonParamaters.label = playerColor - buttonParamaters.color = playerColor - buttonParamaters.hover_color = playerColor - buttonParamaters.click_function = "changeColor" - buttonParamaters.tooltip = "change color" - buttonParamaters.position = { -0.475, 0.11, 0.25 } - buttonParamaters.width = 440 - self.createButton(buttonParamaters) - - -- start loop to update card count - loopId = Wait.time(||updateValue(), 1, -1) - - -- context menu to quickly bind color - self.addContextMenuItem("Bind to my color", function(color) - changeColor(_, _, _, color) - end) - - -- context menu to display additional information - self.addContextMenuItem("More Information", function() - printToAll("------------------------------", "White") - printToAll("Hand Helper by Chr1Z", "Orange") - printToAll("original by Tikatoy", "White") - printToAll("Note: 'Hidden' cards can't be randomly discarded.", "Yellow") - printToAll("Set them aside beforehand!", "Yellow") - end) - - -- initialize the pseudo random number generator - math.randomseed(os.time()) + -- start loop to update card count + loopId = Wait.time(updateValue, 1, -1) end +-- updates colors when object is dropped somewhere +function onDrop() updateColors() end + +-- toggles counting method briefly function onObjectHover(hover_color, obj) - -- only continue if correct player hovers over "self" - if obj ~= self or hover_color ~= playerColor then return end + -- only continue if correct player hovers over "self" + if obj ~= self or hover_color ~= handColor then return end - -- stop loop, toggle "des" and displayed value briefly, then start new loop - Wait.stop(loopId) - des = not des - updateValue() - des = not des - loopId = Wait.time(||updateValue(), 1, -1) + -- stop loop, toggle "des" and displayed value briefly, then start new loop after 2s + Wait.stop(loopId) + updateValue(true) + Wait.time(function() loopId = Wait.time(updateValue, 1, -1) end, 2) end --- toggle "des" and update button label -function toggleDES() - des = not des - self.editButton({index = 1, label = "DES: " .. (des and "✓" or "✗")}) - updateValue() +-- updates the matcolor and handcolor variable +function updateColors() + matColor = playmatAPI.getMatColorByPosition(self.getPosition()) + handColor = playmatAPI.getHandColor(matColor) + self.setName(handColor .. " Hand Helper") end -- count cards in hand (by name for DES) -function updateValue() - if not playerExists(playerColor) then return end +function updateValue(toggle) + -- update colors if handColor doesn't own a handzone + if Player[handColor].getHandCount() == 0 then + updateColors() + end - local hand = Player[playerColor].getHandObjects() - local size = 0 + -- if there is still no handzone, then end here + if Player[handColor].getHandCount() == 0 then return end - if des then - local cardHash = {} - for _, obj in pairs(hand) do - if obj.tag == "Card" then - local name = obj.getName() - local title = string.match(name, '(.+)(%s%(%d+%))') or name - cardHash[title] = obj - end - end - for _, obj in pairs(cardHash) do - size = size + 1 - end - else - for _, obj in pairs(hand) do - if obj.tag == "Card" then size = size + 1 end - end + -- get state of "Dream-Enhancing Serum" from playermat and update button label + local des = playmatAPI.isDES(matColor) + if toggle then des = not des end + self.editButton({ index = 1, label = "DES: " .. (des and "✓" or "✗") }) + + -- count cards in hand + local hand = Player[handColor].getHandObjects() + local size = 0 + + if des then + local cardHash = {} + for _, obj in pairs(hand) do + if obj.tag == "Card" then + local name = obj.getName() + local title = string.match(name, '(.+)(%s%(%d+%))') or name + cardHash[title] = true + end end - -- change button label and color - self.editButton({index = 0, font_color = des and "Green" or "White", label = size}) -end - --- allows change of color via external call -function externalColorChange(newColor) - changeColor(_, _, _, newColor) -end - --- get index of current color and move up one step (or down for right-click) -function changeColor(_, _, isRightClick, color) - if color then - playerColor = color - else - local COLORS = Player.getAvailableColors() - local pos = indexOf(COLORS, playerColor) - - if isRightClick then - if pos == nil or pos == 1 then pos = #COLORS - else pos = pos - 1 end - else - if pos == nil or pos == #COLORS then pos = 1 - else pos = pos + 1 end - end - - -- update playerColor - playerColor = COLORS[pos] + for _, title in pairs(cardHash) do + size = size + 1 end - - -- update "change color" button (note: remove and create instantly updates hover_color) - buttonParamaters.label = playerColor - buttonParamaters.color = playerColor - buttonParamaters.hover_color = playerColor - self.removeButton(3) - self.createButton(buttonParamaters) + else + for _, obj in pairs(hand) do + if obj.tag == "Card" then size = size + 1 end + end + end + + -- update button label and color + self.editButton({ index = 0, font_color = des and "Green" or "White", label = size }) end ---------------------------------------------------------- --- discards a random card from hand ---------------------------------------------------------- - +-- discards a random non-hidden card from hand function discardRandom() - if not playerExists(playerColor) then return end - - -- error handling: hand is empty - local hand = Player[playerColor].getHandObjects() - if #hand == 0 then - broadcastToAll("Cannot discard from empty hand!", "Red") - else - local searchPos = Player[playerColor].getHandTransform().position - - local discardPos = playmatAPI.getDiscardPosition(playmatAPI.getMatColorByPosition(searchPos)) - if discardPos == nil then - broadcastToAll("Couldn't retrieve discard position from playermat!", "Red") - return - end - - local num = math.random(1, #hand) - hand[num].setPosition(discardPos) - broadcastToAll(playerColor .. " randomly discarded card " .. num .. "/" .. #hand .. ".", "White") - end -end - ---------------------------------------------------------- --- helper functions ---------------------------------------------------------- - --- helper to search array -function indexOf(array, value) - for i, v in ipairs(array) do - if v == value then return i end - end -end - --- helper to check if player exists -function playerExists(color) - local COLORS = Player.getAvailableColors() - return indexOf(COLORS, color) and true or false + playmatAPI.doDiscardOne(matColor) end diff --git a/src/core/Global.ttslua b/src/core/Global.ttslua index 0234bbd5..26eed36f 100644 --- a/src/core/Global.ttslua +++ b/src/core/Global.ttslua @@ -925,9 +925,7 @@ function spawnHelperObject(name, position, rotation, color) 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 + if name == "Token Arranger" then Wait.time(function() object.call("layout") end, 0.1) end end diff --git a/src/playermat/Playmat.ttslua b/src/playermat/Playmat.ttslua index 0a7b7cc3..0893bf38 100644 --- a/src/playermat/Playmat.ttslua +++ b/src/playermat/Playmat.ttslua @@ -5,7 +5,7 @@ local tokenChecker = require("core/token/TokenChecker") local DEBUG = false -- we use this to turn off collision handling until onLoad() is complete -local COLLISION_ENABLED = false +local collisionEnabled = false -- position offsets relative to mat [x, y, z] local DRAWN_ENCOUNTER_CARD_OFFSET = {1.365, 0.5, -0.635} @@ -62,6 +62,9 @@ local RESOURCE_COUNTER activeInvestigatorId = "00000" local isDrawButtonVisible = false +-- global variable to report "Dream-Enhancing Serum" status +isDES = false + function onSave() return JSON.encode({ zoneID = zoneID, @@ -122,7 +125,9 @@ function onLoad(save_state) showDrawButton(isDrawButtonVisible) if getObjectFromGUID(zoneID) == nil then spawnDeckZone() end - COLLISION_ENABLED = true + collisionEnabled = true + + math.randomseed(os.time()) end --------------------------------------------------------- @@ -409,6 +414,51 @@ function shuffleDiscardIntoDeck() discardPile = nil end +-- discard a random non-hidden card from hand +function doDiscardOne() + local handColor = getHandColor() + local hand = Player[handColor].getHandObjects() + if #hand == 0 then + broadcastToAll("Cannot discard from empty hand!", "Red") + else + local choices = {} + for i = 1, #hand do + local notes = JSON.decode(hand[i].getGMNotes()) + if notes ~= nil then + if notes.hidden ~= true then + table.insert(choices, i) + end + else + table.insert(choices, i) + end + end + + if #choices == 0 then + broadcastToAll("Hidden cards can't be randomly discarded.", "Orange") + return + end + + -- get a random non-hidden card (from the "choices" table) + local num = math.random(1, #choices) + hand[choices[num]].setPosition(returnGlobalDiscardPosition()) + broadcastToAll(handColor .. " randomly discarded card " .. choices[num] .. "/" .. #hand .. ".", "White") + end +end + +-- gets the hand color of the closest seated player (by roughly cutting the table into quarters) +function getHandColor() + for _, handColor in ipairs(Player.getAvailableColors()) do + local handPosition = Player[handColor].getHandTransform().position + + if (PLAYER_COLOR == "White" and handPosition.x < -42 and handPosition.z > 0) + or (PLAYER_COLOR == "Orange" and handPosition.x < -42 and handPosition.z < 0) + or (PLAYER_COLOR == "Green" and handPosition.x > -42 and handPosition.z > 0) + or (PLAYER_COLOR == "Red" and handPosition.x > -42 and handPosition.z < 0) then + return handColor + end + end +end + --------------------------------------------------------- -- playmat token spawning --------------------------------------------------------- @@ -493,9 +543,14 @@ function spawnTokensFor(object) end function onCollisionEnter(collision_info) - if not COLLISION_ENABLED then return end local object = collision_info.collision_object + -- detect if "Dream-Enhancing Serum" is placed + if object.getName() == "Dream-Enhancing Serum" then isDES = true end + + -- only continue if loading is completed + if not collisionEnabled then return end + -- only continue for cards if object.name ~= "Card" and object.name ~= "CardCustom" then return end @@ -509,6 +564,11 @@ function onCollisionEnter(collision_info) end end +-- detect if "Dream-Enhancing Serum" is removed +function onCollisionExit(collision_info) + if collision_info.collision_object.getName() == "Dream-Enhancing Serum" then isDES = false end +end + function shouldSpawnTokens(card) if card.is_face_down then return false diff --git a/src/playermat/PlaymatApi.ttslua b/src/playermat/PlaymatApi.ttslua index 9070a00b..a04893fc 100644 --- a/src/playermat/PlaymatApi.ttslua +++ b/src/playermat/PlaymatApi.ttslua @@ -41,6 +41,20 @@ do end end + -- Returns the color of the player's hand that is seated next to the playermat + ---@param matColor String Color of the playermat + PlaymatApi.getHandColor = function(matColor) + local mat = getObjectFromGUID(MAT_IDS[matColor]) + return mat.call("getHandColor") + end + + -- Returns if there is the card"Dream-Enhancing Serum" on the requested playermat + ---@param matColor String Color of the playermat + PlaymatApi.isDES = function(matColor) + local mat = getObjectFromGUID(MAT_IDS[matColor]) + return mat.getVar("isDES") + end + -- Returns the draw deck of the requested playmat ---@param matColor String Color of the playermat PlaymatApi.getDrawDeck = function(matColor) @@ -116,6 +130,13 @@ do end end + -- Discard a non-hidden card from the corresponding player's hand + PlaymatApi.doDiscardOne = function(matColor) + for _, mat in ipairs(internal.getMatForColor(matColor)) do + mat.call("doDiscardOne") + end + end + -- Convenience function to look up a mat's object by color, or get all mats. ---@param matColor String for one of the active player colors - White, Orange, Green, Red. Also -- accepts "All" as a special value which will return all four mats. From 8ee07b25829b1ea3a9f43753d42624ee3a5cd17c Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Tue, 28 Feb 2023 15:08:05 +0100 Subject: [PATCH 4/7] minor bugfix --- src/accessories/HandHelper.ttslua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/accessories/HandHelper.ttslua b/src/accessories/HandHelper.ttslua index 3137a966..21e2e586 100644 --- a/src/accessories/HandHelper.ttslua +++ b/src/accessories/HandHelper.ttslua @@ -1,7 +1,5 @@ local playmatAPI = require("playermat/PlaymatApi") -local matColor -local handColor -local loopId +local matColor, handColor, loopId, hovering function onLoad() local buttonParamaters = {} @@ -48,12 +46,18 @@ function onDrop() updateColors() end -- toggles counting method briefly function onObjectHover(hover_color, obj) -- only continue if correct player hovers over "self" - if obj ~= self or hover_color ~= handColor then return end + if obj ~= self or hover_color ~= handColor or hovering then return end + + -- toggle this flag so this doesn't get executed multiple times during the delay + hovering = true -- stop loop, toggle "des" and displayed value briefly, then start new loop after 2s Wait.stop(loopId) updateValue(true) - Wait.time(function() loopId = Wait.time(updateValue, 1, -1) end, 2) + Wait.time(function() + loopId = Wait.time(updateValue, 1, -1) + hovering = false + end, 1) end -- updates the matcolor and handcolor variable @@ -99,7 +103,7 @@ function updateValue(toggle) if obj.tag == "Card" then size = size + 1 end end end - + -- update button label and color self.editButton({ index = 0, font_color = des and "Green" or "White", label = size }) end From a1e6560440d884c4ae81d5222f6c23d8c5e888b8 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Tue, 28 Feb 2023 18:22:03 +0100 Subject: [PATCH 5/7] removal of unneeded option panel code --- src/core/Global.ttslua | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/core/Global.ttslua b/src/core/Global.ttslua index 26eed36f..ec157987 100644 --- a/src/core/Global.ttslua +++ b/src/core/Global.ttslua @@ -856,10 +856,10 @@ function applyOptionPanelChange(id, state) -- option: Show hand helper for each player elseif id == "showHandHelper" then - optionPanel[id][1] = spawnOrRemoveHelper(state, "Hand Helper", {-50.85, 1.6, 7.32}, {0, 270, 0}, "White") - optionPanel[id][2] = spawnOrRemoveHelper(state, "Hand Helper", {-50.85, 1.6, -24.88}, {0, 270, 0}, "Orange") - optionPanel[id][3] = spawnOrRemoveHelper(state, "Hand Helper", {-39.13, 1.6, 22.45}, {0, 000, 0}, "Green") - optionPanel[id][4] = spawnOrRemoveHelper(state, "Hand Helper", {-21.57, 1.6, -22.45}, {0, 180, 0}, "Red") + optionPanel[id][1] = spawnOrRemoveHelper(state, "Hand Helper", {-50.85, 1.6, 7.32}, {0, 270, 0}) + optionPanel[id][2] = spawnOrRemoveHelper(state, "Hand Helper", {-50.85, 1.6, -24.88}, {0, 270, 0}) + optionPanel[id][3] = spawnOrRemoveHelper(state, "Hand Helper", {-39.13, 1.6, 22.45}, {0, 000, 0}) + optionPanel[id][4] = spawnOrRemoveHelper(state, "Hand Helper", {-21.57, 1.6, -22.45}, {0, 180, 0}) -- option: Show search assistant for each player elseif id == "showSearchAssistant" then @@ -899,12 +899,11 @@ end ---@param name String Name of the helper object ---@param position Vector Position of the object (where it will spawn) ---@param rotation Vector Rotation of the object for spawning (default: {0, 270, 0}) ----@param color String This is only needed for correctly setting the color of the "Hand Helper" ---@return. GUID of the spawnedObj (or nil if object was removed) -function spawnOrRemoveHelper(state, name, position, rotation, color) +function spawnOrRemoveHelper(state, name, position, rotation) if state then Player.getPlayers()[1].pingTable(position) - return spawnHelperObject(name, position, rotation, color).getGUID() + return spawnHelperObject(name, position, rotation).getGUID() else return removeHelperObject(name) end @@ -913,7 +912,7 @@ end -- copies the specified tool (by name) from the barrel ---@param name String Name of the object that should be copied ---@param position Table Desired position of the object -function spawnHelperObject(name, position, rotation, color) +function spawnHelperObject(name, position, rotation) local barrel = getObjectFromGUID(BARREL_GUID) -- error handling for missing barrel From 1e1dff22618c55722867d369a37e5794d53d5785 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Wed, 1 Mar 2023 00:46:02 +0100 Subject: [PATCH 6/7] stop including permanent cards --- src/arkhamdb/DeckImporterMain.ttslua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arkhamdb/DeckImporterMain.ttslua b/src/arkhamdb/DeckImporterMain.ttslua index 2099e0bb..b5c125e2 100644 --- a/src/arkhamdb/DeckImporterMain.ttslua +++ b/src/arkhamdb/DeckImporterMain.ttslua @@ -269,7 +269,8 @@ function handleUnderworldMarket(cardList, playerColor) card.zone = "SetAside3" elseif (card.metadata.traits ~= nil and string.find(card.metadata.traits, "Illicit", 1, true) and card.metadata.bonded_to == nil - and not card.metadata.weakness) then + and not card.metadata.weakness + and not card.metadata.permanent) then table.insert(illicitList, i) end end From 46bd6b090105c4e39795d6aaad93ad966079d782 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Wed, 1 Mar 2023 02:03:10 +0100 Subject: [PATCH 7/7] checking zone instead of metadata --- src/arkhamdb/DeckImporterMain.ttslua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/arkhamdb/DeckImporterMain.ttslua b/src/arkhamdb/DeckImporterMain.ttslua index b5c125e2..8d981451 100644 --- a/src/arkhamdb/DeckImporterMain.ttslua +++ b/src/arkhamdb/DeckImporterMain.ttslua @@ -267,10 +267,7 @@ function handleUnderworldMarket(cardList, playerColor) -- Underworld Market found hasMarket = true card.zone = "SetAside3" - elseif (card.metadata.traits ~= nil and string.find(card.metadata.traits, "Illicit", 1, true) - and card.metadata.bonded_to == nil - and not card.metadata.weakness - and not card.metadata.permanent) then + elseif card.metadata.traits ~= nil and string.find(card.metadata.traits, "Illicit", 1, true) and card.zone == "Deck" then table.insert(illicitList, i) end end