Module:Equipinfo

local trim = mw.text.trim local cargo = mw.ext.cargo

local currentFrame local args_table local lang local l10n_table

local isDebug local debugStr = ''

local l10n = function(key, data1, data2) return currentFrame:expandTemplate{ title = 'localization/long', args = { 'getEquipInfo', key, calledFromModule = true, __data1 = data1, __data2 = data2 } } end

local getArg = function(key) local value = args_table[key] if not value then return nil end value = trim(value) if value == '' then return nil end return value end

-- credit: http://richard.warburton.it -- this version is with trim. local function explode(div,str) if (div=='') then return false end local pos,arr = 0,{} -- for each divider found for st,sp in function return string.find(str,div,pos,true) end do		arr[#arr + 1] = trim(string.sub(str,pos,st-1)) -- Attach chars left of current divider pos = sp + 1 -- Jump past current divider end arr[#arr + 1] = trim(string.sub(str,pos)) -- Attach chars right of last divider return arr end

local function round(x, dec) local factor = 10^(dec or 0) return math.floor(x * factor + 0.5) / factor end

local function statList return 'ccdryLight, cciceBarrier, ccwetLight, accCalendar, accCompass, accCritterGuide, accDepthMeter, accDivingHelm, accDreamCatcher, accFishFinder, accFishingLine, accFlipper, accJarOfSouls, accLavaFishing, accMerman, accOreFinder, accRunSpeed, accStopwatch, accTackleBox, accThirdEye, accWatch, accWeatherRadio, aggro, ammoCost75, ammoCost80, arcticDivingGear, armorPenetration, arrowDamage, autoActuator, autoJump, autoPaint, autoReuseGlove, blackBelt, blockRange, boneGlove, brainOfConfusion, buffImmune, bulletDamage, canFloatInWater, CanSeeInvisibleBlocks, carpet, chloroAmmoCost80, cordage, counterWeight, dashType, dd2Accessory, desertBoots, discount, empressBrooch, endurance, equippedAnyTileRangeAcc, equippedAnyTileSpeedAcc, equippedAnyWallSpeedAcc, extraFall, fireWalk, fishingSkill, flowerBoots, frogLegJumpBoost, goldRing, gravControl2, hasCreditsSceneMusicBox, hasJumpOption_Blizzard, hasJumpOption_Cloud, hasJumpOption_Fart, hasJumpOption_Sail, hasJumpOption_Sandstorm, hasLuckyCoin, hasMoltenQuiver, hasPaladinShield, huntressAmmoCost90, iceSkate, InfoAccMechShowWires, jumpBoost, jumpSpeedBoost, kbGlove, killClothier, killGuide, lavaMax, lavaRose, lifeRegen, longInvince, magicCrit, magicCuffs, magicDamage, magicQuiver, magmaStone, manaCost, manaFlower, manaMagnet, manaRegenBonus, manaRegenDelayBonus, maxMinions, maxTurrets, meleeCrit, meleeDamage, meleeScaleGlove, meleeSpeed, minionDamage, minionKB, moonLordLegs, moveSpeed, nightVision, noFallDmg, noKnockback, npcTypeNoAggro, panic, pickSpeed, pStone, rangedCrit, rangedDamage, releaseBeesWhenHurt, rocketBoots, rocketDamage, rulerGrid, rulerLine, scope, shinyStone, skyStoneEffects, slowFall, spikedBoots, sporeSac, starCloak, starCloakIsBeeCloak, starCloakIsManaCloak, starCloakIsStarVeil, statManaMax2, strongBees, tileRangeX, tileRangeY, treasureMagnet, volatileGelatin, waterWalk, waterWalk2, wolfAcc, yoyoGlove, yoyoString' --	currentFrame:expandTemplate{ title = 'getEquipInfo/db', args = {} }	return currentFrame:callParserFunction{ name = ' end

local function formatStatValue(statvalues, stat) -- format value --		return a table { data1, data2 }, where:		* data1 holds the actual value, formatted		* data2 holds supplemental information, the nature of which depends on the stat:		** For most basic ± stats, it simply is empty if data1 is negative, and not empty otherwise.		** For accRunSpeed and desertDash, it is the value wrapped in .		** For buffImmune (list of buffs), counterWeight (list of projectiles), and npcTypeNoAggro (list of npcs), it holds the number of items in the data1 list. local value = statvalues[stat] if value == nil or value == '' then return { nil } end if stat == 'accRunSpeed' then -- pixels/tick → tiles/sec local tps = round(value * 3.75, 2) local mph = currentFrame:expandTemplate{ title = 'mph', args = { tps .. 'tiles' } } return { tps, mph } elseif stat == 'buffImmune' then -- buff id → name local valueList = explode('¤', value) for i, buffId in ipairs(valueList) do			valueList[i] = currentFrame:expandTemplate{ title = 'exclusive icon link', args = { currentFrame:expandTemplate{ title = 'buffNameFromId', args = { buffId, lang='en' } } } } end return { table.concat(valueList, ', '), #valueList } elseif stat == 'counterWeight' then -- projectile id → name local valueList = explode('¤', value) for i, projectileId in ipairs(valueList) do			valueList[i] = currentFrame:expandTemplate{ title = 'exclusive icon link', args = { currentFrame:expandTemplate{ title = 'projectileNameFromId', args = { projectileId, lang='en' } } } } end return { table.concat(valueList, ', '), #valueList } elseif stat == 'desertBoots' then -- pixels/tick → tiles/sec local tps = round(statvalues['accRunSpeed'] * 1.75 * 3.75, 2) local mph = currentFrame:expandTemplate{ title = 'mph', args = { tps .. 'tiles' } } return { tps, mph } elseif stat == 'lavaMax' then -- ticks → return { currentFrame:expandTemplate{ title = 'duration', args = { value/60 } } } elseif stat == 'lifeRegen' then -- half return { value/2 } elseif stat == 'allDamage' or stat == 'magicDamage' or stat == 'meleeDamage' or stat == 'minionDamage' or stat == 'rangedDamage' or stat == 'arrowDamage' or stat == 'bulletDamage' or stat == 'rocketDamage' or stat == 'meleeSpeed' or stat == 'moveSpeed' or stat == 'pickSpeed' or stat == 'manaCost' or stat == 'endurance' then -- decimal → return { currentFrame:expandTemplate{ title = 'percent', args = { value } } } elseif stat == 'allCrit' or stat == 'magicCrit' or stat == 'meleeCrit' or stat == 'rangedCrit' or stat == 'fishingSkill' then -- 		return { currentFrame:expandTemplate{ title = 'percent', args = { value/100 } } } -- multiplies the input by 100 elseif stat == 'npcTypeNoAggro' then -- npc id → name local valueList = explode('¤', value) for i, npcId in ipairs(valueList) do			valueList[i] = currentFrame:expandTemplate{ title = 'exclusive icon link', args = { currentFrame:expandTemplate{ title = 'npcNameFromId', args = { npcId, lang='en' } } } } end return { table.concat(valueList, ', '), #valueList } end -- no format return { value } end

local function formatStat(statvalues, stat) -- format stat, for l10n key local statFormatted = '' if stat == 'accWatch' or stat == 'dashType' or stat == 'rocketBoots' then --		the values of these stats are like a switch		e.g. Copper Watch has "accWatch=1", Gold Watch has "accWatch=3"		so depending on the value, different l10n strings are needed		e.g. for Copper Watch: "displays the time down to the hour", for Gold Watch: "displays the time down to the minute"		and the l10n keys are based on the values, e.g. "stat_accWatch-1" for Copper Watch statFormatted = 'stat_' .. stat .. '-' .. statvalues[stat] else statFormatted = 'stat_' .. stat end -- format value valueFormatted = formatStatValue(statvalues, stat) return { statFormatted = statFormatted, valueFormatted = valueFormatted } end

local function formatSingleStat(statvalues, stat) local formatted = formatStat(statvalues, stat) return formatted['valueFormatted'][1] end

local function formatStatList(statvalues) -- remove individual damage/crit stats if we have allDamage/allCrit if statvalues['allDamage'] ~= nil then statvalues['magicDamage'] = nil statvalues['meleeDamage'] = nil statvalues['minionDamage'] = nil statvalues['rangedDamage'] = nil end if statvalues['allCrit'] ~= nil then statvalues['magicCrit'] = nil statvalues['meleeCrit'] = nil statvalues['rangedCrit'] = nil end local statStr = '' -- iterate over stats, apply formatting->l10n to each one. -- stats may overwrite each other (e.g. accRunSpeed & desertBoots), so don't modify stat array itself. for stat, value in pairs(statvalues) do		local formatted = formatStat(statvalues, stat) if formatted['valueFormatted'][2] == nil or formatted['valueFormatted'][2] == '' then -- if there is no supplemental formatting information if tostring(value):sub(1, 1) ~= '-' then formatted['valueFormatted'][2] = true -- set to true if value is positive else formatted['valueFormatted'][2] = '' end local vF1firstChar = tostring(formatted['valueFormatted'][1]):sub(1, 1) if vF1firstChar == '-' or vF1firstChar == '+' then formatted['valueFormatted'][1] = tostring(formatted['valueFormatted'][1]):sub(2) -- strip +/- sign end end statStr = statStr .. '' if isDebug then statStr = statStr .. table.concat({ formatted['statFormatted'], formatted['valueFormatted'][1], formatted['valueFormatted'][2] }, '§§') .. ' – '		end statStr = statStr .. l10n(formatted['statFormatted'], formatted['valueFormatted'][1], formatted['valueFormatted'][2]) .. '' end if statStr == '' then return '' end return statStr.. '' end

local function parseFrom(result) local statvalues = {} -- store the cargo result to statvalues table for _, row in ipairs(result) do		for stat, value in pairs(row) do			if value ~= '' then local add = false local valueFirstChar = tostring(value):sub(1, 1) if statvalues[stat] ~= nil then add = valueFirstChar == '+' or valueFirstChar == '-' -- if value starts with +/-, then do perform addition/subtraction end if valueFirstChar == '+' then value = value:sub(2) -- strip plus sign end if add then statvalues[stat] = statvalues[stat] + value else statvalues[stat] = value end end end end return statvalues end

- -- main return object return {

go = function(frame) -- init cache currentFrame = frame args_table = frame.args lang = getArg('lang') or 'en'

local queryStat = getArg('queryStat') local queryItemId = getArg('queryItemId') local outputMode = getArg('outputMode') local isDebug = getArg('debug') local statList = statList local queryItemIdList = queryItemId:gsub('/', ',') -- input is "1234/1235/1236", but SQL expects "1234,1235,1236" local result = cargo.query('Equipinfo', statList, { where = 'itemid IN (' .. queryItemIdList .. ')' } )	if result == nil then return end -- store the cargo result to statvalues table local statvalues = parseFrom(result) -- pre-process -- if all four damage values are the same and not nil, add an "allDamage" stat local allDamageSet = (statvalues['magicDamage'] and statvalues['meleeDamage'] and statvalues['minionDamage'] and statvalues['rangedDamage']) ~= nil if allDamageSet and statvalues['magicDamage'] == statvalues['meleeDamage'] and statvalues['meleeDamage'] == statvalues['minionDamage'] and statvalues['minionDamage'] == statvalues['rangedDamage'] then statvalues['allDamage'] = statvalues['magicDamage'] end -- if all three crit chance values are the same and not nil, add an "allCrit" stat local allCritSet = (statvalues['magicCrit'] and statvalues['meleeCrit'] and statvalues['rangedCrit']) ~= nil if allCritSet and statvalues['magicCrit'] == statvalues['meleeCrit'] and statvalues['meleeCrit'] == statvalues['rangedCrit'] then statvalues['allCrit'] = statvalues['magicCrit'] end -- if all the "equippedAnyTileRangeAcc" is set, pass its effects to "tileRangeX" and "tileRangeY" if statvalues['equippedAnyTileRangeAcc'] then statvalues['tileRangeX'] = (statvalues['tileRangeX'] or 0) + 3 statvalues['tileRangeY'] = (statvalues['tileRangeY'] or 0) + 2 end -- output local outputStr = '' if outputMode == 'raw' then outputStr = statvalues[queryStat] elseif outputMode == 'singlestat' then outputStr = formatSingleStat(statvalues, queryStat) elseif outputMode == 'listraw' then for stat, value in pairs(statvalues) do outputStr = outputStr .. stat .. ':' .. value .. ';'		end elseif outputMode == 'list' then outputStr = formatStatList(statvalues) end if isDebug then outputStr = '(debug start)' .. debugStr .. '(debug end) ' .. outputStr end return outputStr end, }