Module:CreepMap/CreepSpot
From Liquipedia Warcraft Wiki
local Abbreviation = require('Module:Abbreviation')
local Array = require('Module:Array')
local Class = require('Module:Class')
local Logic = require('Module:Logic')
local String = require('Module:StringUtils')
local Variables = require('Module:Variables')
local SPOT_ICON = {
easy = '[[File:Wc3 easy creep spot.png|20px|link=]]',
medium = '[[File:Wc3 medium creep spot.png|22px|link=]]',
hard = '[[File:Wc3 hard creep spot.png|24px|link=]]',
}
local DIFFICULTY = {
easy = 'Easy',
medium = 'Medium',
hard = 'Hard',
}
local CREEP_COLORS = {
'sapphire-text',
'cinnabar-text',
'forest-green-text',
'red-violet-text',
}
local ITEM_DATAS = {
{index = 1, colorClass = 'sapphire-text'},
{index = '1-2', colorClass = 'sapphire-text'},
{index = '1-3', colorClass = 'sapphire-text'},
{index = '1-4', colorClass = 'sapphire-text'},
{index = '1-5', colorClass = 'sapphire-text'},
{index = 2, colorClass = 'cinnabar-text'},
{index = '2-2', colorClass = 'cinnabar-text'},
{index = 3, colorClass = 'forest-green-text'},
{index = 4, colorClass = 'red-violet-text'},
}
local _cache = {}
local CreepSpot = {}
function CreepSpot.run(args)
args = args or {}
local imageWidth = tonumber(Variables.varDefault('imgwidth', 0))
local imageHeight = tonumber(Variables.varDefault('imgheight', 0))
local display = mw.html.create('div')
:addClass('creep-spot creep-spot-' .. (args.spot or '|medium'))
:css('position', 'absolute')
:css('left', ((tonumber(args.x) or 0) * imageWidth - 12) .. 'px')
:css('top', ((tonumber(args.y) or 0) * imageHeight - 12) .. 'px')
:wikitext(SPOT_ICON[args.spot] or SPOT_ICON.medium)
local difficulty = DIFFICULTY[args.spot] or DIFFICULTY.medium
local popup = display:tag('div')
:addClass('creep-spot-popup')
local creepLevel = 0
local levels = {}
local creeps = {}
local level1, level2, level3, level4, level5
for i = 1, 5 do
creeps[i] = CreepSpot._fetchCreep(args['creep' .. i]) or {}
levels[i] = tonumber((creeps[i].extradata or {}).unitlevel) or 0
creepLevel = creepLevel + (tonumber(args['creepcount' .. i]) or 1) * levels[i]
end
-- popup header
popup:tag('div')
:addClass('creep-spot-popup-header')
:wikitext(difficulty .. ' Creep Spot [')
:tag('i'):wikitext(Abbreviation.make{text = creepLevel, title = 'Total Creep Level'}):done()
:wikitext(']')
local popupBody = popup:tag('div')
:addClass('creep-spot-popup-body')
local spotTable = popupBody:tag('table')
:addClass('wikitable wikitable-striped')
:css('margin-top', '-1px')
:css('margin-bottom', '0px')
:css('width', '100%')
:css('font-size', '85%')
:css('line-height', '90%')
:css('text-align', 'center')
:node(CreepSpot._spotTableHeader1())
:node(CreepSpot._spotTableHeader2())
for index, creep in ipairs(creeps) do
spotTable:node(CreepSpot._unitRow{
creep = creep,
level = levels[index],
count = tonumber(args['creepcount' .. index]) or 1,
item = args['item' .. index],
colorClass = CREEP_COLORS[index],
})
end
local itemTable = popupBody:tag('table')
:addClass('wikitable wikitable-striped')
:css('margin-top', '-1px')
:css('margin-bottom', '0px')
:css('width', '100%')
:css('font-size', '85%')
:css('line-height', '90%')
:css('text-align', 'center')
:node(CreepSpot._itemTableHeader())
for _, itemData in ipairs(ITEM_DATAS) do
itemTable:node(CreepSpot._itemRow{
item = args['item' .. itemData.index],
itemname = args['itemname' .. itemData.index],
level = args['itemlevel' .. itemData.index],
percentage = args['itempercentage' .. itemData.index],
colorClass = itemData.colorClass,
})
end
return display
end
function CreepSpot._spotTableHeader1()
return mw.html.create('tr')
:tag('th')
:attr('colspan', 5)
:css('padding', '2px')
:tag('span')
:css('font-size', '85%')
:css('line-height', '80%')
:wikitext('Creeps')
:done()
:done()
end
function CreepSpot._spotTableHeader2()
return mw.html.create('tr')
:tag('th')
:css('padding', '2px')
:css('width', '200px')
:wikitext('Unit')
:done()
:tag('th')
:css('padding', '2px')
:css('width', '40px')
:wikitext('Count')
:done()
:tag('th')
:css('padding', '2px')
:css('width', '40px')
:wikitext('Level')
:done()
:tag('th')
:css('padding', '2px')
:css('width', '40px')
:wikitext('[[Experience|XP]]')
:done()
:tag('th')
:css('padding', '2px')
:css('width', '40px')
:wikitext('Item')
:done()
end
function CreepSpot._fetchCreep(creep)
if Logic.isEmpty(creep) then
return {extradata = {}}
end
local creepData = mw.ext.LiquipediaDB.lpdb('datapoint', {
conditions = '[[type::unit]] AND [[pagename::' .. creep:gsub(' ', '_') .. ']]',
query = 'name, pagename, extradata, image',
order = 'name asc',
limit = 1,
})[1]
if not creep then
return {extradata = {}}
end
return creepData
end
function CreepSpot._unitRow(props)
if props.level == 0 then
return
end
local creep = props.creep
return mw.html.create('tr')
:tag('td')
:css('text-align', 'left')
:css('overflow', 'hidden')
:css('text-overflow', 'ellipsis')
:css('white-space', 'nowrap')
:wikitext('[[File:' .. creep.image .. '|20px|link=]] [[' .. creep.pagename .. '|' .. creep.name .. ']]')
:done()
:tag('td'):wikitext(props.count):done()
:tag('td'):wikitext(props.level):done()
:tag('td'):wikitext(creep.extradata.experience or 0):done()
:tag('td'):addClass(props.colorClass or 'sapphire-text'):wikitext(props.item and '◈' or nil):done()
end
function CreepSpot._itemTableHeader()
return mw.html.create('tr')
:tag('th')
:attr('colspan', 4)
:css('padding', '2px')
:tag('span')
:css('font-size', '85%')
:css('line-height', '80%')
:wikitext('Items')
:done()
:done()
end
function CreepSpot._itemRow(props)
if not props.item then
return
end
local percentageDisplay = ''
if props.percentage then
local pct = tonumber(props.percentage)
if pct then
percentageDisplay = string.format('%.1f%%', pct)
else
percentageDisplay = props.percentage
end
end
-- Determine the item description text
local itemDescription
if props.itemname then
-- Use custom name if provided
itemDescription = props.itemname
elseif props.level then
-- Use level-based format if level is provided
itemDescription = 'Level ' .. props.level .. ', ' .. props.item
else
-- Fall back to 'Custom drop'
itemDescription = 'Custom drop'
end
return mw.html.create('tr')
:tag('td')
:addClass(props.colorClass)
:css('width', '25px')
:wikitext('◈')
:done()
:tag('td')
:css('text-align', 'left')
:css('width', '125px')
:css('text-align', 'left')
:css('overflow', 'hidden')
:css('text-overflow', 'ellipsis')
:css('white-space', 'nowrap')
:wikitext(itemDescription)
:done()
:tag('td'):wikitext(CreepSpot._fetchItems(props)):done()
:tag('td')
:css('width', '50px')
:css('font-size', '80%')
:wikitext(percentageDisplay)
:done()
end
function CreepSpot._fetchItems(props)
local conditions = '[[type::item]]'
if props.level then
conditions = conditions .. ' AND [[extradata_level::' .. props.level .. ']] AND [[information::' .. props.item .. ' Items]]'
else
local items = Array.map(mw.text.split(props.item, ','), String.trim)
local itemConds = {}
for _, item in ipairs(items) do
table.insert(itemConds, '[[pagename::' .. item:gsub(' ', '_').. ']]')
end
conditions = conditions .. ' AND (' .. table.concat(itemConds, ' OR ') .. ')'
end
local itemData = mw.ext.LiquipediaDB.lpdb('datapoint', {
conditions = conditions,
query = 'name, pagename, image',
order = 'name asc',
limit = 5000,
})
local display = {}
for _, item in ipairs(itemData) do
table.insert(display, '[[File:' .. item.image .. '|20px|' .. item.name .. '|link=' .. item.pagename .. ']]')
end
return table.concat(display, ' ')
end
return Class.export(CreepSpot)