Merge branch 'main' into scroll-of-secrets

This commit is contained in:
Chr1Z93 2024-06-27 02:21:09 +02:00
commit 2d202bd513
51 changed files with 985 additions and 1194 deletions

View File

@ -3,6 +3,7 @@
"ComponentTags_path": "ComponentTags.json", "ComponentTags_path": "ComponentTags.json",
"CustomUIAssets_path": "CustomUIAssets.json", "CustomUIAssets_path": "CustomUIAssets.json",
"DecalPallet_path": "DecalPallet.json", "DecalPallet_path": "DecalPallet.json",
"Decals": [],
"GameComplexity": "", "GameComplexity": "",
"GameMode": "Arkham Horror LCG - Super Complete Edition", "GameMode": "Arkham Horror LCG - Super Complete Edition",
"GameType": "", "GameType": "",
@ -140,7 +141,7 @@
"ArkhamDBDeckImporter.a28140", "ArkhamDBDeckImporter.a28140",
"Configuration.03804b", "Configuration.03804b",
"DrawingTool.280086", "DrawingTool.280086",
"PlaymatImageSwapper.b7b45b", "PlayAreaImageSwapper.b7b45b",
"AllPlayerCards.15bb07", "AllPlayerCards.15bb07",
"InvestigatorSkillTracker.af7ed7", "InvestigatorSkillTracker.af7ed7",
"InvestigatorSkillTracker.e598c2", "InvestigatorSkillTracker.e598c2",

View File

@ -22,7 +22,7 @@
"ImageURL": "https://i.imgur.com/SBE8GR5.png", "ImageURL": "https://i.imgur.com/SBE8GR5.png",
"WidthScale": 0 "WidthScale": 0
}, },
"Description": "Only tracks tokens that actually hit the playmat.\n\nAll credit goes to TadGH!", "Description": "",
"DragSelectable": true, "DragSelectable": true,
"GMNotes": "", "GMNotes": "",
"GUID": "766620", "GUID": "766620",

View File

@ -1,188 +1,172 @@
tableHeightOffset =-9 tableHeightOffset = -9
function onSave() function onSave()
saved_data = JSON.encode({tid=tableImageData, cd=checkData}) return JSON.encode({ tid = tableImageData, cd = checkData })
--saved_data = ""
return saved_data
end end
function onload(saved_data) function onload(saved_data)
--Loads the tracking for if the game has started yet if saved_data ~= "" then
if saved_data ~= "" then local loaded_data = JSON.decode(saved_data)
local loaded_data = JSON.decode(saved_data) tableImageData = loaded_data.tid
tableImageData = loaded_data.tid checkData = loaded_data.cd
checkData = loaded_data.cd else
else tableImageData = {}
tableImageData = {} checkData = { move = false, scale = false }
checkData = {move=false, scale=false} end
end
--Disables interactable status of objects with GUID in list --Disables interactable status of objects with GUID in list
for _, guid in ipairs(ref_noninteractable) do for _, guid in ipairs(ref_noninteractable) do
local obj = getObjectFromGUID(guid) local obj = getObjectFromGUID(guid)
if obj then obj.interactable = false end if obj then obj.interactable = false end
end end
--Establish references to table parts --Establish references to table parts
obj_leg1 = getObjectFromGUID("afc863") obj_leg1 = getObjectFromGUID("afc863")
obj_leg2 = getObjectFromGUID("c8edca") obj_leg2 = getObjectFromGUID("c8edca")
obj_leg3 = getObjectFromGUID("393bf7") obj_leg3 = getObjectFromGUID("393bf7")
obj_leg4 = getObjectFromGUID("12c65e") obj_leg4 = getObjectFromGUID("12c65e")
obj_surface = getObjectFromGUID("4ee1f2") obj_surface = getObjectFromGUID("4ee1f2")
obj_side_top = getObjectFromGUID("35b95f") obj_side_top = getObjectFromGUID("35b95f")
obj_side_bot = getObjectFromGUID("f938a2") obj_side_bot = getObjectFromGUID("f938a2")
obj_side_lef = getObjectFromGUID("9f95fd") obj_side_lef = getObjectFromGUID("9f95fd")
obj_side_rig = getObjectFromGUID("5af8f2") obj_side_rig = getObjectFromGUID("5af8f2")
controlActive = true controlActive = true
createOpenCloseButton() createOpenCloseButton()
end end
--Activation/deactivation of control panel --Activation/deactivation of control panel
--Activated by clicking on --Activated by clicking on
function click_toggleControl(_, color) function click_toggleControl(_, color)
if permissionCheck(color) then if permissionCheck(color) then
if not controlActive then if not controlActive then
--Activate control panel --Activate control panel
controlActive = true controlActive = true
self.clearButtons() self.clearButtons()
createOpenCloseButton() createOpenCloseButton()
createSurfaceInput() createSurfaceInput()
createSurfaceButtons() createSurfaceButtons()
createScaleInput() createScaleInput()
createScaleButtons() createScaleButtons()
else else
--Deactivate control panel --Deactivate control panel
controlActive = false controlActive = false
self.clearButtons() self.clearButtons()
self.clearInputs() self.clearInputs()
createOpenCloseButton() createOpenCloseButton()
end
end end
end
end end
--Table surface control --Table surface control
--Changes table surface --Changes table surface
function click_applySurface(_, color) function click_applySurface(_, color)
if permissionCheck(color) then if permissionCheck(color) then
updateSurface() updateSurface()
broadcastToAll("New Table Image Applied", {0.2,0.9,0.2}) broadcastToAll("New Table Image Applied", { 0.2, 0.9, 0.2 })
end end
end end
--Saves table surface --Saves table surface
function click_saveSurface(_, color) function click_saveSurface(_, color)
if permissionCheck(color) then if permissionCheck(color) then
local nickname = self.getInputs()[1].value local nickname = self.getInputs()[1].value
local url = self.getInputs()[2].value local url = self.getInputs()[2].value
if nickname == "" then if nickname == "" then
--No nickname --No nickname
broadcastToAll("Please supply a nickname for this save.", {0.9,0.2,0.2}) broadcastToAll("Please supply a nickname for this save.", { 0.9, 0.2, 0.2 })
else else
--Nickname exists --Nickname exists
if findInImageDataIndex(url, nickname) == nil then if findInImageDataIndex(url, nickname) == nil then
--Save doesn't exist already --Save doesn't exist already
table.insert(tableImageData, {url=url, name=nickname}) table.insert(tableImageData, { url = url, name = nickname })
broadcastToAll("Image URL saved to memory.", {0.2,0.9,0.2}) broadcastToAll("Image URL saved to memory.", { 0.2, 0.9, 0.2 })
--Refresh buttons --Refresh buttons
self.clearButtons()
createOpenCloseButton()
createSurfaceButtons()
createScaleButtons()
else
--Save exists already
broadcastToAll("Memory already contains a save with this Name or URL. Delete it first.", {0.9,0.2,0.2})
end
end
end
end
--Loads table surface
function click_loadMemory(_, color, index)
if permissionCheck(color) then
self.editInput({index=0, value=tableImageData[index].name})
self.editInput({index=1, value=tableImageData[index].url})
updateSurface()
broadcastToAll("Table Image Loaded", {0.2,0.9,0.2})
end
end
--Deletes table surface
function click_deleteMemory(_, color, index)
if permissionCheck(color) then
table.remove(tableImageData, index)
self.clearButtons() self.clearButtons()
createOpenCloseButton() createOpenCloseButton()
createSurfaceButtons() createSurfaceButtons()
createScaleButtons() createScaleButtons()
broadcastToAll("Element Removed from Memory", {0.2,0.9,0.2}) else
--Save exists already
broadcastToAll("Memory already contains a save with this Name or URL. Delete it first.", { 0.9, 0.2, 0.2 })
end
end end
end
end
--Loads table surface
function click_loadMemory(_, color, index)
if permissionCheck(color) then
self.editInput({ index = 0, value = tableImageData[index].name })
self.editInput({ index = 1, value = tableImageData[index].url })
updateSurface()
broadcastToAll("Table Image Loaded", { 0.2, 0.9, 0.2 })
end
end
--Deletes table surface
function click_deleteMemory(_, color, index)
if permissionCheck(color) then
table.remove(tableImageData, index)
self.clearButtons()
createOpenCloseButton()
createSurfaceButtons()
createScaleButtons()
broadcastToAll("Element Removed from Memory", { 0.2, 0.9, 0.2 })
end
end end
--Updates surface from the values in the input field --Updates surface from the values in the input field
function updateSurface() function updateSurface()
local customInfo = obj_surface.getCustomObject() local customInfo = obj_surface.getCustomObject()
customInfo.diffuse = self.getInputs()[2].value customInfo.diffuse = self.getInputs()[2].value
obj_surface.setCustomObject(customInfo) obj_surface.setCustomObject(customInfo)
obj_surface = obj_surface.reload() obj_surface = obj_surface.reload()
end end
--Table Scale control --Table Scale control
--Applies Scale to table pieces --Applies Scale to table pieces
function click_applyScale(_, color) function click_applyScale(_, color)
if permissionCheck(color) then if permissionCheck(color) then
local newWidth = tonumber(self.getInputs()[3].value) local newWidth = tonumber(self.getInputs()[3].value)
local newDepth = tonumber(self.getInputs()[4].value) local newDepth = tonumber(self.getInputs()[4].value)
if type(newWidth) ~= "number" then if type(newWidth) ~= "number" then
broadcastToAll("Invalid Width", {0.9,0.2,0.2}) broadcastToAll("Invalid Width", { 0.9, 0.2, 0.2 })
return return
elseif type(newDepth) ~= "number" then elseif type(newDepth) ~= "number" then
broadcastToAll("Invalid Depth", {0.9,0.2,0.2}) broadcastToAll("Invalid Depth", { 0.9, 0.2, 0.2 })
return return
elseif newWidth<0.1 or newDepth<0.1 then elseif newWidth < 0.1 or newDepth < 0.1 then
broadcastToAll("Scale cannot go below 0.1", {0.9,0.2,0.2}) broadcastToAll("Scale cannot go below 0.1", { 0.9, 0.2, 0.2 })
return return
elseif newWidth>12 or newDepth>12 then elseif newWidth > 12 or newDepth > 12 then
broadcastToAll("Scale should not go over 12 (world size limitation)", {0.9,0.2,0.2}) broadcastToAll("Scale should not go over 12 (world size limitation)", { 0.9, 0.2, 0.2 })
return return
else else
changeTableScale(math.abs(newWidth), math.abs(newDepth)) changeTableScale(math.abs(newWidth), math.abs(newDepth))
broadcastToAll("Scale applied.", {0.2,0.9,0.2}) broadcastToAll("Scale applied.", { 0.2, 0.9, 0.2 })
end
end end
end
end end
--Checks/unchecks move box for hands --Checks/unchecks move box for hands
function click_checkMove(_, color) function click_checkMove(_, color)
if permissionCheck(color) then if permissionCheck(color) then
local find_func = function(o) return o.click_function=="click_checkMove" end local find_func = function(o) return o.click_function == "click_checkMove" end
if checkData.move == true then if checkData.move == true then
checkData.move = false checkData.move = false
local buttonEntry = findButton(self, find_func) local buttonEntry = findButton(self, find_func)
self.editButton({index=buttonEntry.index, label=""}) self.editButton({ index = buttonEntry.index, label = "" })
else else
checkData.move = true checkData.move = true
local buttonEntry = findButton(self, find_func) local buttonEntry = findButton(self, find_func)
self.editButton({index=buttonEntry.index, label=string.char(10008)}) self.editButton({ index = buttonEntry.index, label = string.char(10008) })
end
end end
end
end end
--Checks/unchecks scale box for hands --Checks/unchecks scale box for hands
@ -206,273 +190,343 @@ end
--Alters scale of elements and moves them --Alters scale of elements and moves them
function changeTableScale(width, depth) function changeTableScale(width, depth)
--Scaling factors used to translate scale to position offset --Scaling factors used to translate scale to position offset
local width2pos = (width-1) * 18 local width2pos = (width - 1) * 18
local depth2pos = (depth-1) * 18 local depth2pos = (depth - 1) * 18
--Hand zone movement --Hand zone movement
if checkData.move == true then if checkData.move == true then
for _, pc in ipairs(ref_playerColor) do for _, pc in ipairs(ref_playerColor) do
if Player[pc].getHandCount() > 0 then if Player[pc].getHandCount() > 0 then
moveHandZone(Player[pc], width2pos, depth2pos) moveHandZone(Player[pc], width2pos, depth2pos)
end end
end
end end
--Hand zone scaling end
--The button to enable this was disabled for technical reasons --Hand zone scaling
if checkData.scale == true then --The button to enable this was disabled for technical reasons
for _, pc in ipairs(ref_playerColor) do if checkData.scale == true then
if Player[pc].getHandCount() > 0 then for _, pc in ipairs(ref_playerColor) do
scaleHandZone(Player[pc], width, depth) if Player[pc].getHandCount() > 0 then
end scaleHandZone(Player[pc], width, depth)
end end
end end
end
--Resizing table elements --Resizing table elements
obj_side_top.setScale({width, 1, 1}) obj_side_top.setScale({ width, 1, 1 })
obj_side_bot.setScale({width, 1, 1}) obj_side_bot.setScale({ width, 1, 1 })
obj_side_lef.setScale({depth, 1, 1}) obj_side_lef.setScale({ depth, 1, 1 })
obj_side_rig.setScale({depth, 1, 1}) obj_side_rig.setScale({ depth, 1, 1 })
obj_surface.setScale({width, 1, depth}) obj_surface.setScale({ width, 1, depth })
--Moving table elements to accomodate new scale --Moving table elements to accomodate new scale
obj_side_lef.setPosition({-width2pos,tableHeightOffset,0}) obj_side_lef.setPosition({ -width2pos, tableHeightOffset, 0 })
obj_side_rig.setPosition({ width2pos,tableHeightOffset,0}) obj_side_rig.setPosition({ width2pos, tableHeightOffset, 0 })
obj_side_top.setPosition({0,tableHeightOffset, depth2pos}) obj_side_top.setPosition({ 0, tableHeightOffset, depth2pos })
obj_side_bot.setPosition({0,tableHeightOffset,-depth2pos}) obj_side_bot.setPosition({ 0, tableHeightOffset, -depth2pos })
obj_leg1.setPosition({-width2pos,tableHeightOffset,-depth2pos}) obj_leg1.setPosition({ -width2pos, tableHeightOffset, -depth2pos })
obj_leg2.setPosition({-width2pos,tableHeightOffset, depth2pos}) obj_leg2.setPosition({ -width2pos, tableHeightOffset, depth2pos })
obj_leg3.setPosition({ width2pos,tableHeightOffset, depth2pos}) obj_leg3.setPosition({ width2pos, tableHeightOffset, depth2pos })
obj_leg4.setPosition({ width2pos,tableHeightOffset,-depth2pos}) obj_leg4.setPosition({ width2pos, tableHeightOffset, -depth2pos })
self.setPosition(obj_leg4.positionToWorld({-22.12, 8.74,-19.16})) self.setPosition(obj_leg4.positionToWorld({ -22.12, 8.74, -19.16 }))
--Only enabled when changing tableHeightOffset --Only enabled when changing tableHeightOffset
--obj_surface.setPosition({0,tableHeightOffset,0}) --obj_surface.setPosition({0,tableHeightOffset,0})
end end
--Move hand zone, p=player reference, facts are scaling factors --Move hand zone, p=player reference, facts are scaling factors
function moveHandZone(p, width2pos, depth2pos) function moveHandZone(p, width2pos, depth2pos)
local widthX = obj_side_rig.getPosition().x local widthX = obj_side_rig.getPosition().x
local depthZ = obj_side_top.getPosition().z local depthZ = obj_side_top.getPosition().z
for i=1, p.getHandCount() do for i = 1, p.getHandCount() do
local handT = p.getHandTransform() local handT = p.getHandTransform()
local pos = handT.position local pos = handT.position
local y = handT.rotation.y local y = handT.rotation.y
if y<45 or y>320 or y>135 and y<225 then if y < 45 or y > 320 or y > 135 and y < 225 then
if pos.z > 0 then if pos.z > 0 then
pos.z = pos.z + depth2pos - depthZ pos.z = pos.z + depth2pos - depthZ
else else
pos.z = pos.z - depth2pos + depthZ pos.z = pos.z - depth2pos + depthZ
end end
else else
if pos.x > 0 then if pos.x > 0 then
pos.x = pos.x + width2pos - widthX pos.x = pos.x + width2pos - widthX
else else
pos.x = pos.x - width2pos + widthX pos.x = pos.x - width2pos + widthX
end end
end
--Only enabled when changing tableHeightOffset
--pos.y = tableHeightOffset + 14
handT.position = pos
p.setHandTransform(handT, i)
end end
end
--Only enabled when changing tableHeightOffset
--pos.y = tableHeightOffset + 14
handT.position = pos
p.setHandTransform(handT, i)
end
end
---Scales hand zones, p=player reference, facts are scaling factors ---Scales hand zones, p=player reference, facts are scaling factors
function scaleHandZone(p, width, depth) function scaleHandZone(p, width, depth)
local widthFact = width / obj_side_top.getScale().x local widthFact = width / obj_side_top.getScale().x
local depthFact = depth / obj_side_lef.getScale().x local depthFact = depth / obj_side_lef.getScale().x
for i=1, p.getHandCount() do for i = 1, p.getHandCount() do
local handT = p.getHandTransform() local handT = p.getHandTransform()
local scale = handT.scale local scale = handT.scale
local y = handT.rotation.y local y = handT.rotation.y
if y<45 or y>320 or y>135 and y<225 then if y < 45 or y > 320 or y > 135 and y < 225 then
scale.x = scale.x * widthFact scale.x = scale.x * widthFact
else else
scale.x = scale.x * depthFact scale.x = scale.x * depthFact
end
handT.scale = scale
p.setHandTransform(handT, i)
end end
handT.scale = scale
p.setHandTransform(handT, i)
end
end end
--Information gathering --Information gathering
--Checks if a color is promoted or host --Checks if a color is promoted or host
function permissionCheck(color) function permissionCheck(color)
if Player[color].host==true or Player[color].promoted==true then if Player[color].host == true or Player[color].promoted == true then
return true return true
else else
return false return false
end end
end end
--Locates a string saved within memory file --Locates a string saved within memory file
function findInImageDataIndex(...) function findInImageDataIndex(...)
for _, str in ipairs({...}) do for _, str in ipairs({ ... }) do
for i, v in ipairs(tableImageData) do for i, v in ipairs(tableImageData) do
if v.url == str or v.name == str then if v.url == str or v.name == str then
return i return i
end end
end
end end
return nil end
return nil
end end
--Round number (num) to the Nth decimal (dec) --Round number (num) to the Nth decimal (dec)
function round(num, dec) function round(num, dec)
local mult = 10^(dec or 0) local mult = 10 ^ (dec or 0)
return math.floor(num * mult + 0.5) / mult return math.floor(num * mult + 0.5) / mult
end end
--Locates a button with a helper function --Locates a button with a helper function
function findButton(obj, func) function findButton(obj, func)
if func==nil then error("No func supplied to findButton") end if func == nil then error("No func supplied to findButton") end
for _, v in ipairs(obj.getButtons()) do for _, v in ipairs(obj.getButtons()) do
if func(v) then if func(v) then
return v return v
end
end end
return nil end
return nil
end end
--Creation of buttons/inputs --Creation of buttons/inputs
function createOpenCloseButton() function createOpenCloseButton()
local tooltip = "Open Table Control Panel" local tooltip = "Open Table Control Panel"
if controlActive then if controlActive then
tooltip = "Close Table Control Panel" tooltip = "Close Table Control Panel"
end end
self.createButton({ self.createButton({
click_function="click_toggleControl", function_owner=self, click_function = "click_toggleControl",
position={0,0,0}, rotation={-45,0,0}, height=400, width=400, function_owner = self,
color={1,1,1,0}, tooltip=tooltip position = { 0, 0, 0 },
}) rotation = { -45, 0, 0 },
height = 400,
width = 400,
color = { 1, 1, 1, 0 },
tooltip = tooltip
})
end end
function createSurfaceInput() function createSurfaceInput()
local currentURL = obj_surface.getCustomObject().diffuse local currentURL = obj_surface.getCustomObject().diffuse
local nickname = "" local nickname = ""
if findInImageDataIndex(currentURL) ~= nil then if findInImageDataIndex(currentURL) ~= nil then
nickname = tableImageData[findInImageDataIndex(currentURL)].name nickname = tableImageData[findInImageDataIndex(currentURL)].name
end end
self.createInput({ self.createInput({
label="Nickname", input_function="none", function_owner=self, label = "Nickname",
alignment=3, position={0,0,2}, height=224, width=4000, input_function = "none",
font_size=200, tooltip="Enter nickname for table image (only used for save)", function_owner = self,
value=nickname alignment = 3,
}) position = { 0, 0, 2 },
self.createInput({ height = 224,
label="URL", input_function="none", function_owner=self, width = 4000,
alignment=3, position={0,0,3}, height=224, width=4000, font_size = 200,
font_size=200, tooltip="Enter URL for tabletop image", tooltip = "Enter nickname for table image (only used for save)",
value=currentURL value = nickname
}) })
self.createInput({
label = "URL",
input_function = "none",
function_owner = self,
alignment = 3,
position = { 0, 0, 3 },
height = 224,
width = 4000,
font_size = 200,
tooltip = "Enter URL for tabletop image",
value = currentURL
})
end end
function createSurfaceButtons() function createSurfaceButtons()
--Label --Label
self.createButton({
label = "Tabletop Surface Image",
click_function = "none",
position = { 0, 0, 1 },
height = 0,
width = 0,
font_size = 300,
font_color = { 1, 1, 1 }
})
--Functional
self.createButton({
label = "Apply Image\nTo Table",
click_function = "click_applySurface",
function_owner = self,
tooltip = "Apply URL as table image",
position = { 2, 0, 4 },
height = 440,
width = 1400,
font_size = 200,
})
self.createButton({
label = "Save Image\nTo Memory",
click_function = "click_saveSurface",
function_owner = self,
tooltip = "Record URL into memory (requires nickname)",
position = { -2, 0, 4 },
height = 440,
width = 1400,
font_size = 200,
})
--Label
self.createButton({
label = "Load From Memory",
click_function = "none",
position = { 0, 0, 5.5 },
height = 0,
width = 0,
font_size = 300,
font_color = { 1, 1, 1 }
})
--Saves, created dynamically from memory file
for i, memoryEntry in ipairs(tableImageData) do
--Load
local funcName = i .. "loadMemory"
local func = function(x, y) click_loadMemory(x, y, i) end
self.setVar(funcName, func)
self.createButton({ self.createButton({
label="Tabletop Surface Image", click_function="none", label = memoryEntry.name,
position={0,0,1}, height=0, width=0, font_size=300, font_color={1,1,1} click_function = funcName,
function_owner = self,
tooltip = memoryEntry.url,
font_size = 200,
position = { -0.6, 0, 6.5 + 0.5 * (i - 1) },
height = 240,
width = 3300,
}) })
--Functional --Delete
local funcName = i .. "deleteMemory"
local func = function(x, y) click_deleteMemory(x, y, i) end
self.setVar(funcName, func)
self.createButton({ self.createButton({
label="Apply Image\nTo Table", click_function="click_applySurface", label = "DELETE",
function_owner=self, tooltip="Apply URL as table image", click_function = funcName,
position={2,0,4}, height=440, width=1400, font_size=200, function_owner = self,
tooltip = "",
position = { 3.6, 0, 6.5 + 0.5 * (i - 1) },
height = 240,
width = 600,
font_size = 160,
font_color = { 1, 0, 0 },
color = { 0.8, 0.8, 0.8 }
}) })
self.createButton({ end
label="Save Image\nTo Memory", click_function="click_saveSurface",
function_owner=self, tooltip="Record URL into memory (requires nickname)",
position={-2,0,4}, height=440, width=1400, font_size=200,
})
--Label
self.createButton({
label="Load From Memory", click_function="none",
position={0,0,5.5}, height=0, width=0, font_size=300, font_color={1,1,1}
})
--Saves, created dynamically from memory file
for i, memoryEntry in ipairs(tableImageData) do
--Load
local funcName = i.."loadMemory"
local func = function(x,y) click_loadMemory(x,y,i) end
self.setVar(funcName, func)
self.createButton({
label=memoryEntry.name, click_function=funcName,
function_owner=self, tooltip=memoryEntry.url, font_size=200,
position={-0.6,0,6.5+0.5*(i-1)}, height=240, width=3300,
})
--Delete
local funcName = i.."deleteMemory"
local func = function(x,y) click_deleteMemory(x,y,i) end
self.setVar(funcName, func)
self.createButton({
label="DELETE", click_function=funcName,
function_owner=self, tooltip="",
position={3.6,0,6.5+0.5*(i-1)}, height=240, width=600,
font_size=160, font_color={1,0,0}, color={0.8,0.8,0.8}
})
end
end end
function createScaleInput() function createScaleInput()
self.createInput({ self.createInput({
label=string.char(8644), input_function="none", function_owner=self, label = string.char(8644),
alignment=3, position={-8.5,0,2}, height=224, width=400, input_function = "none",
font_size=200, tooltip="Table Width", function_owner = self,
value=round(obj_side_top.getScale().x, 1) alignment = 3,
}) position = { -8.5, 0, 2 },
self.createInput({ height = 224,
label=string.char(8645), input_function="none", function_owner=self, width = 400,
alignment=3, position={-7.5,0,2}, height=224, width=400, font_size = 200,
font_size=200, tooltip="Table Depth", tooltip = "Table Width",
value=round(obj_side_lef.getScale().x, 1) value = round(obj_side_top.getScale().x, 1)
}) })
self.createInput({
label = string.char(8645),
input_function = "none",
function_owner = self,
alignment = 3,
position = { -7.5, 0, 2 },
height = 224,
width = 400,
font_size = 200,
tooltip = "Table Depth",
value = round(obj_side_lef.getScale().x, 1)
})
end end
function createScaleButtons() function createScaleButtons()
--Labels --Labels
self.createButton({ self.createButton({
label="Table Scale", click_function="none", label = "Table Scale",
position={-8,0,1}, height=0, width=0, font_size=300, font_color={1,1,1} click_function = "none",
}) position = { -8, 0, 1 },
self.createButton({ height = 0,
label=string.char(8644).." "..string.char(8645), width = 0,
click_function="none", font_size = 300,
position={-8,0,2}, height=0, width=0, font_size=300, font_color={1,1,1} font_color = { 1, 1, 1 }
}) })
self.createButton({ self.createButton({
label="Move Hands:", click_function="none", label = string.char(8644) .. " " .. string.char(8645),
position={-8.3,0,3}, height=0, width=0, font_size=200, font_color={1,1,1} click_function = "none",
}) position = { -8, 0, 2 },
--Disabled due to me removing the feature for technical reasons height = 0,
--[[ width = 0,
font_size = 300,
font_color = { 1, 1, 1 }
})
self.createButton({
label = "Move Hands:",
click_function = "none",
position = { -8.3, 0, 3 },
height = 0,
width = 0,
font_size = 200,
font_color = { 1, 1, 1 }
})
--Disabled due to me removing the feature for technical reasons
--[[
self.createButton({ self.createButton({
label="Scale Hands:", click_function="none", label="Scale Hands:", click_function="none",
position={-8.3,0,4}, height=0, width=0, font_size=200, font_color={1,1,1} position={-8.3,0,4}, height=0, width=0, font_size=200, font_color={1,1,1}
}) })
]] ]]
--Checkboxes --Checkboxes
local label = "" local label = ""
if checkData.move == true then label = string.char(10008) end if checkData.move == true then label = string.char(10008) end
self.createButton({ self.createButton({
label=label, click_function="click_checkMove", label = label,
function_owner=self, tooltip="Check to move hands when table is rescaled", click_function = "click_checkMove",
position={-6.8,0,3}, height=224, width=224, font_size=200, function_owner = self,
}) tooltip = "Check to move hands when table is rescaled",
--[[ position = { -6.8, 0, 3 },
height = 224,
width = 224,
font_size = 200,
})
--[[
local label = "" local label = ""
if checkData.scale == true then label = string.char(10008) end if checkData.scale == true then label = string.char(10008) end
self.createButton({ self.createButton({
@ -481,31 +535,29 @@ function createScaleButtons()
position={-6.8,0,4}, height=224, width=224, font_size=200, position={-6.8,0,4}, height=224, width=224, font_size=200,
}) })
]] ]]
--Apply button --Apply button
self.createButton({ self.createButton({
label="Apply Scale", click_function="click_applyScale", label = "Apply Scale",
function_owner=self, tooltip="Apply width/depth to table", click_function = "click_applyScale",
position={-8,0,4}, height=440, width=1400, font_size=200, function_owner = self,
}) tooltip = "Apply width/depth to table",
position = { -8, 0, 4 },
height = 440,
width = 1400,
font_size = 200,
})
end end
--Data tables --Data tables
ref_noninteractable = { ref_noninteractable = {
"afc863","c8edca","393bf7","12c65e","f938a2","9f95fd","35b95f", "afc863", "c8edca", "393bf7", "12c65e", "f938a2", "9f95fd", "35b95f",
"5af8f2","4ee1f2","bd69bd" "5af8f2", "4ee1f2", "bd69bd"
} }
ref_playerColor = { ref_playerColor = {
"White", "Brown", "Red", "Orange", "Yellow", "White", "Brown", "Red", "Orange", "Yellow",
"Green", "Teal", "Blue", "Purple", "Pink", "Black" "Green", "Teal", "Blue", "Purple", "Pink", "Black"
} }
--Dummy function, absorbs unwanted triggers --Dummy function, absorbs unwanted triggers

