Merge pull request #740 from argonui/misc

Code maintenance
This commit is contained in:
dscarpac 2024-07-03 15:23:07 -05:00 committed by GitHub
commit ecf2c23976
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 189 additions and 219 deletions

View File

@ -124,22 +124,17 @@ function startSearch(messageColor, number)
end end
-- get position and rotation for set aside cards -- get position and rotation for set aside cards
local handData = Player[handColor].getHandTransform() local handData = Player[handColor].getHandTransform()
local handCards = Player[handColor].getHandObjects() local handCards = Player[handColor].getHandObjects()
setAsidePosition = handData.position + offset * handData.right setAsidePosition = (handData.position + offset * handData.right):setAt("y", 1.5)
setAsideRotation = { handData.rotation.x, handData.rotation.y + 180, 180 } setAsideRotation = { handData.rotation.x, handData.rotation.y + 180, 180 }
-- set y-value -- place hand cards set aside
setAsidePosition.y = 1.5 deckLib.placeOrMergeIntoDeck(handCards, setAsidePosition, setAsideRotation)
for i = #handCards, 1, -1 do
handCards[i].setPosition(setAsidePosition + Vector(0, (#handCards - i) * 0.1, 0))
handCards[i].setRotation(setAsideRotation)
end
-- handling for Norman Withers -- handling for Norman Withers
if deckAreaObjects.topCard then if deckAreaObjects.topCard then
deckAreaObjects.topCard.flip() deckAreaObjects.topCard.setRotation(setAsideRotation)
topCardDetected = true topCardDetected = true
end end
@ -155,35 +150,36 @@ end
function endSearch(_, _, isRightClick) function endSearch(_, _, isRightClick)
local handCards = Player[handColor].getHandObjects() local handCards = Player[handColor].getHandObjects()
local handCount = #handCards -- place cards on deck
for i = handCount, 1, -1 do deckLib.placeOrMergeIntoDeck(handCards, drawDeckPosition, setAsideRotation)
Wait.time(function() deckLib.placeOrMergeIntoDeck(handCards[i], drawDeckPosition, setAsideRotation) end,
(handCount - i + 1) * 0.1)
end
-- draw set aside cards (from the ground!) -- draw set aside cards (from the ground!)
Wait.time(drawSetAsideCards, 0.5 + #handCards * 0.1)
normalView()
Wait.time(function()
-- maybe shuffle deck
if not isRightClick then
local deckAreaObjects = playermatApi.getDeckAreaObjects(matColor)
if deckAreaObjects.draw then
deckAreaObjects.draw.shuffle()
end
end
-- Norman Withers handling
if topCardDetected then
playermatApi.flipTopCardFromDeck(matColor)
end
end, 1 + #handCards * 0.1)
end
function drawSetAsideCards()
for _, obj in ipairs(searchLib.atPosition(setAsidePosition, "isCardOrDeck")) do for _, obj in ipairs(searchLib.atPosition(setAsidePosition, "isCardOrDeck")) do
local count = 1 local count = 1
if obj.type == "Deck" then if obj.type == "Deck" then
count = #obj.getObjects() count = #obj.getObjects()
end end
Wait.time(function() obj.deal(count, handColor) end, 1) obj.deal(count, handColor)
end
normalView()
-- delay is to wait for cards to enter deck
if not isRightClick then
Wait.time(function()
local deckAreaObjects = playermatApi.getDeckAreaObjects(matColor)
if deckAreaObjects.draw then
deckAreaObjects.draw.shuffle()
end
end, #handCards * 0.3 + 0.5)
end
-- Norman Withers handling
if topCardDetected then
Wait.time(function() playermatApi.flipTopCardFromDeck(matColor) end, #handCards * 0.3 + 0.75)
end end
end end

View File

@ -1,7 +1,8 @@
local searchLib = require("util/SearchLib")
local chaosBagApi = require("chaosbag/ChaosBagApi") local chaosBagApi = require("chaosbag/ChaosBagApi")
local deckLib = require("util/DeckLib")
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local playAreaApi = require("core/PlayAreaApi") local playAreaApi = require("core/PlayAreaApi")
local searchLib = require("util/SearchLib")
local tokenChecker = require("core/token/TokenChecker") local tokenChecker = require("core/token/TokenChecker")
local pendingCall = false local pendingCall = false
@ -234,28 +235,30 @@ end
-- places the provided card in the first empty spot -- places the provided card in the first empty spot
function placeCard(card) function placeCard(card)
local trash = guidReferenceApi.getObjectByOwnerAndType("Mythos", "Trash") local name = card.getName() or "Unnamed card"
-- check snap point states -- get sorted list of snap points to check slots
local snaps = self.getSnapPoints() 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.x > b.position.x end)
table.sort(snaps, function(a, b) return a.position.z < b.position.z end) table.sort(snaps, function(a, b) return a.position.z < b.position.z end)
-- get first empty slot -- get first empty slot
local fullSlots = {} local emptyIndex, emptyPos
local positions = {}
for i, snap in ipairs(snaps) do for i, snap in ipairs(snaps) do
positions[i] = self.positionToWorld(snap.position) local snapPos = self.positionToWorld(snap.position)
local searchResult = searchLib.atPosition(positions[i], "isCardOrDeck") local searchResult = searchLib.atPosition(snapPos, "isCardOrDeck")
fullSlots[i] = #searchResult > 0 if #searchResult == 0 then
emptyPos = snapPos
emptyIndex = i
break
end
end end
-- remove tokens from the card -- remove tokens from the card
for _, obj in ipairs(searchLib.onObject(card)) do local trash = guidReferenceApi.getObjectByOwnerAndType("Mythos", "Trash")
-- don't touch decks / cards for _, obj in ipairs(searchLib.onObject(card, "isTileOrToken")) do
if obj.type == "Deck" or obj.type == "Card" then if tokenChecker.isChaosToken(obj) then
-- put chaos tokens back into bag -- put chaos tokens back into bag
elseif tokenChecker.isChaosToken(obj) then
local chaosBag = chaosBagApi.findChaosBag() local chaosBag = chaosBagApi.findChaosBag()
chaosBag.putObject(obj) chaosBag.putObject(obj)
elseif obj.memo ~= nil and obj.getLock() == false then elseif obj.memo ~= nil and obj.getLock() == false then
@ -263,18 +266,15 @@ function placeCard(card)
end end
end end
-- place the card -- use the first snap position in case all slots are full
local name = card.getName() or "Unnamed card" local pos = emptyPos or self.positionToWorld(snaps[1].position)
for i = 1, 10 do local rot = card.getRotation():setAt("x", 0):setAt("y", 270)
if fullSlots[i] ~= true then deckLib.placeOrMergeIntoDeck(card, pos, rot)
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
end
broadcastToAll("Victory Display is full! " .. name .. " placed into slot 1.", "Orange") -- give a feedback message
card.setPositionSmooth(positions[1], false, true) if emptyPos then
broadcastToAll("Victory Display: " .. name .. " placed into slot " .. emptyIndex .. ".", "Green")
else
broadcastToAll("Victory Display is full! " .. name .. " placed into slot 1.", "Orange")
end
end end

View File

@ -1,13 +1,20 @@
require("playercards/CardsWithHelper") require("playercards/CardsWithHelper")
local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi") local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local playermatApi = require("playermat/PlayermatApi") local playermatApi = require("playermat/PlayermatApi")
local searchLib = require("util/SearchLib") local searchLib = require("util/SearchLib")
local tokenManager = require("core/token/TokenManager") local tokenManager = require("core/token/TokenManager")
local isHelperEnabled = false local isHelperEnabled = false
local updated 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() function updateSave()
self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled }) self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled })
end end
@ -57,37 +64,36 @@ function removeAndExtraAction()
local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat") local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")
local rotation = mat.getRotation() local rotation = mat.getRotation()
-- find empty action token slots -- find empty action token slots by checking snap points
-- check snap point states
local snaps = mat.getSnapPoints() local snaps = mat.getSnapPoints()
-- get first empty slot -- get first empty slot in the top row (so the second empty slot because of the ability token)
local fullSlots = {} local emptyPos = position -- default to card position
local positions = {} for i, snap in ipairs(snaps) do
for _, snap in ipairs(snaps) do if i > 1 then
if snap.tags[1] == "UniversalToken" then if snap.tags[1] == "UniversalToken" then
table.insert(positions, mat.positionToWorld(snap.position)) local snapPos = mat.positionToWorld(snap.position)
local searchResult = searchLib.atPosition(positions[#positions], "isUniversalToken") local searchResult = searchLib.atPosition(snapPos, "isUniversalToken")
table.insert(fullSlots, #searchResult > 0) if #searchResult == 0 then
emptyPos = snapPos
break
end
end
end end
end end
for i = 2, 6 do -- look at all 5 slots above investigator card callback = function(spawned)
if fullSlots[i] ~= true then spawned.call("updateClassAndSymbol", { class = "Mystic", symbol = "Mystic" })
callback = function(spawned) spawned.call("updateClassAndSymbol", { class = "Mystic", symbol = "Mystic" }) spawned.addTag("Temporary") end spawned.addTag("Temporary")
tokenManager.spawnToken(positions[i] + Vector(0, 0.7, 0), "universalActionAbility", rotation, callback)
return
end
end end
tokenManager.spawnToken(emptyPos + Vector(0, 0.7, 0), "universalActionAbility", rotation, callback)
-- 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 end
function elderSignAbility() function elderSignAbility()
blessCurseManagerApi.addToken("Bless") blessCurseManagerApi.addToken("Bless")
blessCurseManagerApi.addToken("Curse") blessCurseManagerApi.addToken("Curse")
updated = false
Wait.frames(maybeUpdateButtonState, 2)
end end
-- count tokens in the bag and show appropriate buttons -- count tokens in the bag and show appropriate buttons
@ -97,37 +103,39 @@ function maybeUpdateButtonState()
if numInBag.Bless <= numInBag.Curse and numInBag.Bless < 10 then if numInBag.Bless <= numInBag.Curse and numInBag.Bless < 10 then
state.Bless = true state.Bless = true
state.ElderSign = true
end end
if numInBag.Curse <= numInBag.Bless and numInBag.Curse < 10 then if numInBag.Curse <= numInBag.Bless and numInBag.Curse < 10 then
state.Curse = true state.Curse = true
state.ElderSign = true
end end
if numInBag.Curse >= 2 and numInBag.Bless >= 2 then if numInBag.Curse >= 2 and numInBag.Bless >= 2 then
state.Action = true state.Action = true
end end
state.ElderSign = true
setUiState(state) setUiState(state)
updated = true updated = true
end end
function setUiState(params) function setUiState(params)
for _, tokenName in ipairs({ "Bless", "Curse", "Action", "ElderSign" }) do for buttonId, state in pairs(params) do
if params[tokenName] then if state then
self.UI.show(tokenName) self.UI.setAttribute(buttonId, "color", xmlData[buttonId].color)
self.UI.hide("inactive" .. tokenName) self.UI.setAttribute(buttonId, "onClick", xmlData[buttonId].onClick)
self.UI.setAttribute(buttonId, "textColor", "white")
else else
self.UI.show("inactive" .. tokenName) self.UI.setAttribute(buttonId, "color", "#353535E6")
self.UI.hide(tokenName) self.UI.setAttribute(buttonId, "onClick", "errorMessage")
self.UI.setAttribute(buttonId, "textColor", "#A0A0A0")
end end
end end
end end
function errorMessage(_, _, triggeringButton) function errorMessage(_, _, triggeringButton)
local numInBag = blessCurseManagerApi.getBlessCurseInBag() 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") broadcastToAll("There are not enough Blesses and/or Curses in the chaos bag.", "Red")
elseif numInBag.Bless == 10 and numInBag.Curse == 10 then elseif numInBag.Bless == 10 and numInBag.Curse == 10 then
broadcastToAll("No more tokens can be added to the chaos bag.", "Red") broadcastToAll("No more tokens can be added to the chaos bag.", "Red")

View File

@ -314,7 +314,7 @@ function doUpkeep(_, clickedByColor, isRightClick)
local rot = self.getRotation() local rot = self.getRotation()
for _, obj in ipairs(searchAroundSelf()) do for _, obj in ipairs(searchAroundSelf()) do
if obj.hasTag("Temporary") == true then if obj.hasTag("Temporary") == true then
discardListOfObjects({obj}) discardListOfObjects({ obj })
elseif obj.hasTag("UniversalToken") == true and obj.is_face_down then elseif obj.hasTag("UniversalToken") == true and obj.is_face_down then
obj.flip() obj.flip()
elseif obj.type == "Card" and not inArea(self.positionToLocal(obj.getPosition()), INVESTIGATOR_AREA) then elseif obj.type == "Card" and not inArea(self.positionToLocal(obj.getPosition()), INVESTIGATOR_AREA) then
@ -389,35 +389,29 @@ function doUpkeep(_, clickedByColor, isRightClick)
local handCards = Player[playerColor].getHandObjects() local handCards = Player[playerColor].getHandObjects()
local cardsToDiscard = {} local cardsToDiscard = {}
for i = 1, #handCards do for _, card in ipairs(handCards) do
local md = JSON.decode(handCards[i].getGMNotes()) local md = JSON.decode(card.getGMNotes())
if md ~= nil and (not md.weakness and not md.hidden and md.type ~= "Enemy") then if md ~= nil and (not md.weakness and not md.hidden and md.type ~= "Enemy") then
table.insert(cardsToDiscard, handCards[i]) table.insert(cardsToDiscard, card)
end end
end end
-- perform discarding 1 by 1 -- perform discarding 1 by 1
local pos = returnGlobalDiscardPosition() local pos = returnGlobalDiscardPosition()
local count = #cardsToDiscard deckLib.placeOrMergeIntoDeck(cardsToDiscard, pos, self.getRotation())
for i = count, 1, -1 do
Wait.time(function() deckLib.placeOrMergeIntoDeck(cardsToDiscard[i], pos, rot) end,
(count - i + 1) * 0.1)
end
-- add some time if there are any cards to discard, if not, draw up to 5 immediately -- draw up to 5 cards
local k = 0 local cardsToDraw = 5 - #handCards + #cardsToDiscard
if count > 0 then if cardsToDraw > 0 then
k = 0.5 + (count * 0.1) printToColor("Discarding " .. #cardsToDiscard .. " and drawing " .. cardsToDraw .. " card(s). (Patrice)", messageColor)
end
Wait.time(function() -- add some time if there are any cards to discard
local handSize = #Player[playerColor].getHandObjects() local k = 0
if handSize < 5 then if #cardsToDiscard > 0 then
local cardsToDraw = 5 - handSize k = 0.8 + (#cardsToDiscard * 0.1)
printToColor("Drawing " .. cardsToDraw .. " cards (Patrice)", messageColor)
drawCardsWithReshuffle(cardsToDraw)
end end
end, k) Wait.time(function() drawCardsWithReshuffle(cardsToDraw) end, k)
end
end end
elseif forcedLearning then elseif forcedLearning then
printToColor("Drawing 2 cards, discard 1 (Forced Learning)", messageColor) printToColor("Drawing 2 cards, discard 1 (Forced Learning)", messageColor)

View File

@ -2,23 +2,33 @@ do
local DeckLib = {} local DeckLib = {}
local searchLib = require("util/SearchLib") 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 objOrTable tts__Object|table Object or table of objects to move
---@param pos table New position for the object ---@param pos table New position for the object
---@param rot? table New rotation for the object ---@param rot? table New rotation for the object
---@param below? boolean Should the object be placed below an existing deck? ---@param below? boolean Should the object be placed below an existing deck?
DeckLib.placeOrMergeIntoDeck = function(obj, pos, rot, below) DeckLib.placeOrMergeIntoDeck = function(objOrTable, pos, rot, below)
if obj == nil or pos == nil then return end if objOrTable == nil or pos == nil then return end
-- handle 'objOrTable' parameter
local objects = {}
if type(objOrTable) == "table" then
objects = objOrTable
else
table.insert(objects, objOrTable)
end
-- search the new position for existing card/deck -- search the new position for existing card/deck
local searchResult = searchLib.atPosition(pos, "isCardOrDeck") local searchResult = searchLib.atPosition(pos, "isCardOrDeck")
local targetObj
-- get new position -- get new position
local offset = 0.5 local offset = 0.5
local newPos = Vector(pos) + Vector(0, offset, 0) local newPos = Vector(pos) + Vector(0, offset, 0)
if #searchResult == 1 then if #searchResult == 1 then
local bounds = searchResult[1].getBounds() targetObj = searchResult[1]
local bounds = targetObj.getBounds()
if below then if below then
newPos = Vector(pos):setAt("y", bounds.center.y - bounds.size.y / 2) newPos = Vector(pos):setAt("y", bounds.center.y - bounds.size.y / 2)
else else
@ -26,25 +36,39 @@ do
end end
end end
-- allow moving the objects smoothly out of the hand -- process objects in reverse order
obj.use_hands = false for i = #objects, 1, -1 do
local obj = objects[i]
-- add a 0.1 delay for each object (for animation purposes)
Wait.time(function()
-- allow moving smoothly out of hand and temporarily lock it
obj.setLock(true)
obj.use_hands = false
if rot then if rot then
obj.setRotationSmooth(rot, false, true) obj.setRotationSmooth(rot, false, true)
end
obj.setPositionSmooth(newPos, false, true)
-- wait for object to finish movement (or 2 seconds)
Wait.condition(
function()
-- revert toggles
obj.setLock(false)
obj.use_hands = true
-- use putObject to avoid a TTS bug that merges unrelated cards that are not resting
if #searchResult == 1 and targetObj ~= obj and not targetObj.isDestroyed() and not obj.isDestroyed() then
targetObj = targetObj.putObject(obj)
else
targetObj = obj
end
end,
-- check state of the object (make sure it's not moving)
function() return obj.isDestroyed() or not obj.isSmoothMoving() end,
2)
end, (#objects- i) * 0.1)
end end
obj.setPositionSmooth(newPos, false, true)
-- continue if the card stops smooth moving
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)
end end
return DeckLib return DeckLib

View File

@ -4,14 +4,6 @@
fontSize="200" fontSize="200"
iconWidth="300" iconWidth="300"
iconAlignment="Right"/> iconAlignment="Right"/>
<Button class="inactive"
onClick="errorMessage"
color="#353535E6"
textColor="#A0A0A0"/>
<Button class="active"
onClick="addTokenToBag"
textColor="white"
active="false"/>
<TableLayout position="0 188 -22" <TableLayout position="0 188 -22"
rotation="0 0 90" rotation="0 0 90"
height="1800" height="1800"
@ -21,74 +13,30 @@
cellBackgroundColor="rgba(1,1,1,0)"/> cellBackgroundColor="rgba(1,1,1,0)"/>
</Defaults> </Defaults>
<Panel id="Helper" <TableLayout id="Helper"
active="false"> active="false">
<TableLayout> <Row>
<Row> <Cell>
<Cell> <Button id="Bless"
<Button id="Bless" icon="token-bless"/>
icon="token-bless" </Cell>
color="#9D702CE6" </Row>
class="active"/> <Row>
</Cell> <Cell>
</Row> <Button id="Curse"
<Row> icon="token-curse"/>
<Cell> </Cell>
<Button id="Curse" </Row>
icon="token-curse" <Row>
color="#633A84E6" <Cell>
class="active"/> <Button id="Action"
</Cell> text="Remove tokens"/>
</Row> </Cell>
<Row> </Row>
<Cell> <Row>
<Button id="Action" <Cell>
text="Remove tokens" <Button id="ElderSign"
color="#6D202CE6" icon="token-eldersign"/>
class="active" </Cell>
onClick="removeAndExtraAction"/> </Row>
</Cell> </TableLayout>
</Row>
<Row>
<Cell>
<Button id="ElderSign"
icon="token-eldersign"
color="#50A8CEE6"
class="active"
onClick="elderSignAbility"/>
</Cell>
</Row>
</TableLayout>
<TableLayout>
<Row>
<Cell>
<Button id="inactiveBless"
icon="token-bless"
class="inactive"/>
</Cell>
</Row>
<Row>
<Cell>
<Button id="inactiveCurse"
icon="token-curse"
class="inactive"/>
</Cell>
</Row>
<Row>
<Cell>
<Button id="inactiveAction"
text="Remove tokens"
class="inactive"/>
</Cell>
</Row>
<Row>
<Cell>
<Button id="inactiveElderSign"
text="Elder Sign"
icon="token-eldersign"
class="inactive"
onClick="elderSignAbility"/>
</Cell>
</Row>
</TableLayout>
</Panel>