Module:Infobox/Extension/Attack

From Liquipedia Stormgate Wiki
|name=
The name of the attack.
|image=|imagedark=
An image of the attack in action.
|target=
What type of units can the attack target, or what kind of targetting it has.
|damage=
How much damage the attack does.
|damage_percentage=
In case the attack is not a flat number but a percentage.
|effect=
If the the attack has some special effect instead of or on top of it's damage.
|speed=
How fast the attack is.
|dps=
How much damage per second the attack can do.
|bonus=|bonus_damage=|bonus_dps=
Does the attack have a bonus agasint certain units? if so which, how much damage, and what the result DPS is.
|range=
how far can the attack reach.
|attack1={{Json
	|name=
	|image=
	|imagedark=
	|target=
	|damage=
	|damage_percentage=
	|effect=
	|speed=
	|dps=
	|bonus=
	|bonus_damage=
	|bonus_dps=
	|range=
}}

---
-- @Liquipedia
-- page=Module:Infobox/Extension/Attack
--
-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
--

local Lua = require('Module:Lua')

local Array = Lua.import('Module:Array')
local Json = Lua.import('Module:Json')
local Logic = Lua.import('Module:Logic')
local Page = Lua.import('Module:Page')
local String = Lua.import('Module:StringUtils')
local Table = Lua.import('Module:Table')

local Widgets = Lua.import('Module:Widget/All')
local Cell = Widgets.Cell
local Title = Widgets.Title

local Attack = {}

---@class StormgateAttackData
---@field name string
---@field targets string[]?
---@field damage number?
---@field damagePercentage string
---@field effect string[]
---@field speed number?
---@field dps number?
---@field bonus string
---@field bonusDamage number?
---@field bonusDps number?
---@field range number?

---@param argsJson string
---@param attackIndex integer
---@param faction string
---@return Widget[]?
function Attack.run(argsJson, attackIndex, faction)
	local args = Json.parseIfTable(argsJson)
	if not args then return end
	assert(args.name, 'Please specify a name for attack ' .. attackIndex)
	assert(faction, 'Faction needs to be specified')

	local data = Attack._parse(args)

	Attack._store(data, args, faction, attackIndex)

	return {
		Title{children = 'Attack' .. attackIndex .. ': ' .. args.name},
		Cell{name = 'Target', children = {Attack._displayArray(data.targets)}},
		Cell{name = 'Damage', children = {Attack._displayDamage(data)}},
		Cell{name = 'Effect', children = {Attack._displayArray(data.effect)}},
		Cell{name = 'Attack Speed', children = {data.speed}},
		Cell{name = 'DPS', children = {Attack._displayDPS(data)}},
		Cell{name = 'Range', children = {data.range}},
	}
end

---@param data table
---@return string?
function Attack._displayDamage(data)
	if data.damagePercentage then
		return (data.damagePercentage .. '%')
	elseif not data.damage then
		return
	elseif Logic.isEmpty(data.bonusData) then
		return data.damage
	end

	local parts = Array.extend({data.damage}, Array.map(data.bonusData, function(bonusElement)
		if Logic.isEmpty(bonusElement.bonusDamage) then return end
		return ' +' .. bonusElement.bonusDamage .. ' vs ' .. Page.makeInternalLink(bonusElement.bonus)
	end))

	return table.concat(parts, '<br>')
end

---@param data table
---@return string?
function Attack._displayDPS(data)
	if not data.dps then
		return
	elseif Logic.isEmpty(data.bonusData) then
		return data.dps
	end

	local parts = Array.extend({data.dps}, Array.map(data.bonusData, function(bonusElement)
		if Logic.isEmpty(bonusElement.bonusDps) then return end
		return ' +' .. bonusElement.bonusDps .. ' vs ' .. Page.makeInternalLink(bonusElement.bonus)
	end))

	return table.concat(parts, '<br>')
end

---@param args table
---@return StormgateAttackData
function Attack._parse(args)
	local bonusInput = Array.parseCommaSeparatedString(args.bonus)
	local bonusDamageInput = Array.parseCommaSeparatedString(args.bonus_damage)
	local bonusDpsInput = Array.parseCommaSeparatedString(args.bonus_dps)
	local bonusData = Array.map(bonusInput, function(bonusElement, bonusIndex)
		return {
			bonus = bonusElement,
			bonusDamage = tonumber(bonusDamageInput[bonusIndex]),
			bonusDps = tonumber(bonusDpsInput[bonusIndex]),
		}
	end)

	return {
		targets = Array.map(Array.map(Array.parseCommaSeparatedString(args.target), string.lower), String.upperCaseFirst),
		damage = tonumber(args.damage),
		damagePercentage = tonumber(args.damage_percentage),
		effect = Array.parseCommaSeparatedString(args.effect),
		speed = tonumber(args.speed),
		dps = tonumber(args.dps),
		bonusData = bonusData,
		range = tonumber(args.range),
	}
end

---@param data StormgateAttackData
---@param args table
---@param faction string
---@param attackIndex integer
function Attack._store(data, args, faction, attackIndex)
	local objectName = 'attack_' .. attackIndex .. args.name
	local extradata = Table.map(data, function (key, value) return key:lower(), value end)

	mw.ext.LiquipediaDB.lpdb_datapoint(objectName, {
		name = args.name,
		type = 'attack',
		information = faction,
		image = args.image,
		imagedark = args.imagedark,
		extradata = mw.ext.LiquipediaDB.lpdb_create_json(extradata),
	})
end

---@param arr string[]
---@return string
function Attack._displayArray(arr)
	return table.concat(Array.map(arr, function(value)
		return Page.makeInternalLink(value)
	end), ', ')
end

return Attack