Módulo:Equipinfo

Fonte: Terraria Wiki
Saltar para a navegação Saltar para a pesquisa

A documentação para este módulo pode ser criada na página Módulo:Equipinfo/doc

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

---A cached version of the current frame, the interface to the parser.
local currentFrame
---Holds the arguments from the template call.
local args_table

local isDebug
local debugStr = ''


---Return the l10n string associated with the `key`. Supplemental information can be passed via the replacement parameters `data1` and `data2`.
---@param key string
---@param data1 string
---@param data2 string
---@return string
local function l10n(key, data1, data2)
	return currentFrame:expandTemplate{ title = 'localization/long', args = { 'getEquipInfo', key, ['$data1$'] = data1, ['$data2$'] = data2 } }
end

---Return a trimmed version of the value of the template parameter with the specified `key`.
---Return `nil` if the parameter is empty or unset.
---@param key string|number
---@return string|nil
local function getArg(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

---Split the `str` on each `div` in it and return the result as a table.
---Original version credit: http://richard.warburton.it. This version trims each substring.
---@param div string
---@param str string
---@return table|boolean
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

---Round the `number` on a number of digits specified by `dec`.
---@param x number
---@param dec number
---@return number
local function round(x, dec)
  local factor = 10^(dec or 0)
  return math.floor(x * factor + 0.5) / factor
end

---Return a string of all possible stats, comma-separated
---@return string
local getStatList = function()
	return 'ccdryLight, cciceBarrier, ccwetLight, accCalendar, accCompass, accCritterGuide, accDepthMeter, accDivingHelm, accDreamCatcher, accFishFinder, accFishingBobber, accFishingLine, accFlipper, accJarOfSouls, accLavaFishing, accMerman, accOreFinder, accRunSpeed, accStopwatch, accTackleBox, accThirdEye, accWatch, accWeatherRadio, aggro, ammoCost75, ammoCost80, arcticDivingGear, armorPenetration, arrowDamage, arrowDamageAdditiveStack, autoActuator, autoJump, autoPaint, autoReuseGlove, blackBelt, blockRange, boneGloveItem, brainOfConfusionItem, buffImmune, bulletDamage, canFloatInWater, CanSeeInvisibleBlocks, carpet, chiselSpeed, chloroAmmoCost80, cordage, counterWeight, dashType, dd2Accessory, desertBoots, discount, dontHurtCritters, dontHurtNature, dontStarveShader, empressBrooch, endurance, equipmentBasedLuckBonus, equippedAnyTileRangeAcc, equippedAnyTileSpeedAcc, equippedAnyWallSpeedAcc, extraFall, fireWalk, fishingSkill, flowerBoots, goldRing, gravControl2, hasCreditsSceneMusicBox, hasJumpOption_Blizzard, hasJumpOption_Cloud, hasJumpOption_Fart, hasJumpOption_Sail, hasJumpOption_Sandstorm, hasLuck_LuckyCoin, hasLuck_LuckyHorseshoe, hasLuckyCoin, hasLucyTheAxe, hasMagiluminescence, hasMoltenQuiver, hasPaladinShield, honeyCombItem, 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, preventAllItemPickups, pStone, rangedCrit, rangedDamage, remoteVisionForDrone, rocketBoots, rocketDamage, rulerGrid, rulerLine, scope, shimmerImmune, shinyStone, skyStoneEffects, slowFall, spikedBoots, sporeSac, starCloakItem, starCloakItem_beeCloakOverrideItem, starCloakItem_manaCloakOverrideItem, starCloakItem_starVeilOverrideItem, statManaMax2, strongBees, tileRangeX, tileRangeY, treasureMagnet, vanityRocketBoots, volatileGelatin, waterWalk, waterWalk2, whipRangeMultiplier, wolfAcc, yoyoGlove, yoyoString'
end

---Apply formatting to a single 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 {{mph}}.
--- * For `buffImmune` (list of buffs), `counterWeight` (list of projectiles), and `npcTypeNoAggro` (list of npcs), it holds the number of items in the `data1` list.
---@param statvalues table The entire data table.
---@param stat string The stat name whose value is to be formatted.
---@return table|nil
local function formatStatValue(statvalues, stat)

	local value = statvalues[stat] -- retrieve value from data table
	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 = 'getBuffInfo', args = { buffId, 'name', 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 == 'hasMagiluminescence' then
		-- pixels/tick → tiles/sec
		local tps = round(3 * 1.15 * 3.75, 2) -- default accRunSpeed is 3
		local mph = currentFrame:expandTemplate{ title = 'mph', args = { tps .. 'tiles' } }
		return { tps, mph }

	elseif stat == 'lavaMax' then
		-- ticks → {{duration}}
		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' or stat == 'arrowDamageAdditiveStack' or stat == 'whipRangeMultiplier' then
		-- decimal → {{percent}}
		return { currentFrame:expandTemplate{ title = 'percent', args = { value } } }

	elseif stat == 'allCrit' or stat == 'magicCrit' or stat == 'meleeCrit' or stat == 'rangedCrit' then
		-- {{percent}}
		return { currentFrame:expandTemplate{ title = 'percent', args = { value/100 } } } -- {{percent}} 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

---Return a table with the l10n key name and the formatted value of the `stat`.
---@param statvalues table The entire data table.
---@param stat string The stat name for which the l10n key and value is to be formatted.
---@return table formatted Contains two keys, `statFormatted` and `valueFormatted`.
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 three 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
	local valueFormatted = formatStatValue(statvalues, stat)

	return { statFormatted = statFormatted, valueFormatted = valueFormatted }
end

---Return a string that is the fully formatted value of the specified `stat`.
---@param statvalues table The entire data table.
---@param stat string The stat name whose value is to be formatted.
---@return string
local function formatSingleStat(statvalues, stat)
	local formatted = formatStat(statvalues, stat)
	-- formatted is now: { ["statFormatted"] = "(l10n key)", ["valueFormatted"] = { data1, data2 } }
	-- we only want data1, nothing else
	return formatted['valueFormatted'][1]
end

---Return a string that is a bullet list with all stats in the `statvalues` table, fully formatted including l10n.
---@param statvalues table
---@return string
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 = '<ul>'
	-- iterate over stats, apply formatting->l10n to each one.
	-- stats may overwrite each other (e.g. accRunSpeed & desertBoots), so don't modify the stat table itself.
	for stat, value in pairs(statvalues) do
		local formatted = formatStat(statvalues, stat)
		-- formatted is now: { ["statFormatted"] = "(l10n key)", ["valueFormatted"] = { data1, data2 } }
		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 .. '<li>'
		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]) .. '</li>'
	end
	if statStr == '<ul>' then
		return ''
	end
	return statStr.. '</ul>'
