[Z-framework stand alone ready]

This commit is contained in:
MrZ_26
2020-07-05 14:46:02 +08:00
parent e1d92a166b
commit 40de030cae
20 changed files with 554 additions and 540 deletions

View File

@@ -5,10 +5,6 @@ local int,rnd,max,min=math.floor,math.random,math.max,math.min
local abs=math.abs
local rem=table.remove
kb.setKeyRepeat(true)
kb.setTextInput(false)
ms.setVisible(false)
local scr=scr
local xOy=love.math.newTransform()
local mx,my,mouseShow=-20,-20,false
@@ -17,7 +13,6 @@ local touchDist=nil
joysticks={}
local devMode
players={alive={},human=0}
local Tmr=require("timer")
local Pnt=require("paint")
@@ -153,7 +148,7 @@ local function onMode(x,y)
local cam=mapCam
x=(cam.x1-640+x)/cam.k1
y=(cam.y1-360+y)/cam.k1
local MM,R=modes,modeRanks
local MM,R=Modes,modeRanks
for _=1,#MM do
if R[_]then
local M=MM[_]
@@ -199,7 +194,7 @@ function mouseClick.mode(x,y,k)
if __ then
SFX.play("click")
cam.moving=true
_=modes[__]
_=Modes[__]
cam.x=_.x*cam.k+180
cam.y=_.y*cam.k
cam.sel=__
@@ -402,17 +397,17 @@ function mouseDown.setting_sound(x,y,k)
VOC.play((t<1.5 or t>15)and"doubt"or rnd()<.8 and"happy"or"egg")
sceneTemp.last=Timer()
if rnd()<.0626 then
for i=1,#modes do
local M=modes[i]
for i=1,#Modes do
local M=Modes[i]
for i=1,#M.unlock do
local m=M.unlock[i]
if not modeRanks[m]then
modeRanks[m]=modes[m].score and 0 or 6
modeRanks[m]=Modes[m].score and 0 or 6
end
end
end
FILE.saveUnlock()
TEXT.show("DEVMODE:UNLOCKALL",640,360,50,"stretch",.6)
TEXT.show("DEVModes:UNLOCKALL",640,360,50,"stretch",.6)
end
end
end

View File

@@ -6,7 +6,7 @@ function love.conf(t)
t.gammacorrect=false
t.appendidentity=true--search files in source before save directory
t.accelerometerjoystick=false--accelerometer=joystick on ios/android
t.audio.mixwithsystem=true
if t.audio then t.audio.mixwithsystem=true end
local W=t.window
W.title="Techmino "..gameVersion

View File

