local gc=love.graphics local kb=love.keyboard local ins,rem=table.insert,table.remove local C=COLOR local inputBox=WIDGET.newInputBox{name='input',x=40,y=650,w=1200,h=50} local outputBox=WIDGET.newTextBox{name='output',x=40,y=30,w=1200,h=610,font=25,lineH=25,fix=true} local function log(str)outputBox:push(str)end log{C.lP,"Techmino Console"} log{C.lC,"©2021 26F Studio some rights reserved"} log{C.dR,"DO NOT RUN ANY CODE YOU DON'T UNDERSTAND"} local history,hisPtr={"?"} local sudomode=false local the_secret=(14^2*10)..(2*11) local commands={}do --[[ format of elements in table 'commands': key: the command name value: a table containing the following two elements: code: code to run when call description: a string that shows when user types 'help'. details: an array of strings containing documents, shows when user types 'help [command]'. ]] local cmdList={}--List of all non-alias commands --Basic commands.help={ code=function(arg) if #arg>0 then --help [command] if commands[arg]then if commands[arg].description then log{C.H,("%s"):format(commands[arg].description)} end if commands[arg].details then for _,v in ipairs(commands[arg].details)do log(v)end else log{C.Y,("No details for command '%s'"):format(arg)} end else log{C.Y,("No command called '%s'"):format(arg)} end else --help for i=1,#cmdList do local cmd=cmdList[i] local body=commands[cmd] log( body.description and {C.Z,cmd,C.H," "..body.description} or log{C.Z,cmd} ) end end end, description="Display help messages", details={ "Display help messages.", "", "Aliases: help ?", "", "Usage:", "help", "help [command_name]", }, }commands["?"]="help" commands["#"]={ description="Run arbitrary Lua code", details={ "Run arbitrary Lua code.", "", "Usage: #[lua_source_code]", "", "print() can be used to print text into this window.", }, } commands.exit={ code=backScene, description="Return to the last menu", details={ "Return to the last menu.", "", "Aliases: exit quit", "", "Usage: exit", }, }commands.quit="exit" commands.echo={ code=function(str)if str~=""then log(str)end end, description="Print a message", details={ "Print a message to this window.", "", "Usage: echo [message]", }, } commands.cls={ code=function()outputBox:clear()end, description="Clear the window", details={ "Clear the log output.", "", "Usage: cls", }, } --File do--tree local function tree(path,name,depth) local info=love.filesystem.getInfo(path..name) if info.type=='file'then log(("\t\t"):rep(depth)..name) elseif info.type=='directory'then log(("\t\t"):rep(depth)..name..">") local L=love.filesystem.getDirectoryItems(path..name) for _,subName in next,L do tree(path..name.."/",subName,depth+1) end else log("Unkown item type: %s (%s)"):format(name,info.type) end end commands.tree={ code=function() local L=love.filesystem.getDirectoryItems"" for _,name in next,L do if love.filesystem.getRealDirectory(name)==SAVEDIR then tree("",name,0) end end end, description="List all files & directories", details={ "List all files & directories in saving directory", "", "Usage: tree", }, } end do--del local function delFile(name) if love.filesystem.remove(name)then log{C.Y,("Deleted: '%s'"):format(name)} else log{C.R,("Failed to delete: '%s'"):format(name)} end end local function delDir(name) if #love.filesystem.getDirectoryItems(name)==0 then if love.filesystem.remove(name)then log{C.Y,("Directory deleted: '%s'"):format(name)} else log{C.R,("Failed to delete directory '%s'"):format(name)} end else log{C.R,"Directory '"..name.."' is not empty"} end end local function recursiveDelDir(dir) local containing=love.filesystem.getDirectoryItems(dir) if #containing==0 then if love.filesystem.remove(dir)then log{C.Y,("Succesfully deleted directory '%s'"):format(dir)} else log{C.R,("Failed to delete directory '%s'"):format(dir)} end else for _,name in next,containing do local path=dir.."/"..name local info=love.filesystem.getInfo(path) if info then if info.type=='file'then delFile(path) elseif info.type=='directory'then recursiveDelDir(path) else log("Unkown item type: %s (%s)"):format(name,info.type) end end end delDir(dir) end end commands.del={ code=function(name) local recursive=name:sub(1,3)=="-s " if recursive then name=name:sub(4) end if name~=""then local info=love.filesystem.getInfo(name) if info then if info.type=='file'then if not recursive then delFile(name) else log{C.R,("'%s' is not a directory."):format(name)} end elseif info.type=='directory'then (recursive and recursiveDelDir or delDir)(name) else log("Unkown item type: %s (%s)"):format(name,info.type) end else log{C.R,("No file called '%s'"):format(name)} end else log{C.A,"Usage: del [filename|dirname]"} log{C.A,"Usage: del -s [dirname]"} end end, description="Delete a file or directory", details={ "Attempt to delete a file or directory (in saving directory)", "", "Aliases: del rm", "", "Usage: del [filename|dirname]", "Usage: del -s [dirname]", } } commands.rm=commands.del end commands.mv={ code=function(arg) --Check arguments arg=STRING.split(arg," ") if #arg>2 then log{C.lY,"Warning: file name with space is not allowed"} return elseif #arg<2 then log{C.A,"Usage: ren [oldfilename] [newfilename]"} return end --Check file exist local info info=love.filesystem.getInfo(arg[1]) if not(info and info.type=='file')then log{C.R,("'%s' is not a file!"):format(arg[1])} return end info=love.filesystem.getInfo(arg[2]) if info then log{C.R,("'%s' already exists!"):format(arg[2])} return end --Read file local data,err1=love.filesystem.read('data',arg[1]) if not data then log{C.R,("Failed to read file '%s': "):format(arg[1],err1 or"Unknown error")} return end --Write file local res,err2=love.filesystem.write(arg[2],data) if not res then log{C.R,("Failed to write file: "):format(err2 or"Unknown error")} return end --Delete file if not love.filesystem.remove(arg[1])then log{C.R,("Failed to delete old file ''"):format(arg[1])} return end log{C.Y,("Succesfully renamed file '%s' to '%s'"):format(arg[1],arg[2])} end, description="Rename or move a file (in saving directory)", details={ "Rename or move a file (in saving directory)", {C.lY,"Warning: file name with space is not allowed"}, "", "Aliases: mv ren", "", "Usage: mv [oldfilename] [newfilename]", }, }commands.ren="mv" commands.print={ code=function(name) if name~=""then local info=love.filesystem.getInfo(name) if info then if info.type=='file'then log{COLOR.lC,"/* "..name.." */"} for l in love.filesystem.lines(name)do log(l) end log{COLOR.lC,"/* END */"} else log{C.R,("Unprintable item: %s (%s)"):format(name,info.type)} end else log{C.R,("No file called '%s'"):format(name)} end else log{C.A,"Usage: print [filename]"} end end, description="Print file content", details={ "Print a file to this window.", "", "Usage: print [filename]", }, } --System commands.crash={ code=function()error("ERROR")end, description="Manually crash the game", } commands.mes={ code=function(arg) if arg=='check'or arg=='info'or arg=='broadcast'or arg=='warn'or arg=='error' then MES.new(arg,"Test message",6) else log{C.A,"Show a message on the up-left corner"} log"" log{C.A,"Usage: mes "} end end, description="Show a message", details={ "Show a message on the up-left corner", "", "Usage: mes ", }, } commands.log={ code=function() local l=LOG.logs for i=1,#l do log(l[i]) end end, description="Show the logs", details={ "Show the logs", "", "Usage: log", }, } commands.openurl={ code=function(url) if url~=""then local res,err=pcall(love.system.openURL,url) if not res then log{C.R,"[ERR] ",C.Z,err} end else log{C.A,"Usage: openurl [url]"} end end, description="Open a URL", details={ "Attempt to open a URL with your device.", "", "Usage: openurl [url]", }, } commands.scrinfo={ code=function() for _,v in next,SCR.info()do log(v) end end, description="Display window info.", details={ "Display information about the game window.", "", "Usage: scrinfo", }, } commands.wireframe={ code=function(bool) if bool=="on"or bool=="off"then gc.setWireframe(bool=="on") log("Wireframe: "..(gc.isWireframe()and"on"or"off")) else log{C.A,"Usage: wireframe "} end end, description="Turn on/off wireframe mode", details={ "Enable or disable wireframe drawing mode.", "", "Usage: wireframe ", }, } commands.gammacorrect={ code=function(bool) if bool=="on"or bool=="off"then love._setGammaCorrect(bool=="on") log("GammaCorrect: "..(gc.isGammaCorrect()and"on"or"off")) else log{C.A,"Usage: gammacorrect "} end end, description="Turn on/off gamma correction", details={ "Enable or disable gamma correction.", "", "Usage: gammacorrect ", }, } commands.fn={ code=function(n) if tonumber(n)then n=math.floor(tonumber(n)) if n>=1 and n<=12 then love.keypressed("f"..n) end else log{C.A,"Usage: fn [1~12]"} end end, description="Simulates a Function key press", details={ "Acts as if you have pressed a function key (i.e. F1-F12) on a keyboard.", "Useful if you are on a mobile device without access to these keys.", "", "Usage: fn <1-12>", }, } commands.playbgm={ code=function(bgm) if bgm~=""then if bgm~=BGM.nowPlay then if BGM.play(bgm)then log("Now playing: "..bgm) else log("No BGM called "..bgm) end else log("Already playing: "..bgm) end else log{C.A,"Usage: playbgm [bgmName]"} end end, description="Play a BGM", details={ "Play a BGM.", "", "Usage: playbgm [bgmName]" }, } commands.stopbgm={ code=function() BGM.stop() end, description="Stop the BGM", details={ "Stop the BGM.", "", "Usage: stopbgm" }, } commands.setbg={ code=function(name) if name~=""then if name~=BG.cur then if BG.set(name)then log(("Background set to '%s'"):format(name)) else log(("No background called '%s'"):format(name)) end else log(("Background already set to '%s'"):format(name)) end else log{C.A,"Usage: setbg [bgName]"} end end, description="Set background", details={ "Set a background.", "", "Usage: setbg [bgName]", }, } commands.theme={ code=function(name) if name~=""then if THEME.set(name)then log("Theme set to: "..name) else log("No theme called "..name) end else log{C.A,"Usage: theme [themeName]"} end end, description="Load theme", details={ "Load a theme.", "", "Usage: theme ", }, } commands.test={ code=function() SCN.go('test','none') end, description="Enter test scene", details={ "Go to an empty test scene", "", "Usage: test", }, } do--app local APPs={ { code="calc", scene='app_calc', description="A simple calculator" }, { code="15p", scene='app_15p', description="15 Puzzle, a.k.a. sliding puzzle" }, { code="grid", scene='app_schulteG', description="Schulte Grid" }, { code="pong", scene='app_pong', description="Pong (2P)" }, { code="atoz", scene='app_AtoZ', description="A to Z, a.k.a. typing" }, { code="uttt", scene='app_UTTT', description="Ultimate Tic-Tac-Toe (2P)" }, { code="cube", scene='app_cubefield', description="Cubefield, original by Max Abernethy" }, { code="2048", scene='app_2048', description="2048 with some new features" }, { code="ten", scene='app_ten', description="Just Get Ten" }, { code="tap", scene='app_tap', description="Clicking/Tapping speed test" }, { code="dtw", scene='app_dtw', description="Don't Touch White, a.k.a. Piano Tiles" }, { code="can", scene='app_cannon', description="A simple cannon shooting game" }, { code="drp", scene='app_dropper', description="Dropper" }, { code="rfl", scene='app_reflect', description="Reflect (2P)" }, { code="poly", scene='app_polyforge', description="Polyforge, original by ImpactBlue Studios" }, { code="link", scene='app_link', description="Connect tiles, a.k.a. Shisen-Sho" }, { code="arm", scene='app_arithmetic', description="Arithmetic" }, } commands.app={ code=function(name) if name=="-list"then for i=1,#APPs do log(APPs[i].code..": "..APPs[i].description) end elseif name~=""then for i=1,#APPs do if APPs[i].code==name then SCN.go(APPs[i].scene) return end end log{C.A,"No applet with this name. Type app -list to view all applets"} else log{C.A,"Usage:"} log{C.A,"app -list"} log{C.A,"app [appName]"} end end, description="Enter a applet scene", details={ "Go to an applet scene", "", "Usage:", "app -list", "app [appName]", }, } end commands.resetall={ code=function(arg) if arg=="sure"then log"Really?" log"Type: resetall really" elseif arg=="really"then WIDGET.unFocus(true)inputBox.hide=true BGM.stop() commands.cls.code() outputBox:clear() outputBox.h=500 local button=WIDGET.newButton{name='bye',x=640,y=615,w=426,h=100,code=function() TASK.new(function() WIDGET.active.bye.hide=true for _=1,30 do coroutine.yield()end log{C.R,"Bye in 5..."}SFX.play('ready')SFX.play('clear_2')for _=1,60 do coroutine.yield()end log{C.R,"Bye in 4..."}SFX.play('ready')SFX.play('clear_2')for _=1,60 do coroutine.yield()end log{C.R,"Bye in 3..."}SFX.play('ready')SFX.play('clear_2')for _=1,60 do coroutine.yield()end log{C.R,"Bye in 2..."}SFX.play('ready')SFX.play('clear_3')for _=1,60 do coroutine.yield()end log{C.R,"Bye in 1..."}SFX.play('ready')SFX.play('clear_3')for _=1,60 do coroutine.yield()end log{C.R,"Bye in 0..."}SFX.play('start')SFX.play('clear_4')for _=1,60 do coroutine.yield()end outputBox.hide=true for _=1,26 do coroutine.yield()end FILE.clear_s('')love.event.quit() end) end} button:setObject("Techmino is fun. Bye.") ins(WIDGET.active,button) else log"Are you sure to reset all?" log"Type: resetall sure" end end, description="Reset all things.", } commands.sudo={ code=function(code) if sudomode then log{C.Y,"You are already in the sudo mode, use # to run any lua code"} log{C.Y,"已经进入最高权限模式了, 请使用 # 执行任意lua代码"} elseif code=="7126"then sudomode=true log{C.Y,"* SUDO MODE ON, DO NOT RUN ANY CODE YOU DON'T UNDERSTAND *"} log{C.Y,"* 最高权限模式开启, 请不要执行任何自己不懂确切含义的代码 *"} else log{C.Y,"Password not correct"} end end, }commands.su="sudo" --Game commands.rmconf={ code=function(key) if #key>0 then if SETTING[key]~=nil then SETTING[key]=nil saveSettings() log{C.Y,("Succesfully erased key '%s'"):format(key)} else log{C.R,"No key called "..key} end else log{C.A,"Usage: rmconf [key]"} end end, description="Erase a setting value", details={ "Erase a setting value", "Useful if you have your setting corrupted", "YOU MUST RESTART THE GAME AFTER USING THIS", "", "Usage: rmconf [key]", }, } commands.rmrecord={ code=function(modeName) if #modeName>0 then if MODES[modeName]then MODES[modeName].records={} log{C.Y,("Succesfully erased records of "..modeName)} love.filesystem.remove("record/"..modeName..".rec") else log{C.R,"No mode called "..modeName} end else log{C.R,"Usage: rmrecord [modeName]"} end end, description="Erase records of a mode", details={ "Erase records of a mode", "Useful if you have a record list corrupted", "", "Usage: rmrecord [modeName]", }, } commands.unlockall={ code=function(bool) if bool=="sure"then for name,M in next,MODES do if type(name)=='string'and not RANKS[name]and M.x then if M.x then RANKS[name]=0 end end end saveProgress() log{C.lC,"\85\78\76\79\67\75\65\76\76"} SFX.play('clear_2') else log"Are you sure to unlock all modes?" log"Type: unlockall sure" end end, description="Unlock the whole map", details={ "Unlock all modes on the map.", "", "Usage: unlockall", }, } commands.play={ code=function(m) if MODES[m]then loadGame(m,true) elseif m~=""then log{C.R,"No mode called "..m} else log{C.A,"Usage: play [modeName]"} end end, description="Load a game mode", details={ "Load a game mode, including those that are not on the map.", "", "Usage: play [mode_name]", }, } commands.tas={ code=function(bool) if bool=="on"or bool=="off"then SETTING.allowTAS=bool=="on" saveSettings() log("Allow TAS: "..bool) if bool then log("Hot keys: f1=play/pause f2=slowdown f3=speedup/nextframe") end else log{C.A,"Usage: tas "} end end, description="Allow you to use TAS tool", details={ "Allow you to use TAS tool, a TAS button will show up at the pause menu", "", "Usage: tas ", }, } commands.tip={ code=function() log(text.getTip()) end, description="Show a random tip", } --Network commands.switchhost={ code=function(arg) arg=STRING.split(arg," ") if arg[1]and #arg<=3 then WS.switchHost(unpack(arg)) log{C.Y,"Host switched"} else log{C.A,"Usage:"} log{C.A,"switchhost [host]"} log{C.A,"switchhost [host] [port]"} log{C.A,"switchhost [host] [port] [path]"} log{C.A,"Example: switchhost 127.0.0.1 26000 /sock"} end end, description="Switch to another host", details={ "Disconnect all connections and switch to another host", "", "Usage:", "switchhost [host]", "switchhost [host] [port]", "switchhost [host] [port] [path]", "Example: switchhost 127.0.0.1 26000 /sock", }, } function commands.manage() if WS.status('manage')=='running'then WS.close('manage') log{C.Y,"Disconnected"} else if({[1]=0,[2]=0,[26]=0})[USER.uid]then NET.wsconn_manage() log{C.Y,"Connecting"} else log{C.R,"Permission denied"} end end end function commands.m_broadcast(str) if #str>0 then WS.send('manage','{"action":0,"data":'..JSON.encode{message=str}..'}') log{C.Y,"Request sent"} else log{C.R,"format error"} end end function commands.m_shutdown(sec) sec=tonumber(sec) if sec and sec>0 and sec~=math.floor(sec) then WS.send('manage','{"action":9,"data":'..JSON.encode{countdown=tonumber(sec)}..'}') log{C.Y,"Request sent"} else log{C.R,"format error"} end end function commands.m_connInfo()WS.send('manage','{"action":10}')end function commands.m_playMgrInfo()WS.send('manage','{"action":11}')end function commands.m_streamMgrInfo()WS.send('manage','{"action":12}')end for cmd,body in next,commands do if type(body)=='function'then commands[cmd]={code=body} end if type(body)~='string'then ins(cmdList,cmd) end end table.sort(cmdList) TABLE.reIndex(commands) end local combKey={ x=function() love.system.setClipboardText(inputBox:getText()) inputBox:clear() SFX.play('reach') end, c=function() love.system.setClipboardText(inputBox:getText()) SFX.play('reach') end, v=function() inputBox:addText(love.system.getClipboardText()) SFX.play('reach') end, } --Environment for user's function local userG={ timer=TIME, _VERSION=VERSION.code, assert=assert,error=error, tonumber=tonumber,tostring=tostring, select=select,next=next, ipairs=ipairs,pairs=pairs, type=type, pcall=pcall,xpcall=xpcall, rawget=rawget,rawset=rawset,rawlen=rawlen,rawequal=rawequal, setfenv=setfenv,setmetatable=setmetatable, -- require=require, -- load=load,loadfile=loadfile,dofile=dofile, -- getfenv=getfenv,getmetatable=getmetatable, -- collectgarbage=collectgarbage, math={},string={},table={},bit={},coroutine={}, debug={"No way."},package={"No way."},io={"No way."},os={"No way."}, } function userG.print(...) local args,L={...},{} for k,v in next,args do ins(L,{k,v})end table.sort(L,function(a,b)return a[1] "..input} local code,err=loadstring(input:sub(2)) if code then local resultColor if sudomode then resultColor=C.lY else setfenv(code,userG) resultColor=C.lG end local success,result=pcall(code) if success then if result~=nil then log{resultColor,">> "..tostring(result)} else log{resultColor,"done"} end else log{C.R,result} end else log{C.R,"[SyntaxErr] ",C.R,err} end else --Execute builtin command log{C.lS,"> "..input} local p=input:find(" ") local cmd,arg if p then cmd=input:sub(1,p-1):lower() arg=input:sub(input:find("%S",p+1)or -1) else cmd=input arg="" end if commands[cmd]then commands[cmd].code(arg) else log{C.R,"No command called "..cmd} end end inputBox:clear() --Insert empty line log"" elseif key=="up"then if not hisPtr then hisPtr=#history if hisPtr>0 then inputBox:setText(history[hisPtr]) end elseif hisPtr>1 then hisPtr=hisPtr-1 inputBox:setText(history[hisPtr]) end elseif key=="down"then if hisPtr then hisPtr=hisPtr+1 if history[hisPtr]then inputBox:setText(history[hisPtr]) else hisPtr=nil inputBox:clear() end end elseif key=="tab"then local str=inputBox:getText() if str~=""and not str:find("%s")then local res={} for c in next,commands do if c:find(str,nil,true)==1 then ins(res,c) end end if #res>1 then log(">Commands start with '"..str.."' :") table.sort(res) for i=1,#res do log{COLOR.lH,res[i]}end elseif #res==1 then inputBox:setText(res[1]) end end elseif key=="scrollup"then outputBox:scroll(-5) elseif key=="scrolldown"then outputBox:scroll(5) elseif key=="pageup"then outputBox:scroll(-20) elseif key=="pagedown"then outputBox:scroll(20) elseif key=="home"then outputBox:scroll(-1e99) elseif key=="end"then outputBox:scroll(1e99) elseif combKey[key]and kb.isDown("lctrl","rctrl")then combKey[key]() elseif key=="escape"then if not WIDGET.isFocus(inputBox)then WIDGET.focus(inputBox) else SCN.back() end else if not WIDGET.isFocus(inputBox)then WIDGET.focus(inputBox) end WIDGET.keyPressed(key) end end scene.widgetList={ outputBox, inputBox, } return scene