Module:Infobox/Mechanic

-- Get Required Modules local loader = require('Module:Loader')

local string, table, yesno, arguments, statname, Infobox, inventorySlot, templates, minimap, animate, sprite, mayor = loader.lazy.require('String', 'Table', 'Yesno', 'Arguments', 'Statname', 'Infobox', 'Inventory slot', 'String/Templates', 'Minimap', 'Animate', 'Sprite', 'Mayor') local iData = loader.lazy.loadData('Infobox/Data')

local getArgs = arguments.getArgs local curTitle = mw.title.getCurrentTitle

-- Begin Exports local p = {} local yesIcon, noIcon, unknownIcon = templates.yes(1), templates.no(1), templates.unknown(1) local aprilFools = false

local function yesnodefault(val, yes, no, def) if tostring(val):sub(1, 1):lower == 'u' then return unknownIcon end local bool = yesno(val); if bool == nil then return def or val elseif bool then return yes else return no	end end

local function yesnoIcon(val, def) return yesnodefault(val, yesIcon, noIcon, def) end

local function additergroup(pref, sdata, parent) for count = 1,iData.MAX_INDEX,1 do		local desc, name = (pref..'%d_desc'):format(count), (pref..'%d_name'):format(count) parent:addData{ sdata[desc], label = sdata[name] } end end

local function argNormalize(tb) -- Simple replacement functions for the whole table local ret = {} for oldkey, v in pairs(tb) do		local key = oldkey:gsub('[{}]', '') ret[key] = v	end return ret end

function p.infoboxCreate(frame) local args = getArgs(frame) return (frame.getParent and frame:getParent or mw.getCurrentFrame):preprocess(p._infoboxCreate(args)) end