@@ -2,8 +2,15 @@
Techmino is my first "huge project"
optimization is welcomed if you also love tetromino game
]]
--Global Setting & Vars
package.path="./?.lua;./parts/?.lua;./modules/?.lua"
math.randomseed(os.time()*626)
--Global vars
love.keyboard.setKeyRepeat(true)
love.keyboard.setTextInput(false)
love.mouse.setVisible(false)
function NULL()end
system=love.system.getOS()
game={}
mapCam={
@@ -22,46 +29,49 @@ mapCam={
scr={x=0,y=0,w=0,h=0,rad=0,k=1}--wid,hei,radius,scale K
customSel={1,22,1,1,7,3,1,1,8,4,1,1,1}
preField={h=20}for i=1,20 do preField[i]={0,0,0,0,0,0,0,0,0,0}end
function NULL()end
players={alive={},human=0}
--blockSkin,blockSkinMini={},{}--redefined in SKIN.change
--Load modules
setFont=require("parts/setfont")
color=require("parts/color")
blocks=require("parts/mino")
SHADER=require("parts/shader")
AITemplate=require("parts/AITemplate")
freeRow=require("parts/freeRow")
tickEvent=require("parts/tickEvent")
color= require("color")
blocks= require("mino")
AITemplate= require("AITemplate")
freeRow= require("freeRow")
require("parts/list")
require("toolfunc")
require("list")
require("gametoolfunc")
require("texture")
require("default_data")
SCN=require("scene")
VIB=require("parts/vib")
SFX=require("parts/sfx")
sysFX=require("parts/sysFX")
BGM=require("parts/bgm")
VOC=require("parts/voice")
SKIN=require("parts/skin")
LANG=require("parts/languages")
FILE=require("parts/file")
TEXT=require("parts/text")
TASK=require("parts/task")
BG=require("parts/bg")
IMG=require("parts/img")
WIDGET=require("parts/widget")
LIGHT=require("parts/light")
SKIN= require("skin")
PLY= require("player")
AIfunc= require("ai")
Modes= require("modes")
require("parts/modes")
require("parts/default_data")
require("parts/ai")
PLY=require("player")
widgetList=require("widgetList")
--load Z's Framework
SHADER= require("shader")
VIB= require("vib")
SFX= require("sfx")
sysFX= require("sysFX")
BG= require("bg")
BGM= require("bgm")
VOC= require("voice")
LANG= require("languages")
FILE= require("file")
TEXT= require("text")
TASK= require("task")
IMG= require("img")
WIDGET= require("widget")
Widgets=require("widgetList")
LIGHT= require("light")
SCN= require("scene")
require("callback")
--load files & settings
modeRanks={}for i=1,#Modes do modeRanks[i]=false assert(i==Modes[i].id,"ModeID error:"..i)end
modeRanks[1]=0
local fs=love.filesystem
if fs.getInfo("keymap.dat")then fs.remove("keymap.dat")end
if fs.getInfo("setting.dat")then fs.remove("setting.dat")end

View File

@@ -22,7 +22,7 @@ return{
getRank=function(P)
local L=P.stat.row
return
L>=2600 and 5 or
L>=2000 and 5 or
L>=1500 and 4 or
L>=1000 and 3 or
L>=500 and 2 or

View File

@@ -27,7 +27,7 @@ return{
getRank=function(P)
local L=P.stat.pc
return
L>=25 and 5 or
L>=24 and 5 or
L>=20 and 4 or
L>=16 and 3 or
L>=13 and 2 or

View File

@@ -152,7 +152,7 @@ function Pnt.mode()
gc.scale(cam.zoomK)
gc.translate(-cam.x1,-cam.y1)
gc.scale(cam.k1)
local MM=modes
local MM=Modes
local R=modeRanks
local sel=cam.sel
setFont(30)

View File

@@ -192,7 +192,7 @@ local function getScore(field,cb,cy)
return score
end
-------------------------------------------------
AI_think={
return{
["9S"]={
function(P,ctrl)
local Tfield={}--test field

View File

@@ -1,5 +1,22 @@
local min=math.min
local rem=table.remove
local function fadeOut(_,id)
local src=BGM.list[id]
local v=src:getVolume()-.025*setting.bgm*.1
src:setVolume(v>0 and v or 0)
if v<=0 then
src:stop()
return true
end
end
local function fadeIn(_,id)
local src=BGM.list[id]
local v=min(src:getVolume()+.025*setting.bgm*.1,setting.bgm*.1)
src:setVolume(v)
if v>=setting.bgm*.1 then return true end
end
local BGM={
--nowPlay=[str:playing ID]
--suspend=[str:pausing ID]
@@ -36,12 +53,12 @@ function BGM.play(s)
return
end
if BGM.nowPlay~=s then
if BGM.nowPlay then TASK.new(tickEvent.bgmFadeOut,nil,BGM.nowPlay)end
TASK.changeCode(tickEvent.bgmFadeIn,tickEvent.bgmFadeOut)
if BGM.nowPlay then TASK.new(fadeOut,nil,BGM.nowPlay)end
TASK.changeCode(fadeIn,fadeOut)
TASK.removeTask_data(s)
BGM.nowPlay,BGM.suspend=s
TASK.new(tickEvent.bgmFadeIn,nil,s)
TASK.new(fadeIn,nil,s)
BGM.playing=BGM.list[s]
BGM.playing:play()
end
@@ -64,9 +81,9 @@ function BGM.freshVolume()
end
function BGM.stop()
if BGM.nowPlay then
TASK.new(tickEvent.bgmFadeOut,nil,BGM.nowPlay)
TASK.new(fadeOut,nil,BGM.nowPlay)
end
TASK.changeCode(tickEvent.bgmFadeIn,tickEvent.bgmFadeOut)
TASK.changeCode(fadeIn,fadeOut)
BGM.playing,BGM.nowPlay=nil
end
return BGM

304
parts/gametoolfunc.lua Normal file
View File

@@ -0,0 +1,304 @@
local tm,gc=love.timer,love.graphics
local kb,data=love.keyboard,love.data
local int,abs,rnd=math.floor,math.abs,math.random
local max,min=math.max,math.min
local sub,find=string.sub,string.find
local char,byte=string.char,string.byte
local ins,rem=table.insert,table.remove
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
freeRow.discard(rem(P.field))
freeRow.discard(rem(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
collectgarbage()
end
function restoreVirtualKey()
for i=1,#VK_org do
local B,O=virtualkey[i],VK_org[i]
B.ava=O.ava
B.x=O.x
B.y=O.y
B.r=O.r
B.isDown=false
B.pressTime=0
end
if not modeEnv.Fkey then
virtualkey[9].ava=false
end
end
function copyBoard()
local str=""
local H=0
for y=20,1,-1 do
for x=1,10 do
if preField[y][x]~=0 then
H=y
goto L
end
end
end
::L::
for y=1,H do
local S=""
local L=preField[y]
for x=1,10 do
S=S..char(L[x]+1)
end
str=str..S
end
love.system.setClipboardText("Techmino sketchpad:"..data.encode("string","base64",data.compress("string","deflate",str)))
TEXT.show(text.copySuccess,350,360,40,"appear",.5)
end
function pasteBoard()
local str=love.system.getClipboardText()
local fX,fY=1,1--*ptr for Field(r*10+(c-1))
local _,Bid
local p=find(str,":")--ptr*
if p then str=sub(str,p+1)end
_,str=pcall(data.decode,"string","base64",str)
if not _ then goto ERROR end
_,str=pcall(data.decompress,"string","deflate",str)
if not _ then goto ERROR end
p=1
while true do
_=byte(str,p)--1byte
if not _ then
if fX~=1 then goto ERROR
else break
end
end--str end
__=_%32-1--block id
if __>17 then goto ERROR end--illegal blockid
_=int(_/32)--mode id
preField[fY][fX]=__
if fX<10 then
fX=fX+1
else
if fY==20 then break end
fX=1;fY=fY+1
end
p=p+1
end
for y=fY+1,20 do
for x=1,10 do
preField[y][x]=0
end
end
do return end
::ERROR::TEXT.show(text.dataCorrupted,350,360,35,"flicker",.5)
end
function mergeStat(stat,delta)
for k,v in next,delta do
if type(v)=="table"then
mergeStat(stat[k],v)
else
stat[k]=stat[k]+v
end
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()
game.mostDangerous,game.secDangerous=nil
local m,m2=0,0
for i=1,#players.alive do
local h=#players.alive[i].field
if h>=m then
game.mostDangerous,game.secDangerous=players.alive[i],game.mostDangerous
m,m2=h,m
elseif h>=m2 then
game.secDangerous=players.alive[i]
m2=h
end
end
end
function freshMostBadge()
game.mostBadge,game.secBadge=nil
local m,m2=0,0
for i=1,#players.alive do
local h=players.alive[i].badge
if h>=m then
game.mostBadge,game.secBadge=players.alive[i],game.mostBadge
m,m2=h,m
elseif h>=m2 then
game.secBadge=players.alive[i]
m2=h
end
end
end
function royaleLevelup()
game.stage=game.stage+1
local spd
TEXT.show(text.royale_remain(#players.alive),640,200,40,"beat",.3)
if game.stage==2 then
spd=30
elseif game.stage==3 then
spd=15
game.garbageSpeed=.6
if players[1].alive then BGM.play("cruelty")end
elseif game.stage==4 then
spd=10
local _=players.alive
for i=1,#_ do
_[i].gameEnv.pushSpeed=3
end
elseif game.stage==5 then
spd=5
game.garbageSpeed=1
elseif game.stage==6 then
spd=3
if players[1].alive then BGM.play("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()
if not SCN.swapping then
restartCount=0--Avoid strange darkness
if not game.result then
game.pauseCount=game.pauseCount+1
end
for i=1,#players do
local l=players[i].keyPressing
for j=1,#l do
if l[j]then
players[i]:releaseKey(j)
end
end
end
SCN.swapTo("pause","none")
end
end
function resumeGame()
SCN.swapTo("play","none")
end
function loadGame(M)
--rec={}
stat.lastPlay=M
curMode=Modes[M]
local lang=setting.lang
drawableText.modeName:set(text.modes[M][1])
drawableText.levelName:set(text.modes[M][2])
needResetGameData=true
SCN.swapTo("play","fade_togame")
SFX.play("enter")
end
function resetPartGameData()
game={
result=false,
pauseTime=0,
pauseCount=0,
garbageSpeed=1,
warnLVL0=0,
warnLVL=0,
}
frame=150-setting.reTime*15
destroyPlayers()
curMode.load()
TEXT.clear()
if modeEnv.task then
for i=1,#players do
players[i].newTask(modeEnv.task)
end
end
if modeEnv.royaleMode then
for i=1,#players do
players[i]:changeAtk(randomTarget(players[i]))
end
end
BG.set(modeEnv.bg)
BGM.play(modeEnv.bgm)
if modeEnv.royaleMode then
for i=1,#players do
players[i]:changeAtk(randomTarget(players[i]))
end
game.stage=1
game.garbageSpeed=.3
end
restoreVirtualKey()
collectgarbage()
end
function resetGameData()
game={
result=false,
pauseTime=0,--Time paused
pauseCount=0,--Pausing count
garbageSpeed=1,--garbage timing speed
warnLVL0=0,
warnLVL=0,
}
frame=150-setting.reTime*15
destroyPlayers()
modeEnv=curMode.env
curMode.load()--bg/bgm need redefine in custom,so up here
if modeEnv.task then
for i=1,#players do
players[i].newTask(modeEnv.task)
end
end
BG.set(modeEnv.bg)
BGM.play(modeEnv.bgm)
TEXT.clear()
FX_badge={}
FX_attack={}
if modeEnv.royaleMode then
for i=1,#players do
players[i]:changeAtk(randomTarget(players[i]))
end
game.stage=1
game.garbageSpeed=.3
end
restoreVirtualKey()
stat.game=stat.game+1
freeRow.reset(30*#players)
SFX.play("ready")
collectgarbage()
end
function gameStart()
SFX.play("start")
for P=1,#players do
P=players[P]
P:popNext()
P.timing=true
P.control=true
end
end

View File

@@ -44,6 +44,10 @@ if setting.lang==1 then
"jstris 也很好玩!",
"tetr.io 也很好玩!",
"nullpomino 也很好玩!",
"↑↑↓↓←→←→BABA",
"草(日本语)",
"dym,永远的神",
"iced,永远的神",
}
elseif setting.lang==2 then
L={
@@ -90,6 +94,10 @@ elseif setting.lang==2 then
"jstris 也很好玩!",
"tetr.io 也很好玩!",
"nullpomino 也很好玩!",
"↑↑↓↓←→←→BABA",
"草(日本语)",
"dym,永远的神",
"iced,永远的神",
}
elseif setting.lang==3 then
L={
@@ -137,6 +145,11 @@ elseif setting.lang==3 then
"Also try jstris!",
"Also try tetr.io!",
"Also try nullpomino!",
"↑↑↓↓←→←→BABA",
"wwwwww",
"diaoyoumei so bully",
"iced so bully",
"diao so bully",
}
elseif setting.lang==4 then
L={'!','@','#','$','%','^','&','*','(',')','-','=','_','+','[',']','{','}','\\','|',';',':','\'','"',',','<','.','>','/','?'}

View File

@@ -1749,7 +1749,7 @@ function LANG.getLen()
end
function LANG.set(l)
text=langList[l]
for S,L in next,widgetList do
for S,L in next,Widgets do
for N,W in next,L do
W.text=text.WidgetText[S][N]
end

View File

@@ -1,4 +1,4 @@
modes={
return{
{"sprint_10", id=1, x=0, y=0, size=35,shape=1,icon="sprint", unlock={2,3}},
{"sprint_20", id=2, x=-300, y=0, size=45,shape=1,icon="sprint", unlock={}},
{"sprint_40", id=3, x=0, y=-400, size=55,shape=1,icon="sprint", unlock={4,9,71,72,73}},
@@ -82,10 +82,4 @@ modes={
{"custom_clear", id=71, x=200, y=-350, size=45,shape=3,icon="custom", unlock={}},
{"custom_puzzle", id=72, x=200, y=-200, size=45,shape=3,icon="puzzle", unlock={}},
{"sprintPenta", id=73, x=-200, y=-200, size=45,shape=3,icon="sprint", unlock={}},
}
modeRanks={}
for i=1,#modes do
modeRanks[i]=false
assert(i==modes[i].id,"ModeID error:"..i)
end
modeRanks[1]=0
}

View File

@@ -1,17 +0,0 @@
local new=love.graphics.setNewFont
local set=love.graphics.setFont
local F,cur={}
return function(s)
local f=F[s]
if s~=cur then
if f then
set(f)
else
f=new("font.ttf",s)
F[s]=f
set(f)
end
cur=s
end
return f
end

View File

@@ -1,71 +0,0 @@
local min=math.min
local mini=love.window.isMinimized
local tickEvent={}
function tickEvent.finish(P)
if SCN.cur~="play"then return true end
P.endCounter=P.endCounter+1
if P.endCounter>120 then pauseGame()end
end
function tickEvent.lose(P)
P.endCounter=P.endCounter+1
if P.endCounter>80 then
for i=1,#P.field do
for j=1,10 do
if P.visTime[i][j]>0 then
P.visTime[i][j]=P.visTime[i][j]-1
end
end
end
if P.endCounter==120 then
for _=#P.field,1,-1 do
freeRow.discard(P.field[_])
freeRow.discard(P.visTime[_])
P.field[_],P.visTime[_]=nil
end
if #players==1 and SCN.cur=="play"then
pauseGame()
end
return true
end
end
end
function tickEvent.throwBadge(A,data)
data[2]=data[2]-1
if data[2]%4==0 then
local S,R=data[1],data[1].lastRecv
local x1,y1,x2,y2
if S.small then
x1,y1=S.centerX,S.centerY
else
x1,y1=S.x+308*S.size,S.y+450*S.size
end
if R.small then
x2,y2=R.centerX,R.centerY
else
x2,y2=R.x+66*R.size,R.y+344*R.size
end
FX_badge[#FX_badge+1]={x1,y1,x2,y2,t=0}
--generate badge object
if not A.ai and data[2]%8==0 then
SFX.play("collect")
end
end
if data[2]<=0 then return true end
end
function tickEvent.bgmFadeOut(_,id)
local src=BGM.list[id]
local v=src:getVolume()-.025*setting.bgm*.1
src:setVolume(v>0 and v or 0)
if v<=0 then
src:stop()
return true
end
end
function tickEvent.bgmFadeIn(_,id)
local src=BGM.list[id]
local v=min(src:getVolume()+.025*setting.bgm*.1,setting.bgm*.1)
src:setVolume(v)
if v>=setting.bgm*.1 then return true end
end
return tickEvent

View File

@@ -239,7 +239,7 @@ local function Pupdate_alive(P,dt)
local C=P.AI_keys
P.AI_delay=P.AI_delay-1
if not C[1]then
P.AI_stage=AI_think[P.AI_mode][P.AI_stage](P,C)
P.AI_stage=AIfunc[P.AI_mode][P.AI_stage](P,C)
elseif P.AI_delay<=0 then
P:pressKey(C[1])P:releaseKey(C[1])
rem(C,1)
@@ -581,10 +581,12 @@ local function Pdraw_norm(P)
gc.setColor(1,1,1,trans)
local x=30*(P.curX+P.sc[2]-1)-15
gc.draw(IMG.spinCenter,x,600-30*(P.curY+P.sc[1]-1)+15,nil,nil,nil,4,4)
gc.translate(0,dy)
gc.setColor(1,1,1,.5)
gc.draw(IMG.spinCenter,x,600-30*(P.y_img+P.sc[1]-1)+15,nil,nil,nil,4,4)
goto E
if P.gameEnv.ghost then
gc.translate(0,dy)
gc.setColor(1,1,1,.5)
gc.draw(IMG.spinCenter,x,600-30*(P.y_img+P.sc[1]-1)+15,nil,nil,nil,4,4)
goto E
end
end--Rotate center
gc.translate(0,dy)
end
@@ -1770,6 +1772,60 @@ end
--------------------------</Methods>--------------------------
--------------------------<Events>--------------------------
local tick={}
function tick.finish(P)
if SCN.cur~="play"then return true end
P.endCounter=P.endCounter+1
if P.endCounter>120 then pauseGame()end
end
function tick.lose(P)
P.endCounter=P.endCounter+1
if P.endCounter>80 then
for i=1,#P.field do
for j=1,10 do
if P.visTime[i][j]>0 then
P.visTime[i][j]=P.visTime[i][j]-1
end
end
end
if P.endCounter==120 then
for _=#P.field,1,-1 do
freeRow.discard(P.field[_])
freeRow.discard(P.visTime[_])
P.field[_],P.visTime[_]=nil
end
if #players==1 and SCN.cur=="play"then
pauseGame()
end
return true
end
end
end
function tick.throwBadge(A,data)
data[2]=data[2]-1
if data[2]%4==0 then
local S,R=data[1],data[1].lastRecv
local x1,y1,x2,y2
if S.small then
x1,y1=S.centerX,S.centerY
else
x1,y1=S.x+308*S.size,S.y+450*S.size
end
if R.small then
x2,y2=R.centerX,R.centerY
else
x2,y2=R.x+66*R.size,R.y+344*R.size
end
FX_badge[#FX_badge+1]={x1,y1,x2,y2,t=0}
--generate badge object
if not A.ai and data[2]%8==0 then
SFX.play("collect")
end
end
if data[2]<=0 then return true end
end
local function gameOver()
FILE.saveData()
local M=curMode
@@ -1787,7 +1843,7 @@ local function gameOver()
for i=1,#M.unlock do
local m=M.unlock[i]
if not modeRanks[m]then
modeRanks[m]=modes[m].score and 0 or 6
modeRanks[m]=Modes[m].score and 0 or 6
_=true
end
end
@@ -1857,7 +1913,7 @@ function player.win(P,result)
if P.human then
gameOver()
end
TASK.new(tickEvent.finish,P)
TASK.new(tick.finish,P)
end
function player.lose(P)
if P.life>0 then
@@ -1901,7 +1957,7 @@ function player.lose(P)
end
P.lastRecv=A
if P.id==1 or A.id==1 then
TASK.new(tickEvent.throwBadge,A,{P,max(3,P.badge)*4})
TASK.new(tick.throwBadge,A,{P,max(3,P.badge)*4})
end
freshMostBadge()
end
@@ -1934,7 +1990,9 @@ function player.lose(P)
end
end
gameOver()
TASK.new(#players>1 and tickEvent.lose or tickEvent.finish,P)
TASK.new(#players>1 and tick.lose or tick.finish,P)
else
TASK.new(tick.lose,P)
end
if #players.alive==1 then
players.alive[1]:win()
@@ -2090,6 +2148,7 @@ function player.act.insLeft(P,auto)
end
if x0~=P.curX then
if P.gameEnv.easyFresh or y0~=P.curY then P:freshLockDelay()end
P.spinLast=false
end
if P.gameEnv.shakeFX then
P.fieldOff.vx=-P.gameEnv.shakeFX*.5
@@ -2112,6 +2171,7 @@ function player.act.insRight(P,auto)
end
if x0~=P.curX then
if P.gameEnv.easyFresh or y0~=P.curY then P:freshLockDelay()end
P.spinLast=false
end
if P.gameEnv.shakeFX then
P.fieldOff.vx=P.gameEnv.shakeFX*.5

View File

@@ -29,7 +29,7 @@ function sceneInit.load()
#BGM.list,
#SFX.list,
IMG.getCount(),
#modes,
#Modes,
1,
},
skip=false,--if skipping
@@ -68,7 +68,7 @@ function sceneInit.mode(org)
local cam=mapCam
cam.zoomK=org=="main"and 5 or 1
if cam.sel then
local M=modes[cam.sel]
local M=Modes[cam.sel]
cam.x,cam.y=M.x*cam.k+180,M.y*cam.k
cam.x1,cam.y1=cam.x,cam.y
end
@@ -246,7 +246,7 @@ function sceneInit.stat()
end
function sceneInit.history()
BG.set("strap")
sceneTemp={require("updateLog"),1}--scroll pos
sceneTemp={require("parts/updateLog"),1}--scroll pos
end
function sceneInit.quit()
love.timer.sleep(.3)
@@ -293,7 +293,7 @@ function SCN.swapUpdate()
if S.time==S.mid then
SCN.init(S.tar,SCN.cur)
SCN.cur=S.tar
WIDGET.set(widgetList[S.tar])
WIDGET.set(Widgets[S.tar])
collectgarbage()
--Scene swapped this moment
end

View File

@@ -18,9 +18,9 @@ function Tmr.load()
elseif S.phase==4 then
IMG.loadOne(S.cur)
elseif S.phase==5 then
local m=modes[S.cur]
modes[S.cur]=require("modes/"..m[1])
local M=modes[S.cur]
local m=Modes[S.cur]
Modes[S.cur]=require("modes/"..m[1])
local M=Modes[S.cur]
M.saveFileName,M.id=m[1],m.id
M.x,M.y,M.size,M.shape=m.x,m.y,m.size,m.shape
M.unlock=m.unlock
@@ -105,7 +105,7 @@ function Tmr.mode(dt)
cam.keyCtrl=true
end
local x,y=(cam.x1-180)/cam.k1,cam.y1/cam.k1
local MM,R=modes,modeRanks
local MM,R=Modes,modeRanks
for _=1,#MM do
if R[_]then
local __
@@ -142,7 +142,7 @@ function Tmr.mode(dt)
cam.zoomMethod=_=="play"and 1 or _=="mode"and 2
if cam.zoomMethod==1 then
if cam.sel then
local M=modes[cam.sel]
local M=Modes[cam.sel]
cam.x=cam.x*.8+M.x*cam.k*.2
cam.y=cam.y*.8+M.y*cam.k*.2
end

View File

@@ -1,11 +1,26 @@
local tm,gc=love.timer,love.graphics
local kb,data=love.keyboard,love.data
local int,abs,rnd=math.floor,math.abs,math.random
local max,min=math.max,math.min
local sub,find=string.sub,string.find
local format,char,byte=string.format,string.char,string.byte
local ins,rem=table.insert,table.remove
local gc=love.graphics
local fontData=love.filesystem.newFile("font.ttf")
local newFont=gc.setNewFont
local setNewFont=gc.setFont
local fontCache,currentFontSize={}
function setFont(s)
local f=fontCache[s]
if s~=currentFontSize then
if f then
setNewFont(f)
else
f=newFont(fontData,s)
fontCache[s]=f
setNewFont(f)
end
currentFontSize=s
end
return f
end
local int=math.floor
local format=string.format
function toTime(s)
if s<60 then
return format("%.3fs",s)
@@ -24,301 +39,4 @@ function mText(s,x,y)
end
function mDraw(s,x,y,a,k)
gc.draw(s,x,y,a,k,nil,s:getWidth()*.5,s:getHeight()*.5)
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
freeRow.discard(rem(P.field))
freeRow.discard(rem(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
collectgarbage()
end
--Single-usage funcs
function restoreVirtualKey()
for i=1,#VK_org do
local B,O=virtualkey[i],VK_org[i]
B.ava=O.ava
B.x=O.x
B.y=O.y
B.r=O.r
B.isDown=false
B.pressTime=0
end
if not modeEnv.Fkey then
virtualkey[9].ava=false
end
end
function copyBoard()
local str=""
local H=0
for y=20,1,-1 do
for x=1,10 do
if preField[y][x]~=0 then
H=y
goto L
end
end
end
::L::
for y=1,H do
local S=""
local L=preField[y]
for x=1,10 do
S=S..char(L[x]+1)
end
str=str..S
end
love.system.setClipboardText("Techmino sketchpad:"..data.encode("string","base64",data.compress("string","deflate",str)))
TEXT.show(text.copySuccess,350,360,40,"appear",.5)
end
function pasteBoard()
local str=love.system.getClipboardText()
local fX,fY=1,1--*ptr for Field(r*10+(c-1))
local _,Bid
local p=find(str,":")--ptr*
if p then str=sub(str,p+1)end
_,str=pcall(data.decode,"string","base64",str)
if not _ then goto ERROR end
_,str=pcall(data.decompress,"string","deflate",str)
if not _ then goto ERROR end
p=1
while true do
_=byte(str,p)--1byte
if not _ then
if fX~=1 then goto ERROR
else break
end
end--str end
__=_%32-1--block id
if __>17 then goto ERROR end--illegal blockid
_=int(_/32)--mode id
preField[fY][fX]=__
if fX<10 then
fX=fX+1
else
if fY==20 then break end
fX=1;fY=fY+1
end
p=p+1
end
for y=fY+1,20 do
for x=1,10 do
preField[y][x]=0
end
end
do return end
::ERROR::TEXT.show(text.dataCorrupted,350,360,35,"flicker",.5)
end
function mergeStat(stat,delta)
for k,v in next,delta do
if type(v)=="table"then
mergeStat(stat[k],v)
else
stat[k]=stat[k]+v
end
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()
game.mostDangerous,game.secDangerous=nil
local m,m2=0,0
for i=1,#players.alive do
local h=#players.alive[i].field
if h>=m then
game.mostDangerous,game.secDangerous=players.alive[i],game.mostDangerous
m,m2=h,m
elseif h>=m2 then
game.secDangerous=players.alive[i]
m2=h
end
end
end
function freshMostBadge()
game.mostBadge,game.secBadge=nil
local m,m2=0,0
for i=1,#players.alive do
local h=players.alive[i].badge
if h>=m then
game.mostBadge,game.secBadge=players.alive[i],game.mostBadge
m,m2=h,m
elseif h>=m2 then
game.secBadge=players.alive[i]
m2=h
end
end
end
function royaleLevelup()
game.stage=game.stage+1
local spd
TEXT.show(text.royale_remain(#players.alive),640,200,40,"beat",.3)
if game.stage==2 then
spd=30
elseif game.stage==3 then
spd=15
game.garbageSpeed=.6
if players[1].alive then BGM.play("cruelty")end
elseif game.stage==4 then
spd=10
local _=players.alive
for i=1,#_ do
_[i].gameEnv.pushSpeed=3
end
elseif game.stage==5 then
spd=5
game.garbageSpeed=1
elseif game.stage==6 then
spd=3
if players[1].alive then BGM.play("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()
if not SCN.swapping then
restartCount=0--Avoid strange darkness
if not game.result then
game.pauseCount=game.pauseCount+1
end
for i=1,#players do
local l=players[i].keyPressing
for j=1,#l do
if l[j]then
players[i]:releaseKey(j)
end
end
end
SCN.swapTo("pause","none")
end
end
function resumeGame()
SCN.swapTo("play","none")
end
function loadGame(M)
--rec={}
stat.lastPlay=M
curMode=modes[M]
local lang=setting.lang
drawableText.modeName:set(text.modes[M][1])
drawableText.levelName:set(text.modes[M][2])
needResetGameData=true
SCN.swapTo("play","fade_togame")
SFX.play("enter")
end
function resetPartGameData()
game={
result=false,
pauseTime=0,
pauseCount=0,
garbageSpeed=1,
warnLVL0=0,
warnLVL=0,
}
frame=150-setting.reTime*15
destroyPlayers()
curMode.load()
TEXT.clear()
if modeEnv.task then
for i=1,#players do
TASK.new(modeEnv.task,players[i])
end
end
if modeEnv.royaleMode then
for i=1,#players do
players[i]:changeAtk(randomTarget(players[i]))
end
end
BG.set(modeEnv.bg)
BGM.play(modeEnv.bgm)
if modeEnv.royaleMode then
for i=1,#players do
players[i]:changeAtk(randomTarget(players[i]))
end
game.stage=1
game.garbageSpeed=.3
end
restoreVirtualKey()
collectgarbage()
end
function resetGameData()
game={
result=false,
pauseTime=0,--Time paused
pauseCount=0,--Pausing count
garbageSpeed=1,--garbage timing speed
warnLVL0=0,
warnLVL=0,
}
frame=150-setting.reTime*15
destroyPlayers()
modeEnv=curMode.env
curMode.load()--bg/bgm need redefine in custom,so up here
if modeEnv.task then
for i=1,#players do
TASK.new(modeEnv.task,players[i])
end
end
BG.set(modeEnv.bg)
BGM.play(modeEnv.bgm)
TEXT.clear()
FX_badge={}
FX_attack={}
if modeEnv.royaleMode then
for i=1,#players do
players[i]:changeAtk(randomTarget(players[i]))
end
game.stage=1
game.garbageSpeed=.3
end
restoreVirtualKey()
stat.game=stat.game+1
freeRow.reset(30*#players)
SFX.play("ready")
collectgarbage()
end
function gameStart()
SFX.play("start")
for P=1,#players do
P=players[P]
P:popNext()
P.timing=true
P.control=true
end
end

View File

@@ -7,54 +7,25 @@ local S=[=[
Alan
幽灵3383
靏鸖龘龘
込余
[rmb10+]:
八零哥
蕴空之灵
gggf127
dtg
ThTsOd
Fireboos
金巧
10元
立斐
Deep_Sea
时雪
yyangdid
sfqr
心痕
Sasoric
夏小亚
仁参
乐↗乐↘
喜欢c4w的ztcjoin
面包
蠢熏
潘一栗
Lied
星街书婉
込余
祝西
829
e m*12
我永远爱白银诺艾尔(鹏
PCX
kagura77
呆喂
GlowingEmbers
轩辕辚
HimuroAki
TCV100
tech有养成系统了@7065
HAGE KANOBU
闪电和拐棍
葡萄味的曼妥思
世界沃德
蓝绿
八零哥 蕴空之灵 gggf127 dtg
ThTsOd Fireboos 金巧 10元
立斐 Deep_Sea 时雪 yyangdid
sfqr 心痕 Sasoric 夏小亚
仁参 乐↗乐↘ 喜欢c4w的ztcjoin 面包
蠢熏 潘一栗 Lied 星街书婉
祝西 829 e m*12 我永远爱白银诺艾尔(鹏
PCX kagura77 呆喂 GlowingEmbers
轩辕辚 HimuroAki TCV100 tech有养成系统了@7065
HAGE KANOBU 闪电和拐棍 葡萄味的曼妥思 世界沃德
蓝绿 天生的魔法师 saki 琳雨空
Thanks!!!
Future outlook:
New mode:
PUYO
game tutorial
finesse tutorial
game Abbr. test
@@ -71,8 +42,9 @@ Future outlook:
dig zen
sprint_symmetry
hidden: sound only
reverb mode (often repeat a piece many times)
KPP-locked mode
reverb (often repeat a piece many times)
KPP-locked
parkour
Other:
mod system with:
block hidden
@@ -86,13 +58,17 @@ Future outlook:
15 puzzle
mine sweeper
2048
tank battle
time-based-rank for master advanced mode(1:58/228/303/300P/100P)
简易防沉迷系统
next SFX
full-key control
dragging control
"next" SFX
new layout of player (rectangle so stupid)
better drop FX
60+ fps supporting
in-game document
lang setting page
dragging control
game recording
new widgets (joystick etc.)
custom sequence(TTT!)
@@ -103,14 +79,28 @@ Future outlook:
network game
new AI: task-Z
0.8.25: Custom Sequence Update
new:
--TODO: custom sequence
changed:
little easier to get S in PC challenge (easy mode)
easier to get S in infinite mode
code:
file sorted
fixed:
hard move won't deactive "spin"
do not clear dead enemies' field
show ghost's center when ghost is off
0.8.24: Bug Fixed
new:
ready to refuse auto-formating stats. if update from versions too old
changed:
little changing of pentomini wallkicks
little changing of pentomino wallkick list
fixed:
incorrect color of P/Q
rank of petomino may be [custom]
0.8.23: Details Update
new:
new hidden BGM: Hay what kind of feeling

View File

@@ -1,4 +1,5 @@
mobileHide=(system=="Android"or system=="iOS")and function()return true end
local mobileHide=(system=="Android"or system=="iOS")and function()return true end
local function BACK()SCN.back()end
local virtualkeySet={
{
{1, 80, 720-200, 80},--moveLeft
@@ -87,7 +88,7 @@ local function setLang(n) return function()LANG.set(n)setting.lang=n end end
local newButton,newSwitch,newSlider=WIDGET.new.button,WIDGET.new.switch,WIDGET.new.slider
local C=color
local widgetList={
local Widgets={
load={},intro={},quit={},
main={
play= newButton(150,280,200,160,C.lightRed, 55,function()SCN.push()SCN.swapTo("mode")end, nil,"setting"),
@@ -103,7 +104,7 @@ local widgetList={
draw= newButton(1100, 440,240,90,C.lightYellow, 40,function()SCN.push()SCN.swapTo("draw")end,function()return mapCam.sel~=71 and mapCam.sel~=72 end),
custom= newButton(1100, 540,240,90,C.lightGreen, 40,function()SCN.push()SCN.swapTo("custom")end,function()return mapCam.sel~=71 and mapCam.sel~=72 end),
start= newButton(1040, 655,180,80,C.lightGrey, 40,function()if mapCam.sel then SCN.push()loadGame(mapCam.sel)end end,function()return not mapCam.sel end),
back= newButton(1200, 655,120,80,C.white, 40,SCN.back),
back= newButton(1200, 655,120,80,C.white, 40,BACK),
--function()SCN.push()SCN.swapTo("custom")end
},
music={
@@ -111,7 +112,7 @@ local widgetList={
up= newButton(1100, 200,120,120,C.white,55,pressKey("up")),
play= newButton(1100, 340,120,120,C.white,35,pressKey("space"),function()return setting.bgm==0 end),
down= newButton(1100, 480,120,120,C.white,55,pressKey("down")),
back= newButton(640, 630,230,90, C.white,40,SCN.back),
back= newButton(640, 630,230,90, C.white,40,BACK),
},
custom={
up= newButton(1000, 360,100,100,C.white, 45,function()sceneTemp=(sceneTemp-2)%#customID+1 end),
@@ -123,7 +124,7 @@ local widgetList={
set3= newButton(640, 340,240,75, C.lightYellow, 35,pressKey("3")),
set4= newButton(640, 430,240,75, C.lightYellow, 35,pressKey("4")),
set5= newButton(640, 520,240,75, C.lightYellow, 35,pressKey("5")),
back= newButton(640, 630,180,60, C.white, 35,SCN.back),
back= newButton(640, 630,180,60, C.white, 35,BACK),
},
draw={
b1= newButton(500+65*1, 150,58,58,C.red, 30,setPen(1)),--B1
@@ -151,7 +152,7 @@ local widgetList={
demo= newSwitch(755, 640,30,function()return sceneTemp.demo end,function()sceneTemp.demo=not sceneTemp.demo end),
copy= newButton(920, 640,120,120,C.lightRed, 35,copyBoard),
paste= newButton(1060, 640,120,120,C.lightBlue, 35,pasteBoard),
back= newButton(1200, 640,120,120,C.white, 35,SCN.back),
back= newButton(1200, 640,120,120,C.white, 35,BACK),
},
play={
pause= newButton(1235,45,80,80,C.white,25,pauseGame),
@@ -167,7 +168,7 @@ local widgetList={
setting=newButton(1120,70,240,90,C.lightBlue,35,function()
SCN.push()SCN.swapTo("setting_sound")
end),
quit= newButton(640,600,240,100,C.white,35,SCN.back),
quit= newButton(640,600,240,100,C.white,35,BACK),
},
setting_game={
graphic=newButton(200,80,240,80,C.lightCyan,35,function()SCN.swapTo("setting_video")end, nil,"sound"),
@@ -185,7 +186,7 @@ local widgetList={
quickR= newSwitch(1050,340,35, SETval("quickR"), SETrev("quickR"), nil,"swap"),
swap= newSwitch(1050,440,19, SETval("swap"), SETrev("swap"), nil,"fine"),
fine= newSwitch(1050,540,20, SETval("fine"), SETrev("fine"), nil,"back"),
back= newButton(1140,650,200,80,C.white,40,SCN.back, nil,"graphic"),
back= newButton(1140,650,200,80,C.white,40,BACK, nil,"graphic"),
},
setting_video={
sound= newButton(200,80,240,80,C.lightCyan,35,function()SCN.swapTo("setting_sound")end, nil,"game"),
@@ -216,7 +217,7 @@ local widgetList={
power= newSwitch(1050,500,35,SETval("powerInfo"),function()
setting.powerInfo=not setting.powerInfo
end,nil,"back"),
back= newButton(1140,650,200,80,C.white,40,SCN.back,nil,"sound"),
back= newButton(1140,650,200,80,C.white,40,BACK,nil,"sound"),
},
setting_sound={
game= newButton(200,80,240,80,C.lightCyan,35,function()SCN.swapTo("setting_game")end, nil,"graphic"),
@@ -226,7 +227,7 @@ local widgetList={
vib= newSlider(180,440,400,5 ,28,function()VIB(2)end, SETval("vib"), SETsto("vib"), nil,"voc"),
voc= newSlider(750,440,400,10,32,function()VOC.play("nya")end, SETval("voc"), SETsto("voc"), nil,"stereo"),
stereo= newSlider(180,630,400,10,35,function()SFX.play("move",1,-1)SFX.play("lock",1,1)end, SETval("stereo"), SETsto("stereo"),function()return setting.sfx==0 end,"back"),
back= newButton(1140,650,200,80,C.white,40,SCN.back,nil,"game"),
back= newButton(1140,650,200,80,C.white,40,BACK,nil,"game"),
},
setting_control={
das= newSlider(226,200,910, 26, 30,nil,SETval("das"), SETsto("das"), nil,"arr"),
@@ -242,10 +243,10 @@ local widgetList={
_.sddas,_.sdarr=0,2
_.ihs,_.irs,_.ims=false,false,false
end,nil,"back"),
back= newButton(1140,650,200,80,C.white,40,SCN.back,nil,"das"),
back= newButton(1140,650,200,80,C.white,40,BACK,nil,"das"),
},
setting_key={
back=newButton(1140,650,200,80,C.white,45,SCN.back),
back=newButton(1140,650,200,80,C.white,45,BACK),
},
setting_skin={
prev= newButton(700,100,140,100,C.white,50,function()SKIN.prevSet()end),
@@ -284,7 +285,7 @@ local widgetList={
end
SFX.play("hold")
end),
back= newButton(1140,650,200,80,C.white,40,SCN.back),
back= newButton(1140,650,200,80,C.white,40,BACK),
},
setting_touch={
default=newButton(520,80,170,80,C.white,35,function()
@@ -310,7 +311,7 @@ local widgetList={
SCN.push()
SCN.swapTo("setting_touchSwitch")
end),
back= newButton(760,180,170,80,C.white,40,SCN.back),
back= newButton(760,180,170,80,C.white,40,BACK),
size= newSlider(450,265,460,14,40,nil,function()
return VK_org[sceneTemp.sel].r/10-1
end,
@@ -354,38 +355,38 @@ local widgetList={
SCN.swapTo("setting_trackSetting")
end,function()return not setting.VKTrack end),
alpha= newSlider(840,540,400,10,40,nil,SETval("VKAlpha"),SETsto("VKAlpha")),
back= newButton(1120,620,200,80,C.white,45,SCN.back),
back= newButton(1120,620,200,80,C.white,45,BACK),
},
setting_trackSetting={
VKDodge=newSwitch(400,200, 35,SETval("VKDodge"),SETrev("VKDodge")),
VKTchW= newSlider(140,310,1000,10,35,nil,SETval("VKTchW"),function(i)setting.VKTchW=i;setting.VKCurW=math.max(setting.VKCurW,i)end),
VKCurW= newSlider(140,370,1000,10,35,nil,SETval("VKCurW"),function(i)setting.VKCurW=i;setting.VKTchW=math.min(setting.VKTchW,i)end),
back= newButton(1080,600,240,80,C.white,45,SCN.back),
back= newButton(1080,600,240,80,C.white,45,BACK),
},
setting_lang={
chi= newButton(160,100,200,120,C.white,45,setLang(1),nil,"chi2"),
chi2= newButton(380,100,200,120,C.white,45,setLang(2),nil,"eng"),
eng= newButton(600,100,200,120,C.white,45,setLang(3),nil,"str"),
str= newButton(820,100,200,120,C.white,45,setLang(4),nil,"back"),
back= newButton(640,600,200,80,C.white,40,SCN.back,nil,"chi"),
back= newButton(640,600,200,80,C.white,40,BACK,nil,"chi"),
},
help={
staff= newButton(980,500,150,80,C.white,32,function()SCN.push()SCN.swapTo("staff")end,nil,"his"),
his= newButton(1160,500,150,80,C.white,32,function()SCN.push()SCN.swapTo("history")end,nil,"qq"),
qq= newButton(980,600,150,80,C.white,32,function()love.system.openURL("tencent://message/?uin=1046101471&Site=&Menu=yes")end,mobileHide,"back"),
back= newButton(640,600,200,80,C.white,40,SCN.back,nil,"staff"),
back= newButton(640,600,200,80,C.white,40,BACK,nil,"staff"),
},
staff={
back= newButton(1160,630,150,80,C.white,40,SCN.back),
back= newButton(1160,630,150,80,C.white,40,BACK),
},
history={
prev= newButton(1155,170,180,180,C.white,65,pressKey("up"),function()return sceneTemp[2]==1 end),
next= newButton(1155,400,180,180,C.white,65,pressKey("down"),function()return sceneTemp[2]==#sceneTemp[1]end),
back= newButton(1155,600,180,90,C.white,40,SCN.back),
back= newButton(1155,600,180,90,C.white,40,BACK),
},
stat={
path= newButton(980,620,250,80,C.white,25,function()love.system.openURL(love.filesystem.getSaveDirectory())end,mobileHide,"back"),
back= newButton(640,620,200,80,C.white,40,SCN.back,nil,"path"),
back= newButton(640,620,200,80,C.white,40,BACK,nil,"path"),
},
}
mobileHide,SETval,SETsto,SETrev=nil
@@ -393,11 +394,11 @@ pressKey,setPen,prevSkin,nextSkin=nil
nextDir,VKAdisp,VKAcode,setLang=nil
newButton,newSwitch,newSlider=nil
for _,L in next,widgetList do
for _,L in next,Widgets do
for _,W in next,L do
if W.next then
W.next,L[W.next].prev=L[W.next],W
end
end
end
return widgetList
return Widgets