Anonymous

Module:Sandbox/AuronTest: Difference between revisions

From Melvor Idle
0.21 Special attack description handling
mNo edit summary
(0.21 Special attack description handling)
Line 71: Line 71:
   return result
   return result
end
end


function p.getItemByID(ID)
function p.getItemByID(ID)
Line 304: Line 306:
     result = result.."\r\n|-\r\n|'''Special Attack:'''"
     result = result.."\r\n|-\r\n|'''Special Attack:'''"
     result = result..'\r\n* '..spAtt.chance..'% chance for '..spAtt.name..':'
     result = result..'\r\n* '..spAtt.chance..'% chance for '..spAtt.name..':'
     result = result..'\r\n** '..spAtt.description
     result = result..'\r\n** '..p._getSpecialAttackDescription(spAtt)
   end
   end
   --For potions, show the number of charges
   --For potions, show the number of charges
Line 404: Line 406:
     result = result..'\r\n|data-sort-value="'..spAttData.sortName..'"|'..table.concat(spAttData.Icons, '<br/>')
     result = result..'\r\n|data-sort-value="'..spAttData.sortName..'"|'..table.concat(spAttData.Icons, '<br/>')
     result = result..'||'..spAtt.name..'||data-sort-value="'..spAtt.chance..'"|'..spAtt.chance..'%'
     result = result..'||'..spAtt.name..'||data-sort-value="'..spAtt.chance..'"|'..spAtt.chance..'%'
     result = result..'||'..spAtt.description
     result = result..'||'..p._getSpecialAttackDescription(spAtt)
   end
   end
   result = result..'\r\n|}'
   result = result..'\r\n|}'
Line 410: Line 412:
   return result
   return result
end
end
local nouns = {
  ["player"] = {
    ["plain"] = "you",
    ["possesive"] = "your",
    ["pronoun"] = "you",
    ["is"] = "are"
  },
  ["enemy"] = {
    ["plain"] = "the enemy",
    ["possesive"] = "the enemy's",
    ["pronoun"] = "they",
    ["is"] = "is"
  }
}
-- Generates a textual description from a special attack's damage attribute
-- Similar to in game function getDamageDescription in attack.js
function p._getDamageDescription(damageList, attName, tarName)
  local rollData = {
    ["CurrentHP"] = {
      ["formatPercent"] = function(value) return Shared.round(value, 2, 0) .. '%' end,
      ["formatName"] = function(name) return ' of ' .. name .. ' current hitpoints' end
    },
    ["MaxHP"] = {
      ["formatPercent"] = function(value) return Shared.round(value, 2, 0) .. '%' end,
      ["formatName"] = function(name) return ' of ' .. name .. ' max hitpoints' end
    },
    ["DamageDealt"] = {
      ["formatPercent"] = function(value) return Shared.round(value, 2, 0) .. '%' end,
      ["formatName"] = function(name) return ' of the damage dealt' end
    },
    ["MaxHit"] = {
      ["formatPercent"] = function(value) return Shared.round(value, 2, 0) .. '%' end,
      ["formatName"] = function(name) return ' of ' .. name .. ' max hit' end
    },
    ["MinHit"] = {
      ["formatPercent"] = function(value) return Shared.round(value, 2, 0) .. '%' end,
      ["formatName"] = function(name) return ' of ' .. name .. ' min hit' end
    },
    ["Fixed"] = {
      ["formatPercent"] = function(value) return Shared.formatnum(math.floor(value * 10)) end,
      ["formatName"] = function(name) return '' end
    },
    ["MagicScaling"] = {
      ["formatPercent"] = function(value) return Shared.round(value, 0, 0) .. '%' end,
      ["formatName"] = function(name) return ' of ' .. name .. ' current hitpoints' end
    },
    ["One"] = {
      ["formatPercent"] = function(value) return '1' end,
      ["formatName"] = function(name) return '' end
    },
    ["Rend"] = {
      ["formatPercent"] = function(value) return Shared.round(value, 2, 0) .. '% if the target has full HP, otherwise 250%' end,
      ["formatName"] = function(name) return ' of the damage dealt' end
    },
  }
  local descPart = {}
  for i, damage in ipairs(damageList) do
    local name = 'Unknown'
    if damage.character == 'Attacker' then
      name = nouns[attName]['possesive']
    elseif damage.character == 'Target' then
      name = nouns[tarName]['possesive']
    end
    local maxData = rollData[damage['maxRoll']]
    local desc = ''
    if damage.roll then
      local minData = rollData[damage['minRoll']]
      if damage['maxRoll'] == damage['minRoll'] then
        -- Same damage type for max & min
        desc = minData.formatPercent(damage['minPercent']) .. '-' .. maxData.formatPercent(damage['maxPercent']) .. minData.formatName(name)
      elseif damage['maxRoll'] == 'MaxHit' and damage['minRoll'] == 'MinHit' and damage['maxPercent'] == damage['minPercent'] then
        desc = maxData.formatPercent(damage['maxPercent']) .. ' of ' .. name .. ' normal damage'
      else
        desc = minData.formatPercent(damage['minPercent']) .. minData.formatName(name) .. ' to ' .. maxData.formatPercent(damage['maxPercent']) .. maxData.formatName(name)
      end
    else
      desc = maxData.formatPercent(damage['maxPercent']) .. maxData.formatName(name)
    end
    table.insert(descPart, desc)
  end
  return Shared.joinList(descPart, ', ', ' and ')
