此模块的文档可以在Module:Stage/doc创建
local m = {}
local root, row
-- ------------------------------- --
-- Helpers --
-- ------------------------------- --
local function substing()
return mw.getCurrentFrame():preprocess('{{NAMESPACE}}') == '{{NAMESPACE}}'
end
local function temp(args)
local rst = mw.getCurrentFrame():expandTemplate{title=table.remove(args,1), args=args}
if substing() then
local _, _, c = mw.ustring.find(rst, '|'..args[1]..'%s*=%s*([^}|]*)')
return c and mw.text.trim(c) or '{{'..table.concat(args,'|')..'}}'
else return rst end
end
local function conv(n)
return string.gsub(n,'0000$','萬')
end
-- ------------------------------- --
-- Table Parts --
-- ------------------------------- --
local function header(tbl)
tbl = tbl or root
tbl:tag('tr')
:tag('th')
:css{width='35px'}
:wikitext('層數')
:done()
:tag('th')
:attr('colspan',2)
:css{width='27%'}
:wikitext('敵人')
:done()
:tag('th')
:css{width='36px'}
:wikitext('攻擊')
:done()
:tag('th')
:css{width='22px'}
:wikitext(temp{'Texttip2','CD','敵人作出攻擊後重置的CD數, 進入該層時初始CD數為此值一半(向上取整)至+1隨機, 括號內數值表示初始CD固定等於該數值'})
:done()
:tag('th')
:css{width='50px'}
:wikitext('HP')
:done()
:tag('th')
:css{width='42px'}
:wikitext('防禦')
:done()
:tag('th')
:css{width='41px'}
:wikitext('掉落')
:done()
:tag('th')
:css{width='30px'}
:wikitext('金幣')
:done()
:tag('th')
:wikitext('備註')
return tostring(h)
end
local function attr(id)
local t = {['水']='w', ['火']='f', ['風']='e', ['雷']='l', ['無']='d'}
return t[temp{id,'attr'}]
end
local function extra(arg)
if arg == nil then return '' end
if arg == '' then return '<br/>'..temp{'Texttip2','亂入','在指定層數(未指定則代表隨機非固定層)稀有單獨出現',classes='line'}
else return '<br/>'..temp{'Texttip2','隨機'..(arg~='1' and arg or ''), '隨機出現其中'..arg..'隻',classes='line'} end
end
local function name(id,num)
local tbl = mw.html.create('table')
tbl:addClass('stageDataName'):tag('tr')
:tag('td')
:wikitext(temp{id,45})
:done()
:tag('td')
:wikitext(temp{id,'name'}..(num and ' ×'..num or ''))
return tostring(tbl)
end
local function cd(nrm,init)
return nrm .. (init and temp{'Texttip2', init, '進入此層時的初始CD'} or '')
end
local function icon(file,text)
local div = mw.html.create('div')
:css{
position = 'relative',
width = '39px',
height = '39px',
margin = '0 0 3.46px'
}
:wikitext('[[File:'..file..'.png|39px|link=]]')
:tag('span')
:addClass('monsterLv')
:css{['font-size']='8pt', ['line-height']='18.92px',['text-align']='center',['white-space']='nowrap',['background-image']='none'}
:wikitext(text)
:allDone()
return tostring(div)
end
local function drop(args)
if args == nil then return '無' end
local div = mw.html.create('div'):addClass('stageDataDrop')
local c = 0
local last
if args['card'] then
last = div:tag('div'):wikitext(temp{'MonsterLv', args['card']['id'], args['card']['lv'], 39})
c = c+1
end
if args['item'] then
last = temp{'Item',args['item']}
div:wikitext(last)
c = c+1
end
if args['coin'] then
last = temp{'Texttip2',icon('Coin',args['coin']),args['coin']..'金幣',classes='bottom'}
div:wikitext(last)
c = c+1
end
if c == 0 then return '無'
elseif c == 1 then return tostring(last)
else return tostring(div)..'<div class="stageDataDropMore"><span class="stageDataDropPlus">+</span></div>' end
end
local function dropnote(drops)
if drops == nil then return '' end
local rare = {'黃','銅','銀','金','白金','白金','白金','白金'}
if drops['rare'] or drops['card'] and not (drops['item'] or drops['coin'] or drops['soul'] or drops['craft']) then return temp{
'Texttip2',
' [[File:'..(drops['rare'] or rare[tonumber(temp{drops['card']['id'],'rare'})])..'卡.png|x20px|link=]]',
'必定掉落一張封印卡',
classes = 'stageNote'
} end
if drops['item'] and not (drops['coin'] or drops['coin'] or drops['soul'] or drops['craft']) then return temp{
'Texttip2',
' [[File:Item'..drops['item']..'.png|x20px|link=]]',
'必定掉落指定物品。若物品已達上限則改為掉落寶箱(1500)',
classes='stageNote'
} end
return temp{'Texttip2',' [[File:DownArrow.png|x20px|link=]]','此層必定掉落',classes='stageNote'}
end
local function addRow(args,class,tbl)
tbl = tbl or root
local row = tbl:tag('tr'):addClass(class)
local td1,td2
if args['stage']=='' then td1 = row:tag('td'):wikitext(args[1]):addClass('random')
elseif args['stage']==nil then td1 = ''
else td1 = row:tag('td'):wikitext(args['stage']):addClass('stage') end
if args['special']==nil then
td2 = nil
row:tag('td'):attr('colspan',2):wikitext(name(args['id'],args['num']))
elseif args['special']=='' then
td2 = ''
row:tag('td'):wikitext(name(args['id'],args['num']))
else
td2 = row:tag('td'):wikitext(mw.getCurrentFrame():preprocess(args['special']))
row:tag('td'):wikitext(name(args['id'],args['num']))
end
local atk = conv(args['atk'])
local cell = row:tag('td'):wikitext(atk)
if mw.ustring.len(atk)>5 then cell:css('letter-spacing','-1px') end
row:tag('td'):wikitext(args['cd'] and cd(args['cd'],args['init']) or temp{args['id'],'turn'})
local hp = conv(args['hp'])
local cell = row:tag('td'):wikitext(hp)
if mw.ustring.len(hp)>7 then cell:css('letter-spacing','-1px') end
local def = conv(args['def'] or temp{args['id'],'def'})
local cell = row:tag('td'):wikitext(def)
if mw.ustring.len(def)>6 then cell:css('letter-spacing','-1px') end
local spec = args['special'] and args['special']~=''
row:tag('td'):css({position='relative', overflow='hidden'}):wikitext(drop(spec and {} or args['drop']))
row:tag('td'):wikitext(spec and 0 or args['coin'] or '')
row:tag('td'):wikitext(args['note'] and mw.getCurrentFrame():preprocess(args['note']) or '')
return td1,td2
end
-- ------------------------------- --
-- Parsers --
-- ------------------------------- --
local function parse(str,patt,pos)
local ret,orig = {},pos or 1
pos = orig
for i,p in ipairs(patt) do
if type(p) == 'table' then ret[i],pos = parse(str,p,pos)
else
local op = (string.sub(p,1,1) ~= '^')
local j,k,cap = string.find(str, (op and p or string.sub(p,2)), pos)
if j ~= pos then
if op then ret[i] = nil
else return nil,orig end
else
ret[i] = cap or string.sub(str,j,k)
pos = k+1
end
end
end
return ret,pos
end
local function parseRow(row)
local p = parse(row,{
{'%*','^%d+','/(%d*)'},'^%s*:','%s*([^;]-)%s*;','^%s*(%d+)','[x×](%d+)','^%s+(%d*)/',{'^%d+','%(%d+%)'},'^/(%d*)/','%d+',
{'^%s+%[',{'%d+','^@(%d+)'},'%s*%f[^%s%[]#(%d+)','%s*%f[^%s%[]$(%d+)','%s*%f[^%s%[]O(%d+)','^%]%s*'}
,'%s*[%s%+]$(%d+)','%s*:(.+)'
})
return p and {
fixdrop = p[1] and p[1][1],
stage = p[1] and (p[1][2]=='0' and '' or p[1][2]),
extra = p[1] and p[1][3],
special = p[3],
id = p[4],
num = p[5],
atk = p[6],
cd = p[7] and p[7][1],
init = p[7] and p[7][2],
hp = p[8],
def = p[9],
drop = p[10] and (p[10][2] or p[10][3] or p[10][4] or p[10][5]) and {
card = p[10][2] and {id = p[10][2][1] or p[4], lv = p[10][2][2]},
item = p[10][3],
coin = p[10][4],
soul = p[10][5],
craft = p[10][6]
},
coin = p[11],
note = p[12]
}
end
local function parseRows(rows)
local rst = {}
for i,row in ipairs(rows) do
if row ~= '' then
local pr = parseRow(row)
if pr then table.insert(rst, pr) end
end
end
return rst
end
-- ------------------------------- --
-- MAIN --
-- ------------------------------- --
function m.stage(frame)
root = mw.html.create('table')
root:addClass('wikitable stageData')
header()
rows = parseRows(mw.text.split(frame.args[1], '\n'))
local c1, c2, row, td1, td2, dr, ex = 1,1
while 1 do
repeat row = table.remove(rows,1) until row ~= ''
if row == nil then break end
local _td1, _td2 = addRow(row,'attr-'..attr(row['id']))
local _dr, _ex = row['fixdrop'] and (row['drop'] or {}), row['stage'] and extra(row['extra'])
if _td1 == nil then error(row) end
if _td2 == '' then c2 = c2 + 1
elseif _td2 then
if td2 then td2:attr('rowspan',c2) end
td2, c2 = _td2, 1
end
if _ex == nil then
if _dr then dr = dr and {'', dr['card'] or _dr['card'], dr['item'] or _dr['item'], dr['coin'] or _dr['coin'], dr['soul'] or _dr['soul'], dr['craft'] or _dr['craft'],''} end
c1 = c1 + 1
else
if td1 then td1:attr('rowspan',c1):wikitext(dropnote(dr)):wikitext(ex) end
td1, dr, ex, c1 = _td1, _dr, _ex, 1
end
end
if td2 then td2:attr('rowspan',c2) end
if td1 then td1:attr('rowspan',c1):wikitext(dropnote(dr)):wikitext(ex) end
return tostring(root)
end
function m.subst(frame)
local rst = '{{關卡數據標題}}\n'
local rows = parseRows(mw.text.split(frame.args[1], '\n'))
local rare = {'黃','銅','銀','金','白金','白金','白金','白金'}
for i,row in ipairs(rows) do
rst = rst .. '{{關卡數據|' .. row.id
if row.stage~='' then
rst = rst .. '|stage=' .. (row.stage or '')
if row.fixdrop then
local j,dr = i,{card=nil, item=nil, coin=nil, soul=nil}
repeat
if rows[j].drop then for k,v in pairs(rows[j].drop) do dr[k] = dr[k] or v end end
j = j+1
until not rows[j] or rows[j].stage
rst = rst .. '{{掉落'
if dr.card and not (dr.item or dr.coin or dr.soul) then rst = rst .. '|' .. (rare[tonumber(temp{row.id,'rare'})] or '白金')
elseif dr.item and not (dr.card or dr.coin or dr.soul) then rst = rst .. '|' .. dr.item
elseif not (dr.card or dr.item or dr.coin or dr.soul) then table.insert(errors, 'Fixdrop: No drop in stage '..row.stage) end
rst = rst .. '}}'
end
if row.extra then rst = rst .. (row.extra=='' and '{{亂入}}' or '{{隨機'..(row.extra=='1' and '' or '|'..row.extra)..'}}') end
end
if row.num then rst = rst .. '|num=' .. row.num end
if row.special then rst = rst .. '|special=' .. row.special end
rst = rst .. '|damage=' .. conv(row.atk)
rst = rst .. '|turn=' .. (row.cd or temp{row.id, 'turn'})
if row.init then rst = rst .. '{{初始CD|' .. row.init .. '}}' end
rst = rst .. '|hp=' .. conv(row.hp)
rst = rst .. '|def=' .. (row.def and conv(row.def) or temp{row.id, 'def'})
if row.drop then
if row.drop.card and row.drop.card.id ~= row.id then rst = rst .. '|drop=' .. row.drop.card.id end
if row.drop.card and row.drop.card.lv then rst = rst .. '|lv=' .. row.drop.card.lv end
if row.drop.item then rst = rst .. '|item=' .. row.drop.item end
if row.drop.chest then rst = rst .. '|coin=' .. row.drop.coin end
if row.drop.soul then rst = rst .. '|soul=' .. row.drop.soul end
if row.drop.craft then rst = rst .. '|craft=' .. row.drop.craft end
end
if row.coin then rst = rst .. '|coin=' .. row.coin end
if row.note then rst = rst .. '|note=' .. row.note end
rst = rst .. '}}\n'
end
rst = rst .. '|}'
return rst
end
function m.header(frame) return header(mw.html.create('')) end
function m.drop(frame)
local args = frame:getParent().args
local drps = {}
for k,v in pairs(args) do
drps[k] = (v~='' or nil) and v
end
drps['card'] = drps['lv'] and {id=drps['drop'], lv=drps['lv']}
return drop(drps)
end
function m.dropnote(frame)
local arg = frame:getParent().args[1]
if not arg then
return dropnote{}
elseif string.find(arg,'^%d+$') then
return dropnote{item=arg}
else
return dropnote{rare=arg}
end
end
return m