Module:Stats

local p = { argDefs = { loadName={isNumeric=false, path={}, doc='Name of the player module from which data should be loaded'}, race={isNumeric=false, path={'race'}, doc='The race of the character. Used to load starting stats, before levelups are applied. In the case of abominations, you can put "Abomination" followed by the name of the original race.'}, Str={isNumeric=false, path={'statLevelups','Str'}, doc='How many levelups of the stat a character has made.'}, Dex={isNumeric=false, path={'statLevelups','Dex'}, doc='How many levelups of the stat a character has made.'}, Spd={isNumeric=false, path={'statLevelups','Spd'}, doc='How many levelups of the stat a character has made.'}, End={isNumeric=false, path={'statLevelups','End'}, doc='How many levelups of the stat a character has made.'}, Awr={isNumeric=false, path={'statLevelups','Awr'}, doc='How many levelups of the stat a character has made.'}, Cun={isNumeric=false, path={'statLevelups','Cun'}, doc='How many levelups of the stat a character has made.'}, Knw={isNumeric=false, path={'statLevelups','Knw'}, doc='How many levelups of the stat a character has made.'}, Nrv={isNumeric=false, path={'statLevelups','Nrv'}, doc='How many levelups of the stat a character has made.'}, Pen={isNumeric=false, path={'nervePenalty'}, doc='A penalty applied to the Nerve stat due to failed Nerve rolls'}, Diving={isNumeric=false, path={'skills','Diving'}, doc='The diving skill of the character.'}, statusEffects={isNumeric=false, path={'statusEffects'}, doc='A table or string containing various status effects for the player (e.g. {name=\'Silent Night\', description=\'Diving always performed at advantage\', duration=\'3 turns\', helpfulness=10},{name=\'Broken Leg\', description=\'Broke leg after falling\', helpfulness=-50}'}   } } local utils = require('Module:Utils') function p.addRow(htmltable, rowTitle, points, sphere, sphereDesc, adjustment, diving)    local finalPoints = points + adjustment    local success    if (finalPoints < 1) then        success = 0    elseif (finalPoints > 20) then        success = 95    else         success = ((finalPoints-1)/20)*100    end    local adjString = ''    local adjColour = 'transparent'    if(adjustment < 0) then        adjString = ' - ' .. tostring(-adjustment)        adjColour = 'violet'    elseif(adjustment > 0) then        adjString = ' + ' .. tostring(adjustment) adjColour = 'limegreen' end if(diving ~= nil and diving > 0) then local finalPointsDive = points + adjustment + diving local successDive if (finalPointsDive < 1) then successDive = 0 elseif (finalPointsDive > 20) then successDive = 95 else successDive = ((finalPointsDive-1)/20)*100 end htmltable :tag('tr') :css('color', 'white') :css('background', '#313e55') :tag('th') :css('text-align', 'right') --:css('font-size', '110%') :css('border-width', '3px') :css('border-color', 'rgb(204, 153, 102)') :wikitext(rowTitle) :done :tag('td') :css('text-align', 'left') :css('border-width', '3px') :css('border-color', 'rgb(204, 153, 102)') :wikitext(points) :tag('span') :css('color', adjColour) :wikitext(adjString) :done :done :tag('td') :css('border-width', '3px') :css('border-color', 'rgb(204, 153, 102)') :wikitext(tostring(success) .. '%') :done :tag('td') :css('border-width', '3px') :css('border-color', 'rgb(204, 153, 102)') :tag('abbr') :attr('title',tostring(sphereDesc)) :wikitext(tostring(sphere)) :done :done :tag('td') :css('border-width', '3px') :css('border-color', 'rgb(204, 153, 102)') :wikitext(tostring(successDive) .. '%') :done; else htmltable :tag('tr') :css('color', 'white') :css('background', '#313e55') :tag('th') :css('text-align', 'right') --:css('font-size', '110%') :css('border-width', '3px') :css('border-color', 'rgb(204, 153, 102)') :wikitext(rowTitle) :done :tag('td') :css('text-align', 'left') :css('border-width', '3px') :css('border-color', 'rgb(204, 153, 102)') :wikitext(points) :tag('span') :css('color', adjColour) :wikitext(adjString) :done :done :tag('td') :css('border-width', '3px') :css('border-color', 'rgb(204, 153, 102)') :wikitext(tostring(success) .. '%') end end function p.addSpecial(specialRow, name, description, duration, helpfulness) local durationString = '' if(duration ~= nil) then durationString = ' (' .. duration .. ')' end local colorString = 'inherit' if(helpfulness==nil) then colorString = 'inherit' elseif(helpfulness > 0) then colorString = 'limegreen' elseif(helpfulness < 0) then colorString = 'violet' else colorString = 'yellow' end specialRow:tag('div') :tag('span') :css('font-weight','bold') :css('font-size', '12px') :css('color', colorString) :wikitext(name .. ': ') :done :wikitext(description .. durationString) end function p.createtableInternal(args) -- Create an empty string that will be returned at the end of the function -- New things will be added to the string as we do them local retString = "" -- Declare stats local Str = 0 local Dex = 0 local Spd = 0 local End = 0 local Awr = 0 local Cun = 0 local Knw = 0 local Nrv = 0 local Adv = 'Unknown' -- Calculate stats based on race local race = "" local raceString = "" if(args.race ~= nil) then race = string.lower(args.race) raceString = " (" .. args.race .. ")" end if (race == 'human' or race == 'man') then Str = 10 Dex = 10 Spd = 10 End = 10 Awr = 10 Cun = 10 Knw = 10 Nrv = 10 Adv = 'Adaptable, expansionist apes. Largest population underground.' elseif (race == 'shang-gei' or race == 'lizard' or race == 'snake' or race == 'snek') then Str = 8 Dex = 12 Spd = 12 End = 8 Awr = 12 Cun = 10 Knw = 8 Nrv = 10 Adv = 'Flexible lizard nomads looking for love. Can “See” in total darkness.' elseif (race == 'ethral' or race == 'moth') then Str = 7 Dex = 12 Spd = 10 End = 8 Awr = 7 Cun = 13 Knw = 13 Nrv = 10 Adv = 'Scholarly Moths prone to shyness and mask wearing. Able to glide and ignore falls, come with mask.' elseif (race == 'honored dead' or race == 'hd' or race == 'dead' or race == 'honored undead' or race == 'hu' or race == 'undead' or race == 'skeleton') then Str = 14 Dex = 8 Spd = 10 End = 14 Awr = 10 Cun = 8 Knw = 6 Nrv = 10 Adv = 'Righteous Undead Warriors seeking glory. Immune to pain and sickness, never heal.' elseif (race == 'shluck' or race == 'slug') then Str = 8 Dex = 10 Spd = 8 End = 10 Awr = 9 Cun = 13 Knw = 12 Nrv = 10 Adv = 'Amphibious Merchant molluscs in mechanical exosuits. Can breathe underwater, comes with exosuit.' elseif (race == 'mole-man' or race == 'moleman' or race == 'mole' or race == 'swole') then Str = 12 Dex = 10 Spd = 8 End = 12 Awr = 10 Cun = 9 Knw = 9 Nrv = 10 Adv = 'Secretive Mole-bipeds. Dig stone without tools and dangerous unarmed fighters.' elseif (race == 'corven' or race == 'crow' or race == 'magpie') then Str = 8 Dex = 13 Spd = 13 End = 6 Awr = 12 Cun = 10 Knw = 8 Nrv = 10 Adv = 'Money obsessed Birdmen. Climb and alike actions always done at an advantage, falls done at disadvantage.' elseif (string.match(race,'abomination')) then Str = 9 Dex = 8 Spd = 8 End = 10 Awr = 12 Cun = 10 Knw = 10 Nrv = 13 Adv = 'Horrifically twisted magical mutants. Loved by the church, hated by the population.' end -- Add levelups if(args.Str ~= nil) then Str = Str + args.Str end if(args.Dex ~= nil) then Dex = Dex + args.Dex end if(args.Spd ~= nil) then Spd = Spd + args.Spd end if(args.End ~= nil) then End = End + args.End end if(args.Awr ~= nil) then Awr = Awr + args.Awr end if(args.Cun ~= nil) then Cun = Cun + args.Cun end if(args.Knw ~= nil) then Knw = Knw + args.Knw end if(args.Nrv ~= nil) then Nrv = Nrv + args.Nrv end -- Subtract nerve penalty local Pen = 0 if(args.Pen ~= nil) then Pen = -args.Pen end -- Create an html node that will represent the table local htmltable = mw.html.create('table') -- Change that node's css properties so that it has the proper style htmltable :css('width','100%') :css('font-size', '14px') :css('float', 'right') :css('margin', '0 0 0em 0em') :css('border-style', 'solid') :css('border-width', '3px') :css('border-color', 'rgb(204, 153, 102)') :css('background', 'rgb(204, 153, 102)') :css('padding', '1px 1px') :css('color', 'white') :css('text-align', 'left') :attr('cellpadding', '1') :attr('cellspacing', '1') -- Add table header texts local colspan = 3 local diving = nil if(args.Diving ~= nil) then diving = tonumber(args.Diving) if(diving > 0) then colspan = 5 end end if(diving ~= nil and diving > 0) then htmltable:tag('tr') :css('background', '#313e55') :tag('th') :attr('colspan', colspan) :css('text-align', 'center') :css('font-size','15px') :wikitext('Stats' .. raceString) htmltable:tag('tr') :css('background', '#313e55') :tag('th') :css('text-align', 'center') :css('font-size','15px') :wikitext('Name') :done :tag('th') :css('text-align', 'center') :css('font-size','15px') :wikitext('Points') :done :tag('th') :css('text-align', 'center') :css('font-size','15px') :wikitext('Success') :done :tag('th') :css('text-align', 'center') :css('font-size','15px') :wikitext('Sphere') :done :tag('th') :css('text-align', 'center') :css('font-size','15px') :wikitext('Diving Success') else htmltable:tag('tr') :css('background', '#313e55') :tag('th') :attr('colspan', colspan) :css('text-align', 'center') :css('font-size','15px') :wikitext('Stats' .. raceString) htmltable:tag('tr') :css('background', '#313e55') :tag('th') :css('text-align', 'center') :css('font-size','15px') :wikitext('Name') :done :tag('th') :css('text-align', 'center') :css('font-size','15px') :wikitext('Points') :done :tag('th') :css('text-align', 'center') :css('font-size','15px') :wikitext('Success') :done end -- Add stat rows p.addRow(htmltable, 'Strength', Str, 'Tzimtzvot', 'Elemental forces: Natural and elemental forces, electricity, light, kinetic energy, radiation, fire, etc.', 0, diving) p.addRow(htmltable, 'Dexterity', Dex, 'Noth', 'Physics: Variables that describe the universe; size, speed, weight, spacial location, time, etc.', 0, diving) p.addRow(htmltable, 'Speed', Spd, 'Konis', 'Weather and natural happenings: rain, snow, flooding, river flow, volcanoes, earthquakes, plate tectonics, oil deposit, tornados, etc.', 0, diving) p.addRow(htmltable, 'Endurance', End, 'Telazch', 'Biology: Life in all forms, poison, healing, disease, animals, plants, etc.', 0, diving) p.addRow(htmltable, 'Awareness', Awr, 'Akhmah', 'Mundane materials: natural, non-organic substances like chemical elements, water, stone, etc. Not things made by mankind or other sentient beings or living things.', 0, diving) p.addRow(htmltable, 'Cunning', Cun, 'Yengenze', 'Mind: The mind, consciousness, and the spark of life. Perception, emotion, skills, thoughts, understanding, dreams, memories, etc.', 0, diving) p.addRow(htmltable, 'Knowledge', Knw, 'Balarim', 'Technology: Anything which is unnatural and created with purpose; writing, spoken language, technology, art, tools.', 0, diving) p.addRow(htmltable, 'Nerve', Nrv, 'Dive Path', 'Travel between spheres, not going insane while diving', Pen, diving) -- Add racial trait row local specialRow = htmltable:tag('tr') :css('background', '#313e55') :tag('td') :attr('colspan', colspan) :css('text-align', 'left') :css('font-size', '12px') p.addSpecial(specialRow, 'Racial Traits', Adv, nil, nil) -- Then add any status effects on top of that if (args.statusEffects ~= nil) then local statusEffects = args.statusEffects if (type(statusEffects) == 'string') then mw.log('Converting [statusEffects=' .. statusEffects .. ']'); statusEffects = p.convertStatusEffects(statusEffects) mw.log('loaded: [statusEffects=' .. utils.tdump(statusEffects) .. ']') end for index, statusEffect in ipairs(statusEffects) do           p.addSpecial(specialRow, statusEffect.name, statusEffect.description, statusEffect.duration, statusEffect.helpfulness) end end -- Add the table to the retString retString = retString .. tostring(htmltable) -- Return the retString, after everything has been processed return retString end function p.createtable(frame) local args = {} --Load args from DB	args = utils.argsFromPlayer(frame.args.loadName, args, p.argDefs) --Override DB args from frame args args = utils.argsFromFrame(frame, args, p.argDefs) --Remember to preprocess everything before returning the string return frame:preprocess(p.createtableInternal(args)) end

