local gc_push,gc_pop=GC.push,GC.pop local gc_translate,gc_scale,gc_rotate,gc_applyTransform=GC.translate,GC.scale,GC.rotate,GC.applyTransform local gc_setColor,gc_setLineWidth=GC.setColor,GC.setLineWidth local gc_draw,gc_line=GC.draw,GC.line local gc_rectangle,gc_circle=GC.rectangle,GC.circle local gc_print,gc_printf=GC.print,GC.printf local ms,kb,tc=love.mouse,love.keyboard,love.touch local max,min=math.max,math.min local floor,abs=math.floor,math.abs local mapCam={ sel=false,-- Selected mode ID xOy=love.math.newTransform(0,0,0,1),-- Transformation for map display keyCtrl=false,-- If controlling with key -- For auto zooming when enter/leave scene zoomMethod=false, zoomK=false, } local visibleModes local touchDist local grid local min_x,max_x=-1500,1350 local min_y,max_y=-1900,660 local modUsed local scene={} function scene.enter() grid=false BG.set() mapCam.zoomK=SCN.prev=='main' and 5 or 1 visibleModes={}-- 1=unlocked, 2=locked but visible for name,M in next,MODES do if RANKS[name] and M.x then visibleModes[name]=1 if M.unlock then for i=1,#M.unlock do visibleModes[M.unlock[i]]=visibleModes[M.unlock[i]] or 2 end end end end modUsed=usingMod() end local function _getK() return abs(mapCam.xOy:transformPoint(1,0)-mapCam.xOy:transformPoint(0,0)) end local function _getPos() return mapCam.xOy:inverseTransformPoint(0,0) end local function _onModeRaw(x,y) for name,M in next,MODES do if visibleModes[name] and M.x then local s=M.size if M.shape==1 then if x>M.x-s and xM.y-s and ymax_x and dx<0 or x0 then dx=0 end if y>max_y and dy<0 or y0 then dy=0 end mapCam.xOy:translate(dx/k,dy/k) end function scene.wheelMoved(_,dy) mapCam.keyCtrl=false local k=_getK() k=min(max(k+dy*.1,.3),1.6)/k mapCam.xOy:scale(k) local x,y=_getPos() mapCam.xOy:translate(x*(1-k),y*(1-k)) end function scene.mouseMove(_,_,dx,dy) if ms.isDown(1) then _moveMap(dx,dy) end mapCam.keyCtrl=false end function scene.mouseClick(x,y) local _=mapCam.sel if not _ or x<920 then x,y=x-640,y-360 x,y=mapCam.xOy:inverseTransformPoint(x,y) local SEL=_onModeRaw(x,y) if _~=SEL then if SEL then mapCam.moving=true _=MODES[SEL] mapCam.sel=SEL SFX.play('click') else mapCam.sel=false end elseif _ then scene.keyDown('return') end end mapCam.keyCtrl=false end function scene.touchDown() touchDist=false end function scene.touchMove(x,y,dx,dy) local L=tc.getTouches() if not L[2] then _moveMap(dx,dy) elseif not L[3] then x,y=SCR.xOy:inverseTransformPoint(tc.getPosition(L[1])) dx,dy=SCR.xOy:inverseTransformPoint(tc.getPosition(L[2]))-- Not delta!!! local d=(x-dx)^2+(y-dy)^2 if d>100 then d=d^.5 if touchDist then scene.wheelMoved(nil,(d-touchDist)*.02) end touchDist=d end end mapCam.keyCtrl=false end function scene.touchClick(x,y) scene.mouseClick(x,y) end function scene.keyDown(key,isRep) if isRep then return end if key=='return' or key=='kpenter' then if mapCam.sel then if visibleModes[mapCam.sel]==2 then MES.new('info',text.unlockHint) else mapCam.keyCtrl=false loadGame(mapCam.sel) end end elseif key=='f1' then SCN.go('mod') elseif key=='f2' then grid=not grid elseif key=='escape' then if mapCam.sel then mapCam.sel=false else SCN.back() end end end function scene.update() local dx,dy=0,0 local F if not SCN.swapping then if kb.isDown('up', 'w') then dy=dy+10 F=true end if kb.isDown('down', 's') then dy=dy-10 F=true end if kb.isDown('left', 'a') then dx=dx+10 F=true end if kb.isDown('right','d') then dx=dx-10 F=true end local js=Z.getJsState()[1] if js then local sx,sy=js._jsObj:getGamepadAxis('leftx'),js._jsObj:getGamepadAxis('lefty') if math.abs(sx)>.1 or math.abs(sy)>.1 then if sy<-.1 then dy=dy-12.6*sy end if sy>.1 then dy=dy-12.6*sy end if sx<-.1 then dx=dx-12.6*sx end if sx>.1 then dx=dx-12.6*sx end F=true end end end if F then mapCam.keyCtrl=true if kb.isDown('lctrl','rctrl','lalt','ralt') then scene.wheelMoved(nil,(dy-dx)*.026) else _moveMap(dx,dy) local x,y=_getPos() local SEL=_onModeRaw(x,y) if SEL and mapCam.sel~=SEL then mapCam.sel=SEL SFX.play('click') end end end local _=SCN.state.tar mapCam.zoomMethod=_=="game" and 1 or _=="mode" and 2 if mapCam.zoomMethod==1 then _=mapCam.zoomK if _<.8 then _=_*1.05 end if _<1.1 then _=_*1.05 end mapCam.zoomK=_*1.05 elseif mapCam.zoomMethod==2 then mapCam.zoomK=mapCam.zoomK^.9 end end -- noRank/B/A/S/U/X local baseRankColor={ [0]={0,0,0,.3}, {.2,.4,.6,.3}, {.6,.85,.65,.3}, {.85,.8,.3,.3}, {.85,.5,.4,.3}, {.85,.3,.8,.3}, } local function _drawModeShape(M,S,drawType) if M.shape==1 then-- Rectangle gc_rectangle(drawType,M.x-S,M.y-S,2*S,2*S) elseif M.shape==2 then-- Diamond gc_circle(drawType,M.x,M.y,S+12,4) elseif M.shape==3 then-- Octagon gc_circle(drawType,M.x,M.y,S+6,8) end end function scene.draw() -- Mod indicator if modUsed then setModBackgroundColor() gc_rectangle('fill',140-220/2,655-80/2,220,80,5,5) end local _ gc_push('transform') gc_translate(640,360) gc_rotate((mapCam.zoomK^.6-1)) gc_scale(mapCam.zoomK^.7) gc_applyTransform(mapCam.xOy); if grid then gc_setColor(1,0,.26,.26) gc_setLineWidth(1) for x=-2000,2000,200 do gc_line(x,-2200,x,1000) end for y=-2200,1000,200 do gc_line(-2000,y,2000,y) end gc_setColor(1,0,.26,.626) gc_setLineWidth(2) gc_line(0,-2200,0,1000) gc_line(-2000,0,1000,0) end local R=RANKS local sel=mapCam.sel -- Lines connecting modes gc_setLineWidth(8) gc_setColor(1,1,1,.2) for name,M in next,MODES do if R[name] and M.unlock and M.x then for _=1,#M.unlock do local m=MODES[M.unlock[_]] gc_line(M.x,M.y,m.x,m.y) end end end -- Modes setFont(80) gc_setLineWidth(4) for name,M in next,MODES do local unlocked=visibleModes[name] if unlocked then local rank=R[name] local S=M.size -- Draw shapes on map if unlocked==1 then gc_setColor(baseRankColor[rank]) _drawModeShape(M,S,'fill') end gc_setColor(1,1,sel==name and 0 or 1,unlocked==1 and .8 or .3) _drawModeShape(M,S,'line') -- Icon local icon=M.icon if icon then gc_setColor(unlocked==1 and COLOR.lH or COLOR.dH) local length=icon:getWidth()*.5 gc_draw(icon,M.x,M.y,nil,S/length,nil,length,length) end -- Rank if unlocked==1 then name=RANK_CHARS[rank] if name then gc_setColor(COLOR.dX) GC.mStr(name,M.x+M.size*.7,M.y-50-M.size*.7) gc_setColor(RANK_COLORS[rank]) GC.mStr(name,M.x+M.size*.7+4,M.y-50-M.size*.7-4) end end end end gc_pop() -- Score board if sel then local M=MODES[sel] gc_setColor(COLOR.lX) gc_rectangle('fill',920,0,360,720,5)-- Info board gc_setColor(COLOR.Z) local modeText=text.modes[sel] if modeText then setFont(40)GC.mStr(modeText[1],1100,5) setFont(30)GC.mStr(modeText[2],1100,50) setFont(25)gc_printf(modeText[3],920,110,360,'center') end if M.slowMark then gc_draw(IMG.ctrlSpeedLimit,1230,50,nil,.4) end if M.score then mText(TEXTOBJ.highScore,1100,240) gc_setColor(COLOR.X) gc_rectangle('fill',940,290,320,280,5)-- Highscore board local L=M.records gc_setColor(1,1,1) if visibleModes[sel]==2 then mText(TEXTOBJ.modeLocked,1100,370) elseif L[1] then for i=1,#L do local t=M.scoreDisp(L[i]) local f=floor((30-#t*.5)/5)*5 setFont(f) gc_print(t,955,275+25*i+17-f*.7) _=L[i].date if _ then setFont(10) gc_print(_,1155,285+25*i) end end else mText(TEXTOBJ.noScore,1100,370) end end end if mapCam.keyCtrl then gc_setColor(1,1,1) gc_setLineWidth(4) gc_translate(640,360) gc_line(-20,0,20,0) gc_line(0,-20,0,20) gc_translate(-640,-360) end end scene.widgetList={ WIDGET.newKey{name='mod', x=140,y=655,w=220,h=80,font=35,code=goScene'mod'}, WIDGET.newButton{name='start',x=1040,y=655,w=180,h=80,font=40,code=pressKey'return',hideF=function() return not mapCam.sel end}, WIDGET.newButton{name='back', x=1200,y=655,w=120,h=80,sound='back',font=60,fText=CHAR.icon.back,code=backScene}, } return scene