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