View File

@ -1 +1 @@
{"acknowledgedUpgradeVersions":[],"chaosTokensGUID":[],"optionPanel":{"cardLanguage":"en","changePlayAreaImage":false,"enableCardHelpers":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,"enableCardHelpers":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}}

View File

@ -22,7 +22,7 @@
"ImageURL": "http://cloud-3.steamusercontent.com/ugc/1915746489209870095/5F6A6F2946DBEB81667C15B112F9E35943E61A97/", "ImageURL": "http://cloud-3.steamusercontent.com/ugc/1915746489209870095/5F6A6F2946DBEB81667C15B112F9E35943E61A97/",
"WidthScale": 0 "WidthScale": 0
}, },
"Description": "Moves all objects on the playmat in the chosen direction.", "Description": "Moves all objects on the playermat in the chosen direction.",
"DragSelectable": true, "DragSelectable": true,
"GMNotes": "", "GMNotes": "",
"GUID": "0f1374", "GUID": "0f1374",

View File

@ -22,7 +22,7 @@
"ImageURL": "http://cloud-3.steamusercontent.com/ugc/1838053776205435595/ECFB88938ADBD1EF7AEF713111A11330FD9FAA5A/", "ImageURL": "http://cloud-3.steamusercontent.com/ugc/1838053776205435595/ECFB88938ADBD1EF7AEF713111A11330FD9FAA5A/",
"WidthScale": 0 "WidthScale": 0
}, },
"Description": "Searches the top X cards of the nearest playmat by setting your hand aside and putting the cards into your hand.\n\nPut the target of your search on your set aside hand.", "Description": "Searches the top X cards of the nearest playermat by setting your hand aside and putting the cards into your hand.\n\nPut the target of your search on your set aside hand.",
"DragSelectable": true, "DragSelectable": true,
"GMNotes": "", "GMNotes": "",
"GUID": "17aed0", "GUID": "17aed0",

View File

