-- SCE Navigation Panel version 1.00 function onLoad(saved_data) self.createButton({ label="", tooltip="Display full overlay", click_function="displayFull", function_owner=self, position={0.0,0.1,-0.57}, height=70, width=800, scale={x=1, y=1, z=1}, color={1,0,0,0} }) self.createButton({ label="", tooltip="Display only play area", click_function="displayPlayArea", function_owner=self, position={0.0,0.1,-0.30}, height=70, width=800, scale={x=1, y=1, z=1}, color={1,0,0,0} }) self.createButton({ label="", tooltip="Close overlay", click_function="closeOverlay", function_owner=self, position={0.0,0.1,-0.03}, height=70, width=800, scale={x=1, y=1, z=1}, color={1,0,0,0} }) self.createButton({ label="", tooltip="Modify a camera position", click_function="beginSetCamera", function_owner=self, position={0.0,0.1,0.37}, height=70, width=800, scale={x=1, y=1, z=1}, color={1,0,0,0} }) self.createButton({ label="", tooltip="Reset camera positions to default", click_function="resetCameras", function_owner=self, position={0.0,0.1,0.77}, height=70, width=800, scale={x=1, y=1, z=1}, color={1,0,0,0} }) defaultCameraParams = { {position={-1.626, -2.5, -0.064}, pitch=62.964, yaw=90.000, distance=17.844}, -- 1. ActAgenda {position={-27.822, -2.5, 0.424}, pitch=75.823, yaw=90.000, distance=-1.000}, -- 2. Map -- {position={-31.592, -2.5, 26.392}, pitch=74.238, yaw=180.000, distance=19.858}, -- 3. Green playmat {position={-31.592, -2.5, 26.392}, pitch=74.238, yaw=180.000, distance=-1.000}, -- 3. Green playmat {position={-55.026, -2.5, 12.052}, pitch=74.238, yaw=90.000, distance=-1.000}, -- 4. White playmat {position={-55.026, -2.5, -11.479}, pitch=74.238, yaw=90.000, distance=-1.000}, -- 5. Orange playmat {position={-31.592, -2.5, -26.392}, pitch=74.238, yaw=0.000, distance=-1.000}, -- 6. Red playmat {position={-2.940, -2.5, 25.160}, pitch=73.556, yaw=90.000, distance=20.146}, -- 7. Victory / SetAside {position={-58.216, -2.5, -71.288}, pitch=76.430, yaw=90.000, distance=20.000}, -- 8. Deckbuilder {position={46.368, -2.5, 0.328}, pitch=69.491, yaw=90.000, distance=46.255}, -- 9. Campaigns {position={13.875, -2.5, 0.328}, pitch=69.491, yaw=90.000, distance=37.962}, -- 10. Scenarios {position={51.940, -2.5, 64.476}, pitch=76.430, yaw=90.000, distance=48.102}, -- 11. Level 0 {position={51.302, -2.5, -73.514}, pitch=76.430, yaw=90.000, distance=48.102}, -- 12. Upgraded {position={-27.788, -2.5, 74.662}, pitch=76.430, yaw=90.000, distance=30.616}, -- 13. Weaknesses {position={-61.090, -2.5, 70.762}, pitch=76.430, yaw=90.000, distance=34.188}, -- 14. Rules {position={-18.547, -2.5, -73.514}, pitch=76.430, yaw=90.000, distance=42.249}, -- 15. Investigators {position={-2.144, -2.5, -26.900}, pitch=73.556, yaw=90.000, distance=20.146}, -- 16. Log {position={-45.000, -2.5, -0.228}, pitch=73.556, yaw=90.000, distance=12.000} -- 17. BlessCurse } fullButtonData = { { id = "1", width = "84", height = "38", offsetX = "1", offsetY = "-9" }, { id = "2", width = "78", height = "50", offsetX = "1", offsetY = "-59" }, { id = "3", width = "36", height = "70", offsetX = "-62", offsetY = "-70" }, { id = "4", width = "70", height = "40", offsetX = "-36", offsetY = "-130" }, { id = "5", width = "70", height = "40", offsetX = "39", offsetY = "-130" }, { id = "6", width = "36", height = "70", offsetX = "64", offsetY = "-70" }, { id = "7", width = "36", height = "36", offsetX = "-63", offsetY = "-9" }, { id = "8", width = "64", height = "64", offsetX = "153", offsetY = "-128" }, { id = "9", width = "155", height = "70", offsetX = "2", offsetY = "120" }, { id = "10", width = "155", height = 70, offsetX = "2", offsetY = "47" }, { id = "11", width = "120", height = "100", offsetX = "-148", offsetY = "101" }, { id = "12", width = "120", height = "100", offsetX = "150", offsetY = "101" }, { id = "13", width = "120", height = "80", offsetX = "-150", offsetY = "-55" }, { id = "14", width = "120", height = "60", offsetX = "-150", offsetY = "-132" }, { id = "15", width = "110", height = "100", offsetX = "152", offsetY = "-42" }, { id = "16", width = "36", height = "36", offsetX = "64", offsetY = "-9" }, { id = "17", width = "44", height = "25", offsetX = "1", offsetY = "-97" } } playButtonData = { { id = "1", width = "84", height = "38", offsetX = "0", offsetY = "59" }, { id = "2", width = "78", height = "50", offsetX = "0", offsetY = "9" }, { id = "3", width = "36", height = "70", offsetX = "-62", offsetY = "-1" }, { id = "4", width = "70", height = "40", offsetX = "-37", offsetY = "-61" }, { id = "5", width = "70", height = "40", offsetX = "39", offsetY = "-61" }, { id = "6", width = "36", height = "70", offsetX = "63", offsetY = "-2" }, { id = "7", width = "36", height = "36", offsetX = "-64", offsetY = "59" }, { id = "16", width = "36", height = "36", offsetX = "63", offsetY = "59" }, { id = "17", width = "44", height = "25", offsetX = "0", offsetY = "-28" } } playermatData = { White = { guid = '8b081b', origin = { x=-54.42, y=0, z=20.96 }, scale = { x=36.63, y=5.10, z=14.59 }, orientation = { x=0, y=270, z=0 }, minX = -61.4, maxX = -48.6, minZ = -2.39, maxZ = 24.53, xOffset = 0.07, zOffset = 0.03 }, Orange = { guid = 'bd0ff4', origin = { x=-54.42, y=0, z=-20.96 }, scale = { x=36.63, y=5.10, z=14.59 }, orientation = { x=0, y=270, z=0 }, minX = -61.4, maxX = -48.6, minZ = -24.53, maxZ = 2.39, xOffset = 0.07, zOffset = 0.02 }, Green = { guid = '383d8b', origin = { x=-25.00, y=0, z=26.20 }, scale = { x=31.5, y=5.10, z=14.59 }, orientation = { x=0, y=0, z=0 }, minX = -44.43, maxX = -17.44, minZ = 20.17, maxZ = 32.97, xOffset = -0.07, zOffset = 0.00 }, Red = { guid = '0840d5', origin = { x=-25.00, y=0, z=-26.60 }, scale = { x=31.5, y=5.10, z=14.59 }, orientation = { x=0, y=180, z=0 }, minX = -44.43, maxX = -17.44, minZ = -32.97, maxZ = -20.17, xOffset = 0.07, zOffset = -0.06 } } editing = false selectedEditButton = -1 editPos = {0, 0, 0} editPitch = 0 editYaw = 0 editDistance = 0 if saved_data ~= "" then local loaded_data = JSON.decode(saved_data) cameraParams = loaded_data.cameras fullVisibility = loaded_data.fullVis playVisibility = loaded_data.playVis resetOverlay() else cameraParams = { Green = {}, White = {}, Orange = {}, Red = {} } for iv, v in pairs({'Green', 'White', 'Orange', 'Red'}) do cameraParams[v] = {} for i = 1,17 do cameraParams[v][i] = {} cameraParams[v][i].position = defaultCameraParams[i].position cameraParams[v][i].pitch = defaultCameraParams[i].pitch cameraParams[v][i].yaw = defaultCameraParams[i].yaw cameraParams[v][i].distance = defaultCameraParams[i].distance end end fullVisibility = { Green = false, White = false, Orange = false, Red = false } playVisibility = { Green = false, White = false, Orange = false, Red = false } end end function onSave() return JSON.encode({ cameras = cameraParams, fullVis = fullVisibility, playVis = playVisibility }) -- return '' end function displayFull(object, color) local playerCount = getPlayerCount() local colors if playerCount == 1 then colors = { 'Green', 'White', 'Orange', 'Red' } else colors = { color } end for i, v in ipairs(colors) do fullVisibility[v] = true playVisibility[v] = false end resetOverlay() end function displayPlayArea(object, color) local playerCount = getPlayerCount() local colors if playerCount == 1 then colors = { 'Green', 'White', 'Orange', 'Red' } else colors = { color } end for i, v in ipairs(colors) do fullVisibility[v] = false playVisibility[v] = true end resetOverlay() end function resetCameras(object, color) local playerCount = getPlayerCount() local colors if playerCount == 1 then colors = { 'Green', 'White', 'Orange', 'Red' } else colors = { color } end for iv, v in ipairs(colors) do for i = 1,17 do cameraParams[v][i].position = defaultCameraParams[i].position cameraParams[v][i].pitch = defaultCameraParams[i].pitch cameraParams[v][i].yaw = defaultCameraParams[i].yaw cameraParams[v][i].distance = defaultCameraParams[i].distance end end end function closeOverlay(object, color) fullVisibility[color] = false playVisibility[color] = false resetOverlay() end function resetOverlay() local guid = self.getGUID() local color local panel local existingXml = UI.getXml() local openingXml = '' -- try to only remove our panels for p = 1,2 do i, j = string.find(existingXml, ' ]] for i, d in ipairs(data) do if editing then if selectedEditButton < 0 then color = "rgba(1,1,1,1)" elseif tonumber(d.id) == selectedEditButton then color = "rgba(0,1,0,1)" else color = "rgba(1,0,0,1)" end else color = "rgba(0,1,0,0)" end xml = xml .. [[ ]] end xml = xml .. [[ ]] end if string.len(playColors) > 0 then data = playButtonData xml = xml .. [[ ]] for i, d in ipairs(data) do if editing then if selectedEditButton < 0 then color = "rgba(1,1,1,1)" elseif tonumber(d.id) == selectedEditButton then color = "rgba(0,1,0,1)" else color = "rgba(1,0,0,1)" end else color = "rgba(0,1,0,0)" end xml = xml .. [[ ]] end xml = xml .. [[ ]] end local existingAssets = UI.getCustomAssets() local largeOverlay = nil local smallOverlay = nil for i,v in pairs(existingAssets) do for ii,vv in pairs(v) do if vv == 'OverlayLarge' then largeOverlay = v end if vv == 'OverlaySmall' then smallOverlay = v end end end local largeURL = 'http://cloud-3.steamusercontent.com/ugc/1745699502804112656/A34D1F30E0DA0E283F300AE6D6B63F59FFC97730/' local smallURL = 'http://cloud-3.steamusercontent.com/ugc/1745699502804112719/CFFC89BF9FB8439204EE19CF94180EC99450CD38/' if largeOverlay == nil then largeOverlay = { name='OverlayLarge', url=largeURL } table.insert(existingAssets, largeOverlay) else largeOverlay.url = largeURL end if smallOverlay == nil then smallOverlay = { name='OverlaySmall', url=smallURL } table.insert(existingAssets, smallOverlay) else smallOverlay.url = smallURL end UI.setXml(xml, existingAssets) end function buttonClicked(player, _, idValue) if editing then if selectedEditButton < 0 then selectedEditButton = tonumber(idValue) else if tonumber(idValue) == selectedEditButton and editDistance > 0 then local playerCount = getPlayerCount() local colors if playerCount == 1 then colors = { 'Green', 'White', 'Orange', 'Red' } else colors = { player.color } end for i, v in ipairs(colors) do cameraParams[v][selectedEditButton].position = editPos cameraParams[v][selectedEditButton].pitch = editPitch cameraParams[v][selectedEditButton].yaw = editYaw cameraParams[v][selectedEditButton].distance = editDistance end end editing = false selectedEditButton = -1 end resetOverlay() else loadCamera(player, _, idValue) end end function loadCamera(player, _, idValue) local index = tonumber(idValue) local color = player.color -- only do map zooming if te camera hasn't been specially set by user if index == 2 and cameraParams[color][index].distance <= 0.0 then local mapObjects = Physics.cast({ origin = { x=-29.2, y=0, z=0.0 }, direction = { x=0, y=1, z=0 }, type = 3, size = { x=36, y=5, z=31.4 }, orientation = { x=0, y=90, z=0 } }) local minX = 100 local maxX = -100 local minZ = 100 local maxZ = -100 for i,v in pairs(mapObjects) do local obj = v.hit_object if obj.type == 'Card' or obj.type == 'Infinite' then local bounds = obj.getBounds() local x1 = bounds['center'][1] - bounds['size'][1]/2 local x2 = bounds['center'][1] + bounds['size'][1]/2 local z1 = bounds['center'][3] - bounds['size'][3]/2 local z2 = bounds['center'][3] + bounds['size'][3]/2 if x1 < minX then minX = x1 end if x2 > maxX then maxX = x2 end if z1 < minZ then minZ = z1 end if z2 > maxZ then maxZ = z2 end end end if minX < 100 then local dx = maxX - minX local dz = (maxZ - minZ) / (1.6) -- screen ratio * 1.2 (for my macbook pro, no idea how to generalize this) local centerX = (minX + maxX) / 2 - dx*0.12 -- offset is to move it a bit up, so the cards don't block anything local centerZ = (minZ + maxZ) / 2 local scale = dx if dz > dx then scale = dz end -- regression line from the following data points, seems linear -- rows 1 scale 4.5 d 12 -- rows 2 scale 11 d 16 -- rows 3 scale 14.5 d 19.6 -- rows 4 scale 19.6 d 25 -- rows 5 scale 23.25 d 28 -- rows 6 scale 30.8 d 34 -- local d = 0.8685 * scale + 7.4505 -- modified by testing -- local d = 0.8685 * scale + 5 local d = 1.04 * scale + 5 player.lookAt({position={centerX, 0, centerZ}, pitch=75.823, yaw=90.000, distance=d}) else player.lookAt({position={-33.667, 0, 0.014}, pitch=75.823, yaw=90.000, distance=36}) end elseif index >= 3 and index <= 6 then local matColor = nil if index == 3 then matColor = 'Green' elseif index == 4 then matColor = 'White' elseif index == 5 then matColor = 'Orange' elseif index == 6 then matColor = 'Red' end if matColor ~= nil then local playerCount = getPlayerCount() if playerCount <= 1 then player.changeColor(matColor) end end if cameraParams[color][index].distance <= 0.0 then local matObjects = Physics.cast({ origin = playermatData[matColor].origin, direction = { x=0, y=1, z=0 }, type = 3, size = playermatData[matColor].scale, orientation = playermatData[matColor].orientation, -- debug=true }) local minX = playermatData[matColor].minX local maxX = playermatData[matColor].maxX local minZ = playermatData[matColor].minZ local maxZ = playermatData[matColor].maxZ for i,v in pairs(matObjects) do local obj = v.hit_object if obj.type == 'Card' or obj.type == 'Infinite' then local bounds = obj.getBounds() local x1 = bounds['center'][1] - bounds['size'][1]/2 local x2 = bounds['center'][1] + bounds['size'][1]/2 local z1 = bounds['center'][3] - bounds['size'][3]/2 local z2 = bounds['center'][3] + bounds['size'][3]/2 if x1 < minX then minX = x1 end if x2 > maxX then maxX = x2 end if z1 < minZ then minZ = z1 end if z2 > maxZ then maxZ = z2 end end end local dx local dz local centerX local centerZ local scale local yaw local d -- White/Orange if index > 3 and index < 6 then dx = maxX - minX dz = (maxZ - minZ) / (1.6) -- screen ratio * 1.2 (for my macbook pro, no idea how to generalize this) centerX = (minX + maxX) / 2 - dx*playermatData[matColor].xOffset -- offset is to move it a bit up, so the cards don't block anything centerZ = (minZ + maxZ) / 2 + dz*playermatData[matColor].zOffset -- offset is to move it right a bit, so the toolbar doesn't block anything yaw = 90 scale = dx if dz > dx then scale = dz end d = 0.64 * scale + 7 else -- Green/Red dx = (maxX - minX) / (1.6) -- screen ratio * 1.2 (for my macbook pro, no idea how to generalize this) dz = maxZ - minZ centerX = (minX + maxX) / 2 + dx*playermatData[matColor].zOffset -- offset is to move it right a bit, so the toolbar doesn't block anything centerZ = (minZ + maxZ) / 2 - dz*playermatData[matColor].xOffset -- offset is to move it a bit up, so the cards don't block anything yaw = playermatData[matColor].orientation.y + 180 scale = dz if dx > dz then scale = dx end d = 0.64 * scale + 7 end -- 15.46 -> 17.081 -- 18.88 -> 19.33 -- 24.34 -> 22.6 -- need to wait if the player color changed Wait.frames(function() player.lookAt({position={centerX, 0, centerZ}, pitch=75.823, yaw=yaw, distance=d}) end, 2) else Wait.frames(function() player.lookAt(cameraParams[color][index]) end, 2) end else player.lookAt(cameraParams[color][index]) end end function beginSetCamera(object, color) editing = true resetOverlay() end function updateEditCamera(params) editPos = params[1] editPitch = params[2] editYaw = params[3] editDistance = params[4] end function getPlayerCount() local playerCount = 0 local playerList = getSeatedPlayers() for i, v in ipairs(playerList) do if v == 'Green' or v == 'White' or v == 'Orange' or v == 'Red' then playerCount = playerCount + 1 end end return playerCount end