--[[ Lua code. See documentation: http://berserk-games.com/knowledgebase/scripting/ --]] -- Card size used for autodealing -- -- global position constants ENCOUNTER_DECK_POS = {-3.8, 1, 5.7} ENCOUNTER_DECK_SPAWN_POS = {-3.8, 3, 5.7} ENCOUNTER_DECK_DISCARD_POSITION = {-3.8, 0.5, 10.5} g_cardWith=2.30; g_cardHeigth=3.40; containerId = 'fea079' tokenDataId = '708279' CACHE = { object = {}, data = {} } --[[ The OnLoad function. This is called after everything in the game save finishes loading. Most of your script code goes here. --]] function onload() --Player.White.changeColor('Yellow') tokenplayerone = { damageone = "https://i.imgur.com/XIJHw3J.png", damagethree = "https://i.imgur.com/eqRC712.png", horrorone = "https://i.imgur.com/Bh0BO47.png", horrorthree = "https://i.imgur.com/pZvTKA7.png", resource = "https://i.imgur.com/j5v5E3j.png", resourcethree = "https://i.imgur.com/1GZsDTt.png", doom = "https://i.imgur.com/EoL7yaZ.png", clue = "https://i.imgur.com/wfCaVU0.png" } TOKEN_DATA = { clue = {image = tokenplayerone.clue, scale = {0.15, 0.15, 0.15}}, resource = {image = tokenplayerone.resource, scale = {0.17, 0.17, 0.17}}, doom = {image = tokenplayerone.doom, scale = {0.17, 0.17, 0.17}} } getObjectFromGUID("6161b4").interactable=false getObjectFromGUID("721ba2").interactable=false getObjectFromGUID("9f334f").interactable=false getObjectFromGUID("23a43c").interactable=false getObjectFromGUID("5450cc").interactable=false getObjectFromGUID("463022").interactable=false getObjectFromGUID("9487a4").interactable=false getObjectFromGUID("91dd9b").interactable=false getObjectFromGUID("f182ee").interactable=false end function take_callback(object_spawned, mat) customObject = object_spawned.getCustomObject() local player = mat.getGUID(); local image = customObject.image -- Update global stats if PULLS[image] == nil then PULLS[image] = 0 end PULLS[image] = PULLS[image] + 1 -- Update player stats if PLAYER_PULLS[player][image] == nil then PLAYER_PULLS[player][image] = 0 end PLAYER_PULLS[player][image] = PLAYER_PULLS[player][image] + 1 end MAT_GUID_TO_COLOUR = { ["8b081b"] = "White", -- player 2 conrad ["bd0ff4"] = "Orange", -- player ["383d8b"] = "Green", -- playur 4 olivia ["0840d5"] = "Red" } PLAYER_PULLS = { -- player 1 max ["8b081b"] = {}, -- player 2 conrad ["bd0ff4"] = {}, -- player ["383d8b"] = {}, -- playur 4 olivia ["0840d5"] = {} } PULLS = { -- cultist ["https://i.imgur.com/VzhJJaH.png"] = 0, -- skull ["https://i.imgur.com/stbBxtx.png"] = 0, -- tablet ["https://i.imgur.com/1plY463.png"] = 0, -- curse ["http://cloud-3.steamusercontent.com/ugc/1011565208488654691/8F0B399048EBC34CD24B99AAD415AEC40E679C65/"] = 0, -- tentacle ["https://i.imgur.com/lns4fhz.png"] = 0, -- minus eight ["https://i.imgur.com/9t3rPTQ.png"] = 0, -- minus seven ["https://i.imgur.com/4WRD42n.png"] = 0, -- minus six ["https://i.imgur.com/c9qdSzS.png"] = 0, -- minus five ["https://i.imgur.com/3Ym1IeG.png"] = 0, -- minus four ["https://i.imgur.com/qrgGQRD.png"] = 0, -- minus three ["https://i.imgur.com/yfs8gHq.png"] = 0, -- minus two ["https://i.imgur.com/bfTg2hb.png"] = 0, -- minus one ["https://i.imgur.com/w3XbrCC.png"] = 0, -- zero ["https://i.imgur.com/btEtVfd.png"] = 0, -- plus one ["https://i.imgur.com/uIx8jbY.png"] = 0, -- elder thing ["https://i.imgur.com/ttnspKt.png"] = 0, -- bless ["http://cloud-3.steamusercontent.com/ugc/1011565208488650618/B2B081032AF3EFDBD90840A5D6888A3CEA228D66/"] = 0, -- elder sign ["https://i.imgur.com/nEmqjmj.png"] = 0, } IMAGE_TOKEN_MAP = { -- cultist ["https://i.imgur.com/VzhJJaH.png"] = "cultist", -- skull ["https://i.imgur.com/stbBxtx.png"] = "skull", -- tablet ["https://i.imgur.com/1plY463.png"] = "tablet", -- elder thing ["https://i.imgur.com/ttnspKt.png"] = "Elder Thing", -- curse ["http://cloud-3.steamusercontent.com/ugc/1011565208488654691/8F0B399048EBC34CD24B99AAD415AEC40E679C65/"] = "curse", -- tentacle ["https://i.imgur.com/lns4fhz.png"] = "Auto-Fail", -- minus eight ["https://i.imgur.com/9t3rPTQ.png"] = "-8", -- minus seven ["https://i.imgur.com/4WRD42n.png"] = "-7", -- minus six ["https://i.imgur.com/c9qdSzS.png"] = "-6", -- minus five ["https://i.imgur.com/3Ym1IeG.png"] = "-5", -- minus four ["https://i.imgur.com/qrgGQRD.png"] = "-4", -- minus three ["https://i.imgur.com/yfs8gHq.png"] = "-3", -- minus two ["https://i.imgur.com/bfTg2hb.png"] = "-2", -- minus one ["https://i.imgur.com/w3XbrCC.png"] = "-1", -- zero ["https://i.imgur.com/btEtVfd.png"] = "0", -- plus one ["https://i.imgur.com/uIx8jbY.png"] = "+1", -- bless ["http://cloud-3.steamusercontent.com/ugc/1011565208488650618/B2B081032AF3EFDBD90840A5D6888A3CEA228D66/"] = "bless", -- elder sign ["https://i.imgur.com/nEmqjmj.png"] = "Elder Sign", } function resetStats() for key,value in pairs(PULLS) do PULLS[key] = 0 end for playerKey, playerValue in pairs(PLAYER_PULLS) do for key,value in pairs(PULLS) do PLAYER_PULLS[playerKey][key] = value end end end function getPlayerName(playerMatGuid) local playerColour = MAT_GUID_TO_COLOUR[playerMatGuid] if Player[playerColour].seated then return Player[playerColour].steam_name else return playerColour end end function printStats() local squidKing = "Nobody" local maxSquid = 0 printToAll("\nOverall Game stats\n") printNonZeroTokenPairs(PULLS) printToAll("\nIndividual Stats\n") for playerMatGuid, countTable in pairs(PLAYER_PULLS) do local playerName = getPlayerName(playerMatGuid) printToAll(playerName .. " Stats", {r=255,g=0,b=0}) printNonZeroTokenPairs(PLAYER_PULLS[playerMatGuid]) playerSquidCount = PLAYER_PULLS[playerMatGuid]["https://i.imgur.com/lns4fhz.png"] if playerSquidCount != nil and playerSquidCount > maxSquid then squidKing = playerName end end printToAll(squidKing .. " is an auto-fail magnet.", {r=255,g=0,b=0}) end function printNonZeroTokenPairs(theTable) for key,value in pairs(theTable) do if value != 0 then printToAll(IMAGE_TOKEN_MAP[key] .. '=' .. tostring(value)) end end end -- Remove comments to enable autorotate cards on hands. -- function onObjectEnterScriptingZone(zone, object) -- Autorotate cards with right side up when entering hand. -- if zone.getGUID() == "c506bf" or -- white -- zone.getGUID() == "cbc751" then -- orange -- object.setRotationSmooth({0,270,0}) -- elseif zone.getGUID() == "67ce9a" then -- green -- object.setRotationSmooth({0,0,0}) -- elseif zone.getGUID() == "57c22c" then -- red -- object.setRotationSmooth({0,180,0}) --end --end function findInRadiusBy(pos, radius, filter, debug) local radius = (radius or 1) local objList = Physics.cast({ origin = pos, direction = {0,1,0}, type = 2, size = {radius, radius, radius}, max_distance = 0, debug = (debug or false) }) local filteredList = {} for _, obj in ipairs(objList) do if filter == nil then table.insert(filteredList, obj.hit_object) elseif filter and filter(obj.hit_object) then table.insert(filteredList, obj.hit_object) end end return filteredList end function dealCardsInRows(paramlist) local currPosition={}; local numRow=1; local numCard=0; local invMultiplier=1; local allCardsDealed=0; if paramlist.inverse then invMultiplier=-1; end if paramlist.maxCardsDealed==nil then allCardsDealed=0; paramlist.maxCardsDealed=paramlist.cardDeck.getQuantity() elseif paramlist.maxCardsDealed>=paramlist.cardDeck.getQuantity() or paramlist.maxCardsDealed<=0 then allCardsDealed=0; paramlist.maxCardsDealed=paramlist.cardDeck.getQuantity() else allCardsDealed=1; end if paramlist.mode=="x" then currPosition={paramlist.iniPosition[1]+(2*g_cardWith*invMultiplier*allCardsDealed),paramlist.iniPosition[2],paramlist.iniPosition[3]}; else currPosition={paramlist.iniPosition[1],paramlist.iniPosition[2],paramlist.iniPosition[3]+(2*g_cardWith*invMultiplier*allCardsDealed)}; end for i = 1,paramlist.maxCardsDealed,1 do paramlist.cardDeck.takeObject ({ position= currPosition, smooth= true }); numCard=numCard+1; if numCard>=paramlist.maxCardRow then if paramlist.mode=="x" then currPosition={paramlist.iniPosition[1]+(2*g_cardWith*invMultiplier*allCardsDealed),paramlist.iniPosition[2],paramlist.iniPosition[3]}; currPosition[3]=currPosition[3]-(numRow*g_cardHeigth*invMultiplier); else currPosition={paramlist.iniPosition[1],paramlist.iniPosition[2],paramlist.iniPosition[3]+(2*g_cardWith*invMultiplier*allCardsDealed)}; currPosition[1]=currPosition[1]+(numRow*g_cardHeigth*invMultiplier); end numCard=0; numRow=numRow+1; else if paramlist.mode=="x" then currPosition[1]=currPosition[1]+(g_cardWith*invMultiplier); else currPosition[3]=currPosition[3]+(g_cardWith*invMultiplier); end end end end function isDeck(x) return x.tag == 'Deck' end function isCardOrDeck(x) return x.tag == 'Card' or isDeck(x) end function drawEncountercard(params) --[[ Parameter Table Position, Table Rotation]] local position = params[1] local rotation = params[2] local isFaceUp = params[3] local faceUpRotation if (isFaceUp) then faceUpRotation = 0 else faceUpRotation = 180 end local items = findInRadiusBy(ENCOUNTER_DECK_POS, 4, isCardOrDeck) if #items > 0 then for i, v in ipairs(items) do if v.tag == 'Deck' then v.takeObject({index = 0, position = position, rotation = {0,rotation.y,faceUpRotation}}) return end end -- we didn't find the deck so just pull the first thing we did find items[1].setPositionSmooth(position, false, false) items[1].setRotationSmooth({0,rotation.y,faceUpRotation}, false, false) return end -- nothing here, time to reshuffle reshuffleEncounterDeck(position, {0,rotation.y,faceUpRotation}) end IS_RESHUFFLING = false function reshuffleEncounterDeck(position, rotation) -- finishes moving the deck back and draws a card local function move(deck) deck.setPositionSmooth(ENCOUNTER_DECK_SPAWN_POS, true, false) deck.takeObject({index = 0, position = position, rotation = rotation, flip = false}) Wait.time(function() IS_RESHUFFLING = false end, 1) end -- bail out if we're mid reshuffle if IS_RESHUFFLING then return end local discarded = findInRadiusBy(ENCOUNTER_DECK_DISCARD_POSITION, 4, isDeck) if #discarded > 0 then IS_RESHUFFLING = true local deck = discarded[1] if not deck.is_face_down then deck.flip() end deck.shuffle() Wait.time(|| move(deck), 0.3) else printToAll("couldn't find encounter discard pile to reshuffle", {1, 0, 0}) end end CHAOS_TOKENS = {} CHAOS_TOKENS_LAST_MAT = nil function putBackChaosTokens() local chaosbagposition = chaosbag.getPosition() for k, token in pairs(CHAOS_TOKENS) do if token != nil then chaosbag.putObject(token) token.setPosition({chaosbagposition[1],chaosbagposition[2]+0.5,chaosbagposition[3]}) end end CHAOS_TOKENS = {} end function drawChaostoken(params) local mat = params[1] local tokenOffset = params[2] local isRightClick = params[3] local isSameMat = (CHAOS_TOKENS_LAST_MAT == nil or CHAOS_TOKENS_LAST_MAT == mat) if not isSameMat then putBackChaosTokens() end CHAOS_TOKENS_LAST_MAT = mat -- if we have left clicked and have no tokens OR if we have right clicked if isRightClick or #CHAOS_TOKENS == 0 then local items = getObjectFromGUID("83ef06").getObjects() for i,v in ipairs(items) do if items[i].getDescription() == "Chaos Bag" then chaosbag = getObjectFromGUID(items[i].getGUID()) break end end -- bail out if we have no tokens if #chaosbag.getObjects() == 0 then return end chaosbag.shuffle() -- add the token to the list, compute new position based on list length tokenOffset[1] = tokenOffset[1] + (0.17 * #CHAOS_TOKENS) local toPosition = mat.positionToWorld(tokenOffset) local token = chaosbag.takeObject({ index = 0, position = toPosition, rotation = mat.getRotation(), callback_function = function(obj) take_callback(obj, mat) end }) CHAOS_TOKENS[#CHAOS_TOKENS + 1] = token return else putBackChaosTokens() end end function spawnToken(params) -- Position to spawn, -- rotation vector to apply -- translation vector to apply -- token type local position = params[1] local tokenType = params[2] local tokenData = TOKEN_DATA[tokenType] if tokenData == nil then error("no token data found for '" .. tokenType .. "'") end local token = spawnObject({ type = 'Custom_Token', position = position, rotation = {x=0, y=270, z=0} }) token.setCustomObject({ image = tokenData['image'], thickness = 0.3, merge_distance = 5.0, stackable = true, }) token.use_snap_points=false token.scale(tokenData['scale']) return token end function round(params) -- Parameter (int number, int numberDecimalPlaces) return tonumber(string.format("%." .. (params[2] or 0) .. "f", params[1])) end function roundposition(params) -- Parameter (Table position) return {round({params[1], 2}),round({params[2], 2}),round({params[3], 2})} end function isEqual(params) --Parameter (Table table1, Table table2) returns true if the tables are equal if params[1][1] == params[2][1] and params[1][2] == params[2][2] and params[1][3] == params[2][3] then return true else return false end end function isFaceup(params) --Object object if params.getRotation()[3] > -5 and params.getRotation()[3] < 5 then return true else return false end end --Difficulty selector script function createSetupButtons(args) local data = getDataValue('modeData', args.key) if data ~= nil then local z = -0.15 if data.easy ~= nil then args.object.createButton({ label = 'Easy', click_function = 'easyClick', function_owner = args.object, position = {0, 0.1, z}, rotation = {0, 0, 0}, scale = {0.47, 1, 0.47}, height = 200, width = 1150, font_size = 100, color = {0.87, 0.8, 0.70}, font_color = {0, 0, 0} }) z = z + 0.20 end if data.normal ~= nil then args.object.createButton({ label = 'Standard', click_function = 'normalClick', function_owner = args.object, position = {0, 0.1, z}, rotation = {0, 0, 0}, scale = {0.47, 1, 0.47}, height = 200, width = 1150, font_size = 100, color = {0.87, 0.8, 0.70}, font_color = {0, 0, 0} }) z = z + 0.20 end if data.hard ~= nil then args.object.createButton({ label = 'Hard', click_function = 'hardClick', function_owner = args.object, position = {0, 0.1, z}, rotation = {0, 0, 0}, scale = {0.47, 1, 0.47}, height = 200, width = 1150, font_size = 100, color = {0.87, 0.8, 0.70}, font_color = {0, 0, 0} }) z = z + 0.20 end if data.expert ~= nil then args.object.createButton({ label = 'Expert', click_function = 'expertClick', function_owner = args.object, position = {0, 0.1, z}, rotation = {0, 0, 0}, scale = {0.47, 1, 0.47}, height = 200, width = 1150, font_size = 100, color = {0.87, 0.8, 0.70}, font_color = {0, 0, 0} }) z = z + 0.20 end z = z + 0.10 if data.standalone ~= nil then args.object.createButton({ label = 'Standalone', click_function = 'standaloneClick', function_owner = args.object, position = {0, 0.1, z}, rotation = {0, 0, 0}, scale = {0.47, 1, 0.47}, height = 200, width = 1150, font_size = 100, color = {0.87, 0.8, 0.70}, font_color = {0, 0, 0} }) end end end function fillContainer(args) local container = getObjectCache(containerId) if container ~= nil then local data = getDataValue('modeData', args.key) if data == nil then return end local value = data[args.mode] if value == nil or value.token == nil then return end local pos = container.getPosition() if args.object ~= nil then pos = args.object.getPosition() end cleanContainer(container) for _, token in ipairs(value.token) do local obj = spawnToken_2(token, pos) if obj ~= nil then container.putObject(obj) end end if value.append ~= nil then for _, token in ipairs(value.append) do local obj = spawnToken_2(token, pos) if obj ~= nil then container.putObject(obj) end end end if value.random then local n = #value.random if n > 0 then for _, token in ipairs(value.random[getRandomCount(n)]) do local obj = spawnToken_2(token, pos) if obj ~= nil then container.putObject(obj) end end end end if value.message then broadcastToAll(value.message) end if value.warning then broadcastToAll(value.warning, { 1, 0.5, 0.5 }) end end end function spawnToken_2(id, pos) local url = getImageUrl(id) if url ~= '' then local obj = spawnObject({ type = 'Custom_Tile', position = {pos.x, pos.y + 3, pos.z}, rotation = {x = 0, y = 260, z = 0} }) obj.setCustomObject({ type = 2, image = url, thickness = 0.10, }) obj.scale {0.81, 1, 0.81} return obj end end function getImageUrl(id) if id == 'p1' then return 'https://i.imgur.com/uIx8jbY.png' end if id == '0' then return 'https://i.imgur.com/btEtVfd.png' end if id == 'm1' then return 'https://i.imgur.com/w3XbrCC.png' end if id == 'm2' then return 'https://i.imgur.com/bfTg2hb.png' end if id == 'm3' then return 'https://i.imgur.com/yfs8gHq.png' end if id == 'm4' then return 'https://i.imgur.com/qrgGQRD.png' end if id == 'm5' then return 'https://i.imgur.com/3Ym1IeG.png' end if id == 'm6' then return 'https://i.imgur.com/c9qdSzS.png' end if id == 'm7' then return 'https://i.imgur.com/4WRD42n.png' end if id == 'm8' then return 'https://i.imgur.com/9t3rPTQ.png' end if id == 'skull' then return 'https://i.imgur.com/stbBxtx.png' end if id == 'cultist' then return 'https://i.imgur.com/VzhJJaH.png' end if id == 'tablet' then return 'https://i.imgur.com/1plY463.png' end if id == 'elder' then return 'https://i.imgur.com/ttnspKt.png' end if id == 'red' then return 'https://i.imgur.com/lns4fhz.png' end if id == 'blue' then return 'https://i.imgur.com/nEmqjmj.png' end return '' end function cleanContainer(container) for _, item in ipairs(container.getObjects()) do destroyObject(container.takeObject({})) end end function getObjectsInZone(zoneId) local zoneObject = getObjectCache(zoneId) if zoneObject == nil then return end local objectsInZone = zoneObject.getObjects() local objectsFound = {} for i = 1, #objectsInZone do local object = objectsInZone[i] if object.tag == 'Bag' then table.insert(objectsFound, object.guid) end end if #objectsFound > 0 then return objectsFound end end function getObjectCache(id) if CACHE.object[id] == nil then CACHE.object[id] = getObjectFromGUID(id) end return CACHE.object[id] end function getDataTable(storage) if CACHE.data[storage] == nil then local obj = getObjectCache(tokenDataId) if obj ~= nil then CACHE.data[storage] = obj.getTable(storage) end end return CACHE.data[storage] end function getDataValue(storage, key) local data = getDataTable(storage) if data ~= nil then local value = data[key] if value ~= nil then local res = {} for m, v in pairs(value) do res[m] = v if res[m].parent ~= nil then local parentData = getDataValue(storage, res[m].parent) if parentData ~= nil and parentData[m] ~= nil and parentData[m].token ~= nil then res[m].token = parentData[m].token end res[m].parent = nil end end return res end end end function getRandomCount(to) updateRandomSeed() return math.random(1, to) end function updateRandomSeed() local chance = math.random(1,10) if chance == 1 then math.randomseed(os.time()) end end