Module:InventorySlot
Jump to navigation
Jump to search
-- Based on work by the MC wiki: https://minecraft.gamepedia.com/
local UISlot = {}
local sprite = require([[Module:Sprite]])
local Sprites = {
minecraft = sprite:new("inventory"),
gm4 = sprite:new("gm4"),
effect = sprite:new("effect"),
trophy = sprite:new("trophy"),
gm4RP = sprite:new("gm4RP")
}
function UISlot:new(item, large)
o = {}
setmetatable(o, {__index = self})
o:SetItem(item)
o.__large = large
return o
end
-- Sets the item of this UISlot. If 'raw html' (=first char == '<') then
-- this will return said html wrapped instead of doing a item lookup
function UISlot:SetItem(item)
if string.sub(item or "",1,1) == '<' then
-- If the item is already html just save that
self.__html = item
return self
end
self.__sprite = UISlot.Decode(item)
return self
end
function UISlot.Decode(item)
if not(item) then return nil end
item = mw.text.trim(item)
if item == "" then item = nil end
if item then
-- split at ':'
local t={}
for str in string.gmatch(item, "([^:]+)") do
table.insert(t, str)
end
if #t == 1 then
return Sprites.minecraft:Item(item,"minecraft")
elseif #t == 2 then
local spr = Sprites[mw.text.trim(t[1])]
if spr then
return spr:Item(mw.text.trim(t[2]), mw.text.trim(t[1]))
else
error("Unknown namespace: " .. mw.text.trim(t[1]))
end
else
error("Got unexpected amount of ':', namely:" .. (#t - 1))
end
else
return nil
end
end
-- Append the HTML for an item
function UISlot.Item(item, large, html)
return UISlot:new(item, large):GenerateHTML(html)
end
-- Generate the HTML for a grid of items
function UISlot.Call(items, width, height, size)
local w = width or 1
local h = height or 1
local grid = {}
local large = size
for i = 1,h do
grid[i] = {}
for j = 1,w do
grid[i][j] = mw.text.trim(items[j+(i-1)*w] or "")
end
end
return UISlot.Grid(grid, large)
end
-- Convert a 2d list of itemnames to an HTML grid
function UISlot.Grid(items, large)
local root = mw.html.create( "table" ):addClass("invgrid")
for i = 1, #items do
local row = root:tag("tr"):addClass("invrow")
for j = 1, #items[i] do
UISlot.Item(items[i][j], large, row)
end
end
return root
end
function UISlot:GenerateHTML (html)
local slot
if html then
slot = html:tag("td")
else
slot = mw.html.create("div")
end
slot:addClass( "invslot" )
if self.__large then
slot:addClass( "invslot-large")
end
if self.__html then
slot:wikitext(self.__html)
end
if self.__sprite then
self.__sprite:GenerateHTML(slot)
end
return slot
end
-- Well Template:InventorySlot does not use any of the above code, so I'm going
-- to start brand new from here, with the Minecraft code
-- Based on work by the Minecraft wiki, https://minecraft.wiki
local i18n = {
filename = 'Invicon $1',
moduleAliases = [[Module:InventorySlot/Aliases]],
prefixes = {
any = 'Any',
matching = 'Matching',
damaged = 'Damaged',
unwaxed = 'Unwaxed',
},
}
local aliases = mw.loadData( i18n.moduleAliases )
--[[Merges a list, or inserts a string
or table into a table
--]]
local function mergeList( parentTable, content )
local i = #parentTable + 1
if content[1] then
-- Merge list into table
for _, v in ipairs( content ) do
parentTable[i] = v
i = i + 1
end
else
-- Add strings or tables to table
parentTable[i] = content
end
end
local function makeItem( args )
local item = mw.html.create( 'span' ):addClass( 'invslot-item' )
if args.imgclass then
item:addClass( args.imgclass )
end
if frame.name == '' then
return item
end
local title = frame.title or mw.text.trim( args.title or '' )
local name = frame.name or ''
local count = frame.count
local description = frame.text
local img
if name:match( '%.gif$' ) or name:match( '%.png$' ) then
img = file:gsub( '%$1', name )
-- Remove file extension from name
name = il8n.filename:sub( 0, -5 )
else
-- Fall back to an individual image if the sprite is lacking
img = i18n.filename:gsub( '%$1', name .. '.png' )
end
local link = args.link or ''
if link == '' then
link = name:gsub( '^' .. i18n.prefixes.damaged .. ' ', '' )
for _, suffix in pairs( i18n.suffixes ) do
link = link:gsub( ' ' .. suffix .. '$', '' )
end
elseif link:lower() == 'none' then
link = nil
end
if link == pageName then
link = nil
end
local formattedTitle
local plainTitle
if title == '' then
plainTitle = name
elseif title:lower() ~= 'none' then
plainTitle = title:gsub( '\\\\', '\' ):gsub( '\\&', '&' )
local formatPattern = '&[0-9a-fk-or]'
if plainTitle:match( formatPattern ) then
formattedTitle = title
plainTitle = plainTitle:gsub( formatPattern, '' )
end
if plainTitle == '' then
plainTitle = name
else
plainTitle = plainTitle:gsub( '\', '\\' ):gsub( '&', '&' )
end
elseif link then
formattedTitle = ''
end
item:attr{
['data-title'] = formattedTitle,
['data-lore'] = description
}
item:addClass( 'invslot-item-image' )
:wikitext( '[[File:', img, '|32x32px|link=', link or '', '|alt=', altText, '|', escapedTitle, ']]' )
if count and count > 1 and count < 1000 then
if link then
item:wikitext( '[[', link, '|' )
end
local number = item
:tag( 'span' )
:addClass( 'invslot-stacksize' )
:attr{ title = plainTitle }
:wikitext( count )
if link then
item:wikitext( ']]' )
end
end
return item
end
function UISlot.slot( f )
local args = f.args or f
-- not really sure what this does
local args = f.args or f
if f == mw.getCurrentFrame() and args[1] == nil then
args = f:getParent().args
end
if not args.parsed then
args[1] = mw.text.trim( args[1] or '' )
end
-- I see. This frames is where you parse the semicolon separated list
-- and enable cycling, in addition to all of the extra data that you
-- need for items. We'll need to investigate whether or not we'll need
-- this? Like it'll be useful for vanilla items, but not for any of our
-- recipes, since we don't need to cycle any of our custom items in recipes.
-- .... I say that, then realize Zauber armor cycles. But tbf, it's all
-- premade from aliases, and does not need custom in-place data
local frames
if args.parsed then
frames = args[1]
elseif args[1] ~= '' then
-- Not using moddata, but that kinda makes me think we could use the
-- module namespaces from automatically imported items... hmm...
frames = UISlot:parseFrameText ( args[1], false )
end
local body = mw.html.create( 'span' ):addClass( 'invslot' ):css{ ['vertical-align'] = args.align }
if animated then body:addClass( 'animated' ) end
if args.class then body:addClass( args.class ) end
if args.style then body:cssText( args.style ) end
if not frames then return tostring ( body) end
-- Figure out cycling here
for i, frame in ipairs( frames ) do
local item
-- how?
item = makeItem( frame, i, args)
body:node( item )
if i == activeFrame and animated then
item:addClass( 'animated-active' )
end
end
return tostring( body )
end
function UISlot.parseFrameText ( framesText, aliasReference )
local frames = {}
local expandedAliases
-- wow so much code for cycling that is being skipped here
-- this line is definitely wrong, but we'll see if this works as a
-- single line hack
local frameText = framesText
local frame = UISlot.makeFrame( frameText )
local newFrame = frame
-- or gm4 ?
if aliases then
local id = frame.name
if frame.mod and frame.mod == 'gm4' then
-- load gm4 aliases, I guess?
end
-- Figure out how to load and access the gm4 alias
local alias = aliases or aliases[id]
if alias then
newFrame = UISlot.getAlias ( alias, frame )
-- lots of other code that we need to do when we accept cycle lists
end
mergeList( frames, newFrame )
end
return frames
end
function UISlot.getAlias( aliasFrames, parentFrame )
if type( aliasFrames ) == 'string' then
local expandedFrame = mw.clone ( parentFrame )
expandedFrame.name = aliasFrames
return { expandedFrame }
end
if aliasFrames.name then
aliasFrames = { aliasFrames }
end
for i, aliasFrame in ipairs( aliasFrames ) do
local expandedFrame
if type( aliasFrame ) == 'string' then
expandedFrame = { name = aliasFrame }
else
expandedFrame = cloneTable( aliasFrame )
end
expandedFrame.title = parentFrame.title or expandedFrame.title
expandedFrame.mod = parentFrame.mod or expandedFrame.mod
expandedFrame.num = parentFrame.num or expandedFrame.num
expandedFrame.text = parentFrame.text or expandedFrame.text
expandedFrames[i] = expandedFrame
end
return expandedFrames
end
function UISlot.makeFrame( frameText )
local frame = {}
frame.title = frameText:match( '^%[([^%]]+)%]' )
frame.mod = frameText:match( '([^:%]]+):' ) or mod
local vanilla = { v = 1, vanilla = 1, mc = 1, minecraft = 1 }
if frame.mod and vanilla[mw.ustring.lower( frame.mod )] or frame.mod == '' then
frame.mod = nil
end
local nameStart = ( frameText:find( ':' ) or frameText:find( '%]' ) or 0 ) + 1
if nameStart - 1 == #frameText then
nameStart = 1
end
-- Come back to this later. If we are going to pull names after colons,
-- then we know whether it's vanilla or gm4. Should maybe use the "mod"
-- stuff at some point, but I'd imagine above is where you'd pull and find
frame.name = frameText:sub( nameStart, ( frameText:find( '[,%[]', nameStart ) or 0 ) - 1 )
frame.text = frameText:match( '%[([^%]]+)%]$' )
return frame
end
return UISlot