Tower of Saviors 維基
注册
Advertisement
Tower of Saviors 維基

此模块的文档可以在Module:Sandbox/doc创建

local m = {}

local errors = {}
local root, row, mode

-- ------------------------------- --
--             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='39px'}
            :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 5.46px'
        }
        :wikitext('[[File:'..file..'.png|39px|link=]]')
        :tag('span')
            :addClass('monsterLv')
            :css{['font-size']='9px', ['line-height']='10.92px'}
            :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 = div:tag('div'):css('margin-top','2.73px'):wikitext('[[File:Item'..args['item']..'.png|39px|link=]]')
        c = c+1
    end
    if args['chest'] then
        last = temp{'Texttip2',icon('ICON075',args['chest']),args['chest']..'金幣',classes='bottom'}
        div:wikitext(last)
        c = c+1
    end
    if args['soul'] then
        last = temp{'Texttip2',icon('Soul',args['soul']),args['soul']..'個靈魂',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['chest'] or drops['soul']) then return temp{
        'Texttip2',
        ' [[File:'..(drops['rare'] or rare[tonumber(temp{drops['card']['id'],'rare'})])..'卡.png|x20px|link=]]',
        '此層必定掉落一張封印卡',
        classes = 'line stageNote'
    } end

    if drops['item'] and not (drops['chest'] or drops['chest'] or drops['soul']) then return temp{
        'Texttip2',
        ' [[File:Item'..drops['item']..'.png|x20px|link=]]',
        '此層必定掉落指定物品。若物品已達上限則改為掉落寶箱(1500)',
        classes='line stageNote'
    } end
    
    return temp{'Texttip2',' [[File:DownArrow.png|x20px|link=]]','此層必定掉落',classes='line 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],
            chest = p[10][4],
            soul = p[10][5]
        },
        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 == nil then table.insert(errors,'Parse Error: Row '..tostring(i)..' < '..row..' >')
            else table.insert(rst, pr) end
        end
    end
    return rst
end

-- ------------------------------- --
--              MAIN               --
-- ------------------------------- --
function m.stage(frame)
    mode = nil
    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['chest'] or _dr['chest'], dr['soul'] or _dr['soul'],''} 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)
    mode = 'subst'
    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, chest=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.chest or dr.soul) then rst = rst .. '|' .. (rare[tonumber(temp{row.id,'rare'})] or '白金')
                elseif dr.item and not (dr.card or dr.chest or dr.soul) then rst = rst .. '|' .. dr.item
                elseif not (dr.card or dr.item or dr.chest 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
        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 .. '|chest=' .. row.drop.chest end
            if row.drop.soul then rst = rst .. '|soul=' .. row.drop.soul 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 .. '|}'
    
    if #errors > 0 then
        rst = rst .. '\n<!-- Module:Stage error report\n'
        for k,v in ipairs(errors) do rst = rst .. v .. '\n' end
        rst = rst .. '-->'
    end
    
    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

function m.parse(s,p,o) return parse(s,p,o) end

function m.m() return 1,2 end

return m
Advertisement