模块:PFTest
{{pf2|lcase=mini|w=1|
[ ijlostzg ]
[ IJLOSTZG ]
}}
|
| |
{{pf2|sys=arika|w=1|
[ IJLOSTZG ]
}}
|
| |
{{pf2|small=1|w=1|
[ IJLOSTZG ]
[ ijlostzg ]
[ IJLOSTZG ]
[ ijlostzg ]
}}
|
| |
{{pf2|.0=xd9a9a9|.1=xba71ba|
[ - X 0 1 2 ]
[ z L0o0SmIlj3T4g ]
[ 0 1 ]
}}
|
| |
{{pf2|sys=arikaw|
[ J L ]
[ I S Z ]
[ G T O ]
}}
|
| |
{{pf2|
[a0a1a2a3a4a5a6a7a8a9Z1Z2z1z2]
[Z L O S I J T G - Z3Z4z3z4]
[B0B X ALARAlArADAHAUL1L2l1l2]
[ZmLmOmSmImJmTmBlg GlL3L4l3l4]
[ O1O2o1o2]
[z l o s i j t O3O4o3o4]
[ZlLlOlSlIlJlTl S1S2s1s2]
[zmlmomsmimjmtmGm S3S4s3s4]
[Z0L0O0S0I0J0T0G0 0 I1I2i1i2]
[z0l0o0s0i0j0t0 I3I4i3i4]
[ J1J2j1j2]
[ J3J4j3j4]
[ T1T2t1t2]
[ T3T4t3t4]
}}
|
|
施工中,格式尚未定型。
文件名
图片存在 $wgServer/tet/ 下,文件命名方式(省略“.png”),暂定全用小写字母数字(在windows上操作不撞车不爆炸):
- SKIN-COLOR(-LUCASETAG)(-MODIFIERs)
- empty、cross、dotted(皮肤无关类特殊单块)
- arrow-NAME
- ascii-NAME
SKIN指皮肤名,默认且最常用为plain,另有arika arikaw gb thenew等。可用参数“skin=SKIN”指定。
COLOR指每个方块对应什么颜色(广义),可能是单词(大致颜色类,区分了purple和magenta?),或者是(以后扩展)xRRGGBB(一些具体的旋转系统,基本只用于plain)。除非是类似gb,无彩色且用花纹区分各种块,则此时COLOR也会是 i j l o s t z 等方块名。可用参数“color=COLORSCHEME”指定,现有super sega thenew direct。
可用参数“sys=ROTSYS”一次指定以上两项一套,现有super sega arika arikaw gb thenew。
皮肤混用用法待思考【
LUCASETAG部分,取决于大小写的解释方式,也就是可指定添加到文件名后的后缀,用参数“ucase=TAG” “lcase=TAG”指定,会自动加“-”分隔,空则不加。默认为lcase无,lcase=dark。
如默认情况下“t”就会生成文件名“plain-purple-dark.png”。
文件完全由服务器管理员单独维护,不在维基的“文件”系统内(正是因为每渲染一个块都要用这个系统缩略图,所以很慢)。目前尚在手工添加。之后的添加需求联系User:Farter。
本体语法
参数“w”,默认w=2,每2个字符代表一个 mino。第一个字符为块名(ijlostz g b)或A、a、-、X(可能继续添加)或空格。
无名参数即为场地数据,每行用[]包裹,每行内容字符数必须为w的倍数。每W字符中,第一个字符为:
- 对于
块、X、-,后续字符每个为一个修改符。可用参数“M.X=MODIFIER”新增定义,X为字符,modifier为文件名上新的一截。现有字符dlm01234对应dark light mini 五种旋转中心。空格也可以接修改符01234。 - 对于
A(对应箭头、占格标记)宽度内的后续字符视作整体“箭头名”。现有字符L R U D l r对应left right up down ccw cw。可用“A.XX=ARROWNAME”新增定义。 - 对于
a(对应ascii字符)宽度内的后续字符视作整体“字符名”,普通字符已定义为直接单字对应。{、|、}、[、]、<、>这些特殊字符,可用参数“a.XX=HH”新增定义。XX为字符名,HH为字符的十六进制码。可能参考添加预制。 - 可用参数“.X=COLOR”新增定义一种用字符X表示的mino对应的颜色(广义)。
参数总结
w=CELLWIDTH sys=ROTSYS color=COLORSCHEME skin=SKIN lcase=TAG ucase=TAG .X=COLOR M.X=MODIFIER A.XX=ARROWN a.XX=ASCIIHEX
local mwServer=mw.site.server
local function split(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t = {}
for part in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
table.insert(t, part)
end
return t
end
local function tableassign(dst,src)
for k,v in pairs(src) do -- merge/override
dst[k]=v
end
return dst
end
local function message(msg, id)
-- Return formatted message text for an error or warning.
local categories = {
error = '[[Category:PF模块错误]]',
warning = '[[Category:PF模块错误]]', -- same as error until determine whether 'Age warning' would be worthwhile
}
local a, b, category
if id == 'warning' then
a = '<sup>[<i>'
b = '</i>]</sup>'
else
a = '<strong class="error">错误:'
b = '</strong>'
end
if mw.title.getCurrentTitle():inNamespaces(0) then
-- Category only in namespaces: 0=article.
category = categories[id or 'error']
end
return
a ..
mw.text.nowiki(msg) ..
b ..
(category or '')
end
local p={}
function p.genempty()
local sImgL,sImgR=[[<img src="]]..mwServer..[[/tet/]],[[empty.png">]]
local sRow="<div>"..string.rep(sImgL..sImgR,10).."</div>"
local sField=string.rep(sRow,20)
local sAll= [=[{| class="pfield" style="line-height: 10px; font-size: 7px; border: 1px solid #999"
|]=]..sField.."\n|}"
return sAll
end
function p.test(frame)
local argfield=frame.args[1]
local args=tableassign({},frame.args)
local pargs=frame:getParent().args -- must be called in template
for k,v in pairs(pargs) do -- merge/override
args[k]=v
end
local t={} -- join
for k,v in pairs(args) do
table.insert(t,"["..k.."]="..v)
end
return table.concat(t,"\n\n").."\n\n"..table.concat(split(argfield,"\n"),",")
end
-- Sanitizer.php validateAttributes hrefExp should be changed to allow relative path
local sImgL=[[<img src="]]..mwServer..[[/tet/]]
sImgL=[[<img src="/tet/]]
local sImgRb=[[.png" width="12" height="12">]]
local sImgRs=[[.png" width="8" height="8">]]
local function genRow(row,small)
local sb={}
local sImgR = small and sImgRs or sImgRb
for i=1,#row do
sb[i]=sImgL..row[i]..sImgR
end
local sRow="<div>"..table.concat(sb,"").."</div>"
return sRow
end
local function genRows(rows,small)
local sb={}
for i=1,#rows do
sb[i]=genRow(rows[i],small)
end
local sField=table.concat(sb)
local sAll
if small then sAll=
[=[{| class="pfield" style="line-height: 5px; font-size: 5px; border: 1px solid #999"
|]=]..sField.."\n|}"
else sAll=
[=[{| class="pfield" style="line-height: 7px; font-size: 7px; border: 1px solid #999"
|]=]..sField.."\n|}"
end
return sAll
end
-- normalize to lower case
local colorSuper={
i="cyan",t="purple",o="yellow",s="green",z="red",j="blue",l="orange",g="gray",b="black"
}
local colorSega={
i="red",t="cyan",o="yellow",s="magenta",z="green",j="blue",l="orange",g="gray"
}
local colorTheNew={
i="cyan",t="yellow",o="silver",s="green",z="red",j="purple",l="magenta",g="gray"
}
local colorDirect={
i="i",t="t",o="o",s="s",z="z",j="j",l="l",g="g"
}
local colorDict={
sega=colorSega,super=colorSuper,thenew=colorTheNew,direct=colorDirect,
""
}
local sysDict={
sega={color=colorSega,skin="sega"},
arika={color=colorSega,skin="arika"},
arikaw={color=colorSuper,skin="arikaw"},
super={color=colorSuper,skin="plain"},
gb={color=colorDirect,skin="gb"},
thenew={color=colorTheNewTetris,skin="thenew"},
""
}
local skinDict={
sega=1,arika=1,arikaw=1,plain=1,gb=1,thenew=1,
""
}
-- SKIN-COLOR-LUCASE-MODIFIERs
-- arrow-SECOND
-- ascii-ASCIIHEX
local function isBadComponent(s)
return s:match("^[a-z0-9_-]*$")==nil
end
local function checkShortDef(s)
s=mw.text.trim(s)
if #s==0 then return false end
for i=1,#s do
local b=s:byte(i)
if b<=32 or b>=127 then return false end
end
return s
end
function p._field(args)
local argfield=args[1]
if not argfield then return message("no arg for field (unnamed first argument, without '=')") end
local rows=split(argfield,"\n")
if #rows==0 then return message("arg for field looks like empty") end
local w=2 -- per mino
local skin='plain'
local minoDict=tableassign({},colorSuper)
local primDict={[' ']='empty',['-']='dotted',X='cross'}
local modiDict={
['0']='rot0',['1']='rot1',['2']='rot2',['3']='rot3',['4']='rot4', -- overlay
m='mini',d='dark',l='light', -- modifier
[' ']=' ',
""
}
local arrowDict={
['L']='left',['R']='right',['U']='up',['D']='down',['l']='ccw',['r']='cw',["H"]="uptack"
}
local asciiDict={['']='20'}
for i=33,127 do
local sAscii=string.char(i)
local sHex=string.format("%x",i)
asciiDict[sAscii]=sHex
end
local argSys=args.sys
if argSys~=nil then
if sysDict[argSys]==nil then return message("argument sys: rotation system not found") end
minoDict=tableassign({},sysDict[argSys].color)
skin=sysDict[argSys].skin
end
local argSkin=args.skin
if argSkin~=nil then
if skinDict[argSkin]==nil then return message("argument skin: skin not found") end
skin=argSkin
end
local argColor=args.color
if argColor~=nil then
if colorDict[argColor]==nil then return message("argument color: color scheme not found") end
minoDict=tableassign({},colorDict[argColor])
end
local argW=tonumber(args.w)
if argW~=nil then
argw=math.floor(argW)
if argW<1 and argW>4 then return message("argument w: should be 1 to 4") end
w=argW
end
local argSmall=not not args.small
local ucase,lcase="","dark" -- default ucase lcase semantics
for k,v in pairs(args) do
if type(k)=="number" then
elseif k:sub(1,1)=="." then -- mino
if #k~=2 then return message("argument .X specify mino color: should only add 1 char") end
local byte=k:byte(2)
if byte<32 or byte>127 then return message("argument .X: invalid char to define") end
if isBadComponent(v) then return message("argument .X: invalid component") end
minoDict[k:sub(2,2)]=v
elseif k:sub(1,2)=="M." then -- modifier or overlay
if #k<3 then return message("argument M.X: should follow 1-3 chars to define as modifier") end
k=checkShortDef(k)
if k==false then return message("argument M.X: invalid name to define") end
if isBadComponent(v) then return message("argument M.X: invalid component") end
modiDict[k:sub(3)]=v
elseif k:sub(1,2)=="A." then -- arrow or other markers
if #k<3 then return message("argument A.X: should follow 1-3 chars to define as arrow/marker") end
k=checkShortDef(k)
if k==false then return message("argument A.X: invalid name to define") end
if isBadComponent(v) then return message("argument A.X: invalid component") end
arrowDict[k:sub(3)]=v
elseif k:sub(1,2)=="a." then -- ascii char
if #k<3 then return message("argument a.X: should follow 1-3 chars to define as ascii char") end
k=checkShortDef(k)
if k==false then return message("argument a.X: invalid name to define") end
if v.match("^%x%x$")==nil then return message("argument a.X: value should be exactly 2 hexadecimal digits") end
asciiDict[k:sub(3)]=v
elseif k=="lcase" or k=="ucase" then
if isBadComponent(v) then return message("argument ucase/lcase: invalid component") end
if k=="ucase" then ucase=v end
if k=="lcase" then lcase=v end
end -- ignore others
end
local tfield={}
for y,srow in ipairs(rows) do
local dbgy="line "..y.." "
if #srow<4 then return message(dbgy.."too short") end
if srow:sub(1,1)~="[" or srow:sub(-1,-1)~="]" then return message(dbgy.."should be enclosed by []") end
srow=srow:sub(2,-2)
if #srow%w~=0 then return message(dbgy.."number of chars within [] should be multiple of "..w) end
trow={}
local n=#srow/w
for x=1,n do
local dbgx=dbgy.."mino "..x.." "
local sslice=srow:sub((x-1)*w+1,(x-1)*w+w)
local smino=sslice:sub(1,1)
local sminoLow=smino:lower()
local tmino
if minoDict[sminoLow]~=nil or primDict[smino]~=nil then
tmino=minoDict[sminoLow] or primDict[smino]
if primDict[smino]==nil then -- is mino
tmino=skin..'-'..tmino
local isUCase=smino:match("^%u$")~=nil
local isLCase=smino:match("^%l$")~=nil
if isUCase and ucase~="" then
tmino=tmino..'-'..ucase
elseif isLCase and lcase~="" then
tmino=tmino..'-'..lcase
end
end
for i=2,w do
local smodi=sslice:sub(i,i)
if smodi==' 'then -- nothing
elseif modiDict[smodi]~=nil then
tmino=tmino..'-'..modiDict[smodi]
else
return message(dbgx.."modifier invalid, mdl01234")
end
end
elseif smino=='A' then
tmino='arrow'
local sarrow=arrowDict[mw.text.trim(sslice:sub(2))]
if sarrow==nil then return message(dbgx.."arrow/marker invalid, LRUDlr") end
tmino=tmino..'-'..sarrow
elseif smino=='a' then
tmino='ascii'
local sascii=asciiDict[mw.text.trim(sslice:sub(2))]
if sascii==nil then return message(dbgx.."ascii invalid") end
tmino=tmino..'-'..sascii
else
return message(dbgx.."unrecognized first char, mino or X-Aa but got "..smino)
end
trow[x]=tmino
end
tfield[y]=trow
end
return genRows(tfield,argSmall)
end
function p.field(frame)
local args=tableassign({},frame.args)
local pargs=frame:getParent().args -- must be called in template
tableassign(args,pargs)
return p._field(args)
end
return p