· 8 years ago · Feb 09, 2018, 07:46 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"}
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"}
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, 1, 3, 3, 3, 3, 3, 3, 3}
52
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 --Possible display modes are 'edit' (all buttons), 'play' (just the most-used buttons), 'view' (no buttons, just labels)
193 charsheetVars.displaymode = "Edit"
194 table.insert(characterSheetsData, charsheetVars)
195end
196function finishCharacterSheetCreation(finishedCharacterSheet, characterSheetIndexTable)
197 --This gets called by the spawnObject callback parameter, so it gets passed a table argument. Index is table[1]
198 --Update the GUID list
199 updateCharacterSheetGUIDs()
200 --Create buttons on this new character sheet
201 rebuildSheetDisplay(characterSheetIndexTable[1])
202end
203
204function updateCharacterSheetGUIDs()
205 --Rebuild the list of character sheet GUIDs
206 -- Use a local variable first to prevent race conditions
207 local guidList = {}
208 for i = 1,#characterSheets do
209 table.insert(guidList, characterSheets[i].getGUID())
210 end
211 --Now overwrite the global list in a single step
212 characterSheetsGUIDs = guidList
213end
214
215function rebuildSheetDisplay(characterSheetIndex)
216 characterSheets[characterSheetIndex].clearButtons()
217 createDisplayLabels(characterSheetIndex)
218 createSkillsDisplay(characterSheetIndex)
219 if characterSheetsData[characterSheetIndex].displaymode ~= "View" then
220 createEditButtons(characterSheetIndex)
221 createDiceDisplay(characterSheets[characterSheetIndex])
222 end
223 createButton(characterSheets[characterSheetIndex], "toggleDisplayMode",
224 characterSheetsData[characterSheetIndex].displaymode .. " mode", 0, -6.55, 300, 300, 1500
225 )
226end
227function rebuildAllSheetDisplays()
228 for i = 1,#characterSheets do
229 rebuildSheetDisplay(i)
230 end
231end
232
233function rebuildTrayDisplay()
234 self.clearButtons()
235 --Create a button to create a new sheet
236 createButton(self, "createCharacterSheet", "New Sheet", 0, 3, 100, 100, 500)
237 --The tray also needs dice count labels and dice spawning buttons
238 createDiceDisplay(self, 1.8, -3)
239end
240
241function createDisplayLabels(characterSheetIndex)
242 --Create non-button (or more accurately fake-button) labels to display stats
243 local characterSheet = characterSheets[characterSheetIndex]
244 local charSheetValues = characterSheetsData[characterSheetIndex]
245 -- Character descriptors, like name and career
246 -- First the player name, since that's to the side
247 createButton(characterSheet, characterDescriptors[1], charSheetValues.characterDescriptorsValues[1], -3.35, 5.4, 125, 0, 0)
248 -- Then the other descriptors
249 local currentZ = 6.3
250 for i=2,#characterDescriptors do
251 createButton(characterSheet, characterDescriptors[i], charSheetValues.characterDescriptorsValues[i], 0, currentZ, 125, 0, 0)
252 currentZ = currentZ - 0.3
253 end
254 -- Battle stats (soak, wounds, etc)
255 -- Start with 'soak value', since that's the only one with a single value
256 createButton(characterSheet, battleFields[1], tostring(charSheetValues.battleFieldsValues[1]), 3.35, 4.45, 350, 0, 0)
257 -- Then iterate over the pairs of values
258 local currentX = 1.5
259 for i=2,#battleFields,2 do
260 createButton(characterSheet, battleFields[i], tostring(charSheetValues.battleFieldsValues[i]), currentX, 4.45, 350, 0, 0)
261 createButton(characterSheet, battleFields[i+1], tostring(charSheetValues.battleFieldsValues[i+1]), currentX - 0.8, 4.45, 350, 0, 0)
262 currentX = currentX - 2.3
263 end
264 -- Characteristics fields
265 currentX = 3.82
266 for i=1,#characteristics do
267 createButton(characterSheet, characteristics[i], tostring(charSheetValues.characteristicsValues[i]), currentX, 3.05, 400, 0, 0)
268 currentX = currentX - 1.55
269 end
270 -- total and available XP
271 createButton(characterSheet, "totalXP", tostring(charSheetValues.totalXP), 3.7, -6.5, 275, 0, 0)
272 createButton(characterSheet, "availableXP", tostring(charSheetValues.availableXP), -3.75, -6.5, 275, 0, 0)
273end
274
275function createEditButtons(characterSheetIndex)
276 local charsheet = characterSheets[characterSheetIndex]
277 local charSheetValues = characterSheetsData[characterSheetIndex]
278 --Create all the edit buttons...
279 if charSheetValues.displaymode == "Edit" then
280 -- ...for editing character descriptors like name and species
281 local charDescriptorEditButtonText = "Edit"
282 if charSheetValues.characterDescriptorsNotecard ~= nil then charDescriptorEditButtonText = "Save" end
283 createButton(charsheet, "editCharacterDescriptors", charDescriptorEditButtonText, 5.1, 6, 225, 250, 550)
284 -- ...a button to claim this sheet
285 createButton(charsheet, "setOwnerToClickedPlayer", "Claim", -5.2, 5.4, 175, 200, 500)
286 end
287 -- ...for battle stats
288 createButton(charsheet, "decreaseSoak", "-", 4.2, 4.3, 125, 125, 125)
289 createButton(charsheet, "increaseSoak", "+", 2.55, 4.3, 125, 125, 125)
290 local currentX = 1.95
291 local Xdecreases = {1.7, 0.57}
292 local currentXdecrease = Xdecreases[1]
293 for i=2,#battleFields do
294 createButton(charsheet, "decrease" .. battleFields[i], "-", currentX, 4.3, 125, 100, 100)
295 createButton(charsheet, "increase" .. battleFields[i], "+", currentX, 5, 125, 100, 100)
296 currentX = currentX - currentXdecrease
297 --Switch between short and long horizontal jumps
298 if currentXdecrease == Xdecreases[1] then currentXdecrease = Xdecreases[2] else currentXdecrease = Xdecreases[1] end
299 end
300 -- ...for characteristics
301 if charSheetValues.displaymode == "Edit" then
302 local currentX = 4.3
303 for i = 1,#characteristics do
304 --minus and plus buttons below the values
305 createButton(charsheet, "decrease".. characteristics[i], "-", currentX, 2.7, 100, 100, 100)
306 createButton(charsheet, "increase".. characteristics[i], "+", currentX - 0.92, 2.7, 100, 100, 100)
307 currentX = currentX - 1.55
308 end
309 end
310 --...for total XP
311 -- Each gets a 1, 5, 10, 50, 100 button, both plus and minus
312 -- Minus on the left, plus on the right, stacked
313 createButton(charsheet, "decreaseTotalXPBy5", "-5", 5, -6.3, 75, 75, 200)
314 createButton(charsheet, "decreaseTotalXPBy50", "-50", 5, -6.6, 75, 75, 200)
315 createButton(charsheet, "decreaseTotalXPBy500", "-500", 5, -6.9, 75, 75, 200)
316 createButton(charsheet, "decreaseTotalXPBy1", "-1", 4.65, -6.3, 75, 75, 200)
317 createButton(charsheet, "decreaseTotalXPBy10", "-10", 4.65, -6.6, 75, 75, 200)
318 createButton(charsheet, "decreaseTotalXPBy100", "-100", 4.65, -6.9, 75, 75, 200)
319 createButton(charsheet, "increaseTotalXPBy1", "+1", 2.75, -6.3, 75, 75, 200)
320 createButton(charsheet, "increaseTotalXPBy10", "+10", 2.75, -6.6, 75, 75, 200)
321 createButton(charsheet, "increaseTotalXPBy100", "+100", 2.75, -6.9, 75, 75, 200)
322 createButton(charsheet, "increaseTotalXPBy5", "+5", 2.4, -6.3, 75, 75, 200)
323 createButton(charsheet, "increaseTotalXPBy50", "+50", 2.4, -6.6, 75, 75, 200)
324 createButton(charsheet, "increaseTotalXPBy500", "+500", 2.4, -6.9, 75, 75, 200)
325 --...for available XP
326 createButton(charsheet, "decreaseAvailableXPBy1", "-1", -2.8, -6.3, 75, 75, 200)
327 createButton(charsheet, "decreaseAvailableXPBy10", "-10", -2.8, -6.6, 75, 75, 200)
328 createButton(charsheet, "decreaseAvailableXPBy100", "-100", -2.8, -6.9, 75, 75, 200)
329 createButton(charsheet, "decreaseAvailableXPBy5", "-5", -2.45, -6.3, 75, 75, 200)
330 createButton(charsheet, "decreaseAvailableXPBy50", "-50", -2.45, -6.6, 75, 75, 200)
331 createButton(charsheet, "decreaseAvailableXPBy500", "-500", -2.45, -6.9, 75, 75, 200)
332 createButton(charsheet, "increaseAvailableXPBy1", "+1", -4.7, -6.3, 75, 75, 200)
333 createButton(charsheet, "increaseAvailableXPBy10", "+10", -4.7, -6.6, 75, 75, 200)
334 createButton(charsheet, "increaseAvailableXPBy100", "+100", -4.7, -6.9, 75, 75, 200)
335 createButton(charsheet, "increaseAvailableXPBy5", "+5", -5.05, -6.3, 75, 75, 200)
336 createButton(charsheet, "increaseAvailableXPBy50", "+50", -5.05, -6.6, 75, 75, 200)
337 createButton(charsheet, "increaseAvailableXPBy500", "+500", -5.05, -6.9, 75, 75, 200)
338end
339
340--Separate function for the skill labels and buttons because sometimes the layout differs a bit between view modes
341-- and this seemed neater than looping through a few times depending on view mode
342function createSkillsDisplay(characterSheetIndex)
343 local charsheet = characterSheets[characterSheetIndex]
344 local charSheetValues = characterSheetsData[characterSheetIndex]
345 --Some buttons should only be pressable in edit mode, otherwise they should be size 0, so invisible, leaving only the text
346 local skillChangeButtonSize = {0, 0}
347 if charSheetValues.displaymode == "Edit" then skillChangeButtonSize = {75, 100} end
348 local diceSpawnButtonSize = 75
349 if charSheetValues.displaymode == "View" then diceSpawnButtonSize = 0 end
350
351 local startZ = 1.72
352 local currentZ = startZ
353 local stepZ = 0.252
354 local currentX = 2.9
355 for i = 1,#skills do
356 local skillName = sanitizeStringForFunctionName(skills[i])
357 --Create a 'career' toggle, to make this a career skill
358 local careerSkillButtonText = "N"
359 if findIndexOfValue(charSheetValues.careerSkills, i) ~= nil then
360 careerSkillButtonText = "Y"
361 end
362 createButton(charsheet, "toggle"..skillName.."AsCareerSkill", careerSkillButtonText, currentX, currentZ, 75, skillChangeButtonSize[1], skillChangeButtonSize[2])
363 --Create a 'spawn dicepool' button
364 createButton(charsheet, "spawnDicepoolFor"..skillName, getDicepoolDisplayString(determineDicepoolForSkill(characterSheetIndex, i)), currentX - 0.75, currentZ, 75, diceSpawnButtonSize)
365 --Skill rank display
366 createButton(charsheet, skillName, tostring(charSheetValues.skillsValues[i]), currentX - 2, currentZ, 75, 0, 0)
367
368 --Add buttons to in- and decrease rank, if needed
369 if charSheetValues.displaymode == "Edit" then
370 createButton(charsheet, "decreaseRankIn"..skillName, "-", currentX - 1.7, currentZ, 75, 75, 75)
371 createButton(charsheet, "increaseRankIn"..skillName, "+", currentX - 2.3, currentZ, 75, 75, 75)
372 end
373
374 currentZ = currentZ - stepZ
375 --Skill 22 (Vigilance) is the last General Skill, and also the last skill on the left column
376 -- So set the x and y to the right column values
377 if i == 22 then
378 currentX = -1.85
379 currentZ = startZ
380 --There's a gap of two rows between the combat skills and the knowledge skills
381 elseif i == 28 then
382 currentZ = currentZ - 1 * stepZ
383 end
384 end
385end
386
387function createDiceDisplay(targetObject, startX, baseZ)
388 --Set the defaults for the character sheets, since that's the main way this function will be used
389 if startX == nil then startX = -0.6 end
390 if baseZ == nil then baseZ = -2.3 end
391 --Create a table. First row is dice name and count, second row is 'Add' button, third row is 'Remove' button
392 local currentX = startX
393 for i,dicename in ipairs(dicenames) do
394 --Dice name
395 createButton(targetObject, dicename, dicename, currentX, baseZ, 75, 0, 0)
396 --Dice count
397 createButton(targetObject, dicename .. "Count", tostring(dicecounts[i]), currentX, baseZ - 0.15, 75, 0, 0)
398 --'Add' and 'Remove' button
399 createButton(targetObject, "spawn" .. dicename .. "Dice", "Add", currentX, baseZ - 0.35, 75, 75, 185)
400 createButton(targetObject, "despawn" .. dicename .. "Dice", "Remove", currentX, baseZ - 0.6, 75, 74, 325)
401
402 --Move over to the next column
403 currentX = currentX - 0.7
404 end
405 --Buttons for dice use
406 createButton(targetObject, "rollDice", "Roll", startX - 1.2, baseZ - 0.9, 100, 100, 300)
407 createButton(targetObject, "startDiceReading", "Read", startX - 1.9, baseZ - 0.9, 100, 100, 300)
408 createButton(targetObject, "clearDice", "Clear", startX - 2.6, baseZ - 0.9, 100, 100, 300)
409 --Display the outcome of the last roll
410 createButton(targetObject, "dicerollOutcomeDisplay", "", startX - 1.9, baseZ - 1.15, 125, 0, 0)
411end
412
413--Handle character sheet and dice deletion by removing all references and stored data
414function onObjectDestroy(destroyedObject)
415 local index = findIndexOfValue(characterSheets, destroyedObject)
416 if index ~= nil then
417 --The destroyed object is a character sheet. Remove everything we've got stored on it
418 table.remove(characterSheets, index)
419 table.remove(characterSheetsData, index)
420 table.remove(characterSheetsGUIDs, index)
421 --Only check if it's a dice when we aren't mass-deleting them
422 elseif areClearingDice == false then
423 index = findIndexOfValue(spawnedDice, destroyedObject)
424 if index ~= nil then
425 --Dice got destroyed, remove reference to it
426 table.remove(spawnedDice, index)
427 --and update the dicecount
428 local diceIndex = findIndexOfValue(dicenames, destroyedObject.getName())
429 dicecounts[diceIndex] = dicecounts[diceIndex] - 1
430 updateDicecountDisplays(diceIndex)
431 end
432 end
433end
434
435
436--DICE-RELATED FUNCTIONS
437function determineDicepoolForSkill(characterSheetIndex, skillIndex)
438 local dicepool = {}
439 local skillValue = characterSheetsData[characterSheetIndex].skillsValues[skillIndex]
440 local characteristicValue = characterSheetsData[characterSheetIndex].characteristicsValues[characteristicInfluencingSkills[skillIndex]]
441 local dicecount = math.max(skillValue, characteristicValue)
442 dicepool["Proficiency"] = math.min(skillValue, characteristicValue)
443 dicepool["Ability"] = dicecount - dicepool["Proficiency"]
444 return dicepool
445end
446
447function getDicepoolDisplayString(dicepool)
448 --Build up the display string
449 local displaystring = ""
450 if dicepool["Proficiency"] > 0 then
451 displaystring = tostring(dicepool["Proficiency"]) .. " prof"
452 end
453 if dicepool["Proficiency"] > 0 and dicepool["Ability"] > 0 then
454 displaystring = displaystring .. ", "
455 end
456 if dicepool["Ability"] > 0 then
457 displaystring = displaystring .. tostring(dicepool["Ability"]) .. " ab"
458 end
459 return displaystring
460end
461
462function updateDicepoolDisplayForSkill(characterSheetIndex, skillIndex)
463 --Set the button text to the dicepool description
464 local labelText = getDicepoolDisplayString(determineDicepoolForSkill(characterSheetIndex, skillIndex))
465 updateButtonText(characterSheets[characterSheetIndex], "spawnDicepoolFor" .. sanitizeStringForFunctionName(skills[skillIndex]), labelText, true)
466end
467
468function recalculateDicepoolPerSkill(characterSheetIndex, characteristicIndex)
469 --Go through all the skills that are influenced by the provided characteristic and recalculate their dicepools
470 for skillIndex = 1,#characteristicInfluencingSkills do
471 if characteristicIndex == nil or characteristicInfluencingSkills[skillIndex] == characteristicIndex then
472 updateDicepoolDisplayForSkill(characterSheetIndex, skillIndex)
473 end
474 end
475end
476
477function updateDicerollOutcomeDisplays(outcomeString)
478 updateButtonText(self, "dicerollOutcomeDisplay", outcomeString)
479 for i,charsheet in ipairs(characterSheets) do
480 updateButtonText(charsheet, "dicerollOutcomeDisplay", outcomeString)
481 end
482end
483
484function spawnDicepool(characterSheet, skillIndex)
485 local characterSheetIndex = findIndexOfValue(characterSheets, characterSheet)
486 local dicepool = determineDicepoolForSkill(characterSheetIndex, skillIndex)
487 for dicename, dicecount in pairs(dicepool) do
488 --Check if we even have to spawn dice
489 if dicecount > 0 then
490 local diceIndex = findIndexOfValue(dicenames, dicename)
491 for i = 1,dicecount do
492 spawnDice(diceIndex, false, i * 2)
493 end
494 --And update the dice count displays
495 updateDicecountDisplays(diceIndex)
496 end
497 end
498end
499
500function spawnDice(diceIndex, shouldUpdateDiceDisplays, diceHeight)
501 --The collider of the tray doesn't work if the tray isn't locked, since it's convex. So make sure it's locked
502 self.setLock(true)
503 --If we haven't been specifically told not to update, update
504 if shouldUpdateDiceDisplays == nil then shouldUpdateDiceDisplays = true end
505 local pos = self.getPosition()
506 --Randomise dice position to prevent phasing through each other on spawn
507 -- Stay within -1.75 to +1.75, both on the x and z axes
508 local spawnPosition = {pos.x - 1.75 + math.random() * 3.5, pos.y + 2, pos.z - 1.75 + math.random() * 3.5}
509 if diceHeight ~= nil then
510 spawnPosition[2] = diceHeight
511 end
512 local dice = spawnObject({type="Custom_Dice", position=spawnPosition})
513 --'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
514 dice.setCustomObject({type=dicedata[diceIndex][1], image=dicedata[diceIndex][2]})
515 dice.setName(dicenames[diceIndex]) --Make it easier to determine the type of dice when reading
516 dice.tooltip = false --Hide the mouse-over text you normally see when hovering over a dice
517 --Store the dice for later checks and despawning
518 table.insert(spawnedDice, dice)
519 --Update the stored dice cound
520 dicecounts[diceIndex] = dicecounts[diceIndex] + 1
521 if shouldUpdateDiceDisplays then
522 updateDicecountDisplays(diceIndex)
523 end
524end
525function despawnDice(diceIndex)
526 for i,dice in ipairs(spawnedDice) do
527 if dice.getName() == dicenames[diceIndex] then
528 dice.destruct()
529 break
530 end
531 end
532end
533
534
535function rollDice()
536 --The tray collider acts as a box collider when unlocked, which could lead to weird roles. Make sure that doesn't happen
537 self.setLock(true)
538 for i,dice in ipairs(spawnedDice) do
539 dice.randomize()
540 end
541 startDiceReading()
542end
543
544function startDiceReading()
545 --Clear the previous diceroll outcome displays
546 updateDicerollOutcomeDisplays("")
547 --Start the dice reading function
548 local cr = coroutine.create(waitForDiceToStopRolling)
549 coroutine.resume(cr)
550end
551function waitForDiceToStopRolling(numberOfChecksLeft)
552 if numberOfChecksLeft == nil then numberOfChecksLeft = {10} end --as a table since that's what the timer passes
553 for i, dice in ipairs(spawnedDice) do
554 if dice.resting == false then
555 if numberOfChecksLeft[1] > 0 then
556 numberOfChecksLeft[1] = numberOfChecksLeft[1] - 1
557 -- Make sure the existing Timer is fully destroyed
558 Timer.destroy(self.getGUID())
559 -- Then make a new timer to try again
560 Timer.create({delay=1.0, identifier=self.getGUID(), function_name="waitForDiceToStopRolling", parameters=numberOfChecksLeft})
561 return
562 else
563 --Waited for dice to stop rolling for too long, let's just stop trying
564 break
565 end
566 end
567 end
568 if numberOfChecksLeft[1] == 0 then printToAll("WARNING: Waiting for dice roll to finish took too long, results may be inaccurate", {1,0,0}) end
569 showDiceValues()
570end
571
572function showDiceValues()
573 local successCount = 0
574 local advantageCount = 0
575 local triumphCount = 0
576 local despairCount = 0
577 for i, dice in ipairs(spawnedDice) do
578 local dicename = dice.getName()
579 local diceIndex = findIndexOfValue(dicenames, dicename)
580 --the value table stores two values per side
581 -- So 'dicevalues[valueIndex-1]' is the number of successes, 'dicevalues[valueIndex]' number of advantages
582 -- (side 1 is index 1 and 2, side 2 is 3 and 4, etc)
583 local valueIndex = dice.getValue() * 2
584 successCount = successCount + dicevalues[diceIndex][valueIndex-1]
585 advantageCount = advantageCount + dicevalues[diceIndex][valueIndex]
586 --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)
587 if dice.getValue() == 4 then
588 if dicename == "Proficiency" then
589 triumphCount = triumphCount + 1
590 elseif dicename == "Challenge" then
591 despairCount = despairCount + 1
592 end
593 end
594 end
595 --Now print the result
596 local successDescriptionString = "successes"
597 if successCount < 0 then
598 successCount = successCount * -1
599 successDescriptionString = "failures"
600 end
601 local advantageDescriptionString = "advantages"
602 if advantageCount < 0 then
603 advantageCount = advantageCount * -1
604 advantageDescriptionString = "threats"
605 end
606 local resultString = string.format("%d %s, %d %s", successCount, successDescriptionString, advantageCount, advantageDescriptionString)
607 if triumphCount > 0 then resultString = string.format("%s, %d triumphs", resultString, triumphCount) end
608 if despairCount > 0 then resultString = string.format("%s, %d despairs", resultString, despairCount) end
609 printToAll(resultString, {1,1,1})
610 --Update all the outcome displays
611 updateDicerollOutcomeDisplays(resultString)
612end
613
614function clearDice()
615 --Reset the dicecounts
616 for i = 1,#dicecounts do
617 dicecounts[i] = 0
618 updateDicecountDisplays(i)
619 end
620 --Clear the diceroll outcome displays
621 updateDicerollOutcomeDisplays("")
622 --And now actually destroy the dice
623 areClearingDice = true --Prevent frequent display updates
624 for i,dice in ipairs(spawnedDice) do
625 dice.destruct()
626 end
627 --Clear the array
628 spawnedDice = {}
629 --Done!
630 areClearingDice = false
631end
632
633
634--VALUE CHANGING FUNCTIONS
635function editCharacterDescriptors(characterSheet)
636 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
637 local charSheetValues = characterSheetsData[charSheetIndex]
638 if characterDescriptorNotepads[characterSheet] == nil then
639 --First lock the sheet, to make notepad selection easier and to make sure it stays positioned right
640 characterSheet.setLock(true)
641 --Create a notecard for users to fill in their descriptors
642 local sheetPosition = characterSheet.getPosition()
643 local sheetRotation = characterSheet.getRotation()
644 --Calculate the relative position for the notecard, taking the charsheet's rotation into account
645 local targetAngle = sheetRotation.y + 82
646 local xDistance = math.cos(math.rad(targetAngle)) * 7.27
647 local zDistance = math.sin(math.rad(targetAngle)) * 7.27
648
649 local notecardPos = {sheetPosition.x - xDistance, sheetPosition.y + 0.4, sheetPosition.z + zDistance}
650 local notecardRot = {sheetRotation.x, sheetRotation.y, sheetRotation.z}
651 characterDescriptorNotepads[characterSheet] = spawnObject({type="Notecard", position=notecardPos, rotation=notecardRot})
652 characterDescriptorNotepads[characterSheet].setLock(true)
653 characterDescriptorNotepads[characterSheet].setName("Character Descriptors")
654 local notecardText = "Right-click to edit description, fill in your info after the colons, then press 'Save'"
655 for i=2,#characterDescriptors do
656 notecardText = notecardText .. "\n[b]" .. characterDescriptors[i] .. "[/b]: " .. charSheetValues.characterDescriptorsValues[i]
657 end
658 characterDescriptorNotepads[characterSheet].setDescription(notecardText)
659 --Update the button text to say 'Save'
660 updateButtonText(characterSheet, "editCharacterDescriptors", "Save")
661 else
662 --A notecard already exists, and we need to save the data on it
663 --Clear the global reference first, so any errors don't brick this function
664 local notecard = characterDescriptorNotepads[characterSheet]
665 characterDescriptorNotepads[characterSheet] = nil
666 -- Change the button text back to 'Edit'
667 updateButtonText(characterSheet, "editCharacterDescriptors", "Edit")
668
669 --Notecard exists, read it out (Lines are '[b]descriptorName[/b]: value')
670 for descriptor, value in string.gmatch(notecard.getDescription(), "%[b%](.-)%[/b%]: ([%w%p ]+)") do
671 if descriptor ~= nil and value ~= nil then
672 value = string.gsub(value, "\n", "; ")
673 local descriptorIndex = findIndexOfValue(characterDescriptors, descriptor)
674 if descriptorIndex == nil then
675 printError("Unknown character descriptor '" .. descriptor .. "'")
676 else
677 charSheetValues.characterDescriptorsValues[descriptorIndex] = value
678 updateButtonText(characterSheet, characterDescriptors[descriptorIndex], value)
679 end
680 end
681 end
682 --We no longer need the card, destroy it
683 notecard.destruct()
684 end
685end
686
687function setOwnerToClickedPlayer(characterSheet, clickingPlayerColor)
688 local characterSheetIndex = findIndexOfValue(characterSheets, characterSheet)
689 --player name is the first entry in 'characterDescriptors
690 characterSheetsData[characterSheetIndex].characterDescriptorsValues[1] = Player[clickingPlayerColor].steam_name
691 --Update the displayed name
692 updateButtonText(characterSheet, "playername", characterSheetsData[characterSheetIndex].characterDescriptorsValues[1])
693end
694
695function changeBattleFieldValue(characterSheet, battleFieldIndex, changeAmount)
696 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
697 local charSheetValues = characterSheetsData[charSheetIndex]
698 local newValue = charSheetValues.battleFieldsValues[battleFieldIndex] + changeAmount
699 if newValue >= 0 then
700 charSheetValues.battleFieldsValues[battleFieldIndex] = newValue
701 --Update display
702 updateButtonText(characterSheet, battleFields[battleFieldIndex], tostring(newValue))
703 end
704end
705
706function changeCharacteristicValue(characterSheet, characteristicIndex, changeAmount)
707 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
708 local charSheetValues = characterSheetsData[charSheetIndex]
709 local newValue = charSheetValues.characteristicsValues[characteristicIndex] + changeAmount
710 --Characteristics can't be zero or negative
711 if newValue > 0 then
712 charSheetValues.characteristicsValues[characteristicIndex] = newValue
713 --Update the value display
714 updateButtonText(characterSheet, characteristics[characteristicIndex], tostring(newValue))
715 --Recalculate the dicepools for all the skills that depend on the characteristic we just changed
716 recalculateDicepoolPerSkill(charSheetIndex, characteristicIndex)
717 end
718end
719
720function toggleCareerSkill(characterSheet, skillIndex)
721 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
722 local charSheetValues = characterSheetsData[charSheetIndex]
723 local careerButtonLabel = ""
724 local indexInCareerSkills = findIndexOfValue(charSheetValues.careerSkills, skillIndex)
725 if indexInCareerSkills ~= nil then
726 --It exists, so remove it
727 table.remove(charSheetValues.careerSkills, indexInCareerSkills)
728 careerButtonLabel = "N"
729 else
730 --It's not there, add it
731 table.insert(charSheetValues.careerSkills, skillIndex)
732 careerButtonLabel = "Y"
733 end
734 --Now update the skill's career button
735 updateButtonText(characterSheet, "toggle" .. sanitizeStringForFunctionName(skills[skillIndex]) .. "AsCareerSkill", careerButtonLabel)
736end
737
738function changeSkillRank(characterSheet, skillIndex, changeAmount)
739 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
740 local charSheetValues = characterSheetsData[charSheetIndex]
741 local newValue = charSheetValues.skillsValues[skillIndex] + changeAmount
742 --Cap skill ranks at a minimum of 0 and a max of 5
743 newValue = math.max(newValue, 0)
744 newValue = math.min(newValue, 5)
745 --Only act if the resulting skill value actually changed
746 if newValue ~= charSheetValues.skillsValues[skillIndex] then
747 charSheetValues.skillsValues[skillIndex] = newValue
748 --Update the rank display
749 updateButtonText(characterSheet, sanitizeStringForFunctionName(skills[skillIndex]), tostring(newValue))
750 --Recalculate dicepool for this skill
751 updateDicepoolDisplayForSkill(charSheetIndex, skillIndex)
752 end
753end
754
755function changeTotalXP(characterSheet, changeAmount)
756 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
757 local charSheetValues = characterSheetsData[charSheetIndex]
758 charSheetValues.totalXP = charSheetValues.totalXP + changeAmount
759 if charSheetValues.totalXP < 0 then charSheetValues.totalXP = 0 end
760 --Update the total XP display
761 updateButtonText(characterSheet, "totalXP", tostring(charSheetValues.totalXP))
762end
763function changeAvailableXP(characterSheet, changeAmount)
764 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
765 local charSheetValues = characterSheetsData[charSheetIndex]
766 charSheetValues.availableXP = charSheetValues.availableXP + changeAmount
767 if charSheetValues.availableXP < 0 then charSheetValues.availableXP = 0 end
768 --Update the available XP display
769 updateButtonText(characterSheet, "availableXP", tostring(charSheetValues.availableXP))
770end
771
772function toggleDisplayMode(characterSheet)
773 local charSheetIndex = findIndexOfValue(characterSheets, characterSheet)
774 local charSheetValues = characterSheetsData[charSheetIndex]
775 if charSheetValues.displaymode == "Edit" then
776 charSheetValues.displaymode = "Play"
777 elseif charSheetValues.displaymode == "Play" then
778 charSheetValues.displaymode = "View"
779 else
780 charSheetValues.displaymode = "Edit"
781 end
782 rebuildSheetDisplay(charSheetIndex)
783end
784
785
786--BUTTON FUNCTIONS
787--Battle Fields values
788function decreaseSoak(clickedCharSheet)
789 changeBattleFieldValue(clickedCharSheet, 1, -1)
790end
791function increaseSoak(clickedCharSheet)
792 changeBattleFieldValue(clickedCharSheet, 1, 1)
793end
794function decreaseWoundsThreshold(clickedCharSheet)
795 changeBattleFieldValue(clickedCharSheet, 2, -1)
796end
797function increaseWoundsThreshold(clickedCharSheet)
798 changeBattleFieldValue(clickedCharSheet, 2, 1)
799end
800function decreaseWoundsCurrent(clickedCharSheet)
801 changeBattleFieldValue(clickedCharSheet, 3, -1)
802end
803function increaseWoundsCurrent(clickedCharSheet)
804 changeBattleFieldValue(clickedCharSheet, 3, 1)
805end
806function decreaseStrainThreshold(clickedCharSheet)
807 changeBattleFieldValue(clickedCharSheet, 4, -1)
808end
809function increaseStrainThreshold(clickedCharSheet)
810 changeBattleFieldValue(clickedCharSheet, 4, 1)
811end
812function decreaseStrainCurrent(clickedCharSheet)
813 changeBattleFieldValue(clickedCharSheet, 5, -1)
814end
815function increaseStrainCurrent(clickedCharSheet)
816 changeBattleFieldValue(clickedCharSheet, 5, 1)
817end
818function decreaseDefenseRanged(clickedCharSheet)
819 changeBattleFieldValue(clickedCharSheet, 6, -1)
820end
821function increaseDefenseRanged(clickedCharSheet)
822 changeBattleFieldValue(clickedCharSheet, 6, 1)
823end
824function decreaseDefenseMelee(clickedCharSheet)
825 changeBattleFieldValue(clickedCharSheet, 7, -1)
826end
827function increaseDefenseMelee(clickedCharSheet)
828 changeBattleFieldValue(clickedCharSheet, 7, 1)
829end
830
831--Characteristics buttons
832function decreaseBrawn(clickedCharSheet)
833 changeCharacteristicValue(clickedCharSheet, 1, -1)
834end
835function increaseBrawn(clickedCharSheet)
836 changeCharacteristicValue(clickedCharSheet, 1, 1)
837end
838function decreaseAgility(clickedCharSheet)
839 changeCharacteristicValue(clickedCharSheet, 2, -1)
840end
841function increaseAgility(clickedCharSheet)
842 changeCharacteristicValue(clickedCharSheet, 2, 1)
843end
844function decreaseIntellect(clickedCharSheet)
845 changeCharacteristicValue(clickedCharSheet, 3, -1)
846end
847function increaseIntellect(clickedCharSheet)
848 changeCharacteristicValue(clickedCharSheet, 3, 1)
849end
850function decreaseCunning(clickedCharSheet)
851 changeCharacteristicValue(clickedCharSheet, 4, -1)
852end
853function increaseCunning(clickedCharSheet)
854 changeCharacteristicValue(clickedCharSheet, 4, 1)
855end
856function decreaseWillpower(clickedCharSheet)
857 changeCharacteristicValue(clickedCharSheet, 5, -1)
858end
859function increaseWillpower(clickedCharSheet)
860 changeCharacteristicValue(clickedCharSheet, 5, 1)
861end
862function decreasePresence(clickedCharSheet)
863 changeCharacteristicValue(clickedCharSheet, 6, -1)
864end
865function increasePresence(clickedCharSheet)
866 changeCharacteristicValue(clickedCharSheet, 6, 1)
867end
868
869--Career skill toggle buttons
870function toggleAstrogationAsCareerSkill(clickedCharSheet)
871 toggleCareerSkill(clickedCharSheet, 1)
872end
873function toggleAthleticsAsCareerSkill(clickedCharSheet)
874 toggleCareerSkill(clickedCharSheet, 2)
875end
876function toggleCharmAsCareerSkill(clickedCharSheet)
877 toggleCareerSkill(clickedCharSheet, 3)
878end
879function toggleCoercionAsCareerSkill(clickedCharSheet)
880 toggleCareerSkill(clickedCharSheet, 4)
881end
882function toggleComputersAsCareerSkill(clickedCharSheet)
883 toggleCareerSkill(clickedCharSheet, 5)
884end
885function toggleCoolAsCareerSkill(clickedCharSheet)
886 toggleCareerSkill(clickedCharSheet, 6)
887end
888function toggleCoordinationAsCareerSkill(clickedCharSheet)
889 toggleCareerSkill(clickedCharSheet, 7)
890end
891function toggleDeceptionAsCareerSkill(clickedCharSheet)
892 toggleCareerSkill(clickedCharSheet, 8)
893end
894function toggleDisciplineAsCareerSkill(clickedCharSheet)
895 toggleCareerSkill(clickedCharSheet, 9)
896end
897function toggleLeadershipAsCareerSkill(clickedCharSheet)
898 toggleCareerSkill(clickedCharSheet, 10)
899end
900function toggleMechanicsAsCareerSkill(clickedCharSheet)
901 toggleCareerSkill(clickedCharSheet, 11)
902end
903function toggleMedicineAsCareerSkill(clickedCharSheet)
904 toggleCareerSkill(clickedCharSheet, 12)
905end
906function toggleNegotiationAsCareerSkill(clickedCharSheet)
907 toggleCareerSkill(clickedCharSheet, 13)
908end
909function togglePerceptionAsCareerSkill(clickedCharSheet)
910 toggleCareerSkill(clickedCharSheet, 14)
911end
912function togglePiloting_PlanetaryAsCareerSkill(clickedCharSheet)
913 toggleCareerSkill(clickedCharSheet, 15)
914end
915function togglePiloting_SpaceAsCareerSkill(clickedCharSheet)
916 toggleCareerSkill(clickedCharSheet, 16)
917end
918function toggleResilienceAsCareerSkill(clickedCharSheet)
919 toggleCareerSkill(clickedCharSheet, 17)
920end
921function toggleSkulduggeryAsCareerSkill(clickedCharSheet)
922 toggleCareerSkill(clickedCharSheet, 18)
923end
924function toggleStealthAsCareerSkill(clickedCharSheet)
925 toggleCareerSkill(clickedCharSheet, 19)
926end
927function toggleStreetwiseAsCareerSkill(clickedCharSheet)
928 toggleCareerSkill(clickedCharSheet, 20)
929end
930function toggleSurvivalAsCareerSkill(clickedCharSheet)
931 toggleCareerSkill(clickedCharSheet, 21)
932end
933function toggleVigilanceAsCareerSkill(clickedCharSheet)
934 toggleCareerSkill(clickedCharSheet, 22)
935end
936function toggleBrawlAsCareerSkill(clickedCharSheet)
937 toggleCareerSkill(clickedCharSheet, 23)
938end
939function toggleGunneryAsCareerSkill(clickedCharSheet)
940 toggleCareerSkill(clickedCharSheet, 24)
941end
942function toggleMeleeAsCareerSkill(clickedCharSheet)
943 toggleCareerSkill(clickedCharSheet, 25)
944end
945function toggleRanged_LightAsCareerSkill(clickedCharSheet)
946 toggleCareerSkill(clickedCharSheet, 26)
947end
948function toggleRanged_HeavyAsCareerSkill(clickedCharSheet)
949 toggleCareerSkill(clickedCharSheet, 27)
950end
951function toggleLightsaberAsCareerSkill(clickedCharSheet)
952 toggleCareerSkill(clickedCharSheet, 28)
953end
954function toggleCoreWorldsAsCareerSkill(clickedCharSheet)
955 toggleCareerSkill(clickedCharSheet, 29)
956end
957function toggleEducationAsCareerSkill(clickedCharSheet)
958 toggleCareerSkill(clickedCharSheet, 30)
959end
960function toggleLoreAsCareerSkill(clickedCharSheet)
961 toggleCareerSkill(clickedCharSheet, 31)
962end
963function toggleOuterRimAsCareerSkill(clickedCharSheet)
964 toggleCareerSkill(clickedCharSheet, 32)
965end
966function toggleUnderworldAsCareerSkill(clickedCharSheet)
967 toggleCareerSkill(clickedCharSheet, 33)
968end
969function toggleXenologyAsCareerSkill(clickedCharSheet)
970 toggleCareerSkill(clickedCharSheet, 34)
971end
972function toggleOtherAsCareerSkill(clickedCharSheet)
973 toggleCareerSkill(clickedCharSheet, 35)
974end
975
976--Rank changes
977function decreaseRankInAstrogation(clickedCharSheet)
978 changeSkillRank(clickedCharSheet, 1, -1)
979end
980function increaseRankInAstrogation(clickedCharSheet)
981 changeSkillRank(clickedCharSheet, 1, 1)
982end
983function decreaseRankInAthletics(clickedCharSheet)
984 changeSkillRank(clickedCharSheet, 2, -1)
985end
986function increaseRankInAthletics(clickedCharSheet)
987 changeSkillRank(clickedCharSheet, 2, 1)
988end
989function decreaseRankInCharm(clickedCharSheet)
990 changeSkillRank(clickedCharSheet, 3, -1)
991end
992function increaseRankInCharm(clickedCharSheet)
993 changeSkillRank(clickedCharSheet, 3, 1)
994end
995function decreaseRankInCoercion(clickedCharSheet)
996 changeSkillRank(clickedCharSheet, 4, -1)
997end
998function increaseRankInCoercion(clickedCharSheet)
999 changeSkillRank(clickedCharSheet, 4, 1)
1000end
1001function decreaseRankInComputers(clickedCharSheet)
1002 changeSkillRank(clickedCharSheet, 5, -1)
1003end
1004function increaseRankInComputers(clickedCharSheet)
1005 changeSkillRank(clickedCharSheet, 5, 1)
1006end
1007function decreaseRankInCool(clickedCharSheet)
1008 changeSkillRank(clickedCharSheet, 6, -1)
1009end
1010function increaseRankInCool(clickedCharSheet)
1011 changeSkillRank(clickedCharSheet, 6, 1)
1012end
1013function decreaseRankInCoordination(clickedCharSheet)
1014 changeSkillRank(clickedCharSheet, 7, -1)
1015end
1016function increaseRankInCoordination(clickedCharSheet)
1017 changeSkillRank(clickedCharSheet, 7, 1)
1018end
1019function decreaseRankInDeception(clickedCharSheet)
1020 changeSkillRank(clickedCharSheet, 8, -1)
1021end
1022function increaseRankInDeception(clickedCharSheet)
1023 changeSkillRank(clickedCharSheet, 8, 1)
1024end
1025function decreaseRankInDiscipline(clickedCharSheet)
1026 changeSkillRank(clickedCharSheet, 9, -1)
1027end
1028function increaseRankInDiscipline(clickedCharSheet)
1029 changeSkillRank(clickedCharSheet, 9, 1)
1030end
1031function decreaseRankInLeadership(clickedCharSheet)
1032 changeSkillRank(clickedCharSheet, 10, -1)
1033end
1034function increaseRankInLeadership(clickedCharSheet)
1035 changeSkillRank(clickedCharSheet, 10, 1)
1036end
1037function decreaseRankInMechanics(clickedCharSheet)
1038 changeSkillRank(clickedCharSheet, 11, -1)
1039end
1040function increaseRankInMechanics(clickedCharSheet)
1041 changeSkillRank(clickedCharSheet, 11, 1)
1042end
1043function decreaseRankInMedicine(clickedCharSheet)
1044 changeSkillRank(clickedCharSheet, 12, -1)
1045end
1046function increaseRankInMedicine(clickedCharSheet)
1047 changeSkillRank(clickedCharSheet, 12, 1)
1048end
1049function decreaseRankInNegotiation(clickedCharSheet)
1050 changeSkillRank(clickedCharSheet, 13, -1)
1051end
1052function increaseRankInNegotiation(clickedCharSheet)
1053 changeSkillRank(clickedCharSheet, 13, 1)
1054end
1055function decreaseRankInPerception(clickedCharSheet)
1056 changeSkillRank(clickedCharSheet, 14, -1)
1057end
1058function increaseRankInPerception(clickedCharSheet)
1059 changeSkillRank(clickedCharSheet, 14, 1)
1060end
1061function decreaseRankInPiloting_Planetary(clickedCharSheet)
1062 changeSkillRank(clickedCharSheet, 15, -1)
1063end
1064function increaseRankInPiloting_Planetary(clickedCharSheet)
1065 changeSkillRank(clickedCharSheet, 15, 1)
1066end
1067function decreaseRankInPiloting_Space(clickedCharSheet)
1068 changeSkillRank(clickedCharSheet, 16, -1)
1069end
1070function increaseRankInPiloting_Space(clickedCharSheet)
1071 changeSkillRank(clickedCharSheet, 16, 1)
1072end
1073function decreaseRankInResilience(clickedCharSheet)
1074 changeSkillRank(clickedCharSheet, 17, -1)
1075end
1076function increaseRankInResilience(clickedCharSheet)
1077 changeSkillRank(clickedCharSheet, 17, 1)
1078end
1079function decreaseRankInSkulduggery(clickedCharSheet)
1080 changeSkillRank(clickedCharSheet, 18, -1)
1081end
1082function increaseRankInSkulduggery(clickedCharSheet)
1083 changeSkillRank(clickedCharSheet, 18, 1)
1084end
1085function decreaseRankInStealth(clickedCharSheet)
1086 changeSkillRank(clickedCharSheet, 19, -1)
1087end
1088function increaseRankInStealth(clickedCharSheet)
1089 changeSkillRank(clickedCharSheet, 19, 1)
1090end
1091function decreaseRankInStreetwise(clickedCharSheet)
1092 changeSkillRank(clickedCharSheet, 20, -1)
1093end
1094function increaseRankInStreetwise(clickedCharSheet)
1095 changeSkillRank(clickedCharSheet, 20, 1)
1096end
1097function decreaseRankInSurvival(clickedCharSheet)
1098 changeSkillRank(clickedCharSheet, 21, -1)
1099end
1100function increaseRankInSurvival(clickedCharSheet)
1101 changeSkillRank(clickedCharSheet, 21, 1)
1102end
1103function decreaseRankInVigilance(clickedCharSheet)
1104 changeSkillRank(clickedCharSheet, 22, -1)
1105end
1106function increaseRankInVigilance(clickedCharSheet)
1107 changeSkillRank(clickedCharSheet, 22, 1)
1108end
1109function decreaseRankInBrawl(clickedCharSheet)
1110 changeSkillRank(clickedCharSheet, 23, -1)
1111end
1112function increaseRankInBrawl(clickedCharSheet)
1113 changeSkillRank(clickedCharSheet, 23, 1)
1114end
1115function decreaseRankInGunnery(clickedCharSheet)
1116 changeSkillRank(clickedCharSheet, 24, -1)
1117end
1118function increaseRankInGunnery(clickedCharSheet)
1119 changeSkillRank(clickedCharSheet, 24, 1)
1120end
1121function decreaseRankInMelee(clickedCharSheet)
1122 changeSkillRank(clickedCharSheet, 25, -1)
1123end
1124function increaseRankInMelee(clickedCharSheet)
1125 changeSkillRank(clickedCharSheet, 25, 1)
1126end
1127function decreaseRankInRanged_Light(clickedCharSheet)
1128 changeSkillRank(clickedCharSheet, 26, -1)
1129end
1130function increaseRankInRanged_Light(clickedCharSheet)
1131 changeSkillRank(clickedCharSheet, 26, 1)
1132end
1133function decreaseRankInRanged_Heavy(clickedCharSheet)
1134 changeSkillRank(clickedCharSheet, 27, -1)
1135end
1136function increaseRankInRanged_Heavy(clickedCharSheet)
1137 changeSkillRank(clickedCharSheet, 27, 1)
1138end
1139function decreaseRankInLightsaber(clickedCharSheet)
1140 changeSkillRank(clickedCharSheet, 28, -1)
1141end
1142function increaseRankInLightsaber(clickedCharSheet)
1143 changeSkillRank(clickedCharSheet, 28, 1)
1144end
1145function decreaseRankInCoreWorlds(clickedCharSheet)
1146 changeSkillRank(clickedCharSheet, 29, -1)
1147end
1148function increaseRankInCoreWorlds(clickedCharSheet)
1149 changeSkillRank(clickedCharSheet, 29, 1)
1150end
1151function decreaseRankInEducation(clickedCharSheet)
1152 changeSkillRank(clickedCharSheet, 30, -1)
1153end
1154function increaseRankInEducation(clickedCharSheet)
1155 changeSkillRank(clickedCharSheet, 30, 1)
1156end
1157function decreaseRankInLore(clickedCharSheet)
1158 changeSkillRank(clickedCharSheet, 31, -1)
1159end
1160function increaseRankInLore(clickedCharSheet)
1161 changeSkillRank(clickedCharSheet, 31, 1)
1162end
1163function decreaseRankInOuterRim(clickedCharSheet)
1164 changeSkillRank(clickedCharSheet, 32, -1)
1165end
1166function increaseRankInOuterRim(clickedCharSheet)
1167 changeSkillRank(clickedCharSheet, 32, 1)
1168end
1169function decreaseRankInUnderworld(clickedCharSheet)
1170 changeSkillRank(clickedCharSheet, 33, -1)
1171end
1172function increaseRankInUnderworld(clickedCharSheet)
1173 changeSkillRank(clickedCharSheet, 33, 1)
1174end
1175function decreaseRankInXenology(clickedCharSheet)
1176 changeSkillRank(clickedCharSheet, 34, -1)
1177end
1178function increaseRankInXenology(clickedCharSheet)
1179 changeSkillRank(clickedCharSheet, 34, 1)
1180end
1181function decreaseRankInOther(clickedCharSheet)
1182 changeSkillRank(clickedCharSheet, 35, -1)
1183end
1184function increaseRankInOther(clickedCharSheet)
1185 changeSkillRank(clickedCharSheet, 35, 1)
1186end
1187
1188--Total XP button functions
1189function increaseTotalXPBy1(clickedCharSheet)
1190 changeTotalXP(clickedCharSheet, 1)
1191end
1192function decreaseTotalXPBy1(clickedCharSheet)
1193 changeTotalXP(clickedCharSheet, -1)
1194end
1195function increaseTotalXPBy5(clickedCharSheet)
1196 changeTotalXP(clickedCharSheet, 5)
1197end
1198function decreaseTotalXPBy5(clickedCharSheet)
1199 changeTotalXP(clickedCharSheet, -5)
1200end
1201function increaseTotalXPBy10(clickedCharSheet)
1202 changeTotalXP(clickedCharSheet, 10)
1203end
1204function decreaseTotalXPBy10(clickedCharSheet)
1205 changeTotalXP(clickedCharSheet, -10)
1206end
1207function increaseTotalXPBy50(clickedCharSheet)
1208 changeTotalXP(clickedCharSheet, 50)
1209end
1210function decreaseTotalXPBy50(clickedCharSheet)
1211 changeTotalXP(clickedCharSheet, -50)
1212end
1213function increaseTotalXPBy100(clickedCharSheet)
1214 changeTotalXP(clickedCharSheet, 100)
1215end
1216function decreaseTotalXPBy100(clickedCharSheet)
1217 changeTotalXP(clickedCharSheet, -100)
1218end
1219function increaseTotalXPBy500(clickedCharSheet)
1220 changeTotalXP(clickedCharSheet, 500)
1221end
1222function decreaseTotalXPBy500(clickedCharSheet)
1223 changeTotalXP(clickedCharSheet, -500)
1224end
1225--Available XP button functions
1226function increaseAvailableXPBy1(clickedCharSheet)
1227 changeAvailableXP(clickedCharSheet, 1)
1228end
1229function decreaseAvailableXPBy1(clickedCharSheet)
1230 changeAvailableXP(clickedCharSheet, -1)
1231end
1232function increaseAvailableXPBy5(clickedCharSheet)
1233 changeAvailableXP(clickedCharSheet, 5)
1234end
1235function decreaseAvailableXPBy5(clickedCharSheet)
1236 changeAvailableXP(clickedCharSheet, -5)
1237end
1238function increaseAvailableXPBy10(clickedCharSheet)
1239 changeAvailableXP(clickedCharSheet, 10)
1240end
1241function decreaseAvailableXPBy10(clickedCharSheet)
1242 changeAvailableXP(clickedCharSheet, -10)
1243end
1244function increaseAvailableXPBy50(clickedCharSheet)
1245 changeAvailableXP(clickedCharSheet, 50)
1246end
1247function decreaseAvailableXPBy50(clickedCharSheet)
1248 changeAvailableXP(clickedCharSheet, -50)
1249end
1250function increaseAvailableXPBy100(clickedCharSheet)
1251 changeAvailableXP(clickedCharSheet, 100)
1252end
1253function decreaseAvailableXPBy100(clickedCharSheet)
1254 changeAvailableXP(clickedCharSheet, -100)
1255end
1256function increaseAvailableXPBy500(clickedCharSheet)
1257 changeAvailableXP(clickedCharSheet, 500)
1258end
1259function decreaseAvailableXPBy500(clickedCharSheet)
1260 changeAvailableXP(clickedCharSheet, -500)
1261end
1262
1263--Dice spawning
1264function spawnDicepoolForAstrogation(clickedCharSheet)
1265 spawnDicepool(clickedCharSheet, 1)
1266end
1267function spawnDicepoolForAthletics(clickedCharSheet)
1268 spawnDicepool(clickedCharSheet, 2)
1269end
1270function spawnDicepoolForCharm(clickedCharSheet)
1271 spawnDicepool(clickedCharSheet, 3)
1272end
1273function spawnDicepoolForCoercion(clickedCharSheet)
1274 spawnDicepool(clickedCharSheet, 4)
1275end
1276function spawnDicepoolForComputers(clickedCharSheet)
1277 spawnDicepool(clickedCharSheet, 5)
1278end
1279function spawnDicepoolForCool(clickedCharSheet)
1280 spawnDicepool(clickedCharSheet, 6)
1281end
1282function spawnDicepoolForCoordination(clickedCharSheet)
1283 spawnDicepool(clickedCharSheet, 7)
1284end
1285function spawnDicepoolForDeception(clickedCharSheet)
1286 spawnDicepool(clickedCharSheet, 8)
1287end
1288function spawnDicepoolForDiscipline(clickedCharSheet)
1289 spawnDicepool(clickedCharSheet, 9)
1290end
1291function spawnDicepoolForLeadership(clickedCharSheet)
1292 spawnDicepool(clickedCharSheet, 10)
1293end
1294function spawnDicepoolForMechanics(clickedCharSheet)
1295 spawnDicepool(clickedCharSheet, 11)
1296end
1297function spawnDicepoolForMedicine(clickedCharSheet)
1298 spawnDicepool(clickedCharSheet, 12)
1299end
1300function spawnDicepoolForNegotiation(clickedCharSheet)
1301 spawnDicepool(clickedCharSheet, 13)
1302end
1303function spawnDicepoolForPerception(clickedCharSheet)
1304 spawnDicepool(clickedCharSheet, 14)
1305end
1306function spawnDicepoolForPiloting_Planetary(clickedCharSheet)
1307 spawnDicepool(clickedCharSheet, 15)
1308end
1309function spawnDicepoolForPiloting_Space(clickedCharSheet)
1310 spawnDicepool(clickedCharSheet, 16)
1311end
1312function spawnDicepoolForResilience(clickedCharSheet)
1313 spawnDicepool(clickedCharSheet, 17)
1314end
1315function spawnDicepoolForSkulduggery(clickedCharSheet)
1316 spawnDicepool(clickedCharSheet, 18)
1317end
1318function spawnDicepoolForStealth(clickedCharSheet)
1319 spawnDicepool(clickedCharSheet, 19)
1320end
1321function spawnDicepoolForStreetwise(clickedCharSheet)
1322 spawnDicepool(clickedCharSheet, 20)
1323end
1324function spawnDicepoolForSurvival(clickedCharSheet)
1325 spawnDicepool(clickedCharSheet, 21)
1326end
1327function spawnDicepoolForVigilance(clickedCharSheet)
1328 spawnDicepool(clickedCharSheet, 22)
1329end
1330function spawnDicepoolForBrawl(clickedCharSheet)
1331 spawnDicepool(clickedCharSheet, 23)
1332end
1333function spawnDicepoolForGunnery(clickedCharSheet)
1334 spawnDicepool(clickedCharSheet, 24)
1335end
1336function spawnDicepoolForMelee(clickedCharSheet)
1337 spawnDicepool(clickedCharSheet, 25)
1338end
1339function spawnDicepoolForRanged_Light(clickedCharSheet)
1340 spawnDicepool(clickedCharSheet, 26)
1341end
1342function spawnDicepoolForRanged_Heavy(clickedCharSheet)
1343 spawnDicepool(clickedCharSheet, 27)
1344end
1345function spawnDicepoolForLightsaber(clickedCharSheet)
1346 spawnDicepool(clickedCharSheet, 28)
1347end
1348function spawnDicepoolForCoreWorlds(clickedCharSheet)
1349 spawnDicepool(clickedCharSheet, 29)
1350end
1351function spawnDicepoolForEducation(clickedCharSheet)
1352 spawnDicepool(clickedCharSheet, 30)
1353end
1354function spawnDicepoolForLore(clickedCharSheet)
1355 spawnDicepool(clickedCharSheet, 31)
1356end
1357function spawnDicepoolForOuterRim(clickedCharSheet)
1358 spawnDicepool(clickedCharSheet, 32)
1359end
1360function spawnDicepoolForUnderworld(clickedCharSheet)
1361 spawnDicepool(clickedCharSheet, 33)
1362end
1363function spawnDicepoolForXenology(clickedCharSheet)
1364 spawnDicepool(clickedCharSheet, 34)
1365end
1366function spawnDicepoolForOther(clickedCharSheet)
1367 spawnDicepool(clickedCharSheet, 35)
1368end
1369
1370--Dice spawning
1371function spawnAbilityDice()
1372 spawnDice(1)
1373end
1374function despawnAbilityDice()
1375 despawnDice(1)
1376end
1377function spawnProficiencyDice()
1378 spawnDice(2)
1379end
1380function despawnProficiencyDice()
1381 despawnDice(2)
1382end
1383function spawnBoostDice()
1384 spawnDice(3)
1385end
1386function despawnBoostDice()
1387 despawnDice(3)
1388end
1389function spawnDifficultyDice()
1390 spawnDice(4)
1391end
1392function despawnDifficultyDice()
1393 despawnDice(4)
1394end
1395function spawnChallengeDice()
1396 spawnDice(5)
1397end
1398function despawnChallengeDice()
1399 despawnDice(5)
1400end
1401function spawnSetbackDice()
1402 spawnDice(6)
1403end
1404function despawnSetbackDice()
1405 despawnDice(6)
1406end