function p._infoboxCreate(args) local deftype = args.default_type -- All checkings local isNPC, isMayor, isQuest, isPuzzle, isStat, isMinion, isLocation do local function checkval(v) return (deftype or ''):lower:match(v) and true or false end isNPC = checkval('npc') or checkval('character') or checkval('mayor') isMayor = checkval('mayor') isQuest = checkval('quest') isPuzzle = checkval('puzzle') isStat = checkval('stat') isMinion = checkval('minion') isLocation = checkval('location') end local minimalist = (isQuest or isPuzzle) and true local pagename = curTitle.text or 'Diamond' local title = args.title local isValidMayor if (not args.title) then title = ((not minimalist) and pagename or nil) isValidMayor = isMayor and mayor.isValidMayor(title) if isLocation then local status, spriteAndTitle = pcall(function return sprite._locationSprite(title, nil, nil, nil, nil, true) end) if status and spriteAndTitle then title = spriteAndTitle end elseif isValidMayor then title = mayor.getMayorLink(title) elseif isNPC then local status, spriteAndTitle = pcall(function return sprite._npcSprite(title, nil, nil, nil, nil, true) end) if status and spriteAndTitle then title = spriteAndTitle end end end local category_to_add = args.category_to_add local onmain = curTitle.namespace == 0 local sections = {} for j = 1,iData.MAX_TAB,1 do		local function argJ(name, default) return args[name..j] or default end local sectionExists = j == 1 or argJ('tab') if sectionExists then -- section one does have numbers after params; on 2+ do that local i = j == 1 and  or j			local _i = j == 1 and  or '_'..j -- needed for when a param ends in a number naturally local function argI(name, default) return args[name..((type(name) == 'string' and name:match('%d$')) and _i or i)] or default end -- table of all params for this section local s = {} local function additerdata(pref) for count = 1,iData.MAX_INDEX,1 do					local desc, name = (pref..'%d_desc'):format(count), (pref..'%d_name'):format(count) s[desc] = argI(desc) s[name] = argI(name) or ('%s %d'):format(string.ucfirst(pref), count) end end -- Top level infobox values --0			s.tab = argJ('tab') or argI('tab') -- purposefully use 'j' here since default section does actually use 'tab1' --0.5			s.tab_title = argJ('tab_title') local tabPage = argJ('tab_page') or pagename -- page to get images/slots from --1|2			s.caption = argI('caption') or argI('imagecaption') s.image_gallery = (argI('image') and argI('image'):match('UNIQ%-%-gallery')) and argI('image') or nil if not s.image_gallery and (argI('image') or not (minimalist or isStat or isMinion)) then if aprilFools and isNPC then s.image = (argI('image') or tabPage..'.png') .. ';Jerry Fan.png' end s.image = string.wrapTag(animate.animate({ s.image or argI('image') or tabPage..'.png', class = 'pi-image-thumbnail', caption = s.caption }), 'center') end if not s.image_gallery and not s.image and isMinion then s.image_gallery = string.dedent:format(tabPage, tabPage) end if s.image_gallery and s.caption then s.caption = string.wrapHtml(s.caption, 'div', { class = 'pi-item-spacing pi-caption' }) end --3			s.slot_item = argI('slot_item') or argI('slot') if not s.slot_item and isValidMayor then s.slot_item = string.wrapHtml((''):format( args.title or tabPage, args.title or tabPage ), 'center') else if isMinion then s.slot_item = s.slot_item or ('*' .. tabPage) end s.slot_item = yesno(s.slot_item, false) and (s.slot_item or tabPage) or s.slot_item s.slot_item = s.slot_item and string.wrapHtml(not s.slot_item:match('(.-)') and inventorySlot.slot{					s.slot_item,					text = argI('slot_text') or nil,					title = argI('slot_title') or nil,					link = argI('slot_link') or (not onmain and 'none' or nil),					display = 'inline-grid'				} or s.slot_item, 'center') end --4			s.aka = argI('aka') --5			s.type = argI('type') or ((not minimalist) and deftype or nil) --6			s.color = argI('color') --7			s.appearance = argI('appearance') --8			s.collection = argI('collection') and (''):format(argI('collection')) --9			s.usage = argI('usage') --10			s.uses = argI('uses') --11			s.ways_to_increase = argI('ways_to_increase') --12			s.category = argI('category') --13			s.collects = argI('collects') and (''):format(argI('collects')) --14			s.upgrade_with = argI('upgrade_with') and (''):format(argI('upgrade_with')) --15			s.travel_scroll = argI('travel_scroll') --16			s.level = argI('level') --17			s.sublocations = argI('sublocations') and (''):format(argI('sublocations')) --18			s.fairy_souls = argI('fairy_souls') --19			s.election_wins = argI('election_wins') or isValidMayor and mayor.getWins{ args.title or tabPage } .. ' [Based on existing data]' or nil --20			s.amount = argI('amount') -- Dungeon Information group --A0 s.dungeon = argI('dungeon') --A1 s.floor = argI('floor') --A2 s.boss = argI('boss') --A3 s.status = argI('status') --A4 s.dungeon_size = argI('dungeon_size') --A5 s.party_size = argI('party_size') --A6 s.required_combat_level = argI('required_combat_level') --A7 s.required_catacombs_level = argI('required_catacombs_level') --A8 s.reqs = argI('reqs') --A9 s.base_xp = argI('base_xp') --A10 s.failable = yesnoIcon(argI('failable')) -- Mob Information group --B0 s.mob_level = argI('mob_level') --B1 s.damage_deals = argI('damage_deals') --B2 s.damage_resistance = argI('damage_resistance') --B3 s.spawn_location = argI('spawn_location') and (''):format(argI('spawn_location')) --B4 s.spawn_condition = argI('spawn_condition') --B5 s.special = argI('special') --B6 s.special_behavior = argI('special_behavior') --B7 local ee = argI('effective_enchant') s.effective_enchant = ee and (				(ee == 'none' or ee == 'no' or ee == 'n') and 'None'				or (''):format(ee)			) -- Quest group --C0 s.requirements = argI('requirements') or argI('requirement') --C1 s.rewards = argI('rewards') or argI('reward') -- Stats group --D0 s.stats = argI('stats') --D1+ table.each(table.values(iData.allstats), function(v)				local ln = v[1]				s[ln] = argI(ln)			end) -- Perks group --E0+ additerdata('perk') if isValidMayor then for i, v in ipairs(mayor._mayorPerksTable(args.title or tabPage)) do					local desc, name = ('perk%d_desc'):format(i), ('perk%d_name'):format(i) if v[2] and not s[desc] then s[desc] = v[2] s[name] = v[1] and string.gsub(v[1], '^%[%[(.*)%]%]*%]$', '\'\'\'%1\'\'\'') or s[name] end end end -- Capacity group --F0 s.default_desc = argI('default_desc') s.default_name = argI('default_name') or 'Default' --F1+ additerdata('upgrade') -- Location group --G0 s.xyz = argI('x') and (' %s  %s  %s  '):format(argI('x'), argI('y') or , argI('z') or ) s.xyz = s.xyz and string.wrapHtml(s.xyz, 'table', { style = 'width:100%; table-layout:fixed; text-align:center;' }) --G1 s.coordinates = argI('coordinates') --G2 do local loc, guide = argI('location'), argI('location_guide') if loc and not loc:match('%[%[') then loc =  .. loc ..  end s.location = (loc and guide) and (loc .. ' ' .. guide) or (loc or guide) end --G3 s.start_location = argI('start_location') and (''):format(argI('start_location')) --G4 s.start_npc = argI('start_npc') and (''):format(argI('start_npc')) --G5 s.prev_location = argI('prev_location') or (argI('next_location') and 'None (lowest tier location)') --G6 s.next_location = argI('next_location') or (argI('prev_location') and 'None (top tier location)') -- Inhabitants group --H0 s.npcs = argI('npcs') and (''):format(argI('npcs')) --H1 s.mobs = argI('mobs') and (''):format(argI('mobs')) -- Resources group --I0 s.drops = argI('drops') and string.wrapHtml(				(''):format(argI('drops')),				'div', { style = 'text-align:left;' }			) --I1 s.resources = argI('resources') and string.wrapHtml(				(''):format(argI('resources')),				'div', { style = 'text-align:left;' }			) -- Drops group --R0 s.mob_drops = argI('mob_drops') and (''):format(argI('mob_drops')) --R1 s.xp = argI('xp') and (''):format(argI('xp')) --R2 s.coins = argI('coins') and (''):format(argI('coins')) --R3 s.experience = argI('exp') or argI('experience') or argI('experience_orbs') --R4 s.essence = argI('essence') and (''):format(argI('essence')) -- Values group --J0 s.base_value = argI('base_value') --J1 s.max_value = argI('max_value') -- Properties group --K0 s.unlock_requirement = argI('unlock_requirement') --K1 s.max_level = argI('max_level') -- Special Effects group --L0 s.skill_special_effect = argI('skill_special_effect') -- Upgrades group --M0 s.super_compactor = isMinion and yesnoIcon(argI('super_compactor') or true) or nil --M1 s.compactor = isMinion and yesnoIcon(argI('compactor')) or nil --M2 s.auto_smelter = isMinion and yesnoIcon(argI('auto_smelter')) or nil -- Player Interactions group --N0 s.quests = argI('quests') --N1 s.shop = yesnoIcon(argI('shop') or isMayor and 'n' or nil) -- Next Event local skydate_start, skydate_end = argI('skydate_start') or argI('skydate_begin'), argI('skydate_end') if skydate_start then --S0 s.datetime = string.wrapHtml('', 'span', {					class = 'skydate-timestamp',					['data-skydate'] = skydate_start,				}) --S1 skydate_end = skydate_end or skydate_start skydate_end = skydate_end .. (skydate_end:match(',') and '' or ', 23:59') s.countdown = string.wrapHtml('', 'span', {					class = 'skydate-countdown',					['data-skydate-start'] = skydate_start,					['data-skydate-end'] = skydate_end,				}) end -- Minimap (at Coordinates) if not argI('location') and isMayor then s.minimap = minimap.getMinimapForInfobox{ 'Community Center', x = 7, z = -110 } elseif isNPC then --O0 s.minimap = minimap.getMinimapForInfobox{ location = argI('location'), minimap_location = argI('minimap_location'), x = argI('x'), z = argI('z') } end -- Item Metadata -- Q0 s.id = argI('item_id') or argI('id') if s.id then -- Always show ID in all caps s.id = string.wrapTag(s.id:upper, 'code') -- If array syntax, make a list s.id = s.id:gsub(' ', '') -- lazy trim for array; ids never naturally have spaces s.id = table.concat(mw.text.split(s.id, ','), ' ') end -- Push section data into array sections[#sections+1] = s		end end -- Make infobox local ibox = Infobox ibox:addTitle{ title } local panel = ibox:addPanel for i, sectionData in ipairs(sections) do		local sdata = argNormalize(sectionData) local section = --0panel:addSection{ label = sdata.tab } --1|2		if sdata.image_gallery then -- seems like galleries does not accept caption section:addImage{ sdata.image_gallery, --caption = { sdata.caption }, source = 'image'..(i == 1 and '' or i) } section:addData{ sdata.caption } else section:addData{ sdata.image } end section --3 :addData{ sdata.slot_item } --4 :addData{ sdata.aka, label = 'Also known as' } --5 :addData{ sdata.type, label = 'Type' } --6 :addData{ sdata.color, label = 'Color' } --7 :addData{ sdata.appearance, label = 'Appearance' } --8 :addData{ sdata.collection, label = 'Collection' } --9 :addData{ sdata.usage, label = 'Usage' } --10 :addData{ sdata.uses, label = 'Uses' } --11 :addData{ sdata.ways_to_increase, label = 'Ways to Increase' } --12 :addData{ sdata.category, label = 'Category' } --13 :addData{ sdata.collects, label = string.makeTitle('Collects', 'Average items collected per action') } --14 :addData{ sdata.upgrade_with, label = 'Upgrade with' } --15 :addData{ sdata.travel_scroll, label = '\'\'\'Travel Scroll\'\'\'' } --16 :addData{ sdata.level, label = 'Level' } --17 :addData{ sdata.sublocations, label = 'Sub-locations' } --18 :addData{ sdata.fairy_souls, label = ('Fairy Soul.png \'\'\'Fairy Souls\'\'\''):format(pagename) } --19 :addData{ sdata.election_wins, label = '\'\'\'Election Wins\'\'\'' } --20 :addData{ sdata.amount, label = 'Amount' } :addGroup --A0 :addData{ sdata.dungeon, label = 'Dungeon' } --A1 :addData{ sdata.floor, label = 'Dungeon Floor' } --A2 :addData{ sdata.boss, label = 'Boss' } --A3 :addData{ sdata.status, label = 'Status' } --A4 :addData{ sdata.dungeon_size, label = 'Dungeon Size' } --A5 :addData{ sdata.party_size, label = 'Party Size' } --A6 :addData{ sdata.required_combat_level, label = 'Required Level' } --A7 :addData{ sdata.required_catacombs_level, label = 'Required Level' } --A8 :addData{ sdata.reqs, label = 'Requirements to enter' } --A9 :addData{ sdata.base_xp, label = 'Base XP' } --A10:addData{ sdata.failable, label = 'Failable' } :done :addGroup --B0 :addData{ sdata.mob_level, label = 'Mob Level' } --B1 :addData{ sdata.damage_deals, label = 'Damage Deals' } --B2 :addData{ sdata.damage_resistance, label = 'Damage Resistance' } --B3 :addData{ sdata.spawn_location, label = 'Spawn Location' } --B4 :addData{ sdata.spawn_condition, label = 'Spawn Condition' } --B5 :addData{ sdata.special, label = 'Special' } --B6 :addData{ sdata.special_behavior, label = 'Special Behavior' } --B7 :addData{ sdata.effective_enchant, label = string.makeTitle('Effective Enchant', 'The weapon enchant that is most effective for killing this mob') } :done :addGroup --C0 :addData{ sdata.requirements, label = 'Start Req.' } --C1 :addData{ sdata.rewards, label = 'Reward' } :done do local group_ group_ = section:addGroup{ header = 'Stats', name = 'infobox-stats-list' } --D0 group_:addData{ sdata.stats } table.each(table.values(iData.allstats), function(v)				local ln = v[1]				--D1+group_:addData{ sdata[ln], label = statname._getStatName(ln, nil, true) }			end) end do local group = section:addGroup{ header = 'Perks' } --E0+ additergroup('perk', sdata, group) end do local group = section:addGroup{ header = 'Perks' } --F0 if sdata.default_desc then group:addData{ sdata.default_desc, label = sdata.default_name } end --F1+ additergroup('upgrade', sdata, group) end section:addGroup{ header = (not minimalist) and 'Location' or '' } --G0 :addData{ sdata.xyz, label = string.wrapHtml('Compass.png Coordinates', 'span', { style = 'white-space:nowrap; vertical-align: middle;' })} --G1 :addData{ sdata.coordinates, label = 'Compass.png Coordinates' } --G2 :addData{ sdata.location, label = 'Location' } --G3 :addData{ sdata.start_location, label = 'Start Location' } --G4 :addData{ sdata.start_npc, label = 'Start NPC' } :addGroup{ layout = 'horizontal' } --G5 :addData{ sdata.prev_location, label = '← Previous Location' } --G6 :addData{ sdata.next_location, label = 'Next Location →' } :done :done :addGroup{ header = 'Inhabitants', collapse = 'open' } :addGroup{ layout = 'horizontal', ['row-items'] = 2 } --H0 :addData{ sdata.npcs, label = 'NPCs' } --H1 :addData{ sdata.mobs, label = 'Mobs' } :done :done :addGroup{ header = 'Resources', collapse = 'open' } :addGroup{ layout = 'horizontal', ['row-items'] = 2 } --I0 :addData{ sdata.drops, label = 'Mob Drops' } --I1 :addData{ sdata.resources, label = 'Resources' } :done :done section:addGroup{ header = 'Drops' } --R0 :addData{ sdata.mob_drops, label = 'Drops' } --R1 :addData{ sdata.xp, label = 'XP' } --R2 :addData{ sdata.coins, label = '' } --R3 :addData{ sdata.experience, label = 'Experience Orb.png Experience Orbs' } --R4 :addData{ sdata.essence, label = 'Essence' } :done :addGroup{ header = 'Values' } --J0 :addData{ sdata.base_value, label = 'Base value' } --J1 :addData{ sdata.max_value, label = 'Max value' } :done :addGroup{ header = 'Properties' } --K0 :addData{ sdata.unlock_requirement, label = 'Unlock Requirements' } --K1 :addData{ sdata.max_level, label = 'Skill Max Level' } :done :addGroup{ header = 'Special Effects' } --L0 :addData{ sdata.skill_special_effect, label = 'Special Effect' } :done :addGroup{ header = 'Upgrades', layout = 'horizontal', ['row-items'] = 1 } --M0 :addData{ sdata.super_compactor, label = 'Super Compactor 3000' } :addGroup{ layout = 'horizontal', ['row-items'] = 2 } --M1 :addData{ sdata.compactor, label = 'Compactor' } --M2 :addData{ sdata.auto_smelter, label = 'Auto Smelter' } :done :done :addGroup{ header = 'Player interactions' } --N0 :addData { sdata.quests, label = 'Quests' } --N1 :addData { sdata.shop, label = 'Shop' } :done :addGroup{ header = 'Next Event', collapse = 'open' } --S0 :addData{ sdata.datetime, label = 'Date & Time' } --S1 :addData{ sdata.countdown, label = 'Happening In' } :done :addGroup{ header = 'Minimap (at Coordinates)', collapse = 'open' } --O0 :addData { sdata.minimap } :done :addGroup{ header = 'Metadata', ['row-items'] = 1, collapse = 'closed' } --Q0 :addData{ sdata.id, label = 'ID' } :done end return table.concat{ ibox:tostring, curTitle.namespace == 0 and category_to_add or '', } end

function p.test return p._infoboxCreate{ } end

--Finish Module/Exports return p