diff --git a/modsettings/CustomUIAssets.json b/modsettings/CustomUIAssets.json index 46ca3769..dc84a999 100644 --- a/modsettings/CustomUIAssets.json +++ b/modsettings/CustomUIAssets.json @@ -234,6 +234,11 @@ "Type": 0, "URL": "http://cloud-3.steamusercontent.com/ugc/2510267932886739653/CB7AA2D73777EF5938A6E6CD664B2ABA52B6E20A/" }, + { + "Name": "token-eldersign", + "Type": 0, + "URL": "http://cloud-3.steamusercontent.com/ugc/2540675016035917168/C0D6F531A85FD94C2F54825DFC50781B5B499A1D/" + }, { "Name": "token-custom-token", "Type": 0, diff --git a/objects/AllPlayerCards.15bb07/KhakuNarukami.54eaa7.json b/objects/AllPlayerCards.15bb07/KhakuNarukami.54eaa7.json index 7c317a95..3cc17a73 100644 --- a/objects/AllPlayerCards.15bb07/KhakuNarukami.54eaa7.json +++ b/objects/AllPlayerCards.15bb07/KhakuNarukami.54eaa7.json @@ -33,7 +33,7 @@ "IgnoreFoW": false, "LayoutGroupSortIndex": 0, "Locked": false, - "LuaScript": "", + "LuaScript": "require(\"playercards/cards/KohakuNarukami\")", "LuaScriptState": "", "MeasureMovement": false, "Name": "Card", @@ -58,5 +58,5 @@ "scaleZ": 1.15 }, "Value": 0, - "XmlUI": "" + "XmlUI": "\u003cInclude src=\"playercards/KohakuNarukami.xml\"/\u003e" } diff --git a/src/chaosbag/BlessCurseManager.ttslua b/src/chaosbag/BlessCurseManager.ttslua index 0d8f50eb..945123e0 100644 --- a/src/chaosbag/BlessCurseManager.ttslua +++ b/src/chaosbag/BlessCurseManager.ttslua @@ -266,6 +266,19 @@ function updateDisplayAndBroadcast(type) end end +function getBlessCurseInBag() + local numInBag = { Bless = 0, Curse = 0 } + local chaosBag = chaosBagApi.findChaosBag() + + for _, v in ipairs(chaosBag.getObjects()) do + if v.name == "Bless" or v.name == "Curse" then + numInBag[v.name] = numInBag[v.name] + 1 + end + end + + return numInBag +end + --------------------------------------------------------- -- main functions: add and remove --------------------------------------------------------- diff --git a/src/chaosbag/BlessCurseManagerApi.ttslua b/src/chaosbag/BlessCurseManagerApi.ttslua index 00290284..896a6c96 100644 --- a/src/chaosbag/BlessCurseManagerApi.ttslua +++ b/src/chaosbag/BlessCurseManagerApi.ttslua @@ -67,5 +67,9 @@ do getManager().call("removeToken", type) end + BlessCurseManagerApi.getBlessCurseInBag = function() + return getManager().call("getBlessCurseInBag", {}) + end + return BlessCurseManagerApi end diff --git a/src/playercards/cards/BookofLivingMyths.ttslua b/src/playercards/cards/BookofLivingMyths.ttslua index b30f04d6..776c9d8b 100644 --- a/src/playercards/cards/BookofLivingMyths.ttslua +++ b/src/playercards/cards/BookofLivingMyths.ttslua @@ -1,9 +1,11 @@ require("playercards/CardsWithHelper") +local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi") local chaosBagApi = require("chaosbag/ChaosBagApi") local guidReferenceApi = require("core/GUIDReferenceApi") local playermatApi = require("playermat/PlayermatApi") local isHelperEnabled = false +local updated function updateSave() self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled }) @@ -34,6 +36,7 @@ function initialize() end function resolveToken(player, _, tokenType) + if not updated then return end local matColor if player.color == "Black" then matColor = playermatApi.getMatColorByPosition(self.getPosition()) @@ -43,11 +46,13 @@ function resolveToken(player, _, tokenType) local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat") chaosBagApi.drawChaosToken(mat, true, tokenType) + updated = false + Wait.frames(maybeUpdateButtonState, 2) end -- count tokens in the bag and show appropriate buttons function maybeUpdateButtonState() - local numInBag = getBlessCurseInBag() + local numInBag = blessCurseManagerApi.getBlessCurseInBag() local state = { Bless = false, Curse = false } if numInBag.Bless >= numInBag.Curse and numInBag.Bless > 0 then @@ -59,19 +64,7 @@ function maybeUpdateButtonState() end setUiState(state) -end - -function getBlessCurseInBag() - local numInBag = { Bless = 0, Curse = 0 } - local chaosBag = chaosBagApi.findChaosBag() - - for _, v in ipairs(chaosBag.getObjects()) do - if v.name == "Bless" or v.name == "Curse" then - numInBag[v.name] = numInBag[v.name] + 1 - end - end - - return numInBag + updated = true end function setUiState(params) @@ -87,7 +80,7 @@ function setUiState(params) end function errorMessage() - local numInBag = getBlessCurseInBag() + local numInBag = blessCurseManagerApi.getBlessCurseInBag() if numInBag.Bless == 0 and numInBag.Curse == 0 then broadcastToAll("There are no Bless or Curse tokens in the chaos bag.", "Red") diff --git a/src/playercards/cards/KohakuNarukami.ttslua b/src/playercards/cards/KohakuNarukami.ttslua new file mode 100644 index 00000000..1d4c20d9 --- /dev/null +++ b/src/playercards/cards/KohakuNarukami.ttslua @@ -0,0 +1,139 @@ +require("playercards/CardsWithHelper") +local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi") +local guidReferenceApi = require("core/GUIDReferenceApi") +local playermatApi = require("playermat/PlayermatApi") +local searchLib = require("util/SearchLib") +local tokenManager = require("core/token/TokenManager") + +local isHelperEnabled = false +local updated + +function updateSave() + self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled }) +end + +function onLoad(savedData) + self.addTag("CardWithHelper") + if savedData and savedData ~= "" then + local loadedData = JSON.decode(savedData) + isHelperEnabled = loadedData.isHelperEnabled + end + checkOptionPanel() +end + +-- hide buttons and stop monitoring +function shutOff() + self.UI.hide("Helper") + Wait.stopAll() + updateSave() +end + +-- show buttons and begin monitoring chaos bag for curse and bless tokens +function initialize() + self.UI.show("Helper") + maybeUpdateButtonState() + Wait.time(maybeUpdateButtonState, 1, -1) + updateSave() +end + +function addTokenToBag(_, _, tokenType) + if not updated then return end + blessCurseManagerApi.addToken(tokenType) + updated = false + Wait.frames(maybeUpdateButtonState, 2) +end + +function removeAndExtraAction() + if not updated then return end + blessCurseManagerApi.removeToken("Bless") + blessCurseManagerApi.removeToken("Bless") + blessCurseManagerApi.removeToken("Curse") + blessCurseManagerApi.removeToken("Curse") + updated = false + Wait.frames(maybeUpdateButtonState, 2) + + local position = self.getPosition() + local matColor = playermatApi.getMatColorByPosition(position) + local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat") + local rotation = mat.getRotation() + + -- find empty action token slots + -- check snap point states + local snaps = mat.getSnapPoints() + + -- get first empty slot + local fullSlots = {} + local positions = {} + for _, snap in ipairs(snaps) do + if snap.tags[1] == "UniversalToken" then + table.insert(positions, mat.positionToWorld(snap.position)) + local searchResult = searchLib.atPosition(positions[#positions], "isUniversalToken") + table.insert(fullSlots, #searchResult > 0) + end + end + + for i = 2, 6 do -- look at all 5 slots above investigator card + if fullSlots[i] ~= true then + callback = function(spawned) spawned.call("updateClassAndSymbol", { class = "Mystic", symbol = "Mystic" }) spawned.addTag("Temporary") end + tokenManager.spawnToken(positions[i] + Vector(0, 0.7, 0), "universalActionAbility", rotation, callback) + return + end + end + + -- if all slots are full + callback = function(spawned) spawned.call("updateClassAndSymbol", { class = "Mystic", symbol = "Mystic" }) spawned.addTag("Temporary") end + tokenManager.spawnToken(position + Vector(0, 0.7, 0), "universalActionAbility", rotation, callback) +end + +function elderSignAbility() + blessCurseManagerApi.addToken("Bless") + blessCurseManagerApi.addToken("Curse") +end + +-- count tokens in the bag and show appropriate buttons +function maybeUpdateButtonState() + local numInBag = blessCurseManagerApi.getBlessCurseInBag() + local state = { Bless = false, Curse = false, Action = false, ElderSign = false } + + if numInBag.Bless <= numInBag.Curse and numInBag.Bless < 10 then + state.Bless = true + end + + if numInBag.Curse <= numInBag.Bless and numInBag.Curse < 10 then + state.Curse = true + end + + if numInBag.Curse >= 2 and numInBag.Bless >= 2 then + state.Action = true + end + + state.ElderSign = true + + setUiState(state) + updated = true +end + +function setUiState(params) + for _, tokenName in ipairs({ "Bless", "Curse", "Action", "ElderSign" }) do + if params[tokenName] then + self.UI.show(tokenName) + self.UI.hide("inactive" .. tokenName) + else + self.UI.show("inactive" .. tokenName) + self.UI.hide(tokenName) + end + end +end + +function errorMessage(_, _, triggeringButton) + local numInBag = blessCurseManagerApi.getBlessCurseInBag() + if triggeringButton == "inactiveAction" then + broadcastToAll("There are not enough Blesses and/or Curses in the chaos bag.", "Red") + elseif numInBag.Bless == 10 and numInBag.Curse == 10 then + broadcastToAll("No more tokens can be added to the chaos bag.", "Red") + elseif numInBag.Bless < numInBag.Curse then + broadcastToAll("There are more Bless tokens than Curse tokens in the chaos bag.", "Red") + else + broadcastToAll("There are more Curse tokens than Bless tokens in the chaos bag.", "Red") + end +end diff --git a/src/playermat/Playermat.ttslua b/src/playermat/Playermat.ttslua index 9f221632..cecce54b 100644 --- a/src/playermat/Playermat.ttslua +++ b/src/playermat/Playermat.ttslua @@ -313,7 +313,9 @@ function doUpkeep(_, clickedByColor, isRightClick) local forcedLearning = false local rot = self.getRotation() for _, obj in ipairs(searchAroundSelf()) do - if obj.hasTag("UniversalToken") == true and obj.is_face_down then + if obj.hasTag("Temporary") == true then + discardListOfObjects({obj}) + elseif obj.hasTag("UniversalToken") == true and obj.is_face_down then obj.flip() elseif obj.type == "Card" and not inArea(self.positionToLocal(obj.getPosition()), INVESTIGATOR_AREA) then local cardMetadata = JSON.decode(obj.getGMNotes()) or {} diff --git a/xml/playercards/KohakuNarukami.xml b/xml/playercards/KohakuNarukami.xml new file mode 100644 index 00000000..277dfcd8 --- /dev/null +++ b/xml/playercards/KohakuNarukami.xml @@ -0,0 +1,94 @@ + +