Difference between revisions of "Module:Apt"

From CrawlWiki
Jump to: navigation, search
(Add a function to calculate average aptitude of a given skill.)
m (Fix)
 
(38 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 
local p = {}
 
local p = {}
 +
 +
local data = mw.loadData('Module:Table of species')
 +
 +
local function name_arg(frame)
 +
  local name = frame.args[1]
 +
  if not name or name == "" then
 +
    name = mw.title.getCurrentTitle().text
 +
  end
 +
  return name
 +
end
 +
 +
local function is_colored_draconian(species)
 +
  return species:match(" Draconian$")
 +
end
 +
 +
local function is_obsolete(species)
 +
  return data[species].Obsolete or false
 +
end
 +
 +
local function is_obsolete_sk(skill)
 +
  return skill == "Charms" or skill == "Slings" or skill == "Bows" or skill == "Crossbows" or skill == "Stabbing" or skill == "Traps"
 +
end
 +
 +
local function is_spell_sk(skill)
 +
  return skill == "Spellcasting" or skill == "Conjurations" or skill == "Hexes" or skill == "Summonings" or skill == "Necromancy" or skill == "Translocations" or skill == "Fire Magic" or skill == "Ice Magic" or skill == "Air Magic" or skill == "Earth Magic" or skill == "Alchemy"
 +
end
 +
 +
local function species_sorted(include_obsolete)
 +
  include_obsolete = include_obsolete or false
 +
  local species = {}
 +
  for sp in pairs(data) do
 +
    if not is_colored_draconian(sp) and (include_obsolete or not is_obsolete(sp)) then
 +
      table.insert(species, sp)
 +
    end
 +
  end
 +
  table.sort(species)
 +
  return species
 +
end
 +
 +
local function skill_average(skill)
 +
  local count = 0
 +
  local sum = 0
 +
  for name, sp in pairs(data) do
 +
    if sp.Aptitudes[skill] and not is_colored_draconian(name) and name ~= "Gnoll" and (is_obsolete_sk(skill) or not is_obsolete(name)) and (name ~= "Djinni" or not is_spell_sk(skill)) then
 +
      count = count + 1
 +
      sum = sum + sp.Aptitudes[skill]
 +
    end
 +
  end
 +
  return string.format("%.3f", sum / count)
 +
end
 
   
 
   
 
function p.aptitude(frame)
 
function p.aptitude(frame)
  local data = mw.loadData('Module:Table of aptitudes')
 
 
   local sp = frame.args[1]
 
   local sp = frame.args[1]
 
   local sk = frame.args[2]
 
   local sk = frame.args[2]
Line 8: Line 57:
 
     return ""
 
     return ""
 
   end
 
   end
   return data[sp][sk]
+
   if sp == "Average" then
 +
    return skill_average(sk)
 +
  else
 +
    return data[sp].Aptitudes[sk] or "N/A"
 +
  end
 
end
 
end
  
 
function p.skill_table(frame)
 
function p.skill_table(frame)
   local data = mw.loadData('Module:Table of aptitudes')
+
   local browser_width = frame.args[2]
   local skill = frame.args[1]
+
  browser_width = tonumber(browser_width) or 50
   local species = {'Human', 'Centaur', 'Demigod', 'Demonspawn',
+
   local skill = name_arg(frame)
  'Draconian', 'Deep Dwarf', 'Deep Elf', 'High Elf',
+
  local headers = {}
  'Felid', 'Formicid', 'Gargoyle', 'Ghoul', 'Halfling', 'Kobold', 'Merfolk',  
+
   local species = species_sorted(is_obsolete_sk(skill))
  'Minotaur', 'Mummy', 'Naga', 'Octopode', 'Ogre', 'Hill Orc',
+
 
  'Spriggan', 'Tengu', 'Troll', 'Vampire', 'Vine Stalker'}
+
  local sp_headers_1 = {}
   local result = [=[
+
  local sp_headers_2 = {}
{| class="wikitable" border="1"
+
  for i, sp in ipairs(species) do
 +
    local header = ("'''[[%s|%s]]'''"):format(sp, data[sp].Abbrev)
 +
    if i<browser_width then
 +
      table.insert(sp_headers_1, header)
 +
    else
 +
      table.insert(sp_headers_2, header)
 +
    end
 +
  end
 +
 
 +
  local sk_headers_1 = {}
 +
  local sk_headers_2 = {}
 +
  for i, sp in ipairs(species) do
 +
    local header = ("%s"):format(data[sp].Aptitudes[skill] or "N/A")
 +
    if i<browser_width then
 +
      table.insert(sk_headers_1, header)
 +
    else
 +
      table.insert(sk_headers_2, header)
 +
    end
 +
  end
 +
 
 +
   local result = [[{| class="wikitable" border="1"
 
|-
 
|-
|'''[[Human|Hu]]'''
+
|]]
|'''[[Centaur|Ce]]'''
+
  result = result .. table.concat(sp_headers_1, "\n|")
|'''[[Demigod|Dg]]'''
+
  result = result .. "\n|-\n| "
|'''[[Demonspawn|Ds]]'''
+
  result = result .. table.concat(sk_headers_1, "\n| ")
|'''[[Draconian|Dr]]'''
+
  if next(sp_headers_2) then
|'''[[Deep Dwarf|DD]]
+
    result = result .. "\n|-\n|"
|'''[[Deep Elf|DE]]'''
+
    result = result .. table.concat(sp_headers_2, "\n|")
|'''[[High Elf|HE]]'''
+
     result = result .. "\n|-\n| "
|'''[[Felid|Fe]]'''
+
    result = result .. table.concat(sk_headers_2, "\n| ")
|'''[[Formicid|Fo]]'''
 
|'''[[Gargoyle|Gr]]'''
 
|'''[[Ghoul|Gh]]'''
 
|'''[[Halfling|Ha]]'''
 
|'''[[Kobold|Ko]]'''
 
|'''[[Merfolk|Mf]]'''
 
|'''[[Minotaur|Mi]]'''
 
|'''[[Mummy|Mu]]'''
 
|'''[[Naga|Na]]'''
 
|'''[[Octopode|Op]]'''
 
|'''[[Ogre|Og]]'''
 
|'''[[Hill Orc|HO]]'''
 
|'''[[Spriggan|Sp]]'''
 
|'''[[Tengu|Te]]'''
 
|'''[[Troll|Tr]]'''
 
|'''[[Vampire|Vp]]'''
 
|'''[[Vine Stalker|VS]]'''
 
|-
 
]=]
 
  for _, sp in ipairs(species) do
 
     result = result .. "| " .. data[sp][skill] .. "\n"
 
 
   end
 
   end
   result = result .. "|}"
+
   result = result .. "\n|}"
 
   return result
 
   return result
 
end
 
end
  
function p.skill_average(frame)
+
function p.skill_draconian_exceptions(frame)
   local data = mw.loadData('Module:Table of aptitudes')
+
   local skill = name_arg(frame)
   local skill = frame.args[1]
+
   local normal = data['Draconian'].Aptitudes[skill]
   local species = {'Human',  'Centaur', 'Demigod', 'Demonspawn',
+
   local result = ''
  'Draconian', 'Deep Dwarf', 'Deep Elf', 'High Elf',
+
   for name, species in pairs(data) do
  'Felid', 'Formicid', 'Gargoyle', 'Ghoul', 'Halfling', 'Kobold', 'Merfolk',
+
     if is_colored_draconian(name) and (is_obsolete_sk(skill) or not is_obsolete(name)) and species.Aptitudes[skill] ~= normal then
  'Minotaur', 'Mummy', 'Naga', 'Octopode', 'Ogre', 'Hill Orc',
+
      local col = name:match("^%a*")
  'Spriggan', 'Tengu', 'Troll', 'Vampire', 'Vine Stalker'}
+
      result = result .. '* [[Draconian#' .. col .. '|' .. col .. ' draconian]]s get ' .. species.Aptitudes[skill] .. '.\n'
  local sum = 0
+
    end
   for _, sp in ipairs(species) do
 
     sum = sum + data[sp][skill]
 
 
   end
 
   end
   return string.format("%.3f", sum / table.getn(species))
+
   return result
 
end
 
end
  
function p.aptitude_chart(skills, header)
+
local function aptitude_chart(skills, header)
  local data = mw.loadData('Module:Table of aptitudes')
 
  local species = {'Human',  'Centaur', 'Demigod', 'Demonspawn',
 
  'Draconian', 'Deep Dwarf', 'Deep Elf', 'High Elf',
 
  'Felid', 'Formicid', 'Gargoyle', 'Ghoul', 'Halfling', 'Kobold', 'Merfolk',
 
  'Minotaur', 'Mummy', 'Naga', 'Octopode', 'Ogre', 'Hill Orc',
 
  'Spriggan', 'Tengu', 'Troll', 'Vampire', 'Vine Stalker'}
 
 
   local result = header
 
   local result = header
  
Line 86: Line 130:
 
   local aa_ord = string.byte('A')
 
   local aa_ord = string.byte('A')
 
   -- generates the table keys
 
   -- generates the table keys
   function sort_key(i)
+
   local function sort_key(i)
 
     local result
 
     local result
 
     if i > z_ord - a_ord then
 
     if i > z_ord - a_ord then
Line 98: Line 142:
  
 
   local i = 0
 
   local i = 0
   for _, sp in ipairs(species) do
+
   for _, sp in ipairs(species_sorted()) do
 
     result = result .. '|<span style="display:none;">' .. sort_key(i) .. '</span>' .. sp .. "\n"
 
     result = result .. '|<span style="display:none;">' .. sort_key(i) .. '</span>' .. sp .. "\n"
     for _,sk in ipairs(skills) do
+
     for _, sk in ipairs(skills) do
       result = result .. "||" .. data[sp][sk] .. "\n"
+
       result = result .. "||" .. (data[sp].Aptitudes[sk] or "N/A") .. "\n"
 
     end
 
     end
 
     result = result .. "|-\n"
 
     result = result .. "|-\n"
Line 111: Line 155:
  
 
function p.aptitude_chart_general(frame)
 
function p.aptitude_chart_general(frame)
   local skills = {'Armour', 'Dodging', 'Stealth',
+
   local skills = {'Armour', 'Dodging',
  'Shields', 'Invocations', 'Evocations', 'Hit Points', 'Magic Points', 'Experience'}
+
  'Shields', 'Stealth', 'Invocations', 'Evocations', 'Shapeshifting', 'Hit Points', 'Magic Points', 'Experience'}
 
   local header = [=[
 
   local header = [=[
 
{| class="wikitable sortable" style="font-size:75%" border=1
 
{| class="wikitable sortable" style="font-size:75%" border=1
Line 118: Line 162:
 
! scope="col" | [[Armour (skill)|Arm]]
 
! scope="col" | [[Armour (skill)|Arm]]
 
! scope="col" | [[Dodging|Ddg]]
 
! scope="col" | [[Dodging|Ddg]]
 +
! scope="col" | [[Shields (skill)|Shd]]
 
! scope="col" | [[Stealth|Sth]]
 
! scope="col" | [[Stealth|Sth]]
! scope="col" | [[Shields (skill)|Shd]]
 
 
! scope="col" | [[Invocations|Inv]]
 
! scope="col" | [[Invocations|Inv]]
 
! scope="col" | [[Evocations|Evo]]
 
! scope="col" | [[Evocations|Evo]]
 +
! scope="col" | [[Shapeshifting|Shp]]
 
! scope="col" | [[HP]]
 
! scope="col" | [[HP]]
 
! scope="col" | [[MP]]
 
! scope="col" | [[MP]]
Line 127: Line 172:
 
|-
 
|-
 
]=]
 
]=]
   return p.aptitude_chart(skills, header)
+
   return aptitude_chart(skills, header)
 
end
 
end
  
 
function p.aptitude_chart_combat(frame)
 
function p.aptitude_chart_combat(frame)
   local skills = {'Fighting', 'Short Blades', 'Long Blades', 'Maces & Flails',
+
   local skills = {'Fighting', 'Maces & Flails',
   'Axes', 'Polearms', 'Staves', 'Unarmed Combat', 'Throwing', 'Slings', 'Bows', 'Crossbows'}
+
   'Axes', 'Polearms', 'Staves', 'Unarmed Combat', 'Throwing', 'Short Blades', 'Long Blades', 'Ranged Weapons'}
 
   local header = [=[
 
   local header = [=[
 
{| class="wikitable sortable" style="font-size:75%" border=1
 
{| class="wikitable sortable" style="font-size:75%" border=1
 
! scope="col" | [[Species]]
 
! scope="col" | [[Species]]
 
! scope="col" | [[Fighting|Fgt]]
 
! scope="col" | [[Fighting|Fgt]]
! scope="col" | [[Short Blades|SBl]]
 
! scope="col" | [[Long Blades|LBl]]
 
 
! scope="col" | [[Maces &amp; Flails|M&amp;F]]
 
! scope="col" | [[Maces &amp; Flails|M&amp;F]]
 
! scope="col" | [[Axes|Axs]]
 
! scope="col" | [[Axes|Axs]]
Line 145: Line 188:
 
! scope="col" | [[Unarmed Combat|UC]]
 
! scope="col" | [[Unarmed Combat|UC]]
 
! scope="col" | [[Throwing|Thr]]
 
! scope="col" | [[Throwing|Thr]]
! scope="col" | [[Slings|Slg]]
+
! scope="col" | [[Short Blades|SBl]]
! scope="col" | [[Bows|Bws]]
+
! scope="col" | [[Long Blades|LBl]]
! scope="col" | [[Crossbows|Crb]]
+
! scope="col" | [[Ranged Weapons|RW]]
 
|-
 
|-
 
]=]
 
]=]
   return p.aptitude_chart(skills, header)
+
   return aptitude_chart(skills, header)
 
end
 
end
  
 
function p.aptitude_chart_magic(frame)
 
function p.aptitude_chart_magic(frame)
   local skills = {'Spellcasting', 'Conjurations', 'Hexes', 'Charms',
+
   local skills = {'Spellcasting', 'Conjurations', 'Hexes',
   'Summonings', 'Necromancy', 'Translocations', 'Transmutations',  
+
   'Summonings', 'Necromancy', 'Translocations', 'Alchemy',  
   'Fire Magic', 'Ice Magic', 'Air Magic', 'Earth Magic', 'Poison Magic'}
+
   'Fire Magic', 'Ice Magic', 'Air Magic', 'Earth Magic'}
 
   local header = [=[
 
   local header = [=[
 
{| class="wikitable sortable" style="font-size:75%" border=1
 
{| class="wikitable sortable" style="font-size:75%" border=1
Line 163: Line 206:
 
! scope="col" | [[Conjurations|Coj]]
 
! scope="col" | [[Conjurations|Coj]]
 
! scope="col" | [[Hexes|Hex]]
 
! scope="col" | [[Hexes|Hex]]
! scope="col" | [[Charms|Cha]]
 
 
! scope="col" | [[Summonings|Sum]]
 
! scope="col" | [[Summonings|Sum]]
 
! scope="col" | [[Necromancy|Nec]]
 
! scope="col" | [[Necromancy|Nec]]
 
! scope="col" | [[Translocations|Trl]]
 
! scope="col" | [[Translocations|Trl]]
! scope="col" | [[Transmutations|Trm]]
+
! scope="col" | [[Alchemy|Alc]]
 
! scope="col" | [[Fire Magic|Fir]]
 
! scope="col" | [[Fire Magic|Fir]]
 
! scope="col" | [[Ice Magic|Ice]]
 
! scope="col" | [[Ice Magic|Ice]]
 
! scope="col" | [[Air Magic|Air]]
 
! scope="col" | [[Air Magic|Air]]
 
! scope="col" | [[Earth Magic|Ear]]
 
! scope="col" | [[Earth Magic|Ear]]
! scope="col" | [[Poison Magic|Poi]]
 
 
|-
 
|-
 
]=]
 
]=]
   return p.aptitude_chart(skills, header)
+
   return aptitude_chart(skills, header)
 
end
 
end
  
 
return p
 
return p

Latest revision as of 14:55, 21 February 2024

Documentation for this module may be created at Module:Apt/doc

local p = {}

local data = mw.loadData('Module:Table of species')

local function name_arg(frame)
  local name = frame.args[1]
  if not name or name == "" then
    name = mw.title.getCurrentTitle().text
  end
  return name
end

local function is_colored_draconian(species)
  return species:match(" Draconian$")
end

local function is_obsolete(species)
  return data[species].Obsolete or false
end

local function is_obsolete_sk(skill)
  return skill == "Charms" or skill == "Slings" or skill == "Bows" or skill == "Crossbows" or skill == "Stabbing" or skill == "Traps"
end

local function is_spell_sk(skill)
  return skill == "Spellcasting" or skill == "Conjurations" or skill == "Hexes" or skill == "Summonings" or skill == "Necromancy" or skill == "Translocations" or skill == "Fire Magic" or skill == "Ice Magic" or skill == "Air Magic" or skill == "Earth Magic" or skill == "Alchemy"
end

local function species_sorted(include_obsolete)
  include_obsolete = include_obsolete or false
  local species = {}
  for sp in pairs(data) do
    if not is_colored_draconian(sp) and (include_obsolete or not is_obsolete(sp)) then
      table.insert(species, sp)
    end
  end
  table.sort(species)
  return species
end

local function skill_average(skill)
  local count = 0
  local sum = 0
  for name, sp in pairs(data) do
    if sp.Aptitudes[skill] and not is_colored_draconian(name) and name ~= "Gnoll" and (is_obsolete_sk(skill) or not is_obsolete(name)) and (name ~= "Djinni" or not is_spell_sk(skill)) then
      count = count + 1
      sum = sum + sp.Aptitudes[skill]
    end
  end
  return string.format("%.3f", sum / count)
end
 
function p.aptitude(frame)
  local sp = frame.args[1]
  local sk = frame.args[2]
  if not sp or not sk then
    return ""
  end
  if sp == "Average" then
    return skill_average(sk)
  else
    return data[sp].Aptitudes[sk] or "N/A"
  end
end

function p.skill_table(frame)
  local browser_width = frame.args[2]
  browser_width = tonumber(browser_width) or 50
  local skill = name_arg(frame)
  local headers = {}
  local species = species_sorted(is_obsolete_sk(skill))

  local sp_headers_1 = {}
  local sp_headers_2 = {}
  for i, sp in ipairs(species) do
    local header = ("'''[[%s|%s]]'''"):format(sp, data[sp].Abbrev)
    if i<browser_width then
      table.insert(sp_headers_1, header)
    else
      table.insert(sp_headers_2, header)
    end
  end
  
  local sk_headers_1 = {}
  local sk_headers_2 = {}
  for i, sp in ipairs(species) do
    local header = ("%s"):format(data[sp].Aptitudes[skill] or "N/A")
    if i<browser_width then
      table.insert(sk_headers_1, header)
    else
      table.insert(sk_headers_2, header)
    end
  end

  local result = [[{| class="wikitable" border="1"
|-
|]]
  result = result .. table.concat(sp_headers_1, "\n|")
  result = result .. "\n|-\n| "
  result = result .. table.concat(sk_headers_1, "\n| ")
  if next(sp_headers_2) then
    result = result .. "\n|-\n|"
    result = result .. table.concat(sp_headers_2, "\n|")
    result = result .. "\n|-\n| "
    result = result .. table.concat(sk_headers_2, "\n| ")
  end
  result = result .. "\n|}"
  return result
end

function p.skill_draconian_exceptions(frame)
  local skill = name_arg(frame)
  local normal = data['Draconian'].Aptitudes[skill]
  local result = ''
  for name, species in pairs(data) do
    if is_colored_draconian(name) and (is_obsolete_sk(skill) or not is_obsolete(name)) and species.Aptitudes[skill] ~= normal then
      local col = name:match("^%a*")
      result = result .. '* [[Draconian#' .. col .. '|' .. col .. ' draconian]]s get ' .. species.Aptitudes[skill] .. '.\n'
    end
  end
  return result
end

local function aptitude_chart(skills, header)
  local result = header

  -- constants used by sort_key
  local a_ord = string.byte('a')
  local z_ord = string.byte('z')
  local aa_ord = string.byte('A')
  -- generates the table keys
  local function sort_key(i)
    local result
    if i > z_ord - a_ord then
      i = i - (z_ord - a_ord) - 1
      result = '!' .. string.char(aa_ord + i)
    else
      result = '"' .. string.char(a_ord + i)
    end
    return result
  end

  local i = 0
  for _, sp in ipairs(species_sorted()) do
    result = result .. '|<span style="display:none;">' .. sort_key(i) .. '</span>' .. sp .. "\n"
    for _, sk in ipairs(skills) do
      result = result .. "||" .. (data[sp].Aptitudes[sk] or "N/A") .. "\n"
    end
    result = result .. "|-\n"
    i = i + 1
  end
  result = result .. "|}"
  return result
end

function p.aptitude_chart_general(frame)
  local skills = {'Armour', 'Dodging',
   'Shields', 'Stealth', 'Invocations', 'Evocations', 'Shapeshifting', 'Hit Points', 'Magic Points', 'Experience'}
  local header = [=[
{| class="wikitable sortable" style="font-size:75%" border=1
! scope="col" | [[Species]]
! scope="col" | [[Armour (skill)|Arm]]
! scope="col" | [[Dodging|Ddg]]
! scope="col" | [[Shields (skill)|Shd]]
! scope="col" | [[Stealth|Sth]]
! scope="col" | [[Invocations|Inv]]
! scope="col" | [[Evocations|Evo]]
! scope="col" | [[Shapeshifting|Shp]]
! scope="col" | [[HP]]
! scope="col" | [[MP]]
! scope="col" | [[Exp]]
|-
]=]
  return aptitude_chart(skills, header)
end

function p.aptitude_chart_combat(frame)
  local skills = {'Fighting', 'Maces & Flails',
   'Axes', 'Polearms', 'Staves', 'Unarmed Combat', 'Throwing', 'Short Blades', 'Long Blades', 'Ranged Weapons'}
  local header = [=[
{| class="wikitable sortable" style="font-size:75%" border=1
! scope="col" | [[Species]]
! scope="col" | [[Fighting|Fgt]]
! scope="col" | [[Maces &amp; Flails|M&amp;F]]
! scope="col" | [[Axes|Axs]]
! scope="col" | [[Polearms|Pla]]
! scope="col" | [[Staves|Stv]]
! scope="col" | [[Unarmed Combat|UC]]
! scope="col" | [[Throwing|Thr]]
! scope="col" | [[Short Blades|SBl]]
! scope="col" | [[Long Blades|LBl]]
! scope="col" | [[Ranged Weapons|RW]]
|-
]=]
  return aptitude_chart(skills, header)
end

function p.aptitude_chart_magic(frame)
  local skills = {'Spellcasting', 'Conjurations', 'Hexes',
   'Summonings', 'Necromancy', 'Translocations', 'Alchemy', 
   'Fire Magic', 'Ice Magic', 'Air Magic', 'Earth Magic'}
  local header = [=[
{| class="wikitable sortable" style="font-size:75%" border=1
! scope="col" | [[Species]]
! scope="col" | [[Spellcasting|Spc]]
! scope="col" | [[Conjurations|Coj]]
! scope="col" | [[Hexes|Hex]]
! scope="col" | [[Summonings|Sum]]
! scope="col" | [[Necromancy|Nec]]
! scope="col" | [[Translocations|Trl]]
! scope="col" | [[Alchemy|Alc]]
! scope="col" | [[Fire Magic|Fir]]
! scope="col" | [[Ice Magic|Ice]]
! scope="col" | [[Air Magic|Air]]
! scope="col" | [[Earth Magic|Ear]]
|-
]=]
  return aptitude_chart(skills, header)
end

return p