diff --git a/objects/PlayArea.721ba2.json b/objects/PlayArea.721ba2.json index 08bac973..7a4e0967 100644 --- a/objects/PlayArea.721ba2.json +++ b/objects/PlayArea.721ba2.json @@ -959,6 +959,13 @@ "ImageURL": "https://steamusercontent-a.akamaihd.net/ugc/998015670465071049/FFAE162920D67CF38045EFBD3B85AD0F916147B2/", "WidthScale": 0 }, + "CustomUIAssets": [ + { + "Name": "font_teutonic-arkham", + "Type": 1, + "URL": "https://steamusercontent-a.akamaihd.net/ugc/2027213118467703445/89328E273B4C5180BF491516CE998DE3C604E162/" + } + ], "Description": "", "DragSelectable": true, "GMNotes": "", @@ -995,5 +1002,5 @@ "scaleZ": 10 }, "Value": 0, - "XmlUI": "" + "XmlUI": "\u003cInclude src=\"PlayArea.xml\"/\u003e" } diff --git a/src/core/DoomCounter.ttslua b/src/core/DoomCounter.ttslua index 2057389b..3bc07839 100644 --- a/src/core/DoomCounter.ttslua +++ b/src/core/DoomCounter.ttslua @@ -61,7 +61,7 @@ function updateVal(number) if number then broadcastDoom(val) else - broadcastToAll("0 doom on the agenda", "White") + broadcastToAll("0 doom on the agenda") end end @@ -72,9 +72,9 @@ function broadcastDoom(val) local doomThreshold = getDoomThreshold() if doomThreshold then - broadcastToAll(val .. " doom on the agenda (" .. doomInPlay .. "/" .. doomThreshold .. " in play)", "White") + broadcastToAll(val .. " doom on the agenda (" .. doomInPlay .. "/" .. doomThreshold .. " in play)") else - broadcastToAll(val .. " doom on the agenda (" .. doomInPlay .. " in play)", "White") + broadcastToAll(val .. " doom on the agenda (" .. doomInPlay .. " in play)") end end diff --git a/src/core/GameKeyHandler.ttslua b/src/core/GameKeyHandler.ttslua index 7d79bd0d..dcc08363 100644 --- a/src/core/GameKeyHandler.ttslua +++ b/src/core/GameKeyHandler.ttslua @@ -54,6 +54,9 @@ function triggerUpkeepMultihanded(playerColor) playermatApi.doUpkeepFromHotkey(matColor, playerColor) end end + + -- also trigger the PlayArea's "Ready Cards" function + playAreaApi.readyCards() end -- adds 1 doom to the agenda diff --git a/src/core/PlayArea.ttslua b/src/core/PlayArea.ttslua index dd0836b1..d6551ff7 100644 --- a/src/core/PlayArea.ttslua +++ b/src/core/PlayArea.ttslua @@ -21,7 +21,8 @@ local CONNECTION_LINE_Y = 1.529 -- used for recreating the link to a custom data helper after image change customDataHelper = nil -local DEFAULT_URL = "https://steamusercontent-a.akamaihd.net/ugc/998015670465071049/FFAE162920D67CF38045EFBD3B85AD0F916147B2/" +local DEFAULT_URL = +"https://steamusercontent-a.akamaihd.net/ugc/998015670465071049/FFAE162920D67CF38045EFBD3B85AD0F916147B2/" local SHIFT_OFFSETS = { left = { x = 0.00, y = 0, z = 7.67 }, @@ -69,7 +70,7 @@ function onLoad(savedData) end -- this needs to be here since the playarea will be reloaded when the image changes - self.interactable = false + self.interactable = false Wait.time(function() collisionEnabled = true end, 0.1) end @@ -308,7 +309,7 @@ function buildConnection(cardId, iconCardList, locData) -- If the reciprocal exists, convert it to BiDi, otherwise add as a one-way if locationConnections[connectedGuid] ~= nil and (locationConnections[connectedGuid][cardId] == ONE_WAY - or locationConnections[connectedGuid][cardId] == BIDIRECTIONAL) then + or locationConnections[connectedGuid][cardId] == BIDIRECTIONAL) then locationConnections[connectedGuid][cardId] = BIDIRECTIONAL locationConnections[cardId][connectedGuid] = nil else @@ -426,7 +427,8 @@ function addOneWayVector(origin, target, vectorOwner, lines) -- Calculate distance to be closer for horizontal positions than vertical, since cards are taller than wide local heading = Vector(originPos):sub(targetPos):heading("y") - local distanceFromCard = DIRECTIONAL_ARROW_DISTANCE * 0.7 + DIRECTIONAL_ARROW_DISTANCE * 0.3 * math.abs(math.sin(math.rad(heading))) + local distanceFromCard = DIRECTIONAL_ARROW_DISTANCE * 0.7 + + DIRECTIONAL_ARROW_DISTANCE * 0.3 * math.abs(math.sin(math.rad(heading))) -- Calculate the three possible arrow positions. These are offset by half the arrow length to -- make them visually balanced by keeping the arrows centered, not tracking the point @@ -449,8 +451,10 @@ end --- positioning and scaling, as well as highlighting connections during a drag operation ---@param lines table List of vector line elements. Mutable, will be updated to add this arrow function addArrowLines(arrowheadPos, originPos, vectorOwner, lines) - local arrowArm1 = Vector(arrowheadPos):moveTowards(originPos, ARROW_ARM_LENGTH):sub(arrowheadPos):rotateOver("y", -1 * ARROW_ANGLE):add(arrowheadPos) - local arrowArm2 = Vector(arrowheadPos):moveTowards(originPos, ARROW_ARM_LENGTH):sub(arrowheadPos):rotateOver("y", ARROW_ANGLE):add(arrowheadPos) + local arrowArm1 = Vector(arrowheadPos):moveTowards(originPos, ARROW_ARM_LENGTH):sub(arrowheadPos):rotateOver("y", + -1 * ARROW_ANGLE):add(arrowheadPos) + local arrowArm2 = Vector(arrowheadPos):moveTowards(originPos, ARROW_ARM_LENGTH):sub(arrowheadPos):rotateOver("y", + ARROW_ANGLE):add(arrowheadPos) local head = vectorOwner.positionToLocal(arrowheadPos) local arm1 = vectorOwner.positionToLocal(arrowArm1) @@ -512,6 +516,55 @@ function highlightMissingData(state) end end +-- Readies all cards in the main playarea (both player cards, treacheries and enemies) +function readyCards(player, clickType) + local playerColor = player.color + + -- when right-clicked + if clickType == "-2" then + printToColor("This will ready (rotate 90° closer to 0°) all cards in the main play area." .. + " Make sure to handle enemy engagement manually. To exclude a card from this (e.g. Handcuffs)," .. + " right-click it, select 'Tags' and add the tag 'DoNotReady' to it.", playerColor) + return + end + + local zone = guidReferenceApi.getObjectByOwnerAndType("Mythos", "PlayAreaZone") + if not zone then + broadcastToColor("Scripting zone couldn't be found.", playerColor, "Red") + return + end + + broadcastToAll("Readied cards in Play Area") + + local rot = self.getRotation() + for _, obj in ipairs(zone.getObjects()) do + if obj.type == "Card" and obj.locked == false and not (obj.getVar("do_not_ready") or obj.hasTag("DoNotReady")) then + local cardRotation = obj.getRotation() + local roundedRotY = round(cardRotation.y, 0) + local yRotDiff = roundedRotY - rot.y + + if yRotDiff < 0 then + yRotDiff = yRotDiff + 360 + end + + -- rotate cards to the next multiple of 90° towards 0° + local cardRotY = rot.y + if yRotDiff > 90 and yRotDiff <= 180 then + cardRotY = rot.y + 90 + elseif yRotDiff > 180 and yRotDiff < 270 then + cardRotY = rot.y + 270 + end + + -- highlighting for readied cards + if cardRotY == rot.y and roundedRotY ~= rot.y then + obj.highlightOn({ r = 0.8, g = 1, b = 0.05 }, 2) + end + + obj.setRotation(cardRotation:setAt("y", cardRotY)) + end + end +end + --------------------------------------------------------- -- functions for outside calls --------------------------------------------------------- diff --git a/src/core/PlayAreaApi.ttslua b/src/core/PlayAreaApi.ttslua index 47bba879..e7721106 100644 --- a/src/core/PlayAreaApi.ttslua +++ b/src/core/PlayAreaApi.ttslua @@ -105,7 +105,12 @@ do -- Updates the surface of the play area PlayAreaApi.updateSurface = function(url) - return getPlayArea().call("updateSurface", url) + getPlayArea().call("updateSurface", url) + end + + -- Readies cards in the PlayArea + PlayAreaApi.readyCards = function() + getPlayArea().call("readyCards") end -- Returns a deep copy of the currently tracked locations diff --git a/src/playermat/Playermat.ttslua b/src/playermat/Playermat.ttslua index 94f8cf60..86ccdb11 100644 --- a/src/playermat/Playermat.ttslua +++ b/src/playermat/Playermat.ttslua @@ -350,23 +350,22 @@ function doUpkeep(_, clickedByColor, isRightClick) elseif obj.type == "Card" and not inArea(self.positionToLocal(obj.getPosition()), INVESTIGATOR_AREA) then local cardMetadata = JSON.decode(obj.getGMNotes()) or {} if not (obj.getVar("do_not_ready") or obj.hasTag("DoNotReady")) then - local cardRotation = round(obj.getRotation().y, 0) - rot.y - local yRotDiff = 0 + local cardRotation = obj.getRotation() + local yRotDiff = round(cardRotation.y, 0) - rot.y - if cardRotation < 0 then - cardRotation = cardRotation + 360 + if yRotDiff < 0 then + yRotDiff = yRotDiff + 360 end -- rotate cards to the next multiple of 90° towards 0° - if cardRotation > 90 and cardRotation <= 180 then - yRotDiff = 90 - elseif cardRotation < 270 and cardRotation > 180 then - yRotDiff = 270 + local cardRotY = rot.y + if yRotDiff > 90 and yRotDiff <= 180 then + cardRotY = rot.y + 90 + elseif yRotDiff > 180 and yRotDiff < 270 then + cardRotY = rot.y + 270 end - -- set correct rotation for face-down cards - rot.z = obj.is_face_down and 180 or 0 - obj.setRotation({ rot.x, rot.y + yRotDiff, rot.z }) + obj.setRotation(cardRotation:setAt("y", cardRotY)) end -- detect Forced Learning to handle card drawing accordingly diff --git a/xml/MythosArea.xml b/xml/MythosArea.xml index 356838c1..15ac038a 100644 --- a/xml/MythosArea.xml +++ b/xml/MythosArea.xml @@ -1,4 +1,4 @@ - @@ -7,5 +7,6 @@ textColors="#ffffff|#88e3cf|#4f8478" font="font_teutonic-arkham" fontSize="62" + textAlignment="MiddleCenter" onClick="reshuffleEncounterDeck">Reshuffle ➡ diff --git a/xml/PlayArea.xml b/xml/PlayArea.xml new file mode 100644 index 00000000..6fd686f0 --- /dev/null +++ b/xml/PlayArea.xml @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file