@ -22,7 +22,7 @@
"ImageURL": "https://i.imgur.com/gs1mtXJ.png", "ImageURL": "https://i.imgur.com/gs1mtXJ.png",
"WidthScale": 0 "WidthScale": 0
}, },
"Description": "Allows changing of the playmat image. Provide URL to the image or leave empty for default image.", "Description": "Allows changing of the playarea image. Provide URL to the image or leave empty for default image.",
"DragSelectable": true, "DragSelectable": true,
"GMNotes": "", "GMNotes": "",
"GUID": "b7b45b", "GUID": "b7b45b",
@ -37,7 +37,7 @@
"LuaScriptState": "{\"selectionIndex\":1,\"typeIndex\":1}", "LuaScriptState": "{\"selectionIndex\":1,\"typeIndex\":1}",
"MeasureMovement": false, "MeasureMovement": false,
"Name": "Custom_Token", "Name": "Custom_Token",
"Nickname": "Playmat Image Swapper", "Nickname": "PlayArea Image Swapper",
"Snap": true, "Snap": true,
"Sticky": true, "Sticky": true,
"Tags": [ "Tags": [

View File

@ -353,7 +353,7 @@
"IgnoreFoW": false, "IgnoreFoW": false,
"LayoutGroupSortIndex": 0, "LayoutGroupSortIndex": 0,
"Locked": true, "Locked": true,
"LuaScript": "require(\"playermat/Playmat\")", "LuaScript": "require(\"playermat/Playermat\")",
"LuaScriptState_path": "Playermat1White.8b081b.luascriptstate", "LuaScriptState_path": "Playermat1White.8b081b.luascriptstate",
"MeasureMovement": false, "MeasureMovement": false,
"Memo": "White", "Memo": "White",

View File

@ -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"]}

View File

@ -353,7 +353,7 @@
"IgnoreFoW": false, "IgnoreFoW": false,
"LayoutGroupSortIndex": 0, "LayoutGroupSortIndex": 0,
"Locked": true, "Locked": true,
"LuaScript": "require(\"playermat/Playmat\")", "LuaScript": "require(\"playermat/Playermat\")",
"LuaScriptState_path": "Playermat2Orange.bd0ff4.luascriptstate", "LuaScriptState_path": "Playermat2Orange.bd0ff4.luascriptstate",
"MeasureMovement": false, "MeasureMovement": false,
"Memo": "Orange", "Memo": "Orange",

View File

@ -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"]}

View File

@ -353,7 +353,7 @@
"IgnoreFoW": false, "IgnoreFoW": false,
"LayoutGroupSortIndex": 0, "LayoutGroupSortIndex": 0,
"Locked": true, "Locked": true,
"LuaScript": "require(\"playermat/Playmat\")", "LuaScript": "require(\"playermat/Playermat\")",
"LuaScriptState_path": "Playermat3Green.383d8b.luascriptstate", "LuaScriptState_path": "Playermat3Green.383d8b.luascriptstate",
"MeasureMovement": false, "MeasureMovement": false,
"Memo": "Green", "Memo": "Green",

View File

@ -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"]}

View File

@ -353,7 +353,7 @@
"IgnoreFoW": false, "IgnoreFoW": false,
"LayoutGroupSortIndex": 0, "LayoutGroupSortIndex": 0,
"Locked": true, "Locked": true,
"LuaScript": "require(\"playermat/Playmat\")", "LuaScript": "require(\"playermat/Playermat\")",
"LuaScriptState_path": "Playermat4Red.0840d5.luascriptstate", "LuaScriptState_path": "Playermat4Red.0840d5.luascriptstate",
"MeasureMovement": false, "MeasureMovement": false,
"Memo": "Red", "Memo": "Red",

View File

@ -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"]}

View File

@ -41,7 +41,7 @@
"LayoutGroupSortIndex": 0, "LayoutGroupSortIndex": 0,
"Locked": false, "Locked": false,
"LuaScript": "require(\"core/UniversalActionAbilityToken\")", "LuaScript": "require(\"core/UniversalActionAbilityToken\")",
"LuaScriptState": "", "LuaScriptState": "{\"class\":\"Neutral\",\"symbol\":\"Neutral\"}",
"MeasureMovement": false, "MeasureMovement": false,
"Memo": "universalActionAbility", "Memo": "universalActionAbility",
"Name": "Custom_Tile", "Name": "Custom_Tile",

View File

@ -4,7 +4,7 @@ local deckImporterApi = require("arkhamdb/DeckImporterApi")
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local optionPanelApi = require("core/OptionPanelApi") local optionPanelApi = require("core/OptionPanelApi")
local playAreaApi = require("core/PlayAreaApi") local playAreaApi = require("core/PlayAreaApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
-- base data for token creation -- base data for token creation
local campaignTokenData = { local campaignTokenData = {
@ -95,7 +95,7 @@ function importFromToken(coin)
Wait.condition( Wait.condition(
function() function()
local campaignBox = getObjectFromGUID(importData["box"]) campaignBox = getObjectFromGUID(importData["box"])
if #campaignBox.getObjects() > 0 then if #campaignBox.getObjects() > 0 then
placeCampaignFromToken(importData, coin) placeCampaignFromToken(importData, coin)
else else
@ -103,11 +103,11 @@ function importFromToken(coin)
end end
end, end,
function() function()
local obj = getObjectFromGUID(importData["box"]) campaignBox = getObjectFromGUID(importData["box"])
if obj == nil then if campaignBox == nil then
return false return false
else else
return obj.type == "Bag" return campaignBox.type == "Bag"
end end
end, end,
2, 2,
@ -190,10 +190,10 @@ function restoreCampaignData(importData, coin)
playAreaApi.updateSurface(importData["playarea"]) playAreaApi.updateSurface(importData["playarea"])
playAreaApi.setInvestigatorCount(importData["clueCount"]) playAreaApi.setInvestigatorCount(importData["clueCount"])
-- restore Playmat slots -- restore playermat slots
if importData["slotData"] then if importData["slotData"] then
for matColor, slotData in pairs(importData["slotData"]) do for matColor, slotData in pairs(importData["slotData"]) do
playmatApi.loadSlotData(matColor, slotData) playermatApi.loadSlotData(matColor, slotData)
end end
end end
@ -272,10 +272,10 @@ function createCampaignToken(_, playerColor, _)
table.insert(campaignTokenData.ContainedObjects, indexData) table.insert(campaignTokenData.ContainedObjects, indexData)
end end
-- get the slot symbol data for each playmat (use GUIDReferenceApi to only get this for existing playmats) -- get the slot symbol data for each playermat (use GUIDReferenceApi to only get this for existing playermats)
campaignData.slotData = {} campaignData.slotData = {}
for matColor, _ in pairs(guidReferenceApi.getObjectsByType("Playermat")) do for matColor, _ in pairs(guidReferenceApi.getObjectsByType("Playermat")) do
local slotData = playmatApi.getSlotData(matColor) local slotData = playermatApi.getSlotData(matColor)
campaignData.slotData[matColor] = slotData campaignData.slotData[matColor] = slotData
end end
@ -306,7 +306,7 @@ end
function setTrauma(trauma) function setTrauma(trauma)
for i, matColor in ipairs({ "White", "Orange", "Green", "Red" }) do for i, matColor in ipairs({ "White", "Orange", "Green", "Red" }) do
playmatApi.updateCounter(matColor, "DamageCounter", trauma[i]) playermatApi.updateCounter(matColor, "DamageCounter", trauma[i])
playmatApi.updateCounter(matColor, "HorrorCounter", trauma[i + 4]) playermatApi.updateCounter(matColor, "HorrorCounter", trauma[i + 4])
end end
end end

View File

@ -1,6 +1,6 @@
-- Cleans up the table for the next scenario in a campaign: -- Cleans up the table for the next scenario in a campaign:
-- sets counters to default values (resources and doom) or trauma values (health and sanity, if not disabled) from campaign log -- sets counters to default values (resources and doom) or trauma values (health and sanity, if not disabled) from campaign log
-- puts everything on playmats and hands into respective trashcans -- puts everything on playermats and hands into respective trashcans
-- use the IGNORE_TAG to exclude objects from tidying (default: "CleanUpHelper_Ignore") -- use the IGNORE_TAG to exclude objects from tidying (default: "CleanUpHelper_Ignore")
local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi") local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
@ -8,7 +8,7 @@ local chaosBagApi = require("chaosbag/ChaosBagApi")
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local mythosAreaApi = require("core/MythosAreaApi") local mythosAreaApi = require("core/MythosAreaApi")
local playAreaApi = require("core/PlayAreaApi") local playAreaApi = require("core/PlayAreaApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local searchLib = require("util/SearchLib") local searchLib = require("util/SearchLib")
local soundCubeApi = require("core/SoundCubeApi") local soundCubeApi = require("core/SoundCubeApi")
local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi") local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi")
@ -28,9 +28,9 @@ options["importTrauma"] = true
options["tidyPlayermats"] = true options["tidyPlayermats"] = true
options["removeDrawnLines"] = false options["removeDrawnLines"] = false
-- don't clean playmats for preludes -- don't clean playermats for preludes
local scenarioName local scenarioName
local preludeList = { local preludeList = {
["Prelude: Welcome to Hemlock Vale!"] = true ["Prelude: Welcome to Hemlock Vale!"] = true
} }
@ -149,13 +149,13 @@ end
function updateCounters() function updateCounters()
if not getOptionValue() then return end if not getOptionValue() then return end
playmatApi.updateCounter("All", "ResourceCounter", 5) playermatApi.updateCounter("All", "ResourceCounter", 5)
playmatApi.updateCounter("All", "ClickableClueCounter", 0) playermatApi.updateCounter("All", "ClickableClueCounter", 0)
playmatApi.resetSkillTracker("All") playermatApi.resetSkillTracker("All")
for i = 1, 4 do for i = 1, 4 do
playmatApi.updateCounter(COLORS[i], "DamageCounter", RESET_VALUES.Damage[i]) playermatApi.updateCounter(COLORS[i], "DamageCounter", RESET_VALUES.Damage[i])
playmatApi.updateCounter(COLORS[i], "HorrorCounter", RESET_VALUES.Horror[i]) playermatApi.updateCounter(COLORS[i], "HorrorCounter", RESET_VALUES.Horror[i])
end end
end end
@ -272,7 +272,7 @@ function discardHands()
for i = 1, 4 do for i = 1, 4 do
local trash = guidReferenceApi.getObjectByOwnerAndType(COLORS[i], "Trash") local trash = guidReferenceApi.getObjectByOwnerAndType(COLORS[i], "Trash")
if trash == nil then return end if trash == nil then return end
local hand = Player[playmatApi.getPlayerColor(COLORS[i])].getHandObjects() local hand = Player[playermatApi.getPlayerColor(COLORS[i])].getHandObjects()
for j = #hand, 1, -1 do for j = #hand, 1, -1 do
trash.putObject(hand[j]) trash.putObject(hand[j])
end end
@ -340,7 +340,7 @@ function tidyPlayerMatCoroutine()
-- get respective trash -- get respective trash
local trash = guidReferenceApi.getObjectByOwnerAndType(COLORS[i], "Trash") local trash = guidReferenceApi.getObjectByOwnerAndType(COLORS[i], "Trash")
if trash == nil then if trash == nil then
printToAll("Trashcan for " .. COLORS[i] .. " playmat could not be found! Skipping this playermat.", "Yellow") printToAll("Trashcan for " .. COLORS[i] .. " playermat could not be found! Skipping this playermat.", "Yellow")
goto continue goto continue
end end
@ -351,7 +351,7 @@ function tidyPlayerMatCoroutine()
local objList local objList
if i < 5 then if i < 5 then
objList = playmatApi.searchAroundPlaymat(COLORS[i]) objList = playermatApi.searchAroundPlayermat(COLORS[i])
else else
-- Victory Display + Mythos Area -- Victory Display + Mythos Area
objList = searchLib.inArea({ -2, 2, 10 }, { 0, 270, 0 }, { 55, 1, 13.5 }) objList = searchLib.inArea({ -2, 2, 10 }, { 0, 270, 0 }, { 55, 1, 13.5 })

View File

@ -1,4 +1,4 @@
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
-- forward declaration of variables that are used across functions -- forward declaration of variables that are used across functions
local matColor, handColor, hovering local matColor, handColor, hovering
@ -36,7 +36,7 @@ function onLoad()
updateColors() updateColors()
-- start loop to update card count -- start loop to update card count
playmatApi.checkForDES(matColor) playermatApi.checkForDES(matColor)
Wait.time(updateValue, 1, -1) Wait.time(updateValue, 1, -1)
end end
@ -49,7 +49,7 @@ function onObjectHover(hoverColor, object)
if object == self then if object == self then
hovering = true hovering = true
playmatApi.checkForDES(matColor) playermatApi.checkForDES(matColor)
updateValue() updateValue()
else else
hovering = false hovering = false
@ -58,8 +58,8 @@ end
-- updates the matcolor and handcolor variable -- updates the matcolor and handcolor variable
function updateColors() function updateColors()
matColor = playmatApi.getMatColorByPosition(self.getPosition()) matColor = playermatApi.getMatColorByPosition(self.getPosition())
handColor = playmatApi.getPlayerColor(matColor) handColor = playermatApi.getPlayerColor(matColor)
self.setName(handColor .. " Hand Helper") self.setName(handColor .. " Hand Helper")
end end
@ -74,7 +74,7 @@ function updateValue()
if Player[handColor].getHandCount() == 0 then return end if Player[handColor].getHandCount() == 0 then return end
-- get state of "Dream-Enhancing Serum" from playermat -- get state of "Dream-Enhancing Serum" from playermat
local hasDES = playmatApi.hasDES(matColor) local hasDES = playermatApi.hasDES(matColor)
-- default to regular count if hovered -- default to regular count if hovered
if hovering then if hovering then
@ -113,5 +113,5 @@ end
-- discards a random non-hidden card from hand -- discards a random non-hidden card from hand
function discardRandom() function discardRandom()
playmatApi.doDiscardOne(matColor) playermatApi.doDiscardOne(matColor)
end end

View File

@ -11,9 +11,6 @@ local phaseImages = {
"http://cloud-3.steamusercontent.com/ugc/982233321870237261/C287CAED2423970F33E72D6C7415CBEC6794C533/" "http://cloud-3.steamusercontent.com/ugc/982233321870237261/C287CAED2423970F33E72D6C7415CBEC6794C533/"
} }
-- these are intentionally global for remote updating
-- phaseId, broadcastChange
function onSave() function onSave()
return JSON.encode({ return JSON.encode({
phaseId = phaseId, phaseId = phaseId,
@ -21,11 +18,15 @@ function onSave()
}) })
end end
function loadFromSaveTable(savedData)
for var, val in pairs(JSON.decode(savedData)) do
_G[var] = val
end
end
function onLoad(savedData) function onLoad(savedData)
if savedData and savedData ~= "" then if savedData and savedData ~= "" then
local loadedData = JSON.decode(savedData) loadFromSaveTable(savedData)
phaseId = loadedData.phaseId
broadcastChange = loadedData.broadcastChange
else else
phaseId = 1 phaseId = 1
broadcastChange = false broadcastChange = false

View File

@ -1,16 +1,16 @@
local deckLib = require("util/DeckLib") local deckLib = require("util/DeckLib")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local searchLib = require("util/SearchLib") local searchLib = require("util/SearchLib")
-- forward declaration of variables that are used across functions -- forward declaration of variables that are used across functions
local matColor, handColor, setAsidePosition, setAsideRotation, drawDeckPosition, topCardDetected local matColor, handColor, setAsidePosition, setAsideRotation, drawDeckPosition, topCardDetected
local quickParameters = {} local quickParameters = {}
quickParameters.function_owner = self quickParameters.function_owner = self
quickParameters.font_size = 165 quickParameters.font_size = 165
quickParameters.width = 275 quickParameters.width = 275
quickParameters.height = 275 quickParameters.height = 275
quickParameters.color = "White" quickParameters.color = "White"
-- common parameters -- common parameters
local buttonParameters = {} local buttonParameters = {}
@ -20,17 +20,17 @@ buttonParameters.width = 650
buttonParameters.height = 225 buttonParameters.height = 225
buttonParameters.color = "White" buttonParameters.color = "White"
local inputParameters = {} local inputParameters = {}
inputParameters.function_owner = self inputParameters.function_owner = self
inputParameters.input_function = "updateSearchNumber" inputParameters.input_function = "updateSearchNumber"
inputParameters.tooltip = "custom search amount" inputParameters.tooltip = "custom search amount"
inputParameters.label = "#" inputParameters.label = "#"
inputParameters.font_size = 175 inputParameters.font_size = 175
inputParameters.width = 400 inputParameters.width = 400
inputParameters.height = inputParameters.font_size + 23 inputParameters.height = inputParameters.font_size + 23
inputParameters.position = { 0, 0.11, 0 } inputParameters.position = { 0, 0.11, 0 }
inputParameters.alignment = 3 inputParameters.alignment = 3
inputParameters.validation = 2 inputParameters.validation = 2
function onLoad() function onLoad()
normalView() normalView()
@ -101,12 +101,12 @@ end
-- start the search (change UI, set handCards aside, draw cards) -- start the search (change UI, set handCards aside, draw cards)
function startSearch(messageColor, number) function startSearch(messageColor, number)
matColor = playmatApi.getMatColorByPosition(self.getPosition()) matColor = playermatApi.getMatColorByPosition(self.getPosition())
handColor = playmatApi.getPlayerColor(matColor) handColor = playermatApi.getPlayerColor(matColor)
topCardDetected = false topCardDetected = false
-- get draw deck -- get draw deck
local deckAreaObjects = playmatApi.getDeckAreaObjects(matColor) local deckAreaObjects = playermatApi.getDeckAreaObjects(matColor)
if deckAreaObjects.draw == nil then if deckAreaObjects.draw == nil then
printToColor(matColor .. " draw deck could not be found!", messageColor, "Red") printToColor(matColor .. " draw deck could not be found!", messageColor, "Red")
return return
@ -117,17 +117,17 @@ function startSearch(messageColor, number)
drawDeckPosition = bounds.center + Vector(0, bounds.size.y / 2 + 0.2, 0) drawDeckPosition = bounds.center + Vector(0, bounds.size.y / 2 + 0.2, 0)
printToColor("Place target(s) of search on set aside hand.", messageColor, "Green") printToColor("Place target(s) of search on set aside hand.", messageColor, "Green")
-- get playmat orientation -- get playermat orientation
local offset = -15 local offset = -15
if matColor == "Orange" or matColor == "Red" then if matColor == "Orange" or matColor == "Red" then
offset = 15 offset = 15
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
setAsideRotation = { handData.rotation.x, handData.rotation.y + 180, 180 } setAsideRotation = { handData.rotation.x, handData.rotation.y + 180, 180 }
-- set y-value -- set y-value
setAsidePosition.y = 1.5 setAsidePosition.y = 1.5
@ -146,7 +146,7 @@ function startSearch(messageColor, number)
searchView() searchView()
Wait.time(function() Wait.time(function()
deckAreaObjects = playmatApi.getDeckAreaObjects(matColor) deckAreaObjects = playermatApi.getDeckAreaObjects(matColor)
deckAreaObjects.draw.deal(number, handColor) deckAreaObjects.draw.deal(number, handColor)
end, 1) end, 1)
end end
@ -175,7 +175,7 @@ function endSearch(_, _, isRightClick)
-- delay is to wait for cards to enter deck -- delay is to wait for cards to enter deck
if not isRightClick then if not isRightClick then
Wait.time(function() Wait.time(function()
local deckAreaObjects = playmatApi.getDeckAreaObjects(matColor) local deckAreaObjects = playermatApi.getDeckAreaObjects(matColor)
if deckAreaObjects.draw then if deckAreaObjects.draw then
deckAreaObjects.draw.shuffle() deckAreaObjects.draw.shuffle()
end end
@ -184,6 +184,6 @@ function endSearch(_, _, isRightClick)
-- Norman Withers handling -- Norman Withers handling
if topCardDetected then if topCardDetected then
Wait.time(function() playmatApi.flipTopCardFromDeck(matColor) end, #handCards * 0.3 + 0.75) Wait.time(function() playermatApi.flipTopCardFromDeck(matColor) end, #handCards * 0.3 + 0.75)
end end
end end

View File

@ -1,277 +1,275 @@
local searchLib = require("util/SearchLib") local searchLib = require("util/SearchLib")
function onload(savedData) function onSave()
revealCardPositions = { return JSON.encode({ saved_hiddenCards = hiddenCards })
Vector(3.5, 0.25, 0),
Vector(-3.5, 0.25, 0)
}
revealCardPositionsSwap = {
Vector(-3.5, 0.25, 0),
Vector(3.5, 0.25, 0)
}
self.createButton({
label = 'Underworld Market\nHelper',
click_function = "none",
function_owner = self,
position = {0,-0.1,-1.6},
height = 0,
width = 0,
font_size = 145,
font_color = {1,1,1}
})
hiddenCards = 10
hiddenCardLabel = '-----'
isSetup = false
movingCards = false
self.addContextMenuItem('Reset helper', resetHelper)
if savedData ~= '' then
local loaded_data = JSON.decode(savedData)
hiddenCards = loaded_data.saved_hiddenCards
isSetup = true
refreshButtons()
end
end end
function onSave() function onload(savedData)
return JSON.encode({ revealCardPositions = {
saved_hiddenCards = hiddenCards Vector(3.5, 0.25, 0),
}) Vector(-3.5, 0.25, 0)
}
revealCardPositionsSwap = {
Vector(-3.5, 0.25, 0),
Vector(3.5, 0.25, 0)
}
self.createButton({
label = 'Underworld Market\nHelper',
click_function = "none",
function_owner = self,
position = { 0, -0.1, -1.6 },
height = 0,
width = 0,
font_size = 145,
font_color = { 1, 1, 1 }
})
hiddenCards = 10
hiddenCardLabel = '-----'
isSetup = false
movingCards = false
self.addContextMenuItem('Reset helper', resetHelper)
if savedData and savedData ~= '' then
local loaded_data = JSON.decode(savedData)
hiddenCards = loaded_data.saved_hiddenCards
isSetup = true
refreshButtons()
end
end end
function onObjectEnterContainer(container, object) function onObjectEnterContainer(container, object)
if container ~= self then return end if container ~= self then return end
if isSetup and object.tag == "Card" then if isSetup and object.tag == "Card" then
refreshButtons() refreshButtons()
end end
if object.tag == "Deck" then if object.tag == "Deck" then
if validateDeck(object) then if validateDeck(object) then
takeDeckOut(object.getGUID(), self.getPosition() + Vector(0, 0.1, 0)) takeDeckOut(object.getGUID(), self.getPosition() + Vector(0, 0.1, 0))
refreshButtons() refreshButtons()
isSetup = true isSetup = true
end
elseif object.tag ~= "Card" then
broadcastToAll("The 'Underworld Market Helper' is meant to be used for cards.", "White")
end end
elseif object.tag ~= "Card" then
broadcastToAll("The 'Underworld Market Helper' is meant to be used for cards.", "White")
end
end end
function onObjectLeaveContainer(container, object) function onObjectLeaveContainer(container, object)
if container ~= self then return end if container ~= self then return end
if isSetup then if isSetup then
refreshButtons() refreshButtons()
end end
end end
function validateDeck(deck) function validateDeck(deck)
if deck.getQuantity() ~= 10 then if deck.getQuantity() ~= 10 then
print('Underworld Market Helper: Deck must include exactly 10 cards.') print('Underworld Market Helper: Deck must include exactly 10 cards.')
return false return false
end
local illicitCount = 0
for _, card in ipairs(deck.getObjects()) do
decodedGMNotes = JSON.decode(card.gm_notes)
if decodedGMNotes ~= nil and string.find(decodedGMNotes.traits, "Illicit", 1, true) then
illicitCount = illicitCount + 1
end end
end
local illicitCount = 0 if illicitCount ~= 10 then
print('Underworld Market Helper: Deck must include 10 Illicit cards.')
return false
end
for _, card in ipairs(deck.getObjects()) do return true
decodedGMNotes = JSON.decode(card.gm_notes)
if decodedGMNotes ~= nil and string.find(decodedGMNotes.traits, "Illicit", 1, true) then
illicitCount = illicitCount + 1
end
end
if illicitCount ~= 10 then
print('Underworld Market Helper: Deck must include 10 Illicit cards.')
return false
end
return true
end end
function refreshButtons() function refreshButtons()
local cardsList = '' local cardsList = ''
for i, card in ipairs(self.getObjects()) do for i, card in ipairs(self.getObjects()) do
local localCardName = card.name local localCardName = card.name
if i <= hiddenCards then if i <= hiddenCards then
localCardName = hiddenCardLabel localCardName = hiddenCardLabel
end
cardsList = cardsList .. localCardName .. '\n'
end end
self.clearButtons() cardsList = cardsList .. localCardName .. '\n'
end
self.createButton({ self.clearButtons()
label = 'Market Deck:',
click_function = "none",
function_owner = self,
position = {0,-0.1,-1.6},
height = 0,
width = 0,
font_size = 150,
font_color = {1,1,1}
})
self.createButton({ self.createButton({
label = cardsList, label = 'Market Deck:',
click_function = "none", click_function = "none",
function_owner = self, function_owner = self,
position = {0,-0.1,0.15}, position = { 0, -0.1, -1.6 },
height = 0, height = 0,
width = 0, width = 0,
font_size = 115, font_size = 150,
font_color = {1,1,1} font_color = { 1, 1, 1 }
}) })
self.createButton({ self.createButton({
click_function = 'revealFirstTwoCards', label = cardsList,
function_owner = self, click_function = "none",
label = 'Reveal', function_owner = self,
position = {-0.85,0,1.6}, position = { 0, -0.1, 0.15 },
width = 375, height = 0,
height = 175, width = 0,
font_size = 90 font_size = 115,
}) font_color = { 1, 1, 1 }
})
self.createButton({ self.createButton({
click_function = 'swap', click_function = 'revealFirstTwoCards',
function_owner = self, function_owner = self,
label = 'Swap', label = 'Reveal',
position = {0,0,1.6}, position = { -0.85, 0, 1.6 },
width = 375, width = 375,
height = 175, height = 175,
font_size = 90 font_size = 90
}) })
self.createButton({ self.createButton({
click_function = 'finish', click_function = 'swap',
function_owner = self, function_owner = self,
label = 'Finish', label = 'Swap',
position = {0.85,0,1.6}, position = { 0, 0, 1.6 },
width = 375, width = 375,
height = 175, height = 175,
font_size = 90 font_size = 90
}) })
self.createButton({
click_function = 'finish',
function_owner = self,
label = 'Finish',
position = { 0.85, 0, 1.6 },
width = 375,
height = 175,
font_size = 90
})
end end
function takeDeckOut(guid, pos) function takeDeckOut(guid, pos)
local deck = self.takeObject({ guid = guid, position = pos, smooth = false }) local deck = self.takeObject({ guid = guid, position = pos, smooth = false })
for i = 1, #deck.getObjects() do for i = 1, #deck.getObjects() do
self.putObject(deck.takeObject({ position = pos + Vector(0, 0.1 * i, 0), smooth = false })) self.putObject(deck.takeObject({ position = pos + Vector(0, 0.1 * i, 0), smooth = false }))
end end
self.shuffle() self.shuffle()
end end
function getRevealedCards() function getRevealedCards()
local revealedCards = {} local revealedCards = {}
for _, pos in ipairs(revealCardPositions) do for _, pos in ipairs(revealCardPositions) do
for _, obj in ipairs(searchLib.atPosition(self.positionToWorld(pos), "isCard")) do for _, obj in ipairs(searchLib.atPosition(self.positionToWorld(pos), "isCard")) do
table.insert(revealedCards, obj.getGUID()) table.insert(revealedCards, obj.getGUID())
end
end end
end
return revealedCards return revealedCards
end end
function revealFirstTwoCards() function revealFirstTwoCards()
if movingCards or #getRevealedCards() > 0 then return end if movingCards or #getRevealedCards() > 0 then return end
for i, card in ipairs(self.getObjects()) do for i, card in ipairs(self.getObjects()) do
movingCards = true movingCards = true
self.takeObject({ self.takeObject({
index = 0, index = 0,
rotation = self.getRotation(), rotation = self.getRotation(),
position = self.positionToWorld(revealCardPositions[i]), position = self.positionToWorld(revealCardPositions[i]),
callback_function = function(obj) callback_function = function(obj)
obj.resting = true obj.resting = true
movingCards = false movingCards = false
end end
}) })
hiddenCards = hiddenCards - 1 hiddenCards = hiddenCards - 1
if i == 2 or #self.getObjects() == 0 then if i == 2 or #self.getObjects() == 0 then
break break
end
end end
end
refreshButtons() refreshButtons()
end end
function swap() function swap()
if movingCards then return end if movingCards then return end
local revealedCards = getRevealedCards() local revealedCards = getRevealedCards()
if #revealedCards == 2 then if #revealedCards == 2 then
for i, revealedCardGUID in ipairs(revealedCards) do for i, revealedCardGUID in ipairs(revealedCards) do
local revealedCard = getObjectFromGUID(revealedCardGUID) local revealedCard = getObjectFromGUID(revealedCardGUID)
revealedCard.setPositionSmooth(self.positionToWorld(revealCardPositionsSwap[i]), false, false) revealedCard.setPositionSmooth(self.positionToWorld(revealCardPositionsSwap[i]), false, false)
end
end end
end
end end
function finish() function finish()
if movingCards then return end if movingCards then return end
local revealedCards = getRevealedCards() local revealedCards = getRevealedCards()
movingCards = true movingCards = true
for i, revealedCardGUID in ipairs(revealedCards) do for i, revealedCardGUID in ipairs(revealedCards) do
self.putObject(getObjectFromGUID(revealedCardGUID)) self.putObject(getObjectFromGUID(revealedCardGUID))
end end
Wait.time( Wait.time(
function() function()
movingCards = false movingCards = false
end, end,
0.75) 0.75)
end end
function resetHelper() function resetHelper()
for i, card in ipairs(self.getObjects()) do for i, card in ipairs(self.getObjects()) do
self.takeObject({ self.takeObject({
index = 0, index = 0,
smooth = false, smooth = false,
rotation = self.getRotation(), rotation = self.getRotation(),
position = self.positionToWorld(revealCardPositions[2]) position = self.positionToWorld(revealCardPositions[2])
})
end
self.clearButtons()
self.createButton({
label = 'Underworld Market\nHelper',
click_function = "none",
function_owner = self,
position = {0,-0.1,-1.6},
height = 0,
width = 0,
font_size = 145,
font_color = {1,1,1}
}) })
end
hiddenCards = 10 self.clearButtons()
isSetup = false
movingCards = false
self.reset() self.createButton({
label = 'Underworld Market\nHelper',
click_function = "none",
function_owner = self,
position = { 0, -0.1, -1.6 },
height = 0,
width = 0,
font_size = 145,
font_color = { 1, 1, 1 }
})
print('Underworld Market Helper: Helper has been reset.') hiddenCards = 10
isSetup = false
movingCards = false
self.reset()
print('Underworld Market Helper: Helper has been reset.')
end end

View File

@ -482,7 +482,6 @@ do
---@param uri table ---@param uri table
---@param on_success fun(status, vararg): boolean, any ---@param on_success fun(status, vararg): boolean, any
---@param on_error nil|fun(status, vararg): string ---@param on_error nil|fun(status, vararg): string
---@vararg any
---@return Request ---@return Request
function Request.start(uri, on_success, on_error, ...) function Request.start(uri, on_success, on_error, ...)
local parameters = table.pack(...) local parameters = table.pack(...)
@ -497,7 +496,6 @@ do
---@param requests Request[] ---@param requests Request[]
---@param on_success fun(content: any, vararg: any) ---@param on_success fun(content: any, vararg: any)
---@param on_error fun(requests: Request, vararg: any)|nil ---@param on_error fun(requests: Request, vararg: any)|nil
---@vararg any
function Request.with_all(requests, on_success, on_error, ...) function Request.with_all(requests, on_success, on_error, ...)
local parameters = table.pack(...) local parameters = table.pack(...)

View File

@ -3,7 +3,7 @@ require("playercards/PlayerCardSpawner")
local allCardsBagApi = require("playercards/AllCardsBagApi") local allCardsBagApi = require("playercards/AllCardsBagApi")
local arkhamDb = require("arkhamdb/ArkhamDb") local arkhamDb = require("arkhamdb/ArkhamDb")
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local zones = require("playermat/Zones") local zones = require("playermat/Zones")
local matsWithInvestigator = {} local matsWithInvestigator = {}
@ -189,7 +189,7 @@ end
function loadDecks() function loadDecks()
if not allCardsBagApi.isIndexReady() then return end if not allCardsBagApi.isIndexReady() then return end
matsWithInvestigator = playmatApi.getUsedMatColors() matsWithInvestigator = playermatApi.getUsedMatColors()
if redDeckId ~= nil and redDeckId ~= "" then if redDeckId ~= nil and redDeckId ~= "" then
buildDeck("Red", redDeckId) buildDeck("Red", redDeckId)
end end
@ -354,7 +354,7 @@ end
---@param deck tts__Object Callback-provided spawned deck object ---@param deck tts__Object Callback-provided spawned deck object
---@param playerColor string Color of the player to draw the cards to ---@param playerColor string Color of the player to draw the cards to
function deckSpawned(deck, playerColor) function deckSpawned(deck, playerColor)
local player = Player[playmatApi.getPlayerColor(playerColor)] local player = Player[playermatApi.getPlayerColor(playerColor)]
local handPos = player.getHandTransform(1).position -- Only one hand zone per player local handPos = player.getHandTransform(1).position -- Only one hand zone per player
local deckCards = deck.getData().ContainedObjects local deckCards = deck.getData().ContainedObjects
@ -453,7 +453,7 @@ function removeBusyZones(playerColor, zoneDecks)
-- check for existing deck -- check for existing deck
local cardsInDeckArea = 0 local cardsInDeckArea = 0
for _, obj in pairs(playmatApi.getDeckAreaObjects(playerColor)) do for _, obj in pairs(playermatApi.getDeckAreaObjects(playerColor)) do
cardsInDeckArea = cardsInDeckArea + #obj.getObjects() cardsInDeckArea = cardsInDeckArea + #obj.getObjects()
end end
@ -732,7 +732,7 @@ end
---@param resourceModifier number Modifier for the starting resources ---@param resourceModifier number Modifier for the starting resources
function updateStartingResources(playerColor, resourceModifier) function updateStartingResources(playerColor, resourceModifier)
if resourceModifier ~= 0 then if resourceModifier ~= 0 then
playmatApi.updateCounter(playerColor, "ResourceCounter", _, resourceModifier) playermatApi.updateCounter(playerColor, "ResourceCounter", _, resourceModifier)
printToAll("Modified starting resources", playerColor) printToAll("Modified starting resources", playerColor)
end end
end end

View File

@ -483,13 +483,12 @@ modeData = {
} }
function onSave() function onSave()
local globalState = JSON.encode(SPAWNED_PLAYER_CARD_GUIDS) return JSON.encode(SPAWNED_PLAYER_CARD_GUIDS)
return globalState
end end
function onLoad(save_state) function onLoad(savedData)
if save_state ~= '' then if savedData and savedData ~= '' then
SPAWNED_PLAYER_CARD_GUIDS = JSON.decode(save_state) SPAWNED_PLAYER_CARD_GUIDS = JSON.decode(savedData)
else else
SPAWNED_PLAYER_CARD_GUIDS = {} SPAWNED_PLAYER_CARD_GUIDS = {}
end end

View File

@ -1,10 +1,10 @@
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local ZONE, TRASH local ZONE, TRASH
local doomURL = "https://i.imgur.com/EoL7yaZ.png" local doomURL = "https://i.imgur.com/EoL7yaZ.png"
local IGNORE_TAG = "DoomCounter_ignore" local IGNORE_TAG = "DoomCounter_ignore"
local TOTAL_PLAY_AREA = { local TOTAL_PLAY_AREA = {
upperLeft = { upperLeft = {
x = -9, x = -9,
z = -35 z = -35
@ -66,15 +66,15 @@ end
-- removes doom from playermats / playarea -- removes doom from playermats / playarea
function removeDoom(options) function removeDoom(options)
if options.Playermats then if options.Playermats then
local count = removeDoomFromList(playmatApi.searchAroundPlaymat("All")) local count = removeDoomFromList(playermatApi.searchAroundPlayermat("All"))
if count > 0 then if count > 0 then
broadcastToAll(count .. " doom removed from playermats.", "White") broadcastToAll(count .. " doom removed from playermats.", "White")
end end
end end
if options.Playarea then if options.Playarea then
local count = removeDoomFromList(ZONE.getObjects()) local count = removeDoomFromList(ZONE.getObjects())
if count > 0 then if count > 0 then
broadcastToAll(count .. " doom removed from play area.", "White") broadcastToAll(count .. " doom removed from play area.", "White")
end end
end end
@ -96,7 +96,7 @@ end
-- helper function to check if a position is inside an area -- helper function to check if a position is inside an area
function inArea(point, bounds) function inArea(point, bounds)
return (point.x < bounds.upperLeft.x return (point.x < bounds.upperLeft.x
and point.x > bounds.lowerRight.x and point.x > bounds.lowerRight.x
and point.z > bounds.upperLeft.z and point.z > bounds.upperLeft.z
and point.z < bounds.lowerRight.z) and point.z < bounds.lowerRight.z)
end end

View File

@ -2,7 +2,7 @@ local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local navigationOverlayApi = require("core/NavigationOverlayApi") local navigationOverlayApi = require("core/NavigationOverlayApi")
local optionPanelApi = require("core/OptionPanelApi") local optionPanelApi = require("core/OptionPanelApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local searchLib = require("util/SearchLib") local searchLib = require("util/SearchLib")
local victoryDisplayApi = require("core/VictoryDisplayApi") local victoryDisplayApi = require("core/VictoryDisplayApi")
@ -26,28 +26,28 @@ function onLoad()
addHotkey("Upkeep (Multi-handed)", triggerUpkeepMultihanded) addHotkey("Upkeep (Multi-handed)", triggerUpkeepMultihanded)
end end
-- triggers the "Upkeep" function of the calling player's playmat -- triggers the "Upkeep" function of the calling player's playermat
function triggerUpkeep(playerColor) function triggerUpkeep(playerColor)
if playerColor == "Black" then if playerColor == "Black" then
broadcastToColor("Triggering 'Upkeep (Multihanded)' instead", playerColor, "Yellow") broadcastToColor("Triggering 'Upkeep (Multihanded)' instead", playerColor, "Yellow")
triggerUpkeepMultihanded(playerColor) triggerUpkeepMultihanded(playerColor)
return return
end end
local matColor = playmatApi.getMatColor(playerColor) local matColor = playermatApi.getMatColor(playerColor)
playmatApi.doUpkeepFromHotkey(matColor, playerColor) playermatApi.doUpkeepFromHotkey(matColor, playerColor)
end end
-- triggers the "Upkeep" function of the calling player's playmat AND -- triggers the "Upkeep" function of the calling player's playermat AND
-- for all playmats that don't have a seated player, but an investigator card -- for all playermats that don't have a seated player, but an investigator card
function triggerUpkeepMultihanded(playerColor) function triggerUpkeepMultihanded(playerColor)
if playerColor ~= "Black" then if playerColor ~= "Black" then
triggerUpkeep(playerColor) triggerUpkeep(playerColor)
end end
local colors = Player.getAvailableColors() local colors = Player.getAvailableColors()
for _, handColor in ipairs(colors) do for _, handColor in ipairs(colors) do
local matColor = playmatApi.getMatColor(handColor) local matColor = playermatApi.getMatColor(handColor)
if playmatApi.returnInvestigatorId(matColor) ~= "00000" and Player[handColor].seated == false then if playermatApi.returnInvestigatorId(matColor) ~= "00000" and Player[handColor].seated == false then
playmatApi.doUpkeepFromHotkey(matColor, playerColor) playermatApi.doUpkeepFromHotkey(matColor, playerColor)
end end
end end
end end
@ -69,11 +69,11 @@ function takeCardIntoThreatArea(playerColor, hoveredObject)
return return
end end
local matColor = playmatApi.getMatColor(playerColor) local matColor = playermatApi.getMatColor(playerColor)
local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat") local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")
-- do not continue if the threat area is already full -- do not continue if the threat area is already full
if playmatApi.getEncounterCardDrawPosition(matColor, false) == playmatApi.getEncounterCardDrawPosition(matColor, true) then if playermatApi.getEncounterCardDrawPosition(matColor, false) == playermatApi.getEncounterCardDrawPosition(matColor, true) then
broadcastToColor("Threat area is full.", playerColor, "Yellow") broadcastToColor("Threat area is full.", playerColor, "Yellow")
return return
end end
@ -84,10 +84,10 @@ function takeCardIntoThreatArea(playerColor, hoveredObject)
table.insert(moveTheseObjects, obj) table.insert(moveTheseObjects, obj)
end end
-- find out if the original card is on the green or red playmats -- find out if the original card is on the green or red playermats
local originalMatColor = guidReferenceApi.getOwnerOfObject(hoveredObject) local originalMatColor = guidReferenceApi.getOwnerOfObject(hoveredObject)
-- determine modifiers for the playmats -- determine modifiers for the playermats
local modifierY = 0 local modifierY = 0
if originalMatColor == "Red" then if originalMatColor == "Red" then
modifierY = 90 modifierY = 90
@ -103,7 +103,7 @@ function takeCardIntoThreatArea(playerColor, hoveredObject)
end end
-- move the main card -- move the main card
local pos = playmatApi.getEncounterCardDrawPosition(matColor, false) local pos = playermatApi.getEncounterCardDrawPosition(matColor, false)
hoveredObject.setPosition(pos) hoveredObject.setPosition(pos)
hoveredObject.setRotation(hoveredObject.getRotation() - Vector(0, 270 - mat.getRotation().y - modifierY, 0)) hoveredObject.setRotation(hoveredObject.getRotation() - Vector(0, 270 - mat.getRotation().y - modifierY, 0))
@ -156,7 +156,7 @@ function performDiscard(playerColor, hoveredObject)
end end
local discardForMatColor = getColorToDiscardFor(hoveredObject, playerColor) local discardForMatColor = getColorToDiscardFor(hoveredObject, playerColor)
playmatApi.discardListOfObjects(discardForMatColor, discardTheseObjects) playermatApi.discardListOfObjects(discardForMatColor, discardTheseObjects)
end end
-- discard the top card of hovered deck, calling discardObject function -- discard the top card of hovered deck, calling discardObject function
@ -180,22 +180,22 @@ end
-- helper function to get the player to trigger the discard function for -- helper function to get the player to trigger the discard function for
function getColorToDiscardFor(hoveredObject, playerColor) function getColorToDiscardFor(hoveredObject, playerColor)
local pos = hoveredObject.getPosition() local pos = hoveredObject.getPosition()
local closestMatColor = playmatApi.getMatColorByPosition(pos) local closestMatColor = playermatApi.getMatColorByPosition(pos)
-- check if actually on the closest playmat -- check if actually on the closest playermat
local closestMat = guidReferenceApi.getObjectByOwnerAndType(closestMatColor, "Playermat") local closestMat = guidReferenceApi.getObjectByOwnerAndType(closestMatColor, "Playermat")
local bounds = closestMat.getBounds() local bounds = closestMat.getBounds()
-- define the area "near" the playmat -- define the area "near" the playermat
local bufferAroundPlaymat = 2 local bufferAroundPlayermat = 2
local areaNearPlaymat = {} local areaNearPlayermat = {}
areaNearPlaymat.minX = bounds.center.x - bounds.size.x / 2 - bufferAroundPlaymat areaNearPlayermat.minX = bounds.center.x - bounds.size.x / 2 - bufferAroundPlayermat
areaNearPlaymat.maxX = bounds.center.x + bounds.size.x / 2 + bufferAroundPlaymat areaNearPlayermat.maxX = bounds.center.x + bounds.size.x / 2 + bufferAroundPlayermat
areaNearPlaymat.minZ = bounds.center.z - bounds.size.z / 2 - bufferAroundPlaymat areaNearPlayermat.minZ = bounds.center.z - bounds.size.z / 2 - bufferAroundPlayermat
areaNearPlaymat.maxZ = bounds.center.z + bounds.size.z / 2 + bufferAroundPlaymat areaNearPlayermat.maxZ = bounds.center.z + bounds.size.z / 2 + bufferAroundPlayermat
-- discard to closest mat if near it -- discard to closest mat if near it
if inArea(pos, areaNearPlaymat) then if inArea(pos, areaNearPlayermat) then
return closestMatColor return closestMatColor
end end
@ -208,7 +208,7 @@ function getColorToDiscardFor(hoveredObject, playerColor)
end end
-- discard to triggering mat if previous conditions weren't met -- discard to triggering mat if previous conditions weren't met
return playmatApi.getMatColor(playerColor) return playermatApi.getMatColor(playerColor)
end end
-- moves the hovered card to the victory display -- moves the hovered card to the victory display
@ -286,7 +286,7 @@ function removeOneUse(playerColor, hoveredObject)
broadcastToAll(playerName .. " removed a token: " .. tokenName, playerColor) broadcastToAll(playerName .. " removed a token: " .. tokenName, playerColor)
local discardForMatColor = getColorToDiscardFor(hoveredObject, playerColor) local discardForMatColor = getColorToDiscardFor(hoveredObject, playerColor)
playmatApi.discardListOfObjects(discardForMatColor, { targetObject }) playermatApi.discardListOfObjects(discardForMatColor, { targetObject })
end end
-- switches the triggering player to the next seat (clockwise) -- switches the triggering player to the next seat (clockwise)
@ -314,7 +314,7 @@ function switchSeat(playerColor, direction)
end end
-- get used playermats -- get used playermats
local usedColors = playmatApi.getUsedMatColors() local usedColors = playermatApi.getUsedMatColors()
table.sort(usedColors, sortByHandPosition) table.sort(usedColors, sortByHandPosition)
-- get current seat index -- get current seat index
@ -407,7 +407,7 @@ function takeClueFromLocation(playerColor, hoveredObject)
local playerName, matColor, pos local playerName, matColor, pos
if Player[playerColor] and Player[playerColor].seated then if Player[playerColor] and Player[playerColor].seated then
playerName = Player[playerColor].steam_name playerName = Player[playerColor].steam_name
matColor = playmatApi.getMatColor(playerColor) matColor = playermatApi.getMatColor(playerColor)
else else
playerName = playerColor playerName = playerColor
matColor = playerColor matColor = playerColor
@ -415,12 +415,12 @@ function takeClueFromLocation(playerColor, hoveredObject)
if clickableClues then if clickableClues then
pos = { x = 0.49, y = 2.66, z = 0.00 } pos = { x = 0.49, y = 2.66, z = 0.00 }
playmatApi.updateCounter(matColor, "ClickableClueCounter", _, 1) playermatApi.updateCounter(matColor, "ClickableClueCounter", _, 1)
else else
pos = playmatApi.transformLocalPosition({ x = -1.12, y = 0.05, z = 0.7 }, matColor) pos = playermatApi.transformLocalPosition({ x = -1.12, y = 0.05, z = 0.7 }, matColor)
end end
local rot = playmatApi.returnRotation(matColor) local rot = playermatApi.returnRotation(matColor)
-- check if found clue is a stack or single token -- check if found clue is a stack or single token
if clue.getQuantity() > 1 then if clue.getQuantity() > 1 then

View File

@ -3,7 +3,7 @@ local guidReferenceApi = require("core/GUIDReferenceApi")
local mythosAreaApi = require("core/MythosAreaApi") local mythosAreaApi = require("core/MythosAreaApi")
local navigationOverlayApi = require("core/NavigationOverlayApi") local navigationOverlayApi = require("core/NavigationOverlayApi")
local playAreaApi = require("core/PlayAreaApi") local playAreaApi = require("core/PlayAreaApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local searchLib = require("util/SearchLib") local searchLib = require("util/SearchLib")
local soundCubeApi = require("core/SoundCubeApi") local soundCubeApi = require("core/SoundCubeApi")
local tokenArrangerApi = require("accessories/TokenArrangerApi") local tokenArrangerApi = require("accessories/TokenArrangerApi")
@ -196,7 +196,7 @@ function onObjectEnterZone(zone, object)
object.type == "Tile" and object.type == "Tile" and
object.getMemo() and object.getMemo() and
not object.getLock() then not object.getLock() then
local matcolor = playmatApi.getMatColorByPosition(object.getPosition()) local matcolor = playermatApi.getMatColorByPosition(object.getPosition())
local trash = guidReferenceApi.getObjectByOwnerAndType(matcolor, "Trash") local trash = guidReferenceApi.getObjectByOwnerAndType(matcolor, "Trash")
trash.putObject(object) trash.putObject(object)
elseif zone.type == "Hand" and object.hasTag("CardWithHelper") then elseif zone.type == "Hand" and object.hasTag("CardWithHelper") then
@ -219,10 +219,10 @@ function onObjectNumberTyped(hoveredObject, playerColor, number)
if hoveredObject.type ~= "Deck" and hoveredObject.type ~= "Card" then return end if hoveredObject.type ~= "Deck" and hoveredObject.type ~= "Card" then return end
-- check whether the hovered object is part of a players draw objects -- check whether the hovered object is part of a players draw objects
for _, color in ipairs(playmatApi.getUsedMatColors()) do for _, color in ipairs(playermatApi.getUsedMatColors()) do
local deckAreaObjects = playmatApi.getDeckAreaObjects(color) local deckAreaObjects = playermatApi.getDeckAreaObjects(color)
if deckAreaObjects.topCard == hoveredObject or deckAreaObjects.draw == hoveredObject then if deckAreaObjects.topCard == hoveredObject or deckAreaObjects.draw == hoveredObject then
playmatApi.drawCardsWithReshuffle(color, number) playermatApi.drawCardsWithReshuffle(color, number)
return true return true
end end
end end
@ -238,9 +238,9 @@ function onObjectNumberTyped(hoveredObject, playerColor, number)
end end
end end
-- TTS event, used to redraw the playmat slot symbols after a small delay to account for the custom font loading -- TTS event, used to redraw the playermat slot symbols after a small delay to account for the custom font loading
function onPlayerConnect() function onPlayerConnect()
Wait.time(function() playmatApi.redrawSlotSymbols("All") end, 0.2) Wait.time(function() playermatApi.redrawSlotSymbols("All") end, 0.2)
end end
--------------------------------------------------------- ---------------------------------------------------------
@ -381,7 +381,7 @@ function returnAndRedraw(_, tokenGUID)
local returnedToken = getObjectFromGUID(tokenGUID) local returnedToken = getObjectFromGUID(tokenGUID)
local tokenName = returnedToken.getName() local tokenName = returnedToken.getName()
local indexOfReturnedToken = getTokenIndex(returnedToken) local indexOfReturnedToken = getTokenIndex(returnedToken)
local matColor = playmatApi.getMatColorByPosition(returnedToken.getPosition()) local matColor = playermatApi.getMatColorByPosition(returnedToken.getPosition())
local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat") local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")
local takeParameters = { local takeParameters = {
@ -461,7 +461,7 @@ function drawChaosToken(params)
local matGUID = params.mat.getGUID() local matGUID = params.mat.getGUID()
-- return token(s) on other playmat first -- return token(s) on other playermat first
if chaosTokensLastMatGUID ~= nil and chaosTokensLastMatGUID ~= matGUID and #chaosTokens ~= 0 then if chaosTokensLastMatGUID ~= nil and chaosTokensLastMatGUID ~= matGUID and #chaosTokens ~= 0 then
returnChaosTokens() returnChaosTokens()
chaosTokensLastMatGUID = nil chaosTokensLastMatGUID = nil
@ -563,8 +563,8 @@ function handleStatTrackerClick(_, _, isRightClick)
playerColor = "White" playerColor = "White"
playerName = "Overall" playerName = "Overall"
else else
local matColor = playmatApi.getMatColorByPosition(getObjectFromGUID(key).getPosition()) local matColor = playermatApi.getMatColorByPosition(getObjectFromGUID(key).getPosition())
playerColor = playmatApi.getPlayerColor(matColor) playerColor = playermatApi.getPlayerColor(matColor)
playerName = Player[playerColor].steam_name or playerColor playerName = Player[playerColor].steam_name or playerColor
local playerSquidCount = personalStats["Auto-fail"] or 0 local playerSquidCount = personalStats["Auto-fail"] or 0
@ -1346,8 +1346,7 @@ function contentDownloadCallback(request, params)
if pos then if pos then
spawnTable.position = pos spawnTable.position = pos
else else
broadcastToAll( broadcastToAll("Please make space in the area below the tentacle stand in the upper middle of the table and try again.", "Red")
"Please make space in the area below the tentacle stand in the upper middle of the table and try again.", "Red")
return return
end end
end end
@ -1498,9 +1497,10 @@ function playermatRemovalSelected(player, selectedIndex, id)
if mat then if mat then
-- confirmation dialog about deletion -- confirmation dialog about deletion
player.pingTable(mat.getPosition()) player.pingTable(mat.getPosition())
player.showConfirmDialog( player.showConfirmDialog("Do you really want to remove " .. matColor .. "'s playermat and related objects? This can't be reversed.",
"Do you really want to remove " .. matColor .. "'s playermat and related objects? This can't be reversed.", function()
function() removePlayermat(matColor) end) removePlayermat(matColor)
end)
else else
-- info dialog that it is already deleted -- info dialog that it is already deleted
player.showInfoDialog(matColor .. "'s playermat has already been removed.") player.showInfoDialog(matColor .. "'s playermat has already been removed.")
@ -1517,7 +1517,7 @@ function removePlayermat(matColor)
if not matObjects.Playermat then return end if not matObjects.Playermat then return end
-- remove action tokens -- remove action tokens
local actionTokens = playmatApi.searchAroundPlaymat(matColor, "isUniversalToken") local actionTokens = playermatApi.searchAroundPlayermat(matColor, "isUniversalToken")
for _, obj in ipairs(actionTokens) do for _, obj in ipairs(actionTokens) do
obj.destruct() obj.destruct()
end end
@ -1557,19 +1557,24 @@ function applyOptionPanelChange(id, state)
-- option: Snap tags -- option: Snap tags
if id == "useSnapTags" then if id == "useSnapTags" then
playmatApi.setLimitSnapsByType(state, "All") playermatApi.setLimitSnapsByType(state, "All")
-- option: Draw 1 button -- option: Draw 1 button
elseif id == "showDrawButton" then elseif id == "showDrawButton" then
playmatApi.showDrawButton(state, "All") playermatApi.showDrawButton(state, "All")
-- option: Use class texture
elseif id == "useClassTexture" then
playermatApi.useClassTexture(state, "All")
-- option: Clickable clue counters -- option: Clickable clue counters
elseif id == "useClueClickers" then elseif id == "useClueClickers" then
playmatApi.clickableClues(state, "All") playermatApi.clickableClues(state, "All")
-- update master clue counter -- update master clue counter
local counter = guidReferenceApi.getObjectByOwnerAndType("Mythos", "MasterClueCounter") local counter = guidReferenceApi.getObjectByOwnerAndType("Mythos", "MasterClueCounter")
counter.setVar("useClickableCounters", state) counter.setVar("useClickableCounters", state)
elseif id == "enableCardHelpers" then elseif id == "enableCardHelpers" then
toggleCardHelpers(state) toggleCardHelpers(state)
@ -1616,7 +1621,7 @@ end
---@param helperName string Name of the helper object ---@param helperName string Name of the helper object
---@param state boolean Contains the state of the option: true = spawn it, false = remove it ---@param state boolean Contains the state of the option: true = spawn it, false = remove it
function spawnOrRemoveHelperForPlayermats(helperName, state) function spawnOrRemoveHelperForPlayermats(helperName, state)
for color, data in pairs(playmatApi.getHelperSpawnData("All", helperName)) do for color, data in pairs(playermatApi.getHelperSpawnData("All", helperName)) do
spawnOrRemoveHelper(state, helperName, data.position, data.rotation, color) spawnOrRemoveHelper(state, helperName, data.position, data.rotation, color)
end end
end end
@ -1709,6 +1714,7 @@ function onClick_defaultSettings()
showHandHelper = false, showHandHelper = false,
showSearchAssistant = false, showSearchAssistant = false,
showTitleSplash = true, showTitleSplash = true,
useClassTexture = true,
useClueClickers = false, useClueClickers = false,
useResourceCounters = "disabled", useResourceCounters = "disabled",
useSnapTags = true useSnapTags = true

View File

@ -1,4 +1,4 @@
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
-- variables are intentionally global to be accessible -- variables are intentionally global to be accessible
count = 0 count = 0
@ -31,12 +31,12 @@ end
-- removes all player clues by calling the respective function from the counting bowls / clickers -- removes all player clues by calling the respective function from the counting bowls / clickers
function removeAllPlayerClues() function removeAllPlayerClues()
printToAll(count .. " clue(s) from playermats removed.", "White") printToAll(count .. " clue(s) from playermats removed.", "White")
playmatApi.removeClues("All") playermatApi.removeClues("All")
self.editButton({ index = 0, label = "0" }) self.editButton({ index = 0, label = "0" })
end end
-- gets the counted values from the counting bowls / clickers and sums them up -- gets the counted values from the counting bowls / clickers and sums them up
function sumClues() function sumClues()
count = playmatApi.getClueCount(useClickableCounters, "All") count = playermatApi.getClueCount(useClickableCounters, "All")
self.editButton({ index = 0, label = tostring(count) }) self.editButton({ index = 0, label = tostring(count) })
end end

View File

@ -1,7 +1,7 @@
local deckLib = require("util/DeckLib") 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 playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local searchLib = require("util/SearchLib") local searchLib = require("util/SearchLib")
local tokenArrangerApi = require("accessories/TokenArrangerApi") local tokenArrangerApi = require("accessories/TokenArrangerApi")
local tokenChecker = require("core/token/TokenChecker") local tokenChecker = require("core/token/TokenChecker")
@ -22,7 +22,14 @@ local ENCOUNTER_DISCARD_POSITION = { x = -3.85, y = 1, z = 10.38 }
local isReshuffling = false local isReshuffling = false
local collisionEnabled = false local collisionEnabled = false
local currentScenario, useFrontData, tokenData local currentScenario, useFrontData, tokenData
local TRASH, DATA_HELPER
function onSave()
return JSON.encode({
currentScenario = currentScenario,
useFrontData = useFrontData,
tokenData = tokenData
})
end
function onLoad(savedData) function onLoad(savedData)
if savedData and savedData ~= "" then if savedData and savedData ~= "" then
@ -31,20 +38,9 @@ function onLoad(savedData)
useFrontData = loadedState.useFrontData or true useFrontData = loadedState.useFrontData or true
tokenData = loadedState.tokenData or {} tokenData = loadedState.tokenData or {}
end end
TRASH = guidReferenceApi.getObjectByOwnerAndType("Mythos", "Trash")
DATA_HELPER = guidReferenceApi.getObjectByOwnerAndType("Mythos", "DataHelper")
Wait.time(function() collisionEnabled = true end, 0.1) Wait.time(function() collisionEnabled = true end, 0.1)
end end
function onSave()
return JSON.encode({
currentScenario = currentScenario,
useFrontData = useFrontData,
tokenData = tokenData
})
end
--------------------------------------------------------- ---------------------------------------------------------
-- collison and container event handling -- collison and container event handling
--------------------------------------------------------- ---------------------------------------------------------
@ -179,9 +175,10 @@ function drawEncounterCard(params)
end end
end end
-- draw the provided card to the requesting playmat -- draw the provided card to the requesting playermat
function actualEncounterCardDraw(card, params) function actualEncounterCardDraw(card, params)
local metadata = JSON.decode(card.getGMNotes()) or {} local metadata = JSON.decode(card.getGMNotes()) or {}
local DATA_HELPER = guidReferenceApi.getObjectByOwnerAndType("Mythos", "DataHelper")
-- draw hidden cards facedown -- draw hidden cards facedown
local faceUpRotation = 0 local faceUpRotation = 0
@ -189,7 +186,7 @@ function actualEncounterCardDraw(card, params)
faceUpRotation = 180 faceUpRotation = 180
end end
local rot = playmatApi.returnRotation(params.matColor):setAt("z", faceUpRotation) local rot = playermatApi.returnRotation(params.matColor):setAt("z", faceUpRotation)
deckLib.placeOrMergeIntoDeck(card, params.position, rot) deckLib.placeOrMergeIntoDeck(card, params.position, rot)
end end
@ -249,6 +246,7 @@ end
-- removes tokens from the provided card/deck -- removes tokens from the provided card/deck
function removeTokensFromObject(object) function removeTokensFromObject(object)
local TRASH = guidReferenceApi.getObjectByOwnerAndType("Mythos", "Trash")
for _, obj in ipairs(searchLib.onObject(object)) do for _, obj in ipairs(searchLib.onObject(object)) do
if obj.getGUID() ~= "4ee1f2" and -- table if obj.getGUID() ~= "4ee1f2" and -- table
obj ~= self and obj ~= self and

View File

@ -1,4 +1,4 @@
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
fullButtonData = { fullButtonData = {
{ id = "1", width = "84", height = "33", offset = "1 2" }, -- 1. Act/Agenda { id = "1", width = "84", height = "33", offset = "1 2" }, -- 1. Act/Agenda
@ -44,10 +44,10 @@ playButtonData = {
cameraData = { cameraData = {
{ position = { -1.6, 1.55, 0 }, distance = 18 }, -- 1. Act/Agenda { position = { -1.6, 1.55, 0 }, distance = 18 }, -- 1. Act/Agenda
{ position = { -28, 1.55, 0 }, distance = -1 }, -- 2. Map { position = { -28, 1.55, 0 }, distance = -1 }, -- 2. Map
{ position = { -31.6, 1.55, 26.4 }, distance = -1 }, -- 3. Green playmat { position = { -31.6, 1.55, 26.4 }, distance = -1 }, -- 3. Green playermat
{ position = { -55, 1.55, 12.05 }, distance = -1 }, -- 4. White playmat { position = { -55, 1.55, 12.05 }, distance = -1 }, -- 4. White playermat
{ position = { -55, 1.55, -11.48 }, distance = -1 }, -- 5. Orange playmat { position = { -55, 1.55, -11.48 }, distance = -1 }, -- 5. Orange playermat
{ position = { -31.6, 1.55, -26.4 }, distance = -1 }, -- 6. Red playmat { position = { -31.6, 1.55, -26.4 }, distance = -1 }, -- 6. Red playermat
{ position = { -3, 1.55, 30 }, distance = 16 }, -- 7. Victory / SetAside { position = { -3, 1.55, 30 }, distance = 16 }, -- 7. Victory / SetAside
{ position = { -3, 1.55, -26.76 }, distance = 16 }, -- 8. Guide { position = { -3, 1.55, -26.76 }, distance = 16 }, -- 8. Guide
{ position = { -11.83, 1.55, 0 }, distance = 10 }, -- 9. Player count { position = { -11.83, 1.55, 0 }, distance = 10 }, -- 9. Player count
@ -89,13 +89,9 @@ function onLoad(savedData)
pitch = loadedData.pitch pitch = loadedData.pitch
distance = loadedData.distance distance = loadedData.distance
else else
local allColors = Player.getColors() -- initialize tables with defaults
for _, color in ipairs(Player.getColors()) do
for _, color in ipairs(allColors) do
-- default state for claims
claims[color] = {} claims[color] = {}
-- default state for visibility
visibility[color] = { full = false, play = false } visibility[color] = { full = false, play = false }
end end
end end
@ -338,19 +334,19 @@ function loadCamera(player, camera)
end end
-- swap to that color if it isn't claimed by someone else and it's currently unoccopied -- swap to that color if it isn't claimed by someone else and it's currently unoccopied
if #getSeatedPlayers() == 1 or (not isClaimed and isPlaymatAvailable(matColor)) then if #getSeatedPlayers() == 1 or (not isClaimed and isPlayermatAvailable(matColor)) then
local newPlayerColor = playmatApi.getPlayerColor(matColor) local newPlayerColor = playermatApi.getPlayerColor(matColor)
copyVisibility({ startColor = player.color, targetColor = newPlayerColor }) copyVisibility({ startColor = player.color, targetColor = newPlayerColor })
player.changeColor(newPlayerColor) player.changeColor(newPlayerColor)
player = Player[newPlayerColor] player = Player[newPlayerColor]
end end
-- search on the playmat for objects -- search on the playermat for objects
local bounds = getDynamicViewBounds(playmatApi.searchAroundPlaymat(matColor)) local bounds = getDynamicViewBounds(playermatApi.searchAroundPlayermat(matColor))
lookHere = { lookHere = {
position = { bounds.middleX, 0, bounds.middleZ }, position = { bounds.middleX, 0, bounds.middleZ },
yaw = playmatApi.returnRotation(matColor).y + 180, yaw = playermatApi.returnRotation(matColor).y + 180,
distance = 0.42 * math.max(bounds.diffX, bounds.diffZ) + 7 distance = 0.42 * math.max(bounds.diffX, bounds.diffZ) + 7
} }
end end
@ -371,9 +367,9 @@ function loadCamera(player, camera)
Wait.frames(function() player.lookAt(lookHere) end, 2) Wait.frames(function() player.lookAt(lookHere) end, 2)
end end
-- helper function to check if a playmat is available for a color swap -- helper function to check if a playermat is available for a color swap
function isPlaymatAvailable(matColor) function isPlayermatAvailable(matColor)
local newPlayerColor = playmatApi.getPlayerColor(matColor) local newPlayerColor = playermatApi.getPlayerColor(matColor)
for _, color in ipairs(getSeatedPlayers()) do for _, color in ipairs(getSeatedPlayers()) do
if color == newPlayerColor then if color == newPlayerColor then
return false return false

View File

@ -133,7 +133,7 @@ function onObjectPickUp(_, object)
local metadata = JSON.decode(object.getGMNotes()) or {} local metadata = JSON.decode(object.getGMNotes()) or {}
if metadata.type == "Location" then if metadata.type == "Location" then
-- onCollisionExit sometimes comes 1 frame after onObjectPickUp (rather than before it or in -- 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. -- 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 -- Waiting ensures we always do thing in the expected Exit->PickUp order
Wait.frames(function() Wait.frames(function()
@ -240,7 +240,7 @@ end
---@param card tts__Object Card to (maybe) stop tracking ---@param card tts__Object Card to (maybe) stop tracking
function maybeUntrackLocation(card) function maybeUntrackLocation(card)
-- Locked objects no longer collide (hence triggering an exit event) but are still in the play -- 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 if locations[card.getGUID()] ~= nil and not card.locked then
locations[card.getGUID()] = nil locations[card.getGUID()] = nil
rebuildConnectionList() rebuildConnectionList()
@ -415,7 +415,7 @@ end
---@param target tts__Object Target card object to connect ---@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 ---@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 --- 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) function addOneWayVector(origin, target, vectorOwner, lines)
-- Start with the BiDi then add the arrow lines to it -- Start with the BiDi then add the arrow lines to it
addBidirectionalVector(origin, target, vectorOwner, lines) addBidirectionalVector(origin, target, vectorOwner, lines)
@ -445,9 +445,9 @@ end
-- Draws an arrowhead at the given position. -- Draws an arrowhead at the given position.
---@param arrowheadPos tts__Vector Centerpoint of the arrowhead to draw (NOT the tip of the arrow) ---@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 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 --- 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) 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 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 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 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 ---@param highlightOff boolean True if highlighting should be enabled
---@return. Returns the total amount of VP found in the play area ---@return. Returns the total amount of VP found in the play area
function countVP(highlightOff) function countVP(highlightOff)
@ -488,14 +488,15 @@ function countVP(highlightOff)
return totalVP return totalVP
end 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 ---@param card tts__Object Card to check for clues
---@return boolean hasClues True if card has clues on it
function cardHasClues(card) function cardHasClues(card)
local searchResult = searchLib.onObject(card, "isClue") local searchResult = searchLib.onObject(card, "isClue")
return #searchResult > 0 return #searchResult > 0
end 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 ---@param state boolean True if highlighting should be enabled
function highlightMissingData(state) function highlightMissingData(state)
for i, obj in pairs(missingData) do for i, obj in pairs(missingData) do
@ -549,7 +550,7 @@ function shiftContents(playerColor, direction)
Wait.time(drawBaseConnections, 0.1) Wait.time(drawBaseConnections, 0.1)
end end
-- sets the image of the playarea -- Sets the image of the playarea
---@param newURL string URL for the new surface image ---@param newURL string URL for the new surface image
function updateSurface(newURL) function updateSurface(newURL)
local customInfo = self.getCustomObject() local customInfo = self.getCustomObject()
@ -569,6 +570,7 @@ function updateSurface(newURL)
guid = customDataHelper.getGUID() guid = customDataHelper.getGUID()
end end
self.script_state = onSave()
self.reload() self.reload()
if guid ~= nil then if guid ~= nil then
@ -646,7 +648,7 @@ function round(num, numDecimalPlaces)
return math.floor(num * mult + 0.5) / mult return math.floor(num * mult + 0.5) / mult
end 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() function buildSnaps()
local upperleft = { x = 1.53, z = -1.09 } local upperleft = { x = 1.53, z = -1.09 }
local lowerright = { x = -1.53, z = 1.55 } local lowerright = { x = -1.53, z = 1.55 }

View File

@ -10,13 +10,13 @@ do
return guidReferenceApi.getObjectByOwnerAndType("Mythos", "InvestigatorCounter") return guidReferenceApi.getObjectByOwnerAndType("Mythos", "InvestigatorCounter")
end end
-- Returns the current value of the investigator counter from the playmat -- Returns the current value of the investigator counter from the playermat
---@return number: Number of investigators currently set on the counter ---@return number: Number of investigators currently set on the counter
PlayAreaApi.getInvestigatorCount = function() PlayAreaApi.getInvestigatorCount = function()
return getInvestigatorCounter().getVar("val") return getInvestigatorCounter().getVar("val")
end end
-- Updates the current value of the investigator counter from the playmat -- Updates the current value of the investigator counter from the playermat
---@param count number Number of investigators to set on the counter ---@param count number Number of investigators to set on the counter
PlayAreaApi.setInvestigatorCount = function(count) PlayAreaApi.setInvestigatorCount = function(count)
getInvestigatorCounter().call("updateVal", count) getInvestigatorCounter().call("updateVal", count)
@ -57,7 +57,7 @@ do
getPlayArea().call("onScenarioChanged", scenarioName) getPlayArea().call("onScenarioChanged", scenarioName)
end end
-- Sets this playmat's snap points to limit snapping to locations or not. -- Sets this playermat's snap points to limit snapping to locations or not.
-- If matchTypes is false, snap points will be reset to snap all cards. -- If matchTypes is false, snap points will be reset to snap all cards.
---@param matchCardTypes boolean Whether snap points should only snap for the matching card types ---@param matchCardTypes boolean Whether snap points should only snap for the matching card types
PlayAreaApi.setLimitSnapsByType = function(matchCardTypes) PlayAreaApi.setLimitSnapsByType = function(matchCardTypes)

View File

@ -3,7 +3,12 @@ local optionPanelApi = require("core/OptionPanelApi")
local playAreaApi = require("core/PlayAreaApi") local playAreaApi = require("core/PlayAreaApi")
local typeIndex, selectionIndex, plainNameCache local typeIndex, selectionIndex, plainNameCache
function onSave() return JSON.encode({ typeIndex = typeIndex, selectionIndex = selectionIndex }) end function onSave()
return JSON.encode({
typeIndex = typeIndex,
selectionIndex = selectionIndex
})
end
function onLoad(savedData) function onLoad(savedData)
if savedData and savedData ~= "" then if savedData and savedData ~= "" then
@ -192,7 +197,7 @@ end
function getPlainName(str) function getPlainName(str)
-- remove prefix type 1 -- remove prefix type 1
str = str:gsub("%w+%-%w%s%-%s", "") -- matches "II-B - Thousand Shapes of Horror 1" str = str:gsub("%w+%-%w%s%-%s", "") -- matches "II-B - Thousand Shapes of Horror 1"
-- remove prefix type 2 -- remove prefix type 2
str = str:gsub("%w+%-%w%s", "") -- matches "59-Z Congress of Keys 1" str = str:gsub("%w+%-%w%s", "") -- matches "59-Z Congress of Keys 1"

View File

@ -2,7 +2,7 @@ do
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local optionPanelApi = require("core/OptionPanelApi") local optionPanelApi = require("core/OptionPanelApi")
local playAreaApi = require("core/PlayAreaApi") local playAreaApi = require("core/PlayAreaApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local searchLib = require("util/SearchLib") local searchLib = require("util/SearchLib")
local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi") local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi")
@ -133,13 +133,13 @@ do
local TokenManager = {} local TokenManager = {}
local internal = {} local internal = {}
-- Spawns tokens for the card. This function is built to just throw a card at it and let it do -- Spawns tokens for the card. This function is built to just throw a card at it and let it do
-- the work once a card has hit an area where it might spawn tokens. It will check to see if -- the work once a card has hit an area where it might spawn tokens. It will check to see if
-- the card has already spawned, find appropriate data from either the uses metadata or the Data -- the card has already spawned, find appropriate data from either the uses metadata or the Data
-- Helper, and spawn the tokens. -- Helper, and spawn the tokens.
---@param card tts__Object Card to maybe spawn tokens for ---@param card tts__Object Card to maybe spawn tokens for
---@param extraUses table A table of <use type>=<count> which will modify the number of tokens ---@param extraUses table A table of <use type>=<count> which will modify the number of tokens
--- spawned for that type. e.g. Akachi's playmat should pass "Charge"=1 --- spawned for that type. e.g. Akachi's playermat should pass "Charge"=1
TokenManager.spawnForCard = function(card, extraUses) TokenManager.spawnForCard = function(card, extraUses)
if tokenSpawnTrackerApi.hasSpawnedTokens(card.getGUID()) then if tokenSpawnTrackerApi.hasSpawnedTokens(card.getGUID()) then
return return
@ -155,10 +155,10 @@ do
-- Spawns a set of tokens on the given card. -- Spawns a set of tokens on the given card.
---@param card tts__Object Card to spawn tokens on ---@param card tts__Object Card to spawn tokens on
---@param tokenType string Type of token to spawn (template needs to be in source bag) ---@param tokenType string Type of token to spawn (template needs to be in source bag)
---@param tokenCount number How many tokens to spawn. For damage or horror this value will be set to the ---@param tokenCount number How many tokens to spawn. For damage or horror this value will be set to the
-- spawned state object rather than spawning multiple tokens -- spawned state object rather than spawning multiple tokens
---@param shiftDown? number An offset for the z-value of this group of tokens ---@param shiftDown? number An offset for the z-value of this group of tokens
---@param subType? string Subtype of token to spawn. This will only differ from the tokenName for resource tokens ---@param subType? string Subtype of token to spawn. This will only differ from the tokenName for resource tokens
TokenManager.spawnTokenGroup = function(card, tokenType, tokenCount, shiftDown, subType) TokenManager.spawnTokenGroup = function(card, tokenType, tokenCount, shiftDown, subType)
local optionPanel = optionPanelApi.getOptions() local optionPanel = optionPanelApi.getOptions()
@ -244,8 +244,8 @@ do
if tokenType == "resource" and stateID ~= nil and stateID ~= 1 then if tokenType == "resource" and stateID ~= nil and stateID ~= 1 then
callback = function(spawned) spawned.setState(stateID) end callback = function(spawned) spawned.setState(stateID) end
elseif tokenType == "universalActionAbility" then elseif tokenType == "universalActionAbility" then
local matColor = playmatApi.getMatColorByPosition(card.getPosition()) local matColor = playermatApi.getMatColorByPosition(card.getPosition())
local class = playmatApi.returnInvestigatorClass(matColor) local class = playermatApi.returnInvestigatorClass(matColor)
callback = function(spawned) spawned.call("updateClassAndSymbol", { class = class, symbol = subType or class }) end callback = function(spawned) spawned.call("updateClassAndSymbol", { class = class, symbol = subType or class }) end
end end
@ -294,7 +294,7 @@ do
-- Checks a card for metadata to maybe replenish it -- Checks a card for metadata to maybe replenish it
---@param card tts__Object Card object to be replenished ---@param card tts__Object Card object to be replenished
---@param uses table The already decoded metadata.uses (to avoid decoding again) ---@param uses table The already decoded metadata.uses (to avoid decoding again)
---@param mat tts__Object The playmat the card is placed on (for rotation and casting) ---@param mat tts__Object The playermat the card is placed on (for rotation and casting)
TokenManager.maybeReplenishCard = function(card, uses, mat) TokenManager.maybeReplenishCard = function(card, uses, mat)
-- TODO: support for cards with multiple uses AND replenish (as of yet, no official card needs that) -- TODO: support for cards with multiple uses AND replenish (as of yet, no official card needs that)
if uses[1].count and uses[1].replenish then if uses[1].count and uses[1].replenish then
@ -302,7 +302,7 @@ do
end end
end end
-- Delegate function to the token spawn tracker. Exists to avoid circular dependencies in some -- Delegate function to the token spawn tracker. Exists to avoid circular dependencies in some
-- callers. -- callers.
---@param card tts__Object Card object to reset the tokens for ---@param card tts__Object Card object to reset the tokens for
TokenManager.resetTokensSpawned = function(card) TokenManager.resetTokensSpawned = function(card)
@ -347,7 +347,7 @@ do
end end
end end
-- Copies the data from the DataHelper. Will only happen once. -- Copies the data from the DataHelper. Will only happen once.
internal.initDataHelperData = function() internal.initDataHelperData = function()
if playerCardData ~= nil then if playerCardData ~= nil then
return return
@ -357,11 +357,11 @@ do
locationData = dataHelper.getTable('LOCATIONS_DATA') locationData = dataHelper.getTable('LOCATIONS_DATA')
end end
-- Spawn tokens for a card based on the uses metadata. This will consider the face up/down state -- Spawn tokens for a card based on the uses metadata. This will consider the face up/down state
-- of the card for both locations and standard cards. -- of the card for both locations and standard cards.
---@param card tts__Object Card to maybe spawn tokens for ---@param card tts__Object Card to maybe spawn tokens for
---@param extraUses table A table of <use type>=<count> which will modify the number of tokens ---@param extraUses table A table of <use type>=<count> which will modify the number of tokens
--- spawned for that type. e.g. Akachi's playmat should pass "Charge"=1 --- spawned for that type. e.g. Akachi's playermat should pass "Charge"=1
internal.spawnTokensFromUses = function(card, extraUses) internal.spawnTokensFromUses = function(card, extraUses)
local uses = internal.getUses(card) local uses = internal.getUses(card)
if uses == nil then return end if uses == nil then return end
@ -380,7 +380,7 @@ do
tokenSpawnTrackerApi.markTokensSpawned(card.getGUID()) tokenSpawnTrackerApi.markTokensSpawned(card.getGUID())
end end
-- Spawn tokens for a card based on the data helper data. This will consider the face up/down state -- Spawn tokens for a card based on the data helper data. This will consider the face up/down state
-- of the card for both locations and standard cards. -- of the card for both locations and standard cards.
---@param card tts__Object Card to maybe spawn tokens for ---@param card tts__Object Card to maybe spawn tokens for
internal.spawnTokensFromDataHelper = function(card) internal.spawnTokensFromDataHelper = function(card)
@ -397,7 +397,7 @@ do
-- Spawn tokens for a player card using data retrieved from the Data Helper. -- Spawn tokens for a player card using data retrieved from the Data Helper.
---@param card tts__Object Card to maybe spawn tokens for ---@param card tts__Object Card to maybe spawn tokens for
---@param playerData table Player card data structure retrieved from the DataHelper. Should be ---@param playerData table Player card data structure retrieved from the DataHelper. Should be
-- the right data for this card. -- the right data for this card.
internal.spawnPlayerCardTokensFromDataHelper = function(card, playerData) internal.spawnPlayerCardTokensFromDataHelper = function(card, playerData)
local token = playerData.tokenType local token = playerData.tokenType
@ -408,7 +408,7 @@ do
-- Spawn tokens for a location using data retrieved from the Data Helper. -- Spawn tokens for a location using data retrieved from the Data Helper.
---@param card tts__Object Card to maybe spawn tokens for ---@param card tts__Object Card to maybe spawn tokens for
---@param locationData table Location data structure retrieved from the DataHelper. Should be ---@param locationData table Location data structure retrieved from the DataHelper. Should be
-- the right data for this card. -- the right data for this card.
internal.spawnLocationTokensFromDataHelper = function(card, locationData) internal.spawnLocationTokensFromDataHelper = function(card, locationData)
local clueCount = internal.getClueCountFromData(card, locationData) local clueCount = internal.getClueCountFromData(card, locationData)
@ -481,7 +481,7 @@ do
---@param card tts__Object Card object to be replenished ---@param card tts__Object Card object to be replenished
---@param uses table The already decoded metadata.uses (to avoid decoding again) ---@param uses table The already decoded metadata.uses (to avoid decoding again)
---@param mat tts__Object The playmat the card is placed on (for rotation and casting) ---@param mat tts__Object The playermat the card is placed on (for rotation and casting)
internal.replenishTokens = function(card, uses, mat) internal.replenishTokens = function(card, uses, mat)
local cardPos = card.getPosition() local cardPos = card.getPosition()

View File

@ -23,7 +23,9 @@ inputParameters.scale = { 0.1, 1, 0.1 }
inputParameters.color = { 0.9, 0.7, 0.5 } inputParameters.color = { 0.9, 0.7, 0.5 }
inputParameters.font_color = { 0, 0, 0 } inputParameters.font_color = { 0, 0, 0 }
function onSave() return JSON.encode({ spawnAll, searchExact, inputParameters.value }) end function onSave()
return JSON.encode({ spawnAll, searchExact, inputParameters.value })
end
function onLoad(savedData) function onLoad(savedData)
local loadedData = JSON.decode(savedData) local loadedData = JSON.decode(savedData)

View File

@ -76,7 +76,7 @@ Thus it should be implemented like this:
local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi") local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
local chaosBagApi = require("chaosbag/ChaosBagApi") local chaosBagApi = require("chaosbag/ChaosBagApi")
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local tokenArrangerApi = require("accessories/TokenArrangerApi") local tokenArrangerApi = require("accessories/TokenArrangerApi")
local sealedTokens = {} local sealedTokens = {}
@ -280,7 +280,7 @@ function resolveSealed()
broadcastToAll("No tokens sealed.", "Red") broadcastToAll("No tokens sealed.", "Red")
return return
end end
local closestMatColor = playmatApi.getMatColorByPosition(self.getPosition()) local closestMatColor = playermatApi.getMatColorByPosition(self.getPosition())
local mat = guidReferenceApi.getObjectByOwnerAndType(closestMatColor, "Playermat") local mat = guidReferenceApi.getObjectByOwnerAndType(closestMatColor, "Playermat")
local guidToBeResolved = table.remove(sealedTokens) local guidToBeResolved = table.remove(sealedTokens)
chaosBagApi.drawChaosToken(mat, true, _, guidToBeResolved) chaosBagApi.drawChaosToken(mat, true, _, guidToBeResolved)

View File

@ -1,7 +1,7 @@
require("playercards/CardsWithHelper") require("playercards/CardsWithHelper")
local chaosBagApi = require("chaosbag/ChaosBagApi") local chaosBagApi = require("chaosbag/ChaosBagApi")
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local isHelperEnabled = false local isHelperEnabled = false
@ -37,9 +37,9 @@ end
function resolveToken(player, _, tokenType) function resolveToken(player, _, tokenType)
local matColor local matColor
if player.color == "Black" then if player.color == "Black" then
matColor = playmatApi.getMatColorByPosition(self.getPosition()) matColor = playermatApi.getMatColorByPosition(self.getPosition())
else else
matColor = playmatApi.getMatColor(player.color) matColor = playermatApi.getMatColor(player.color)
end end
local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat") local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")

View File

@ -1,5 +1,5 @@
require("playercards/CardsWithHelper") require("playercards/CardsWithHelper")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
-- common button parameters -- common button parameters
local buttonParameters = {} local buttonParameters = {}
@ -109,9 +109,9 @@ function createButtons()
end end
function findUpgradeSheet() function findUpgradeSheet()
local matColor = playmatApi.getMatColorByPosition(self.getPosition()) local matColor = playermatApi.getMatColorByPosition(self.getPosition())
local result = playmatApi.searchAroundPlaymat(matColor, "isCard") local result = playermatApi.searchAroundPlaymat(matColor, "isCard")
for _, card in ipairs(result) do for j, card in ipairs(result) do
local metadata = JSON.decode(card.getGMNotes()) or {} local metadata = JSON.decode(card.getGMNotes()) or {}
if metadata.id == "09041-c" then if metadata.id == "09041-c" then
return card return card

View File

@ -1,4 +1,4 @@
local playmatApi = require("playermat/PlaymatApi") 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")
@ -46,8 +46,8 @@ end
function takeAll(playerColor) function takeAll(playerColor)
searchSelf() searchSelf()
local matColor = playmatApi.getMatColorByPosition(self.getPosition()) local matColor = playermatApi.getMatColorByPosition(self.getPosition())
playmatApi.updateCounter(matColor, "ResourceCounter", _, foundTokens) playermatApi.updateCounter(matColor, "ResourceCounter", _, foundTokens)
if clickableResourceCounter then if clickableResourceCounter then
clickableResourceCounter.call("updateVal", 0) clickableResourceCounter.call("updateVal", 0)

View File

@ -1,5 +1,5 @@
local mythosAreaApi = require("core/MythosAreaApi") local mythosAreaApi = require("core/MythosAreaApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
function onLoad() function onLoad()
-- get class via metadata and proceed menu accordingly: -- get class via metadata and proceed menu accordingly:
@ -29,8 +29,8 @@ function contextFunc(playerColor, amount)
-- check for players with a deck and only display them as option -- check for players with a deck and only display them as option
for _, color in ipairs(Player.getAvailableColors()) do for _, color in ipairs(Player.getAvailableColors()) do
local matColor = playmatApi.getMatColor(color) local matColor = playermatApi.getMatColor(color)
local deckAreaObjects = playmatApi.getDeckAreaObjects(matColor) local deckAreaObjects = playermatApi.getDeckAreaObjects(matColor)
if deckAreaObjects.draw or deckAreaObjects.topCard then if deckAreaObjects.draw or deckAreaObjects.topCard then
local playerName = Player[color].steam_name local playerName = Player[color].steam_name

View File

@ -1,4 +1,4 @@
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
function onLoad() function onLoad()
self.addContextMenuItem("Discard 10 cards", shortSupply) self.addContextMenuItem("Discard 10 cards", shortSupply)
@ -6,12 +6,12 @@ end
-- called by context menu entry -- called by context menu entry
function shortSupply(color) function shortSupply(color)
local matColor = playmatApi.getMatColorByPosition(self.getPosition()) local matColor = playermatApi.getMatColorByPosition(self.getPosition())
-- get draw deck and discard position -- get draw deck and discard position
local deckAreaObjects = playmatApi.getDeckAreaObjects(matColor) local deckAreaObjects = playermatApi.getDeckAreaObjects(matColor)
local drawDeck = deckAreaObjects.draw local drawDeck = deckAreaObjects.draw
local discardPos = playmatApi.getDiscardPosition(matColor) local discardPos = playermatApi.getDiscardPosition(matColor)
-- error handling -- error handling
if discardPos == nil then if discardPos == nil then

View File

@ -1,5 +1,5 @@
local deckLib = require("util/DeckLib") local deckLib = require("util/DeckLib")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
function onLoad() function onLoad()
self.addContextMenuItem("Return this card", returnSelf) self.addContextMenuItem("Return this card", returnSelf)
@ -18,9 +18,9 @@ end
-- places this card below the deck of the player that triggered it -- places this card below the deck of the player that triggered it
function placeBelowDeck(playerColor) function placeBelowDeck(playerColor)
local matColor = playmatApi.getMatColor(playerColor) local matColor = playermatApi.getMatColor(playerColor)
local deckPos = playmatApi.getDrawPosition(matColor) local deckPos = playermatApi.getDrawPosition(matColor)
local deckRot = playmatApi.returnRotation(matColor) local deckRot = playermatApi.returnRotation(matColor)
deckRot = deckRot:setAt("z", 180) deckRot = deckRot:setAt("z", 180)
deckLib.placeOrMergeIntoDeck(self, Vector(deckPos), deckRot, true) deckLib.placeOrMergeIntoDeck(self, Vector(deckPos), deckRot, true)
end end

View File

@ -1,5 +1,5 @@
require("playercards/CardsWithHelper") require("playercards/CardsWithHelper")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local buttonParameters = { local buttonParameters = {
click_function = "shutOff", click_function = "shutOff",
@ -46,8 +46,8 @@ function shutOff()
end end
function updateButton() function updateButton()
local matColor = playmatApi.getMatColorByPosition(self.getPosition()) local matColor = playermatApi.getMatColorByPosition(self.getPosition())
local resources = playmatApi.getCounterValue(matColor, "ResourceCounter") local resources = playermatApi.getCounterValue(matColor, "ResourceCounter")
local count = tostring(math.floor(resources / modValue)) local count = tostring(math.floor(resources / modValue))
self.editButton({ index = 0, label = count }) self.editButton({ index = 0, label = count })
end end

View File

@ -19,7 +19,7 @@
-- selectedUpgrades holds the state of checkboxes and text input, each element being: -- selectedUpgrades holds the state of checkboxes and text input, each element being:
-- selectedUpgrades[row] = { xp = #, text = "" } -- selectedUpgrades[row] = { xp = #, text = "" }
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
-- Y position for UI elements. Visibility of checkboxes moves the checkbox inside the card object -- Y position for UI elements. Visibility of checkboxes moves the checkbox inside the card object
-- when not selected. -- when not selected.
@ -230,7 +230,7 @@ function clickCheckbox(row, col)
selectedUpgrades[row].xp = col selectedUpgrades[row].xp = col
end end
updateCheckboxes(row) updateCheckboxes(row)
playmatApi.syncAllCustomizableCards() playermatApi.syncAllCustomizableCards()
end end
-- Updates saved value for given text box when it loses focus -- Updates saved value for given text box when it loses focus

View File

@ -1,10 +1,10 @@
local guidReferenceApi = require("core/GUIDReferenceApi") local guidReferenceApi = require("core/GUIDReferenceApi")
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local searchLib = require("util/SearchLib") local searchLib = require("util/SearchLib")
exposedValue = 0 exposedValue = 0
local playmat local playermat
local searchParam = {} local searchParam = {}
function onLoad() function onLoad()
@ -19,14 +19,14 @@ function onLoad()
font_size = 2000 font_size = 2000
}) })
-- get closest playmat -- get closest playermat
local matColor = playmatApi.getMatColorByPosition(self.getPosition()) local matColor = playermatApi.getMatColorByPosition(self.getPosition())
playmat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat") playermat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")
-- get search parameters (threat area excluded) -- get search parameters (threat area excluded)
local localPos = playmat.positionToLocal(playmat.getPosition()) local localPos = playermat.positionToLocal(playermat.getPosition())
searchParam.pos = playmat.positionToWorld(localPos + Vector(0, 0, 0.4)) searchParam.pos = playermat.positionToWorld(localPos + Vector(0, 0, 0.4))
searchParam.rot = playmat.getRotation() + Vector(0, 90, 0) searchParam.rot = playermat.getRotation() + Vector(0, 90, 0)
searchParam.size = Vector(8, 1, 27) searchParam.size = Vector(8, 1, 27)
searchParam.filter = "isClue" searchParam.filter = "isClue"
@ -34,7 +34,7 @@ function onLoad()
Wait.time(countItems, 1.5, -1) Wait.time(countItems, 1.5, -1)
end end
-- activated once per second, counts clues on the playmat -- activated once per second, counts clues on the playermat
function countItems() function countItems()
local totalValue = 0 local totalValue = 0
for _, item in ipairs(getClues()) do for _, item in ipairs(getClues()) do

View File

@ -46,7 +46,7 @@ local DRAWN_ENCOUNTER_POSITION = { x = 1.365, y = 0.5, z = -0.625 }
-- global position of encounter discard pile -- global position of encounter discard pile
local ENCOUNTER_DISCARD_POSITION = { x = -3.85, y = 1.5, z = 10.38 } local ENCOUNTER_DISCARD_POSITION = { x = -3.85, y = 1.5, z = 10.38 }
-- used for the buttons on the right side of the playmat -- used for the buttons on the right side of the playermat
-- starts off with the data for the "Upkeep" button and will then be changed -- starts off with the data for the "Upkeep" button and will then be changed
local buttonParameters = { local buttonParameters = {
label = "Upkeep", label = "Upkeep",
@ -60,6 +60,16 @@ local buttonParameters = {
font_size = 180 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/2444972799638881117/169F4520A94FB186B54E0F2BF4BAC809844C923E/",
Survivor = "http://cloud-3.steamusercontent.com/ugc/2444972799638880687/EEDF8F8BC3266069FECB09775845BE2501310C17/"
}
-- translation table for slot names to characters for special font -- translation table for slot names to characters for special font
local slotNameToChar = { local slotNameToChar = {
["any"] = "", ["any"] = "",
@ -86,12 +96,11 @@ local defaultSlotData = {
-- global variables for access -- global variables for access
activeInvestigatorClass = "Neutral" activeInvestigatorClass = "Neutral"
activeInvestigatorId = "00000" activeInvestigatorId = "00000"
local isDrawButtonVisible = false
-- global variable to report "Dream-Enhancing Serum" status
hasDES = false hasDES = false
local isClassTextureEnabled = true
local isDrawButtonVisible = false
-- table of type-object reference pairs of all owned objects -- table of type-object reference pairs of all owned objects
local ownedObjects = {} local ownedObjects = {}
local matColor = self.getMemo() local matColor = self.getMemo()
@ -100,6 +109,7 @@ function onSave()
return JSON.encode({ return JSON.encode({
activeInvestigatorClass = activeInvestigatorClass, activeInvestigatorClass = activeInvestigatorClass,
activeInvestigatorId = activeInvestigatorId, activeInvestigatorId = activeInvestigatorId,
isClassTextureEnabled = isClassTextureEnabled,
isDrawButtonVisible = isDrawButtonVisible, isDrawButtonVisible = isDrawButtonVisible,
playerColor = playerColor, playerColor = playerColor,
slotData = slotData slotData = slotData
@ -111,6 +121,7 @@ function onLoad(savedData)
local loadedData = JSON.decode(savedData) local loadedData = JSON.decode(savedData)
activeInvestigatorClass = loadedData.activeInvestigatorClass activeInvestigatorClass = loadedData.activeInvestigatorClass
activeInvestigatorId = loadedData.activeInvestigatorId activeInvestigatorId = loadedData.activeInvestigatorId
isClassTextureEnabled = loadedData.isClassTextureEnabled
isDrawButtonVisible = loadedData.isDrawButtonVisible isDrawButtonVisible = loadedData.isDrawButtonVisible
playerColor = loadedData.playerColor playerColor = loadedData.playerColor
slotData = loadedData.slotData slotData = loadedData.slotData
@ -169,7 +180,7 @@ function searchArea(origin, size, filter)
return searchLib.inArea(origin, self.getRotation(), size, filter) return searchLib.inArea(origin, self.getRotation(), size, filter)
end end
-- finds all objects on the playmat and associated set aside zone. -- finds all objects on the playermat and associated set aside zone.
function searchAroundSelf(filter) function searchAroundSelf(filter)
local scale = self.getScale() local scale = self.getScale()
local bounds = self.getBoundsNormalized() local bounds = self.getBoundsNormalized()
@ -180,11 +191,11 @@ function searchAroundSelf(filter)
bounds.size.z = bounds.size.z + SEARCH_AROUND_SELF_Z_BUFFER bounds.size.z = bounds.size.z + SEARCH_AROUND_SELF_Z_BUFFER
-- 'setAsideDirection' accounts for the set aside zone being on the left or right, -- 'setAsideDirection' accounts for the set aside zone being on the left or right,
-- depending on the table position of the playmat -- depending on the table position of the playermat
local setAsideDirection = bounds.center.z > 0 and 1 or -1 local setAsideDirection = bounds.center.z > 0 and 1 or -1
-- Since the cast is centered on the position, shift left or right to keep -- Since the cast is centered on the position, shift left or right to keep
-- the non-set aside edge of the cast at the edge of the playmat -- the non-set aside edge of the cast at the edge of the playermat
local localCenter = self.positionToLocal(bounds.center) local localCenter = self.positionToLocal(bounds.center)
localCenter.x = localCenter.x + setAsideDirection * SEARCH_AROUND_SELF_X_BUFFER / 2 / scale.x localCenter.x = localCenter.x + setAsideDirection * SEARCH_AROUND_SELF_X_BUFFER / 2 / scale.x
localCenter.z = localCenter.z - SEARCH_AROUND_SELF_Z_BUFFER / 2 / scale.z localCenter.z = localCenter.z - SEARCH_AROUND_SELF_Z_BUFFER / 2 / scale.z
@ -391,8 +402,8 @@ function doUpkeep(_, clickedByColor, isRightClick)
j = j + 1 j = j + 1
Wait.time(function() deckLib.placeOrMergeIntoDeck(cardsToDiscard[i], returnGlobalDiscardPosition(), self.getRotation()) end, j * 0.1) Wait.time(function() deckLib.placeOrMergeIntoDeck(cardsToDiscard[i], returnGlobalDiscardPosition(), self.getRotation()) end, j * 0.1)
end end
--add some time if there are any cards to discard, if not, draw up to 5 immediately -- add some time if there are any cards to discard, if not, draw up to 5 immediately
if j > 0 then if j > 0 then
k = 0.7 + (j * 0.1) k = 0.7 + (j * 0.1)
else else
@ -751,7 +762,7 @@ function changeColor(clickedByColor)
end end
--------------------------------------------------------- ---------------------------------------------------------
-- playmat token spawning -- playermat token spawning
--------------------------------------------------------- ---------------------------------------------------------
-- Finds all customizable cards in this play area and updates their metadata based on the selections -- Finds all customizable cards in this play area and updates their metadata based on the selections
@ -907,10 +918,12 @@ function maybeUpdateActiveInvestigator(card)
notes.combatIcons, notes.combatIcons,
notes.agilityIcons notes.agilityIcons
}) })
updateTexture()
elseif activeInvestigatorId ~= "00000" then elseif activeInvestigatorId ~= "00000" then
activeInvestigatorClass = "Neutral" activeInvestigatorClass = "Neutral"
activeInvestigatorId = "00000" activeInvestigatorId = "00000"
ownedObjects.InvestigatorSkillTracker.call("updateStats", { 1, 1, 1, 1 }) ownedObjects.InvestigatorSkillTracker.call("updateStats", { 1, 1, 1, 1 })
updateTexture()
else else
return return
end end
@ -964,7 +977,7 @@ function maybeUpdateActiveInvestigator(card)
count[type] = count[type] + 1 count[type] = count[type] + 1
if count[type] > 2 then 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 else
local localSpawnPos = tokenSpawnPos[type][count[type]] local localSpawnPos = tokenSpawnPos[type][count[type]]
local globalSpawnPos = self.positionToWorld(localSpawnPos):add(Vector(0, 0.2, 0)) local globalSpawnPos = self.positionToWorld(localSpawnPos):add(Vector(0, 0.2, 0))
@ -978,6 +991,50 @@ function maybeUpdateActiveInvestigator(card)
end end
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
-- temporarily lock objects so they don't fall through the mat
local objectsToUnlock = {}
for _, obj in ipairs(searchAroundSelf()) do
if not obj.getLock() then
obj.setLock(true)
table.insert(objectsToUnlock, obj)
end
end
self.script_state = onSave()
customInfo.image = newUrl
self.setCustomObject(customInfo)
local reloadedMat = self.reload()
-- unlock objects when mat is reloaded
Wait.condition(function()
for _, obj in ipairs(objectsToUnlock) do
obj.setLock(false)
end
end, function() return reloadedMat.loading_custom == false end)
end
end
--------------------------------------------------------- ---------------------------------------------------------
-- manipulation of owned objects -- manipulation of owned objects
--------------------------------------------------------- ---------------------------------------------------------
@ -1009,7 +1066,7 @@ function resetSkillTracker()
if obj ~= nil then if obj ~= nil then
obj.call("updateStats", { 1, 1, 1, 1 }) obj.call("updateStats", { 1, 1, 1, 1 })
else else
printToAll("Skill tracker for " .. matColor .. " playmat could not be found.", "Yellow") printToAll("Skill tracker for " .. matColor .. " playermat could not be found.", "Yellow")
end end
end end
@ -1079,7 +1136,7 @@ function showDrawButton(visible)
end end
end end
-- shows / hides a clickable clue counter for this playmat and sets the correct amount of clues -- shows / hides a clickable clue counter for this playermat and sets the correct amount of clues
---@param showCounter boolean Whether the clickable clue counter should be visible ---@param showCounter boolean Whether the clickable clue counter should be visible
function clickableClues(showCounter) function clickableClues(showCounter)
local clickerPos = ownedObjects.ClickableClueCounter.getPosition() local clickerPos = ownedObjects.ClickableClueCounter.getPosition()
@ -1111,6 +1168,14 @@ function clickableClues(showCounter)
end end
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) -- removes all clues (moving tokens to the trash and setting counters to 0)
function removeClues() function removeClues()
ownedObjects.ClueCounter.call("removeAllClues", ownedObjects.Trash) ownedObjects.ClueCounter.call("removeAllClues", ownedObjects.Trash)

View File

@ -1,347 +0,0 @@
do
local PlaymatApi = {}
local guidReferenceApi = require("core/GUIDReferenceApi")
local searchLib = require("util/SearchLib")
local localInvestigatorPosition = { x = -1.17, y = 1, z = -0.01 }
-- Convenience function to look up a mat's object by color, or get all mats.
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
---@return table: Single-element if only single playmat is requested
local function getMatForColor(matColor)
if matColor == "All" then
return guidReferenceApi.getObjectsByType("Playermat")
else
return { matColor = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat") }
end
end
-- Returns the color of the closest playmat
---@param startPos table Starting position to get the closest mat from
PlaymatApi.getMatColorByPosition = function(startPos)
local result, smallestDistance
for matColor, mat in pairs(getMatForColor("All")) do
local distance = Vector.between(startPos, mat.getPosition()):magnitude()
if smallestDistance == nil or distance < smallestDistance then
smallestDistance = distance
result = matColor
end
end
return result
end
-- Returns the color of the player's hand that is seated next to the playmat
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.getPlayerColor = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.getVar("playerColor")
end
end
-- Returns the color of the playmat that owns the playercolor's hand
---@param handColor string Color of the playmat
PlaymatApi.getMatColor = function(handColor)
for matColor, mat in pairs(getMatForColor("All")) do
local playerColor = mat.getVar("playerColor")
if playerColor == handColor then
return matColor
end
end
end
-- Instructs a playmat to check for DES
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
PlaymatApi.checkForDES = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("checkForDES")
end
end
-- Returns if there is the card "Dream-Enhancing Serum" on the requested playmat
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
---@return boolean: whether DES is present on the playmat
PlaymatApi.hasDES = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.getVar("hasDES")
end
end
-- gets the slot data for the playmat
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.getSlotData = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.getTable("slotData")
end
end
-- sets the slot data for the playmat
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
---@param newSlotData table New slot data for the playmat
PlaymatApi.loadSlotData = function(matColor, newSlotData)
for _, mat in pairs(getMatForColor(matColor)) do
mat.setTable("slotData", newSlotData)
mat.call("redrawSlotSymbols")
return
end
end
-- Performs a search of the deck area of the requested playmat and returns the result as table
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.getDeckAreaObjects = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.call("getDeckAreaObjects")
end
end
-- Flips the top card of the deck (useful after deck manipulation for Norman Withers)
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.flipTopCardFromDeck = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.call("flipTopCardFromDeck")
end
end
-- Returns the position of the discard pile of the requested playmat
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.getDiscardPosition = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.call("returnGlobalDiscardPosition")
end
end
-- Returns the position of the draw pile of the requested playmat
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.getDrawPosition = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.call("returnGlobalDrawPosition")
end
end
-- Transforms a local position into a global position
---@param localPos table Local position to be transformed
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.transformLocalPosition = function(localPos, matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.positionToWorld(localPos)
end
end
-- Returns the rotation of the requested playmat
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.returnRotation = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.getRotation()
end
end
-- Returns a table with spawn data (position and rotation) for a helper object
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
---@param helperName string Name of the helper object
PlaymatApi.getHelperSpawnData = function(matColor, helperName)
local resultTable = {}
local localPositionTable = {
["Hand Helper"] = {0.05, 0, -1.182},
["Search Assistant"] = {-0.3, 0, -1.182}
}
for color, mat in pairs(getMatForColor(matColor)) do
resultTable[color] = {
position = mat.positionToWorld(localPositionTable[helperName]),
rotation = mat.getRotation()
}
end
return resultTable
end
-- Triggers the Upkeep for the requested playmat
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
---@param playerColor string Color of the calling player (for messages)
PlaymatApi.doUpkeepFromHotkey = function(matColor, playerColor)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("doUpkeepFromHotkey", playerColor)
end
end
-- Handles discarding for the requested playmat for the provided list of objects
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
---@param objList table List of objects to discard
PlaymatApi.discardListOfObjects = function(matColor, objList)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("discardListOfObjects", objList)
end
end
-- Returns the active investigator id
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.returnInvestigatorId = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.getVar("activeInvestigatorId")
end
end
-- Returns the class of the active investigator
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.returnInvestigatorClass = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.getVar("activeInvestigatorClass")
end
end
-- Returns the position for encounter card drawing
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
---@param stack boolean If true, returns the leftmost position instead of the first empty from the right
PlaymatApi.getEncounterCardDrawPosition = function(matColor, stack)
for _, mat in pairs(getMatForColor(matColor)) do
return Vector(mat.call("getEncounterCardDrawPosition", stack))
end
end
-- Sets the requested playmat'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
-- be reset to snap all cards.
---@param matchCardTypes boolean Whether snap points should only snap for the matching card types
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
PlaymatApi.setLimitSnapsByType = function(matchCardTypes, matColor)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("setLimitSnapsByType", matchCardTypes)
end
end
-- Sets the requested playmat's draw 1 button to visible
---@param isDrawButtonVisible boolean Whether the draw 1 button should be visible or not
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
PlaymatApi.showDrawButton = function(isDrawButtonVisible, matColor)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("showDrawButton", isDrawButtonVisible)
end
end
-- Shows or hides the clickable clue counter for the requested playmat
---@param showCounter boolean Whether the clickable counter should be present or not
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
PlaymatApi.clickableClues = function(showCounter, matColor)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("clickableClues", showCounter)
end
end
-- Removes all clues (to the trash for tokens and counters set to 0) for the requested playmat
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
PlaymatApi.removeClues = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("removeClues")
end
end
-- Reports the clue count for the requested playmat
---@param useClickableCounters boolean Controls which type of counter is getting checked
PlaymatApi.getClueCount = function(useClickableCounters, matColor)
local count = 0
for _, mat in pairs(getMatForColor(matColor)) do
count = count + mat.call("getClueCount", useClickableCounters)
end
return count
end
-- Updates the specified owned counter
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
---@param type string Counter to target
---@param newValue number Value to set the counter to
---@param modifier number If newValue is not provided, the existing value will be adjusted by this modifier
PlaymatApi.updateCounter = function(matColor, type, newValue, modifier)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("updateCounter", { type = type, newValue = newValue, modifier = modifier })
end
end
-- Triggers the draw function for the specified playmat
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
---@param number number Amount of cards to draw
PlaymatApi.drawCardsWithReshuffle = function(matColor, number)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("drawCardsWithReshuffle", number)
end
end
-- Returns the resource counter amount
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
---@param type string Counter to target
PlaymatApi.getCounterValue = function(matColor, type)
for _, mat in pairs(getMatForColor(matColor)) do
return mat.call("getCounterValue", type)
end
end
-- Returns a list of mat colors that have an investigator placed
PlaymatApi.getUsedMatColors = function()
local usedColors = {}
for matColor, mat in pairs(getMatForColor("All")) do
local searchPos = mat.positionToWorld(localInvestigatorPosition)
local searchResult = searchLib.atPosition(searchPos, "isCardOrDeck")
if #searchResult > 0 then
table.insert(usedColors, matColor)
end
end
return usedColors
end
-- Returns investigator name
---@param matColor string Color of the playmat - White, Orange, Green or Red (does not support "All")
PlaymatApi.getInvestigatorName = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
local searchPos = mat.positionToWorld(localInvestigatorPosition)
local searchResult = searchLib.atPosition(searchPos, "isCardOrDeck")
if #searchResult == 1 then
return searchResult[1].getName()
end
end
return ""
end
-- Resets the specified skill tracker to "1, 1, 1, 1"
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
PlaymatApi.resetSkillTracker = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("resetSkillTracker")
end
end
-- Redraws the XML for the slot symbols based on the slotData table
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
PlaymatApi.redrawSlotSymbols = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("redrawSlotSymbols")
end
end
-- Finds all objects on the playmat and associated set aside zone and returns a table
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
---@param filter string Name of the filte function (see util/SearchLib)
PlaymatApi.searchAroundPlaymat = function(matColor, filter)
local objList = {}
for _, mat in pairs(getMatForColor(matColor)) do
for _, obj in ipairs(mat.call("searchAroundSelf", filter)) do
table.insert(objList, obj)
end
end
return objList
end
-- Discard a non-hidden card from the corresponding player's hand
---@param matColor string Color of the playmat - White, Orange, Green, Red or All
PlaymatApi.doDiscardOne = function(matColor)
for _, mat in pairs(getMatForColor(matColor)) do
mat.call("doDiscardOne")
end
end
-- Triggers the metadata sync for all playmats
PlaymatApi.syncAllCustomizableCards = function()
for _, mat in pairs(getMatForColor("All")) do
mat.call("syncAllCustomizableCards")
end
end
return PlaymatApi
end

View File

@ -20,7 +20,7 @@
-- SetAside5: Hunch Deck for Joe Diamond -- SetAside5: Hunch Deck for Joe Diamond
-- SetAside6: currently unused -- SetAside6: currently unused
do do
local playmatApi = require("playermat/PlaymatApi") local playermatApi = require("playermat/PlayermatApi")
local Zones = { } local Zones = { }
local commonZones = {} local commonZones = {}
@ -126,7 +126,7 @@ do
and playerColor ~= "Green") then and playerColor ~= "Green") then
return nil return nil
end end
return playmatApi.transformLocalPosition(zoneData[playerColor][zoneName], playerColor) return playermatApi.transformLocalPosition(zoneData[playerColor][zoneName], playerColor)
end end
-- Return the global rotation for a card on the given player mat, based on its zone. -- Return the global rotation for a card on the given player mat, based on its zone.
@ -136,7 +136,7 @@ do
-- Y rotation to orient the card on the given player mat as well as a -- Y rotation to orient the card on the given player mat as well as a
-- Z rotation to place the card face up or face down. -- Z rotation to place the card face up or face down.
Zones.getDefaultCardRotation = function(playerColor, zoneName) Zones.getDefaultCardRotation = function(playerColor, zoneName)
local cardRotation = playmatApi.returnRotation(playerColor) local cardRotation = playermatApi.returnRotation(playerColor)
if zoneName == "Deck" then if zoneName == "Deck" then
cardRotation = cardRotation + Vector(0, 0, 180) cardRotation = cardRotation + Vector(0, 0, 180)
end end

View File

@ -1,4 +1,4 @@
local playmatApi = require("playermat/PlaymatApi") 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 TOKEN_INDEX = {} local TOKEN_INDEX = {}
@ -79,8 +79,8 @@ function onScriptingButtonDown(index, playerColor)
end end
-- check for nearest investigator card and change action token state to its class -- check for nearest investigator card and change action token state to its class
elseif tokenType == "universalActionAbility" then elseif tokenType == "universalActionAbility" then
local matColor = playmatApi.getMatColorByPosition(position) local matColor = playermatApi.getMatColorByPosition(position)
local class = playmatApi.returnInvestigatorClass(matColor) local class = playermatApi.returnInvestigatorClass(matColor)
callback = function(spawned) spawned.call("updateClassAndSymbol", { class = class, symbol = class }) end callback = function(spawned) spawned.call("updateClassAndSymbol", { class = class, symbol = class }) end
end end

View File

@ -288,6 +288,21 @@
</Cell> </Cell>
</Row> </Row>
<!-- Option: use class-specific texture -->
<Row class="option-text"
tooltip="Controls whether a class-specific playermat texture should be automatically loaded.">
<Cell class="option-text">
<Panel class="singleColumn-wrapper">
<Text class="option-header">Use class-specific texture</Text>
</Panel>
</Cell>
<Cell class="option-button">
<Button class="optionToggle"
id="useClassTexture"
onClick="onClick_toggleOption"/>
</Cell>
</Row>
<!-- Option: use clickable clue-counters --> <!-- Option: use clickable clue-counters -->
<Row class="option-text" <Row class="option-text"
tooltip="Instead of automatically counting clues in the respective area on your playermat,&#xA;this displays a clickable counter for clues."> tooltip="Instead of automatically counting clues in the respective area on your playermat,&#xA;this displays a clickable counter for clues.">
@ -323,7 +338,7 @@
</Cell> </Cell>
</Row> </Row>
<!-- Option: remove a player mat --> <!-- Option: remove a playermat -->
<Row class="option-text" <Row class="option-text"
tooltip="Remove an unused playermat for more table space.&#xA;Displayed are the default colors."> tooltip="Remove an unused playermat for more table space.&#xA;Displayed are the default colors.">
<Cell class="option-singleColumn"> <Cell class="option-singleColumn">