end

---Return a statvalues table from an Equipinfo cargo query result.
---@param result table
---@return table
local function parseFrom(result)
	local statvalues = {}
	for _, row in ipairs(result) do -- iterate over rows
		for stat, value in pairs(row) do -- iterate over columns
			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

---Pre-process the `statvalues` table: Add `allDamage`/`allCrit` if necessary, and resolve `equippedAnyTileRangeAcc`.
---@param statvalues table
---@return table statvalues
local function preProcessStatvalues(statvalues)
	-- 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 the "accFishingBobber" is set, pass its effects to "fishingSkill"
	if statvalues['accFishingBobber'] then
		statvalues['fishingSkill'] = (statvalues['fishingSkill'] or 0) + 10
	end
	-- if the "dd2Accessory" is set, pass its effects to "minionDamage" and "maxTurrets"
	if statvalues['dd2Accessory'] then
		statvalues['minionDamage'] = (statvalues['minionDamage'] or 0) + 0.1
		statvalues['maxTurrets'] = (statvalues['maxTurrets'] or 0) + 1
	end
	-- if the "equippedAnyTileSpeedAcc" is set, pass its effects to "tileSpeed"
	if statvalues['equippedAnyTileSpeedAcc'] then
		statvalues['tileSpeed'] = (statvalues['tileSpeed'] or 0) + 0.5
	end
	-- if the "chiselSpeed" is set, pass its effects to "pickSpeed"
	if statvalues['chiselSpeed'] then
		statvalues['pickSpeed'] = (statvalues['pickSpeed'] or 0) - 0.25
	end
	-- if the "equippedAnyWallSpeedAcc" is set, pass its effects to "wallSpeed"
	if statvalues['equippedAnyWallSpeedAcc'] then
		statvalues['wallSpeed'] = (statvalues['wallSpeed'] or 0) + 0.5
	end
	-- if 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
	-- if the "hasLuck_LuckyHorseshoe" is set, pass its effects to "equipmentBasedLuckBonus"
	if statvalues['hasLuck_LuckyHorseshoe'] then
		statvalues['equipmentBasedLuckBonus'] = (statvalues['equipmentBasedLuckBonus'] or 0) + 0.05
	end
	-- if the "hasLuck_LuckyCoin" is set, pass its effects to "equipmentBasedLuckBonus"
	if statvalues['hasLuck_LuckyCoin'] then
		statvalues['equipmentBasedLuckBonus'] = (statvalues['equipmentBasedLuckBonus'] or 0) + 0.05
	end

	return statvalues
end

-----------------------------------------------------------------
-- main return object
return {

go = function(frame)
	-- init cache
	currentFrame = frame
	args_table = frame.args
	isDebug = getArg('debug')

	-- prepare cargo query
	local queryItemId = getArg('queryItemId')
	local statList = getStatList()
	local queryItemIdList = queryItemId:gsub('₴', ',') -- input is "1234₴42₴777", but SQL expects "1234,42,777"

	-- fetch data: perform cargo query
	local result = cargo.query('Equipinfo', statList, { where = 'itemid IN (' .. queryItemIdList .. ')' } )
	if result == nil then return end
	local statvalues = parseFrom(result)
	statvalues = preProcessStatvalues(statvalues)

	-- assemble output string
	local outputMode = getArg('outputMode')
	local queryStat = getArg('queryStat')
	local outputStr = ''
	if outputMode == 'raw' then
		-- raw: just print the value as it is in cargo
		outputStr = statvalues[queryStat]
	elseif outputMode == 'singlestat' then
		-- single stat: print the formatted value of one stat
		outputStr = formatSingleStat(statvalues, queryStat)
	elseif outputMode == 'listraw' then
		-- raw list: print the values of all stats
		for stat, value in pairs(statvalues) do
			outputStr = outputStr .. stat .. ':' .. value .. ';'
		end
	elseif outputMode == 'list' then
		-- list: print a fully formatted and localized bullet list with all stats
		outputStr = formatStatList(statvalues)
	end

	if isDebug then
		outputStr = '<small class="note-text">(debug start)' .. debugStr .. '(debug end)</small>' .. outputStr
	end

	return outputStr

end,
getStatList = getStatList,
}