--[[ Character Sheet Template by: MrStump You can set up your own character sheet if you follow these steps. Step 1) Change the character sheet image -Right click on the character sheet, click Custom -Replace the image URL with one for your character sheet -Click import, make sure your sheet loads -SAVE THE GAME (the table setup) -LOAD FROM THAT SAVE YOU JUST MADE Step 2) Edit script to fit your character sheet -Below you will see some general options, and then the big data table -The data table is what determines how many of which buttons are made -Checkboxes -Counters -Textboxes -By default, there are 3 of each. You can add more or remove entries -If you intend to add/remove, be sure only to add/remove ENTRIES -This is what an entry looks like: { pos = {-0.977,0.1,-0.589}, size = 800, state = false }, -Deleting the whole thing would remove that specific item on the sheet -Copy and pasting it after another entry would create another -Each entry type has unique data points (pos, size, state, etc) -Do not try to add in your own data points or remove them individually -There is a summary of what each point does at the top of its category Step 3) Save and check script changes -Hit Save & Apply in the script window to save your code -You can edit your code as needed and Save+Apply as often as needed -When you are finished, make disableSave = false below then Save+apply -This enables saving, so your sheet will remember whats on it. Bonus) Finding/Editing Positions for elements I have included a tool to get positions for buttons in {x,y,z} form Place it where you want the center of your element to be Then copy the table from the notes (lower right of screen) You can highlight it and CTRL+C Paste it into the data table where needed (pos=) If you want to manually tweek the values: {0,0,0} is the center of the character sheet {1,0,0} is right, {-1,0,0} is left {0,0,-1} is up, {0,0,1} is down 0.1 for Y is the height off of the page. If it was 0, it would be down inside the model of the sheet Begin editing below: ]] --Set this to true while editing and false when you have finished disableSave = false --Remember to set this to false once you are done making changes --Then, after you save & apply it, save your game too --Color information for button text (r,g,b, values of 0-1) buttonFontColor = {0,0,0} --Color information for button background buttonColor = {0.902,0.886,0.788} --Change scale of button (Avoid changing if possible) buttonScale = {0.1,0.1,0.1} --This is the button placement information defaultButtonData = { --Add checkboxes checkbox = { --[[ pos = the position (pasted from the helper tool) size = height/width/font_size for checkbox state = default starting value for checkbox (true=checked, false=not) ]] --1 checkbox -- { -- pos = {0.306,0.1,0.05}, -- size = 250, -- state = false -- }, --End of checkboxes }, --Add counters that have a + and - button counter = { --[[ pos = the position (pasted from the helper tool) size = height/width/font_size for counter value = default starting value for counter hideBG = if background of counter is hidden (true=hidden, false=not) ]] --Slot one counter 1 { pos = {-0.7,0.1,-0.46}, size = 400, value = 0, hideBG = true }, --Slot one counter 2 { pos = {-0.51,0.1,-0.46}, size = 400, value = 0, hideBG = true }, --Slot one xp 1 { pos = {-0.517,0.1,-0.56}, size = 300, value = 0, hideBG = true }, --Slot two counter 1 { pos = {-0.274,0.1,-0.455}, size = 400, value = 0, hideBG = true }, --Slot two counter 2 { pos = {-0.06,0.1,-0.455}, size = 400, value = 0, hideBG = true }, --Slot two xp 1 { pos = {-0.061,0.1,-0.55}, size = 300, value = 0, hideBG = true }, --Slot three counter 1 { pos = {0.15,0.1,-0.45}, size = 400, value = 0, hideBG = true }, --Slot three counter 2 { pos = {0.379,0.1,-0.45}, size = 400, value = 0, hideBG = true }, --Slot three xp 1 { pos = {0.38,0.1,-0.55}, size = 300, value = 0, hideBG = true }, --Slot four counter 1 { pos = {0.614,0.1,-0.44}, size = 400, value = 0, hideBG = true }, --Slot four counter 2 { pos = {0.82,0.1,-0.44}, size = 400, value = 0, hideBG = true }, --Slot four xp 1 { pos = {0.827,0.1,-0.54}, size = 300, value = 0, hideBG = true }, --End of counters }, --Add editable text boxes textbox = { --[[ pos = the position (pasted from the helper tool) rows = how many lines of text you want for this box width = how wide the text box is font_size = size of text. This and "rows" effect overall height label = what is shown when there is no text. "" = nothing value = text entered into box. "" = nothing alignment = Number to indicate how you want text aligned (1=Automatic, 2=Left, 3=Center, 4=Right, 5=Justified) ]] --Slot one player { pos = {-0.64,0.1,-0.72}, rows = 1, width = 2000, font_size = 150, label = "Click to type", value = "", alignment = 2 }, --Slot one investigator { pos = {-0.64,0.1,-0.63}, rows = 1, width = 2000, font_size = 150, label = "Click to type", value = "", alignment = 2 }, --Slot one story { pos = {-0.64,0.1,-0.27}, rows = 9, width = 2000, font_size = 100, label = "Click to type", value = "", alignment = 2 }, --Slot two player { pos = {-0.2,0.1,-0.715}, rows = 1, width = 2000, font_size = 150, label = "Click to type", value = "", alignment = 2 }, --Slot two investigator { pos = {-0.2,0.1,-0.63}, rows = 1, width = 2000, font_size = 150, label = "Click to type", value = "", alignment = 2 }, --Slot two story { pos = {-0.2,0.1,-0.27}, rows = 9, width = 2000, font_size = 100, label = "Click to type", value = "", alignment = 2 }, --Slot three player { pos = {0.241,0.1,-0.71}, rows = 1, width = 2000, font_size = 150, label = "Click to type", value = "", alignment = 2 }, --Slot three investigator { pos = {0.24,0.1,-0.625}, rows = 1, width = 2000, font_size = 150, label = "Click to type", value = "", alignment = 2 }, --Slot three story { pos = {0.24,0.1,-0.268}, rows = 9, width = 2000, font_size = 100, label = "Click to type", value = "", alignment = 2 }, --Slot four player { pos = {0.69,0.1,-0.71}, rows = 1, width = 2000, font_size = 150, label = "Click to type", value = "", alignment = 2 }, --Slot four investigator { pos = {0.69,0.1,-0.62}, rows = 1, width = 2000, font_size = 150, label = "Click to type", value = "", alignment = 2 }, --Slot four story { pos = {0.671,0.1,-0.265}, rows = 9, width = 2000, font_size = 100, label = "Click to type", value = "", alignment = 2 }, --Memories Recovered { pos = {0.44,0.1,0.325}, rows =14, width = 3500, font_size = 200, label = "Click to type", value = "", alignment = 2 }, --Campaign Notes 1 { pos = {-0.43,0.1,0.33}, rows =14, width = 3500, font_size = 200, label = "Click to type", value = "", alignment = 2 }, --Campaign Notes 2 { pos = {-0.478,0.1,0.8}, rows = 8, width = 3000, font_size = 150, label = "Click to type", value = "", alignment = 2 }, --Killed and Insane { pos = {0.448,0.1,0.887}, rows = 5, width = 4000, font_size = 150, label = "Click to type", value = "", alignment = 2 }, --End of textboxes } } --Lua beyond this point, I recommend doing something more fun with your life --Save function local alreadySaving = false -- Copy this too! function updateSave() function string.replaceText(text, old, new) local b,e = text:find(old,1,true) if b==nil then return text else return text:sub(1,b-1) .. new .. text:sub(e+1) end end function wait(time) local start = os.time() repeat coroutine.yield(0) until os.time() > start + time end function deepcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[deepcopy(orig_key)] = deepcopy(orig_value) end setmetatable(copy, deepcopy(getmetatable(orig))) else -- number, string, boolean, etc copy = orig end return copy end function startSaving() while alreadySaving do wait(0.01) end alreadySaving = true local ref_buttonData = deepcopy(ref_buttonData) local input_values = {} local checkbox_values = {} local counter_values = {} local GUID = self.getGUID() local counter = 1 for _, val in ipairs(ref_buttonData.textbox) do if val.value != nil then input_values[counter] = val.value val.value = "u"..GUID..":iv:"..counter.."u" counter = counter + 1 end if val.label != nil then input_values[counter] = val.label val.label = "u"..GUID..":iv:"..counter.."u" counter = counter + 1 end end local counter = 1 for _, val in ipairs(ref_buttonData.checkbox) do if val.value != nil then checkbox_values[counter] = val.value val.value = "u"..GUID..":bv:"..counter.."u" counter = counter + 1 end end local counter = 1 for _, val in ipairs(ref_buttonData.counter) do if val.value != nil then counter_values[counter] = val.value val.value = "u"..GUID..":cv:"..counter.."u" counter = counter + 1 if val.counters != nil then for _, val2 in ipairs(val.counters) do if val2.value != nil then counter_values[counter] = val2.value val2.value = "u"..GUID..":cv:"..counter.."u" counter = counter + 1 end if val2.change_value != nil then counter_values[counter] = val2.change_value val2.change_value = "u"..GUID..":cv:"..counter.."u" counter = counter + 1 end end end end end saved_data = JSON.encode(ref_buttonData) local counter = 1 for _, val in ipairs(ref_buttonData.textbox) do if val.value != nil then saved_data = saved_data:replaceText("u"..GUID..":iv:"..counter.."u", string.gsub(input_values[counter], "[\\\"']", "\\%1")) val.value = input_values[counter] counter = counter + 1 end if val.label != nil then saved_data = saved_data:replaceText("u"..GUID..":iv:"..counter.."u", string.gsub(input_values[counter], "[\\\"']", "\\%1")) val.label = input_values[counter] counter = counter + 1 end end local counter = 1 for _, val in ipairs(ref_buttonData.checkbox) do if val.value != nil then val.value = checkbox_values[counter] saved_data = saved_data:replaceText("u"..GUID..":bv:"..counter.."u", string.gsub(checkbox_values[counter], "[\\\"']", "\\%1")) counter = counter + 1 end end local counter = 1 for _, val in ipairs(ref_buttonData.counter) do if val.value != nil then val.value = counter_values[counter] saved_data = saved_data:replaceText("u"..GUID..":cv:"..counter.."u", string.gsub(counter_values[counter], "[\\\"']", "\\%1")) counter = counter + 1 if val.counters != nil then for _, val2 in ipairs(val.counters) do if val2.value != nil then val2.value = counter_values[counter] saved_data = saved_data:replaceText("u"..GUID..":cv:"..counter.."u", string.gsub(counter_values[counter], "[\\\"']", "\\%1")) counter = counter + 1 end if val2.change_value != nil then val2.change_value = counter_values[counter] saved_data = saved_data:replaceText("u"..GUID..":cv:"..counter.."u", string.gsub(counter_values[counter], "[\\\"']", "\\%1")) counter = counter + 1 end end end end end if disableSave==true then saved_data="" end self.script_state = saved_data alreadySaving = false return 1 end startLuaCoroutine(self, "startSaving") end --Startup procedure function onload(saved_data) if disableSave==true then saved_data="" end if saved_data ~= "" then local loaded_data = JSON.decode(saved_data) ref_buttonData = loaded_data else ref_buttonData = defaultButtonData end spawnedButtonCount = 0 createCheckbox() createCounter() createTextbox() end --Click functions for buttons --Checks or unchecks the given box function click_checkbox(tableIndex, buttonIndex) if ref_buttonData.checkbox[tableIndex].state == true then ref_buttonData.checkbox[tableIndex].state = false self.editButton({index=buttonIndex, label=""}) else ref_buttonData.checkbox[tableIndex].state = true self.editButton({index=buttonIndex, label=string.char(10008)}) end updateSave() end --Applies value to given counter display function click_counter(tableIndex, buttonIndex, amount) ref_buttonData.counter[tableIndex].value = ref_buttonData.counter[tableIndex].value + amount self.editButton({index=buttonIndex, label=ref_buttonData.counter[tableIndex].value}) updateSave() end --Updates saved value for given text box function click_textbox(i, value, selected) if selected == false then ref_buttonData.textbox[i].value = value updateSave() end end --Dud function for if you have a background on a counter function click_none() end --Button creation --Makes checkboxes function createCheckbox() for i, data in ipairs(ref_buttonData.checkbox) do --Sets up reference function local buttonNumber = spawnedButtonCount local funcName = "checkbox"..i local func = function() click_checkbox(i, buttonNumber) end self.setVar(funcName, func) --Sets up label local label = "" if data.state==true then label=string.char(10008) end --Creates button and counts it self.createButton({ label=label, click_function=funcName, function_owner=self, position=data.pos, height=data.size, width=data.size, font_size=data.size, scale=buttonScale, color=buttonColor, font_color=buttonFontColor }) spawnedButtonCount = spawnedButtonCount + 1 end end --Makes counters function createCounter() for i, data in ipairs(ref_buttonData.counter) do --Sets up display local displayNumber = spawnedButtonCount --Sets up label local label = data.value --Sets height/width for display local size = data.size if data.hideBG == true then size = 0 end --Creates button and counts it self.createButton({ label=label, click_function="click_none", function_owner=self, position=data.pos, height=size, width=size, font_size=data.size, scale=buttonScale, color=buttonColor, font_color=buttonFontColor }) spawnedButtonCount = spawnedButtonCount + 1 --Sets up add 1 local funcName = "counterAdd"..i local func = function() click_counter(i, displayNumber, 1) end self.setVar(funcName, func) --Sets up label local label = "+" --Sets up position local offsetDistance = (data.size/2 + data.size/4) * (buttonScale[1] * 0.002) local pos = {data.pos[1] + offsetDistance, data.pos[2], data.pos[3]} --Sets up size local size = data.size / 2 --Creates button and counts it self.createButton({ label=label, click_function=funcName, function_owner=self, position=pos, height=size, width=size, font_size=size, scale=buttonScale, color=buttonColor, font_color=buttonFontColor }) spawnedButtonCount = spawnedButtonCount + 1 --Sets up subtract 1 local funcName = "counterSub"..i local func = function() click_counter(i, displayNumber, -1) end self.setVar(funcName, func) --Sets up label local label = "-" --Set up position local pos = {data.pos[1] - offsetDistance, data.pos[2], data.pos[3]} --Creates button and counts it self.createButton({ label=label, click_function=funcName, function_owner=self, position=pos, height=size, width=size, font_size=size, scale=buttonScale, color=buttonColor, font_color=buttonFontColor }) spawnedButtonCount = spawnedButtonCount + 1 end end function createTextbox() for i, data in ipairs(ref_buttonData.textbox) do --Sets up reference function local funcName = "textbox"..i local func = function(_,_,val,sel) click_textbox(i,val,sel) end self.setVar(funcName, func) self.createInput({ input_function = funcName, function_owner = self, label = data.label, alignment = data.alignment, position = data.pos, scale = buttonScale, width = data.width, height = (data.font_size*data.rows)+24, font_size = data.font_size, color = buttonColor, font_color = buttonFontColor, value = data.value, }) end end