function p.convertStatusEffects(statusEffects) local retTable = {} if string.match(statusEffects,'^{{') then statusEffects = string.sub(statusEffects,2,-2) end for statusEffect in string.gmatch(statusEffects,'{([^}]*)}') do       local statusTable = {} mw.log('Converting status effect [statusEffect=' .. statusEffect .. ']'); local fieldName = '' local fieldValue = '' local prevEscape = false local doingFieldName = true local ignoreChar = false local inString = false local foundString = false for c in string.gmatch(statusEffect, '.') do           --mw.log('Processing character [c=' .. c .. ', fieldName=' .. fieldName .. ', fieldValue=' .. fieldValue .. ', prevEscape=' .. tostring(prevEscape) .. ', doingFieldName=' .. tostring(doingFieldName) .. ', ignoreChar=' .. tostring(ignoreChar) .. ', inString=' .. tostring(inString) .. ', foundString=' .. tostring(foundString) .. ']'); --if this is escape, just write the char if(prevEscape) then prevEscape = false if(doingFieldName) then fieldName = fieldName .. c               else fieldValue = fieldValue .. c               end else --Else, this is not an escape, so we should check for special chars if (inString and c == '\\') then prevEscape = true elseif (c == '=' and not instring) then doingFieldName = false foundString = false elseif (c == '\'') then if(inString) then inString = false foundString = true else if(foundString) then error('duplicate string start [c=' .. c .. ', fieldName=' .. fieldName .. ', fieldValue=' .. fieldValue .. ', prevEscape=' .. tostring(prevEscape) .. ', doingFieldName=' .. tostring(doingFieldName) .. ', ignoreChar=' .. tostring(ignoreChar) .. ', inString=' .. tostring(inString) .. ', foundString=' .. tostring(foundString) .. ']') end inString = true end elseif (c == ' ' and not inString) then --simply ignore spaces elseif (c == ',' and not inString) then --we reached the end, add to values and reset if(foundString) then statusTable[fieldName]=fieldValue else statusTable[fieldName]=tonumber(fieldValue) end fieldName = '' fieldValue = '' prevEscape = false doingFieldName = true ignoreChar = false inString = false foundString = false elseif (foundString) then --invalid character, expected end of value after end of string error('expected end of value declaration [c=' .. c .. ', fieldName=' .. fieldName .. ', fieldValue=' .. fieldValue .. ', prevEscape=' .. tostring(prevEscape) .. ', doingFieldName=' .. tostring(doingFieldName) .. ', ignoreChar=' .. tostring(ignoreChar) .. ', inString=' .. tostring(inString) .. ', foundString=' .. tostring(foundString) .. ']') else if(doingFieldName) then fieldName = fieldName .. c                   else fieldValue = fieldValue .. c                   end end end end if(fieldName ~=  and fieldValue ~= ) then if(inString) then error('expected end of string [c=' .. c .. ', fieldName=' .. fieldName .. ', fieldValue=' .. fieldValue .. ', prevEscape=' .. tostring(prevEscape) .. ', doingFieldName=' .. tostring(doingFieldName) .. ', ignoreChar=' .. tostring(ignoreChar) .. ', inString=' .. tostring(inString) .. ', foundString=' .. tostring(foundString) .. ']') end if(foundString) then statusTable[fieldName]=fieldValue else statusTable[fieldName]=tonumber(fieldValue) end end mw.log('Inserting status to return list [statusTable=' .. utils.tdump(statusTable) .. ']') table.insert(retTable, statusTable) end mw.log('Finally got converted values [retTable=' .. utils.tdump(retTable) .. ']'); return retTable end return p