end
function p._getEffectDescription(effectList, attName, tarName)
  local getAllModText = function(modifierList, doColor)
                          local returnPart = {}
                          for modName, val in pairs(modifierList) do
                            table.insert(returnPart, Constants._getModifierText(modName, val, doColor))
                          end
                          return Shared.joinList(returnPart, ', ', ' and ')
                        end
  local descPart = {}
  for i, effect in ipairs(effectList) do
    local desc = ''
    if effect['type'] == 'DOT' then
      local damageDesc = p._getDamageDescription(effect['damage'], attName, tarName)
      local parts = nil
      if effect['subtype'] == 'Regen' then
        parts = {'give', 'heals', ''}
      else
        parts = {'inflict', 'deals', 'as damage '}
      end
      if effect['chance'] < 100 then
          desc = 'has a ' .. Shared.round(effect['chance'], 2, 0) .. '% chance to ' .. parts[1] .. ' ' .. effect['subtype'] .. ' '
      else
          desc = parts[1] .. 's ' .. effect['subtype'] .. ' '
      end
      desc = desc .. 'that ' .. parts[2] .. ' ' .. damageDesc .. ' ' .. parts[3] .. 'over ' .. Shared.round(effect['procs'] * effect['interval'] / 1000, 2, 0) .. 's'
    elseif effect['type'] == 'Reflexive' then
      local modDesc = getAllModText(effect.modifiers, false)
      desc = 'gives ' .. nouns[attName]['plain'] .. ' ' .. modDesc .. ' each time ' .. nouns[attName]['pronoun'] .. ' are hit for the duration of this attack (Stacks up to ' .. Shared.formatnum(math.floor(effect['maxStacks'])) .. ' times)'
    elseif effect['type'] == 'Stacking' then
      local modDesc = getAllModText(effect.modifiers, false)
      desc = 'applies +' .. Shared.formatnum(math.floor(effect['stacksToAdd'])) .. ' stack' .. (effect['stacksToAdd'] > 1 and 's' or '') .. ' of ' .. effect['name'] .. ' to ' .. nouns[tarName]['plain']
      desc = desc .. ' (Max ' .. Shared.formatnum(math.floor(effect['maxStacks'])) .. ' stack' .. (effect['maxStacks'] > 1 and 's' or '') .. '). ' .. effect['name'] .. ' gives ' .. modDesc .. ' regardless of number of stacks. One stack is removed after each of the ' .. nouns[tarName]['possesive'] .. ' turns'
    elseif effect['type'] == 'Modifier' then
      local modDesc = getAllModText(effect.modifiers, false)
      local name = effect['character'] == 'Attacker' and attName or tarName
      local countName = effect['countsOn'] == 'Attacker' and attName or tarName
      desc = 'gives ' .. nouns[name]['plain'] .. ' ' .. modDesc
      if effect['maxStacks'] > 1 then
        desc = desc .. ' that stacks up to ' .. Shared.formatnum(math.floor(effect['maxStacks'])) .. ' times'
      elseif effect['turns'] == nil then
        -- Take a nil turns value to mean Infinity, as in JS JSON.Stringify() converts Infinity to null
        -- This assumption will potentially cause issues in the future
        desc = desc .. ' until the end of the fight'
      elseif effect['turns'] > 0 then
        desc = desc .. ' for ' .. Shared.formatnum(math.floor(effect['turns'])) .. ' of ' .. nouns[countName]['possesive'] .. ' turn' .. (effect['turns'] > 1 and 's' or '')
      else
        desc = desc .. ' until the end of the attack'
      end
    elseif effect['type'] == 'Sleep' or effect['type'] == 'Stun' then
      local effName = (effect['type'] == 'Sleep' and 'sleep' or string.gsub(effect['flavour'], '^(%a)', function(c) return string.lower(c) end))
      if effect['chance'] < 100 then
        desc = 'has a ' .. Shared.round(effect['chance'], 2, 0) .. '%' .. ' chance to apply ' .. effName
      else
        desc = 'applies ' .. effName
      end
      desc = desc .. ' for ' .. Shared.formatnum(math.floor(effect['turns'])) .. ' turn' .. (effect['turns'] > 1 and 's' or '')
    else
      desc = 'Unknown effect type: ' .. effect['type'] .. '[[Category:Pages with script errors]]'
    end
    table.insert(descPart, desc)
  end
  return Shared.joinList(descPart, '; ', ' and ')
