2018-07-22 03:43:01 +00:00
|
|
|
package doodle
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2018-07-26 02:38:54 +00:00
|
|
|
"strconv"
|
2018-10-02 17:11:38 +00:00
|
|
|
|
2019-04-10 00:35:44 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/enum"
|
2019-04-20 00:23:37 +00:00
|
|
|
"github.com/robertkrimen/otto"
|
2018-07-22 03:43:01 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Command is a parsed shell command.
|
|
|
|
type Command struct {
|
|
|
|
Raw string // The complete raw command the user typed.
|
|
|
|
Command string // The first word of their command.
|
|
|
|
Args []string // The shell-args array of parameters.
|
|
|
|
ArgsLiteral string // The args portion of the command literally.
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run the command.
|
|
|
|
func (c Command) Run(d *Doodle) error {
|
|
|
|
if len(c.Raw) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-04-10 01:28:08 +00:00
|
|
|
// Cheat codes
|
|
|
|
if c.Raw == "unleash the beast" {
|
|
|
|
if fpsDoNotCap {
|
|
|
|
d.Flash("Reset frame rate throttle to factory default FPS")
|
|
|
|
} else {
|
|
|
|
d.Flash("Unleashing as many frames as we can render!")
|
|
|
|
}
|
|
|
|
fpsDoNotCap = !fpsDoNotCap
|
|
|
|
return nil
|
2019-05-29 05:34:54 +00:00
|
|
|
} else if c.Raw == "don't edit and drive" {
|
|
|
|
if playScene, ok := d.Scene.(*PlayScene); ok {
|
|
|
|
playScene.drawing.Editable = true
|
|
|
|
d.Flash("Level canvas is now editable. Don't edit and drive!")
|
|
|
|
} else {
|
|
|
|
d.Flash("Use this cheat in Play Mode to make the level canvas editable.")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
} else if c.Raw == "scroll scroll scroll your boat" {
|
|
|
|
if playScene, ok := d.Scene.(*PlayScene); ok {
|
|
|
|
playScene.drawing.Scrollable = true
|
|
|
|
d.Flash("Level canvas is now scrollable with the arrow keys.")
|
|
|
|
} else {
|
|
|
|
d.Flash("Use this cheat in Play Mode to make the level scrollable.")
|
|
|
|
}
|
|
|
|
return nil
|
2019-04-10 01:28:08 +00:00
|
|
|
}
|
|
|
|
|
2018-07-22 03:43:01 +00:00
|
|
|
switch c.Command {
|
2018-07-25 05:26:27 +00:00
|
|
|
case "echo":
|
|
|
|
d.Flash(c.ArgsLiteral)
|
|
|
|
return nil
|
2018-07-22 03:43:01 +00:00
|
|
|
case "new":
|
|
|
|
return c.New(d)
|
|
|
|
case "save":
|
|
|
|
return c.Save(d)
|
|
|
|
case "edit":
|
|
|
|
return c.Edit(d)
|
|
|
|
case "play":
|
|
|
|
return c.Play(d)
|
2018-10-08 17:38:49 +00:00
|
|
|
case "close":
|
|
|
|
return c.Close(d)
|
2018-07-22 03:43:01 +00:00
|
|
|
case "exit":
|
|
|
|
case "quit":
|
|
|
|
return c.Quit()
|
2018-07-25 05:26:27 +00:00
|
|
|
case "help":
|
|
|
|
return c.Help(d)
|
2018-08-02 01:52:52 +00:00
|
|
|
case "reload":
|
|
|
|
d.Goto(d.Scene)
|
|
|
|
return nil
|
|
|
|
case "guitest":
|
|
|
|
d.Goto(&GUITestScene{})
|
|
|
|
return nil
|
2018-07-26 02:38:54 +00:00
|
|
|
case "eval":
|
|
|
|
case "$":
|
2019-04-20 00:23:37 +00:00
|
|
|
out, err := c.RunScript(d, c.ArgsLiteral)
|
2018-07-26 02:38:54 +00:00
|
|
|
d.Flash("%+v", out)
|
|
|
|
return err
|
2018-10-08 20:06:42 +00:00
|
|
|
case "repl":
|
|
|
|
d.shell.Repl = true
|
|
|
|
d.shell.Text = "$ "
|
2018-07-26 02:38:54 +00:00
|
|
|
case "boolProp":
|
|
|
|
return c.BoolProp(d)
|
2018-07-22 03:43:01 +00:00
|
|
|
default:
|
|
|
|
return c.Default()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// New opens a new map in the editor mode.
|
|
|
|
func (c Command) New(d *Doodle) error {
|
2018-07-25 05:26:27 +00:00
|
|
|
d.Flash("Starting a new map")
|
2018-07-22 03:43:01 +00:00
|
|
|
d.NewMap()
|
|
|
|
return nil
|
2018-10-08 17:38:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Close returns to the Main Scene.
|
|
|
|
func (c Command) Close(d *Doodle) error {
|
|
|
|
main := &MainScene{}
|
|
|
|
d.Goto(main)
|
|
|
|
return nil
|
2018-07-22 03:43:01 +00:00
|
|
|
}
|
|
|
|
|
2018-07-25 05:26:27 +00:00
|
|
|
// Help prints the help info.
|
|
|
|
func (c Command) Help(d *Doodle) error {
|
|
|
|
if len(c.Args) == 0 {
|
|
|
|
d.Flash("Available commands: new save edit play quit echo clear help")
|
|
|
|
d.Flash("Type `help` and then the command, like: `help edit`")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
switch c.Args[0] {
|
|
|
|
case "new":
|
|
|
|
d.Flash("Usage: new")
|
|
|
|
d.Flash("Create a new drawing in Edit Mode")
|
|
|
|
case "save":
|
|
|
|
d.Flash("Usage: save [filename.json]")
|
|
|
|
d.Flash("Save the map to disk (in Edit Mode only)")
|
|
|
|
case "edit":
|
|
|
|
d.Flash("Usage: edit <filename.json>")
|
|
|
|
d.Flash("Open a file on disk in Edit Mode")
|
|
|
|
case "play":
|
|
|
|
d.Flash("Usage: play <filename.json>")
|
|
|
|
d.Flash("Open a map from disk in Play Mode")
|
|
|
|
case "echo":
|
|
|
|
d.Flash("Usage: echo <message>")
|
|
|
|
d.Flash("Flash a message back to the console")
|
|
|
|
case "quit":
|
|
|
|
case "exit":
|
|
|
|
d.Flash("Usage: quit")
|
|
|
|
d.Flash("Closes the dev console")
|
|
|
|
case "clear":
|
|
|
|
d.Flash("Usage: clear")
|
|
|
|
d.Flash("Clears the terminal output history")
|
|
|
|
case "help":
|
|
|
|
d.Flash("Usage: help <command>")
|
|
|
|
default:
|
|
|
|
d.Flash("Unknown help topic.")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-07-22 03:43:01 +00:00
|
|
|
// Save the current map to disk.
|
|
|
|
func (c Command) Save(d *Doodle) error {
|
2018-07-26 02:38:54 +00:00
|
|
|
if scene, ok := d.Scene.(*EditorScene); ok {
|
2018-07-22 03:43:01 +00:00
|
|
|
filename := ""
|
|
|
|
if len(c.Args) > 0 {
|
|
|
|
filename = c.Args[0]
|
|
|
|
} else if scene.filename != "" {
|
|
|
|
filename = scene.filename
|
|
|
|
} else {
|
2018-10-02 17:11:38 +00:00
|
|
|
return errors.New("usage: save <filename>")
|
2018-07-22 03:43:01 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 17:11:38 +00:00
|
|
|
switch scene.DrawingType {
|
|
|
|
case enum.LevelDrawing:
|
|
|
|
d.shell.Write("Saving Level: " + filename)
|
|
|
|
scene.SaveLevel(filename)
|
|
|
|
case enum.DoodadDrawing:
|
|
|
|
d.shell.Write("Saving Doodad: " + filename)
|
|
|
|
scene.SaveDoodad(filename)
|
|
|
|
}
|
2018-07-22 03:43:01 +00:00
|
|
|
} else {
|
|
|
|
return errors.New("save: only available in Edit Mode")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Edit a map from disk.
|
|
|
|
func (c Command) Edit(d *Doodle) error {
|
|
|
|
if len(c.Args) == 0 {
|
|
|
|
return errors.New("Usage: edit <file name>")
|
|
|
|
}
|
|
|
|
|
|
|
|
filename := c.Args[0]
|
2018-10-02 17:11:38 +00:00
|
|
|
d.shell.Write("Editing file: " + filename)
|
2019-04-20 00:23:37 +00:00
|
|
|
return d.EditFile(filename)
|
2018-07-22 03:43:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Play a map.
|
|
|
|
func (c Command) Play(d *Doodle) error {
|
|
|
|
if len(c.Args) == 0 {
|
|
|
|
return errors.New("Usage: play <file name>")
|
|
|
|
}
|
|
|
|
|
|
|
|
filename := c.Args[0]
|
|
|
|
d.shell.Write("Playing level: " + filename)
|
|
|
|
d.PlayLevel(filename)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Quit the command line shell.
|
|
|
|
func (c Command) Quit() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-07-26 02:38:54 +00:00
|
|
|
// BoolProp command sets available boolean variables.
|
|
|
|
func (c Command) BoolProp(d *Doodle) error {
|
|
|
|
if len(c.Args) != 2 {
|
|
|
|
return errors.New("Usage: boolProp <name> <true or false>")
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
name = c.Args[0]
|
|
|
|
value = c.Args[1]
|
|
|
|
truthy = value[0] == 't' || value[0] == 'T' || value[0] == '1'
|
|
|
|
ok = true
|
|
|
|
)
|
|
|
|
|
|
|
|
switch name {
|
|
|
|
case "Debug":
|
|
|
|
case "D":
|
|
|
|
d.Debug = truthy
|
|
|
|
case "DebugOverlay":
|
|
|
|
case "DO":
|
|
|
|
DebugOverlay = truthy
|
|
|
|
case "DebugCollision":
|
|
|
|
case "DC":
|
|
|
|
DebugCollision = truthy
|
|
|
|
default:
|
|
|
|
ok = false
|
|
|
|
}
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
d.Flash("Set boolProp %s=%s", name, strconv.FormatBool(truthy))
|
|
|
|
} else {
|
|
|
|
d.Flash("Unknown boolProp name %s", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-04-20 00:23:37 +00:00
|
|
|
// RunScript evaluates some JavaScript code safely.
|
|
|
|
func (c Command) RunScript(d *Doodle, code interface{}) (otto.Value, error) {
|
|
|
|
defer func() {
|
|
|
|
if err := recover(); err != nil {
|
|
|
|
d.Flash("Panic: %s", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
out, err := d.shell.js.Run(code)
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
2018-07-22 03:43:01 +00:00
|
|
|
// Default command.
|
|
|
|
func (c Command) Default() error {
|
|
|
|
return fmt.Errorf("%s: command not found. Try `help` for help",
|
|
|
|
c.Command,
|
|
|
|
)
|
|
|
|
}
|