Module:Rates: Difference between revisions

From Ephinea PSO Wiki
No edit summary
No edit summary
 
(56 intermediate revisions by 2 users not shown)
Line 1: Line 1:
-- <nowiki>
--
-- Formats drop rates and calculates two rates multiplied together (usually DAR and RDR)
--
local p = {}
local p = {}


-- Every DAR/RDR fraction between 1/2 and 1/1
local wholeFractions =
local wholeFractions =
{
{
Line 7: Line 13:
   [0.875] = "7/8",
   [0.875] = "7/8",
   [0.85] = "17/20",
   [0.85] = "17/20",
  [0.7] = "7/10",
   [0.8] = "4/5",
   [0.8] = "4/5",
   [0.6] = "3/5",
   [0.6] = "3/5",
   [0.5625] = "9/16",
   [0.5625] = "9/16",
   [0.55] = "9/20",
   [0.55] = "9/20",
  [0.50625] = "81/160",
   [0.5] = "1/2"
   [0.5] = "1/2"
}
}


function p.calcRate(frame)
--
   return frame.args[1]*frame.args[2]
-- Multiply a DAR and RDR together. Any number works but it's basically just for those
--
-- @param dar {number}
-- @param rdr {number}
-- @return {number}
--
local function calcRate(dar, rdr)
  local mult = {}
  mult[1] = dar
  mult[2] = rdr
  -- Initialize numbers for string conversion
  local frac = {}
  frac[1] = {}
  frac[2] = {}
  -- If either number is a fraction, split it up into numerator and denominator
  -- Thanks, Ender!
  for i=1,2,1 do
    for number in string.gmatch(mult[i], '([^/]+)') do
      table.insert(frac[i], number)
    end
    -- If either number wasn't a fraction, fill 1 in for its denominator
    if frac[i][2] == nil then
      frac[i][2] = 1
    end
  end
   return (frac[1][1]/frac[1][2])*(frac[2][1]/frac[2][2])
end
end


local function trimRate(rate, fmt, digits)
--
-- Number formatting. Pass in a number in either fraction, decimal, or whole format and convert it.
--
-- @param rate {string}
-- @param fmt {string} -- "f" for fraction, "p" for percent, "n" for both fraction and percent used in the Note template
-- @param digits {number} -- optional
-- @return {string}
--
local function fmtRate(rate, fmt, digits)
   local out = ""
   local out = ""
   if digits == nil then
  local frac = {}
     digits = 0
  -- If either number is a fraction, split it up into numerator and denominator
  -- Thanks, Ender!
  for number in string.gmatch(rate, '([^/]+)') do
    table.insert(frac, number)
  end
  -- If either number wasn't a fraction, fill 1 in for its denominator
   if frac[2] == nil then
     frac[2] = 1
   end
   end
  local num = frac[1]
  local den = frac[2]
  -- Turn rate into a number!
  rate = num / den
   if fmt == "f" then
   if fmt == "f" then
     if rate < 10 then
     if wholeFractions[rate] == nil then
      digits = math.max(digits, 2)
      if not digits then
    elseif rate < 100 then
        digits = 0
      digits = math.max(digits, 1)
      end
      -- Set maximum number of decimal places
      if 1/rate < 10 then
        -- Displays with two places between 1.01 ~ 9.99
        digits = math.max(digits, 2)
      elseif 1/rate < 100 then
        -- Displays with one place between 10.1 ~ 99.9
        digits = math.max(digits, 1)
      end
      -- Even if we're displaying one or more decimal places, cut zeroes off
      out = string.format("1/%." .. digits .. "f", 1/rate)
      return out:gsub("%.0+$", "")
     else
     else
       digits = math.max(digits, 0)
       out = wholeFractions[rate]
     end
     end
    out = out .. string.format("%f", string.format(" %." .. digits .. "f", rate)):gsub("%.?0+$", "")
     return out
     return out
   elseif fmt == "p" then
   elseif fmt == "p" then
     rate = string.format("%f", string.format(" %.5f", rate)):gsub("%.?0+$", "")
     -- Display up to five decimal places. Cut zeroes off
     out = out .. rate
    out = string.format("%.5f", rate * 100)
     return out
    if string.find(out, "%.") then
    out = string.gsub(out, "%.0+$", "")
     end
     return string.format("%s%%", out)
   end
   end
end
end


--
-- Rate display accessed through #invoke. Display up to TWO rates plus their combination!
--
-- @param frame {table}
-- @return {string}
--
function p.displayRate(frame)
function p.displayRate(frame)
   local rate = frame.args[1]
  -- Separate the format (strings) from the rates (numbers passed in as strings).
   local fmt = frame.args[2]
   local fmt = frame.args[1]
   local digits = frame.args[3]
   local rate = {}
  rate[1] = frame.args[2]
   if frame.args[3] == nil then
    rate[2] = 1
  else
    rate[2] = frame.args[3]
  end
  if rate[1] == "0" or rate[2] == "0" then
    return nil
  end
   local out = ""
   local out = ""
   if fmt == "f" then
   if fmt == "f" then
     if wholeFractions[rate] == nil then
     -- Fraction
      out = out .. string.format("1/%s", trimRate(1/rate, "f", digits))
    out = out .. fmtRate(rate[1], "f")
     else
  elseif fmt == "p" then
      out = out .. wholeFractions[rate]
     -- Percentage
    end
    out = out .. fmtRate(rate[1], "p")
  end
   elseif fmt == "n" then
   if fmt == "p" then
     -- Fraction with hover text showing first two input rates as Fraction (Percentage)
     out = out .. string.format("%s%%", trimRate(rate*100, "p"))
    local span = mw.html.create("span")
  end
    span
  if fmt == "n" then
      :addClass("more_info")
     out = out .. p.displayRate(rate, "f", 2) .. " (" .. p.displayRate(rate, "p") .. ")"
      :attr("title", string.format("Drop Rate: %s (%s), Rare Rate: %s (%s)", fmtRate(rate[1], "f"), fmtRate(rate[1], "p"), fmtRate(rate[2], "f", 2), fmtRate(rate[2], "p")))
      :css("border-bottom", "1px dotted")
      :wikitext(string.format("%s", fmtRate(calcRate(rate[1], rate[2]), "f")))
     --out = out .. fmtRate(rate, "f", 2) .. " (" .. fmtRate(rate, "p") .. ")"  
    return span:allDone()
   end
   end
   return out
   return out