end
-- Generates a textual description for a special attack
-- Similar to in game function describeAttack in attack.js
function p._getSpecialAttackDescription(attack, targetIsEnemy)
  local attackDescriptors = {
    ["count"] = function(attack, attName, tarName) return attack['attackCount'] end,
    ["damage"] = function(attack, attName, tarName) return p._getDamageDescription(attack['damage'], attName, tarName) end,
    ["lifesteal"] = function(attack, attName, tarName) return Shared.round(attack['lifesteal'], 2, 0) .. '%' end,
    ["target"] = function(attack, attName, tarName) return nouns[tarName]['plain'] end,
    ["attacker"] = function(attack, attName, tarName) return nouns[attName]['plain'] end,
    ["tarPos"] = function(attack, attName, tarName) return nouns[tarName]['possesive'] end,
    ["attPos"] = function(attack, attName, tarName) return nouns[attName]['possesive'] end,
    ["prehitEffect"] = function(attack, attName, tarName) return p._getEffectDescription(attack['prehitEffects'], attName, tarName) end,
    ["hitEffect"] = function(attack, attName, tarName) return p._getEffectDescription(attack['onhitEffects'], attName, tarName) end,
    ["canMiss"] = function(attack, attName, tarName) return attack['cantMiss'] and "can't miss" or "can miss" end,
    ["avoidable"] = function(attack, attName, tarName) return attack['cantMiss'] and "unavoidable" or "avoidable" end,
    ["duration"] = function(attack, attName, tarName) return Shared.round((attack['attackCount'] - 1) * attack['attackInterval'] / 1000, 2, 0) .. 's' end,
    ["interval"] = function(attack, attName, tarName) return Shared.round(attack['attackInterval'] / 1000, 2, 0) .. 's' end,
    ["tarIs"] = function(attack, attName, tarName) return nouns[tarName]['is'] end,
    ["attIs"] = function(attack, attName, tarName) return nouns[attName]['is'] end,
  }
  -- string.gsub() searches for a pattern rather than a literal and is case sensitive, so use the below to:
  -- 1. Escape any characters that have special meanings within patterns
  -- 2. Modify the pattern to be case insensitive (by replacing each alpha char with a class containing
  --    both the uppercase & lowercase characters)
  local patternFormat = function(str, caseInsensitive)
                          local pat = string.gsub(str, '[%(%)%.%%+%-%*%?%[%]%^%$]', function(c) return '%' .. c end)
                          if caseInsensitive then pat = string.gsub(pat, '(%a)', function(c) return '[' .. string.upper(c) .. string.lower(c) .. ']' end) end
                          return pat
                        end
  local attackDesc = attack['description']
  local attName, tarName = targetIsEnemy and 'player' or 'enemy', targetIsEnemy and 'enemy' or 'player'
  for desc, repFunc in pairs(attackDescriptors) do
    local searchPat = '<' .. patternFormat(desc, true) .. '>'
    if string.find(attackDesc, searchPat) ~= nil then
      local repText = repFunc(attack, attName, tarName)
      repText = patternFormat(string.upper(string.sub(repText, 1, 1)) .. string.sub(repText, 2))
      attackDesc = string.gsub(attackDesc, searchPat, repText)
    end
  end
  return attackDesc
end
-- mw.log(p._getSpecialAttackDescription(p.getSpecialAttackByID(84), false))
-- mw.log(p._getSpecialAttackDescription(p.getSpecialAttackByID(31), true))


return p
return p