1168 lines
37 KiB
Lua
1168 lines
37 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
|
||
_SCLOG=log
|
||
|
||
log{C.lP,"Techmino Console"}
|
||
log{C.lC,"© Copyright 2019–2022 26F Studio. Some rights reserved."}
|
||
log{C.dR,"WARNING: DO NOT RUN ANY CODE THAT YOU DON'T UNDERSTAND."}
|
||
|
||
local history,hisPtr={"?"}
|
||
local sumode=false
|
||
local the_secret=(0xe^2*10)..(2*0xb)
|
||
|
||
local scene={}
|
||
|
||
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,(" $1 $2"):repD(("·"):rep(16-#cmd),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("Unknown 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 FILE.isSafe(name) 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("Unknown 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("Unknown 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=arg:split(" ")
|
||
if #arg>2 then
|
||
log{C.lY,"Warning: file names must have no spaces"}
|
||
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.viewlog={
|
||
code=goScene('viewlog'),
|
||
description="View crash logs",
|
||
details={
|
||
"Open the crash logs menu",
|
||
"",
|
||
"Usage: viewlog"
|
||
}
|
||
}
|
||
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.getPlaying()[1] 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 BGM",
|
||
details={
|
||
"Stop the currently playing BGM.",
|
||
"",
|
||
"Usage: stopbgm"
|
||
},
|
||
}
|
||
commands.setbg={
|
||
code=function(name)
|
||
if name~="" then
|
||
if SETTING.lockBG then
|
||
log{"Background is currently ",C.R,"locked",C.Z,"! You can unlock it in Video settings."}
|
||
elseif 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 SETTING.noTheme then
|
||
log{"Themes are currently ",C.R,"disabled",C.Z,"! You can re-enable it in Video settings."}
|
||
else
|
||
if THEME.set(name) then
|
||
log("Theme set to: "..name)
|
||
else
|
||
log("No theme called "..name)
|
||
end
|
||
end
|
||
else
|
||
log{C.A,"Usage: theme <xmas|halloween|sprfes|zday1/2/3|season1/2/3/4|fool|birth>"}
|
||
end
|
||
end,
|
||
description="Load theme",
|
||
details={
|
||
"Load a theme.",
|
||
"",
|
||
"Usage: theme <xmas|sprfes|zday1/2/3|season1/2/3/4|fool|birth>",
|
||
},
|
||
}
|
||
commands.test={
|
||
code=function()
|
||
SCN.go('test','none')
|
||
end,
|
||
description="Enter test scene",
|
||
details={
|
||
"Go to an empty test scene",
|
||
"",
|
||
"Usage: test",
|
||
},
|
||
}
|
||
commands.support={
|
||
code=function(arg)
|
||
if FNNS then
|
||
if arg:find"pl" and arg:find"fk" then
|
||
SCN.go('support','none')
|
||
else
|
||
love.system.openURL("https://www.bilibili.com/video/BV1uT4y1P7CX?secretcode=fkpl")
|
||
end
|
||
else
|
||
SCN.go('support','none')
|
||
end
|
||
end,
|
||
description="Enter support scene",
|
||
details={
|
||
"Go to an support scene",
|
||
"",
|
||
"Usage: support",
|
||
},
|
||
}
|
||
do-- app
|
||
local APPs={
|
||
{
|
||
code="calc",
|
||
scene='app_calc',
|
||
description="A simple calculator"
|
||
},
|
||
{
|
||
code="15p",
|
||
scene='app_15p',
|
||
description="15 Puzzle (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 (typing)"
|
||
},
|
||
{
|
||
code="uttt",
|
||
scene='app_UTTT',
|
||
description="Ultimate Tic-Tac-Toe (2P)"
|
||
},
|
||
{
|
||
code="cube",
|
||
scene='app_cubefield',
|
||
description="Cubefield, original game by Max Abernethy"
|
||
},
|
||
{
|
||
code="2048",
|
||
scene='app_2048',
|
||
description="2048 with some new features. Original by Asher Vollmer"
|
||
},
|
||
{
|
||
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 (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 (Shisen-Sho)"
|
||
},
|
||
{
|
||
code="arm",
|
||
scene='app_arithmetic',
|
||
description="Arithmetic"
|
||
},
|
||
{
|
||
code="piano",
|
||
scene='app_piano',
|
||
description="A simple keyboard piano"
|
||
},
|
||
{
|
||
code="mem",
|
||
scene='app_memorize',
|
||
description="Number memorize"
|
||
},
|
||
{
|
||
code="trp",
|
||
scene='app_triple',
|
||
description="A Match-3 Game. Original idea from Sanlitun / Triple Town"
|
||
},
|
||
{
|
||
code="sw",
|
||
scene='app_stopwatch',
|
||
description="A stopwatch"
|
||
},
|
||
{
|
||
code="mj",
|
||
scene='app_mahjong',
|
||
description="A simple mahjong game (1 player)"
|
||
},
|
||
{
|
||
code="spin",
|
||
scene='app_spin',
|
||
description="¿"
|
||
},
|
||
}
|
||
commands.app={
|
||
code=function(name)
|
||
if name=="-list" then
|
||
for i=1,#APPs do
|
||
log(("$1 $2 $3"):repD(APPs[i].code,("·"):rep(10-#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"FINAL WARNING!"
|
||
log"Please remember that resetting everything will delete all saved data. Delete the saved data anyway?"
|
||
log"Once the data has been deleted, there is no way to recover it."
|
||
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()
|
||
scene.widgetList.bye.hide=true
|
||
TEST.yieldN(30)
|
||
log{C.R,"Deleting all data in 10..."}SFX.play('ready')SFX.play('clear_1')TEST.yieldN(60)
|
||
log{C.R,"Deleting all data in 9..."} SFX.play('ready')SFX.play('clear_1')TEST.yieldN(60)
|
||
log{C.R,"Deleting all data in 8..."} SFX.play('ready')SFX.play('clear_1')TEST.yieldN(60)
|
||
log{C.R,"Deleting all data in 7..."} SFX.play('ready')SFX.play('clear_2')TEST.yieldN(60)
|
||
log{C.R,"Deleting all data in 6..."} SFX.play('ready')SFX.play('clear_2')TEST.yieldN(60)
|
||
log{C.R,"Deleting all data in 5..."} SFX.play('ready')SFX.play('clear_3')TEST.yieldN(60)
|
||
log{C.R,"Deleting all data in 4..."} SFX.play('ready')SFX.play('clear_3')TEST.yieldN(60)
|
||
log{C.R,"Deleting all data in 3..."} SFX.play('ready')SFX.play('clear_4')TEST.yieldN(60)
|
||
log{C.R,"Deleting all data in 2..."} SFX.play('ready')SFX.play('clear_4')TEST.yieldN(60)
|
||
log{C.R,"Deleting all data in 1..."} SFX.play('ready')SFX.play('clear_5')TEST.yieldN(60)
|
||
log{C.R,"Deleting all data in 0..."} SFX.play('start')SFX.play('clear_6')TEST.yieldN(60)
|
||
outputBox.hide=true
|
||
TEST.yieldN(26)
|
||
FILE.clear_s('')
|
||
love.event.quit()
|
||
end)
|
||
end}
|
||
button:setObject("Techmino is fun. Bye.")
|
||
ins(scene.widgetList,button)
|
||
else
|
||
log"Are you sure you want to reset everything?"
|
||
log"This will delete EVERYTHING in your saved game data, including but not limited to:"
|
||
log"All your replays, saved scores, settings, etc."
|
||
log"This cannot be undone."
|
||
log"Type: resetall sure"
|
||
end
|
||
end,
|
||
description="Reset everything and delete all saved data.",
|
||
}
|
||
commands.su={
|
||
code=function(code)
|
||
if sumode then
|
||
log{C.Y,"You are already in su mode. Use # to run any lua code"}
|
||
log{C.Y,"已经进入最高权限模式了, 请使用 # 执行任意lua代码"}
|
||
elseif code=="7126" then
|
||
sumode=true
|
||
log{C.Y,"* SU MODE ON - DO NOT RUN ANY CODES IF YOU DO NOT KNOW WHAT THEY DO *"}
|
||
log{C.Y,"* Use the _SCLOG(message) function to print into this console *"}
|
||
log{C.Y,"* 最高权限模式开启, 请不要执行任何自己不懂确切含义的代码 *"}
|
||
log{C.Y,"* 使用_SCLOG(信息)函数在控制台打印信息 *"}
|
||
else
|
||
log{C.Y,"Password incorrect"}
|
||
end
|
||
end,
|
||
}
|
||
|
||
-- Game
|
||
commands.rmconf={
|
||
code=function(key)
|
||
if #key>0 then
|
||
if SETTING[key]~=nil then
|
||
SETTING[key]=nil
|
||
saveSettings()
|
||
log{C.Y,("Successfully 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 any of your settings are corrupted.",
|
||
"YOU MUST RESTART THE GAME AFTER USING THIS COMMAND.",
|
||
"",
|
||
"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 you want to unlock all game 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. This includes 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=slow down f3=speed up/next frame f4=adjust skip settings")
|
||
end
|
||
else
|
||
log{C.A,"Usage: tas <on|off>"}
|
||
end
|
||
end,
|
||
description="Toggle TAS tool",
|
||
details={
|
||
"Once the TAS tool is enabled, 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=arg:split(" ")
|
||
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.m_broadcast(str)
|
||
if #str>0 then
|
||
WS.send('game',JSON.encode{action=0,data={message=str}})
|
||
log{C.Y,"Request sent"}
|
||
else
|
||
log{C.R,"Format error"}
|
||
end
|
||
end
|
||
function commands.m_shutdown(time)
|
||
time=tonumber(time)
|
||
if time and time>1 then
|
||
WS.send('game',JSON.encode{action=0,data={countdown=time}})
|
||
log{C.Y,"Request sent"}
|
||
else
|
||
log{C.R,"Format error"}
|
||
end
|
||
end
|
||
function commands.m_connInfo() WS.send('game',JSON.encode{action=10}) end
|
||
function commands.m_playMgrInfo() WS.send('game',JSON.encode{action=11}) end
|
||
function commands.m_streamMgrInfo() WS.send('game',JSON.encode{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={},package={},io={},os={},
|
||
}
|
||
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)
|
||
local dangerousLibMeta={__index=function() error("No way.") end}
|
||
setmetatable(userG.debug,dangerousLibMeta)
|
||
setmetatable(userG.package,dangerousLibMeta)
|
||
setmetatable(userG.io,dangerousLibMeta)
|
||
setmetatable(userG.os,dangerousLibMeta)
|
||
|
||
-- 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
|
||
|
||
|
||
|
||
function scene.enter()
|
||
WIDGET.focus(inputBox)
|
||
BG.set('none')
|
||
DiscordRPC.update("Hacking the system")
|
||
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 sumode 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 that 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(-25)
|
||
elseif key=='pagedown' then outputBox:scroll(25)
|
||
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
|
||
return true
|
||
end
|
||
end
|
||
|
||
scene.widgetList={
|
||
outputBox,
|
||
inputBox,
|
||
}
|
||
|
||
return scene |