Files
Techmino/toolfunc.lua
2020-02-04 19:36:54 +08:00

626 lines
13 KiB
Lua

local tm=love.timer
local gc=love.graphics
local kb=love.keyboard
local setFont=setFont
local int,abs,rnd,max,min=math.floor,math.abs,math.random,math.max,math.min
local sub,find=string.sub,string.find
local ins,rem=table.insert,table.remove
local toN,toS=tonumber,tostring
local concat=table.concat
local function splitS(s,sep)
local t,n={},1
repeat
local p=find(s,sep)or #s+1
t[n]=sub(s,1,p-1)
n=n+1
s=sub(s,p+#sep)
until #s==0
return t
end
function mStr(s,x,y)
gc.printf(s,x-320,y,640,"center")
end
function mDraw(s,x,y)
gc.draw(s,x-s:getWidth()*.5,y)
end
function destroyPlayers()
for i=#players,1,-1 do
local P=players[i]
if P.canvas then P.canvas:release()end
while P.field[1]do
removeRow(P.field)
removeRow(P.visTime)
end
if P.AI_mode=="CC"then
BOT.free(P.bot_opt)
BOT.free(P.bot_wei)
BOT.destroy(P.AI_bot)
P.AI_mode=nil
end
players[i]=nil
end
for i=#players.alive,1,-1 do
players.alive[i]=nil
end
players.human=0
end
function getNewRow(val)
local t=rem(freeRow)
for i=1,10 do
t[i]=val
end
freeRow.L=freeRow.L-1
--get a row from buffer
if not freeRow[1]then
for i=1,10 do
freeRow[i]={0,0,0,0,0,0,0,0,0,0}
end
freeRow.L=freeRow.L+10
end
--prepare new rows
return t
end
function removeRow(t,k)
freeRow[#freeRow+1]=rem(t,k)
freeRow.L=freeRow.L+1
end
--Single-usage funcs
langName={"中文","全中文","English"}
local langID={"chi","chi_full","eng"}
local drawableTextLoad={
"next","hold",
"pause","finish",
"custom",
"setting_game","setting_graphic","setting_sound",
"keyboard","joystick",
"ctrlSetHelp",
"musicRoom",
"nowPlaying",
"warning",
}
function swapLanguage(l)
text=require("language/"..langID[l])
for S,L in next,Widget do
for N,W in next,L do
W.text=text.WidgetText[S][N]
end
end
gc.push("transform")
gc.origin()
royaleCtrlPad=gc.newCanvas(300,100)
gc.setCanvas(royaleCtrlPad)
gc.setColor(1,1,1)
setFont(25)
gc.setLineWidth(2)
for i=1,4 do
gc.rectangle("line",RCPB[2*i-1],RCPB[2*i],90,35,8,4)
mStr(text.atkModeName[i],RCPB[2*i-1]+45,RCPB[2*i]+3)
end
gc.pop()
gc.setCanvas()
for _,s in next,drawableTextLoad do
drawableText[s]:set(text[s])
end
collectgarbage()
end
function changeBlockSkin(n)
n=n-1
gc.push("transform")
gc.origin()
gc.setColor(1,1,1)
for i=1,13 do
gc.setCanvas(blockSkin[i])
gc.draw(blockImg,30-30*i,-30*n)
gc.setCanvas(blockSkinmini[i])
gc.draw(blockImg,6-6*i,-6*n,nil,.2)
end
gc.pop()
gc.setCanvas()
end
local vibrateLevel={0,.015,.02,.03,.04,.05,.06,.07,.08,.09}
function VIB(t)
if setting.vib>0 then
love.system.vibrate(vibrateLevel[setting.vib+t])
end
end
function SFX(s,v)
if setting.sfx>0 then
local n=1
::L::if sfx[s][n]:isPlaying()then
n=n+1
if not sfx[s][n]then
sfx[s][n]=sfx[s][n-1]:clone()
sfx[s][n]:seek(0)
goto quit
end
goto L
end::quit::
sfx[s][n]:setVolume((v or 1)*setting.sfx*.125)
sfx[s][n]:play()
end
end
function getFreeVoiceChannel()
local i=#voiceQueue
for i=1,i do
if #voiceQueue[i]==0 then return i end
end
voiceQueue[i+1]={}
return i+1
end
function VOICE(s,chn)
if setting.voc>0 then
if chn then
voiceQueue[chn][#voiceQueue[chn]+1]=voiceList[s][rnd(#voiceList[s])]
--添加到[chn]
else
voiceQueue[getFreeVoiceChannel()]={voiceList[s][rnd(#voiceList[s])]}
--自动查找/创建空轨
end
end
end
function BGM(s)
if setting.bgm>0 then
if bgmPlaying~=s then
if bgmPlaying then newTask(Event_task.bgmFadeOut,nil,bgmPlaying)end
for i=#Task,1,-1 do
local T=Task[i]
if T.code==Event_task.bgmFadeIn then
T.code=Event_task.bgmFadeOut
elseif T.code==Event_task.bgmFadeOut and T.data==s then
rem(Task,i)
end
end
if s then
newTask(Event_task.bgmFadeIn,nil,s)
bgm[s]:play()
end
bgmPlaying=s
else
if bgmPlaying then
local v=setting.bgm*.125
bgm[bgmPlaying]:setVolume(v)
if v>0 then
bgm[bgmPlaying]:play()
else
bgm[bgmPlaying]:pause()
end
end
end
elseif bgmPlaying then
bgm[bgmPlaying]:pause()
bgmPlaying=nil
end
end
local swapDeck_data={
{4,0,1,1},{6,0,15,1},{5,0,9,1},{6,0,6,1},
{1,0,3,1},{3,0,12,1},{1,1,8,1},{2,1,4,2},
{3,2,13,2},{4,1,12,2},{5,2,1,2},{7,1,11,2},
{2,1,9,3},{3,0,6,3},{4,2,14,3},{1,0,4,4},
{7,1,1,4},{6,0,2,4},{5,2,6,4},{6,0,14,5},
{3,3,15,5},{4,0,7,6},{7,1,10,5},{5,0,2,6},
{2,1,1,7},{1,0,4,6},{4,1,13,5},{1,1,6,7},
{5,3,11,5},{3,2,11,7},{6,0,8,7},{4,2,12,8},
{7,0,8,9},{1,0,2,8},{5,2,4,8},{6,0,15,8},
}--Block id [ZSLJTOI] ,dir,x,y
local swap={
none={2,1,d=NULL},
flash={8,1,d=function()gc.clear(1,1,1)end},
fade={30,15,d=function()
local t=1-abs(sceneSwaping.time*.06667-1)
gc.setColor(0,0,0,t)
gc.rectangle("fill",0,0,1280,720)
end},
deck={50,8,d=function()
local t=sceneSwaping.time
gc.setColor(1,1,1)
if t>8 then
local t=max(t,15)
for i=1,51-t do
local bn=swapDeck_data[i][1]
local b=blocks[bn][swapDeck_data[i][2]]
local cx,cy=swapDeck_data[i][3],swapDeck_data[i][4]
for y=1,#b do for x=1,#b[1]do
if b[y][x]then
gc.draw(blockSkin[bn],80*(cx+x-2),80*(10-cy-y),nil,8/3)
end
end end
end
end
if t<17 then
gc.setColor(1,1,1,(8-abs(t-8))*.125)
gc.rectangle("fill",0,0,1280,720)
end
end},
}--Scene swapping animations
function gotoScene(s,style)
if not sceneSwaping and s~=scene then
style=style or"fade"
sceneSwaping={
tar=s,style=style,
time=swap[style][1],mid=swap[style][2],
draw=swap[style].d
}
widget_sel=nil
if style~="none"then
SFX("swipe")
end
end
end
function updateStat()
for k,v in next,players[1].stat do
stat[k]=stat[k]+v
end
end
local prevMenu={
load=love.event.quit,
intro="quit",
main="intro",
music="main",
mode="main",
custom="mode",
draw="custom",
play=function()
kb.setKeyRepeat(true)
updateStat()
saveData()
clearTask("play")
gotoScene(curMode.id~="custom"and"mode"or"custom","deck")
end,
setting_game=function()
saveSetting()
gotoScene("main")
end,
setting_control="setting_game",
setting_touch= "setting_game",
help="main",
history="help",
stat="main",
}
prevMenu.pause=prevMenu.play
prevMenu.setting_graphic=prevMenu.setting_game
prevMenu.setting_sound=prevMenu.setting_game
function back()
local t=prevMenu[scene]
if type(t)=="string"then
gotoScene(t)
else
t()
end
end
function randomTarget(P)
if #players.alive>1 then
local R
repeat
R=players.alive[rnd(#players.alive)]
until R~=P
return R
end
end--return a random opponent for P
function freshMostDangerous()
mostDangerous,secDangerous=nil
local m,m2=0,0
for i=1,#players.alive do
local h=#players.alive[i].field
if h>=m then
mostDangerous,secDangerous=players.alive[i],mostDangerous
m,m2=h,m
elseif h>=m2 then
secDangerous=players.alive[i]
m2=h
end
end
end
function freshMostBadge()
mostBadge,secBadge=nil
local m,m2=0,0
for i=1,#players.alive do
local h=players.alive[i].badge
if h>=m then
mostBadge,secBadge=players.alive[i],mostBadge
m,m2=h,m
elseif h>=m2 then
secBadge=players.alive[i]
m2=h
end
end
end
function royaleLevelup()
gameStage=gameStage+1
local spd
if(gameStage==3 or gameStage>4)and players[1].alive then
players[1]:showText(text.royale_remain(#players.alive),"beat",50,-100,.3)
end
if gameStage==2 then
spd=30
elseif gameStage==3 then
spd=15
garbageSpeed=.6
if players[1].alive then BGM("cruelty")end
elseif gameStage==4 then
spd=10
pushSpeed=3
elseif gameStage==5 then
spd=5
garbageSpeed=1
elseif gameStage==6 then
spd=3
if players[1].alive then BGM("final")end
end
for i=1,#players.alive do
players.alive[i].gameEnv.drop=spd
end
if curMode.lv==3 then
for i=1,#players.alive do
local P=players.alive[i]
P.gameEnv.drop=int(P.gameEnv.drop*.3)
if P.gameEnv.drop==0 then
P.curY=P.y_img
P.gameEnv._20G=true
if P.AI_mode=="CC"then CC_switch20G(P)end--little cheating,never mind
end
end
end
end
function pauseGame()
pauseTimer=0--Pause timer for animation
if not gamefinished then
pauseCount=pauseCount+1
end
for i=1,#players.alive do
local l=players.alive[i].keyPressing
for j=1,#l do
if l[j]then
players.alive[i]:releaseKey(j)
end
end
end
gotoScene("pause","none")
end
function resumeGame()
gotoScene("play","fade")
end
function loadGame(mode,level)
--rec={}
curMode={id=modeID[mode],lv=level}
drawableText.modeName:set(text.modeName[mode])
drawableText.levelName:set(modeLevel[modeID[mode]][level])
needResetGameData=true
gotoScene("play","deck")
end
function resetPartGameData()
frame=30
destroyPlayers()
loadmode[curMode.id]()
if modeEnv.task then
for i=1,#players do
newTask(Event_task[modeEnv.task],players[i])
end
end
if modeEnv.royaleMode then
for i=1,#players do
players[i]:changeAtk(randomTarget(players[i]))
end
end
for i=1,#virtualkey do
virtualkey[i].press=false
end
collectgarbage()
end
function resetGameData()
gamefinished=false
frame=0
garbageSpeed=1
pushSpeed=3
pauseTime=0--Time paused
pauseCount=0--Times paused
destroyPlayers()
local E=defaultModeEnv[curMode.id]
modeEnv=E[curMode.lv]or E[1]
loadmode[curMode.id]()--bg/bgm need redefine in custom,so up here
if modeEnv.task then
for i=1,#players do
newTask(Event_task[modeEnv.task],players[i])
end
end
curBG=modeEnv.bg
BGM(modeEnv.bgm)
FX_badge={}
FX_attack={}
for _,v in next,PTC.dust do
v:release()
end
for i=1,#players do
if not players[i].small then
PTC.dust[i]=PTC.dust0:clone()
PTC.dust[i]:start()
end
end
if modeEnv.royaleMode then
for i=1,#players do
players[i]:changeAtk(randomTarget(players[i]))
end
mostBadge,mostDangerous,secBadge,secDangerous=nil
gameStage=1
garbageSpeed=.3
pushSpeed=2
end
for i=1,#virtualkey do
virtualkey[i].press=false
end
stat.game=stat.game+1
local m,p=#freeRow,40*#players+1
while freeRow[p]do
m,freeRow[m]=m-1
end
freeRow.L=#freeRow
SFX("ready")
collectgarbage()
end
function gameStart()
SFX("start")
for P=1,#players do
P=players[P]
P:resetblock()
P.timing=true
P.control=true
end
end
local dataOpt={
"run","game","time",
"key","rotate","hold","piece","row",
"atk","send","recv","pend",
"clear_1","clear_2","clear_3","clear_4",
"spin_0","spin_1","spin_2","spin_3",
"b2b","b3b","pc","score",
}
function loadData()
userData:open("r")
local t=userData:read()
if not find(t,"spin")then
t=love.data.decompress("string","zlib",t)
end
t=splitS(t,"\r\n")
userData:close()
for i=1,#t do
local p=find(t[i],"=")
if p then
local t,v=sub(t[i],1,p-1),sub(t[i],p+1)
if t=="gametime"then t="time"end
for i=1,#dataOpt do
if t==dataOpt[i]then
v=toN(v)if not v or v<0 then v=0 end
stat[t]=v
break
end
end
end
end
end
function saveData()
local t={}
for i=1,#dataOpt do
t[i]=dataOpt[i].."="..toS(stat[dataOpt[i]])
end
t=concat(t,"\r\n")
userData:open("w")
userData:write(t)
userData:close()
end
function loadSetting()
userSetting:open("r")
local t=userSetting:read()
if not find(t,"virtual")then
t=love.data.decompress("string","zlib",t)
end
t=splitS(t,"\r\n")
userSetting:close()
for i=1,#t do
local p=find(t[i],"=")
if p then
local t,v=sub(t[i],1,p-1),sub(t[i],p+1)
if t=="sfx"or t=="bgm"or t=="voc"then
setting[t]=toN(v:match("[012345678]"))or setting[t]
elseif t=="vib"then
setting.vib=toN(v:match("[012345]"))or 0
elseif t=="fullscreen"then
setting.fullscreen=v=="true"
love.window.setFullscreen(setting.fullscreen)
elseif t=="virtualkeyAlpha"then
setting.virtualkeyAlpha=min(int(abs(toN(v))),10)
elseif
t=="ghost"or t=="center"or t=="grid"or t=="swap"or
t=="quickR"or t=="bgblock"or t=="smo"or
t=="virtualkeyIcon"or t=="virtualkeySwitch"
then
setting[t]=v=="true"
elseif t=="frameMul"then
setting.frameMul=min(max(toN(v)or 100,0),100)
elseif t=="das"or t=="arr"or t=="sddas"or t=="sdarr"then
v=toN(v)if not v or v<0 then v=0 end
setting[t]=int(v)
elseif t=="dropFX"or t=="shakeFX"or t=="atkFX"then
setting[t]=toN(v:match("[0123]"))or 0
elseif t=="lang"then
setting[t]=toN(v:match("[123]"))or 1
elseif t=="skin"then
setting[t]=toN(v:match("[12345678]"))or 1
elseif t=="keymap"then
v=splitS(v,"/")
for i=1,16 do
local v1=splitS(v[i],",")
for j=1,#v1 do
setting.keyMap[i][j]=v1[j]
end
end
elseif t=="virtualkey"then
v=splitS(v,"/")
for i=1,10 do
if v[i]then
virtualkey[i]=splitS(v[i],",")
for j=1,4 do
virtualkey[i][j]=toN(virtualkey[i][j])
end
end
end
end
end
end
end
local saveOpt={
"das","arr",
"sddas","sdarr",
"quickR",
"swap",
"ghost","center",
"smo","grid",
"dropFX",
"shakeFX",
"atkFX",
"frameMul",
"fullscreen",
"bg",
"bgblock",
"lang",
"skin",
"sfx","bgm",
"vib","voc",
"virtualkeyAlpha",
"virtualkeyIcon",
"virtualkeySwitch",
}
function saveSetting()
local vk={}
for i=1,10 do
for j=1,4 do
virtualkey[i][j]=int(virtualkey[i][j]+.5)
end--Saving a integer is better?
vk[i]=concat(virtualkey[i],",")
end--pre-pack virtualkey setting
local map={}
for i=1,16 do
map[i]=concat(setting.keyMap[i],",")
end
local t={
"keymap="..toS(concat(map,"/")),
"virtualkey="..toS(concat(vk,"/")),
}
for i=1,#saveOpt do
t[i+2]=saveOpt[i].."="..toS(setting[saveOpt[i]])
--not always i+2!
end
t=concat(t,"\r\n")
userSetting:open("w")
userSetting:write(t)
userSetting:close()
end