Created
April 12, 2020 09:16
-
-
Save jbaiter/50b7cf9a1261692d4992205365ca03ba to your computer and use it in GitHub Desktop.
TableTop Simulator: Scripted Azul
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ Lua code. See documentation: https://api.tabletopsimulator.com/ --]] | |
#include <vscode/console> | |
tileDiffuseUrls = {} | |
tileDiffuseUrls["http://cloud-3.steamusercontent.com/ugc/967597347416754435/BA4334969D1AD4E8B146AE7E7A1A430F14C7A5DA/"] = "yellow" | |
tileDiffuseUrls["http://cloud-3.steamusercontent.com/ugc/967597347419272946/C8F005A109AAD820E38A8E377F1026074B830401/"] = "turquois" | |
tileDiffuseUrls["http://cloud-3.steamusercontent.com/ugc/967597347419272641/EE644ECD0ADC6C78AC61E0C538BAF98FD8703908/"] = "red" | |
tileDiffuseUrls["http://cloud-3.steamusercontent.com/ugc/967597347419272833/D4C93372171EBA7604524C0E6B6DA29347B5209A/"] = "blue" | |
tileDiffuseUrls["http://cloud-3.steamusercontent.com/ugc/967597347419273056/A03D249CF12867EB4134A9A7E9A9D2A1632EE704/"] = "black" | |
-- TODO: For automatic registration of broken tiles | |
--playerRowZones = { | |
-- { | |
-- '731332', | |
-- '31a0dd', | |
-- 'e2f094', | |
-- 'bb4835', | |
-- 'f42ad5' | |
-- } | |
--} | |
TABLE_HEIGHT = 5 | |
centerDisplayGUID = 'deadbeef' | |
tileBagGUID = 'd101ec' | |
discardBagGUID = '68e703' | |
dealButtonGUID = "8cea79" | |
centerAreaGUID = "e9d6b5" | |
hasGameStarted = false | |
factoryDisplayGUIDs = {} | |
-- display -> tile mapping | |
displayToTiles = {deadbeef={}} | |
-- tile -> display mapping | |
tileToDisplay = {} | |
--[[ The onLoad event is called after the game save finishes loading. --]] | |
function onLoad(saved_data) | |
-- In order for the save and rewind buttons to function we | |
-- need to make sure our local variables are saved properly | |
if(saved_data ~= "") then | |
local loaded_data = JSON.decode(saved_data) | |
hasGameStarted = loaded_data.started | |
if hasGameStarted then | |
factoryDisplayGUIDs = loaded_data.factoryDisplayGUIDs | |
end | |
end | |
-- Sets the snap points for the scoring area on each board | |
-- TODO: migrate the snap points that are set on individual boards here | |
setBoardSnaps() | |
-- start gaem button | |
if not(hasGameStarted) then | |
startPawn = getObjectFromGUID('45cea7') | |
startPawn.createButton({ | |
click_function = 'startGame', | |
label = "Start Game", | |
function_owner = self, | |
position = {0, 0 ,5}, | |
rotation = {0, 90, 0}, | |
width = 3000, | |
height = 800, | |
font_size = 400, | |
color = {1,1, 1}, | |
font_color = {0, 0, 0}, | |
tooltip = "Wait until all players are seated to start." | |
}) | |
else | |
createDealButton() | |
end | |
end | |
--[[ The onUpdate event is called once per frame. --]] | |
function onUpdate() | |
--[[ print('onUpdate loop!') --]] | |
end | |
function tablelength(T) | |
local count = 0 | |
for _ in pairs(T) do count = count + 1 end | |
return count | |
end | |
function onObjectPickUp(colorName, obj) | |
--print(colorName .. " picked up " .. obj.getName() .. " at " .. JSON.encode(obj.getPosition())) | |
end | |
function onObjectDrop(colorName, obj) | |
displayId = tileToDisplay[obj.getGUID()] | |
if displayId == nil then | |
-- Not dropped from display, nothing to do | |
return | |
end | |
-- TODO: Do nothing if the tile is not moved from the display | |
color = obj.getName() | |
print(colorName .. " dropped " .. color .. " taken from display " .. displayId) | |
-- Tile is no longer associated with a display | |
tileToDisplay[obj.getGUID()] = nil | |
-- Get the other tiles on the same display | |
otherTiles = displayToTiles[displayId] | |
-- Every other tile of the same color is horizontally offset | |
numDropped = 1 | |
offset = 0 | |
for __, objId in ipairs(otherTiles) do | |
if objId ~= obj.getGUID() then | |
otherTile = getObjectFromGUID(objId) | |
if otherTile.getName() == color then | |
pos = obj.getPosition() | |
-- Direction of offset depends on table side | |
if pos.z > 0 then | |
offset = offset - 2.3 | |
else | |
offset = offset + 2.3 | |
end | |
pos.x = pos.x - offset | |
otherTile.setPositionSmooth(pos, false, false) | |
otherTile.setRotationSmooth({ x=0, y=0, z=0 }, false, true) | |
-- Tile is no longer associated with a display | |
tileToDisplay[objId] = nil | |
numDropped = numDropped + 1 | |
elseif displayId ~= centerDisplayGUID then | |
-- Other tiles are moved to a random position the center | |
x = math.random(-8000, 8000) | |
z = math.random(-18000, -2000) | |
otherTile.setPositionSmooth({ x=x/1000.0, y=TABLE_HEIGHT, z=z/1000.0 }, false, true) | |
-- Tile is now associated with the center pseudo-display | |
tileToDisplay[objId] = centerDisplayGUID | |
table.insert(displayToTiles[centerDisplayGUID], objId) | |
end | |
end | |
end | |
-- Clear display tile registry | |
if displayId ~= centerDisplayGUID then | |
displayToTiles[displayId] = {} | |
end | |
-- TODO: For automatic registration of broken tiles | |
--for i, rowGuid in pairs(playerRowZones[1]) do | |
-- print(i .. " -> " .. rowGuid) | |
-- zone = getObjectFromGUID(rowGuid) | |
-- tileIds = {} | |
-- for _, subObj in pairs(zone.getObjects()) do | |
-- table.insert(tileIds, subObj.getGUID()) | |
-- end | |
-- print(i .. " has " .. JSON.encode_pretty(tileIds)) | |
--end | |
end | |
function onSave() | |
--Save data for future loading | |
if hasGameStarted then | |
local data_to_save = { | |
started = hasGameStarted, | |
Players = getSeatedPlayers(), | |
factoryDisplayGUIDs = factoryDisplayGUIDs | |
} | |
saved_data = JSON.encode(data_to_save) | |
return saved_data | |
end | |
end | |
-- This deals out the displays and then triggers each display to get tiles | |
-- TODO: Should this be a button for the user to select the number of players, | |
-- instead of using the number of seated players? | |
function dealDisplays(playerCount) | |
Players = getSeatedPlayers() | |
playerCount = playerCount or #Players | |
displayCounts = { | |
[1] = 9, [2] = 5, [3] = 7, [4] = 9 | |
} | |
factoryDisplayStack = getObjectFromGUID('914fda') | |
-- Lay the displays out in a circle | |
y = TABLE_HEIGHT | |
basex = 0 | |
basez = -10 | |
radius = 15 | |
numDisplays = displayCounts[playerCount] | |
step = 2 * math.pi / numDisplays | |
for i = 1, numDisplays do | |
theta = step * i | |
x = basex + radius * math.cos(theta) | |
z = basez + radius * math.sin(theta) | |
factoryDisplayStack.takeObject({ | |
position = {x, y, z}, | |
callback_function = function(obj) dealtDisplay(obj) end, | |
}) | |
end | |
end | |
-- callback function that populates each display with tiles | |
function dealtDisplay(display) | |
table.insert(factoryDisplayGUIDs, display.getGUID()) | |
display.setLock(true) | |
dealTiles(display) | |
end | |
function startGame(buttonObj) | |
hasGameStarted = true | |
dealDisplays() | |
createDealButton() | |
buttonObj.removeButton(0) | |
end | |
function createDealButton() | |
-- Add a button to deal the new round | |
tileBag = getObjectFromGUID(tileBagGUID) | |
tileBag.shuffle() | |
tileBag.createButton({ | |
click_function = 'newRound', | |
label = "Deal Tiles", | |
function_owner = self, | |
position = {-6, 0.5,5}, | |
rotation = {0, 0, 0}, | |
width = 2800, | |
height = 800, | |
font_size = 340, | |
color = {1,1, 1}, | |
font_color = {0, 0, 0}, | |
tooltip = "Deals tiles to the factory displays and shuffles in discard bag if needed." | |
}) | |
end | |
function newRound() | |
tileBag = getObjectFromGUID(tileBagGUID) | |
tileBag.shuffle() | |
for __, displayGUID in ipairs(factoryDisplayGUIDs) do | |
-- There's a race condition on reshuffling the tiles that we need to delay for. | |
-- TODO: find a better way to do this | |
if tileBag.getQuantity() < 4 then | |
recycleTiles() | |
Wait.time(function() fillDisplay(displayGUID) end, 2) | |
else | |
fillDisplay(displayGUID) | |
end | |
end | |
end | |
function fillDisplay(displayGUID) | |
display = getObjectFromGUID(displayGUID) | |
dealTiles(display) | |
end | |
function dealTiles(display) | |
tileBag = getObjectFromGUID(tileBagGUID) | |
displayPos = display.getPosition() | |
targetPositions = { | |
{2.3, 0.0, 0}, | |
{-2.3, 0.0, 0}, | |
{0, 0.0, -2.3}, | |
{0, 0.0, 2.3}, | |
} | |
displayToTiles[display.getGUID()] = {} | |
for i = 1, 4 do | |
tilePosition = display.positionToWorld(targetPositions[i]) | |
tileBag.takeObject({ | |
position = tilePosition, | |
rotation={0,0,0}, | |
callback_function = function (obj) | |
color = obj.getName() | |
if (color == nil or color == '') then | |
color = tileDiffuseUrls[obj.getCustomObject().diffuse] | |
obj.setName(color) | |
end | |
tileToDisplay[obj.getGUID()] = display.getGUID() | |
table.insert(displayToTiles[display.getGUID()], obj.getGUID()) | |
end | |
}) | |
end | |
end | |
-- Move tiles from the discard bag to the draw bag | |
function recycleTiles() | |
tileBag = getObjectFromGUID(tileBagGUID) | |
discardBag = getObjectFromGUID(discardBagGUID) | |
discardBagContent = discardBag.getObjects() | |
log(discardBagContent) | |
for __, v in ipairs(discardBagContent) do | |
tileBag.putObject(discardBag.takeObject({ guid = v.guid })) | |
end | |
end | |
function setBoardSnaps() | |
scoresnaps = {} | |
for row = 1, 5 do | |
for i=1, 20 do | |
currentx = 7.8 - 0.82*(i-1) | |
currenty = -7.7 + 1*(row-1) | |
snapdex = (row-1)*20+i | |
scoresnaps[snapdex] = { position = {currentx, 0.0, currenty}, rotation = {0,0,0}, rotation_snap = true } | |
end | |
end | |
boards = {getObjectFromGUID('18a461'),getObjectFromGUID('9f42ee'),getObjectFromGUID('8259b9'),getObjectFromGUID('4b40cd')} | |
for __, board in ipairs(boards) do | |
board.setSnapPoints(scoresnaps) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment