local ms,kb,tc=love.mouse,love.keyboard,love.touch local gc,sys=love.graphics,love.system local Timer=love.timer.getTime 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 local touching=nil--第一触摸ID local touchDist=nil joysticks={} local devMode players={alive={},human=0} local Tmr=require("timer") local Pnt=require("paint") local infoCanvas=gc.newCanvas(108,27) local function updatePowerInfo() local state,pow=sys.getPowerInfo() gc.setCanvas(infoCanvas)gc.push("transform")gc.origin() gc.clear(0,0,0,.25) if state~="unknown"then gc.setLineWidth(4) local charging=state=="charging" if state=="nobattery"then gc.setColor(1,1,1) gc.setLineWidth(2) gc.line(74,5,100,22) elseif pow then if charging then gc.setColor(0,1,0) elseif pow>50 then gc.setColor(1,1,1) elseif pow>26 then gc.setColor(1,1,0) elseif pow<26 then gc.setColor(1,0,0) else gc.setColor(.5,0,1) end gc.rectangle("fill",76,6,pow*.22,14) if pow<100 then setFont(14) gc.setColor(0,0,0) gc.print(pow,77,2) gc.print(pow,77,4) gc.print(pow,79,2) gc.print(pow,79,4) gc.setColor(1,1,1) gc.print(pow,78,3) end end gc.draw(batteryImage,73,3) end setFont(25) gc.print(os.date("%H:%M",os.time()),3,-5) gc.pop()gc.setCanvas() end local function onVirtualkey(x,y) local dist,nearest=1e10 for K=1,#virtualkey do local b=virtualkey[K] if b.ava then local d1=(x-b.x)^2+(y-b.y)^2 if d10 then if floatWheel<0 then floatWheel=0 end floatWheel=floatWheel+y^1.2 elseif y<0 then if floatWheel>0 then floatWheel=0 end floatWheel=floatWheel-(-y)^1.2 end while floatWheel>=1 do love.keypressed("up") floatWheel=floatWheel-1 end while floatWheel<=-1 do love.keypressed("down") floatWheel=floatWheel+1 end end local mouseClick,touchClick={},{} local mouseDown,mouseMove,mouseUp,wheelMoved={},{},{},{} local touchDown,touchUp,touchMove={},{},{} local keyDown,keyUp={},{} local gamepadDown,gamepadUp={},{} function keyDown.load(k) if k=="s"then marking=nil sceneTemp.skip=true end end function touchDown.load() if #tc.getTouches()>2 then sceneTemp.skip=true end end function mouseDown.intro(x,y,k) if k==2 then VOC.play("bye") SCN.back() else SCN.push() SCN.swapTo("main") end end function touchDown.intro(id,x,y) SCN.push() SCN.swapTo("main") end function keyDown.intro(key) if key=="escape"then VOC.play("bye") SCN.back() else SCN.push() SCN.swapTo("main") end end 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 for _=1,#MM do if R[_]then local M=MM[_] local s=M.size if M.shape==1 then if x>M.x-s and xM.y-s and y1.5 then k=1.5 elseif k<.3 then k=.3 end t=k/t if cam.sel then cam.x=(cam.x-180)*t+180;cam.y=cam.y*t else cam.x=cam.x*t;cam.y=cam.y*t end cam.k=k cam.keyCtrl=false end function mouseMove.mode(x,y,dx,dy) if ms.isDown(1)then mapCam.x,mapCam.y=mapCam.x-dx,mapCam.y-dy end mapCam.keyCtrl=false end function mouseClick.mode(x,y,k) local cam=mapCam local _=cam.sel if not cam.sel or x<920 then local __=onMode(x,y) if _~=__ then if __ then SFX.play("click") cam.moving=true _=modes[__] cam.x=_.x*cam.k+180 cam.y=_.y*cam.k cam.sel=__ else cam.sel=nil cam.x=cam.x-180 end end end cam.keyCtrl=false end function touchMove.mode(id,x,y,dx,dy) local L=tc.getTouches() if not L[2]then mapCam.x,mapCam.y=mapCam.x-dx,mapCam.y-dy elseif not L[3]then x,y=xOy:inverseTransformPoint(tc.getPosition(L[1])) dx,dy=xOy:inverseTransformPoint(tc.getPosition(L[2]))--dx,dy not Δ! local d=(x-dx)^2+(y-dy)^2 if d>100 then d=d^.5 if touchDist then wheelMoved.mode(nil,(d-touchDist)*.02) end touchDist=d end end mapCam.keyCtrl=false end function touchClick.mode(x,y,id) mouseClick.mode(x,y,1) end function keyDown.mode(key) if key=="return"then if mapCam.sel then mapCam.keyCtrl=false SCN.push()loadGame(mapCam.sel) end elseif key=="escape"then if mapCam.sel then mapCam.sel=nil else SCN.back() end elseif mapCam.sel==71 or mapCam.sel==72 then if key=="q"then SCN.push()SCN.swapTo("draw") elseif key=="e"then SCN.push()SCN.swapTo("custom") end end end function wheelMoved.music(x,y) if y>0 then keyDown.music("up") elseif y<0 then keyDown.music("down") end end function keyDown.music(key) if key=="down"then sceneTemp=sceneTemp%#musicID+1 elseif key=="up"then sceneTemp=(sceneTemp-2)%#musicID+1 elseif key=="return"or key=="space"then if BGM.nowPlay~=musicID[sceneTemp]then SFX.play("click") BGM.play(musicID[sceneTemp]) else BGM.stop() end elseif key=="escape"then SCN.back() end end function keyDown.custom(key) local sel=sceneTemp if key=="left"then customSel[sel]=(customSel[sel]-2)%#customRange[customID[sel]]+1 if sel==12 then BG.set(customRange.bg[customSel[12]]) elseif sel==13 then BGM.play(customRange.bgm[customSel[13]]) end elseif key=="right"then customSel[sel]=customSel[sel]%#customRange[customID[sel]]+1 if sel==12 then BG.set(customRange.bg[customSel[sel]]) elseif sel==13 then BGM.play(customRange.bgm[customSel[sel]]) end elseif key=="down"then sceneTemp=sel%#customID+1 elseif key=="up"then sceneTemp=(sel-2)%#customID+1 elseif key=="1"then Widget.custom.set1.code() elseif key=="2"then Widget.custom.set2.code() elseif key=="3"then Widget.custom.set3.code() elseif key=="4"then Widget.custom.set4.code() elseif key=="5"then Widget.custom.set5.code() elseif key=="escape"then SCN.back() end end function mouseDown.draw(x,y,k) mouseMove.draw(x,y) end function mouseMove.draw(x,y,dx,dy) local sx,sy=int((x-200)/30)+1,20-int((y-60)/30) if sx<1 or sx>10 then sx=nil end if sy<1 or sy>20 then sy=nil end sceneTemp.x,sceneTemp.y=sx,sy if sx and sy and ms.isDown(1,2,3)then preField[sy][sx]=ms.isDown(1)and sceneTemp.pen or ms.isDown(2)and -1 or 0 end end function wheelMoved.draw(x,y) local pen=sceneTemp.pen if y<0 then pen=pen+1 if pen==8 then pen=9 elseif pen==14 then pen=0 end else pen=pen-1 if pen==8 then pen=7 elseif pen==-1 then pen=13 end end sceneTemp.pen=pen end function touchDown.draw(id,x,y) mouseMove.draw(x,y) end function touchMove.draw(id,x,y,dx,dy) local sx,sy=int((x-200)/30)+1,20-int((y-60)/30) if sx<1 or sx>10 then sx=nil end if sy<1 or sy>20 then sy=nil end sceneTemp.x,sceneTemp.y=sx,sy if sx and sy then preField[sy][sx]=sceneTemp.pen end end local penKey={ q=1,w=2,e=3,r=4,t=5,y=6,u=7,i=8,o=9,p=10,["["]=11, a=12,s=13,d=14,f=15,g=16,h=17, z=0,x=-1, } function keyDown.draw(key) local sx,sy,pen=sceneTemp.x,sceneTemp.y,sceneTemp.pen if key=="up"or key=="down"or key=="left"or key=="right"then if not sx then sx=1 end if not sy then sy=1 end if key=="up"and sy<20 then sy=sy+1 elseif key=="down"and sy>1 then sy=sy-1 elseif key=="left"and sx>1 then sx=sx-1 elseif key=="right"and sx<10 then sx=sx+1 end if kb.isDown("space")then preField[sy][sx]=pen end elseif key=="delete"then if sceneTemp.sure>20 then for y=1,20 do for x=1,10 do preField[y][x]=0 end end sceneTemp.sure=0 else sceneTemp.sure=50 end elseif key=="space"then if sx and sy then preField[sy][sx]=pen end elseif key=="escape"then SCN.back() elseif key=="c"and kb.isDown("lctrl","rctrl")then copyBoard() elseif key=="v"and kb.isDown("lctrl","rctrl")then pasteBoard() else pen=penKey[key]or pen end sceneTemp.x,sceneTemp.y,sceneTemp.pen=sx,sy,pen end function mouseDown.setting_sound(x,y,k) if x>780 and x<980 and y>470 and sceneTemp.jump==0 then sceneTemp.jump=10 local t=Timer()-sceneTemp.last if t>1 then 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,#M.unlock do local m=M.unlock[i] if not modeRanks[m]then modeRanks[m]=modes[m].score and 0 or 6 end end end FILE.saveUnlock() TEXT.show("DEVMODE:UNLOCKALL",640,360,50,"stretch",.6) end end end end function touchDown.setting_sound(id,x,y) mouseDown.setting_sound(x,y) end function keyDown.setting_key(key) local s=sceneTemp if key=="escape"then if s.kS then s.kS=false SFX.play("finesseError",.5) else SCN.back() end elseif s.kS then for l=1,8 do for y=1,20 do if keyMap[l][y]==key then keyMap[l][y]="" goto L end end end ::L:: keyMap[s.board][s.kb]=key SFX.play("reach",.5) s.kS=false elseif key=="return"then s.kS=true SFX.play("lock",.5) elseif key=="up"then if s.kb>1 then s.kb=s.kb-1 SFX.play("move",.5) end elseif key=="down"then if s.kb<20 then s.kb=s.kb+1 SFX.play("move",.5) end elseif key=="left"then if s.board>1 then s.board=s.board-1 SFX.play("rotate",.5) end elseif key=="right"then if s.board<8 then s.board=s.board+1 SFX.play("rotate",.5) end end end function gamepadDown.setting_key(key) local s=sceneTemp if key=="back"then if s.jS then s.jS=false SFX.play("finesseError",.5) else SCN.back() end elseif s.jS then for l=9,16 do for y=1,20 do if keyMap[l][y]==key then keyMap[l][y]="" goto L end end end ::L:: keyMap[8+s.board][s.js]=key SFX.play("reach",.5) s.jS=false elseif key=="start"then s.jS=true SFX.play("lock",.5) elseif key=="dpup"then if s.js>1 then s.js=s.js-1 SFX.play("move",.5) end elseif key=="dpdown"then if s.js<20 then s.js=s.js+1 SFX.play("move",.5) end elseif key=="dpleft"then if s.board>1 then s.board=s.board-1 SFX.play("rotate",.5) end elseif key=="dpright"then if s.board<8 then s.board=s.board+1 SFX.play("rotate",.5) end end end function mouseDown.setting_touch(x,y,k) if k==2 then SCN.back()end sceneTemp.sel=onVK_org(x,y)or sceneTemp.sel end function mouseMove.setting_touch(x,y,dx,dy) if sceneTemp.sel and ms.isDown(1)and not widget_sel then local B=VK_org[sceneTemp.sel] B.x,B.y=B.x+dx,B.y+dy end end function mouseUp.setting_touch(x,y,k) if sceneTemp.sel then local B=VK_org[sceneTemp.sel] local k=snapLevelValue[sceneTemp.snap] B.x,B.y=int(B.x/k+.5)*k,int(B.y/k+.5)*k end end function touchDown.setting_touch(id,x,y) sceneTemp.sel=onVK_org(x,y)or sceneTemp.sel end function touchUp.setting_touch(id,x,y) if sceneTemp.sel then local B=VK_org[sceneTemp.sel] local k=snapLevelValue[sceneTemp.snap] B.x,B.y=int(B.x/k+.5)*k,int(B.y/k+.5)*k end end function touchMove.setting_touch(id,x,y,dx,dy) if sceneTemp.sel and not widget_sel then local B=VK_org[sceneTemp.sel] B.x,B.y=B.x+dx,B.y+dy end end function keyDown.pause(key) if key=="escape"then SCN.back() elseif key=="space"then resumeGame() elseif key=="s"then SCN.push() SCN.swapTo("setting_sound") elseif key=="r"then TASK.clear("play") mergeStat(stat,players[1].stat) resetGameData() SCN.swapTo("play","none") end end function touchDown.play(id,x,y) if setting.VKSwitch then local t=onVirtualkey(x,y) if t then players[1]:pressKey(t) if setting.VKSFX>0 then SFX.play("virtualKey",setting.VKSFX*.25) end virtualkey[t].isDown=true virtualkey[t].pressTime=10 if setting.VKTrack then local B=virtualkey[t] if setting.VKDodge then--按钮软碰撞(做不来hhh随便做一个,效果还行!) for i=1,#virtualkey do local b=virtualkey[i] local d=B.r+b.r-((B.x-b.x)^2+(B.y-b.y)^2)^.5--碰撞深度(负数=间隔距离) if d>0 then b.x=b.x+(b.x-B.x)*d*b.r*.00005 b.y=b.y+(b.y-B.y)*d*b.r*.00005 end end end local O=VK_org[t] local _FW,_CW=setting.VKTchW*.1,1-setting.VKCurW*.1 local _OW=1-_FW-_CW --按钮自动跟随:手指位置,当前位置,原始位置,权重取决于设置 B.x,B.y=x*_FW+B.x*_CW+O.x*_OW,y*_FW+B.y*_CW+O.y*_OW end VIB(setting.VKVIB) end end end function touchUp.play(id,x,y) if setting.VKSwitch then local t=onVirtualkey(x,y) if t then players[1]:releaseKey(t) end end end function touchMove.play(id,x,y,dx,dy) if setting.VKSwitch then local l=tc.getTouches() for n=1,#virtualkey do local B=virtualkey[n] for i=1,#l do local x,y=xOy:inverseTransformPoint(tc.getPosition(l[i])) if(x-B.x)^2+(y-B.y)^2<=B.r^2 then goto next end end players[1]:releaseKey(n) ::next:: end end end function keyDown.play(key) if key=="escape"then pauseGame() return end local m=keyMap for p=1,players.human do for k=1,20 do if key==m[2*p-1][k]or key==m[2*p][k]then players[p]:pressKey(k) if p==1 then virtualkey[k].isDown=true virtualkey[k].pressTime=10 end return end end end end function keyUp.play(key) local m=keyMap for p=1,players.human do for k=1,20 do if key==m[2*p-1][k]or key==m[2*p][k]then players[p]:releaseKey(k) if p==1 then virtualkey[k].isDown=false end return end end end end function gamepadDown.play(key) if key=="back"then SCN.back()return end local m=keyMap for p=1,players.human do for k=1,20 do if key==m[2*p+7][k]or key==m[2*p+8][k]then players[p]:pressKey(k) if p==1 then virtualkey[k].isDown=true virtualkey[k].pressTime=10 end return end end end end function gamepadUp.play(key) local m=keyMap for p=1,players.human do for k=1,20 do if key==m[2*p+7][k]or key==m[2*p+8][k]then players[p]:releaseKey(k) if p==1 then virtualkey[k].isDown=false end return end end end end function touchDown.help(id,x,y) local pw=sceneTemp.pw local t=pw%4 if t==0 and x<640 and y<360 or t==1 and x>640 and y<360 or t==2 and x<640 and y>360 or t==3 and x>640 and y>360 then pw=pw+1 if pw==8 then marking=nil SFX.play("reach") end else pw=x<640 and y<360==1 and 1 or 0 end sceneTemp.pw=pw end function wheelMoved.history(x,y) wheelScroll(y) end function keyDown.history(key) if key=="up"then sceneTemp[2]=max(sceneTemp[2]-3,1) elseif key=="down"then sceneTemp[2]=min(sceneTemp[2]+3,#sceneTemp[1]-22) elseif key=="escape"then SCN.back() end end ------------------------------------------------------------- local function widgetPress(W,x,y) if W.type=="button"then W.code() W:FX() SFX.play("button") VOC.play("nya") elseif W.type=="switch"then W.code() SFX.play("move",.6) elseif W.type=="slider"then if not x then return end local p,P=W.disp(),xW.x+W.w and W.unit or int((x-W.x)*W.unit/W.w+.5) if p==P then return end W.code(P) if W.change then W.change()end end if W.hide and W.hide()then widget_sel=nil end end local function widgetDrag(W,x,y,dx,dy) if W.type=="slider"then local p,P=W.disp(),xW.x+W.w and W.unit or int((x-W.x)*W.unit/W.w+.5) if p==P then return end W.code(P) if W.change then W.change()end elseif not W:isAbove(x,y)then widget_sel=nil end end local function widgetControl_key(i) if i=="tab"then if widget_sel then widget_sel=kb.isDown("lshift")and widget_sel.prev or widget_sel.next or widget_sel else widget_sel=select(2,next(Widget[SCN.cur])) end elseif i=="space"or i=="return"then if widget_sel then widgetPress(widget_sel) end elseif i=="left"or i=="right"then if widget_sel then local W=widget_sel if W.type=="slider"then local p=W.disp() local P=i=="left"and(p>0 and p-1)or p0 and p-1)or p=.5625 then scr.k=w/1280 scr.x,scr.y=0,(h-w*9/16)*.5 else scr.k=h/720 scr.x,scr.y=(w-h*16/9)*.5,0 end xOy=xOy:setTransformation(w*.5,h*.5,nil,scr.k,nil,640,360) BG.resize(w,h) end function love.focus(f) if SCN.cur=="play"and not f and setting.autoPause then pauseGame()end end local scs={1,2,1,2,1,2,1,2,1,2,1.5,1.5,.5,2.5} local devColor={ color.white, color.lightMagenta, color.lightGreen, color.lightBlue, } local FPS=love.timer.getFPS love.draw,love.update=nil function love.run() local T=love.timer local STEP,GETΔ,WAIT=T.step,T.getDelta,T.sleep local lastFrame=T.getTime() local lastFreshPow=lastFrame local FCT=0--framedraw counter local mini=love.window.isMinimized local PUMP,POLL=love.event.pump,love.event.poll love.resize(gc.getWidth(),gc.getHeight()) SCN.init("load")--Scene Launch marking=true return function() --EVENT PUMP() for N,a,b,c,d,e in POLL()do if love[N]then love[N](a,b,c,d,e) elseif N=="quit"then destroyPlayers() return 1 end end --UPDATE STEP()local dt=GETΔ() TASK.update() VOC.update() BG.update(dt) sysFX.update(dt) TEXT.update() local _=Tmr[SCN.cur]if _ then _(dt)end if SCN.swapping then SCN.swapUpdate()end for _,W in next,Widget[SCN.cur]do W:update() end--更新控件 --DRAW if not mini()then FCT=FCT+setting.frameMul if FCT>=100 then FCT=FCT-100 gc.discard()--SPEED UPUPUP! BG.draw() gc.push("transform") gc.replaceTransform(xOy) if Pnt[SCN.cur]then Pnt[SCN.cur]()end for k,W in next,Widget[SCN.cur]do if not(W.hide and W.hide())then W:draw() end end--Draw widgets if mouseShow then local r=Timer()*.5 local R=int(r)%7+1 _=SKIN.libColor[setting.skin[R]] gc.setColor(_[1],_[2],_[3],min(1-abs(1-r%1*2),.3)) gc.draw(miniBlock[R],mx,my,Timer()%3.1416*4,20,20,scs[2*R]-.5,#blocks[R][0]-scs[2*R-1]+.5) gc.setColor(1,1,1,.5)gc.circle("fill",mx,my,5) gc.setColor(1,1,1)gc.circle("fill",mx,my,3) end--Awesome mouse! sysFX.draw() TEXT.draw() gc.pop() gc.setColor(1,1,1) gc.draw(infoCanvas,0,0,0,scr.k) --Power Info if SCN.swapping then _=SCN.swap _.draw(_.time) end--Scene swapping animation setFont(15) gc.setColor(1,1,1) _=scr.h-20 gc.print(FPS(),5,_) if devMode then gc.setColor(devColor[devMode]) gc.print("Cache used:"..gcinfo(),5,_-20) gc.print("Free Row:"..freeRow.getCount(),5,_-40) gc.print("Mouse:"..mx.." "..my,5,_-60) gc.print("Voices:"..VOC.getCount(),5,_-80) gc.print("Tasks:"..TASK.getCount(),5,_-100) if devMode==3 then love.timer.sleep(.26) elseif devMode==4 then love.timer.sleep(.626) end end--DEV info gc.present() end end --FRAME TIME CTRL if Timer()-lastFrame<.058 then WAIT(.01)end while Timer()-lastFrame<.0159 do WAIT(.001)end --FRESH POWER lastFrame=Timer() if Timer()-lastFreshPow>1 then updatePowerInfo() lastFreshPow=Timer() end end end function love.errorhandler(msg) local PUMP,POLL=love.event.pump,love.event.poll love.mouse.setVisible(true) love.audio.stop() local err={"Error:"..msg} local trace=debug.traceback("",2) local c=2 for l in string.gmatch(trace,"(.-)\n")do if c>2 then if not string.find(l,"boot")then err[c]=string.gsub(l,"^\t*","") c=c+1 end else err[2]="Traceback" c=3 end end print(table.concat(err,"\n"),1,c-2) gc.reset() local CAP local function _(_)CAP=gc.newImage(_)end gc.captureScreenshot(_) gc.present() setting.sfx=setting.voc--only for error "voice" played with voice volume,not saved if SFX.list.error then SFX.play("error",.8)end local BGcolor=rnd()>.026 and{.3,.5,.9},{.62,.3,.926} local needDraw=true return function() PUMP() for E,a,b,c,d,e in POLL()do if E=="quit"or a=="escape"then destroyPlayers() return 1 elseif E=="resize"then love.resize(a,b) needDraw=true elseif E=="focus"then needDraw=true end end if needDraw then gc.discard() gc.clear(BGcolor) gc.setColor(1,1,1) gc.push("transform") gc.replaceTransform(xOy) gc.draw(CAP,100,365,nil,512/CAP:getWidth(),288/CAP:getHeight()) setFont(120)gc.print(":(",100,40) setFont(38)gc.printf(text.errorMsg,100,200,1280-100) setFont(20) gc.print(system.."-"..gameVersion,100,660) gc.print("scene:"..SCN.cur,400,660) gc.printf(err[1],626,360,1260-626) gc.print("TRACEBACK",626,426) for i=4,#err-2 do gc.print(err[i],626,370+20*i) end gc.pop() gc.present() needDraw=false end love.timer.sleep(.2) end end