├── .emmyrc.json ├── .gitattributes ├── .gitignore ├── Clever Notecard ├── notecard.lua └── notecard.xml ├── Commander Gen 2 ├── DEPRECATED │ ├── Boss │ │ ├── boss.lua │ │ └── boss.xml │ └── Token │ │ ├── token.lua │ │ └── token.xml ├── Initiative Stuff │ ├── initiative preset │ │ ├── epic.lua │ │ └── lair.lua │ ├── initiative-mat.lua │ ├── initiative-mat.xml │ └── initiative-token.lua ├── Monster Token │ ├── monster.lua │ ├── ui.lua │ └── ui.xml ├── NPC Commander.v2.lua └── README.md ├── DEPRECATED ├── NPC Commander v0.lua ├── README.md ├── notecard.lua ├── rolling-block.lua ├── token-boss.lua ├── token-boss.xml ├── token-tracker.lua ├── token.lua └── token.xml ├── HUD ├── Assets │ ├── Widget-flipped-open.png │ ├── Widget-flipped-overlay.png │ ├── Widget-flipper.png │ ├── Widget-open.png │ ├── Widget-overlay.png │ ├── Widget.png │ ├── ally-open.png │ ├── ally.png │ ├── enemy-open.png │ ├── enemy.png │ ├── neutral-open.png │ ├── neutral.png │ ├── player-open.png │ ├── player.png │ ├── player_request.png │ ├── reminder-closed.png │ ├── reminder-glow.png │ └── reminder-open.png ├── HUD.lua ├── HUD.xml ├── Projector-Global.lua ├── Projector-Global.xml ├── average-hud.lua ├── average-hud.xml ├── breaker.lua ├── breaker.xml ├── epic-reminder.lua ├── epic-reminder.xml ├── initiative-hud.lua ├── initiative-hud.xml ├── reminder-hud.lua └── reminder-hud.xml ├── LICENSE ├── Projector.lua ├── README.md ├── Utility tools ├── Color Switcher Tool.lua ├── README.md ├── empty-container.lua ├── mansion-mover.lua └── memo-viewer.lua ├── VERSIONS ├── average-button.lua ├── average-notecard.lua ├── bag-peeker.lua ├── bundle-map.lua ├── card creator ├── card creator-2.0.lua ├── card creator.lua └── card creator.xml ├── command-manager.lua ├── debug-button.lua ├── dice-mat.lua ├── dice-rolling-tool.lua ├── exploding_dice ├── .exploding-strip.lua ├── dice-bundler.lua ├── exploding-dice.lua └── exploding-note.lua ├── hide-me.lua ├── image-changer.lua ├── interactable.lua ├── item-positioner.lua ├── item-stack.lua ├── macro-maker.lua ├── map-positioner.lua ├── notecard 2.0.lua ├── pin-positioner.lua ├── pin.lua ├── pin.xml ├── player_manager ├── conditions │ ├── blinded.png │ ├── charmed.png │ ├── concentration.png │ ├── deafened.png │ ├── frightened.png │ ├── grappled.png │ ├── incapacitated.png │ ├── invisible.png │ ├── on fire.png │ ├── paralyzed.png │ ├── petrified.png │ ├── poisoned.png │ ├── restrained.png │ └── stunned.png ├── move-token-snippet.lua ├── move-token-snippet.min.lua ├── player-manager-area.lua ├── player-manager-area.min.lua ├── player-manager.lua ├── player-manager.xml ├── readme.md ├── shapes │ ├── circle.png │ ├── cone.png │ └── cube.png ├── state-player-manager.lua └── state-player-manager.min.lua ├── potion maker ├── potion maker.lua └── potion maker.xml ├── reset-characters.lua ├── script-updater.lua ├── table-updater.lua ├── table-updater.xml └── tarot-cards.lua /.emmyrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "diagnostics": { 3 | "disable": ["undefined-global"] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode/ -------------------------------------------------------------------------------- /Clever Notecard/notecard.lua: -------------------------------------------------------------------------------- 1 | --[[StartXML 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | Description 9 | StopXML--xml]] 10 | 11 | 12 | function loadXML() 13 | local script = self.getLuaScript() 14 | local xml = script:sub(script:find("StartXML")+8, script:find("StopXML")-1) 15 | self.UI.setXml(xml) 16 | Wait.frames(function() setData() end, 20) 17 | end 18 | 19 | local commander = "878b50" 20 | 21 | function onload() 22 | loadXML() 23 | 24 | local data = { 25 | click_function = "parse", 26 | function_owner = self, 27 | label = "Parse", 28 | position = {1.92, 0.1, 1.33}, 29 | scale = {0.3, 0.3, 0.3}, 30 | width = 1200, 31 | height = 500, 32 | font_size = 400, 33 | color = {0.1341, 0.1341, 0.1341, 1}, 34 | font_color = {1, 1, 1, 1}, 35 | tooltip = "Parse" 36 | } 37 | 38 | self.addContextMenuItem("Set Commander", function(player) 39 | if Player[player].admin then 40 | local guid = self.getName() 41 | local obj = getObjectFromGUID(guid) 42 | if not obj then 43 | broadcastToColor("You must write the NPC Commander ID as the name of the notecard.", "Black", Color.White) 44 | else 45 | self.memo = guid 46 | end 47 | end 48 | end, false) 49 | self.createButton(data) 50 | end 51 | 52 | function onHover() 53 | setData() 54 | end 55 | 56 | function setData() 57 | self.UI.setAttribute("title", "text", self.getName()) 58 | self.UI.setAttribute("description", "text", self.getDescription()) 59 | end 60 | 61 | function parse() 62 | if self.getDescription() ~= "" and self.getName() ~= "" then 63 | local vars = JSON.decode(self.getDescription()) 64 | local npc_commander = getObjectFromGUID(self.memo or commander) 65 | 66 | if vars.name then 67 | npc_commander.call("setName", {input = vars.name}) 68 | end 69 | 70 | if vars.ini then 71 | npc_commander.call("setINI", {input = vars.ini}) 72 | end 73 | 74 | if vars.hp then 75 | npc_commander.call("setHP", {input = vars.hp}) 76 | end 77 | 78 | if vars.ac then 79 | npc_commander.call("setAC", {input = vars.ac}) 80 | end 81 | 82 | if vars.mov then 83 | npc_commander.call("setMovement", {input = vars.mov}) 84 | end 85 | 86 | if vars.size then 87 | npc_commander.call("setSize", {input = vars.size}) 88 | end 89 | 90 | if vars.image then 91 | npc_commander.setDescription(vars.image) 92 | npc_commander.call("toggleIsBoss", {input = true}) 93 | else 94 | npc_commander.call("toggleIsBoss", {input = false}) 95 | end 96 | 97 | if vars.side then 98 | npc_commander.call("setSide", {input = vars.side}) 99 | else 100 | npc_commander.call("setSide", {input = "enemy"}) 101 | end 102 | 103 | if vars.extra then 104 | npc_commander.call("setExtraParams", vars.extra) 105 | else 106 | npc_commander.call("setExtraParams", nil) 107 | end 108 | 109 | if self.getGMNotes() ~= "" then 110 | -- this means i have multiple that i want to make 111 | local number = tonumber(self.getGMNotes()) 112 | npc_commander.call("setNumberToCreate", {input = number}) 113 | else 114 | npc_commander.call("setNumberToCreate", {input = 1}) 115 | end 116 | end 117 | end 118 | 119 | function mysplit(inputstr, sep) 120 | if sep == nil then 121 | sep = "%s" 122 | end 123 | local t = {} 124 | i = 1 125 | for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do 126 | t[i] = str 127 | i = i + 1 128 | end 129 | return t 130 | end 131 | -------------------------------------------------------------------------------- /Clever Notecard/notecard.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | Description -------------------------------------------------------------------------------- /Commander Gen 2/DEPRECATED/Boss/boss.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | 23 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Commander Gen 2/DEPRECATED/Token/token.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | 20 | 21 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Commander Gen 2/Initiative Stuff/initiative preset/epic.lua: -------------------------------------------------------------------------------- 1 | --Runs when the scripted button inside the button is clicked 2 | function buttonPress() 3 | if lockout == false then 4 | local gm = self.getGMNotes() 5 | 6 | if gm ~= nil then 7 | local bag = getObjectFromGUID(gm) 8 | local pos = self.getPosition() 9 | pos.y = pos.y + 3 10 | local takeParams = { 11 | position = pos, 12 | rotation = {0, 0, 0}, 13 | callback_function = function(spawned) 14 | Wait.time( 15 | function() 16 | spawned.call( 17 | "_init", 18 | { 19 | input = { 20 | name = "Epic Die", 21 | modifier = 50, 22 | pawn = "", 23 | side = "epic", 24 | static = true 25 | } 26 | } 27 | ) 28 | end, 29 | 1 30 | ) 31 | end 32 | } 33 | bag.takeObject(takeParams) 34 | end 35 | 36 | self.AssetBundle.playTriggerEffect(0) --triggers animation/sound 37 | lockout = true --locks out the button 38 | startLockoutTimer() --Starts up a timer to remove lockout 39 | end 40 | end 41 | 42 | --Runs on load, creates button and makes sure the lockout is off 43 | function onload() 44 | self.createButton( 45 | { 46 | label = "Big Red Button\n\nBy: MrStump", 47 | click_function = "buttonPress", 48 | function_owner = self, 49 | position = {0, 0.25, 0}, 50 | height = 1400, 51 | width = 1400 52 | } 53 | ) 54 | lockout = false 55 | end 56 | 57 | --Starts a timer that, when it ends, will unlock the button 58 | function startLockoutTimer() 59 | Timer.create({identifier = self.getGUID(), function_name = "unlockLockout", delay = 0.5}) 60 | end 61 | 62 | --Unlocks button 63 | function unlockLockout() 64 | lockout = false 65 | end 66 | 67 | --Ends the timer if the object is destroyed before the timer ends, to prevent an error 68 | function onDestroy() 69 | Timer.destroy(self.getGUID()) 70 | end 71 | -------------------------------------------------------------------------------- /Commander Gen 2/Initiative Stuff/initiative preset/lair.lua: -------------------------------------------------------------------------------- 1 | --Runs when the scripted button inside the button is clicked 2 | function buttonPress() 3 | if lockout == false then 4 | local gm = self.getGMNotes() 5 | 6 | if gm ~= nil then 7 | local bag = getObjectFromGUID(gm) 8 | local pos = self.getPosition() 9 | pos.y = pos.y + 3 10 | local takeParams = { 11 | position = pos, 12 | rotation = {0, 0, 0}, 13 | callback_function = function(spawned) 14 | Wait.time( 15 | function() 16 | spawned.call( 17 | "_init", 18 | { 19 | input = { 20 | name = "Lair", 21 | modifier = 20, 22 | pawn = "", 23 | side = "lair", 24 | static = true 25 | } 26 | } 27 | ) 28 | end, 29 | 1 30 | ) 31 | end 32 | } 33 | bag.takeObject(takeParams) 34 | end 35 | 36 | self.AssetBundle.playTriggerEffect(0) --triggers animation/sound 37 | lockout = true --locks out the button 38 | startLockoutTimer() --Starts up a timer to remove lockout 39 | end 40 | end 41 | 42 | --Runs on load, creates button and makes sure the lockout is off 43 | function onload() 44 | self.createButton( 45 | { 46 | label = "Big Red Button\n\nBy: MrStump", 47 | click_function = "buttonPress", 48 | function_owner = self, 49 | position = {0, 0.25, 0}, 50 | height = 1400, 51 | width = 1400 52 | } 53 | ) 54 | lockout = false 55 | end 56 | 57 | --Starts a timer that, when it ends, will unlock the button 58 | function startLockoutTimer() 59 | Timer.create({identifier = self.getGUID(), function_name = "unlockLockout", delay = 0.5}) 60 | end 61 | 62 | --Unlocks button 63 | function unlockLockout() 64 | lockout = false 65 | end 66 | 67 | --Ends the timer if the object is destroyed before the timer ends, to prevent an error 68 | function onDestroy() 69 | Timer.destroy(self.getGUID()) 70 | end 71 | -------------------------------------------------------------------------------- /Commander Gen 2/Initiative Stuff/initiative-mat.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | StopXML--xml]] -------------------------------------------------------------------------------- /Commander Gen 2/Monster Token/ui.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Commander Gen 2/README.md: -------------------------------------------------------------------------------- 1 | This is the main tool that you will use for the most part. If you want to understand most of the things that are used in the project then this is where you should start. 2 | -------------------------------------------------------------------------------- /DEPRECATED/README.md: -------------------------------------------------------------------------------- 1 | ### Deprecated stuff folder 2 | Even though all this stuff has not been used for a very long time as they have been replaced by a much better version of themselves, this is kept here for the sake of keeping working code in the github itself. -------------------------------------------------------------------------------- /DEPRECATED/notecard.lua: -------------------------------------------------------------------------------- 1 | --local commander = "9d42ad" 2 | local commander = "878b50" 3 | 4 | function onLoad() 5 | local data = { 6 | click_function = "parse", 7 | function_owner = self, 8 | label = "Parse", 9 | position = {-0.39, 2.4, -0.43}, 10 | rotation = {0, 180, 0}, 11 | scale = {0.1, 1, 0.18}, 12 | width = 1100, 13 | height = 400, 14 | font_size = 400, 15 | color = {0.1341, 0.1341, 0.1341, 1}, 16 | font_color = {1, 1, 1, 1} 17 | } 18 | self.createButton(data) 19 | end 20 | 21 | --/|2|r50-68|12|6|2d6+4 22 | 23 | function parse() 24 | if self.getDescription() ~= "" and self.getName() ~= "" then 25 | local stuff = mysplit(mysplit(self.getDescription(), "\n")[1], "|") 26 | local npc_commander = getObjectFromGUID(commander) 27 | npc_commander.call("setName", {input = stuff[1]}) 28 | npc_commander.call("setINI", {input = stuff[2]}) 29 | npc_commander.call("setHP", {input = stuff[3]}) 30 | npc_commander.call("setAC", {input = stuff[4]}) 31 | npc_commander.call("setATK", {input = stuff[5]}) 32 | npc_commander.call("setDMG", {input = stuff[6]}) 33 | 34 | if stuff[7] then 35 | npc_commander.call("setMovement", {input = stuff[7]}) 36 | end 37 | 38 | if stuff[8] then 39 | npc_commander.call("setSize", {input = stuff[8]}) 40 | end 41 | 42 | local second_line = mysplit(self.getDescription(), "\n")[2] 43 | if second_line ~= nil and second_line ~= "" then 44 | -- this means it is a boss 45 | npc_commander.setDescription(second_line) 46 | npc_commander.call("toggleIsBoss", {input = true}) 47 | else 48 | npc_commander.call("toggleIsBoss", {input = false}) 49 | end 50 | 51 | if self.getGMNotes() ~= "" then 52 | -- this means i have multiple that i want to make 53 | local number = tonumber(self.getGMNotes()) 54 | npc_commander.call("setNumberToCreate", {input = number}) 55 | end 56 | end 57 | end 58 | 59 | function mysplit(inputstr, sep) 60 | if sep == nil then 61 | sep = "%s" 62 | end 63 | local t = {} 64 | i = 1 65 | for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do 66 | t[i] = str 67 | i = i + 1 68 | end 69 | return t 70 | end 71 | -------------------------------------------------------------------------------- /DEPRECATED/rolling-block.lua: -------------------------------------------------------------------------------- 1 | local _sz = "876993" 2 | local reference = nil 3 | 4 | self.createInput({ 5 | input_function = "name", 6 | function_owner = self, 7 | label = "Name", 8 | alignment = 3, 9 | position = {x=0, y=0.5, z=-0.3}, 10 | rotation = {0, 0, 0}, 11 | width = 1600, 12 | height = 400, 13 | font_size = 200, 14 | validation = 1, 15 | scale = {0.3, 0.5, 0.4}, 16 | }) 17 | 18 | self.createInput({ 19 | input_function = "value", 20 | function_owner = self, 21 | label = "V", 22 | alignment = 3, 23 | position = {x=-0.4, y=0.5, z=0.15}, 24 | rotation = {0, 0, 0}, 25 | width = 300, 26 | height = 300, 27 | font_size = 260, 28 | validation = 2, 29 | scale = {0.3, 0.3, 0.6}, 30 | }) 31 | 32 | self.createInput({ 33 | input_function = "modifier", 34 | function_owner = self, 35 | label = "M", 36 | alignment = 3, 37 | position = {x=-0.2, y=0.5, z=0.15}, 38 | rotation = {0, 0, 0}, 39 | width = 300, 40 | height = 300, 41 | font_size = 260, 42 | validation = 2, 43 | scale = {0.3, 0.3, 0.6}, 44 | }) 45 | 46 | self.createInput({ 47 | input_function = "name", 48 | function_owner = self, 49 | label = "R", 50 | alignment = 3, 51 | position = {x=0.1, y=0.5, z=0.15}, 52 | rotation = {0, 0, 0}, 53 | width = 580, 54 | height = 300, 55 | font_size = 260, 56 | validation = 1, 57 | scale = {0.3, 0.3, 0.6}, 58 | }) 59 | 60 | self.createButton({ 61 | click_function = "roll_die", 62 | function_owner = self, 63 | label = "R", 64 | position = {0.4, 0.5, 0.15}, 65 | scale = {0.3, 0.3, 0.6}, 66 | width = 380, 67 | height = 300, 68 | font_size = 260, 69 | tooltip = "R", 70 | alignment = 3 71 | }) 72 | 73 | function modifier(obj, color, input, stillEditing) 74 | if not stillEditing then 75 | local die = findDie() 76 | if die then 77 | die.setDescription(input) 78 | else 79 | broadcastToColor("delete me pls", "Black", {1,1,1}) 80 | end 81 | updateResult() 82 | end 83 | end 84 | 85 | function findDie() 86 | if not reference then 87 | local name = getTop() 88 | local zone = getObjectFromGUID(_sz) 89 | local dices = zone.getObjects() 90 | for i=0, #dices do 91 | local die = dices[i] 92 | if die then 93 | if die.getName() == name then 94 | reference = die 95 | return reference 96 | end 97 | end 98 | end 99 | end 100 | return reference 101 | end 102 | 103 | function value(obj, color, input, stillEditing) 104 | if not stillEditing then 105 | updateResult() 106 | end 107 | end 108 | 109 | function updateModifier(params) 110 | self.editInput({index=2, value=params.input}) 111 | updateResult() 112 | end 113 | 114 | function updateResult() 115 | self.editInput({index=3, value="= "..getValue() + getModifier()}) 116 | end 117 | 118 | function getTop() 119 | return self.getInputs()[1].value 120 | end 121 | function getValue() 122 | return tonumber(self.getInputs()[2].value) 123 | end 124 | function getModifier() 125 | return tonumber(self.getInputs()[3].value) 126 | end 127 | function getResult() 128 | return tonumber(self.getInputs()[4].value) 129 | end 130 | 131 | function name() 132 | end 133 | 134 | function roll_die() 135 | local obj = findDie() 136 | obj.roll() 137 | local rollWatch = function() return obj.resting end 138 | local rollEnd = function() 139 | self.editInput({index=1, value = obj.getRotationValue()}) 140 | updateResult() 141 | end 142 | Wait.condition(rollEnd, rollWatch) 143 | end 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /DEPRECATED/token-boss.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /DEPRECATED/token-tracker.lua: -------------------------------------------------------------------------------- 1 | -- textbox = { 2 | -- --[[ 3 | -- pos = the position (pasted from the helper tool) 4 | -- rows = how many lines of text you want for this box 5 | -- width = how wide the text box is 6 | -- font_size = size of text. This and "rows" effect overall height 7 | -- label = what is shown when there is no text. "" = nothing 8 | -- value = text entered into box. "" = nothing 9 | -- alignment = Number to indicate how you want text aligned 10 | -- (1=Automatic, 2=Left, 3=Center, 4=Right, 5=Justified) 11 | -- ]] 12 | local _color = {1, 1, 1, 0.3} 13 | local _tracker_name = "npc_tracker" 14 | 15 | function onLoad() 16 | -- name 17 | self.createInput( 18 | { 19 | input_function = "none", 20 | function_owner = self, 21 | label = "Name", 22 | position = {0.6, 0.1, -0.6}, 23 | scale = {0.6, 0.6, 0.7}, 24 | width = 3000, 25 | height = 470, 26 | font_size = 400, 27 | color = {1, 1, 1, 0}, 28 | font_color = {1, 1, 1, 100}, 29 | alignment = 3, 30 | value = "" 31 | } 32 | ) 33 | 34 | -- hp 35 | self.createInput( 36 | { 37 | input_function = "hp", 38 | function_owner = self, 39 | label = "HP", 40 | position = {-1.63, 0.1, 0.7}, 41 | scale = {0.8, 0.5, 0.9}, 42 | width = 500, 43 | height = 440, 44 | font_size = 400, 45 | color = _color, 46 | font_color = {0, 0, 0, 100}, 47 | alignment = 3, 48 | value = "" 49 | } 50 | ) 51 | 52 | -- ac 53 | self.createInput( 54 | { 55 | input_function = "ac", 56 | function_owner = self, 57 | label = "AC", 58 | position = {-0.43, 0.1, 0.7}, 59 | scale = {0.8, 0.5, 0.9}, 60 | width = 500, 61 | height = 440, 62 | font_size = 400, 63 | color = _color, 64 | font_color = {0, 0, 0, 100}, 65 | alignment = 3, 66 | value = "" 67 | } 68 | ) 69 | 70 | -- atk 71 | self.createInput( 72 | { 73 | input_function = "atk", 74 | function_owner = self, 75 | label = "ATK", 76 | position = {0.77, 0.1, 0.7}, 77 | scale = {0.8, 0.5, 0.9}, 78 | width = 500, 79 | height = 440, 80 | font_size = 150, 81 | color = _color, 82 | font_color = {0, 0, 0, 100}, 83 | alignment = 3, 84 | value = "" 85 | } 86 | ) 87 | 88 | self.createInput( 89 | { 90 | input_function = "dmg", 91 | function_owner = self, 92 | label = "DMG", 93 | position = {1.97, 0.1, 0.7}, 94 | scale = {0.8, 0.5, 0.9}, 95 | width = 500, 96 | height = 440, 97 | font_size = 150, 98 | color = _color, 99 | font_color = {0, 0, 0, 100}, 100 | alignment = 3, 101 | value = "" 102 | } 103 | ) 104 | 105 | self.createButton( 106 | { 107 | click_function = "none", 108 | function_owner = self, 109 | label = " ", 110 | position = {-1.9, 0.1, -0.62}, 111 | scale = {0.5, 0.5, 0.5}, 112 | width = 600, 113 | height = 600, 114 | font_size = 400 115 | } 116 | ) 117 | end 118 | 119 | function none() 120 | end 121 | 122 | function hp(self, color, text, stillEditing) 123 | if not stillEditing then 124 | local size = convertSize(text) 125 | self.editInput({index = 1, font_size = size}) 126 | end 127 | end 128 | 129 | function ac(self, color, text, stillEditing) 130 | if not stillEditing then 131 | local size = convertSize(text) 132 | self.editInput({index = 2, font_size = size}) 133 | end 134 | end 135 | 136 | function atk(self, color, text, stillEditing) 137 | if not stillEditing then 138 | local size = convertSize(text) 139 | self.editInput({index = 3, font_size = size}) 140 | end 141 | end 142 | 143 | function dmg(self, color, text, stillEditing) 144 | if not stillEditing then 145 | local size = convertSize(text) 146 | self.editInput({index = 4, font_size = size}) 147 | end 148 | end 149 | 150 | function convertSize(input) 151 | if string.len(input) <= 2 then 152 | return 400 153 | elseif string.len(input) == 3 then 154 | return 300 155 | else 156 | return 150 157 | end 158 | end 159 | 160 | function setName(params) 161 | self.editInput({index = 0, value = params.input}) 162 | end 163 | 164 | function setHP(params) 165 | self.editInput({index = 1, value = params.input}) 166 | local size = convertSize(params.input) 167 | self.editInput({index = 1, font_size = size}) 168 | end 169 | function setAC(params) 170 | self.editInput({index = 2, value = params.input}) 171 | local size = convertSize(params.input) 172 | self.editInput({index = 2, font_size = size}) 173 | end 174 | function setATK(params) 175 | self.editInput({index = 3, value = params.input}) 176 | local size = convertSize(params.input) 177 | self.editInput({index = 3, font_size = size}) 178 | end 179 | function setDMG(params) 180 | self.editInput({index = 4, value = params.input}) 181 | local size = convertSize(params.input) 182 | self.editInput({index = 4, font_size = size}) 183 | end 184 | 185 | function setColor(params) 186 | self.editButton({index = 0, color = params.input}) 187 | end 188 | 189 | function order(params) 190 | local blockPosition = {x = 42.83, y = 1.5, z = -2.77} 191 | local zone = getObjectFromGUID(params.input) 192 | local objs = zone.getObjects() 193 | local x_diffence = 2.16 194 | local z_difference = 4.87 195 | local row = 1 196 | for i = 0, #objs do 197 | local obj = objs[i] 198 | if obj then 199 | if obj.getName() == _tracker_name then 200 | obj.setPositionSmooth(blockPosition, false, true) 201 | obj.setRotationSmooth({0, 90, 0}, false, true) 202 | if row == 1 then 203 | blockPosition.x = blockPosition.x + x_diffence 204 | row = row + 1 205 | elseif row == 2 then 206 | row = 1 207 | blockPosition.x = 42.83 208 | blockPosition.z = blockPosition.z + z_difference 209 | end 210 | end 211 | end 212 | end 213 | end 214 | 215 | --function mysplit(inputstr, sep) 216 | -- if sep == nil then 217 | -- sep = "%s" 218 | -- end 219 | -- local t={} ; i=1 220 | -- for str in string.gmatch(inputstr, "([^"..sep.."]+)") do 221 | -- t[i] = str 222 | -- i = i + 1 223 | -- end 224 | -- return t 225 | --end 226 | -- 227 | --function getHP(text) 228 | -- local spl = mysplit(text, "\n")[1] 229 | -- return mysplit(spl, " ")[2] 230 | --end 231 | -- 232 | --function getAC(text) 233 | -- local spl = mysplit(text, "\n")[2] 234 | -- return mysplit(spl, " ")[2] 235 | --end 236 | --function getATK(text) 237 | -- local spl = mysplit(text, "\n")[3] 238 | -- return mysplit(spl, " ")[2] 239 | --end 240 | --function getDMG(text) 241 | -- local spl = mysplit(text, "\n")[4] 242 | -- return mysplit(spl, " ")[2] 243 | --end 244 | -------------------------------------------------------------------------------- /DEPRECATED/token.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /HUD/Assets/Widget-flipped-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/Widget-flipped-open.png -------------------------------------------------------------------------------- /HUD/Assets/Widget-flipped-overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/Widget-flipped-overlay.png -------------------------------------------------------------------------------- /HUD/Assets/Widget-flipper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/Widget-flipper.png -------------------------------------------------------------------------------- /HUD/Assets/Widget-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/Widget-open.png -------------------------------------------------------------------------------- /HUD/Assets/Widget-overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/Widget-overlay.png -------------------------------------------------------------------------------- /HUD/Assets/Widget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/Widget.png -------------------------------------------------------------------------------- /HUD/Assets/ally-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/ally-open.png -------------------------------------------------------------------------------- /HUD/Assets/ally.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/ally.png -------------------------------------------------------------------------------- /HUD/Assets/enemy-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/enemy-open.png -------------------------------------------------------------------------------- /HUD/Assets/enemy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/enemy.png -------------------------------------------------------------------------------- /HUD/Assets/neutral-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/neutral-open.png -------------------------------------------------------------------------------- /HUD/Assets/neutral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/neutral.png -------------------------------------------------------------------------------- /HUD/Assets/player-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/player-open.png -------------------------------------------------------------------------------- /HUD/Assets/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/player.png -------------------------------------------------------------------------------- /HUD/Assets/player_request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/player_request.png -------------------------------------------------------------------------------- /HUD/Assets/reminder-closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/reminder-closed.png -------------------------------------------------------------------------------- /HUD/Assets/reminder-glow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/reminder-glow.png -------------------------------------------------------------------------------- /HUD/Assets/reminder-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/HUD/Assets/reminder-open.png -------------------------------------------------------------------------------- /HUD/Projector-Global.lua: -------------------------------------------------------------------------------- 1 | --#region projector 2 | function toggleProjectorGUI(player, value, btn_id) 3 | local color = player.color:lower() 4 | self.UI.setAttribute("projector-panel-" .. color, "active", "false") 5 | end 6 | --#endregion 7 | -------------------------------------------------------------------------------- /HUD/Projector-Global.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 4 | 5 | Show Reminders 6 | Ajax (aaaaaa) 7 | 8 | 9 | 10 | Turn Start 11 | 12 | 13 | 14 | Turn End 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Emanuele Sbabo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tabletop Simulator Table 2 | 3 | This library is **not meant** for distribution, I use this place to share my code and to reference it when I do need it. If you found this place through a link given by me or by a friend, hi I guess. If you found this by googling, be aware that these scripts even though are optimized as much as I'm able to they are also very specific to my table (which is not released in the workshop, still working on that) 4 | 5 | I hope that whoever found this place will find the code within useful in some ways, sorry for no comments around but this is all stuff made for private usage. 6 | If you need help you can contact me @Zavian#8253 on discord (you can also find me in the official tabletop simulator discord if you don't want to add random friends for simple questions, you can join it here https://discord.gg/tabletopsimulator. I am **NOT** a Berserk developer and even though I'd like to don't ping anybody but me if you really need to ping someone), just be aware that I'm GMT+1 and if you are from another side of the planet it'll be hard for me to answer at all times. Peace 🐌 7 | 8 | # What's all this stuff? How do I go around this repository? 9 | 10 | Well, as a basis the nomenclature of the files makes pretty obvious, so through some logic and stuff like that, you'll be able to figure out most things. Even though this is on github the actual context of most of these things isn't really anywhere, for now. 11 | 12 | If a file has a .xml version it means that it's both UI and Lua based. 13 | 14 | If a file is in the **DEPRECATED** folder then there is probably a better version of it or it has simply become useless by the implementation of different code. 15 | 16 | # Who am I? 17 | 18 | I'm a developer that has taken under his responsibility to recreate a series of tools to ease DnD into Tabletop Simulator. Don't think of me of anything as I am far from expert on the tool, however the scrips present in this page can be used in all sorts of manners, just be aware that there is close to no documentation, you can still concact me if you need to understand anything from the project. 19 | 20 | # What is the purpose of all these scripts? 21 | 22 | The things that I'm trying to achieve via these scripts is to reach a decent level of both automation and management of a DnD table, mostly for combat related activities. Many tools are inspired by other external programs such as Roll20, Foundry, FantasyGrounds, etc. 23 | The end goal is to have a table that is both **stable** (still working on it) and easy to understand with all the features you may be in need for managing a DnD game. 24 | 25 | # Credits where credits are due 26 | 27 | It goes without saying that a lot of the things that can be found here are things that are gathered from the community, both from the official tabletop simulator discord (in which plenty of people have helped me) and other github repositories that I have found throught the years. Additionally a lot of the work could've not been done if it wasn't for the various top developers that can be found in the workshop. Among these there is: 28 | * [Mr. Stump](https://steamcommunity.com/id/MrStump/myworkshopfiles/?appid=286160) 29 | * [St0m 🐱](https://steamcommunity.com/id/st0m/myworkshopfiles/?appid=286160) 30 | * [CHRY](https://steamcommunity.com/id/chries/myworkshopfiles/?appid=286160) 31 | * [Kijan](https://steamcommunity.com/id/kijands/myworkshopfiles/?appid=286160) 32 | 33 | And countless more. If it wasn't for these wonderful people I would've probably not started making anything as daunting as this projects. 💖 34 | If you feel unrepresented please do go ahead and contact me. 35 | -------------------------------------------------------------------------------- /Utility tools/README.md: -------------------------------------------------------------------------------- 1 | This is a folder dedicated to many tools that don't really have a function in a table but rather are made to serve one purpose. -------------------------------------------------------------------------------- /Utility tools/empty-container.lua: -------------------------------------------------------------------------------- 1 | function onLoad() 2 | local button = { 3 | click_function = "emptyContainer", 4 | function_owner = self, 5 | label = "Click", 6 | position = {0, 0.6, 0}, 7 | scale = {0.5, 0.5, 0.5}, 8 | width = 2000, 9 | height = 400, 10 | font_size = 400 11 | } 12 | end 13 | 14 | function emptyContainer() 15 | local gm = self.getGMNotes() 16 | 17 | local obj = getObjectFromGUID(gm) 18 | print(obj) 19 | if not obj then 20 | print("Could not find object with GUID: " .. gm) 21 | return 22 | end 23 | 24 | local objects = obj.getObjects() 25 | print("Found " .. #objects .. " objects in container") 26 | 27 | --for _, v in ipairs(objects) do 28 | -- v.destruct() 29 | --end 30 | end 31 | -------------------------------------------------------------------------------- /Utility tools/mansion-mover.lua: -------------------------------------------------------------------------------- 1 | local _floors = { 2 | [1] = { 3 | id = "c18d92", 4 | initial_pos = {x = 0.02, y = 1.18, z = -0.09} 5 | }, 6 | [2] = { 7 | id = "7d3103", 8 | initial_pos = {x = 0.02, y = 1.48, z = -0.09} 9 | }, 10 | [3] = { 11 | id = "94c856", 12 | initial_pos = {x = 0.02, y = 1.78, z = -0.09} 13 | } 14 | } 15 | 16 | function onLoad() 17 | dim_floor(_floors[2]) 18 | 19 | self.createButton( 20 | { 21 | click_function = "show_all_floors", 22 | function_owner = self, 23 | label = "Show All Floors", 24 | position = {6, 0.6, 7}, 25 | scale = {0.5, 0.5, 0.5}, 26 | color = {0, 0.4117, 0.7058}, 27 | width = 3000, 28 | height = 800, 29 | font_size = 400 30 | } 31 | ) 32 | self.createButton({ 33 | click_function = 'toggle_first_floor', 34 | function_owner = self, 35 | label = '1st Floor', 36 | position = {6.6, 0.6, 6.2}, 37 | scale = {0.3, 0.3, 0.3}, 38 | color = {0.2784, 0.7255, 0.2784}, 39 | width = 3000, 40 | height = 800, 41 | font_size = 400, 42 | tooltip = 'Visible' 43 | }) 44 | 45 | self.createButton({ 46 | click_function = 'toggle_second_floor', 47 | function_owner = self, 48 | label = '2nd Floor', 49 | position = {6.6, 0.6, 5.7}, 50 | scale = {0.3, 0.3, 0.3}, 51 | color = {0.2784, 0.7255, 0.2784}, 52 | width = 3000, 53 | height = 800, 54 | font_size = 400, 55 | tooltip = 'Visible' 56 | }) 57 | 58 | self.createButton({ 59 | click_function = 'toggle_third_floor', 60 | function_owner = self, 61 | label = '3rd Floor', 62 | position = {6.6, 0.6, 5.2}, 63 | scale = {0.3, 0.3, 0.3}, 64 | color = {0.2784, 0.7255, 0.2784}, 65 | width = 3000, 66 | height = 800, 67 | font_size = 400, 68 | tooltip = 'Visible' 69 | }) 70 | end 71 | 72 | 73 | local can_set = true 74 | local showing_all = false 75 | 76 | function move_floor(floor, offset) 77 | local obj = getObjectFromGUID(floor.id) 78 | local pos = obj.getPosition() 79 | local newPos = { 80 | x = pos.x + offset, 81 | y = _floors[1].initial_pos.y, 82 | z = pos.z 83 | } 84 | if obj then 85 | obj.setPositionSmooth(newPos, false, false) 86 | end 87 | end 88 | 89 | function reset_floor(floor) 90 | local obj = getObjectFromGUID(floor.id) 91 | local pos = floor.initial_pos 92 | if obj then 93 | obj.setPositionSmooth(pos, false, false) 94 | end 95 | end 96 | 97 | function mat_floor(floor) 98 | local obj = getObjectFromGUID(floor.id) 99 | if obj then 100 | obj.setColorTint({r = 1, g = 1, b = 1, a = 1}) 101 | end 102 | end 103 | 104 | function dim_floor(floor) 105 | local obj = getObjectFromGUID(floor.id) 106 | if obj then 107 | obj.setColorTint({r = 0.5568, g = 0.5568, b = 0.5568, a = 1}) 108 | end 109 | end 110 | 111 | function isVisible(floor_number) 112 | return self.getButtons()[floor_number+1].tooltip == 'Visible' 113 | end 114 | 115 | function toggle_floor(floor_number) 116 | local floor = _floors[floor_number] 117 | if isVisible(floor_number) then 118 | getObjectFromGUID(floor.id).setInvisibleTo({ 119 | "White", 120 | "Brown", 121 | "Red", 122 | "Orange", 123 | "Yellow", 124 | "Green", 125 | "Teal", 126 | "Blue", 127 | "Purple", 128 | "Pink", 129 | "Grey", 130 | "Black" 131 | }) 132 | self.editButton({index = floor_number, tooltip = "Invisible", color = {r = 1, g = 0.2549, b = 0.2117}}) 133 | else 134 | getObjectFromGUID(floor.id).setInvisibleTo({}) 135 | self.editButton({index = floor_number, tooltip = "Visible", color = {0.2784, 0.7255, 0.2784}}) 136 | end 137 | end 138 | 139 | function toggle_first_floor() 140 | toggle_floor(1) 141 | end 142 | 143 | function toggle_second_floor() 144 | toggle_floor(2) 145 | end 146 | 147 | function toggle_third_floor() 148 | toggle_floor(3) 149 | if isVisible(2) and not showing_all then 150 | mat_floor(_floors[2]) 151 | end 152 | 153 | if isVisible(3) and not showing_all then 154 | dim_floor(_floors[2]) 155 | end 156 | end 157 | 158 | 159 | function show_all_floors() 160 | local offset = 17 161 | if not showing_all then 162 | if can_set then 163 | _floors[1].initial_pos = getObjectFromGUID(_floors[1].id).getPosition() 164 | _floors[2].initial_pos = getObjectFromGUID(_floors[2].id).getPosition() 165 | _floors[3].initial_pos = getObjectFromGUID(_floors[3].id).getPosition() 166 | can_set = false 167 | Wait.time(function() can_set = true end, 10) 168 | end 169 | 170 | move_floor(_floors[2], offset) 171 | move_floor(_floors[3], offset * -1) 172 | 173 | mat_floor(_floors[2]) 174 | 175 | for i = 1, 3 do 176 | self.editButton({index = i, width = 0, height = 0, label = ""}) 177 | getObjectFromGUID(_floors[i].id).setName( 178 | i == 1 and "1st Floor" 179 | or i == 2 and "2nd Floor" 180 | or "3rd Floor" 181 | ) 182 | end 183 | else 184 | reset_floor(_floors[2]) 185 | reset_floor(_floors[3]) 186 | 187 | dim_floor(_floors[2]) 188 | 189 | for i = 1, 3 do 190 | self.editButton({index = i, width = 3000, height = 800, 191 | label = 192 | i == 1 and "1st Floor" 193 | or i == 2 and "2nd Floor" 194 | or "3rd Floor" 195 | } 196 | ) 197 | getObjectFromGUID(_floors[i].id).setName("") 198 | end 199 | end 200 | 201 | showing_all = not showing_all 202 | end -------------------------------------------------------------------------------- /Utility tools/memo-viewer.lua: -------------------------------------------------------------------------------- 1 | function onLoad() 2 | self.createButton({ 3 | click_function = 'showMemo', 4 | function_owner = self, 5 | label = 'MEMO', 6 | position = {0, 0, 0}, 7 | rotation = {180, 180, 0}, 8 | scale = {0.3, 0.3, 0.3}, 9 | width = 1200, 10 | height = 800, 11 | font_size = 400, 12 | color = {1,0.863,0}, 13 | tooltip = 'Show Memo' 14 | }) 15 | end 16 | 17 | local _SAVED_GUID = null 18 | 19 | function onCollisionEnter(collision_info) 20 | -- collision_info table: 21 | -- collision_object Object 22 | -- contact_points Table {Vector, ...} 23 | -- relative_velocity Vector 24 | if(not collision_info.collision_object.interactable) then return end 25 | if(collision_info.collision_object == self) then return end 26 | _SAVED_GUID = collision_info.collision_object.getGUID() 27 | print("GUID Found: ".._SAVED_GUID) 28 | collision_info.collision_object.highlightOn(Color.Green, 1) 29 | end 30 | 31 | function showMemo(obj, player_color) 32 | if player_color ~= "Black" then return end 33 | if _SAVED_GUID == null then broadcastToColor("Must select an object first!", player_color, Color.red); return; end 34 | -- print(getObjectFromGUID(_SAVED_GUID).) 35 | 36 | local chosen_object = getObjectFromGUID(_SAVED_GUID) 37 | 38 | Player["Black"].showMemoDialog("Memo of " .. _SAVED_GUID, chosen_object.memo, 39 | function(input, player_color) 40 | -- print(input) 41 | if input ~= chosen_object.memo then 42 | -- chosen_object.setDescription(input) 43 | Player["Black"].showConfirmDialog("Memo and text don't match, confirm change?", 44 | function() 45 | broadcastToColor("Memo saved!", player_color, Color.green) 46 | chosen_object.memo = input 47 | end 48 | ) 49 | end 50 | end 51 | ) 52 | end -------------------------------------------------------------------------------- /VERSIONS: -------------------------------------------------------------------------------- 1 | table_updater 1.2 2 | npc_commander 2.2.3 3 | monster 4.0 4 | initiative_mat 2.3.2 5 | initiative_token 1.1.4 6 | player_manager 3.0 7 | note 2.1.1 -------------------------------------------------------------------------------- /average-button.lua: -------------------------------------------------------------------------------- 1 | local expanded = false 2 | local _Black = Color.Black 3 | 4 | function buttonPress() 5 | if lockout == false then 6 | --Call on any other function here. For example: 7 | --Global.call("Function Name", {table of parameters if needed}) 8 | --You could also add your own scrting here. For example: 9 | --print("The button was pressed. Hoozah.") 10 | self.AssetBundle.playTriggerEffect(0) --triggers animation/sound 11 | lockout = true --locks out the button 12 | startLockoutTimer() --Starts up a timer to remove lockout 13 | 14 | local notes = self.getGMNotes() 15 | local vars = JSON.decode(notes) 16 | -- send to open all things from seated players 17 | -- and send it back to a notepad 18 | if not notes then 19 | printError() 20 | return 21 | end 22 | local notecard = getObjectFromGUID(vars["note"]) 23 | if not notecard then 24 | printError() 25 | return 26 | else 27 | notecard.setDescription("") 28 | end 29 | if not expanded then 30 | Global.call("showHuds", {notecard = vars["note"], players = createSeatedTable()}) 31 | notecard.call("reset") 32 | else 33 | Global.call("showHuds", {notecard = vars["note"], players = createSelectedTable()}) 34 | notecard.call("reset", {colors = createSelectedTable()}) 35 | end 36 | end 37 | end 38 | 39 | function printError() 40 | printToColor("Error in the average, gotta setup the note in the GM Note", "Black", Color.White) 41 | end 42 | 43 | function onload() 44 | self.createButton( 45 | { 46 | label = "Big Red Button\n\nBy: MrStump", 47 | click_function = "buttonPress", 48 | function_owner = self, 49 | position = {0, 0.25, 0}, 50 | height = 1400, 51 | width = 1400 52 | } 53 | ) 54 | 55 | local colors = getAllColors() 56 | 57 | local x = 1.9 58 | local z = -1.4 59 | for i = 1, #colors do 60 | x = x + 1.5 61 | if i == 5 or i == 9 then 62 | z = z + 1.6 63 | x = 3.4 64 | end 65 | local button = { 66 | label = colors[i], 67 | click_function = "Button_" .. colors[i], 68 | function_owner = self, 69 | position = {x, 0.2, z}, 70 | font_size = 215, 71 | color = _Black, 72 | font_color = Color.White, 73 | width = 700, 74 | height = 700, 75 | scale = {0, 0, 0} 76 | } 77 | self.createButton(button) 78 | end 79 | self.createButton( 80 | { 81 | -- button for expanding extra buttons 82 | click_function = "toggleExtra", 83 | function_owner = self, 84 | label = "▶", 85 | position = {2.1, 0.2, 0}, 86 | scale = {0.5, 0.5, 0.5}, 87 | width = 950, 88 | height = 950, 89 | font_size = 900, 90 | color = _Black, 91 | font_color = Color.White 92 | } 93 | ) 94 | lockout = false 95 | end 96 | 97 | function createSeatedTable() 98 | local returner = {} 99 | local colors = getAllColors() 100 | for i = 1, #colors do 101 | local seat = Seated(colors[i]) 102 | if seat then 103 | table.insert(returner, seat) 104 | end 105 | end 106 | return returner 107 | end 108 | 109 | function createSelectedTable() 110 | returner = {} 111 | local buttons = self.getButtons() 112 | for i = 1, #getAllColors() do 113 | if buttons[i].font_color == Color.Red then 114 | log("Found color " .. buttons[i].label) 115 | table.insert(returner, buttons[i].label) 116 | end 117 | end 118 | return returner 119 | end 120 | 121 | function toggleExtra() 122 | local buttons = #self.getButtons() 123 | local button = self.getButtons()[buttons] 124 | if button.label == "▶" then 125 | self.editButton({index = buttons - 1, label = "◀"}) 126 | enlargeExtras(true) 127 | else 128 | self.editButton({index = buttons - 1, label = "▶"}) 129 | enlargeExtras(false) 130 | end 131 | end 132 | 133 | function enlargeExtras(doIt) 134 | local scale = doIt and {1, 1, 1} or {0, 0, 0} 135 | local colors = getAllColors() 136 | for i = 1, #colors do 137 | self.editButton({index = i, scale = scale}) 138 | if not Seated(colors[i]) then 139 | self.editButton({index = i, font_color = _Black}) 140 | else 141 | self.editButton({index = i, font_color = Color.White}) 142 | end 143 | end 144 | expanded = doIt 145 | end 146 | 147 | function getAllColors() 148 | return { 149 | "White", 150 | "Teal", 151 | "Brown", 152 | "Blue", 153 | "Red", 154 | "Purple", 155 | "Orange", 156 | "Pink", 157 | "Yellow", 158 | "Green" 159 | } 160 | end 161 | 162 | function Seated(color) 163 | if Player[color].seated then 164 | return color 165 | else 166 | return nil 167 | end 168 | end 169 | 170 | function getColorIndex(color) 171 | local colors = getAllColors() 172 | for i = 1, #colors do 173 | if color == colors[i] then 174 | return i 175 | end 176 | end 177 | return -1 178 | end 179 | 180 | function toggleButton(color) 181 | local buttons = self.getButtons() 182 | for i = 1, #buttons do 183 | local label = buttons[i].label 184 | if label == color then 185 | local fc = buttons[i].font_color 186 | if fc.b ~= _Black.b then 187 | if fc ~= Color.White then 188 | self.editButton({index = i - 1, font_color = Color.White}) 189 | else 190 | self.editButton({index = i - 1, font_color = Color.Red}) 191 | end 192 | end 193 | end 194 | end 195 | end 196 | 197 | function Button_White() 198 | toggleButton("White") 199 | end 200 | 201 | function Button_Teal() 202 | toggleButton("Teal") 203 | end 204 | 205 | function Button_Brown() 206 | toggleButton("Brown") 207 | end 208 | 209 | function Button_Blue() 210 | toggleButton("Blue") 211 | end 212 | 213 | function Button_Red() 214 | toggleButton("Red") 215 | end 216 | 217 | function Button_Purple() 218 | toggleButton("Purple") 219 | end 220 | 221 | function Button_Orange() 222 | toggleButton("Orange") 223 | end 224 | 225 | function Button_Pink() 226 | toggleButton("Pink") 227 | end 228 | 229 | function Button_Yellow() 230 | toggleButton("Yellow") 231 | end 232 | 233 | function Button_Green() 234 | toggleButton("Green") 235 | end 236 | 237 | --Starts a timer that, when it ends, will unlock the button 238 | function startLockoutTimer() 239 | Timer.create({identifier = self.getGUID(), function_name = "unlockLockout", delay = 0.5}) 240 | end 241 | 242 | --Unlocks button 243 | function unlockLockout() 244 | lockout = false 245 | end 246 | 247 | --Ends the timer if the object is destroyed before the timer ends, to prevent an error 248 | function onDestroy() 249 | Timer.destroy(self.getGUID()) 250 | end 251 | -------------------------------------------------------------------------------- /average-notecard.lua: -------------------------------------------------------------------------------- 1 | local _buttons = {} 2 | local _startIndex = 0 3 | 4 | local _setup = false 5 | 6 | local _critColor = {r = 0.0667, g = 0.3019, b = 0.0667, a = 1} 7 | local _failColor = {r = 0.3019, g = 0.0667, b = 0.0667, a = 1} 8 | 9 | function onLoad() 10 | self.createButton( 11 | { 12 | click_function = "setup", 13 | function_owner = self, 14 | label = "Setup", 15 | position = {0, 2.6, 0.42}, 16 | rotation = {180, 0, 180}, 17 | scale = {0.15, 0.2, 0.2}, 18 | width = 1010, 19 | height = 330, 20 | font_size = 200, 21 | color = Color.Black, 22 | font_color = Color.White 23 | } 24 | ) 25 | self.createButton( 26 | { 27 | click_function = "average", 28 | function_owner = self, 29 | label = "AVG", 30 | position = {0, 2.6, -0.58}, 31 | rotation = {180, 0, 180}, 32 | scale = {0.15, 0.2, 0.2}, 33 | width = 1010, 34 | height = 330, 35 | font_size = 200, 36 | color = Color.Red, 37 | font_color = Color.White 38 | } 39 | ) 40 | _startIndex = 2 41 | 42 | --Wait.Time( 43 | -- function() 44 | -- setup() 45 | -- randomizeDebug() 46 | -- end, 47 | -- 2 48 | --) 49 | end 50 | 51 | function randomizeDebug() 52 | local colors = getAllColors() 53 | for i = 1, #colors do 54 | Wait.Time( 55 | function() 56 | local avg = math.random(1, 22) 57 | local crit = nil 58 | if avg == 1 then 59 | crit = 1 60 | elseif avg >= 20 then 61 | crit = 20 62 | end 63 | setData({avg = avg, color = colors[i], crit = crit}) 64 | end, 65 | 0.5 66 | ) 67 | end 68 | end 69 | 70 | function setData(params) 71 | if not _setup then 72 | setup() 73 | end 74 | local buttonIndex = findButtonByColor(params.color) - 1 75 | self.editButton({index = buttonIndex, label = params.avg}) 76 | if params.crit ~= nil then 77 | local desc = self.getDescription() 78 | if params.crit == 20 then 79 | self.editButton({index = buttonIndex, color = _critColor}) 80 | self.setDescription(desc == "" and params.avg or desc .. " " .. params.avg) 81 | else 82 | self.editButton({index = buttonIndex, color = _failColor}) 83 | self.setDescription(desc == "" and "1" or desc .. " 1") 84 | end 85 | else 86 | self.editButton({index = buttonIndex, color = Color.Black}) 87 | end 88 | end 89 | 90 | function findButtonByColor(color) 91 | local buttons = self.getButtons() 92 | for i = 1, #buttons do 93 | local button = buttons[i] 94 | if button.tooltip == color then 95 | return i 96 | end 97 | end 98 | end 99 | 100 | function reset(params) 101 | setup() 102 | if params then 103 | Wait.Time( 104 | function() 105 | local buttons = self.getButtons() 106 | for i = 1, #buttons do 107 | if notInList(params.colors, buttons[i].tooltip) and i - 1 >= _startIndex then 108 | self.editButton({index = i - 1, font_color = Color.Black}) 109 | end 110 | end 111 | end, 112 | 0.5 113 | ) 114 | end 115 | end 116 | 117 | function notInList(list, color) 118 | for i = 1, #list do 119 | if list[i] == color then 120 | return false 121 | end 122 | end 123 | return true 124 | end 125 | 126 | function setup() 127 | if #_buttons > 0 then 128 | resetButtons() 129 | end 130 | 131 | local colors = getAllColors() 132 | 133 | local x = 0.39 134 | local z = -0.36 135 | for i = 1, #colors do 136 | if Seated(colors[i]) then 137 | local button = { 138 | label = colors[i], 139 | click_function = "none", 140 | function_owner = self, 141 | position = {x, 2.6, z}, 142 | font_size = 215, 143 | color = Color.Black, 144 | font_color = Color[colors[i]], 145 | tooltip = colors[i], 146 | width = 700, 147 | height = 700, 148 | scale = {0.13, 0.15, 0.15}, 149 | rotation = {180, 0, 180} 150 | } 151 | self.createButton(button) 152 | table.insert(_buttons, button) 153 | x = x - 0.19 154 | if i == 5 or i == 10 then 155 | z = z + 0.23 156 | x = 0.39 157 | end 158 | end 159 | end 160 | _setup = true 161 | end 162 | 163 | function resetButtons() 164 | for i = 1, #self.getButtons() do 165 | if i - 1 >= _startIndex then 166 | self.removeButton(i - 1) 167 | _buttons = {} 168 | _setup = false 169 | end 170 | end 171 | end 172 | 173 | function none() 174 | end 175 | 176 | function average() 177 | local numbers = 0 178 | local tot = 0 179 | -- get all buttons 180 | local buttons = self.getButtons() 181 | for i = _startIndex + 1, #buttons do 182 | if buttons[i].font_color ~= Color.Black then 183 | --log(buttons[i].tooltip .. " " .. buttons[i].label) 184 | local num = tonumber(buttons[i].label) 185 | if (num) then 186 | tot = tot + num 187 | numbers = numbers + 1 188 | end 189 | end 190 | end 191 | 192 | if self.getDescription() ~= "" then 193 | local extras = split(self.getDescription(), " ") 194 | for i = 1, #extras do 195 | tot = tot + tonumber(extras[i]) 196 | numbers = numbers + 1 197 | end 198 | end 199 | self.setName("[00000000]" .. tot / numbers .. "[-]") 200 | self.editButton({index = 1, label = math.floor(tot / numbers)}) 201 | end 202 | 203 | function Seated(color) 204 | if Player[color].seated then 205 | return color 206 | else 207 | return nil 208 | end 209 | end 210 | 211 | function getAllColors() 212 | return { 213 | "White", 214 | "Teal", 215 | "Brown", 216 | "Blue", 217 | "Red", 218 | "Purple", 219 | "Orange", 220 | "Pink", 221 | "Yellow", 222 | "Green" 223 | } 224 | end 225 | 226 | function split(inputstr, sep) 227 | if sep == nil then 228 | sep = "%s" 229 | end 230 | local t = {} 231 | i = 1 232 | for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do 233 | t[i] = str 234 | i = i + 1 235 | end 236 | return t 237 | end 238 | -------------------------------------------------------------------------------- /bag-peeker.lua: -------------------------------------------------------------------------------- 1 | local firstItem = "" 2 | 3 | function onLoad() 4 | self.createButton( 5 | { 6 | click_function = "none", 7 | function_owner = self, 8 | label = firstItem, 9 | position = {0, 0.6, 2.9}, 10 | scale = {0.7, 0.7, 0.7}, 11 | width = 7200, 12 | height = 800, 13 | font_size = 600 14 | } 15 | ) 16 | getFirstItem() 17 | end 18 | 19 | function none() 20 | end 21 | 22 | function onObjectEnterContainer(bag, obj) 23 | if bag == self then 24 | getFirstItem() 25 | end 26 | end 27 | 28 | function onObjectLeaveContainer(bag, obj) 29 | if bag == self then 30 | getFirstItem() 31 | end 32 | end 33 | 34 | function getFirstItem() 35 | local objs = self.getObjects() 36 | if objs then 37 | if objs[1] then 38 | firstItem = objs[#objs].name 39 | else 40 | firstItem = "" 41 | end 42 | self.editButton({index = 0, label = firstItem}) 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /card creator/card creator-2.0.lua: -------------------------------------------------------------------------------- 1 | local bag = self.getDescription() 2 | 3 | local objs = {} 4 | 5 | local processing = false 6 | local index = 1 7 | 8 | function mysplit(inputstr, sep) 9 | if sep == nil then 10 | sep = "%s" 11 | end 12 | local t = {} 13 | i = 1 14 | for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do 15 | t[i] = str 16 | i = i + 1 17 | end 18 | return t 19 | end 20 | 21 | --Runs when the scripted button inside the button is clicked 22 | function buttonPress() 23 | if lockout == false then 24 | --Call on any other function here. For example: 25 | --Global.call("Function Name", {table of parameters if needed}) 26 | --You could also add your own scrting here. For example: 27 | --print("The button was pressed. Hoozah.") 28 | 29 | text = self.UI.getAttribute("text", "value") 30 | local lines = mysplit(text, "\n") 31 | 32 | local readingBack = false 33 | local card = "" 34 | 35 | for i = 1, #lines do 36 | local line = lines[i] 37 | local isSmall = #mysplit(line, "|") > 1 38 | 39 | local card = line 40 | if isSmall then 41 | card = mysplit(line, "|")[1] 42 | end 43 | 44 | local elements = mysplit(card, " ") 45 | local result = "" 46 | if #elements == 1 then -- in the case that i only put the link 47 | result = elements[1] .. "|" .. elements[1] 48 | take_card(result) 49 | elseif #elements == 2 then -- in the case that i two links 50 | result = elements[1] .. "|" .. elements[2] 51 | take_card(result) 52 | elseif #elements == 3 then -- in the case that i have also the color 53 | local isHex = elements[1]:sub(1, 1) == "#" 54 | result = elements[2] .. "|" .. elements[3] 55 | take_card(result, true, isHex) 56 | end 57 | end 58 | 59 | local waiter = function() 60 | if #objs == 0 then 61 | return false 62 | end 63 | for i = 1, #objs do 64 | local res = objs[i].o.resting 65 | if res == false then 66 | return false 67 | end 68 | end 69 | return true 70 | end 71 | 72 | local waited = function() 73 | setCards() 74 | end 75 | 76 | Wait.condition(waited, waiter) 77 | 78 | self.AssetBundle.playTriggerEffect(0) --triggers animation/sound 79 | lockout = true --locks out the button 80 | startLockoutTimer() --Starts up a timer to remove lockout 81 | end 82 | end 83 | 84 | function take_card(c, hasColor, isHex) 85 | local returner = {} 86 | 87 | local splitted = mysplit(c, "|") 88 | 89 | if hasColor then 90 | if not isHex then 91 | local colo = splitted[3]:gsub("-", "") 92 | returner.color = colorTranslate(colo) 93 | else 94 | local colo = hexToRgb(splitted[3]) 95 | returner.color = colo 96 | end 97 | else 98 | returner.color {r = 0, g = 0, b = 0} 99 | end 100 | 101 | returner.card = {splitted[1], splitted[2]} 102 | takeParams = { 103 | position = {119.49, 2.80, 13.54}, 104 | rotation = {0, 0, 0}, 105 | callback_function = function(obj) 106 | returner.o = obj 107 | table.insert(objs, returner) 108 | end 109 | } 110 | --printTable(objs) 111 | 112 | getObjectFromGUID(bag).takeObject(takeParams) 113 | end 114 | 115 | function setCards(small) 116 | for i = 1, #objs do 117 | objs[i].o.setCustomObject( 118 | { 119 | image = objs[i].card[1], 120 | image_secondary = objs[i].card[2] 121 | } 122 | ) 123 | if objs[i].color ~= nil then 124 | objs[i].o.setColorTint(objs[i].color) 125 | end 126 | 127 | if small ~= nil then 128 | if small then 129 | objs[i].o.setScale({1.76, 1.00, 1.76}) 130 | end 131 | elseif makeSmall() then 132 | objs[i].o.setScale({1.76, 1.00, 1.76}) 133 | end 134 | 135 | objs[i].o.reload() 136 | end 137 | 138 | objs = {} 139 | end 140 | 141 | function colorTranslate(color) 142 | --[[ 143 | arr["Green"] = "u"; 144 | arr["Navy"] = "r"; 145 | arr["BlueViolet"] = "e"; 146 | arr["#c46709"] = "l"; 147 | --]] 148 | local r = "" 149 | if color == "u" then 150 | r = "Green" 151 | elseif color == "r" then 152 | r = "Blue" 153 | elseif color == "e" then 154 | r = "Purple" 155 | elseif color == "l" then 156 | r = {r = 0.768627, g = 0.403922, b = 0.035294} 157 | else 158 | r = {r = 0, g = 0, b = 0} 159 | end 160 | 161 | return r 162 | end 163 | 164 | --Runs on load, creates button and makes sure the lockout is off 165 | function onload() 166 | self.createButton( 167 | { 168 | label = "Big Red Button\n\nBy: MrStump", 169 | click_function = "buttonPress", 170 | function_owner = self, 171 | position = {0, 0.25, 0}, 172 | height = 1400, 173 | width = 1400 174 | } 175 | ) 176 | self.createButton( 177 | { 178 | click_function = "changeSmall", 179 | function_owner = self, 180 | label = " ", 181 | position = {-1.5, 0.45, 1.5}, 182 | width = 400, 183 | height = 400, 184 | color = {0.856, 0.1, 0.094, 1}, 185 | tooltip = "big" 186 | } 187 | ) 188 | lockout = false 189 | 190 | local desc = self.getDescription() 191 | if desc ~= "" then 192 | bag = desc 193 | end 194 | self.UI.setAttribute("text", "onValueChanged", self.getGUID() .. "/UIUpdateValue(value)") 195 | end 196 | 197 | function changeSmall() 198 | local btn = self.getButtons()[2] 199 | local isBig = btn.tooltip == "big" 200 | local color = { 201 | red = {0.856, 0.1, 0.094, 1}, 202 | green = {0.4418, 0.8101, 0.4248, 1} 203 | } 204 | if isBig then 205 | self.editButton({index = 1, color = color.green}) 206 | self.editButton({index = 1, tooltip = "small"}) 207 | else 208 | self.editButton({index = 1, color = color.red}) 209 | self.editButton({index = 1, tooltip = "big"}) 210 | end 211 | end 212 | 213 | function makeSmall() 214 | local btn = self.getButtons()[2] 215 | return btn.tooltip == "small" 216 | end 217 | 218 | function UIUpdateValue(player, text, id) 219 | self.UI.setAttribute("text", "value", text) 220 | end 221 | 222 | --Starts a timer that, when it ends, will unlock the button 223 | function startLockoutTimer() 224 | Timer.create({identifier = self.getGUID(), function_name = "unlockLockout", delay = 0.5}) 225 | end 226 | 227 | --Unlocks button 228 | function unlockLockout() 229 | lockout = false 230 | end 231 | 232 | --Ends the timer if the object is destroyed before the timer ends, to prevent an error 233 | function onDestroy() 234 | Timer.destroy(self.getGUID()) 235 | end 236 | 237 | function hexToRgb(hex) 238 | hex = hex:gsub("#", "") 239 | if #hex < 8 then 240 | hex = hex .. "ff" 241 | end 242 | return color( 243 | tonumber("0x" .. hex:sub(1, 2), 16) / 255, 244 | tonumber("0x" .. hex:sub(3, 4), 16) / 255, 245 | tonumber("0x" .. hex:sub(5, 6), 16) / 255, 246 | tonumber("0x" .. hex:sub(7, 8), 16) / 255 247 | ) 248 | end 249 | -------------------------------------------------------------------------------- /card creator/card creator.lua: -------------------------------------------------------------------------------- 1 | local bag = self.getDescription() 2 | 3 | local objs = {} 4 | 5 | local processing = false 6 | local index = 1 7 | 8 | function mysplit(inputstr, sep) 9 | if sep == nil then 10 | sep = "%s" 11 | end 12 | local t = {} 13 | i = 1 14 | for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do 15 | t[i] = str 16 | i = i + 1 17 | end 18 | return t 19 | end 20 | 21 | --Runs when the scripted button inside the button is clicked 22 | function buttonPress() 23 | if lockout == false then 24 | --Call on any other function here. For example: 25 | --Global.call("Function Name", {table of parameters if needed}) 26 | --You could also add your own scrting here. For example: 27 | --print("The button was pressed. Hoozah.") 28 | 29 | text = self.UI.getAttribute("text", "value") 30 | local lines = mysplit(text, "\n") 31 | 32 | local readingBack = false 33 | local card = "" 34 | 35 | for i = 1, #lines do 36 | local str = lines[i] 37 | local firstChar = string.sub(lines[i], 1, 1) 38 | if firstChar == "h" then 39 | --if not readingBack then 40 | -- card = str 41 | -- readingBack = true 42 | --else 43 | -- card = card .. "|" .. str 44 | -- readingBack = false 45 | -- take_card(card) 46 | --end 47 | -- there's no color detailed 48 | local sp = mysplit(str, " ") 49 | take_card(sp[1] .. "|" .. sp[2]) 50 | elseif firstChar == "-" then 51 | --color 52 | local sp = mysplit(str, " ") 53 | take_card(sp[2] .. "|" .. sp[3] .. "|" .. sp[1], true) 54 | elseif firstChar == "#" then 55 | local sp = mysplit(str, " ") 56 | take_card(sp[2] .. "|" .. sp[3] .. "|" .. sp[1], true, true) 57 | end 58 | end 59 | 60 | local waiter = function() 61 | if #objs == 0 then 62 | return false 63 | end 64 | for i = 1, #objs do 65 | local res = objs[i].o.resting 66 | if res == false then 67 | return false 68 | end 69 | end 70 | return true 71 | end 72 | 73 | local waited = function() 74 | setCards() 75 | end 76 | 77 | Wait.condition(waited, waiter) 78 | 79 | self.AssetBundle.playTriggerEffect(0) --triggers animation/sound 80 | lockout = true --locks out the button 81 | startLockoutTimer() --Starts up a timer to remove lockout 82 | end 83 | end 84 | 85 | function take_card(c, hasColor, isHex) 86 | local returner = {} 87 | 88 | local splitted = mysplit(c, "|") 89 | 90 | if hasColor then 91 | if not isHex then 92 | local colo = splitted[3]:gsub("-", "") 93 | returner.color = colorTranslate(colo) 94 | else 95 | local colo = hexToRgb(splitted[3]) 96 | returner.color = colo 97 | end 98 | else 99 | returner.color {r = 0, g = 0, b = 0} 100 | end 101 | returner.card = {splitted[1], splitted[2]} 102 | takeParams = { 103 | position = {119.49, 2.80, 13.54}, 104 | rotation = {0, 0, 0}, 105 | callback_function = function(obj) 106 | returner.o = obj 107 | table.insert(objs, returner) 108 | end 109 | } 110 | --printTable(objs) 111 | 112 | getObjectFromGUID(bag).takeObject(takeParams) 113 | end 114 | 115 | function setCards() 116 | for i = 1, #objs do 117 | objs[i].o.setCustomObject( 118 | { 119 | image = objs[i].card[1], 120 | image_secondary = objs[i].card[2] 121 | } 122 | ) 123 | if objs[i].color ~= nil then 124 | objs[i].o.setColorTint(objs[i].color) 125 | end 126 | 127 | if makeSmall() then 128 | objs[i].o.setScale({1.76, 1.00, 1.76}) 129 | end 130 | 131 | objs[i].o.reload() 132 | end 133 | 134 | objs = {} 135 | end 136 | 137 | function colorTranslate(color) 138 | --[[ 139 | arr["Green"] = "u"; 140 | arr["Navy"] = "r"; 141 | arr["BlueViolet"] = "e"; 142 | arr["#c46709"] = "l"; 143 | --]] 144 | local r = "" 145 | if color == "u" then 146 | r = "Green" 147 | elseif color == "r" then 148 | r = "Blue" 149 | elseif color == "e" then 150 | r = "Purple" 151 | elseif color == "l" then 152 | r = {r = 0.768627, g = 0.403922, b = 0.035294} 153 | else 154 | r = {r = 0, g = 0, b = 0} 155 | end 156 | 157 | return r 158 | end 159 | 160 | --Runs on load, creates button and makes sure the lockout is off 161 | function onload() 162 | self.createButton( 163 | { 164 | label = "Big Red Button\n\nBy: MrStump", 165 | click_function = "buttonPress", 166 | function_owner = self, 167 | position = {0, 0.25, 0}, 168 | height = 1400, 169 | width = 1400 170 | } 171 | ) 172 | self.createButton( 173 | { 174 | click_function = "changeSmall", 175 | function_owner = self, 176 | label = " ", 177 | position = {-1.5, 0.45, 1.5}, 178 | width = 400, 179 | height = 400, 180 | color = {0.856, 0.1, 0.094, 1}, 181 | tooltip = "big" 182 | } 183 | ) 184 | lockout = false 185 | 186 | local desc = self.getDescription() 187 | if desc ~= "" then 188 | bag = desc 189 | end 190 | self.UI.setAttribute("text", "onValueChanged", self.getGUID() .. "/UIUpdateValue(value)") 191 | end 192 | 193 | function changeSmall() 194 | local btn = self.getButtons()[2] 195 | local isBig = btn.tooltip == "big" 196 | local color = { 197 | red = {0.856, 0.1, 0.094, 1}, 198 | green = {0.4418, 0.8101, 0.4248, 1} 199 | } 200 | if isBig then 201 | self.editButton({index = 1, color = color.green}) 202 | self.editButton({index = 1, tooltip = "small"}) 203 | else 204 | self.editButton({index = 1, color = color.red}) 205 | self.editButton({index = 1, tooltip = "big"}) 206 | end 207 | end 208 | 209 | function makeSmall() 210 | local btn = self.getButtons()[2] 211 | return btn.tooltip == "small" 212 | end 213 | 214 | function UIUpdateValue(player, text, id) 215 | self.UI.setAttribute("text", "value", text) 216 | end 217 | 218 | --Starts a timer that, when it ends, will unlock the button 219 | function startLockoutTimer() 220 | Timer.create({identifier = self.getGUID(), function_name = "unlockLockout", delay = 0.5}) 221 | end 222 | 223 | --Unlocks button 224 | function unlockLockout() 225 | lockout = false 226 | end 227 | 228 | --Ends the timer if the object is destroyed before the timer ends, to prevent an error 229 | function onDestroy() 230 | Timer.destroy(self.getGUID()) 231 | end 232 | 233 | function hexToRgb(hex) 234 | hex = hex:gsub("#", "") 235 | if #hex < 8 then 236 | hex = hex .. "ff" 237 | end 238 | return color( 239 | tonumber("0x" .. hex:sub(1, 2), 16) / 255, 240 | tonumber("0x" .. hex:sub(3, 4), 16) / 255, 241 | tonumber("0x" .. hex:sub(5, 6), 16) / 255, 242 | tonumber("0x" .. hex:sub(7, 8), 16) / 255 243 | ) 244 | end 245 | -------------------------------------------------------------------------------- /card creator/card creator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /command-manager.lua: -------------------------------------------------------------------------------- 1 | local _messages 2 | 3 | function onLoad() 4 | updateMessages() 5 | end 6 | 7 | function updateMessages() 8 | _messages = {} 9 | for _, containedObject in ipairs(self.getObjects()) do 10 | local command = containedObject.name 11 | local desc = containedObject.description 12 | 13 | table.insert(_messages, {command = command, desc = desc}) 14 | 15 | end 16 | end 17 | 18 | function isContained(command) 19 | for i = 1, #_messages do 20 | if _messages[i].command == command then 21 | return _messages[i] 22 | end 23 | end 24 | 25 | return false 26 | end 27 | 28 | function onChat(message, player) 29 | local contained = isContained(message) 30 | 31 | if contained then 32 | createDialog(contained) 33 | end 34 | end 35 | 36 | function createDialog(message) 37 | Player["Black"].showMemoDialog(message.command, message.desc) 38 | end 39 | 40 | function onObjectEnterContainer(container, enter_object) 41 | if container == self then 42 | updateMessages() 43 | end 44 | end 45 | 46 | function onObjectLeaveContainer(container, leave_object) 47 | if container == self then 48 | updateMessages() 49 | end 50 | end -------------------------------------------------------------------------------- /debug-button.lua: -------------------------------------------------------------------------------- 1 | local _stuffs = { 2 | {obj = "28f96e", bag = "e1e28a"}, 3 | {obj = "1d7e9d", bag = "627199"}, 4 | {obj = "b81df8", bag = "de97c2"} 5 | } 6 | 7 | local _snap = nil 8 | local _color = nil 9 | 10 | function onLoad() 11 | self.setRotation({0.00, 0.00, 0.00}) 12 | self.createButton( 13 | { 14 | click_function = "store_stuff", 15 | function_owner = self, 16 | label = "Store Stuff", 17 | position = {0, 0.5, 0}, 18 | rotation = {0, 180, 0}, 19 | scale = {0.4, 0.7, 0.4}, 20 | width = 1600, 21 | height = 450, 22 | font_size = 320 23 | } 24 | ) 25 | 26 | local notes = self.getGMNotes() 27 | local vars = JSON.decode(notes) 28 | 29 | if vars.stuff then 30 | _stuffs = vars.stuff 31 | end 32 | 33 | if vars.snap ~= nil then 34 | _snap = vars.snap 35 | end 36 | 37 | if vars.color ~= nil then 38 | _color = hexToRgb(vars.color) 39 | end 40 | 41 | store_stuff() 42 | end 43 | 44 | function store_stuff() 45 | for i = 1, #_stuffs do 46 | local o = getObjectFromGUID(_stuffs[i].obj) 47 | local put = 48 | o.clone( 49 | { 50 | position = { 51 | x = o.getPosition().x, 52 | y = o.getPosition().y + 3, 53 | z = o.getPosition().z 54 | } 55 | } 56 | ) 57 | put.setLock(true) 58 | 59 | local b = getObjectFromGUID(_stuffs[i].bag) 60 | 61 | if _color ~= nil then 62 | b.setColorTint(_color) 63 | end 64 | 65 | if _snap ~= nil then 66 | put.use_grid = _snap 67 | put.use_snap_points = _snap 68 | end 69 | 70 | Wait.time( 71 | function() 72 | b.reset() 73 | local waiter = function() 74 | return put.resting 75 | end 76 | local waited = function() 77 | local pos = b.getPosition() 78 | pos.y = pos.y + 2 79 | put.setLock(false) 80 | 81 | put.setPositionSmooth(pos, false, true) 82 | end 83 | Wait.condition(waited, waiter) 84 | end, 85 | 1.2 86 | ) 87 | end 88 | end 89 | 90 | function hexToRgb(hex) 91 | hex = hex:gsub("#", "") 92 | if #hex < 8 then 93 | hex = hex .. "ff" 94 | end 95 | return color( 96 | tonumber("0x" .. hex:sub(1, 2), 16) / 255, 97 | tonumber("0x" .. hex:sub(3, 4), 16) / 255, 98 | tonumber("0x" .. hex:sub(5, 6), 16) / 255, 99 | tonumber("0x" .. hex:sub(7, 8), 16) / 255 100 | ) 101 | end 102 | -------------------------------------------------------------------------------- /dice-mat.lua: -------------------------------------------------------------------------------- 1 | local _sz = "876993" 2 | local _blockBag = "012999" 3 | 4 | local _blockPosition = {x=-1.21, y=2.30, z=8.34} 5 | local _blockName = "block" 6 | local _color = "Black" 7 | 8 | local dices = {} 9 | 10 | function getSides(dice) 11 | local values = dice.getRotationValues(dice) 12 | value = values[#values].value 13 | return value 14 | end 15 | 16 | self.createButton({ 17 | click_function = "roll_all", 18 | function_owner = self, 19 | label = "Roll All", 20 | position = {0.8, 0.33, 1.15}, 21 | rotation = {0, 90, 0}, 22 | scale = {0.3, 0.6, 0.5}, 23 | width = 600, 24 | height = 200, 25 | font_size = 150, 26 | color = {0.113725, 0.117647, 0.066667, 1}, font_color = {1, 1, 1, 1}, 27 | alignment = 3 28 | }) 29 | 30 | self.createInput({ 31 | input_function = "edit_mods", 32 | function_owner = self, 33 | label = "v", 34 | position = {0.8, 0.35, 0.956}, 35 | rotation = {0, 90, 0}, 36 | scale = {0.2, 0.4, 0.4}, 37 | width = 200, 38 | height = 200, 39 | font_size = 150, 40 | color = {0.1137, 0.1176, 0.0666, 1}, 41 | font_color = {1, 1, 1, 1}, 42 | tooltip = "Edit All Mods", 43 | alignment = 3 44 | }) 45 | 46 | function takeBlock(spawned, name, color, reference) 47 | spawned.setColorTint(color) 48 | spawned.editInput({index=0, value=name}) 49 | spawned.editInput({index=1, value=reference.getRotationValue()}) 50 | spawned.editInput({index=2, value=reference.getDescription()}) 51 | spawned.editInput({index=3, value="= " .. reference.getRotationValue()+reference.getDescription()}) 52 | 53 | spawned.setScale({2.29,0.2,1.17}) 54 | spawned.tooltip = false 55 | spawned.setName(_blockName) 56 | spawned.setLock(true) 57 | 58 | dices[reference.getGUID()] = spawned.getGUID() 59 | orderBlocks() 60 | end 61 | 62 | function orderBlocks() 63 | local blockPosition = {x=-1.21, y=2.30, z=8.34} 64 | local zone = getObjectFromGUID(_sz) 65 | local objs = zone.getObjects() 66 | local difference = 1.29 67 | for i=0, #objs do 68 | local obj = objs[i] 69 | if obj then 70 | if obj.getName() == _blockName then 71 | obj.setPositionSmooth(blockPosition, false, true) 72 | obj.setRotationSmooth({0,90,0},false,true) 73 | blockPosition.x = blockPosition.x+difference 74 | end 75 | end 76 | end 77 | end 78 | 79 | function onObjectEnterScriptingZone(zone, obj) 80 | if zone.getGUID() == _sz then 81 | if obj.tag == "Dice" then 82 | if obj.getDescription() == "" then 83 | obj.setDescription("0") 84 | 85 | end 86 | 87 | color = obj.getColorTint() 88 | if getSides(obj) == 20 then 89 | local takeParams = { 90 | position = _blockPosition, 91 | rotation = {0.00, 90.00, 0.00}, 92 | callback_function = function(block) takeBlock(block, obj.getName(), color, obj) end, 93 | } 94 | getObjectFromGUID(_blockBag).takeObject(takeParams) 95 | 96 | end 97 | end 98 | 99 | end 100 | end 101 | 102 | function onObjectLeaveScriptingZone(zone, obj) 103 | if zone.getGUID() == _sz then 104 | if dices[obj.getGUID()] then 105 | getObjectFromGUID(dices[obj.getGUID()]).destruct() 106 | dices[obj.getGUID()] = nil 107 | orderBlocks() 108 | end 109 | end 110 | 111 | end 112 | 113 | function onObjectRandomize(obj, color) 114 | if color == _color then 115 | if dices[obj.getGUID()] then 116 | --getObjectFromGUID(dices[obj.getGUID()]).call("updateValue") 117 | local block = getObjectFromGUID(dices[obj.getGUID()]) 118 | local rollWatch = function() return obj.resting end 119 | local rollEnd = function() 120 | block.editInput({index=1, value = obj.getRotationValue()}) 121 | block.call("updateResult", nil) 122 | end 123 | Wait.condition(rollEnd, rollWatch) 124 | end 125 | end 126 | end 127 | 128 | function roll_all() 129 | local zone = getObjectFromGUID(_sz) 130 | local objs = zone.getObjects() 131 | for i=0, #objs do 132 | local obj = objs[i] 133 | if obj then 134 | if obj.getName() == _blockName then 135 | obj.call("roll_die") 136 | end 137 | end 138 | end 139 | end 140 | 141 | function edit_mods(obj, color, _input, stillEditing) 142 | if not stillEditing then 143 | local zone = getObjectFromGUID(_sz) 144 | local objs = zone.getObjects() 145 | for i=0, #objs do 146 | local obj = objs[i] 147 | if obj then 148 | if obj.getName() == _blockName then 149 | obj.call("updateModifier", {input=_input}) 150 | end 151 | end 152 | end 153 | end 154 | end -------------------------------------------------------------------------------- /dice-rolling-tool.lua: -------------------------------------------------------------------------------- 1 | local _dice = { 2 | diceSets = { 3 | [4] = 0, 4 | [6] = 0, 5 | [8] = 0, 6 | [10] = 0, 7 | [12] = 0, 8 | [20] = 0 9 | }, 10 | modifier = 0 11 | } 12 | 13 | local registeredDice = {} 14 | 15 | function onload() 16 | self.createButton( 17 | { 18 | click_function = "calculate", 19 | function_owner = self, 20 | label = "Calculate", 21 | position = {0, 0.25, -1.18}, 22 | scale = {0.5, 0.5, 0.5}, 23 | width = 3075, 24 | height = 600, 25 | font_size = 400 26 | } 27 | ) 28 | self.createButton( 29 | { 30 | click_function = "setDiceVal", 31 | function_owner = self, 32 | label = "Dice", 33 | position = {-1, 0.25, -1.75}, 34 | scale = {0.5, 0.5, 0.5}, 35 | width = 1175, 36 | height = 450, 37 | font_size = 150, 38 | tooltip = "Dice", 39 | alignment = 3 40 | } 41 | ) 42 | 43 | self.createButton( 44 | { 45 | click_function = "reset", 46 | function_owner = self, 47 | label = "X", 48 | position = {0, 0.27, -1.75}, 49 | scale = {0.5, 0.5, 0.5}, 50 | width = 575, 51 | height = 450, 52 | font_size = 250, 53 | color = {0.098, 0.098, 0.098, 1}, 54 | font_color = {1, 1, 1, 1}, 55 | tooltip = "Reset", 56 | alignment = 3 57 | } 58 | ) 59 | 60 | self.createInput( 61 | { 62 | input_function = "setModVal", 63 | function_owner = self, 64 | label = "Mod", 65 | position = {1, 0.25, -1.75}, 66 | scale = {0.5, 0.5, 0.5}, 67 | width = 1175, 68 | height = 450, 69 | font_size = 400, 70 | tooltip = "Mod", 71 | alignment = 3 72 | } 73 | ) 74 | end 75 | 76 | function onCollisionEnter(info) 77 | if info then 78 | local obj = info.collision_object 79 | if obj then 80 | if obj.type == "Dice" and not registered(obj.guid) then 81 | local sides = #obj.getRotationValues() 82 | _dice.diceSets[sides] = _dice.diceSets[sides] + 1 83 | table.insert(registeredDice, obj.guid) 84 | updateDiceVal() 85 | end 86 | end 87 | end 88 | end 89 | 90 | function registered(guid) 91 | for i, v in ipairs(registeredDice) do 92 | if v == guid then 93 | return true 94 | end 95 | end 96 | return false 97 | end 98 | 99 | function setDiceVal(obj, player_color) 100 | updateDiceVal() 101 | end 102 | 103 | function updateDiceVal() 104 | local str = "" 105 | for k, v in pairs(_dice.diceSets) do 106 | if v > 0 then 107 | if string.len(str) > 0 then 108 | str = str .. "+" .. v .. "d" .. k 109 | else 110 | str = v .. "d" .. k 111 | end 112 | end 113 | end 114 | self.editButton({index = 1, label = str}) 115 | end 116 | 117 | function setModVal() 118 | _dice.modifier = tonumber(self.getInputs()[1].value) 119 | end 120 | 121 | function reset() 122 | _dice.diceSets = { 123 | [4] = 0, 124 | [6] = 0, 125 | [8] = 0, 126 | [10] = 0, 127 | [12] = 0, 128 | [20] = 0 129 | } 130 | _dice.modifier = 0 131 | self.editButton({index = 1, label = ""}) 132 | self.editInput({index = 0, value = ""}) 133 | self.editButton({index = 0, label = "Calculate"}) 134 | self.setDescription("") 135 | registeredDice = {} 136 | end 137 | 138 | function calculate(obj, player_clicker_color, alt_click) 139 | local green = "2ECC40" 140 | local red = "AAAAAAaa" 141 | local rolledString = self.getButtons()[2].label 142 | 143 | self.setDescription("") 144 | local log = "" 145 | local result = 0 146 | 147 | for k, v in pairs(_dice.diceSets) do 148 | if v > 0 then 149 | local subset = calcSet({sides = k, dice = v}) 150 | log = log .. "Rolling " .. v .. "d" .. k .. ": (" .. subset.result .. ")\n " 151 | for i = 1, #subset.rolls do 152 | log = 153 | log .. 154 | string.format("([%s]%s[-] [%s]%s[-])", green, subset.rolls[i].roll, red, subset.rolls[i].scrap) 155 | end 156 | log = log .. "\n" 157 | result = result + subset.result 158 | end 159 | end 160 | log = 161 | log .. 162 | string.format("\n[%s][b]Total: %s + %s = %s[/b][-]", green, result, _dice.modifier, result + _dice.modifier) 163 | 164 | local inCombat = Global.call("isInCombat") 165 | log(inCombat) 166 | log(type(inCombat)) 167 | if inCombat then 168 | -- monitoring purposes 169 | printToColor( 170 | string.format("Rolling %s: %s+%s", rolledString, result, _dice.modifier), 171 | "Black", 172 | {0.666, 0.666, 0.666, 1} 173 | ) 174 | end 175 | result = result + _dice.modifier 176 | self.setDescription(log) 177 | self.editButton({index = 0, label = result}) 178 | end 179 | 180 | function calcSet(set) 181 | local result = 0 182 | local rolls = {} 183 | for i = 1, set.dice do 184 | math.randomseed(math.random(250, 12456)) 185 | local roll1 = math.random(1, set.sides) 186 | math.randomseed(math.random(roll1 * math.random(750, 98723))) 187 | local roll2 = math.random(1, set.sides) 188 | 189 | local roll = math.max(roll1, roll2) 190 | table.insert(rolls, {roll = roll, scrap = math.min(roll1, roll2)}) 191 | result = result + roll 192 | end 193 | return {result = result, rolls = rolls} 194 | end 195 | 196 | function split(str, pat) 197 | local t = {} 198 | local fpat = "(.-)" .. pat 199 | local last_end = 1 200 | local s, 201 | e, 202 | cap = str:find(fpat, 1) 203 | while s do 204 | if s ~= 1 or cap ~= "" then 205 | table.insert(t, cap) 206 | end 207 | last_end = e + 1 208 | s, 209 | e, 210 | cap = str:find(fpat, last_end) 211 | end 212 | if last_end <= #str then 213 | cap = str:sub(last_end) 214 | table.insert(t, cap) 215 | end 216 | return t 217 | end 218 | -------------------------------------------------------------------------------- /exploding_dice/exploding-dice.lua: -------------------------------------------------------------------------------- 1 | ref_customDieSides = {["4"] = 0, ["6"] = 1, ["8"] = 2, ["10"] = 3, ["12"] = 4, ["20"] = 5} 2 | ref_customDieSides_rev = {4, 6, 8, 10, 12, 20} 3 | ref_defaultDieSides = {"Die_4", "Die_6", "Die_8", "Die_10", "Die_12", "Die_20"} 4 | 5 | local sides = nil 6 | local rolling = false 7 | local refDie = nil 8 | local crit = nil 9 | local custom_dice = false 10 | 11 | function onLoad() 12 | sides = self.getRotationValues() 13 | custom_dice = self.getCustomObject() ~= nil 14 | 15 | self.addContextMenuItem("Reroll dice", reroll) 16 | 17 | toRoll(self) 18 | end 19 | 20 | function setCustom(params) 21 | ref_diceCustom[params.side] = params.url 22 | end 23 | 24 | function selfReroll(params) 25 | if self.getLock() then 26 | self.setLock(false) 27 | self.setColorTint(Color.Green) 28 | end 29 | end 30 | 31 | function reroll(player_color) 32 | local objs = Player[player_color].getSelectedObjects() 33 | 34 | if #objs > 1 then 35 | for i = 1, #objs do 36 | callIfCallable(objs[i].call("selfReroll")) 37 | --objs[i].call("selfReroll") 38 | end 39 | elseif self.getLock() then 40 | self.setLock(false) 41 | self.setColorTint(Color.Green) 42 | end 43 | end 44 | 45 | function onDestroy() 46 | if refDie ~= nil then 47 | refDie.destruct() 48 | end 49 | end 50 | 51 | function onRandomize() 52 | if not rolling and not self.getLock() then 53 | monitorDie(self) 54 | end 55 | end 56 | 57 | function monitorDie(die) 58 | rolling = true 59 | function monitorDie_coroutine() 60 | repeat 61 | coroutine.yield(0) 62 | until die.resting == true 63 | rolling = false 64 | die.setLock(true) 65 | didRoll(die) 66 | 67 | local gm = self.getGMNotes() 68 | if gm ~= nil and gm ~= "" then 69 | local json = JSON.decode(gm) 70 | if json["crit"] then 71 | crit = json["crit"] 72 | end 73 | end 74 | 75 | if crit then 76 | local value = die.getValue() 77 | if crit == 0 then 78 | explode(die) 79 | elseif value >= #sides - crit then 80 | explode(die) 81 | end 82 | elseif die.getValue() == #sides then 83 | explode(die) 84 | end 85 | 86 | return 1 87 | end 88 | startLuaCoroutine(self, "monitorDie_coroutine") 89 | end 90 | 91 | function explode(die) 92 | if #sides ~= 4 then 93 | local s = ref_customDieSides[tostring(#sides)] 94 | explodeWith(ref_customDieSides_rev[s]) 95 | end 96 | end 97 | 98 | function explodeWith(dieSides) 99 | local spawnPos = self.getPosition() 100 | spawnPos.x = spawnPos.x + math.random(-1.5, 1.5) 101 | spawnPos.z = spawnPos.z + math.random(-1.5, 1.5) 102 | 103 | local selfScale = self.getScale() 104 | 105 | if not custom_dice then 106 | dieSides = "Die" .. dieSides 107 | end 108 | 109 | spawnObject( 110 | { 111 | type = custom_dice ~= nil and "Custom_Dice" or dieSides, 112 | position = spawnPos, 113 | rotation = randomRotation(), 114 | scale = {selfScale.x - 0.05, selfScale.y - 0.05, selfScale.z - 0.05}, 115 | callback_function = function(obj) 116 | obj.setLuaScript(self.getLuaScript()) 117 | obj.setGMNotes(self.getGMNotes()) 118 | refDie = obj 119 | if custom_dice ~= nil then 120 | obj.setCustomObject( 121 | { 122 | image = ref_diceCustom[dieSides], 123 | type = ref_customDieSides[tostring(dieSides)] 124 | } 125 | ) 126 | obj.reload() 127 | end 128 | end 129 | } 130 | ) 131 | end 132 | 133 | function toRoll(die) 134 | die.setColorTint(Color.Green) 135 | end 136 | 137 | function didRoll(die) 138 | die.setColorTint(Color.Red) 139 | end 140 | 141 | --Gets a random rotation vector 142 | function randomRotation() 143 | --Credit for this function goes to Revinor (forums) 144 | --Get 3 random numbers 145 | local u1 = math.random() 146 | local u2 = math.random() 147 | local u3 = math.random() 148 | --Convert them into quats to avoid gimbal lock 149 | local u1sqrt = math.sqrt(u1) 150 | local u1m1sqrt = math.sqrt(1 - u1) 151 | local qx = u1m1sqrt * math.sin(2 * math.pi * u2) 152 | local qy = u1m1sqrt * math.cos(2 * math.pi * u2) 153 | local qz = u1sqrt * math.sin(2 * math.pi * u3) 154 | local qw = u1sqrt * math.cos(2 * math.pi * u3) 155 | --Apply rotation 156 | local ysqr = qy * qy 157 | local t0 = -2.0 * (ysqr + qz * qz) + 1.0 158 | local t1 = 2.0 * (qx * qy - qw * qz) 159 | local t2 = -2.0 * (qx * qz + qw * qy) 160 | local t3 = 2.0 * (qy * qz - qw * qx) 161 | local t4 = -2.0 * (qx * qx + ysqr) + 1.0 162 | --Correct 163 | if t2 > 1.0 then 164 | t2 = 1.0 165 | end 166 | if t2 < -1.0 then 167 | ts = -1.0 168 | end 169 | --Convert back to X/Y/Z 170 | local xr = math.asin(t2) 171 | local yr = math.atan2(t3, t4) 172 | local zr = math.atan2(t1, t0) 173 | --Return result 174 | return {math.deg(xr), math.deg(yr), math.deg(zr)} 175 | end 176 | 177 | function callIfCallable(f) 178 | return function(...) 179 | error, 180 | result = pcall(f, ...) 181 | if error then -- f exists and is callable 182 | print("ok") 183 | return result 184 | end 185 | -- nothing to do, as though not called, or print('error', result) 186 | end 187 | end 188 | -------------------------------------------------------------------------------- /exploding_dice/exploding-note.lua: -------------------------------------------------------------------------------- 1 | function onLoad() 2 | self.createButton( 3 | { 4 | click_function = "calculateTotal", 5 | function_owner = self, 6 | label = "TOT", 7 | position = {0, 2.5, -0.37}, 8 | rotation = {0, 180, 0}, 9 | scale = {0.3, 0.5, 0.5}, 10 | width = 350, 11 | height = 300, 12 | color = {0, 0, 0, 1}, 13 | font_color = {1, 1, 1, 1}, 14 | tooltip = "Total" 15 | } 16 | ) 17 | self.createButton( 18 | { 19 | click_function = "clearDice", 20 | function_owner = self, 21 | label = "X", 22 | position = {-0.46, 2.5, 0.44}, 23 | rotation = {0.00, 180.00, 0.00}, 24 | scale = {0.5, 0.5, 0.5}, 25 | width = 65, 26 | height = 100, 27 | font_size = 50, 28 | color = {0, 0, 0, 1}, 29 | font_color = {1, 0, 0, 1}, 30 | tooltip = "Clear Dice" 31 | } 32 | ) 33 | 34 | self.createButton( 35 | { 36 | click_function = "clearTotal", 37 | function_owner = self, 38 | label = "Clear Total", 39 | position = {-0.36, 2.5, 0.439999997615814}, 40 | rotation = {0, 180, 0}, 41 | scale = {0.2, 0.5, 0.3}, 42 | width = 315, 43 | height = 185, 44 | font_size = 50, 45 | color = {0, 0, 0, 1}, 46 | font_color = {1, 0, 0, 1}, 47 | tooltip = "" 48 | } 49 | ) 50 | end 51 | 52 | function calculateTotal() 53 | local desc = self.getDescription() 54 | if desc ~= "" then 55 | local numbers = mysplit(desc, ", ") 56 | local tot = 0 57 | for i = 1, #numbers do 58 | tot = tot + numbers[i] 59 | end 60 | self.editButton({index = 0, label = tot}) 61 | end 62 | end 63 | 64 | function clearDice() 65 | local desc = self.getGMNotes() 66 | if desc ~= "" then 67 | local objs = mysplit(desc, ",") 68 | for i = 1, #objs do 69 | local o = getObjectFromGUID(objs[i]) 70 | o.destruct() 71 | end 72 | self.setGMNotes("") 73 | end 74 | end 75 | 76 | function clearTotal() 77 | self.setDescription("") 78 | local oldTot = self.getButtons()[1].label 79 | 80 | self.editButton({index = 0, label = "TOT"}) 81 | self.editButton({index = 2, tooltip = "Old Total: " .. oldTot}) 82 | end 83 | 84 | function mysplit(inputstr, sep) 85 | if sep == nil then 86 | sep = "%s" 87 | end 88 | local t = {} 89 | i = 1 90 | for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do 91 | t[i] = str 92 | i = i + 1 93 | end 94 | return t 95 | end 96 | -------------------------------------------------------------------------------- /hide-me.lua: -------------------------------------------------------------------------------- 1 | function onload() 2 | local gm = self.getGMNotes() 3 | if gm == "" then 4 | self.setGMNotes("true") 5 | gm = "true" 6 | end 7 | 8 | if gm == "true" then 9 | self.addContextMenuItem("[2ECC40]Visible[-]", hideMe) 10 | else 11 | self.addContextMenuItem("[FF4136]Invisible[-]", showMe) 12 | end 13 | end 14 | 15 | function hideMe() 16 | self.setGMNotes("false") 17 | self.setInvisibleTo( 18 | { 19 | "White", 20 | "Brown", 21 | "Red", 22 | "Orange", 23 | "Yellow", 24 | "Green", 25 | "Teal", 26 | "Blue", 27 | "Purple", 28 | "Pink", 29 | "Grey" 30 | } 31 | ) 32 | 33 | self.clearContextMenu() 34 | self.addContextMenuItem("[FF4136]Invisible[-]", showMe) 35 | end 36 | 37 | function showMe() 38 | self.setGMNotes("true") 39 | self.setInvisibleTo({}) 40 | 41 | self.clearContextMenu() 42 | self.addContextMenuItem("[2ECC40]Visible[-]", hideMe) 43 | end -------------------------------------------------------------------------------- /image-changer.lua: -------------------------------------------------------------------------------- 1 | --Runs when the scripted button inside the button is clicked 2 | function buttonPress() 3 | if lockout == false then 4 | local gm = self.getGMNotes() 5 | local obj = getObjectFromGUID(gm) 6 | 7 | local img = self.getDescription() 8 | obj.setCustomObject({image = img}) 9 | obj.reload() 10 | 11 | obj.highlightOn(Color.White, 2) 12 | 13 | self.AssetBundle.playTriggerEffect(0) --triggers animation/sound 14 | lockout = true --locks out the button 15 | startLockoutTimer() --Starts up a timer to remove lockout 16 | end 17 | end 18 | 19 | --Runs on load, creates button and makes sure the lockout is off 20 | function onload() 21 | self.createButton( 22 | { 23 | label = "Big Red Button\n\nBy: MrStump", 24 | click_function = "buttonPress", 25 | function_owner = self, 26 | position = {0, 0.25, 0}, 27 | height = 1400, 28 | width = 1400 29 | } 30 | ) 31 | lockout = false 32 | end 33 | 34 | --Starts a timer that, when it ends, will unlock the button 35 | function startLockoutTimer() 36 | Timer.create({identifier = self.getGUID(), function_name = "unlockLockout", delay = 0.5}) 37 | end 38 | 39 | --Unlocks button 40 | function unlockLockout() 41 | lockout = false 42 | end 43 | 44 | --Ends the timer if the object is destroyed before the timer ends, to prevent an error 45 | function onDestroy() 46 | Timer.destroy(self.getGUID()) 47 | end 48 | -------------------------------------------------------------------------------- /interactable.lua: -------------------------------------------------------------------------------- 1 | function onLoad(save_state) 2 | self.createButton( 3 | { 4 | click_function = "make_interact", 5 | function_owner = self, 6 | label = "Make Interactable", 7 | position = {0, 0.5, 0.8}, 8 | scale = {0.5, 0.5, 0.5}, 9 | width = 3300, 10 | height = 600, 11 | font_size = 400, 12 | color = {0.192, 0.701, 0.168, 1} 13 | } 14 | ) 15 | 16 | self.createButton( 17 | { 18 | click_function = "make_not_interact", 19 | function_owner = self, 20 | label = "Make Non-Interactable", 21 | position = {0, 0.5, 1.6}, 22 | scale = {0.5, 0.5, 0.5}, 23 | width = 4200, 24 | height = 600, 25 | font_size = 400, 26 | color = {0.856, 0.1, 0.094, 1} 27 | } 28 | ) 29 | end 30 | 31 | function isMe(id) 32 | return id == self.getGUID() 33 | end 34 | 35 | function onCollisionEnter(info) 36 | local id = info.collision_object.getGUID() 37 | self.setDescription("Found: " .. id .. "\nMyself: " .. self.guid) 38 | end 39 | 40 | function make_interact(obj, player_clicker_color, alt_click) 41 | local id = self.getDescription() 42 | if Player[player_clicker_color].admin and not isMe(id) then 43 | local id = self.getDescription() 44 | if id == "" then 45 | return 46 | end 47 | local o = getObjectFromGUID(id) 48 | 49 | o.interactable = true 50 | self.setDescription("") 51 | Player[player_clicker_color].pingTable(getObjectFromGUID(id).getPosition()) 52 | 53 | local code = "function onload() self.interactable = true end" 54 | o.setLuaScript(code) 55 | end 56 | end 57 | 58 | function make_not_interact(obj, player_clicker_color, alt_click) 59 | if Player[player_clicker_color].admin and not isMe(id) then 60 | local id = self.getDescription() 61 | if id == "" then 62 | return 63 | end 64 | local o = getObjectFromGUID(id) 65 | o.interactable = false 66 | o.setLock(true) 67 | self.setDescription("") 68 | Player[player_clicker_color].pingTable(getObjectFromGUID(id).getPosition()) 69 | 70 | local code = "function onload() self.interactable = false end" 71 | o.setLuaScript(code) 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /item-positioner.lua: -------------------------------------------------------------------------------- 1 | local _objs = { 2 | ["d645e1"] = {pos = {5.52, 10.47, 8.68}, start = {}, moved = false}, 3 | ["3d7a9b"] = {pos = {9.84, 10.47, 14.15}, start = {}, moved = false}, 4 | ["62b14e"] = {pos = {11.66, 10.47, 6.45}, start = {}, moved = false}, 5 | ["989b93"] = {pos = {5.49, 10.47, -3.39}, start = {}, moved = false}, 6 | ["53caf9"] = {pos = {9.90, 10.47, -8.87}, start = {}, moved = false}, 7 | ["2c0d91"] = {pos = {11.68, 10.47, -1.18}, start = {}, moved = false}, 8 | ["9462fd"] = {pos = {14.96, 10.47, 2.68}, start = {}, moved = false}, 9 | ["016301"] = {pos = {1.95, 10.47, 12.58}, start = {}, moved = false}, 10 | ["7b3148"] = {pos = {1.91, 10.47, -7.35}, start = {}, moved = false}, 11 | ["cb43e0"] = {pos = {0.66, 8.61, 5.34}, start = {}, moved = false}, 12 | ["c9d7ee"] = {pos = {0.70, 8.61, -0.09}, start = {}, moved = false}, 13 | ["76e7e6"] = {pos = {-2.44, 7.12, 3.72}, start = {}, moved = false}, 14 | ["4b84cd"] = {pos = {-2.44, 7.12, 1.32}, start = {}, moved = false}, 15 | ["5cd489"] = {pos = {-4.96, 7.12, 0.46}, start = {}, moved = false}, 16 | ["e30a6a"] = {pos = {-4.96, 7.12, 4.55}, start = {}, moved = false} 17 | } 18 | 19 | local set = false 20 | 21 | function onLoad() 22 | local buttons = { 23 | { 24 | label = "d645e1", 25 | position = {1.2, 0.2, 0}, 26 | scale = {0.5, 0.5, 0.5}, 27 | width = 650, 28 | height = 200 29 | }, 30 | { 31 | label = "3d7a9b", 32 | position = {1.5, 0.2, 0.4}, 33 | scale = {0.5, 0.5, 0.5}, 34 | width = 650, 35 | height = 200 36 | }, 37 | { 38 | label = "62b14e", 39 | position = {0.9, 0.2, 0.8}, 40 | scale = {0.5, 0.5, 0.5}, 41 | width = 650, 42 | height = 200 43 | }, 44 | { 45 | label = "989b93", 46 | position = {-1.2, 0.2, 0}, 47 | scale = {0.5, 0.5, 0.5}, 48 | width = 650, 49 | height = 200 50 | }, 51 | { 52 | label = "53caf9", 53 | position = {-1.5, 0.2, 0.4}, 54 | scale = {0.5, 0.5, 0.5}, 55 | width = 650, 56 | height = 200 57 | }, 58 | { 59 | label = "2c0d91", 60 | position = {-0.9, 0.2, 0.8}, 61 | scale = {0.5, 0.5, 0.5}, 62 | width = 650, 63 | height = 200 64 | }, 65 | { 66 | label = "9462fd", 67 | position = {0, 0.2, 1.2}, 68 | scale = {0.5, 0.5, 0.5}, 69 | width = 650, 70 | height = 200 71 | }, 72 | { 73 | label = "016301", 74 | position = {1.4, 0.2, -0.4}, 75 | scale = {0.5, 0.5, 0.5}, 76 | width = 650, 77 | height = 200 78 | }, 79 | { 80 | label = "7b3148", 81 | position = {-1.4, 0.2, -0.4}, 82 | scale = {0.5, 0.5, 0.5}, 83 | width = 650, 84 | height = 200 85 | }, 86 | { 87 | label = "cb43e0", 88 | position = {0.25, 0.2, -0.7}, 89 | scale = {0.5, 0.5, 0.5}, 90 | width = 450, 91 | height = 200 92 | }, 93 | { 94 | label = "c9d7ee", 95 | position = {-0.25, 0.2, -0.7}, 96 | scale = {0.5, 0.5, 0.5}, 97 | width = 450, 98 | height = 200 99 | }, 100 | { 101 | label = "76e7e6", 102 | position = {0.35, 0.2, -1.1}, 103 | scale = {0.5, 0.5, 0.5}, 104 | width = 450, 105 | height = 200 106 | }, 107 | { 108 | label = "4b84cd", 109 | position = {-0.35, 0.2, -1.1}, 110 | scale = {0.5, 0.5, 0.5}, 111 | width = 450, 112 | height = 200 113 | }, 114 | { 115 | label = "5cd489", 116 | position = {-0.4, 0.2, -1.3}, 117 | scale = {0.5, 0.5, 0.5}, 118 | width = 450, 119 | height = 200 120 | }, 121 | { 122 | label = "e30a6a", 123 | position = {0.4, 0.2, -1.3}, 124 | scale = {0.5, 0.5, 0.5}, 125 | width = 450, 126 | height = 200 127 | } 128 | } 129 | for i = 1, #buttons do 130 | local funcName = "button_" .. i 131 | local func = function(_, c) 132 | button_click(c, buttons[i].label) 133 | end 134 | self.setVar(funcName, func) 135 | self.createButton( 136 | { 137 | click_function = funcName, 138 | function_owner = self, 139 | label = buttons[i].label, 140 | position = buttons[i].position, 141 | scale = {0.5, 0.5, 0.5}, 142 | width = buttons[i].width, 143 | height = buttons[i].height 144 | } 145 | ) 146 | end 147 | 148 | self.createButton( 149 | { 150 | click_function = "interactable", 151 | function_owner = self, 152 | label = "Interactable", 153 | position = {0, 0.2, -0.2}, 154 | scale = {0.5, 0.5, 0.5}, 155 | width = 650, 156 | height = 300 157 | } 158 | ) 159 | self.createButton( 160 | { 161 | click_function = "setup", 162 | function_owner = self, 163 | label = "Setup", 164 | position = {0, 0.2, 0.1}, 165 | scale = {0.5, 0.5, 0.5}, 166 | width = 650, 167 | height = 300 168 | } 169 | ) 170 | end 171 | 172 | function button_click(color, guid) 173 | if not set then 174 | notSet() 175 | return 176 | end 177 | 178 | local o = getObjectFromGUID(guid) 179 | local obj = _objs[guid] 180 | if (obj) then 181 | if not obj.moved then 182 | o.setPositionSmooth(obj.pos, false, false) 183 | obj.moved = true 184 | else 185 | o.setPositionSmooth(obj.start, false, false) 186 | obj.moved = false 187 | end 188 | end 189 | end 190 | 191 | function notSet() 192 | broadcastToColor("Need to set the thing", "Black", {r = 1, g = 1, b = 1}) 193 | end 194 | 195 | function setup() 196 | for guid, a in pairs(_objs) do 197 | local obj = getObjectFromGUID(guid) 198 | _objs[guid].start = obj.getPosition() 199 | end 200 | 201 | set = true 202 | end 203 | 204 | function interactable() 205 | if not set then 206 | notSet() 207 | return 208 | end 209 | for guid, a in pairs(_objs) do 210 | local obj = getObjectFromGUID(guid) 211 | obj.interactable = not obj.interactable 212 | end 213 | end 214 | -------------------------------------------------------------------------------- /item-stack.lua: -------------------------------------------------------------------------------- 1 | function onLoad() 2 | self.createButton( 3 | { 4 | click_function = "stack", 5 | function_owner = self, 6 | label = " ", 7 | position = {0, 0.1, 0}, 8 | scale = {0.5, 0.5, 0.5}, 9 | width = 750, 10 | height = 750, 11 | font_size = 400, 12 | color = {0.5, 0.5, 0.5, 1}, 13 | tooltip = "Stack buttons" 14 | } 15 | ) 16 | 17 | self.setGMNotes("") 18 | end 19 | 20 | function onCollisionEnter(info) 21 | if info then 22 | local obj = info.collision_object 23 | if obj then 24 | if obj.interactable then 25 | if obj.getGUID() then 26 | local returner = {} 27 | local gm = self.getGMNotes() 28 | local json = JSON.decode(gm) 29 | if json then 30 | returner = json 31 | end 32 | 33 | table.insert(returner, obj.getGUID()) 34 | self.setGMNotes(JSON.encode(returner)) 35 | end 36 | end 37 | end 38 | end 39 | end 40 | 41 | -- function onObjectCollisionEnter(hit_object, collision_info) 42 | -- -- collision_info table: 43 | -- -- collision_object Object 44 | -- -- contact_points Table {Vector, ...} 45 | -- -- relative_velocity Vector 46 | 47 | -- local returner = {} 48 | -- local gm = self.getGMNotes() 49 | -- local json = JSON.decode(gm) 50 | -- if #json > 0 then 51 | -- returner = json 52 | -- end 53 | 54 | -- if hit_object.interactable then 55 | -- local id = hit_object.getGUID() 56 | -- table.insert(returner, id) 57 | -- self.setGMNotes(JSON.encode(returner)) 58 | -- end 59 | -- end 60 | 61 | function stack() 62 | local gm = self.getGMNotes() 63 | local objs = JSON.decode(gm) 64 | 65 | local pos = self.getPosition() 66 | local rot = self.getRotation() 67 | 68 | pos.x = pos.x - 7 69 | pos.y = pos.y + 10 70 | 71 | for i, obj in ipairs(objs) do 72 | local o = getObjectFromGUID(obj) 73 | if o then 74 | Wait.time( 75 | function() 76 | o.setPosition(pos) 77 | o.setRotation({0, 0, 0}) 78 | end, 79 | 0.2 * i 80 | ) 81 | end 82 | end 83 | self.setGMNotes("") 84 | end 85 | -------------------------------------------------------------------------------- /macro-maker.lua: -------------------------------------------------------------------------------- 1 | function onLoad() 2 | self.createButton( 3 | { 4 | click_function = "work_macro", 5 | function_owner = self, 6 | label = "Activate Macro", 7 | position = {0, 0.5, 0.8}, 8 | scale = {0.5, 0.5, 0.5}, 9 | width = 3300, 10 | height = 600, 11 | font_size = 400, 12 | color = {0.2026, 0.4071, 0.9773, 1} 13 | } 14 | ) 15 | end 16 | 17 | function none() 18 | end 19 | 20 | function onCollisionEnter(info) 21 | if info.collision_object.interactable then 22 | local id = info.collision_object.getGUID() 23 | local gm = self.getGMNotes() 24 | local macro = JSON.decode(gm) 25 | macro.obj = id 26 | self.setGMNotes(JSON.encode(macro)) 27 | end 28 | end 29 | 30 | function onHover(player_color) 31 | if player_color == "Black" then 32 | local gm = self.getGMNotes() 33 | if gm == "" or gm == nil then 34 | self.setGMNotes( 35 | [[{ 36 | "obj":"aaaaaa", 37 | "position":[999,999,999], 38 | "rotation":[999,999,999], 39 | "interact": true, 40 | "lock": true, 41 | "visible": true 42 | }]] 43 | ) 44 | self.highlightOn(Color.Green, 1) 45 | end 46 | end 47 | end 48 | 49 | function work_macro() 50 | -- position 51 | -- make interactable 52 | -- make visible 53 | --[[ 54 | { 55 | "obj":"aaaaaa", 56 | "position":[1,1,1], 57 | "rotation":[1,1,1], 58 | "interact": true, 59 | "lock": true, 60 | "visible": true 61 | } 62 | ]] 63 | -- with position = 999 then the token will take relative position 64 | local gm = self.getGMNotes() 65 | if gm then 66 | local macro = JSON.decode(gm) 67 | 68 | local obj = getObjectFromGUID(macro.obj) 69 | local pos, 70 | rot, 71 | interact 72 | if exists(macro.position) ~= nil then 73 | pos = { 74 | x = correctPositionCoordinate("x", macro.position[1], obj), 75 | y = correctPositionCoordinate("y", macro.position[2], obj), 76 | z = correctPositionCoordinate("z", macro.position[3], obj) 77 | } 78 | obj.setPosition(pos) 79 | end 80 | if exists(macro.rotation) then 81 | rot = { 82 | x = correctRotationCoordinate("x", macro.rotation[1], obj), 83 | y = correctRotationCoordinate("y", macro.rotation[2], obj), 84 | z = correctRotationCoordinate("z", macro.rotation[3], obj) 85 | } 86 | obj.setRotation(rot) 87 | end 88 | if exists(macro.interact) then 89 | interact = macro.interact 90 | if exists(macro.lock) then 91 | toggle_interact(obj, interact, macro.lock) 92 | else 93 | toggle_interact(obj, interact, true) 94 | end 95 | end 96 | 97 | if exists(macro.visible) then 98 | if macro.visible then 99 | obj.setColorTint({r = 1, g = 1, b = 1, a = 1}) 100 | else 101 | obj.setColorTint({r = 1, g = 1, b = 1, a = 0}) 102 | end 103 | end 104 | end 105 | end 106 | 107 | function correctPositionCoordinate(xyz, coord, obj) 108 | if coord == 999 then 109 | return obj.getPosition()[xyz] 110 | else 111 | return coord 112 | end 113 | end 114 | 115 | function correctRotationCoordinate(xyz, coord, obj) 116 | if coord == 999 then 117 | return obj.getRotation()[xyz] 118 | else 119 | return coord 120 | end 121 | end 122 | 123 | function exists(variable) 124 | return variable ~= nil 125 | end 126 | 127 | function toggle_interact(o, interact, lock) 128 | o.interactable = interact 129 | o.setLock(lock) 130 | local code = "function onload() self.interactable = " .. tostring(interact) .. " end" 131 | o.setLuaScript(code) 132 | end 133 | -------------------------------------------------------------------------------- /notecard 2.0.lua: -------------------------------------------------------------------------------- 1 | --local commander = "9d42ad" 2 | local commander = "878b50" 3 | 4 | function onLoad() 5 | local data = { 6 | click_function = "parse", 7 | function_owner = self, 8 | label = "Parse", 9 | position = {-0.39, 2.4, -0.43}, 10 | rotation = {0, 180, 0}, 11 | scale = {0.1, 1, 0.18}, 12 | width = 1100, 13 | height = 400, 14 | font_size = 400, 15 | color = {0.1341, 0.1341, 0.1341, 1}, 16 | font_color = {1, 1, 1, 1} 17 | } 18 | self.createButton(data) 19 | end 20 | 21 | --/|2|r50-68|12|6|2d6+4 22 | 23 | function parse() 24 | if self.getDescription() ~= "" and self.getName() ~= "" then 25 | local vars = JSON.decode(self.getDescription()) 26 | local npc_commander = getObjectFromGUID(commander) 27 | 28 | if vars.name then 29 | npc_commander.call("setName", {input = vars.name}) 30 | end 31 | 32 | if vars.ini then 33 | npc_commander.call("setINI", {input = vars.ini}) 34 | end 35 | 36 | if vars.hp then 37 | npc_commander.call("setHP", {input = vars.hp}) 38 | end 39 | 40 | if vars.ac then 41 | npc_commander.call("setAC", {input = vars.ac}) 42 | end 43 | 44 | if vars.mov then 45 | npc_commander.call("setMovement", {input = vars.mov}) 46 | end 47 | 48 | if vars.size then 49 | npc_commander.call("setSize", {input = vars.size}) 50 | end 51 | 52 | if vars.image then 53 | npc_commander.setDescription(vars.image) 54 | npc_commander.call("toggleIsBoss", {input = true}) 55 | else 56 | npc_commander.call("toggleIsBoss", {input = false}) 57 | end 58 | 59 | if vars.side then 60 | npc_commander.call("setSide", {input = vars.side}) 61 | else 62 | npc_commander.call("setSide", {input = "enemy"}) 63 | end 64 | 65 | if self.getGMNotes() ~= "" then 66 | -- this means i have multiple that i want to make 67 | local number = tonumber(self.getGMNotes()) 68 | npc_commander.call("setNumberToCreate", {input = number}) 69 | else 70 | npc_commander.call("setNumberToCreate", {input = 1}) 71 | end 72 | 73 | -- local stuff = mysplit(mysplit(self.getDescription(), "\n")[1], "|") 74 | -- local npc_commander = getObjectFromGUID(commander) 75 | -- npc_commander.call("setName", {input = stuff[1]}) 76 | -- npc_commander.call("setINI", {input = stuff[2]}) 77 | -- npc_commander.call("setHP", {input = stuff[3]}) 78 | -- npc_commander.call("setAC", {input = stuff[4]}) 79 | -- npc_commander.call("setATK", {input = stuff[5]}) 80 | -- npc_commander.call("setDMG", {input = stuff[6]}) 81 | 82 | -- if stuff[7] then 83 | -- npc_commander.call("setMovement", {input = stuff[7]}) 84 | -- end 85 | 86 | -- if stuff[8] then 87 | -- npc_commander.call("setSize", {input = stuff[8]}) 88 | -- end 89 | 90 | -- local second_line = mysplit(self.getDescription(), "\n")[2] 91 | -- if second_line ~= nil and second_line ~= "" then 92 | -- -- this means it is a boss 93 | -- npc_commander.setDescription(second_line) 94 | -- npc_commander.call("toggleIsBoss", {input = true}) 95 | -- else 96 | -- npc_commander.call("toggleIsBoss", {input = false}) 97 | -- end 98 | 99 | -- if self.getGMNotes() ~= "" then 100 | -- -- this means i have multiple that i want to make 101 | -- local number = tonumber(self.getGMNotes()) 102 | -- npc_commander.call("setNumberToCreate", {input = number}) 103 | -- end 104 | end 105 | end 106 | 107 | function mysplit(inputstr, sep) 108 | if sep == nil then 109 | sep = "%s" 110 | end 111 | local t = {} 112 | i = 1 113 | for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do 114 | t[i] = str 115 | i = i + 1 116 | end 117 | return t 118 | end 119 | -------------------------------------------------------------------------------- /pin-positioner.lua: -------------------------------------------------------------------------------- 1 | --Runs when the scripted button inside the button is clicked 2 | function buttonPress() 3 | if lockout == false then 4 | local desc = self.getDescription() 5 | if desc ~= "" then 6 | local obj = getObjectFromGUID(desc) 7 | 8 | local notes = obj.getGMNotes() 9 | local pos = {} 10 | local rot = {} 11 | 12 | if notes == "" then 13 | pos = {115.27, 11.88, -79.46} 14 | rot = {347.94, 314.99, 0.35} 15 | else 16 | local vars = JSON.decode(notes) 17 | pos = {vars.pos[1], vars.pos[2], vars.pos[3]} 18 | rot = {vars.rot[1], vars.rot[2], vars.rot[3]} 19 | end 20 | obj.setPositionSmooth(pos, false, true) 21 | obj.setRotationSmooth(rot, false, true) 22 | obj.setLock(true) 23 | self.setDescription("") 24 | end 25 | 26 | self.AssetBundle.playTriggerEffect(0) --triggers animation/sound 27 | lockout = true --locks out the button 28 | startLockoutTimer() --Starts up a timer to remove lockout 29 | end 30 | end 31 | 32 | --Runs on load, creates button and makes sure the lockout is off 33 | function onload() 34 | self.createButton( 35 | { 36 | label = "Big Red Button\n\nBy: MrStump", 37 | click_function = "buttonPress", 38 | function_owner = self, 39 | position = {0, 0.25, 0}, 40 | height = 1400, 41 | width = 1400 42 | } 43 | ) 44 | lockout = false 45 | end 46 | 47 | function onCollisionEnter(info) 48 | local obj = info.collision_object 49 | if obj.interactable then 50 | if obj.getGUID() then 51 | self.setDescription(obj.getGUID()) 52 | end 53 | end 54 | end 55 | 56 | --Starts a timer that, when it ends, will unlock the button 57 | function startLockoutTimer() 58 | Timer.create({identifier = self.getGUID(), function_name = "unlockLockout", delay = 0.5}) 59 | end 60 | 61 | --Unlocks button 62 | function unlockLockout() 63 | lockout = false 64 | end 65 | 66 | --Ends the timer if the object is destroyed before the timer ends, to prevent an error 67 | function onDestroy() 68 | Timer.destroy(self.getGUID()) 69 | end 70 | -------------------------------------------------------------------------------- /pin.lua: -------------------------------------------------------------------------------- 1 | function onLoad(save_state) 2 | local desc = self.getDescription() 3 | local label = "" 4 | if desc ~= "" then 5 | label = desc 6 | end 7 | 8 | --self.createButton( 9 | -- { 10 | -- click_function = "none", 11 | -- function_owner = self, 12 | -- label = label, 13 | -- position = {0, 0, 1}, 14 | -- rotation = {-90, 0, 0}, 15 | -- scale = {0.5, 0.5, 0.5}, 16 | -- width = 2000, 17 | -- height = 900, 18 | -- font_size = 250, 19 | -- alignment = 3 20 | -- } 21 | --) 22 | 23 | self.UI.setAttribute("txt", "text", label) 24 | if label == "" then 25 | self.UI.setAttribute("bg", "color", "#ffffff00") 26 | else 27 | self.UI.setAttribute("bg", "color", "#ffffffaa") 28 | if hasSecondLine(label) then 29 | self.UI.setAttribute("bg", "height", "60") 30 | else 31 | self.UI.setAttribute("bg", "height", "30") 32 | end 33 | end 34 | 35 | self.addContextMenuItem("[1A4F8B]Aquila[-]", aquila) 36 | self.addContextMenuItem("[76922B]Ekehm[-]", ekehm) 37 | self.addContextMenuItem("[813CA3]Mourning Lands[-]", ml) 38 | self.addContextMenuItem("[9B1412]Oshil[-]", oshil) 39 | self.addContextMenuItem("[B03900]Trisen[-]", trisen) 40 | self.addContextMenuItem("[8AB90D]Zunirth[-]", zunirth) 41 | self.addContextMenuItem("[39CCCC]Save[-]", save) 42 | self.addContextMenuItem("[1E6D6D]Reposition[-]", repos) 43 | end 44 | 45 | local _reposPos = {129.35, 4, -29.81} 46 | function repos(player_color) 47 | if (player_color == "Black") then 48 | self.setPositionSmooth(_reposPos, false, false) 49 | self.setRotation({0, 270, 0}) 50 | self.setLock(false) 51 | end 52 | end 53 | 54 | function save() 55 | local curPos = self.getPosition() 56 | local curRot = self.getRotation() 57 | local vals = { 58 | pos = { 59 | tonumber(string.format("%.2f", curPos.x)), 60 | tonumber(string.format("%.2f", curPos.y)), 61 | tonumber(string.format("%.2f", curPos.z)) 62 | }, 63 | rot = { 64 | tonumber(string.format("%.2f", curRot.x)), 65 | tonumber(string.format("%.2f", curRot.y)), 66 | tonumber(string.format("%.2f", curRot.z)) 67 | } 68 | } 69 | self.setGMNotes(JSON.encode(vals)) 70 | end 71 | 72 | function none() 73 | end 74 | 75 | function aquila() 76 | self.setColorTint({r = 27 / 255, g = 80 / 255, b = 140 / 255}) 77 | end 78 | 79 | function trisen() 80 | self.setColorTint({r = 176 / 255, g = 58 / 255, b = 0 / 255}) 81 | end 82 | 83 | function oshil() 84 | self.setColorTint({r = 155 / 255, g = 21 / 255, b = 19 / 255}) 85 | end 86 | 87 | function zunirth() 88 | self.setColorTint({r = 138 / 255, g = 185 / 255, b = 14 / 255}) 89 | end 90 | 91 | function ml() 92 | self.setColorTint({r = 130 / 255, g = 61 / 255, b = 163 / 255}) 93 | end 94 | 95 | function ekehm() 96 | self.setColorTint({r = 119 / 255, g = 146 / 255, b = 44 / 255}) 97 | end 98 | 99 | local lineHeight = 30 100 | local offset = 10 101 | function onObjectPickUp(player_color, picked_up_object) 102 | if picked_up_object.getGUID() == self.getGUID() then 103 | --self.editButton( 104 | -- { 105 | -- index = 0, 106 | -- label = self.getDescription() 107 | -- } 108 | --) 109 | local label = self.getDescription() 110 | self.UI.setAttribute("txt", "text", label) 111 | if label == "" then 112 | self.UI.setAttribute("bg", "color", "#ffffff00") 113 | else 114 | self.UI.setAttribute("bg", "color", "#ffffffaa") 115 | if hasSecondLine(label) then 116 | self.UI.setAttribute("bg", "height", tostring(lineHeight * 2)) 117 | else 118 | self.UI.setAttribute("bg", "height", tostring(lineHeight)) 119 | end 120 | end 121 | end 122 | end 123 | 124 | function hasSecondLine(txt) 125 | return string.find(txt, "\n") ~= nil 126 | end 127 | -------------------------------------------------------------------------------- /pin.xml: -------------------------------------------------------------------------------- 1 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Manage Reminders 53 | 54 | 55 | -------------------------------------------------------------------------------- /player_manager/readme.md: -------------------------------------------------------------------------------- 1 | This is a snippet, meaning that it must be put as a piece of code somewhere else. The variables within need to be changed accordingly for your own table. If you need a representation of how to implement it, just read the changelog that was introduced with this file and you should be able how I implemented it. 2 | 3 | Credits to https://game-icons.net for all the icons that can be found in /states/ 4 | -------------------------------------------------------------------------------- /player_manager/shapes/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/player_manager/shapes/circle.png -------------------------------------------------------------------------------- /player_manager/shapes/cone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/player_manager/shapes/cone.png -------------------------------------------------------------------------------- /player_manager/shapes/cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zavian/Tabletop-Simulator-Scripts/912056c197148f715400a8f7cf102ffc8d079090/player_manager/shapes/cube.png -------------------------------------------------------------------------------- /player_manager/state-player-manager.min.lua: -------------------------------------------------------------------------------- 1 | local a=nil;local b=nil;function manage_state(c,d,e)if master~=""then a=getObjectFromGUID(master)end;if c.color=="Black"then self.UI.setAttribute(e,"active","false")else self.UI.setAttribute(e,"active","false")a.call("manage_condition",{c=e})end end;function onCollisionEnter(f)if master~=""then a=getObjectFromGUID(master)end;if a~=nil then local g=f.collision_object;if isCondition(g.getName():gsub(" ","_"))then self.UI.setAttribute(string.lower(g.getName()),"active","true")g.destruct()elseif g.getName()=="Clear Area"then removeArea()elseif isAreaObject(g.getName())then makeJoined(g)end end end;function isCondition(h)h=string.lower(h)local i={"blinded","charmed","concentration","deafened","frightened","grappled","incapacitated","invisible","on_fire","paralyzed","petrified","poisoned","restrained","stunned"}for j=1,#i do if i[j]==h then return true end end;return false end;function makeJoined(g)removeArea()g.jointTo(self,{type="Fixed",collision=false})g.setVar("parent",self)g.setLuaScript('function onLoad()(self.getComponent("BoxCollider")or self.getComponent("MeshCollider")).set("enabled",false)Wait.condition(function()(self.getComponent("BoxCollider")or self.getComponent("MeshCollider")).set("enabled",false)end,function()return not self.loading_custom end)end;function onUpdate()if parent~=nil then if not parent.resting then self.setPosition(parent.getPosition())local a=parent.getScale()if a.x<=1 then self.setScale({x=1.70,y=0.01,z=1.70})end end else self.destruct()end end')g.getComponent("MeshRenderer").set("receiveShadows",false)g.mass=0;g.bounciness=0;g.drag=0;g.use_snap_points=false;g.use_grid=false;g.use_gravity=false;g.auto_raise=false;g.sticky=false;g.interactable=true;Wait.time(function()local k=g.getScale()g.setScale({x=k.x,y=0.01,z=k.z})g.setRotationSmooth({x=0,y=g.getRotation().y,z=0},false,true)b=g end,0.5)end;function removeArea()if b then b.destruct()b=nil end end;function isAreaObject(l)local m={"10'r","15'r","20'r","30'r","40'r","10'cone","15'cone","30'cone","60'cone","10'c","15'c","20'c","30'c","40'c"}for j=1,#m do if l==m[j]then return true end end;return false end -------------------------------------------------------------------------------- /potion maker/potion maker.lua: -------------------------------------------------------------------------------- 1 | function mysplit(inputstr, sep) 2 | if sep == nil then 3 | sep = "%s" 4 | end 5 | local t = {} 6 | i = 1 7 | for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do 8 | t[i] = str 9 | i = i + 1 10 | end 11 | return t 12 | end 13 | 14 | --Runs when the scripted button inside the button is clicked 15 | function buttonPress() 16 | if lockout == false then 17 | --Call on any other function here. For example: 18 | --Global.call("Function Name", {table of parameters if needed}) 19 | --You could also add your own scrting here. For example: 20 | --print("The button was pressed. Hoozah.") 21 | 22 | local text = self.UI.getAttribute("text", "value") 23 | local desc = self.getDescription() 24 | 25 | local data = JSON.decode(text) 26 | 27 | local obj = getObjectFromGUID(desc) 28 | 29 | obj.setName(data.title .. data.description) 30 | obj.setDescription(data.lore) 31 | obj.highlightOn(Color.Green, 1) 32 | 33 | obj.setColorTint(hexToRgb(data.color)) 34 | 35 | self.AssetBundle.playTriggerEffect(0) --triggers animation/sound 36 | lockout = true --locks out the button 37 | startLockoutTimer() --Starts up a timer to remove lockout 38 | end 39 | end 40 | 41 | function colorTranslate(color) 42 | --[[ 43 | arr["Green"] = "u"; 44 | arr["Navy"] = "r"; 45 | arr["BlueViolet"] = "e"; 46 | arr["#c46709"] = "l"; 47 | --]] 48 | local r = "" 49 | if color == "u" then 50 | r = "Green" 51 | elseif color == "r" then 52 | r = "Blue" 53 | elseif color == "e" then 54 | r = "Purple" 55 | elseif color == "l" then 56 | r = {r = 0.768627, g = 0.403922, b = 0.035294} 57 | else 58 | r = "White" 59 | end 60 | 61 | return r 62 | end 63 | 64 | --Runs on load, creates button and makes sure the lockout is off 65 | function onload() 66 | self.createButton( 67 | { 68 | label = "Big Red Button\n\nBy: MrStump", 69 | click_function = "buttonPress", 70 | function_owner = self, 71 | position = {0, 0.25, 0}, 72 | height = 1400, 73 | width = 1400 74 | } 75 | ) 76 | lockout = false 77 | 78 | self.UI.setAttribute("text", "onValueChanged", self.getGUID() .. "/UIUpdateValue(value)") 79 | end 80 | 81 | function onCollisionEnter(info) 82 | local guid = info.collision_object.guid 83 | if info.collision_object.interactable then 84 | self.setDescription(guid) 85 | info.collision_object.highlightOn(Color.Yellow, 1) 86 | else 87 | self.setDescription("") 88 | end 89 | end 90 | 91 | function UIUpdateValue(player, text, id) 92 | self.UI.setAttribute("text", "value", text) 93 | end 94 | 95 | --Starts a timer that, when it ends, will unlock the button 96 | function startLockoutTimer() 97 | Timer.create({identifier = self.getGUID(), function_name = "unlockLockout", delay = 0.5}) 98 | end 99 | 100 | --Unlocks button 101 | function unlockLockout() 102 | lockout = false 103 | end 104 | 105 | --Ends the timer if the object is destroyed before the timer ends, to prevent an error 106 | function onDestroy() 107 | Timer.destroy(self.getGUID()) 108 | end 109 | 110 | function hexToRgb(hex) 111 | hex = hex:gsub("#", "") 112 | if #hex < 8 then 113 | hex = hex .. "ff" 114 | end 115 | return color( 116 | tonumber("0x" .. hex:sub(1, 2), 16) / 255, 117 | tonumber("0x" .. hex:sub(3, 4), 16) / 255, 118 | tonumber("0x" .. hex:sub(5, 6), 16) / 255, 119 | tonumber("0x" .. hex:sub(7, 8), 16) / 255 120 | ) 121 | end 122 | -------------------------------------------------------------------------------- /potion maker/potion maker.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /reset-characters.lua: -------------------------------------------------------------------------------- 1 | --Runs when the scripted button inside the button is clicked 2 | 3 | local original_pos = {} 4 | local original_rot = {} 5 | local first = true 6 | 7 | function buttonPress() 8 | if lockout == false then 9 | local notes = self.getGMNotes() 10 | local j = JSON.decode(notes) 11 | 12 | local tokens = nil 13 | local coin = nil 14 | local point = nil 15 | local coinPos = nil 16 | 17 | if j.players then 18 | tokens = j.players 19 | point = { 20 | x = j.startingPoint.x and j.startingPoint.x or self.getPosition().x, 21 | y = j.startingPoint.y and j.startingPoint.y or 5, 22 | z = j.startingPoint.z and j.startingPoint.z or self.getPosition().z 23 | } 24 | end 25 | if j.coin then 26 | coin = j.coin 27 | coinPos = { 28 | x = j.coinPos.x and j.coinPos.x or self.getPosition().x, 29 | y = j.coinPos.y and j.coinPos.y or 5, 30 | z = j.coinPos.z and j.coinPos.z or self.getPosition().z 31 | } 32 | end 33 | local spacing = j.spacing and j.spacing or 1.7 34 | 35 | if first then 36 | original_pos = {} 37 | original_rot = {} 38 | 39 | if tokens then 40 | for i = 1, #tokens do 41 | --local token_info = tokens[i] 42 | local obj = getObjectFromGUID(tokens[i]) 43 | original_pos[tokens[i]] = obj.getPosition() 44 | original_pos[tokens[i]][2] = original_pos[tokens[i]][2] + 2 45 | 46 | original_rot[tokens[i]] = obj.getRotation() 47 | 48 | local pos = point 49 | local rotation = {0, 90.00, 0} 50 | 51 | obj.setRotationSmooth(rotation, false, true) 52 | obj.setPositionSmooth(pos, false, false) 53 | 54 | point.z = point.z - spacing 55 | if i % 3 == 0 then 56 | point.z = j.startingPoint.z and j.startingPoint.z or self.getPosition().z 57 | point.x = point.x + spacing 58 | end 59 | end 60 | 61 | if coin then 62 | local obj = getObjectFromGUID(coin) 63 | obj.setRotationSmooth({0, 90.0, 0}, false, true) 64 | obj.setPositionSmooth(coinPos, false, false) 65 | end 66 | else 67 | log("I do need some tokens from the resetter thinking") 68 | end 69 | first = false 70 | else 71 | first = true 72 | for i = 1, #tokens do 73 | local obj = getObjectFromGUID(tokens[i]) 74 | obj.setPositionSmooth(original_pos[tokens[i]], false, false) 75 | obj.setRotationSmooth(original_rot[tokens[i]], false, true) 76 | end 77 | end 78 | end 79 | end 80 | 81 | --Runs on load, creates button and makes sure the lockout is off 82 | function onload() 83 | self.createButton( 84 | { 85 | label = "Big Red Button\n\nBy: MrStump", 86 | click_function = "buttonPress", 87 | function_owner = self, 88 | position = {0, 0.25, 0}, 89 | height = 1400, 90 | width = 1400 91 | } 92 | ) 93 | lockout = false 94 | end 95 | 96 | --Starts a timer that, when it ends, will unlock the button 97 | function startLockoutTimer() 98 | Timer.create({identifier = self.getGUID(), function_name = "unlockLockout", delay = 0.5}) 99 | end 100 | 101 | --Unlocks button 102 | function unlockLockout() 103 | lockout = false 104 | end 105 | 106 | --Ends the timer if the object is destroyed before the timer ends, to prevent an error 107 | function onDestroy() 108 | Timer.destroy(self.getGUID()) 109 | end 110 | -------------------------------------------------------------------------------- /table-updater.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |