1106 lines
34 KiB
Lua
1106 lines
34 KiB
Lua
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,fType='mono'}
|
|
local outputBox=WIDGET.newTextBox{name='output',x=40,y=30,w=1200,h=610,font=25,fType='mono',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 <check|info|broadcast|warn|error>"}
|
|
end
|
|
end,
|
|
description="Show a message",
|
|
details={
|
|
"Show a message on the up-left corner",
|
|
"",
|
|
"Usage: mes <check|info|warn|error>",
|
|
},
|
|
}
|
|
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 <on|off>"}
|
|
end
|
|
end,
|
|
description="Turn on/off wireframe mode",
|
|
details={
|
|
"Enable or disable wireframe drawing mode.",
|
|
"",
|
|
"Usage: wireframe <on|off>",
|
|
},
|
|
}
|
|
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 <on|off>"}
|
|
end
|
|
end,
|
|
description="Turn on/off gamma correction",
|
|
details={
|
|
"Enable or disable gamma correction.",
|
|
"",
|
|
"Usage: gammacorrect <on|off>",
|
|
},
|
|
}
|
|
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 <classic|xmas|sprfes|zday1/2/3|birth>",
|
|
},
|
|
}
|
|
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"
|
|
},
|
|
{
|
|
code="piano",
|
|
scene='app_piano',
|
|
description="A simple keyboard piano"
|
|
},
|
|
{
|
|
code="spin",
|
|
scene='app_spin',
|
|
description="???"
|
|
},
|
|
}
|
|
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 <on|off>"}
|
|
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 <on|off>",
|
|
},
|
|
}
|
|
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]<b[1]end)
|
|
local i=1
|
|
while L[1]do
|
|
if i==L[1][1]then
|
|
log(tostring(L[1][2]))
|
|
rem(L,1)
|
|
else
|
|
log("nil")
|
|
end
|
|
i=i+1
|
|
end
|
|
end
|
|
userG._G=userG
|
|
TABLE.complete(math,userG.math)
|
|
TABLE.complete(string,userG.string)userG.string.dump=nil
|
|
TABLE.complete(table,userG.table)
|
|
TABLE.complete(bit,userG.bit)
|
|
TABLE.complete(coroutine,userG.coroutine)
|
|
|
|
--Puzzle box
|
|
local first_key={}
|
|
local fleg={
|
|
pw=the_secret,
|
|
supw=7126,
|
|
second_box="Coming soon",
|
|
}setmetatable(fleg,{__tostring=function()return"The fl\97g."end})
|
|
function userG.the_box(k)
|
|
if k~=first_key then
|
|
log"Usage:"log"*The box is locked*"
|
|
return
|
|
end
|
|
log"*Breaking sound*"
|
|
userG.the_box,userG.the_key=nil,nil
|
|
return fleg
|
|
end
|
|
userG.the_key=first_key
|
|
|
|
|
|
|
|
local scene={}
|
|
|
|
function scene.sceneInit()
|
|
WIDGET.focus(inputBox)
|
|
BG.set('none')
|
|
end
|
|
|
|
function scene.wheelMoved(_,y)
|
|
WHEELMOV(y,"scrollup","scrolldown")
|
|
end
|
|
|
|
function scene.keyDown(key)
|
|
if key=="return" or key=="kpenter"then
|
|
local input=STRING.trim(inputBox:getText())
|
|
if input==""then return end
|
|
|
|
--Write History
|
|
ins(history,input)
|
|
if history[27]then
|
|
rem(history,1)
|
|
end
|
|
hisPtr=nil
|
|
|
|
--Execute
|
|
if input:byte()==35 then
|
|
--Execute lua code
|
|
log{C.lC,"> "..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
|