diff --git a/src/core/VictoryDisplay.ttslua b/src/core/VictoryDisplay.ttslua
index 13c56694..d5541102 100644
--- a/src/core/VictoryDisplay.ttslua
+++ b/src/core/VictoryDisplay.ttslua
@@ -234,28 +234,28 @@ end
-- places the provided card in the first empty spot
function placeCard(card)
- local trash = guidReferenceApi.getObjectByOwnerAndType("Mythos", "Trash")
-
- -- check snap point states
+ -- get sorted list of snap points to check slots
local snaps = self.getSnapPoints()
table.sort(snaps, function(a, b) return a.position.x > b.position.x end)
table.sort(snaps, function(a, b) return a.position.z < b.position.z end)
-- get first empty slot
- local fullSlots = {}
- local positions = {}
+ local emptyIndex, emptyPos
for i, snap in ipairs(snaps) do
- positions[i] = self.positionToWorld(snap.position)
- local searchResult = searchLib.atPosition(positions[i], "isCardOrDeck")
- fullSlots[i] = #searchResult > 0
+ local snapPos = self.positionToWorld(snap.position)
+ local searchResult = searchLib.atPosition(snapPos, "isCardOrDeck")
+ if #searchResult == 0 then
+ emptyPos = snapPos
+ emptyIndex = i
+ break
+ end
end
-- remove tokens from the card
- for _, obj in ipairs(searchLib.onObject(card)) do
- -- don't touch decks / cards
- if obj.type == "Deck" or obj.type == "Card" then
+ local trash = guidReferenceApi.getObjectByOwnerAndType("Mythos", "Trash")
+ for _, obj in ipairs(searchLib.onObject(card, "isTileOrToken")) do
+ if tokenChecker.isChaosToken(obj) then
-- put chaos tokens back into bag
- elseif tokenChecker.isChaosToken(obj) then
local chaosBag = chaosBagApi.findChaosBag()
chaosBag.putObject(obj)
elseif obj.memo ~= nil and obj.getLock() == false then
@@ -264,17 +264,14 @@ function placeCard(card)
end
-- place the card
+ card.setRotation({ 0, 270, card.getRotation().z })
local name = card.getName() or "Unnamed card"
- for i = 1, 10 do
- if fullSlots[i] ~= true then
- local rot = { 0, 270, card.getRotation().z }
- card.setPositionSmooth(positions[i], false, true)
- card.setRotation(rot)
- broadcastToAll("Victory Display: " .. name .. " placed into slot " .. i .. ".", "Green")
- return
- end
+ if emptyPos then
+ card.setPositionSmooth(emptyPos, false, true)
+ broadcastToAll("Victory Display: " .. name .. " placed into slot " .. emptyIndex .. ".", "Green")
+ else
+ -- use the first snap position in case all slots are full
+ card.setPositionSmooth(self.positionToWorld(snaps[1].position), false, true)
+ broadcastToAll("Victory Display is full! " .. name .. " placed into slot 1.", "Orange")
end
-
- broadcastToAll("Victory Display is full! " .. name .. " placed into slot 1.", "Orange")
- card.setPositionSmooth(positions[1], false, true)
end
diff --git a/src/playercards/cards/KohakuNarukami.ttslua b/src/playercards/cards/KohakuNarukami.ttslua
index 1d4c20d9..adb9d069 100644
--- a/src/playercards/cards/KohakuNarukami.ttslua
+++ b/src/playercards/cards/KohakuNarukami.ttslua
@@ -1,13 +1,20 @@
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 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 isHelperEnabled = false
local updated
+local xmlData = {
+ Action = { color = "#6D202CE6", onClick = "removeAndExtraAction" },
+ Bless = { color = "#9D702CE6", onClick = "addTokenToBag" },
+ Curse = { color = "#633A84E6", onClick = "addTokenToBag" },
+ ElderSign = { color = "#50A8CEE6", onClick = "elderSignAbility" }
+}
+
function updateSave()
self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled })
end
@@ -57,32 +64,29 @@ function removeAndExtraAction()
local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")
local rotation = mat.getRotation()
- -- find empty action token slots
- -- check snap point states
+ -- find empty action token slots by checking snap points
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)
+
+ -- get first empty slot in the top row (so the second empty slot because of the ability token)
+ local emptyPos = position -- default to card position
+ for i, snap in ipairs(snaps) do
+ if i > 1 then
+ if snap.tags[1] == "UniversalToken" then
+ local snapPos = mat.positionToWorld(snap.position)
+ local searchResult = searchLib.atPosition(snapPos, "isUniversalToken")
+ if #searchResult == 0 then
+ emptyPos = snapPos
+ break
+ end
+ end
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
+ callback = function(spawned)
+ spawned.call("updateClassAndSymbol", { class = "Mystic", symbol = "Mystic" })
+ spawned.addTag("Temporary")
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)
+ tokenManager.spawnToken(emptyPos + Vector(0, 0.7, 0), "universalActionAbility", rotation, callback)
end
function elderSignAbility()
@@ -97,37 +101,39 @@ function maybeUpdateButtonState()
if numInBag.Bless <= numInBag.Curse and numInBag.Bless < 10 then
state.Bless = true
+ state.ElderSign = true
end
if numInBag.Curse <= numInBag.Bless and numInBag.Curse < 10 then
state.Curse = true
+ state.ElderSign = true
end
- if numInBag.Curse >= 2 and numInBag.Bless >= 2 then
+ 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)
+ for buttonId, state in ipairs(params) do
+ if state then
+ self.UI.setAttribute(buttonId, "color", xmlData[buttonId].color)
+ self.UI.setAttribute(buttonId, "onClick", xmlData[buttonId].onClick)
+ self.UI.setAttribute(buttonId, "textColor", "white")
else
- self.UI.show("inactive" .. tokenName)
- self.UI.hide(tokenName)
+ self.UI.setAttribute(buttonId, "color", "#353535E6")
+ self.UI.setAttribute(buttonId, "onClick", "errorMessage")
+ self.UI.setAttribute(buttonId, "textColor", "#A0A0A0")
end
end
end
function errorMessage(_, _, triggeringButton)
local numInBag = blessCurseManagerApi.getBlessCurseInBag()
- if triggeringButton == "inactiveAction" then
+ if triggeringButton == "Action" 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")
diff --git a/src/util/DeckLib.ttslua b/src/util/DeckLib.ttslua
index a88cb50c..0655ce1d 100644
--- a/src/util/DeckLib.ttslua
+++ b/src/util/DeckLib.ttslua
@@ -2,23 +2,25 @@ do
local DeckLib = {}
local searchLib = require("util/SearchLib")
- -- places a card/deck at a position or merges into an existing deck
+ -- places a card/deck at a position or merges into an existing deck below
---@param obj tts__Object Object to move
---@param pos table New position for the object
---@param rot? table New rotation for the object
---@param below? boolean Should the object be placed below an existing deck?
DeckLib.placeOrMergeIntoDeck = function(obj, pos, rot, below)
- if obj == nil or pos == nil then return end
+ if obj == nil or obj.isDestroyed() or pos == nil then return end
-- search the new position for existing card/deck
local searchResult = searchLib.atPosition(pos, "isCardOrDeck")
+ local targetObj
-- get new position
local offset = 0.5
local newPos = Vector(pos) + Vector(0, offset, 0)
if #searchResult == 1 then
- local bounds = searchResult[1].getBounds()
+ targetObj = searchResult[1]
+ local bounds = targetObj.getBounds()
if below then
newPos = Vector(pos):setAt("y", bounds.center.y - bounds.size.y / 2)
else
@@ -26,7 +28,8 @@ do
end
end
- -- allow moving the objects smoothly out of the hand
+ -- allow moving the objects smoothly out of the hand and temporarily lock it
+ obj.setLock(true)
obj.use_hands = false
if rot then
@@ -34,17 +37,17 @@ do
end
obj.setPositionSmooth(newPos, false, true)
- -- continue if the card stops smooth moving
+ -- use putObject if the card stops smooth moving to avoid a TTS bug that merges unrelated cards that are not resting
+ -- pcall avoids errors (physics is sometimes too fast so the object doesn't exist for the put)
Wait.condition(
- function()
- obj.use_hands = true
- -- this avoids a TTS bug that merges unrelated cards that are not resting
- if #searchResult == 1 and searchResult[1] ~= obj and searchResult[1] ~= nil then
- -- call this with avoiding errors (physics is sometimes too fast so the object doesn't exist for the put)
- pcall(function() searchResult[1].putObject(obj) end)
- end
- end,
- function() return not obj.isSmoothMoving() end, 3)
+ pcall(function()
+ obj.setLock(false)
+ obj.use_hands = true
+ if #searchResult == 1 and targetObj ~= obj then
+ targetObj.putObject(obj)
+ end
+ end),
+ function() return not obj.isSmoothMoving() end, 3)
end
return DeckLib
diff --git a/xml/playercards/KohakuNarukami.xml b/xml/playercards/KohakuNarukami.xml
index 277dfcd8..adea3dba 100644
--- a/xml/playercards/KohakuNarukami.xml
+++ b/xml/playercards/KohakuNarukami.xml
@@ -4,14 +4,6 @@
fontSize="200"
iconWidth="300"
iconAlignment="Right"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+