Documentation

Basic use

To use this module, do as follows:

{{#invoke:CalculatedStats|<function>}}

This module should not be invoked directly in the mainspace and should be part of a template; the values get filled in by template parameters.

Valid values for function (case sensitive):

  • smt1 for Shin Megami Tensei
  • smt2 for Shin Megami Tensei II
  • smtif for Shin Megami Tensei if... (alias for smt2)
  • smtn for Shin Megami Tensei: Nine
  • desum for Shin Megami Tensei: Devil Summoner
  • sh1 for Devil Summoner: Soul Hackers
  • p2is for Persona 2: Innocent Sin

Platform

Shin Megami Tensei: Devil Summoner by default shows the normal, Super CD-ROM², and Mega-CD values for all calculated stats. Set the named parameter platform to CD2 or MCD (case insensitive) to display only the Super CD-ROM² or Mega-CD stats, or set it to anything else to only display the usual calculations.

Shin Megami Tensei: Devil Summoner by default shows both the Sega Saturn and PlayStation Portable values for Magic Defense. Set the named parameter platform to either SAT or PSP (case insensitive) to display only one of them.

For Persona 2: Innocent Sin, set the named parameter platform to PS or PSP to show only one platform's set of stats. PSP stats only apply to demons; Personas always use the PS calculations even on PSP.

Boss

Shin Megami Tensei (Mega-CD) uses different stat calculations for bosses than it does for regular demons. Set the named parameter boss to something (recommended: y) to use the boss calculations.

Manual stat inputting

Devil Summoner: Soul Hackers and Shin Megami Tensei: Nine support manual input of stats through named arguments (see the code to know what to use). This is because some of the calculations for Devil Summoner: Soul Hackers and Shin Megami Tensei: Nine are not yet perfect.

Sources

All sources were verified and, if they were wrong, corrected formulas are used in this module.


--For calculated stats in SMT1, SMT2, SMTif, SMT Devil Summoner, Soul Hackers, Persona 2 IS, Persona 2 EP, SMT Nine
--To do:
	--Fix Shin Megami Tensei: Nine accuracy
	--Fix Soul Hackers p. hit and m. atk
	--Add Persona 2: Eternal Punishment (formulas unknown)

local getArgs = require('Module:Arguments').getArgs
local p = {}

local function round(number)
	return math.floor(number + 0.5)
end

local function outputCells(array)
	local output = ""
	for i, stat in ipairs(array) do
		output = output .. "| " .. stat .. "\n"
	end

	return output:sub(1,-2)
end

function p.smt1(frame)
	local args = getArgs(frame)
	local platform = nil
	if args["platform"] then
		platform = string.lower(args["platform"])
	end
	local level = args["level"] --Level
	local strength = args["st"] --Strength
	local intelligence = args["in"] --Intelligence
	local magic = args["ma"] --Magic
	local vitality = args["vi"] --Vitality
	local agility = args["ag"] --Agility
	local luck = args["lu"] --Luck
	local isBoss = false
	if args["boss"] then
		isBoss = true
	end
	local levelMinus19 = math.max(level - 19,0)
	local levelMinus20 = math.max(level - 20,0)
	local statTable = {
		atk = levelMinus19 + (strength * 3) + round(vitality / 4),
		acc = round(strength / 4) + agility,
		def = round(levelMinus19 / 2) + round(strength / 4) + (vitality * 2),
		eva = round(intelligence / 8) + agility,
		matk = round(intelligence / 8) + magic,
		mefc = intelligence + round(magic / 8),
		atkCD2 = levelMinus19 + (strength * 3) + round(vitality / 4),
		accCD2 = math.floor(strength / 4) + agility,
		defCD2 = round(levelMinus19 / 2) + math.floor(strength / 4) + (vitality * 2),
		evaCD2 = round(intelligence / 8) + agility,
		matkCD2 = math.floor(intelligence / 8) + magic,
		mefcCD2 = intelligence + math.floor(magic / 8),
		atkMCD = levelMinus20 + (strength * 3) + math.floor(vitality / 4),
		accMCD = math.floor(vitality / 4) + agility,
		defMCD = math.floor(levelMinus20 / 2) + math.floor(strength / 4) + (vitality * 3),
		evaMCD = round(intelligence / 8) + agility,
		matkMCD = round(intelligence / 8) + magic,
		mefcMCD = intelligence + round(magic / 8)
	}
	if isBoss then
		statTable["atkMCD"] = levelMinus20 + 1 + (strength * 3) + round(vitality / 4)
		statTable["accMCD"] = round(strength / 4) + agility
		statTable["defMCD"] = math.floor((levelMinus20 + 1) / 2) + math.floor(strength / 4) + (vitality * 2)
		statTable["evaMCD"] = math.floor(intelligence / 8) + agility
		statTable["matkMCD"] = math.floor(intelligence / 8) + magic
		statTable["mefcMCD"] = intelligence + math.floor(magic / 8)
	end
	local stats = { "atk", "acc", "def", "eva", "matk", "mefc" }
	local function bothPlatsValue(stat)
		if platform == "mcd" then
			return statTable[stat.."MCD"]
		elseif platform == "cd2" then
			return statTable[stat.."CD2"]
		elseif statTable[stat] == statTable[stat.."MCD"] and statTable[stat] ~= statTable[stat.."CD2"] then
			return frame:expandTemplate{ title = "tt", args = { statTable[stat], "Most versions" } } .. "/" .. frame:expandTemplate{ title = "tt", args = { statTable[stat.."CD2"], "Super CD-ROM²" } }
		elseif statTable[stat] ~= statTable[stat.."MCD"] and statTable[stat] == statTable[stat.."CD2"] then
			return frame:expandTemplate{ title = "tt", args = { statTable[stat], "Most versions" } } .. "/" .. frame:expandTemplate{ title = "tt", args = { statTable[stat.."MCD"], "Mega-CD" } }
		elseif statTable[stat] ~= statTable[stat.."MCD"] and statTable[stat] ~= statTable[stat.."CD2"] and statTable[stat.."MCD"] == statTable[stat.."CD2"] then
			return frame:expandTemplate{ title = "tt", args = { statTable[stat], "Most versions" } } .. "/" .. frame:expandTemplate{ title = "tt", args = { statTable[stat.."MCD"], "Super CD-ROM² and Mega-CD" } }
		elseif platform ~= nil or (statTable[stat] == statTable[stat.."MCD"] and statTable[stat] == statTable[stat.."CD2"]) then
			return statTable[stat]
		else
			return frame:expandTemplate{ title = "tt", args = { statTable[stat], "Most versions" } } .. "/" .. frame:expandTemplate{ title = "tt", args = { statTable[stat.."CD2"], "Super CD-ROM²" } } .. "/" .. frame:expandTemplate{ title = "tt", args = { statTable[stat.."MCD"], "Mega-CD" } }
		end
	end
	local outputStats = {}
	for i, stat in ipairs(stats) do --Manual override
		table.insert(outputStats,i,bothPlatsValue(stat))
	end
	
	return outputCells(outputStats)
end

function p.smt2(frame)
	local args = getArgs(frame)
	local level = args["level"] --Level
	local strength = args["st"] --Strength
	local intelligence = args["in"] --Intelligence
	local magic = args["ma"] --Magic
	local vitality = args["vi"] --Vitality
	local agility = args["ag"] --Agility
	local luck = args["lu"] --Luck
	local statTable = {
		atk = (level + strength) * 2,
		acc = math.floor(level * 1.5) + agility + math.floor((strength + luck) / 4),
		def = (level + vitality) * 2,
		eva = math.floor(level * 1.5) + agility + math.floor((intelligence + luck) / 4),
		matk = math.floor(intelligence / 4) + magic,
		mefc = intelligence + math.floor(magic / 4)
	}
	local stats = { "atk", "acc", "def", "eva", "matk", "mefc" }
	local outputStats = {}
	for i, stat in ipairs(stats) do --Add category
		table.insert(outputStats,i,statTable[stat])
	end
	return outputCells(outputStats)
end

p.smtif = p.smt2

function p.desum(frame)
	local args = getArgs(frame)
	local level = args["level"] --Level
	local strength = args["st"] --Strength
	local intelligence = args["in"] --Intelligence
	local magic = args["ma"] --Magic
	local endurance = args["en"] --Endurance
	local agility = args["ag"] --Agility
	local luck = args["lu"] --Luck
	local platform = ""
	if args["platform"] then
		platform = string.lower(args["platform"]) --game platform
	end
	local isHuman = false
	if args["human"] then
		isHuman = true
	end
	local statTable = {
		atk = (level + strength) * 2,
		acc = math.floor(level * 1.5) + agility + math.floor((strength + luck) / 4),
		def = (level + endurance) * 2,
		eva = math.floor(level * 1.5) + agility + math.floor((intelligence + luck) / 4),
		matk = math.floor(intelligence / 2) + (magic * 2),
		mdef = intelligence + math.floor(level / 2) + math.floor(magic / 4) + math.floor(endurance / 2),
		mdefPSP = math.floor(intelligence + (level / 2) + (magic / 4) + (endurance / 2))
	}
	local statTableHuman = { --Not right, but very low priority due to how few people it affects; won't be implemented into template for now.
		--swdatk = math.floor(level / 4) + strength,
		--swdacc = level + agility + math.floor(luck / 2),
		--gunatk = math.floor(level / 4),
		--gunacc = level + agility + math.floor(luck / 2),
		def = endurance + agility,
		eva = level + agility + math.floor((intelligence + luck) / 4),
		matk = math.floor(intelligence / 2) + (magic * 2),
		mdef = math.floor(intelligence + magic / 4 + agility / 4),
		mdefPSP = intelligence + math.floor(magic / 4) + math.floor(agility / 4)
	}
	local stats = { "atk", "acc", "def", "eva", "matk", "mdef" }
	local statsHuman = { "def", "eva", "matk", "mdef" }
	if isHuman then
		statTable = statTableHuman
		stats = statsHuman
	end
	local function bothPlatsValue(stat)
		if args[stat] then --Manual override
			return args[stat]
		elseif platform == "psp" and statTable[stat.."PSP"] then
			return statTable[stat.."PSP"]
		elseif platform == "sat" or statTable[stat] == statTable[stat.."PSP"] or not statTable[stat.."PSP"] then
			return statTable[stat]
		else
			return frame:expandTemplate{ title = "tt", args = { statTable[stat], "Sega Saturn" } } .. "/" .. frame:expandTemplate{ title = "tt", args = { statTable[stat.."PSP"], "PlayStation Portable" } }
		end
	end
	local outputStats = {}
	local additionalOutput = ""
	for i, stat in ipairs(stats) do
		if args[stat] then --Manual override
			additionalOutput = "[[Category:Pages with manually input calculated stats]]"
		end
		table.insert(outputStats,i,bothPlatsValue(stat))
	end
	
	return outputCells(outputStats) .. additionalOutput
end

function p.sh1(frame)
	local args = getArgs(frame)
	local level = args["level"] --Level
	local strength = args["st"] --Strength
	local intelligence = args["in"] --Intelligence
	local magic = args["ma"] --Magic
	local endurance = args["en"] --Endurance
	local agility = args["ag"] --Agility
	local luck = args["lu"] --Luck
	local statTable = {
		patk = (level + strength) * 2,
		phit = math.floor(level * 1.5) + math.floor((agility * 2 + luck) * 0.6), --Needs work
		matk = math.floor(intelligence / 2) * 4 + math.floor(magic * 7.5), --Needs work
		mhit = (intelligence + math.floor(magic / 2)) * 2,
		def = (level + endurance) * 2 + 16,
		eva = math.floor(level * 1.5) + agility + math.floor(luck / 2)
	}
	local stats = { "patk", "phit", "matk", "mhit", "def", "eva" }
	local outputStats = {}
	local additionalOutput = ""
	for i, stat in ipairs(stats) do
		if args[stat] then --Manual override
			statTable[stat] = args[stat]
			additionalOutput = "[[Category:Pages with manually input calculated stats]]"
		end
		table.insert(outputStats,i,statTable[stat])
	end
	return outputCells(outputStats) .. additionalOutput
end

function p.p2is(frame)
	local args = getArgs(frame)
	local level = args["level"] --Level
	local strength = args["st"] --Strength
	local vitality = args["vi"] --Vitality
	local dexterity = args["dx"] --Dexterity
	local agility = args["ag"] --Agility
	local luck = args["lu"] --Luck
	local platform = ""
	if args["platform"] then
		platform = string.lower(args["platform"]) --game platform
	end
	local statTable = {
		atk = (level + strength) * 2,
		def = (level + vitality) * 2,
		matk = dexterity * 2 + math.floor(level * 0.8),
		mdef = math.floor(dexterity * 2.5) + math.floor(vitality / 2),
		atkPSP = math.floor(0.7 * ((level + strength) * 2)),
		defPSP = math.floor(0.8 * ((level + vitality) * 2)),
		matkPSP = math.floor(0.7 * (dexterity * 2 + math.floor(level * 0.8))),
		mdefPSP = math.floor(0.8 * (math.floor(dexterity * 2.5) + math.floor(vitality / 2)))
	}
	local function bothPlatsValue(stat)
		if platform == "psp" then
			return statTable[stat.."PSP"]
		elseif platform == "ps" then
			return statTable[stat]
		else
			return frame:expandTemplate{ title = "tt", args = { statTable[stat], "PlayStation" } } .. "/" .. frame:expandTemplate{ title = "tt", args = { statTable[stat.."PSP"], "PlayStation Portable" } }
		end
	end
	local stats = { "atk", "def", "matk", "mdef" }
	local outputStats = {}
	for i, stat in ipairs(stats) do
		table.insert(outputStats,i,bothPlatsValue(stat))
	end

	return outputCells(outputStats)
end

function p.smtn(frame)
	local args = getArgs(frame)
	local level = args["level"] --Level
	local strength = args["st"] --Strength
	local intelligence = args["in"] --Intelligence
	local magic = args["ma"] --Magic
	local vitality = args["vi"] --Vitality
	local agility = args["ag"] --Agility
	local luck = args["lu"] --Luck
	local statTable = {
		atk = (level + strength) * 2,
		acc = math.floor(level * 1.5) + math.floor(agility * 1.25) + math.floor(luck * 5/8), --Needs work
		attacks = 1,
		pdef = (level + vitality) * 2 + 16,
		peva = math.floor(level * 1.5) + agility + math.floor(luck / 2),
		matk = level + math.floor(intelligence / 4) + math.floor(intelligence / 8) + magic * 3,
		msuc = intelligence + math.floor(magic / 2),
		mdef = level + vitality + intelligence * 2 + math.floor(magic/4)
	}
	local stats = { "atk", "acc", "attacks", "pdef", "peva", "matk", "msuc", "mdef" }
	local additionalOutput = ""
	local outputStats = {}
	for i, stat in ipairs(stats) do
		if args[stat] then --Manual override
			statTable[stat] = args[stat]
			if stat ~= "attacks" then
				additionalOutput = "[[Category:Pages with manually input calculated stats]]"
			end
		end
		table.insert(outputStats,i,statTable[stat])
	end
	return outputCells(outputStats) .. additionalOutput
end

return p