diff --git a/modsettings/CustomUIAssets.json b/modsettings/CustomUIAssets.json index 37fe7bd3..f07b8088 100644 --- a/modsettings/CustomUIAssets.json +++ b/modsettings/CustomUIAssets.json @@ -19,6 +19,31 @@ "Type": 0, "URL": "http://cloud-3.steamusercontent.com/ugc/2038486957000850722/37F0D4848BA08788F79DB2D3FB6D11429CB1F861/" }, + { + "Name": "Playermat-Guardian-Cache", + "Type": 0, + "URL": "http://cloud-3.steamusercontent.com/ugc/2444972799638881117/169F4520A94FB186B54E0F2BF4BAC809844C923E/" + }, + { + "Name": "Playermat-Mystic-Cache", + "Type": 0, + "URL": "http://cloud-3.steamusercontent.com/ugc/2444972799638880413/B59966123EA41649EDCBD614167E590C8C105582/" + }, + { + "Name": "Playermat-Rogue-Cache", + "Type": 0, + "URL": "http://cloud-3.steamusercontent.com/ugc/2444972799638880905/CFC02BF5A6140B9B4B92312AD6DC74D8DD61180B/" + }, + { + "Name": "Playermat-Seeker-Cache", + "Type": 0, + "URL": "http://cloud-3.steamusercontent.com/ugc/2444972799638880905/CFC02BF5A6140B9B4B92312AD6DC74D8DD61180B/" + }, + { + "Name": "Playermat-Survivor-Cache", + "Type": 0, + "URL": "http://cloud-3.steamusercontent.com/ugc/2444972799638880687/EEDF8F8BC3266069FECB09775845BE2501310C17/" + }, { "Name": "NavigationOverlayIcon", "Type": 0, diff --git a/objects/LuaScriptState.luascriptstate b/objects/LuaScriptState.luascriptstate index 5fac6212..f8e751f1 100644 --- a/objects/LuaScriptState.luascriptstate +++ b/objects/LuaScriptState.luascriptstate @@ -1 +1 @@ -{"acknowledgedUpgradeVersions":[],"chaosTokensGUID":[],"optionPanel":{"cardLanguage":"en","changePlayAreaImage":false,"playAreaConnectionColor":{"a":1,"b":0.4,"g":0.4,"r":0.4},"playAreaConnections":true,"playAreaSnapTags":true,"showAttachmentHelper":false,"showCleanUpHelper":false,"showCYOA":false,"showDisplacementTool":false,"showDrawButton":false,"showHandHelper":false,"showSearchAssistant":false,"showTitleSplash":true,"useClueClickers":false,"useResourceCounters":"disabled","useSnapTags":true}} +{"acknowledgedUpgradeVersions":[],"chaosTokensGUID":[],"optionPanel":{"cardLanguage":"en","changePlayAreaImage":false,"playAreaConnectionColor":{"a":1,"b":0.4,"g":0.4,"r":0.4},"playAreaConnections":true,"playAreaSnapTags":true,"showAttachmentHelper":false,"showCleanUpHelper":false,"showCYOA":false,"showDisplacementTool":false,"showDrawButton":false,"showHandHelper":false,"showSearchAssistant":false,"showTitleSplash":true,"useClassTexture":true,"useClueClickers":false,"useResourceCounters":"disabled","useSnapTags":true}} diff --git a/objects/Playermat1White.8b081b.luascriptstate b/objects/Playermat1White.8b081b.luascriptstate index ec466f0b..37f3fb4a 100644 --- a/objects/Playermat1White.8b081b.luascriptstate +++ b/objects/Playermat1White.8b081b.luascriptstate @@ -1 +1 @@ -{"activeInvestigatorClass":"Neutral","activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"White","slotData":["any","any","any","Tarot","Hand (left)","Hand (right)","Ally","any","any","any","Accessory","Arcane","Arcane","Body"]} +{"activeInvestigatorClass":"Neutral","activeInvestigatorId":"00000","isClassTextureEnabled":true,"isDrawButtonVisible":false,"playerColor":"White","slotData":["any","any","any","Tarot","Hand (left)","Hand (right)","Ally","any","any","any","Accessory","Arcane","Arcane","Body"]} diff --git a/objects/Playermat2Orange.bd0ff4.luascriptstate b/objects/Playermat2Orange.bd0ff4.luascriptstate index c5d912d1..82227cf3 100644 --- a/objects/Playermat2Orange.bd0ff4.luascriptstate +++ b/objects/Playermat2Orange.bd0ff4.luascriptstate @@ -1 +1 @@ -{"activeInvestigatorClass":"Neutral","activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Orange","slotData":["any","any","any","Tarot","Hand (left)","Hand (right)","Ally","any","any","any","Accessory","Arcane","Arcane","Body"]} +{"activeInvestigatorClass":"Neutral","activeInvestigatorId":"00000","isClassTextureEnabled":true,"isDrawButtonVisible":false,"playerColor":"Orange","slotData":["any","any","any","Tarot","Hand (left)","Hand (right)","Ally","any","any","any","Accessory","Arcane","Arcane","Body"]} diff --git a/objects/Playermat3Green.383d8b.luascriptstate b/objects/Playermat3Green.383d8b.luascriptstate index 9cc6512e..3f44af1d 100644 --- a/objects/Playermat3Green.383d8b.luascriptstate +++ b/objects/Playermat3Green.383d8b.luascriptstate @@ -1 +1 @@ -{"activeInvestigatorClass":"Neutral","activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Green","slotData":["any","any","any","Tarot","Hand (left)","Hand (right)","Ally","any","any","any","Accessory","Arcane","Arcane","Body"]} +{"activeInvestigatorClass":"Neutral","activeInvestigatorId":"00000","isClassTextureEnabled":true,"isDrawButtonVisible":false,"playerColor":"Green","slotData":["any","any","any","Tarot","Hand (left)","Hand (right)","Ally","any","any","any","Accessory","Arcane","Arcane","Body"]} diff --git a/objects/Playermat4Red.0840d5.luascriptstate b/objects/Playermat4Red.0840d5.luascriptstate index 71a6f128..74f4e1f9 100644 --- a/objects/Playermat4Red.0840d5.luascriptstate +++ b/objects/Playermat4Red.0840d5.luascriptstate @@ -1 +1 @@ -{"activeInvestigatorClass":"Neutral","activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Red","slotData":["any","any","any","Tarot","Hand (left)","Hand (right)","Ally","any","any","any","Accessory","Arcane","Arcane","Body"]} +{"activeInvestigatorClass":"Neutral","activeInvestigatorId":"00000","isClassTextureEnabled":true,"isDrawButtonVisible":false,"playerColor":"Red","slotData":["any","any","any","Tarot","Hand (left)","Hand (right)","Ally","any","any","any","Accessory","Arcane","Arcane","Body"]} diff --git a/src/arkhamdb/ArkhamDb.ttslua b/src/arkhamdb/ArkhamDb.ttslua index 5ff08a63..f60d8e94 100644 --- a/src/arkhamdb/ArkhamDb.ttslua +++ b/src/arkhamdb/ArkhamDb.ttslua @@ -482,7 +482,6 @@ do ---@param uri table ---@param on_success fun(status, vararg): boolean, any ---@param on_error nil|fun(status, vararg): string - ---@vararg any ---@return Request function Request.start(uri, on_success, on_error, ...) local parameters = table.pack(...) @@ -497,7 +496,6 @@ do ---@param requests Request[] ---@param on_success fun(content: any, vararg: any) ---@param on_error fun(requests: Request, vararg: any)|nil - ---@vararg any function Request.with_all(requests, on_success, on_error, ...) local parameters = table.pack(...) diff --git a/src/core/DoomInPlayCounter.ttslua b/src/core/DoomInPlayCounter.ttslua index c97695e8..07029a75 100644 --- a/src/core/DoomInPlayCounter.ttslua +++ b/src/core/DoomInPlayCounter.ttslua @@ -1,10 +1,10 @@ local guidReferenceApi = require("core/GUIDReferenceApi") -local playermatApi = require("playermat/PlayermatApi") +local playermatApi = require("playermat/PlayermatApi") local ZONE, TRASH -local doomURL = "https://i.imgur.com/EoL7yaZ.png" -local IGNORE_TAG = "DoomCounter_ignore" -local TOTAL_PLAY_AREA = { +local doomURL = "https://i.imgur.com/EoL7yaZ.png" +local IGNORE_TAG = "DoomCounter_ignore" +local TOTAL_PLAY_AREA = { upperLeft = { x = -9, z = -35 @@ -67,14 +67,14 @@ end function removeDoom(options) if options.Playermats then local count = removeDoomFromList(playermatApi.searchAroundPlayermat("All")) - if count > 0 then + if count > 0 then broadcastToAll(count .. " doom removed from playermats.", "White") end end if options.Playarea then local count = removeDoomFromList(ZONE.getObjects()) - if count > 0 then + if count > 0 then broadcastToAll(count .. " doom removed from play area.", "White") end end @@ -96,7 +96,7 @@ end -- helper function to check if a position is inside an area function inArea(point, bounds) return (point.x < bounds.upperLeft.x - and point.x > bounds.lowerRight.x - and point.z > bounds.upperLeft.z - and point.z < bounds.lowerRight.z) + and point.x > bounds.lowerRight.x + and point.z > bounds.upperLeft.z + and point.z < bounds.lowerRight.z) end diff --git a/src/core/DownloadBox.ttslua b/src/core/DownloadBox.ttslua index 21957367..4f1c650a 100644 --- a/src/core/DownloadBox.ttslua +++ b/src/core/DownloadBox.ttslua @@ -18,14 +18,14 @@ function onLoad() if string.match(notes, "................") == "campaigns/return" then buttonParameters.position.z = 2 - -- official campaign boxes + -- official campaign boxes elseif string.match(notes, ".........") == "campaigns" or self.hasTag("LargeBox") then buttonParameters.position.z = 6 buttonParameters.height = 500 buttonParameters.width = 1700 buttonParameters.font_size = 350 - -- investigator boxes + -- investigator boxes elseif string.match(notes, ".............") == "investigators" then buttonParameters.position.z = 7 buttonParameters.height = 850 diff --git a/src/core/Global.ttslua b/src/core/Global.ttslua index 073d8487..5e7cbb9b 100644 --- a/src/core/Global.ttslua +++ b/src/core/Global.ttslua @@ -1433,11 +1433,15 @@ function applyOptionPanelChange(id, state) if id == "useSnapTags" then playermatApi.setLimitSnapsByType(state, "All") - -- option: Draw 1 button + -- option: Draw 1 button elseif id == "showDrawButton" then playermatApi.showDrawButton(state, "All") - -- option: Clickable clue counters + -- option: Use class texture + elseif id == "useClassTexture" then + playermatApi.useClassTexture(state, "All") + + -- option: Clickable clue counters elseif id == "useClueClickers" then playermatApi.clickableClues(state, "All") @@ -1445,40 +1449,40 @@ function applyOptionPanelChange(id, state) local counter = guidReferenceApi.getObjectByOwnerAndType("Mythos", "MasterClueCounter") counter.setVar("useClickableCounters", state) - -- option: Play area connection drawing + -- option: Play area connection drawing elseif id == "playAreaConnections" then playAreaApi.setConnectionDrawState(state) - -- option: Play area connection color + -- option: Play area connection color elseif id == "playAreaConnectionColor" then playAreaApi.setConnectionColor(state) UI.setAttribute(id, "color", "#" .. Color.new(state):toHex()) - -- option: Play area snap tags + -- option: Play area snap tags elseif id == "playAreaSnapTags" then playAreaApi.setLimitSnapsByType(state) - -- option: Show clean up helper + -- option: Show clean up helper elseif id == "showCleanUpHelper" then spawnOrRemoveHelper(state, "Clean Up Helper", { -66, 1.53, 46 }) - -- option: Show hand helper for each player + -- option: Show hand helper for each player elseif id == "showHandHelper" then spawnOrRemoveHelperForPlayermats("Hand Helper", state) - -- option: Show search assistant for each player + -- option: Show search assistant for each player elseif id == "showSearchAssistant" then spawnOrRemoveHelperForPlayermats("Search Assistant", state) - -- option: Show attachment helper + -- option: Show attachment helper elseif id == "showAttachmentHelper" then spawnOrRemoveHelper(state, "Attachment Helper", { -62, 1.4, 0 }) - -- option: Show CYOA campaign guides + -- option: Show CYOA campaign guides elseif id == "showCYOA" then spawnOrRemoveHelper(state, "CYOA Campaign Guides", { 39, 1.3, -20 }) - -- option: Show displacement tool + -- option: Show displacement tool elseif id == "showDisplacementTool" then spawnOrRemoveHelper(state, "Displacement Tool", { -57, 1.53, 46 }) end @@ -1580,6 +1584,7 @@ function onClick_defaultSettings() showHandHelper = false, showSearchAssistant = false, showTitleSplash = true, + useClassTexture = true, useClueClickers = false, useResourceCounters = "disabled", useSnapTags = true diff --git a/src/core/PlayArea.ttslua b/src/core/PlayArea.ttslua index 92f265ca..22447b3f 100644 --- a/src/core/PlayArea.ttslua +++ b/src/core/PlayArea.ttslua @@ -133,7 +133,7 @@ function onObjectPickUp(_, object) local metadata = JSON.decode(object.getGMNotes()) or {} if metadata.type == "Location" then -- onCollisionExit sometimes comes 1 frame after onObjectPickUp (rather than before it or in - -- the same frame). This causes a mismatch in the data between dragging the on-table, and + -- the same frame). This causes a mismatch in the data between dragging the on-table, and -- that one frame draws connectors on the card which then show up as shadows for snap points. -- Waiting ensures we always do thing in the expected Exit->PickUp order Wait.frames(function() @@ -240,7 +240,7 @@ end ---@param card tts__Object Card to (maybe) stop tracking function maybeUntrackLocation(card) -- Locked objects no longer collide (hence triggering an exit event) but are still in the play - -- area. If the object is now locked, don't remove it. + -- area. If the object is now locked, don't remove it. if locations[card.getGUID()] ~= nil and not card.locked then locations[card.getGUID()] = nil rebuildConnectionList() @@ -415,7 +415,7 @@ end ---@param target tts__Object Target card object to connect ---@param vectorOwner tts__Object The object which these lines will be set to. Used for relative --- 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 connector +---@param lines table List of vector line elements. Mutable, will be updated to add this connector function addOneWayVector(origin, target, vectorOwner, lines) -- Start with the BiDi then add the arrow lines to it addBidirectionalVector(origin, target, vectorOwner, lines) @@ -445,9 +445,9 @@ end -- Draws an arrowhead at the given position. ---@param arrowheadPos tts__Vector Centerpoint of the arrowhead to draw (NOT the tip of the arrow) ---@param originPos tts__Vector Origin point of the connection, used to position the arrow arms ----@param vectorOwner tts__Object The object which these lines will be set to. Used for relative +---@param vectorOwner tts__Object The object which these lines will be set to. Used for relative --- 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 +---@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) @@ -462,7 +462,7 @@ function addArrowLines(arrowheadPos, originPos, vectorOwner, lines) }) end --- count victory points on locations in play area +-- Count victory points from locations in play area ---@param highlightOff boolean True if highlighting should be enabled ---@return. Returns the total amount of VP found in the play area function countVP(highlightOff) @@ -488,14 +488,15 @@ function countVP(highlightOff) return totalVP end --- checks if a card has clues on it, returns true if clues are on it +-- Checks if a card has clues on it ---@param card tts__Object Card to check for clues +---@return boolean hasClues True if card has clues on it function cardHasClues(card) local searchResult = searchLib.onObject(card, "isClue") return #searchResult > 0 end --- highlights all locations in the play area without metadata +-- Highlights all locations in the play area without metadata ---@param state boolean True if highlighting should be enabled function highlightMissingData(state) for i, obj in pairs(missingData) do @@ -549,7 +550,7 @@ function shiftContents(playerColor, direction) Wait.time(drawBaseConnections, 0.1) end --- sets the image of the playarea +-- Sets the image of the playarea ---@param newURL string URL for the new surface image function updateSurface(newURL) local customInfo = self.getCustomObject() @@ -569,6 +570,7 @@ function updateSurface(newURL) guid = customDataHelper.getGUID() end + self.script_state = onSave() self.reload() if guid ~= nil then @@ -646,7 +648,7 @@ function round(num, numDecimalPlaces) return math.floor(num * mult + 0.5) / mult end --- rebuilds local snap points (could be useful in the future again) +-- Rebuilds local snap points (could be useful in the future again) function buildSnaps() local upperleft = { x = 1.53, z = -1.09 } local lowerright = { x = -1.53, z = 1.55 } diff --git a/src/core/PlayAreaSelector.ttslua b/src/core/PlayAreaSelector.ttslua index e5431e1a..fe32286f 100644 --- a/src/core/PlayAreaSelector.ttslua +++ b/src/core/PlayAreaSelector.ttslua @@ -192,7 +192,7 @@ end function getPlainName(str) -- remove prefix type 1 str = str:gsub("%w+%-%w%s%-%s", "") -- matches "II-B - Thousand Shapes of Horror 1" - + -- remove prefix type 2 str = str:gsub("%w+%-%w%s", "") -- matches "59-Z Congress of Keys 1" diff --git a/src/playermat/Playermat.ttslua b/src/playermat/Playermat.ttslua index 6f2db69c..653308de 100644 --- a/src/playermat/Playermat.ttslua +++ b/src/playermat/Playermat.ttslua @@ -60,6 +60,16 @@ local buttonParameters = { font_size = 180 } +-- table of texture URLs +local nameToTexture = { + Guardian = "http://cloud-3.steamusercontent.com/ugc/2444972799638881117/169F4520A94FB186B54E0F2BF4BAC809844C923E/", + Mystic = "http://cloud-3.steamusercontent.com/ugc/2444972799638880413/B59966123EA41649EDCBD614167E590C8C105582/", + Neutral = "http://cloud-3.steamusercontent.com/ugc/2462982115659543571/5D778EA4BC682DAE97E8F59A991BCF8CB3979B04/", + Rogue = "http://cloud-3.steamusercontent.com/ugc/2444972799638880905/CFC02BF5A6140B9B4B92312AD6DC74D8DD61180B/", + Seeker = "http://cloud-3.steamusercontent.com/ugc/2444972799638880905/CFC02BF5A6140B9B4B92312AD6DC74D8DD61180B/", + Survivor = "http://cloud-3.steamusercontent.com/ugc/2444972799638880687/EEDF8F8BC3266069FECB09775845BE2501310C17/" +} + -- translation table for slot names to characters for special font local slotNameToChar = { ["any"] = "", @@ -86,12 +96,11 @@ local defaultSlotData = { -- global variables for access activeInvestigatorClass = "Neutral" activeInvestigatorId = "00000" - -local isDrawButtonVisible = false - --- global variable to report "Dream-Enhancing Serum" status hasDES = false +local isClassTextureEnabled = true +local isDrawButtonVisible = false + -- table of type-object reference pairs of all owned objects local ownedObjects = {} local matColor = self.getMemo() @@ -100,6 +109,7 @@ function onSave() return JSON.encode({ activeInvestigatorClass = activeInvestigatorClass, activeInvestigatorId = activeInvestigatorId, + isClassTextureEnabled = isClassTextureEnabled, isDrawButtonVisible = isDrawButtonVisible, playerColor = playerColor, slotData = slotData @@ -111,6 +121,7 @@ function onLoad(savedData) local loadedData = JSON.decode(savedData) activeInvestigatorClass = loadedData.activeInvestigatorClass activeInvestigatorId = loadedData.activeInvestigatorId + isClassTextureEnabled = loadedData.isClassTextureEnabled isDrawButtonVisible = loadedData.isDrawButtonVisible playerColor = loadedData.playerColor slotData = loadedData.slotData @@ -879,10 +890,12 @@ function maybeUpdateActiveInvestigator(card) notes.combatIcons, notes.agilityIcons }) + updateTexture() elseif activeInvestigatorId ~= "00000" then activeInvestigatorClass = "Neutral" activeInvestigatorId = "00000" ownedObjects.InvestigatorSkillTracker.call("updateStats", { 1, 1, 1, 1 }) + updateTexture() else return end @@ -936,7 +949,7 @@ function maybeUpdateActiveInvestigator(card) count[type] = count[type] + 1 if count[type] > 2 then - print("More than two extra tokens of the same type are not supported.") + printToColor("More than two extra tokens of the same type are not supported.", playerColor) else local localSpawnPos = tokenSpawnPos[type][count[type]] local globalSpawnPos = self.positionToWorld(localSpawnPos):add(Vector(0, 0.2, 0)) @@ -950,6 +963,34 @@ function maybeUpdateActiveInvestigator(card) end end +-- updates the texture of the playermat +---@param overrideName? string Force a specific texture +function updateTexture(overrideName) + local name = "Neutral" + + -- use class specific texture if enabled + if isClassTextureEnabled then + name = activeInvestigatorClass + end + + -- get new texture URL + local newUrl = nameToTexture[name] + + -- override name if valid + if nameToTexture[overrideName] then + newUrl = nameToTexture[overrideName] + end + + -- apply texture + local customInfo = self.getCustomObject() + if customInfo.image ~= newUrl then + self.script_state = onSave() + customInfo.image = newUrl + self.setCustomObject(customInfo) + self.reload() + end +end + --------------------------------------------------------- -- manipulation of owned objects --------------------------------------------------------- @@ -1083,6 +1124,14 @@ function clickableClues(showCounter) end end +-- Toggles the use of class textures +---@param state boolean Whether the class texture should be used or not +function useClassTexture(state) + if state == isClassTextureEnabled then return end + isClassTextureEnabled = state + updateTexture() +end + -- removes all clues (moving tokens to the trash and setting counters to 0) function removeClues() ownedObjects.ClueCounter.call("removeAllClues", ownedObjects.Trash) diff --git a/src/playermat/PlayermatApi.ttslua b/src/playermat/PlayermatApi.ttslua index 284a2f36..aab81bb7 100644 --- a/src/playermat/PlayermatApi.ttslua +++ b/src/playermat/PlayermatApi.ttslua @@ -225,6 +225,15 @@ do end end + -- Toggles the use of class textures for the requested playermat + ---@param state boolean Whether the class texture should be used or not + ---@param matColor string Color of the playermat - White, Orange, Green, Red or All + PlayermatApi.useClassTexture = function(state, matColor) + for _, mat in pairs(getMatForColor(matColor)) do + mat.call("useClassTexture", state) + end + end + -- Removes all clues (to the trash for tokens and counters set to 0) for the requested playermat ---@param matColor string Color of the playermat - White, Orange, Green, Red or All PlayermatApi.removeClues = function(matColor) diff --git a/xml/Global/OptionPanel.xml b/xml/Global/OptionPanel.xml index d6b0b6dc..ab27fd34 100644 --- a/xml/Global/OptionPanel.xml +++ b/xml/Global/OptionPanel.xml @@ -273,6 +273,21 @@ + + + + + Use class-specific texture + + + +