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