Line 62: Line 146:


return p
return p
-- </nowiki>

Latest revision as of 14:17, 12 June 2023

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

-- <nowiki>
--
-- Formats drop rates and calculates two rates multiplied together (usually DAR and RDR)
--

local p = {}

-- Every DAR/RDR fraction between 1/2 and 1/1
local wholeFractions =
{
  [0.9] = "9/10",
  [0.88] = "22/25",
  [0.875] = "7/8",
  [0.85] = "17/20",
  [0.7] = "7/10",
  [0.8] = "4/5",
  [0.6] = "3/5",
  [0.5625] = "9/16",
  [0.55] = "9/20",
  [0.50625] = "81/160",
  [0.5] = "1/2"
}

--
-- Multiply a DAR and RDR together. Any number works but it's basically just for those
--
-- @param dar {number}
-- @param rdr {number}
-- @return {number}
--
local function calcRate(dar, rdr)
  local mult = {}
  mult[1] = dar
  mult[2] = rdr
  -- Initialize numbers for string conversion
  local frac = {}
  frac[1] = {}
  frac[2] = {}
  -- If either number is a fraction, split it up into numerator and denominator
  -- Thanks, Ender!
  for i=1,2,1 do
    for number in string.gmatch(mult[i], '([^/]+)') do
      table.insert(frac[i], number)
    end
    -- If either number wasn't a fraction, fill 1 in for its denominator
    if frac[i][2] == nil then
      frac[i][2] = 1
    end
  end
  return (frac[1][1]/frac[1][2])*(frac[2][1]/frac[2][2])
end

--
-- Number formatting. Pass in a number in either fraction, decimal, or whole format and convert it.
--
-- @param rate {string}
-- @param fmt {string} -- "f" for fraction, "p" for percent, "n" for both fraction and percent used in the Note template
-- @param digits {number} -- optional
-- @return {string}
--
local function fmtRate(rate, fmt, digits)
  local out = ""
  local frac = {}
  -- If either number is a fraction, split it up into numerator and denominator
  -- Thanks, Ender!
  for number in string.gmatch(rate, '([^/]+)') do
    table.insert(frac, number)
  end
  -- If either number wasn't a fraction, fill 1 in for its denominator
  if frac[2] == nil then
    frac[2] = 1
  end
  local num = frac[1]
  local den = frac[2]
  -- Turn rate into a number!
  rate = num / den
  if fmt == "f" then
    if wholeFractions[rate] == nil then
      if not digits then
        digits = 0
      end
      -- Set maximum number of decimal places
      if 1/rate < 10 then
        -- Displays with two places between 1.01 ~ 9.99
        digits = math.max(digits, 2)
      elseif 1/rate < 100 then
        -- Displays with one place between 10.1 ~ 99.9
        digits = math.max(digits, 1)
      end
      -- Even if we're displaying one or more decimal places, cut zeroes off
      out = string.format("1/%." .. digits .. "f", 1/rate)
      return out:gsub("%.0+$", "")
    else
      out = wholeFractions[rate]
    end
    return out
  elseif fmt == "p" then
    -- Display up to five decimal places. Cut zeroes off
    out = string.format("%.5f", rate * 100)
    if string.find(out, "%.") then
    	out = string.gsub(out, "%.0+$", "")
    end
    return string.format("%s%%", out)
  end
end

--
-- Rate display accessed through #invoke. Display up to TWO rates plus their combination!
--
-- @param frame {table}
-- @return {string}
--
function p.displayRate(frame)
  -- Separate the format (strings) from the rates (numbers passed in as strings).
  local fmt = frame.args[1]
  local rate = {}
  rate[1] = frame.args[2]
  if frame.args[3] == nil then
    rate[2] = 1
  else
    rate[2] = frame.args[3]
  end
  if rate[1] == "0" or rate[2] == "0" then
    return nil
  end
  local out = ""
  if fmt == "f" then
    -- Fraction
    out = out .. fmtRate(rate[1], "f")
  elseif fmt == "p" then
    -- Percentage
    out = out .. fmtRate(rate[1], "p")
  elseif fmt == "n" then
    -- Fraction with hover text showing first two input rates as Fraction (Percentage)
    local span = mw.html.create("span")
    span
      :addClass("more_info")
      :attr("title", string.format("Drop Rate: %s (%s), Rare Rate: %s (%s)", fmtRate(rate[1], "f"), fmtRate(rate[1], "p"), fmtRate(rate[2], "f", 2), fmtRate(rate[2], "p")))
      :css("border-bottom", "1px dotted")
      :wikitext(string.format("%s", fmtRate(calcRate(rate[1], rate[2]), "f")))
    --out = out .. fmtRate(rate, "f", 2) .. " (" .. fmtRate(rate, "p") .. ")" 
    return span:allDone()
  end
  return out
end

return p
-- </nowiki>