diff --git a/config.json b/config.json index 30b12fd2..8e125836 100644 --- a/config.json +++ b/config.json @@ -191,7 +191,8 @@ "VictoryDisplay.6ccd6d", "CampaignOverview.e03c01", "OptionPanelSource.830bd0", - "SoundCube.3c988f" + "SoundCube.3c988f", + "GameKeyHandler.fce69c" ], "PlayArea": 1, "PlayerCounts": [ diff --git a/objects/GameKeyHandler.fce69c.json b/objects/GameKeyHandler.fce69c.json new file mode 100644 index 00000000..c2ba5ca2 --- /dev/null +++ b/objects/GameKeyHandler.fce69c.json @@ -0,0 +1,45 @@ +{ + "AltLookAngle": { + "x": 0, + "y": 0, + "z": 0 + }, + "Autoraise": true, + "ColorDiffuse": { + "b": 0.66176, + "g": 0.66176, + "r": 0.66176 + }, + "Description": "This object contains \"Game Keys\" that can be assigned via Options --\u003e Game Keys.", + "DragSelectable": true, + "GMNotes": "", + "GUID": "fce69c", + "Grid": true, + "GridProjection": false, + "Hands": false, + "HideWhenFaceDown": false, + "IgnoreFoW": false, + "LayoutGroupSortIndex": 0, + "Locked": false, + "LuaScript": "require(\"core/GameKeyHandler\")", + "LuaScriptState": "", + "MeasureMovement": false, + "Name": "go_game_piece_white", + "Nickname": "Game Key Handler", + "Snap": true, + "Sticky": true, + "Tooltip": true, + "Transform": { + "posX": 78, + "posY": 1.328, + "posZ": -10, + "rotX": 0, + "rotY": 0, + "rotZ": 0, + "scaleX": 1, + "scaleY": 1, + "scaleZ": 1 + }, + "Value": 0, + "XmlUI": "" +} \ No newline at end of file diff --git a/src/chaosbag/BlessCurseManager.ttslua b/src/chaosbag/BlessCurseManager.ttslua index a11910a6..b07b3381 100644 --- a/src/chaosbag/BlessCurseManager.ttslua +++ b/src/chaosbag/BlessCurseManager.ttslua @@ -63,10 +63,6 @@ function onLoad(saved_state) self.addContextMenuItem("Remove all", doRemove) self.addContextMenuItem("Reset", doReset) - -- hotkeys - addHotkey("Bless Curse Status", printStatus, false) - addHotkey("Wendy's Menu", addMenuOptions, false) - -- initializing tables numInPlay = { Bless = 0, Curse = 0 } tokensTaken = { Bless = {}, Curse = {} } @@ -347,7 +343,9 @@ end -- Wendy Menu (context menu for cards on hotkey press) --------------------------------------------------------- -function addMenuOptions(playerColor, hoveredObject) +function addMenuOptions(parameters) + local playerColor = parameters.playerColor + local hoveredObject = parameters.hoveredObject if hoveredObject == nil or hoveredObject.getVar("MENU_ADDED") == true then return end if hoveredObject.tag ~= "Card" then broadcastToColor("Right-click seal options can only be added to cards", playerColor) diff --git a/src/chaosbag/BlessCurseManagerApi.ttslua b/src/chaosbag/BlessCurseManagerApi.ttslua index 71c9a2e4..3e35b801 100644 --- a/src/chaosbag/BlessCurseManagerApi.ttslua +++ b/src/chaosbag/BlessCurseManagerApi.ttslua @@ -20,5 +20,17 @@ do getObjectFromGUID(MANAGER_GUID).call("releasedToken", { type = type, guid = guid }) end + -- broadcasts the current status for bless/curse tokens + ---@param playerColor String Color of the player to show the broadcast to + BlessCurseManagerApi.broadcastStatus = function(playerColor) + getObjectFromGUID(MANAGER_GUID).call("broadcastStatus", playerColor) + end + + -- adds Wendy's menu to the hovered card (allows sealing of tokens) + ---@param color String Color of the player to show the broadcast to + BlessCurseManagerApi.addWendysMenu = function(playerColor, hoveredObject) + getObjectFromGUID(MANAGER_GUID).call("addMenuOptions", { playerColor = playerColor, hoveredObject = hoveredObject }) + end + return BlessCurseManagerApi end diff --git a/src/core/DoomCounter.ttslua b/src/core/DoomCounter.ttslua index 9fa128c5..9d7efd2b 100644 --- a/src/core/DoomCounter.ttslua +++ b/src/core/DoomCounter.ttslua @@ -44,6 +44,15 @@ function addOrSubtract(_, _, isRightClick) end end +-- adds the provided number to the current count +function addVal(number) + number = tonumber(number) or 0 + val = val + number + self.editButton({ index = 0, label = tostring(val) }) + printToAll("Doom on agenda set to: " .. val) +end + +-- sets the current count to the provided number function updateVal(number) val = number or 0 self.editButton({ index = 0, label = tostring(val) }) diff --git a/src/core/GameKeyHandler.ttslua b/src/core/GameKeyHandler.ttslua new file mode 100644 index 00000000..94513042 --- /dev/null +++ b/src/core/GameKeyHandler.ttslua @@ -0,0 +1,59 @@ +local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi") +local playmatApi = require("playermat/PlaymatApi") + +function onLoad() + addHotkey("Upkeep", triggerUpkeep) + addHotkey("Upkeep (Multi-handed)", triggerUpkeepMultihanded) + addHotkey("Add Doom to Agenda", addDoomToAgenda) + addHotkey("Move card to Victory Display", moveCardToVictoryDisplay) + addHotkey("Bless/Curse Status", showBlessCurseStatus) + addHotkey("Wendy's Menu", addWendysMenu) +end + +-- triggers the "Upkeep" function of the calling player's playmat +function triggerUpkeep(playerColor) + if playerColor == "Black" then + broadcastToColor("Triggering 'Upkeep (Multihanded)' instead", playerColor, "Yellow") + triggerUpkeepMultihanded(playerColor) + return + end + local matColor = playmatApi.getMatColor(playerColor) + playmatApi.doUpkeepFromHotkey(matColor, playerColor) +end + +-- triggers the "Upkeep" function of the calling player's playmat AND +-- for all playmats that don't have a seated player, but a investigator card +function triggerUpkeepMultihanded(playerColor) + if playerColor ~= "Black" then + triggerUpkeep(playerColor) + end + local colors = Player.getAvailableColors() + for _, handColor in ipairs(colors) do + local matColor = playmatApi.getMatColor(handColor) + if playmatApi.returnInvestigatorId(matColor) ~= "00000" and Player[handColor].seated == false then + playmatApi.doUpkeepFromHotkey(matColor, playerColor) + end + end +end + +-- adds 1 doom to the agenda +function addDoomToAgenda() + getObjectFromGUID("85c4c6").call("addVal", 1) +end + +-- moves the hovered card to the victory display +function moveCardToVictoryDisplay(playerColor, hoveredObject) + -- check if the provided object is a card + if hoveredObject == nil or hoveredObject.tag ~= "Card" then return end + getObjectFromGUID("6ccd6d").call("placeCard", hoveredObject) +end + +-- broadcasts the bless/curse status to the calling player +function showBlessCurseStatus(playerColor) + blessCurseManagerApi.broadcastStatus(playerColor) +end + +-- adds Wendy's menu to the hovered card +function addWendysMenu(playerColor, hoveredObject) + blessCurseManagerApi.addWendysMenu(playerColor, hoveredObject) +end diff --git a/src/core/VictoryDisplay.ttslua b/src/core/VictoryDisplay.ttslua index 8461b85f..a274f929 100644 --- a/src/core/VictoryDisplay.ttslua +++ b/src/core/VictoryDisplay.ttslua @@ -246,6 +246,40 @@ function highlightCountedVP() highlightCounted = not highlightCounted end +-- places the provided card in the first empty spot +function placeCard(card) + -- check snap point states + 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 = {} + for i, snap in ipairs(snaps) do + positions[i] = self.positionToWorld(snap.position) + local hits = checkSnapPointState(positions[i]) + + -- first hit is self, additional hits must be cards / decks + if #hits > 1 then + fullSlots[i] = true + end + end + + -- place the card + local name = card.getName() or "Unnamed card" + for i = 1, 10 do + if fullSlots[i] ~= true then + card.setPositionSmooth(positions[i], false, true) + broadcastToAll("Victory Display: " .. name .. " placed into slot " .. i .. ".", "Green") + return + end + end + + broadcastToAll("Victory Display is full! " .. name .. " placed into slot 1.", "Orange") + card.setPositionSmooth(positions[1], false, true) +end + --------------------------------------------------------- -- utility functions --------------------------------------------------------- @@ -261,6 +295,16 @@ function searchOnObj(obj) }) end +function checkSnapPointState(pos) + return Physics.cast({ + direction = { 0, 1, 0 }, + max_distance = 0.1, + type = 3, + size = { 0.1, 0.1, 0.1 }, + origin = pos + }) +end + -- search a table for a value, return true if found (else returns false) function tableContains(table, value) for _, v in ipairs(table) do diff --git a/src/playermat/Playmat.ttslua b/src/playermat/Playmat.ttslua index 57ad6d0d..b1b1d513 100644 --- a/src/playermat/Playmat.ttslua +++ b/src/playermat/Playmat.ttslua @@ -223,6 +223,11 @@ end -- Upkeep button --------------------------------------------------------- +-- calls the Upkeep function with correct parameter +function doUpkeepFromHotkey(color) + doUpkeep(_, color) +end + function doUpkeep(_, clickedByColor, isRightClick) -- right-click allow color changing if isRightClick then diff --git a/src/playermat/PlaymatApi.ttslua b/src/playermat/PlaymatApi.ttslua index d8975615..1a20bb77 100644 --- a/src/playermat/PlaymatApi.ttslua +++ b/src/playermat/PlaymatApi.ttslua @@ -48,6 +48,17 @@ do return mat.getVar("playerColor") end + -- Returns the color of the playermat that owns the playercolor's hand + ---@param handColor String Color of the playermat + PlaymatApi.getMatColor = function(handColor) + local matColors = {"White", "Orange", "Green", "Red"} + for i, mat in ipairs(internal.getMatForColor("All")) do + local color = mat.getVar("playerColor") + if color == handColor then return matColors[i] end + end + return "NOT_FOUND" + 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) @@ -85,6 +96,21 @@ do return mat.getRotation() end + -- Triggers the Upkeep for the requested playmat + ---@param matColor String Color of the playermat + ---@param playerColor String Color of the calling player (for messages) + PlaymatApi.doUpkeepFromHotkey = function(matColor, playerColor) + local mat = getObjectFromGUID(MAT_IDS[matColor]) + return mat.call("doUpkeepFromHotkey", playerColor) + end + + -- Returns the active investigator id + ---@param matColor String Color of the playermat + PlaymatApi.returnInvestigatorId = function(matColor) + local mat = getObjectFromGUID(MAT_IDS[matColor]) + return mat.getVar("activeInvestigatorId") + end + -- Sets the requested playermat's snap points to limit snapping to matching card types or not. If -- matchTypes is true, the main card slot snap points will only snap assets, while the -- investigator area point will only snap Investigators. If matchTypes is false, snap points will