· 8 years ago · Apr 04, 2018, 08:14 PM
1--Automated Star Wars Edge Of The Empire tabletop RPG character sheet
2--Made by Didero
3--Character sheet by LambMower
4--Heavily inspired by the scripted EotE sheet by Marlow: http://steamcommunity.com/sharedfiles/filedetails/?id=672608406
5--Dice images by Gordon: http://steamcommunity.com/sharedfiles/filedetails/?id=624350397
6--Version RC3
7
8--VARIABLE DECLARATION
9spawnedDice = {}
10areClearingDice = false --Used in the 'OnObjectDestroy' check, to prevent frequent dice display updates on dice clear
11--Character sheet stuff. All use the same index. So characterSheetsData[2] refers to the data of characterSheetList[2]
12characterSheets = {} --A list of references to the character sheet object list
13characterSheetsGUIDs = {} --A list with the GUIDs of the character sheet objects, so we can find them again
14characterSheetsData = {} --A table that will contain tables of character sheet values
15
16characterDescriptorNotepads = {} --A table that will store the notepads per character sheet, so we know if it exists
17
18--Dice description data
19dicenames = {"Ability", "Proficiency", "Boost", "Difficulty", "Challenge", "Setback"}
20-- the next dice tables are in the same order as the 'dicenames' table
21dicecounts = {0, 0, 0, 0, 0, 0}
22-- {{dicetype, imageUrl}}, where 'dicetype' is the internal type number. 0 is 4-sided, 1 is 6-sided, etc
23dicedata = {{2,"http://i.imgur.com/wmnD7f3.png"}, {4,"http://i.imgur.com/ZmKYETO.png"}, {1,"http://i.imgur.com/BATmCZ9.png"},
24 {2, "http://i.imgur.com/apULLij.png"}, {4, "http://i.imgur.com/fHWIxAY.png"}, {1, "http://i.imgur.com/rZXn6z5.png"}
25}
26-- Convert normal dice numbers to EotE values like 'success', 'fault', ...
27-- There's six values: success, advantage, triumph, failure, threat, despair
28-- failure cancels success, threat cancels advantage, triumph and despair can co-exist
29-- Since triumph and despair are only on one side of one dice each, no sense storing that for every side
30--'dicevalues' is {dicetype={successOnSide1,advantageOnSide1, successOnSide2,advantageOnSide2, ..}}
31-- failure is just negative success, threat is negative advantage
32-- triumphs and despairs are counted here as a success roll, and with a special check in the 'getDiceValues' function
33-- (dice values don't correspond to the values on page 12 of the rulebook since they're placed differently in the dice mod)
34dicevalues = {{0,0, 1,0, 0,1, 0,2, 1,1, 1,0, 0,1, 2,0},
35 {0,0, 0,2, 2,0, 1,0, 1,1, 1,0, 1,1, 0,1, 2,0, 1,0, 1,1, 0,2},
36 {0,0, 1,0, 1,1, 0,2, 0,1, 0,0},
37 {0,0, 0,-1, 0,-1, -2,0, -1,-1, 0,-1, -1,0, 0,-2},
38 {0,0, -2,0, -2,0, -1,0, -1,-1, -1,0, -1,0, 0,-1, 0,-2, -1,-1, 0,-1, 0,-2},
39 {0,0, 0,0, 0,-1, -1,0, 0,-1, -1,0}
40}
41
42--Descriptive variables, used to find the index of fields
43--Character description strings
44characterDescriptors = {"playername", "charactername", "species", "career", "specialization"}
45--Skill names
46characteristics = {"Brawn", "Agility", "Intellect", "Cunning", "Willpower", "Presence", "SaberSkill"}
47--First 22 skills (up to 'Vigilance') are general skills, then 5 combat skills (up to 'Ranged - Heavy'), the rest are knowledge skills
48skills = {"Astrogation", "Athletics", "Charm", "Coercion", "Computers", "Cool", "Coordination", "Deception", "Discipline", "Leadership", "Mechanics", "Medicine", "Negotiation", "Perception", "Piloting - Planetary", "Piloting - Space", "Resilience", "Skulduggery", "Stealth", "Streetwise", "Survival", "Vigilance", "Brawl", "Gunnery", "Melee", "Ranged - Light", "Ranged - Heavy", "Lightsaber", "Core Worlds", "Education", "Lore", "Outer Rim", "Underworld", "Xenology", "Other"}
49battleFields = {"Soak", "WoundsThreshold", "WoundsCurrent", "StrainThreshold", "StrainCurrent", "DefenseRanged", "DefenseMelee", "CritWound"}
50--What characteristic the skill depends on, as an index to the Characteristics table
51characteristicInfluencingSkills = {3, 1, 6, 5, 3, 6, 2, 4, 5, 6, 3, 3, 6, 4, 2, 2, 1, 4, 2, 4, 4, 5, 1, 2, 1, 2, 2, 7, 3, 3, 3, 3, 3, 3, 3}
52saberlables = {"Br", "Ag", "Int", "Cu", "Wil", "Pr"}
53
54--UTILITY FUNCTIONS
55function printError(msg)
56 printToAll("ERROR: " .. msg, {1, 0, 0})
57end
58
59--For some reason this isn't built into Lua?
60function findIndexOfValue(array, valueToFind)
61 --Loop over the array until we find the value we want or we run out of array
62 for index, value in ipairs(array) do
63 if value == valueToFind then
64 return index
65 end
66 end
67 return nil
68end
69
70function sanitizeStringForFunctionName(s)
71 --Remove spaces and dashes so the string will work as a function name
72 s = string.gsub(s, " ", "")
73 s = string.gsub(s, "-", "_")
74 return s
75end
76
77function calculateButtonWidth(label)
78 return string.len(label) * 35 + 30
79end
80
81function createButton(targetObject, onClickFunctionName, label, posX, posZ, fontSize, buttonHeight, buttonWidth)
82 if fontSize == nil then fontSize = 75 end
83 if buttonHeight == nil then buttonHeight = fontSize end
84 if buttonWidth == nil then
85 if buttonHeight == 0 then
86 buttonWidth = 0
87 else
88 buttonWidth = calculateButtonWidth(label)
89 end
90 end
91 targetObject.createButton({function_owner=self, click_function=onClickFunctionName, label=label, position={posX, 0.25, posZ}, height=buttonHeight, width=buttonWidth, font_size=fontSize, rotation={0, 180, 0}})
92end
93
94function getButtonIndex(buttonOwner, clickFunctionToFind)
95 for i, button in ipairs(buttonOwner.getButtons()) do
96 if button["click_function"] == clickFunctionToFind then
97 return button["index"]
98 end
99 end
100 return nil
101end
102
103function updateButtonText(buttonOwner, clickFunctionToFind, newLabelText, shouldAdjustButtonWidth)
104 local index = getButtonIndex(buttonOwner, clickFunctionToFind)
105 if index ~= nil then
106 local newButtonParams = {index=index, label=newLabelText}
107 if shouldAdjustButtonWidth == true then
108 newButtonParams["width"] = calculateButtonWidth(newLabelText)
109 end
110 buttonOwner.editButton(newButtonParams)
111 end
112end
113
114function updateDicecountDisplay(displayOwner, diceIndex)
115 updateButtonText(displayOwner, dicenames[diceIndex] .. "Count", tostring(dicecounts[diceIndex]))
116end
117function updateDicecountDisplays(diceIndex)
118 --Update the central dice display
119 updateDicecountDisplay(self, diceIndex)
120 --And the displays on all the character sheets
121 for i,charsheet in ipairs(characterSheets) do
122 updateDicecountDisplay(charsheet, diceIndex)
123 end
124end
125
126
127--SET UP CODE
128function onLoad(savestate)
129 if savestate ~= "" then
130 local savedata = JSON.decode(savestate)
131 if savedata["saveversion"] ~= 1 then
132 printError("Expected savedata version 1, but found " .. tostring(savedata["saveversion"]))
133 else
134 --For each stored GUID, check if the sheet still exists. If it does, store it
135 for i, guid in ipairs(savedata.characterSheetsGUIDs) do
136 local guidObject = getObjectFromGUID(guid)
137 if guidObject ~= nil then
138 table.insert(characterSheetsGUIDs, guid)
139 table.insert(characterSheets, guidObject)
140 table.insert(characterSheetsData, savedata.characterSheetsData[i])
141 end
142 end
143 end
144 end
145 rebuildAllSheetDisplays()
146 rebuildTrayDisplay()
147end
148
149function onSave()
150 local savedata = {saveversion=1, characterSheetsData=characterSheetsData, characterSheetsGUIDs=characterSheetsGUIDs}
151 return JSON.encode(savedata)
152end
153
154
155--CHARACTER SHEET FUNCTIONS
156function createCharacterSheet()
157 --First create the physical object
158 local ourPos = self.getPosition()
159 local ourRot = self.getRotation()
160 --Since not everything can be done with a newly spawned object, register a finishing function to be called when spawning and internal set-up is done
161 -- Pass along the index in the character sheet list this sheet will be saved in, so we know which sheet we're talking about
162 local charsheet = spawnObject({type="Custom_Model", position={ourPos.x, ourPos.y + 1, ourPos.z}, rotation={ourRot.x, ourRot.y, ourRot.z},
163 callback="finishCharacterSheetCreation", callback_owner=self, params={#characterSheets + 1},
164 })
165 charsheet.setCustomObject({mesh="http://pastebin.com/raw/zkq8DdFz", diffuse="https://i.imgur.com/yuSKhuE.png", material=3})
166 table.insert(characterSheets, charsheet)
167 --Set the stats to their defaults for now
168 local charsheetVars = {}
169 charsheetVars.characterDescriptorsValues = {}
170 for i = 1,#characterDescriptors do
171 charsheetVars.characterDescriptorsValues[i] = ""
172 end
173 charsheetVars.characteristicsValues = {}
174 for i = 1,#characteristics do
175 charsheetVars.characteristicsValues[i] = 2 --2 is defined as 'average'
176 end
177 charsheetVars.skillsValues = {}
178 for i = 1,#skills do
179 charsheetVars.skillsValues[i] = 0
180 end
181 charsheetVars.battleFieldsValues = {}
182 for i = 1,#battleFields do
183 charsheetVars.battleFieldsValues[i] = 0
184 end
185 --Career skills is a table with indices to the skill array, if the index is in here that skill is a career skill
186 charsheetVars.careerSkills = {}
187 --Store a reference to the character descriptors edit notecard here, so we can know if it's spawned and read it out
188 charsheetVars.characterDescriptorsNotecard = nil
189 --XP values
190 charsheetVars.totalXP = 0
191 charsheetVars.availableXP = 0
192 charsheetVars.ForceRank = 0
193 charsheetVars.ForceCommitted = 0
194 charsheetVars.ForceAvailable = 0
195 charsheetVars.EncumbranceThreshold = 0
196 charsheetVars.Encumbrance = 0
197 charsheetVars.Lightsaber =
198 --Possible display modes are 'edit' (all buttons), 'play' (just the most-used buttons), 'view' (no buttons, just labels)
199 charsheetVars.displaymode = "Edit"
200 table.insert(characterSheetsData, charsheetVars)
201end
202function finishCharacterSheetCreation(finishedCharacterSheet, characterSheetIndexTable)
203 --This gets called by the spawnObject callback parameter, so it gets passed a table argument. Index is table[1]
204 --Update the GUID list
205 updateCharacterSheetGUIDs()
206 --Create buttons on this new character sheet
207 rebuildSheetDisplay(characterSheetIndexTable[1])
208end
209
210function updateCharacterSheetGUIDs()
211 --Rebuild the list of character sheet GUIDs
212 -- Use a local variable first to prevent race conditions
213 local guidList = {}
214 for i = 1,#characterSheets do
215 table.insert(guidList, characterSheets[i].getGUID())
216 end
217 --Now overwrite the global list in a single step
218 characterSheetsGUIDs = guidList
219end
220
221function rebuildSheetDisplay(characterSheetIndex)
222 characterSheets[characterSheetIndex].clearButtons()
223 createDisplayLabels(characterSheetIndex)
224 createSkillsDisplay(characterSheetIndex)
225 if characterSheetsData[characterSheetIndex].displaymode ~= "View" then
226 createEditButtons(characterSheetIndex)
227 createDiceDisplay(characterSheets[characterSheetIndex])
228 end
229 createButton(characterSheets[characterSheetIndex], "toggleDisplayMode",
230 characterSheetsData[characterSheetIndex].displaymode .. " mode", 0, -6.55, 300, 300, 1500
231 )
232end
233function rebuildAllSheetDisplays()
234 for i = 1,#characterSheets do
235 rebuildSheetDisplay(i)
236 end
237end
238
239function rebuildTrayDisplay()
240 self.clearButtons()
241 --Create a button to create a new sheet
242 createButton(self, "createCharacterSheet", "New Sheet", 0, 3, 100, 100, 500)
243 --The tray also needs dice count labels and dice spawning buttons
244 createDiceDisplay(self, 1.8, -3)
245end
246
247function createDisplayLabels(characterSheetIndex)
248 --Create non-button (or more accurately fake-button) labels to display stats
249 local characterSheet = characterSheets[characterSheetIndex]
250 local charSheetValues = characterSheetsData[characterSheetIndex]
251 -- Character descriptors, like name and career
252 -- First the player name, since that's to the side
253 createButton(characterSheet, characterDescriptors[1], charSheetValues.characterDescriptorsValues[1], -3.35, 5.4, 125, 0, 0)
254 -- Then the other descriptors
255 local currentZ = 6.3
256 for i=2,#characterDescriptors do
257 createButton(characterSheet, characterDescriptors[i], charSheetValues.characterDescriptorsValues[i], 0, currentZ, 125, 0, 0)
258 currentZ = currentZ - 0.3
259 end
260 -- Battle stats (soak, wounds, etc)
261 -- Start with 'soak value', since that's the only one with a single value
262 createButton(characterSheet, battleFields[1], tostring(charSheetValues.battleFieldsValues[1]), 3.35, 4.45, 350, 0, 0)
263 createButton(characterSheet, battleFields[8], tostring(charSheetValues.battleFieldsValues[8]), -2.00, 5.28, 250, 0, 0)
264 -- Then iterate over the pairs of values
265 local currentX = 1.5
266 for i=2,7,2 do
267 createButton(characterSheet, battleFields[i], tostring(charSheetValues.battleFieldsValues[i]), currentX, 4.45, 350, 0, 0)
268 createButton(characterSheet, battleFields[i+1], tostring(charSheetValues.battleFieldsValues[i+1]), currentX - 0.8, 4.45, 350, 0, 0)
269 currentX = currentX - 2.3
270 end
271 -- Characteristics fields
272 currentX = 3.82
273 for i=1,6 do
274 createButton(characterSheet, characteristics[i], tostring(charSheetValues.characteristicsValues[i]), currentX, 3.05, 400, 0, 0)
275 currentX = currentX - 1.55
276 end
277 for i=1,#saberlables do
278 createButton(characterSheet, "SaberSkill", tostring(saberlables[i]), -1.35, 0.45, 75, 150, 75)
279 end
280 -- total and available XP
281 createButton(characterSheet, "totalXP", tostring(charSheetValues.totalXP), 3.7, -6.5, 275, 0, 0)
282 createButton(characterSheet, "availableXP", tostring(charSheetValues.availableXP), -3.75, -6.5, 275, 0, 0)
283 -- Force Rank related stat displays
284 createButton(characterSheet, "ForceRank", tostring(charSheetValues.ForceRank), -3.1925, -5.05, 275, 0, 0)
285 createButton(characterSheet, "ForceCommitted", tostring(charSheetValues.ForceCommitted), -0.9, -5.25, 275, 0, 0)
286 createButton(characterSheet, "ForceAvailable", tostring(charSheetValues.ForceAvailable), -1.7, -5.25, 275, 0, 0)
287 createButton(characterSheet, "EncumbranceThreshold", tostring(charSheetValues.EncumbranceThreshold), 3.4, -5.25, 275, 0, 0)
288 createButton(characterSheet, "Encumbrance", tostring(charSheetValues.Encumbrance), 2.75, -5.25, 275, 0, 0)
289end
290
291function changeSaberLabel(characterSheet, changeAmount)
292
293function createEditButtons(characterSheetIndex)
294 local charsheet = characterSheets[characterSheetIndex]
295 local charSheetValues = characterSheetsData[characterSheetIndex]
296 --Create all the edit buttons...
297 if charSheetValues.displaymode == "Edit" then
298 -- ...for editing character descriptors like name and species
299 local charDescriptorEditButtonText = "Edit"
300 if charSheetValues.characterDescriptorsNotecard ~= nil then charDescriptorEditButtonText = "Save" end
301 createButton(charsheet, "editCharacterDescriptors", charDescriptorEditButtonText, 5.1, 6, 225, 250, 550)
302 -- ...a button to claim this sheet
303 createButton(charsheet, "setOwnerToClickedPlayer", "Claim", -5.2, 5.4, 175, 200, 500)
304 end
305 -- ...for battle stats
306 createButton(charsheet, "decreaseSoak", "-", 4.2, 4.3, 125, 125, 125)
307 createButton(charsheet, "increaseSoak", "+", 2.55, 4.3, 125, 125, 125)
308 createButton(charsheet, "decreaseCritWound", "-", -2.4, 5.25, 75, 75, 75)
309 createButton(charsheet, "increaseCritWound", "+", -2.4, 5.45, 75, 75, 75)
310 local currentX = 1.95
311 local Xdecreases = {1.7, 0.57}
312 local currentXdecrease = Xdecreases[1]
313 for i=2,7 do
314 createButton(charsheet, "decrease" .. battleFields[i], "-", currentX, 4.3, 125, 100, 100)
315 createButton(charsheet, "increase" .. battleFields[i], "+", currentX, 5, 125, 100, 100)
316 currentX = currentX - currentXdecrease
317 --Switch between short and long horizontal jumps
318 if currentXdecrease == Xdecreases[1] then currentXdecrease = Xdecreases[2] else currentXdecrease = Xdecreases[1] end
319 end
320 -- ...for characteristics
321 if charSheetValues.displaymode == "Edit" then
322 local currentX = 4.3
323 for i = 1,6 do
324 --minus and plus buttons below the values
325 createButton(charsheet, "decrease".. characteristics[i], "-", currentX, 2.7, 100, 100, 100)
326 createButton(charsheet, "increase".. characteristics[i], "+", currentX - 0.92, 2.7, 100, 100, 100)
327 currentX = currentX - 1.55
328 end
329 createButton(charsheet, "decreaseForceRank", "-", -3.7, -5.3, 75, 75, 75)
330 createButton(charsheet, "increaseForceRank", "+", -3.7, -4.75, 75, 75, 75)
331 end
332 --Force Committed +/- buttons
333 createButton(charsheet, "decreaseForceCommitted", "-", -0.3, -5.3, 75, 75, 75)
334 createButton(charsheet, "increaseForceCommitted", "+", -0.3, -4.75, 75, 75, 75)
335 --Encumbrance buttons
336 createButton(charsheet, "decreaseEncumbranceThreshold", "-", 4.1, -5.3, 75, 75, 75)
337 createButton(charsheet, "increaseEncumbranceThreshold", "+", 4.1, -4.75, 75, 75, 75)
338 createButton(charsheet, "decreaseEncumbrance", "-", 2.05, -5.3, 75, 75, 75)
339 createButton(charsheet, "increaseEncumbrance", "+", 2.05, -4.75, 75, 75, 75)
340 --...for total XP
341 -- Each gets a 1, 5, 10, 50, 100 button, both plus and minus
342 -- Minus on the left, plus on the right, stacked
343 createButton(charsheet, "decreaseTotalXPBy5", "-5", 5, -6.3, 75, 75, 200)
344 createButton(charsheet, "decreaseTotalXPBy50", "-50", 5, -6.6, 75, 75, 200)
345 createButton(charsheet, "decreaseTotalXPBy500", "-500", 5, -6.9, 75, 75, 200)
346 createButton(charsheet, "decreaseTotalXPBy1", "-1", 4.65, -6.3, 75, 75, 200)
347 createButton(charsheet, "decreaseTotalXPBy10", "-10", 4.65, -6.6, 75, 75, 200)
348 createButton(charsheet, "decreaseTotalXPBy100", "-100", 4.65, -6.9, 75, 75, 200)
349 createButton(charsheet, "increaseTotalXPBy1", "+1", 2.75, -6.3, 75, 75, 200)
350 createButton(charsheet, "increaseTotalXPBy10", "+10", 2.75, -6.6, 75, 75, 200)
351 createButton(charsheet, "increaseTotalXPBy100", "+100", 2.75, -6.9, 75, 75, 200)
352 createButton(charsheet, "increaseTotalXPBy5", "+5", 2.4, -6.3, 75, 75, 200)
353 createButton(charsheet, "increaseTotalXPBy50", "+50", 2.4, -6.6, 75, 75, 200)
354 createButton(charsheet, "increaseTotalXPBy500", "+500", 2.4, -6.9, 75, 75, 200)
355 --...for available XP
356 createButton(charsheet, "decreaseAvailableXPBy1", "-1", -2.8, -6.3, 75, 75, 200)
357 createButton(charsheet, "decreaseAvailableXPBy10", "-10", -2.8, -6.6, 75, 75, 200)
358 createButton(charsheet, "decreaseAvailableXPBy100", "-100", -2.8, -6.9, 75, 75, 200)
359 createButton(charsheet, "decreaseAvailableXPBy5", "-5", -2.45, -6.3, 75, 75, 200)
360 createButton(charsheet, "decreaseAvailableXPBy50", "-50", -2.45, -6.6, 75, 75, 200)
361 createButton(charsheet, "decreaseAvailableXPBy500", "-500", -2.45, -6.9, 75, 75, 200)
362 createButton(charsheet, "increaseAvailableXPBy1", "+1", -4.7, -6.3, 75, 75, 200)
363 createButton(charsheet, "increaseAvailableXPBy10", "+10", -4.7, -6.6, 75, 75, 200)
364 createButton(charsheet, "increaseAvailableXPBy100", "+100", -4.7, -6.9, 75, 75, 200)
365 createButton(charsheet, "increaseAvailableXPBy5", "+5", -5.05, -6.3, 75, 75, 200)
366 createButton(charsheet, "increaseAvailableXPBy50", "+50", -5.05, -6.6, 75, 75, 200)
367 createButton(charsheet, "increaseAvailableXPBy500", "+500", -5.05, -6.9, 75, 75, 200)
368end
369
370--Separate function for the skill labels and buttons because sometimes the layout differs a bit between view modes
371-- and this seemed neater than looping through a few times depending on view mode
372function createSkillsDisplay(characterSheetIndex)
373 local charsheet = characterSheets[characterSheetIndex]
374 local charSheetValues = characterSheetsData[characterSheetIndex]
375 --Some buttons should only be pressable in edit mode, otherwise they should be size 0, so invisible, leaving only the text
376 local skillChangeButtonSize = {0, 0}
377 if charSheetValues.displaymode == "Edit" then skillChangeButtonSize = {75, 100} end
378 local diceSpawnButtonSize = 75
379 if charSheetValues.displaymode == "View" then diceSpawnButtonSize = 0 end
380
381 local startZ = 1.72
382 local currentZ = startZ
383 local stepZ = 0.252
384 local currentX = 2.9
385 for i = 1,#skills do
386 local skillName = sanitizeStringForFunctionName(skills[i])
387 --Create a 'career' toggle, to make this a career skill
388 local careerSkillButtonText = "N"
389 if findIndexOfValue(charSheetValues.careerSkills, i) ~= nil then
390 careerSkillButtonText = "Y"
391 end
392 createButton(charsheet, "toggle"..skillName.."AsCareerSkill", careerSkillButtonText, currentX, currentZ, 75, skillChangeButtonSize[1], skillChangeButtonSize[2])
393 --Create a 'spawn dicepool' button
394 createButton(charsheet, "spawnDicepoolFor"..skillName, getDicepoolDisplayString(determineDicepoolForSkill(characterSheetIndex, i)), currentX - 0.75, currentZ, 75, diceSpawnButtonSize)
395 --Skill rank display
396 createButton(charsheet, skillName, tostring(charSheetValues.skillsValues[i]), currentX - 2, currentZ, 75, 0, 0)
397
398 --Add buttons to in- and decrease rank, if needed
399 if charSheetValues.displaymode == "Edit" then
400 createButton(charsheet, "decreaseRankIn"..skillName, "-", currentX - 1.7, currentZ, 75, 75, 75)
401 createButton(charsheet, "increaseRankIn"..skillName, "+", currentX - 2.3, currentZ, 75, 75, 75)
402 end
403
404 currentZ = currentZ - stepZ
405 --Skill 22 (Vigilance) is the last General Skill, and also the last skill on the left column
406 -- So set the x and y to the right column values
407 if i == 22 then
408 currentX = -1.85
409 currentZ = startZ
410 --There's a gap of two rows between the combat skills and the knowledge skills
411 elseif i == 28 then
412 currentZ = currentZ - 1 * stepZ
413 end
414 end
415end
416
417function createDiceDisplay(targetObject, startX, baseZ)
418 --Set the defaults for the character sheets, since that's the main way this function will be used
419 if startX == nil then startX = -0.6 end
420 if baseZ == nil then baseZ = -2.3 end
421 --Create a table. First row is dice name and count, second row is 'Add' button, third row is 'Remove' button
422 local currentX = startX
423 for i,dicename in ipairs(dicenames) do
424 --Dice name
425 createButton(targetObject, dicename, dicename, currentX, baseZ, 75, 0, 0)
426 --Dice count
427 createButton(targetObject, dicename .. "Count", tostring(dicecounts[i]), currentX, baseZ - 0.15, 75, 0, 0)
428 --'Add' and 'Remove' button
429 createButton(targetObject, "spawn" .. dicename .. "Dice", "Add", currentX, baseZ - 0.35, 75, 75, 185)
430 createButton(targetObject, "despawn" .. dicename .. "Dice", "Remove", currentX, baseZ - 0.6, 75, 74, 325)
431
432 --Move over to the next column
433 currentX = currentX - 0.7
434 end
435 --Buttons for dice use
436 createButton(targetObject, "rollDice", "Roll", startX - 1.2, baseZ - 0.9, 100, 100, 300)
437 createButton(targetObject, "startDiceReading", "Read", startX - 1.9, baseZ - 0.9, 100, 100, 300)
438 createButton(targetObject, "clearDice", "Clear", startX - 2.6, baseZ - 0.9, 100, 100, 300)
439 --Display the outcome of the last roll
440 createButton(targetObject, "dicerollOutcomeDisplay", "", startX - 1.9, baseZ - 1.15, 125, 0, 0)
441end
442
443--Handle character sheet and dice deletion by removing all references and stored data
444function onObjectDestroy(destroyedObject)
445 local index = findIndexOfValue(characterSheets, destroyedObject)
446 if index ~= nil then
447 --The destroyed object is a character sheet. Remove everything we've got stored on it
448 table.remove(characterSheets, index)
449 table.remove(characterSheetsData, index)
450 table.remove(characterSheetsGUIDs, index)
451 --Only check if it's a dice when we aren't mass-deleting them
452 elseif areClearingDice == false then
453 index = findIndexOfValue(spawnedDice, destroyedObject)
454 if index ~= nil then
455 --Dice got destroyed, remove reference to it
456 table.remove(spawnedDice, index)
457 --and update the dicecount
458 local diceIndex = findIndexOfValue(dicenames, destroyedObject.getName())
459 dicecounts[diceIndex] = dicecounts[diceIndex] - 1
460 updateDicecountDisplays(diceIndex)
461 end
462 end
463end
464
465
466--DICE-RELATED FUNCTIONS
467function determineDicepoolForSkill(characterSheetIndex, skillIndex)
468 local dicepool = {}
469 local skillValue = characterSheetsData[characterSheetIndex].skillsValues[skillIndex]
470 local characteristicValue = characterSheetsData[characterSheetIndex].characteristicsValues[characteristicInfluencingSkills[skillIndex]]
471 local dicecount = math.max(skillValue, characteristicValue)
472 dicepool["Proficiency"] = math.min(skillValue, characteristicValue)
473 dicepool["Ability"] = dicecount - dicepool["Proficiency"]
474 return dicepool
475end
476
477function getDicepoolDisplayString(dicepool)
478 --Build up the display string
479 local displaystring = ""
480 if dicepool["Proficiency"] > 0 then
481 displaystring = tostring(dicepool["Proficiency"]) .. " prof"
482 end
483 if dicepool["Proficiency"] > 0 and dicepool["Ability"] > 0 then
484 displaystring = displaystring .. ", "
485 end
486 if dicepool["Ability"] > 0 then
487 displaystring = displaystring .. tostring(dicepool["Ability"]) .. " ab"
488 end
489 return displaystring
490end
491
492function updateDicepoolDisplayForSkill(characterSheetIndex, skillIndex)
493 --Set the button text to the dicepool description
494 local labelText = getDicepoolDisplayString(determineDicepoolForSkill(characterSheetIndex, skillIndex))
495 updateButtonText(characterSheets[characterSheetIndex], "spawnDicepoolFor" .. sanitizeStringForFunctionName(skills[skillIndex]), labelText, true)
496end
497
498function recalculateDicepoolPerSkill(characterSheetIndex, characteristicIndex)
499 --Go through all the skills that are influenced by the provided characteristic and recalculate their dicepools
500 for skillIndex = 1,#characteristicInfluencingSkills do
501 if characteristicIndex == nil or characteristicInfluencingSkills[skillIndex] == characteristicIndex then
502 updateDicepoolDisplayForSkill(characterSheetIndex, skillIndex)
503 end
504 end
505end
506
507function updateDicerollOutcomeDisplays(outcomeString)
508 updateButtonText(self, "dicerollOutcomeDisplay", outcomeString)
509 for i,charsheet in ipairs(characterSheets) do
510 updateButtonText(charsheet, "dicerollOutcomeDisplay", outcomeString)
511 end
512end
513
514function spawnDicepool(characterSheet, skillIndex)
515 local characterSheetIndex = findIndexOfValue(characterSheets, characterSheet)
516 local dicepool = determineDicepoolForSkill(characterSheetIndex, skillIndex)
517 for dicename, dicecount in pairs(dicepool) do
518 --Check if we even have to spawn dice
519 if dicecount > 0 then
520 local diceIndex = findIndexOfValue(dicenames, dicename)
521 for i = 1,dicecount do
522 spawnDice(diceIndex, false, i * 2)
523 end
524 --And update the dice count displays
525 updateDicecountDisplays(diceIndex)
526 end
527 end
528end
529
530function spawnDice(diceIndex, shouldUpdateDiceDisplays, diceHeight)
531 --The collider of the tray doesn't work if the tray isn't locked, since it's convex. So make sure it's locked
532 self.setLock(true)
533 --If we haven't been specifically told not to update, update
534 if shouldUpdateDiceDisplays == nil then shouldUpdateDiceDisplays = true end
535 local pos = self.getPosition()
536 --Randomise dice position to prevent phasing through each other on spawn
537 -- Stay within -1.75 to +1.75, both on the x and z axes
538 local spawnPosition = {pos.x - 1.75 + math.random() * 3.5, pos.y + 2, pos.z - 1.75 + math.random() * 3.5}
539 if diceHeight ~= nil then
540 spawnPosition[2] = diceHeight
541 end
542 local dice = spawnObject({type="Custom_Dice", position=spawnPosition})
543 --'dicedata' is a list of two-sized tables, [1] is the dice type (0 for 4-sided, 1 for 6-sided, etc), [2] is image url
544 dice.setCustomObject({type=dicedata[diceIndex][1], image=dicedata[diceIndex][2]})
545 dice.setName(dicenames[diceIndex]) --Make it easier to determine the type of dice when reading
546 dice.tooltip = false --Hide the mouse-over text you normally see when hovering over a dice
547 --Store the dice for later checks and despawning
548 table.insert(spawnedDice, dice)
549 --Update the stored dice cound
550 dicecounts[diceIndex] = dicecounts[diceIndex] + 1
551 if shouldUpdateDiceDisplays then
552 updateDicecountDisplays(diceIndex)
553 end
554end
555function despawnDice(diceIndex)
556 for i,dice in ipairs(spawnedDice) do
557 if dice.getName() == dicenames[diceIndex] then
558 dice.destruct()
559 break
560 end
561 end
562end
563
564
565function rollDice()
566 --The tray collider acts as a box collider when unlocked, which could lead to weird roles. Make sure that doesn't happen
567 self.setLock(true)
568 for i,dice in ipairs(spawnedDice) do
569 dice.randomize()
570 end
571 startDiceReading()
572end
573
574function startDiceReading()
575 --Clear the previous diceroll outcome displays
576 updateDicerollOutcomeDisplays("")
577 --Start the dice reading function
578 local cr = coroutine.create(waitForDiceToStopRolling)
579 coroutine.resume(cr)
580end
581function waitForDiceToStopRolling(numberOfChecksLeft)
582 if numberOfChecksLeft == nil then numberOfChecksLeft = {10} end --as a table since that's what the timer passes
583 for i, dice in ipairs(spawnedDice) do
584 if dice.resting == false then
585 if numberOfChecksLeft[1] > 0 then
586 numberOfChecksLeft[1] = numberOfChecksLeft[1] - 1
587 -- Make sure the existing Timer is fully destroyed
588 Timer.destroy(self.getGUID())
589 -- Then make a new timer to try again
590 Timer.create({delay=1.0, identifier=self.getGUID(), function_name="waitForDiceToStopRolling", parameters=numberOfChecksLeft})
591 return
592 else
593 --Waited for dice to stop rolling for too long, let's just stop trying
594 break
595 end
596 end
597 end
598 if numberOfChecksLeft[1] == 0 then printToAll("WARNING: Waiting for dice roll to finish took too long, results may be inaccurate", {1,0,0}) end
599 showDiceValues()
600end
601
602function showDiceValues()
603 local successCount = 0
604 local advantageCount = 0
605 local triumphCount = 0
606 local despairCount = 0
607 for i, dice in ipairs(spawnedDice) do
608 local dicename = dice.getName()
609 local diceIndex = findIndexOfValue(dicenames, dicename)
610 --the value table stores two values per side
611 -- So 'dicevalues[valueIndex-1]' is the number of successes, 'dicevalues[valueIndex]' number of advantages
612 -- (side 1 is index 1 and 2, side 2 is 3 and 4, etc)
613 local valueIndex = dice.getValue() * 2
614 successCount = successCount + dicevalues[diceIndex][valueIndex-1]
615 advantageCount = advantageCount + dicevalues[diceIndex][valueIndex]
616 --Triumph and despair results are special cases, they're on the proficience and challenge dice respectively, and only on a 12-roll (here on side 4)
617 if dice.getValue() == 4 then
618 if dicename == "Proficiency" then
619 triumphCount = triumphCount + 1
620 elseif dicename == "Challenge" then
621 despairCount = despairCount + 1
622 end
623 end
624 end
625 --Now print the result
626 local successDescriptionString = "successes"
627 if successCount < 0 then
628 successCount = successCount * -1
629 successDescriptionString = "failures"
630 end
631 local advantageDescriptionString = "advantages"
632 if advantageCount < 0 then
633 advantageCount = advantageCount * -1
634 advantageDescriptionString = "threats"
635 end
636 local resultString = string.format("%d %s, %d %s", successCount, successDescriptionString, advantageCount, advantageDescriptionString)
637 if triumphCount > 0 then resultString = string.format("%s, %d triumphs", resultString, triumphCount) end
638 if despairCount > 0 then resultString = string.format("%s, %d despairs", resultString, despairCount) end
639 printToAll(resultString, {1,1,1})
640 --Update all the outcome displays
641 updateDicerollOutcomeDisplays(resultString)
642end
643
644function clearDice()
645 --Reset the dicecounts
646 for i = 1,#dicecounts do
647 dicecounts[i] = 0
648 updateDicecountDisplays(i)
649 end
650 --Clear the diceroll outcome displays
651 updateDicerollOutcomeDisplays("")
652 --And now actually destroy the dice
653 areClearingDice = true --Prevent frequent display updates
654 for i,dice in ipairs(spawnedDice) do
655 dice.destruct()
656 end
657 --Clear the array
658 spawnedDice = {}
659 --Done!
660 areClearingDice = false
661end
662
663
664--VALUE CHANGING FUNCTIONS
665function editCharacterDescriptors(characterSheet)
666 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
667 local charSheetValues = characterSheetsData[charSheetIndex]
668 if characterDescriptorNotepads[characterSheet] == nil then
669 --First lock the sheet, to make notepad selection easier and to make sure it stays positioned right
670 characterSheet.setLock(true)
671 --Create a notecard for users to fill in their descriptors
672 local sheetPosition = characterSheet.getPosition()
673 local sheetRotation = characterSheet.getRotation()
674 --Calculate the relative position for the notecard, taking the charsheet's rotation into account
675 local targetAngle = sheetRotation.y + 82
676 local xDistance = math.cos(math.rad(targetAngle)) * 7.27
677 local zDistance = math.sin(math.rad(targetAngle)) * 7.27
678
679 local notecardPos = {sheetPosition.x - xDistance, sheetPosition.y + 0.4, sheetPosition.z + zDistance}
680 local notecardRot = {sheetRotation.x, sheetRotation.y, sheetRotation.z}
681 characterDescriptorNotepads[characterSheet] = spawnObject({type="Notecard", position=notecardPos, rotation=notecardRot})
682 characterDescriptorNotepads[characterSheet].setLock(true)
683 characterDescriptorNotepads[characterSheet].setName("Character Descriptors")
684 local notecardText = "Right-click to edit description, fill in your info after the colons, then press 'Save'"
685 for i=2,#characterDescriptors do
686 notecardText = notecardText .. "\n[b]" .. characterDescriptors[i] .. "[/b]: " .. charSheetValues.characterDescriptorsValues[i]
687 end
688 characterDescriptorNotepads[characterSheet].setDescription(notecardText)
689 --Update the button text to say 'Save'
690 updateButtonText(characterSheet, "editCharacterDescriptors", "Save")
691 else
692 --A notecard already exists, and we need to save the data on it
693 --Clear the global reference first, so any errors don't brick this function
694 local notecard = characterDescriptorNotepads[characterSheet]
695 characterDescriptorNotepads[characterSheet] = nil
696 -- Change the button text back to 'Edit'
697 updateButtonText(characterSheet, "editCharacterDescriptors", "Edit")
698
699 --Notecard exists, read it out (Lines are '[b]descriptorName[/b]: value')
700 for descriptor, value in string.gmatch(notecard.getDescription(), "%[b%](.-)%[/b%]: ([%w%p ]+)") do
701 if descriptor ~= nil and value ~= nil then
702 value = string.gsub(value, "\n", "; ")
703 local descriptorIndex = findIndexOfValue(characterDescriptors, descriptor)
704 if descriptorIndex == nil then
705 printError("Unknown character descriptor '" .. descriptor .. "'")
706 else
707 charSheetValues.characterDescriptorsValues[descriptorIndex] = value
708 updateButtonText(characterSheet, characterDescriptors[descriptorIndex], value)
709 end
710 end
711 end
712 --We no longer need the card, destroy it
713 notecard.destruct()
714 end
715end
716
717function setOwnerToClickedPlayer(characterSheet, clickingPlayerColor)
718 local characterSheetIndex = findIndexOfValue(characterSheets, characterSheet)
719 --player name is the first entry in 'characterDescriptors
720 characterSheetsData[characterSheetIndex].characterDescriptorsValues[1] = Player[clickingPlayerColor].steam_name
721 --Update the displayed name
722 updateButtonText(characterSheet, "playername", characterSheetsData[characterSheetIndex].characterDescriptorsValues[1])
723end
724
725function changeBattleFieldValue(characterSheet, battleFieldIndex, changeAmount)
726 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
727 local charSheetValues = characterSheetsData[charSheetIndex]
728 local newValue = charSheetValues.battleFieldsValues[battleFieldIndex] + changeAmount
729 if newValue >= 0 then
730 charSheetValues.battleFieldsValues[battleFieldIndex] = newValue
731 --Update display
732 updateButtonText(characterSheet, battleFields[battleFieldIndex], tostring(newValue))
733 end
734end
735
736function changeCharacteristicValue(characterSheet, characteristicIndex, changeAmount)
737 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
738 local charSheetValues = characterSheetsData[charSheetIndex]
739 local newValue = charSheetValues.characteristicsValues[characteristicIndex] + changeAmount
740 --Characteristics can't be zero or negative
741 if newValue > 0 then
742 charSheetValues.characteristicsValues[characteristicIndex] = newValue
743 --Update the value display
744 updateButtonText(characterSheet, characteristics[characteristicIndex], tostring(newValue))
745 --Recalculate the dicepools for all the skills that depend on the characteristic we just changed
746 recalculateDicepoolPerSkill(charSheetIndex, characteristicIndex)
747 end
748end
749
750function toggleCareerSkill(characterSheet, skillIndex)
751 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
752 local charSheetValues = characterSheetsData[charSheetIndex]
753 local careerButtonLabel = ""
754 local indexInCareerSkills = findIndexOfValue(charSheetValues.careerSkills, skillIndex)
755 if indexInCareerSkills ~= nil then
756 --It exists, so remove it
757 table.remove(charSheetValues.careerSkills, indexInCareerSkills)
758 careerButtonLabel = "N"
759 else
760 --It's not there, add it
761 table.insert(charSheetValues.careerSkills, skillIndex)
762 careerButtonLabel = "Y"
763 end
764 --Now update the skill's career button
765 updateButtonText(characterSheet, "toggle" .. sanitizeStringForFunctionName(skills[skillIndex]) .. "AsCareerSkill", careerButtonLabel)
766end
767
768function changeSkillRank(characterSheet, skillIndex, changeAmount)
769 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
770 local charSheetValues = characterSheetsData[charSheetIndex]
771 local newValue = charSheetValues.skillsValues[skillIndex] + changeAmount
772 --Cap skill ranks at a minimum of 0 and a max of 5
773 newValue = math.max(newValue, 0)
774 newValue = math.min(newValue, 5)
775 --Only act if the resulting skill value actually changed
776 if newValue ~= charSheetValues.skillsValues[skillIndex] then
777 charSheetValues.skillsValues[skillIndex] = newValue
778 --Update the rank display
779 updateButtonText(characterSheet, sanitizeStringForFunctionName(skills[skillIndex]), tostring(newValue))
780 --Recalculate dicepool for this skill
781 updateDicepoolDisplayForSkill(charSheetIndex, skillIndex)
782 end
783end
784
785function changeTotalXP(characterSheet, changeAmount)
786 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
787 local charSheetValues = characterSheetsData[charSheetIndex]
788 charSheetValues.totalXP = charSheetValues.totalXP + changeAmount
789 if charSheetValues.totalXP < 0 then charSheetValues.totalXP = 0 end
790 --Update the total XP display
791 updateButtonText(characterSheet, "totalXP", tostring(charSheetValues.totalXP))
792end
793function changeAvailableXP(characterSheet, changeAmount)
794 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
795 local charSheetValues = characterSheetsData[charSheetIndex]
796 charSheetValues.availableXP = charSheetValues.availableXP + changeAmount
797 if charSheetValues.availableXP < 0 then charSheetValues.availableXP = 0 end
798 --Update the available XP display
799 updateButtonText(characterSheet, "availableXP", tostring(charSheetValues.availableXP))
800end
801function changeForceRank(characterSheet, changeAmount)
802 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
803 local charSheetValues = characterSheetsData[charSheetIndex]
804 charSheetValues.ForceRank = charSheetValues.ForceRank + changeAmount
805 if charSheetValues.ForceRank < 0 then charSheetValues.ForceRank = 0 end
806 --Update the Force Rank display
807 updateButtonText(characterSheet, "ForceRank", tostring(charSheetValues.ForceRank))
808 changeForceAvailable(characterSheet, changeAmount)
809end
810function changeForceCommitted(characterSheet, changeAmount)
811 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
812 local charSheetValues = characterSheetsData[charSheetIndex]
813 charSheetValues.ForceCommitted = charSheetValues.ForceCommitted + changeAmount
814 if charSheetValues.ForceCommitted < 0 then charSheetValues.ForceCommitted = 0
815 elseif charSheetValues.ForceCommitted > charSheetValues.ForceRank then charSheetValues.ForceCommitted = charSheetValues.ForceRank end
816 --Update the Force Committed display
817 updateButtonText(characterSheet, "ForceCommitted", tostring(charSheetValues.ForceCommitted))
818 changeForceAvailable(characterSheet, changeAmount)
819end
820function changeForceAvailable(characterSheet, changeAmount)
821 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
822 local charSheetValues = characterSheetsData[charSheetIndex]
823 charSheetValues.ForceAvailable = charSheetValues.ForceRank - charSheetValues.ForceCommitted
824 --Update the Force Available display
825 updateButtonText(characterSheet, "ForceAvailable", tostring(charSheetValues.ForceAvailable))
826end
827function changeEncumbranceThreshold(characterSheet, changeAmount)
828 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
829 local charSheetValues = characterSheetsData[charSheetIndex]
830 charSheetValues.EncumbranceThreshold = charSheetValues.EncumbranceThreshold + changeAmount
831 if charSheetValues.EncumbranceThreshold < 0 then charSheetValues.EncumbranceThreshold = 0 end
832 --Update the Force Rank display
833 updateButtonText(characterSheet, "EncumbranceThreshold", tostring(charSheetValues.EncumbranceThreshold))
834end
835function changeEncumbrance(characterSheet, changeAmount)
836 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
837 local charSheetValues = characterSheetsData[charSheetIndex]
838 charSheetValues.Encumbrance = charSheetValues.Encumbrance + changeAmount
839 if charSheetValues.Encumbrance < 0 then charSheetValues.Encumbrance = 0 end
840 --Update the Force Rank display
841 updateButtonText(characterSheet, "Encumbrance", tostring(charSheetValues.Encumbrance))
842end
843
844function toggleDisplayMode(characterSheet)
845 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
846 local charSheetValues = characterSheetsData[charSheetIndex]
847 if charSheetValues.displaymode == "Edit" then
848 charSheetValues.displaymode = "Play"
849 elseif charSheetValues.displaymode == "Play" then
850 charSheetValues.displaymode = "View"
851 else
852 charSheetValues.displaymode = "Edit"
853 end
854 rebuildSheetDisplay(charSheetIndex)
855end
856
857
858--BUTTON FUNCTIONS
859--Force Rank values
860function decreaseForceRank(clickedCharSheet)
861 changeForceRank(clickedCharSheet, -1)
862end
863function increaseForceRank(clickedCharSheet)
864 changeForceRank(clickedCharSheet, 1)
865end
866--Force Committed Values
867function decreaseForceCommitted(clickedCharSheet)
868 changeForceCommitted(clickedCharSheet, -1)
869end
870function increaseForceCommitted(clickedCharSheet)
871 changeForceCommitted(clickedCharSheet, 1)
872end
873--Encumbrance values
874function decreaseEncumbranceThreshold(clickedCharSheet)
875 changeEncumbranceThreshold(clickedCharSheet, -1)
876end
877function increaseEncumbranceThreshold(clickedCharSheet)
878 changeEncumbranceThreshold(clickedCharSheet, 1)
879end
880function decreaseEncumbrance(clickedCharSheet)
881 changeEncumbrance(clickedCharSheet, -1)
882end
883function increaseEncumbrance(clickedCharSheet)
884 changeEncumbrance(clickedCharSheet, 1)
885end
886--Battle Fields values
887function decreaseSoak(clickedCharSheet)
888 changeBattleFieldValue(clickedCharSheet, 1, -1)
889end
890function increaseSoak(clickedCharSheet)
891 changeBattleFieldValue(clickedCharSheet, 1, 1)
892end
893function decreaseWoundsThreshold(clickedCharSheet)
894 changeBattleFieldValue(clickedCharSheet, 2, -1)
895end
896function increaseWoundsThreshold(clickedCharSheet)
897 changeBattleFieldValue(clickedCharSheet, 2, 1)
898end
899function decreaseWoundsCurrent(clickedCharSheet)
900 changeBattleFieldValue(clickedCharSheet, 3, -1)
901end
902function increaseWoundsCurrent(clickedCharSheet)
903 changeBattleFieldValue(clickedCharSheet, 3, 1)
904end
905function decreaseStrainThreshold(clickedCharSheet)
906 changeBattleFieldValue(clickedCharSheet, 4, -1)
907end
908function increaseStrainThreshold(clickedCharSheet)
909 changeBattleFieldValue(clickedCharSheet, 4, 1)
910end
911function decreaseStrainCurrent(clickedCharSheet)
912 changeBattleFieldValue(clickedCharSheet, 5, -1)
913end
914function increaseStrainCurrent(clickedCharSheet)
915 changeBattleFieldValue(clickedCharSheet, 5, 1)
916end
917function decreaseDefenseRanged(clickedCharSheet)
918 changeBattleFieldValue(clickedCharSheet, 6, -1)
919end
920function increaseDefenseRanged(clickedCharSheet)
921 changeBattleFieldValue(clickedCharSheet, 6, 1)
922end
923function decreaseDefenseMelee(clickedCharSheet)
924 changeBattleFieldValue(clickedCharSheet, 7, -1)
925end
926function increaseDefenseMelee(clickedCharSheet)
927 changeBattleFieldValue(clickedCharSheet, 7, 1)
928end
929function decreaseCritWound(clickedCharSheet)
930 changeBattleFieldValue(clickedCharSheet, 8, -1)
931end
932function increaseCritWound(clickedCharSheet)
933 changeBattleFieldValue(clickedCharSheet, 8, 1)
934end
935
936--Characteristics buttons
937function decreaseBrawn(clickedCharSheet)
938 changeCharacteristicValue(clickedCharSheet, 1, -1)
939end
940function increaseBrawn(clickedCharSheet)
941 changeCharacteristicValue(clickedCharSheet, 1, 1)
942end
943function decreaseAgility(clickedCharSheet)
944 changeCharacteristicValue(clickedCharSheet, 2, -1)
945end
946function increaseAgility(clickedCharSheet)
947 changeCharacteristicValue(clickedCharSheet, 2, 1)
948end
949function decreaseIntellect(clickedCharSheet)
950 changeCharacteristicValue(clickedCharSheet, 3, -1)
951end
952function increaseIntellect(clickedCharSheet)
953 changeCharacteristicValue(clickedCharSheet, 3, 1)
954end
955function decreaseCunning(clickedCharSheet)
956 changeCharacteristicValue(clickedCharSheet, 4, -1)
957end
958function increaseCunning(clickedCharSheet)
959 changeCharacteristicValue(clickedCharSheet, 4, 1)
960end
961function decreaseWillpower(clickedCharSheet)
962 changeCharacteristicValue(clickedCharSheet, 5, -1)
963end
964function increaseWillpower(clickedCharSheet)
965 changeCharacteristicValue(clickedCharSheet, 5, 1)
966end
967function decreasePresence(clickedCharSheet)
968 changeCharacteristicValue(clickedCharSheet, 6, -1)
969end
970function increasePresence(clickedCharSheet)
971 changeCharacteristicValue(clickedCharSheet, 6, 1)
972end
973
974--Career skill toggle buttons
975function toggleAstrogationAsCareerSkill(clickedCharSheet)
976 toggleCareerSkill(clickedCharSheet, 1)
977end
978function toggleAthleticsAsCareerSkill(clickedCharSheet)
979 toggleCareerSkill(clickedCharSheet, 2)
980end
981function toggleCharmAsCareerSkill(clickedCharSheet)
982 toggleCareerSkill(clickedCharSheet, 3)
983end
984function toggleCoercionAsCareerSkill(clickedCharSheet)
985 toggleCareerSkill(clickedCharSheet, 4)
986end
987function toggleComputersAsCareerSkill(clickedCharSheet)
988 toggleCareerSkill(clickedCharSheet, 5)
989end
990function toggleCoolAsCareerSkill(clickedCharSheet)
991 toggleCareerSkill(clickedCharSheet, 6)
992end
993function toggleCoordinationAsCareerSkill(clickedCharSheet)
994 toggleCareerSkill(clickedCharSheet, 7)
995end
996function toggleDeceptionAsCareerSkill(clickedCharSheet)
997 toggleCareerSkill(clickedCharSheet, 8)
998end
999function toggleDisciplineAsCareerSkill(clickedCharSheet)
1000 toggleCareerSkill(clickedCharSheet, 9)
1001end
1002function toggleLeadershipAsCareerSkill(clickedCharSheet)
1003 toggleCareerSkill(clickedCharSheet, 10)
1004end
1005function toggleMechanicsAsCareerSkill(clickedCharSheet)
1006 toggleCareerSkill(clickedCharSheet, 11)
1007end
1008function toggleMedicineAsCareerSkill(clickedCharSheet)
1009 toggleCareerSkill(clickedCharSheet, 12)
1010end
1011function toggleNegotiationAsCareerSkill(clickedCharSheet)
1012 toggleCareerSkill(clickedCharSheet, 13)
1013end
1014function togglePerceptionAsCareerSkill(clickedCharSheet)
1015 toggleCareerSkill(clickedCharSheet, 14)
1016end
1017function togglePiloting_PlanetaryAsCareerSkill(clickedCharSheet)
1018 toggleCareerSkill(clickedCharSheet, 15)
1019end
1020function togglePiloting_SpaceAsCareerSkill(clickedCharSheet)
1021 toggleCareerSkill(clickedCharSheet, 16)
1022end
1023function toggleResilienceAsCareerSkill(clickedCharSheet)
1024 toggleCareerSkill(clickedCharSheet, 17)
1025end
1026function toggleSkulduggeryAsCareerSkill(clickedCharSheet)
1027 toggleCareerSkill(clickedCharSheet, 18)
1028end
1029function toggleStealthAsCareerSkill(clickedCharSheet)
1030 toggleCareerSkill(clickedCharSheet, 19)
1031end
1032function toggleStreetwiseAsCareerSkill(clickedCharSheet)
1033 toggleCareerSkill(clickedCharSheet, 20)
1034end
1035function toggleSurvivalAsCareerSkill(clickedCharSheet)
1036 toggleCareerSkill(clickedCharSheet, 21)
1037end
1038function toggleVigilanceAsCareerSkill(clickedCharSheet)
1039 toggleCareerSkill(clickedCharSheet, 22)
1040end
1041function toggleBrawlAsCareerSkill(clickedCharSheet)
1042 toggleCareerSkill(clickedCharSheet, 23)
1043end
1044function toggleGunneryAsCareerSkill(clickedCharSheet)
1045 toggleCareerSkill(clickedCharSheet, 24)
1046end
1047function toggleMeleeAsCareerSkill(clickedCharSheet)
1048 toggleCareerSkill(clickedCharSheet, 25)
1049end
1050function toggleRanged_LightAsCareerSkill(clickedCharSheet)
1051 toggleCareerSkill(clickedCharSheet, 26)
1052end
1053function toggleRanged_HeavyAsCareerSkill(clickedCharSheet)
1054 toggleCareerSkill(clickedCharSheet, 27)
1055end
1056function toggleLightsaberAsCareerSkill(clickedCharSheet)
1057 toggleCareerSkill(clickedCharSheet, 28)
1058end
1059function toggleCoreWorldsAsCareerSkill(clickedCharSheet)
1060 toggleCareerSkill(clickedCharSheet, 29)
1061end
1062function toggleEducationAsCareerSkill(clickedCharSheet)
1063 toggleCareerSkill(clickedCharSheet, 30)
1064end
1065function toggleLoreAsCareerSkill(clickedCharSheet)
1066 toggleCareerSkill(clickedCharSheet, 31)
1067end
1068function toggleOuterRimAsCareerSkill(clickedCharSheet)
1069 toggleCareerSkill(clickedCharSheet, 32)
1070end
1071function toggleUnderworldAsCareerSkill(clickedCharSheet)
1072 toggleCareerSkill(clickedCharSheet, 33)
1073end
1074function toggleXenologyAsCareerSkill(clickedCharSheet)
1075 toggleCareerSkill(clickedCharSheet, 34)
1076end
1077function toggleOtherAsCareerSkill(clickedCharSheet)
1078 toggleCareerSkill(clickedCharSheet, 35)
1079end
1080
1081--Rank changes
1082function decreaseRankInAstrogation(clickedCharSheet)
1083 changeSkillRank(clickedCharSheet, 1, -1)
1084end
1085function increaseRankInAstrogation(clickedCharSheet)
1086 changeSkillRank(clickedCharSheet, 1, 1)
1087end
1088function decreaseRankInAthletics(clickedCharSheet)
1089 changeSkillRank(clickedCharSheet, 2, -1)
1090end
1091function increaseRankInAthletics(clickedCharSheet)
1092 changeSkillRank(clickedCharSheet, 2, 1)
1093end
1094function decreaseRankInCharm(clickedCharSheet)
1095 changeSkillRank(clickedCharSheet, 3, -1)
1096end
1097function increaseRankInCharm(clickedCharSheet)
1098 changeSkillRank(clickedCharSheet, 3, 1)
1099end
1100function decreaseRankInCoercion(clickedCharSheet)
1101 changeSkillRank(clickedCharSheet, 4, -1)
1102end
1103function increaseRankInCoercion(clickedCharSheet)
1104 changeSkillRank(clickedCharSheet, 4, 1)
1105end
1106function decreaseRankInComputers(clickedCharSheet)
1107 changeSkillRank(clickedCharSheet, 5, -1)
1108end
1109function increaseRankInComputers(clickedCharSheet)
1110 changeSkillRank(clickedCharSheet, 5, 1)
1111end
1112function decreaseRankInCool(clickedCharSheet)
1113 changeSkillRank(clickedCharSheet, 6, -1)
1114end
1115function increaseRankInCool(clickedCharSheet)
1116 changeSkillRank(clickedCharSheet, 6, 1)
1117end
1118function decreaseRankInCoordination(clickedCharSheet)
1119 changeSkillRank(clickedCharSheet, 7, -1)
1120end
1121function increaseRankInCoordination(clickedCharSheet)
1122 changeSkillRank(clickedCharSheet, 7, 1)
1123end
1124function decreaseRankInDeception(clickedCharSheet)
1125 changeSkillRank(clickedCharSheet, 8, -1)
1126end
1127function increaseRankInDeception(clickedCharSheet)
1128 changeSkillRank(clickedCharSheet, 8, 1)
1129end
1130function decreaseRankInDiscipline(clickedCharSheet)
1131 changeSkillRank(clickedCharSheet, 9, -1)
1132end
1133function increaseRankInDiscipline(clickedCharSheet)
1134 changeSkillRank(clickedCharSheet, 9, 1)
1135end
1136function decreaseRankInLeadership(clickedCharSheet)
1137 changeSkillRank(clickedCharSheet, 10, -1)
1138end
1139function increaseRankInLeadership(clickedCharSheet)
1140 changeSkillRank(clickedCharSheet, 10, 1)
1141end
1142function decreaseRankInMechanics(clickedCharSheet)
1143 changeSkillRank(clickedCharSheet, 11, -1)
1144end
1145function increaseRankInMechanics(clickedCharSheet)
1146 changeSkillRank(clickedCharSheet, 11, 1)
1147end
1148function decreaseRankInMedicine(clickedCharSheet)
1149 changeSkillRank(clickedCharSheet, 12, -1)
1150end
1151function increaseRankInMedicine(clickedCharSheet)
1152 changeSkillRank(clickedCharSheet, 12, 1)
1153end
1154function decreaseRankInNegotiation(clickedCharSheet)
1155 changeSkillRank(clickedCharSheet, 13, -1)
1156end
1157function increaseRankInNegotiation(clickedCharSheet)
1158 changeSkillRank(clickedCharSheet, 13, 1)
1159end
1160function decreaseRankInPerception(clickedCharSheet)
1161 changeSkillRank(clickedCharSheet, 14, -1)
1162end
1163function increaseRankInPerception(clickedCharSheet)
1164 changeSkillRank(clickedCharSheet, 14, 1)
1165end
1166function decreaseRankInPiloting_Planetary(clickedCharSheet)
1167 changeSkillRank(clickedCharSheet, 15, -1)
1168end
1169function increaseRankInPiloting_Planetary(clickedCharSheet)
1170 changeSkillRank(clickedCharSheet, 15, 1)
1171end
1172function decreaseRankInPiloting_Space(clickedCharSheet)
1173 changeSkillRank(clickedCharSheet, 16, -1)
1174end
1175function increaseRankInPiloting_Space(clickedCharSheet)
1176 changeSkillRank(clickedCharSheet, 16, 1)
1177end
1178function decreaseRankInResilience(clickedCharSheet)
1179 changeSkillRank(clickedCharSheet, 17, -1)
1180end
1181function increaseRankInResilience(clickedCharSheet)
1182 changeSkillRank(clickedCharSheet, 17, 1)
1183end
1184function decreaseRankInSkulduggery(clickedCharSheet)
1185 changeSkillRank(clickedCharSheet, 18, -1)
1186end
1187function increaseRankInSkulduggery(clickedCharSheet)
1188 changeSkillRank(clickedCharSheet, 18, 1)
1189end
1190function decreaseRankInStealth(clickedCharSheet)
1191 changeSkillRank(clickedCharSheet, 19, -1)
1192end
1193function increaseRankInStealth(clickedCharSheet)
1194 changeSkillRank(clickedCharSheet, 19, 1)
1195end
1196function decreaseRankInStreetwise(clickedCharSheet)
1197 changeSkillRank(clickedCharSheet, 20, -1)
1198end
1199function increaseRankInStreetwise(clickedCharSheet)
1200 changeSkillRank(clickedCharSheet, 20, 1)
1201end
1202function decreaseRankInSurvival(clickedCharSheet)
1203 changeSkillRank(clickedCharSheet, 21, -1)
1204end
1205function increaseRankInSurvival(clickedCharSheet)
1206 changeSkillRank(clickedCharSheet, 21, 1)
1207end
1208function decreaseRankInVigilance(clickedCharSheet)
1209 changeSkillRank(clickedCharSheet, 22, -1)
1210end
1211function increaseRankInVigilance(clickedCharSheet)
1212 changeSkillRank(clickedCharSheet, 22, 1)
1213end
1214function decreaseRankInBrawl(clickedCharSheet)
1215 changeSkillRank(clickedCharSheet, 23, -1)
1216end
1217function increaseRankInBrawl(clickedCharSheet)
1218 changeSkillRank(clickedCharSheet, 23, 1)
1219end
1220function decreaseRankInGunnery(clickedCharSheet)
1221 changeSkillRank(clickedCharSheet, 24, -1)
1222end
1223function increaseRankInGunnery(clickedCharSheet)
1224 changeSkillRank(clickedCharSheet, 24, 1)
1225end
1226function decreaseRankInMelee(clickedCharSheet)
1227 changeSkillRank(clickedCharSheet, 25, -1)
1228end
1229function increaseRankInMelee(clickedCharSheet)
1230 changeSkillRank(clickedCharSheet, 25, 1)
1231end
1232function decreaseRankInRanged_Light(clickedCharSheet)
1233 changeSkillRank(clickedCharSheet, 26, -1)
1234end
1235function increaseRankInRanged_Light(clickedCharSheet)
1236 changeSkillRank(clickedCharSheet, 26, 1)
1237end
1238function decreaseRankInRanged_Heavy(clickedCharSheet)
1239 changeSkillRank(clickedCharSheet, 27, -1)
1240end
1241function increaseRankInRanged_Heavy(clickedCharSheet)
1242 changeSkillRank(clickedCharSheet, 27, 1)
1243end
1244function decreaseRankInLightsaber(clickedCharSheet)
1245 changeSkillRank(clickedCharSheet, 28, -1)
1246end
1247function increaseRankInLightsaber(clickedCharSheet)
1248 changeSkillRank(clickedCharSheet, 28, 1)
1249end
1250function decreaseRankInCoreWorlds(clickedCharSheet)
1251 changeSkillRank(clickedCharSheet, 29, -1)
1252end
1253function increaseRankInCoreWorlds(clickedCharSheet)
1254 changeSkillRank(clickedCharSheet, 29, 1)
1255end
1256function decreaseRankInEducation(clickedCharSheet)
1257 changeSkillRank(clickedCharSheet, 30, -1)
1258end
1259function increaseRankInEducation(clickedCharSheet)
1260 changeSkillRank(clickedCharSheet, 30, 1)
1261end
1262function decreaseRankInLore(clickedCharSheet)
1263 changeSkillRank(clickedCharSheet, 31, -1)
1264end
1265function increaseRankInLore(clickedCharSheet)
1266 changeSkillRank(clickedCharSheet, 31, 1)
1267end
1268function decreaseRankInOuterRim(clickedCharSheet)
1269 changeSkillRank(clickedCharSheet, 32, -1)
1270end
1271function increaseRankInOuterRim(clickedCharSheet)
1272 changeSkillRank(clickedCharSheet, 32, 1)
1273end
1274function decreaseRankInUnderworld(clickedCharSheet)
1275 changeSkillRank(clickedCharSheet, 33, -1)
1276end
1277function increaseRankInUnderworld(clickedCharSheet)
1278 changeSkillRank(clickedCharSheet, 33, 1)
1279end
1280function decreaseRankInXenology(clickedCharSheet)
1281 changeSkillRank(clickedCharSheet, 34, -1)
1282end
1283function increaseRankInXenology(clickedCharSheet)
1284 changeSkillRank(clickedCharSheet, 34, 1)
1285end
1286function decreaseRankInOther(clickedCharSheet)
1287 changeSkillRank(clickedCharSheet, 35, -1)
1288end
1289function increaseRankInOther(clickedCharSheet)
1290 changeSkillRank(clickedCharSheet, 35, 1)
1291end
1292
1293--Total XP button functions
1294function increaseTotalXPBy1(clickedCharSheet)
1295 changeTotalXP(clickedCharSheet, 1)
1296end
1297function decreaseTotalXPBy1(clickedCharSheet)
1298 changeTotalXP(clickedCharSheet, -1)
1299end
1300function increaseTotalXPBy5(clickedCharSheet)
1301 changeTotalXP(clickedCharSheet, 5)
1302end
1303function decreaseTotalXPBy5(clickedCharSheet)
1304 changeTotalXP(clickedCharSheet, -5)
1305end
1306function increaseTotalXPBy10(clickedCharSheet)
1307 changeTotalXP(clickedCharSheet, 10)
1308end
1309function decreaseTotalXPBy10(clickedCharSheet)
1310 changeTotalXP(clickedCharSheet, -10)
1311end
1312function increaseTotalXPBy50(clickedCharSheet)
1313 changeTotalXP(clickedCharSheet, 50)
1314end
1315function decreaseTotalXPBy50(clickedCharSheet)
1316 changeTotalXP(clickedCharSheet, -50)
1317end
1318function increaseTotalXPBy100(clickedCharSheet)
1319 changeTotalXP(clickedCharSheet, 100)
1320end
1321function decreaseTotalXPBy100(clickedCharSheet)
1322 changeTotalXP(clickedCharSheet, -100)
1323end
1324function increaseTotalXPBy500(clickedCharSheet)
1325 changeTotalXP(clickedCharSheet, 500)
1326end
1327function decreaseTotalXPBy500(clickedCharSheet)
1328 changeTotalXP(clickedCharSheet, -500)
1329end
1330--Available XP button functions
1331function increaseAvailableXPBy1(clickedCharSheet)
1332 changeAvailableXP(clickedCharSheet, 1)
1333end
1334function decreaseAvailableXPBy1(clickedCharSheet)
1335 changeAvailableXP(clickedCharSheet, -1)
1336end
1337function increaseAvailableXPBy5(clickedCharSheet)
1338 changeAvailableXP(clickedCharSheet, 5)
1339end
1340function decreaseAvailableXPBy5(clickedCharSheet)
1341 changeAvailableXP(clickedCharSheet, -5)
1342end
1343function increaseAvailableXPBy10(clickedCharSheet)
1344 changeAvailableXP(clickedCharSheet, 10)
1345end
1346function decreaseAvailableXPBy10(clickedCharSheet)
1347 changeAvailableXP(clickedCharSheet, -10)
1348end
1349function increaseAvailableXPBy50(clickedCharSheet)
1350 changeAvailableXP(clickedCharSheet, 50)
1351end
1352function decreaseAvailableXPBy50(clickedCharSheet)
1353 changeAvailableXP(clickedCharSheet, -50)
1354end
1355function increaseAvailableXPBy100(clickedCharSheet)
1356 changeAvailableXP(clickedCharSheet, 100)
1357end
1358function decreaseAvailableXPBy100(clickedCharSheet)
1359 changeAvailableXP(clickedCharSheet, -100)
1360end
1361function increaseAvailableXPBy500(clickedCharSheet)
1362 changeAvailableXP(clickedCharSheet, 500)
1363end
1364function decreaseAvailableXPBy500(clickedCharSheet)
1365 changeAvailableXP(clickedCharSheet, -500)
1366end
1367
1368--Dice spawning
1369function spawnDicepoolForAstrogation(clickedCharSheet)
1370 spawnDicepool(clickedCharSheet, 1)
1371end
1372function spawnDicepoolForAthletics(clickedCharSheet)
1373 spawnDicepool(clickedCharSheet, 2)
1374end
1375function spawnDicepoolForCharm(clickedCharSheet)
1376 spawnDicepool(clickedCharSheet, 3)
1377end
1378function spawnDicepoolForCoercion(clickedCharSheet)
1379 spawnDicepool(clickedCharSheet, 4)
1380end
1381function spawnDicepoolForComputers(clickedCharSheet)
1382 spawnDicepool(clickedCharSheet, 5)
1383end
1384function spawnDicepoolForCool(clickedCharSheet)
1385 spawnDicepool(clickedCharSheet, 6)
1386end
1387function spawnDicepoolForCoordination(clickedCharSheet)
1388 spawnDicepool(clickedCharSheet, 7)
1389end
1390function spawnDicepoolForDeception(clickedCharSheet)
1391 spawnDicepool(clickedCharSheet, 8)
1392end
1393function spawnDicepoolForDiscipline(clickedCharSheet)
1394 spawnDicepool(clickedCharSheet, 9)
1395end
1396function spawnDicepoolForLeadership(clickedCharSheet)
1397 spawnDicepool(clickedCharSheet, 10)
1398end
1399function spawnDicepoolForMechanics(clickedCharSheet)
1400 spawnDicepool(clickedCharSheet, 11)
1401end
1402function spawnDicepoolForMedicine(clickedCharSheet)
1403 spawnDicepool(clickedCharSheet, 12)
1404end
1405function spawnDicepoolForNegotiation(clickedCharSheet)
1406 spawnDicepool(clickedCharSheet, 13)
1407end
1408function spawnDicepoolForPerception(clickedCharSheet)
1409 spawnDicepool(clickedCharSheet, 14)
1410end
1411function spawnDicepoolForPiloting_Planetary(clickedCharSheet)
1412 spawnDicepool(clickedCharSheet, 15)
1413end
1414function spawnDicepoolForPiloting_Space(clickedCharSheet)
1415 spawnDicepool(clickedCharSheet, 16)
1416end
1417function spawnDicepoolForResilience(clickedCharSheet)
1418 spawnDicepool(clickedCharSheet, 17)
1419end
1420function spawnDicepoolForSkulduggery(clickedCharSheet)
1421 spawnDicepool(clickedCharSheet, 18)
1422end
1423function spawnDicepoolForStealth(clickedCharSheet)
1424 spawnDicepool(clickedCharSheet, 19)
1425end
1426function spawnDicepoolForStreetwise(clickedCharSheet)
1427 spawnDicepool(clickedCharSheet, 20)
1428end
1429function spawnDicepoolForSurvival(clickedCharSheet)
1430 spawnDicepool(clickedCharSheet, 21)
1431end
1432function spawnDicepoolForVigilance(clickedCharSheet)
1433 spawnDicepool(clickedCharSheet, 22)
1434end
1435function spawnDicepoolForBrawl(clickedCharSheet)
1436 spawnDicepool(clickedCharSheet, 23)
1437end
1438function spawnDicepoolForGunnery(clickedCharSheet)
1439 spawnDicepool(clickedCharSheet, 24)
1440end
1441function spawnDicepoolForMelee(clickedCharSheet)
1442 spawnDicepool(clickedCharSheet, 25)
1443end
1444function spawnDicepoolForRanged_Light(clickedCharSheet)
1445 spawnDicepool(clickedCharSheet, 26)
1446end
1447function spawnDicepoolForRanged_Heavy(clickedCharSheet)
1448 spawnDicepool(clickedCharSheet, 27)
1449end
1450function spawnDicepoolForLightsaber(clickedCharSheet)
1451 spawnDicepool(clickedCharSheet, 28)
1452end
1453function spawnDicepoolForCoreWorlds(clickedCharSheet)
1454 spawnDicepool(clickedCharSheet, 29)
1455end
1456function spawnDicepoolForEducation(clickedCharSheet)
1457 spawnDicepool(clickedCharSheet, 30)
1458end
1459function spawnDicepoolForLore(clickedCharSheet)
1460 spawnDicepool(clickedCharSheet, 31)
1461end
1462function spawnDicepoolForOuterRim(clickedCharSheet)
1463 spawnDicepool(clickedCharSheet, 32)
1464end
1465function spawnDicepoolForUnderworld(clickedCharSheet)
1466 spawnDicepool(clickedCharSheet, 33)
1467end
1468function spawnDicepoolForXenology(clickedCharSheet)
1469 spawnDicepool(clickedCharSheet, 34)
1470end
1471function spawnDicepoolForOther(clickedCharSheet)
1472 spawnDicepool(clickedCharSheet, 35)
1473end
1474
1475--Dice spawning
1476function spawnAbilityDice()
1477 spawnDice(1)
1478end
1479function despawnAbilityDice()
1480 despawnDice(1)
1481end
1482function spawnProficiencyDice()
1483 spawnDice(2)
1484end
1485function despawnProficiencyDice()
1486 despawnDice(2)
1487end
1488function spawnBoostDice()
1489 spawnDice(3)
1490end
1491function despawnBoostDice()
1492 despawnDice(3)
1493end
1494function spawnDifficultyDice()
1495 spawnDice(4)
1496end
1497function despawnDifficultyDice()
1498 despawnDice(4)
1499end
1500function spawnChallengeDice()
1501 spawnDice(5)
1502end
1503function despawnChallengeDice()
1504 despawnDice(5)
1505end
1506function spawnSetbackDice()
1507 spawnDice(6)
1508end
1509function despawnSetbackDice()
1510 despawnDice(6)
1511end