Cheats Menu UI
* Added a Cheats Menu UI accessible from the Settings window's "Experimental" tab and from there you can enable the Cheats Menu from the "Help" screen of the gameplay mode. * Commonly used cheats all have corresponding buttons to click on, especially helpful for touchscreen devices like the Pinephone where keyboard input doesn't always work reliably. * The buttons in the Cheats Menu just automate entry of the cheat commands. * `boolProp` command has a new `flip` option to toggle their value (e.g. `boolProp show-hidden-doodads flip`)
This commit is contained in:
parent
06dd30893c
commit
a10a09a818
12
Changes.md
12
Changes.md
|
@ -1,5 +1,17 @@
|
|||
# Changes
|
||||
|
||||
## v0.13.2 (TBD)
|
||||
|
||||
* In the level editor, you can now use the Pan Tool to access the actor
|
||||
properties of doodads you've dropped into your level. Similar to the
|
||||
Actor Tool, when you mouse-over an actor on your level it will highlight
|
||||
in a grey box and a gear icon in the corner can be clicked to access
|
||||
its properties. Making the properties available for the Pan Tool can
|
||||
help with touchscreen devices, where it is difficult to touch the
|
||||
properties button without accidentally dragging the actor elsewhere
|
||||
on your level as might happen with the Actor Tool!
|
||||
* Start distributing AppImage releases for GNU/Linux (64-bit and 32-bit)
|
||||
|
||||
## v0.13.1 (Oct 10 2022)
|
||||
|
||||
This release brings a handful of minor new features to the game.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package balance
|
||||
|
||||
import magicform "git.kirsle.net/SketchyMaze/doodle/pkg/uix/magic-form"
|
||||
|
||||
// Store a copy of the PlayerCharacterDoodad original value.
|
||||
var playerCharacterDefault string
|
||||
|
||||
|
@ -50,3 +52,39 @@ var CheatActors = map[string]string{
|
|||
"megaton weight": "anvil",
|
||||
"play as thief": "thief",
|
||||
}
|
||||
|
||||
// Options for the "Play as:" drop-down in the Cheat Menu window.
|
||||
var CheatMenuActors = []magicform.Option{
|
||||
{
|
||||
Value: "",
|
||||
Label: "Play as . . .",
|
||||
},
|
||||
{
|
||||
Value: "boy.doodad",
|
||||
Label: "Boy",
|
||||
},
|
||||
{
|
||||
Value: "thief.doodad",
|
||||
Label: "Thief",
|
||||
},
|
||||
{
|
||||
Value: "azu-blu.doodad",
|
||||
Label: "Azulian",
|
||||
},
|
||||
{
|
||||
Value: "bird-red.doodad",
|
||||
Label: "Bird",
|
||||
},
|
||||
{
|
||||
Value: "crusher.doodad",
|
||||
Label: "Crusher",
|
||||
},
|
||||
{
|
||||
Value: "snake.doodad",
|
||||
Label: "Snake",
|
||||
},
|
||||
{
|
||||
Value: "anvil.doodad",
|
||||
Label: "Anvil",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -227,6 +227,9 @@ var (
|
|||
DoodadDropperCols = 6 // rows/columns of buttons
|
||||
DoodadDropperRows = 3
|
||||
|
||||
// CheatsMenu window settings.
|
||||
CheatsMenuBackground = render.RGBA(0, 153, 153, 255)
|
||||
|
||||
// Button styles, customized in init().
|
||||
ButtonPrimary = style.DefaultButton
|
||||
ButtonDanger = style.DefaultButton
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
const (
|
||||
AppName = "Sketchy Maze"
|
||||
Summary = "A drawing-based maze game"
|
||||
Version = "0.13.1"
|
||||
Version = "0.13.2"
|
||||
Website = "https://www.sketchymaze.com"
|
||||
Copyright = "2022 Noah Petherbridge"
|
||||
Byline = "a game by Noah Petherbridge."
|
||||
|
|
|
@ -7,11 +7,48 @@ import (
|
|||
"git.kirsle.net/SketchyMaze/doodle/pkg/balance"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/modal"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/modal/loadscreen"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/windows"
|
||||
"git.kirsle.net/go/ui"
|
||||
)
|
||||
|
||||
// IsDefaultPlayerCharacter checks whether the DefaultPlayerCharacter doodad has
|
||||
// been modified
|
||||
|
||||
// MakeCheatsWindow initializes the windows/cheats_menu.go window from anywhere you need it,
|
||||
// binding all the variables in. If you pass a nil Supervisor, this function will attempt to
|
||||
// find one based on your Scene and
|
||||
func (d *Doodle) MakeCheatsWindow(supervisor *ui.Supervisor) *ui.Window {
|
||||
// If not given a supervisor, try and find one.
|
||||
if supervisor == nil {
|
||||
if v, err := d.FindLikelySupervisor(); err != nil {
|
||||
d.FlashError("Couldn't make cheats window: %s", err)
|
||||
return nil
|
||||
} else {
|
||||
supervisor = v
|
||||
}
|
||||
}
|
||||
|
||||
cfg := windows.CheatsMenu{
|
||||
Supervisor: supervisor,
|
||||
Engine: d.Engine,
|
||||
SceneName: func() string {
|
||||
return d.Scene.Name()
|
||||
},
|
||||
RunCommand: func(command string) {
|
||||
d.shell.Execute(command)
|
||||
},
|
||||
OnSetPlayerCharacter: func(doodad string) {
|
||||
if scene, ok := d.Scene.(*PlayScene); ok {
|
||||
scene.SetPlayerCharacter(doodad)
|
||||
} else {
|
||||
shmem.FlashError("This only works during Play Mode.")
|
||||
}
|
||||
},
|
||||
}
|
||||
return windows.MakeCheatsMenu(cfg)
|
||||
}
|
||||
|
||||
// SetPlayerCharacter -- this is designed to be called in-game with the developer
|
||||
// console. Sets your player character to whatever doodad you want, not just the
|
||||
// few that have cheat codes. If you set an invalid filename, you become the
|
||||
|
|
|
@ -315,13 +315,14 @@ func (c Command) BoolProp(d *Doodle) error {
|
|||
}
|
||||
|
||||
if len(c.Args) != 2 {
|
||||
return errors.New("Usage: boolProp <name> [true or false]")
|
||||
return errors.New("Usage: boolProp <name> [true, false, flip]")
|
||||
}
|
||||
|
||||
var (
|
||||
name = c.Args[0]
|
||||
value = c.Args[1]
|
||||
truthy = value[0] == 't' || value[0] == 'T' || value[0] == '1'
|
||||
flip = value == "flip"
|
||||
ok = true
|
||||
)
|
||||
|
||||
|
@ -331,16 +332,28 @@ func (c Command) BoolProp(d *Doodle) error {
|
|||
d.Debug = truthy
|
||||
case "DebugOverlay":
|
||||
case "DO":
|
||||
if flip {
|
||||
DebugOverlay = !DebugOverlay
|
||||
} else {
|
||||
DebugOverlay = truthy
|
||||
}
|
||||
case "DebugCollision":
|
||||
case "DC":
|
||||
if flip {
|
||||
DebugCollision = !DebugCollision
|
||||
} else {
|
||||
DebugCollision = truthy
|
||||
}
|
||||
default:
|
||||
ok = false
|
||||
}
|
||||
|
||||
if ok {
|
||||
if flip {
|
||||
d.Flash("Toggled boolProp %s", name)
|
||||
} else {
|
||||
d.Flash("Set boolProp %s=%s", name, strconv.FormatBool(truthy))
|
||||
}
|
||||
} else {
|
||||
// Try the global boolProps in balance package.
|
||||
if err := balance.BoolProp(name, truthy); err != nil {
|
||||
|
|
|
@ -255,6 +255,9 @@ func (d *Doodle) MakeSettingsWindow(supervisor *ui.Supervisor) *ui.Window {
|
|||
OnApply: func() {
|
||||
|
||||
},
|
||||
OnOpenCheatsWindow: func() *ui.Window {
|
||||
return d.MakeCheatsWindow(supervisor)
|
||||
},
|
||||
|
||||
// Boolean checkbox bindings
|
||||
DebugOverlay: &DebugOverlay,
|
||||
|
|
|
@ -54,7 +54,7 @@ type PlayScene struct {
|
|||
cheated bool // user has entered a cheat code while playing
|
||||
|
||||
// UI widgets.
|
||||
supervisor *ui.Supervisor
|
||||
Supervisor *ui.Supervisor
|
||||
screen *ui.Frame // A window sized invisible frame to position UI elements.
|
||||
menubar *ui.MenuBar
|
||||
editButton *ui.Button
|
||||
|
@ -87,6 +87,9 @@ type PlayScene struct {
|
|||
invenItems []string // item list
|
||||
invenDoodads map[string]*uix.Canvas
|
||||
|
||||
// Cheats window
|
||||
cheatsWindow *ui.Window
|
||||
|
||||
// Elapsed Time frame.
|
||||
timerFrame *ui.Frame
|
||||
timerPerfectImage *ui.Image
|
||||
|
@ -109,7 +112,7 @@ func (s *PlayScene) Name() string {
|
|||
func (s *PlayScene) Setup(d *Doodle) error {
|
||||
s.d = d
|
||||
s.scripting = scripting.NewSupervisor()
|
||||
s.supervisor = ui.NewSupervisor()
|
||||
s.Supervisor = ui.NewSupervisor()
|
||||
|
||||
// Show the loading screen.
|
||||
loadscreen.ShowWithProgress()
|
||||
|
@ -167,7 +170,7 @@ func (s *PlayScene) setupAsync(d *Doodle) error {
|
|||
s.EditLevel()
|
||||
return nil
|
||||
})
|
||||
s.supervisor.Add(s.editButton)
|
||||
s.Supervisor.Add(s.editButton)
|
||||
|
||||
// Set up the inventory HUD.
|
||||
s.setupInventoryHud()
|
||||
|
@ -751,7 +754,7 @@ func (s *PlayScene) Loop(d *Doodle, ev *event.State) error {
|
|||
// Update the timer.
|
||||
s.timerLabel.Text = savegame.FormatDuration(time.Since(s.startTime))
|
||||
|
||||
s.supervisor.Loop(ev)
|
||||
s.Supervisor.Loop(ev)
|
||||
|
||||
// Has the window been resized?
|
||||
if ev.WindowResized || s.drawing.Point().IsZero() {
|
||||
|
@ -845,7 +848,7 @@ func (s *PlayScene) Draw(d *Doodle) error {
|
|||
s.DrawTouchable()
|
||||
|
||||
// Let Supervisor draw menus
|
||||
s.supervisor.Present(d.Engine)
|
||||
s.Supervisor.Present(d.Engine)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ func (u *PlayScene) setupMenuBar(d *Doodle) *ui.MenuBar {
|
|||
// TODO: de-duplicate code from MainScene
|
||||
if u.winLevelPacks == nil {
|
||||
u.winLevelPacks = windows.NewLevelPackWindow(windows.LevelPack{
|
||||
Supervisor: u.supervisor,
|
||||
Supervisor: u.Supervisor,
|
||||
Engine: d.Engine,
|
||||
|
||||
OnPlayLevel: func(lp levelpack.LevelPack, which levelpack.Level) {
|
||||
|
@ -66,7 +66,7 @@ func (u *PlayScene) setupMenuBar(d *Doodle) *ui.MenuBar {
|
|||
levelMenu.AddSeparator()
|
||||
levelMenu.AddItemAccel("New viewport", "v", func() {
|
||||
pip := windows.MakePiPWindow(d.width, d.height, windows.PiP{
|
||||
Supervisor: u.supervisor,
|
||||
Supervisor: u.Supervisor,
|
||||
Engine: u.d.Engine,
|
||||
Level: u.Level,
|
||||
Event: u.d.event,
|
||||
|
@ -76,9 +76,22 @@ func (u *PlayScene) setupMenuBar(d *Doodle) *ui.MenuBar {
|
|||
})
|
||||
}
|
||||
|
||||
d.MakeHelpMenu(menu, u.supervisor)
|
||||
helpMenu := d.MakeHelpMenu(menu, u.Supervisor)
|
||||
if usercfg.Current.EnableCheatsMenu {
|
||||
helpMenu.AddSeparator()
|
||||
helpMenu.AddItem("Cheats Menu", func() {
|
||||
if u.cheatsWindow != nil {
|
||||
u.cheatsWindow.Hide()
|
||||
u.cheatsWindow.Destroy()
|
||||
u.cheatsWindow = nil
|
||||
}
|
||||
|
||||
menu.Supervise(u.supervisor)
|
||||
u.cheatsWindow = u.d.MakeCheatsWindow(u.Supervisor)
|
||||
u.cheatsWindow.Show()
|
||||
})
|
||||
}
|
||||
|
||||
menu.Supervise(u.Supervisor)
|
||||
menu.Compute(d.Engine)
|
||||
|
||||
return menu
|
||||
|
|
|
@ -30,8 +30,8 @@ func (s *PlayScene) LoopTouchable(ev *event.State) {
|
|||
|
||||
// Don't do any of this if the mouse is over the menu bar, so
|
||||
// clicking on the menus doesn't make the character move or jump.
|
||||
if cursor.Inside(s.menubar.Rect()) || s.supervisor.GetModal() != nil ||
|
||||
s.supervisor.IsPointInWindow(cursor) {
|
||||
if cursor.Inside(s.menubar.Rect()) || s.Supervisor.GetModal() != nil ||
|
||||
s.Supervisor.IsPointInWindow(cursor) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
15
pkg/shell.go
15
pkg/shell.go
|
@ -2,6 +2,7 @@ package doodle
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -44,6 +45,20 @@ func (d *Doodle) PromptPre(question string, prefilled string, callback func(stri
|
|||
d.shell.Open = true
|
||||
}
|
||||
|
||||
// FindLikelySupervisor will locate a most likely ui.Supervisor depending on the current Scene,
|
||||
// if it understands the Scene and knows where it keeps its Supervisor.
|
||||
func (d *Doodle) FindLikelySupervisor() (*ui.Supervisor, error) {
|
||||
switch scene := d.Scene.(type) {
|
||||
case *EditorScene:
|
||||
return scene.UI.Supervisor, nil
|
||||
case *PlayScene:
|
||||
return scene.Supervisor, nil
|
||||
case *MainScene:
|
||||
return scene.Supervisor, nil
|
||||
}
|
||||
return nil, errors.New("couldn't find a Supervisor")
|
||||
}
|
||||
|
||||
// Shell implements the developer console in-game.
|
||||
type Shell struct {
|
||||
parent *Doodle
|
||||
|
|
|
@ -152,9 +152,15 @@ func (form Form) Create(into *ui.Frame, fields []Field) {
|
|||
btn.Compute(form.Engine)
|
||||
form.Supervisor.Add(btn)
|
||||
|
||||
// Tooltip? TODO - make nicer.
|
||||
if row.Tooltip.Text != "" || row.Tooltip.TextVariable != nil {
|
||||
tt := ui.NewTooltip(btn, row.Tooltip)
|
||||
tt.Supervise(form.Supervisor)
|
||||
}
|
||||
|
||||
frame.Pack(btn, ui.Pack{
|
||||
Side: ui.W,
|
||||
PadX: 4,
|
||||
PadX: 2,
|
||||
PadY: 2,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ Package usercfg has functions around the user's Game Settings.
|
|||
|
||||
Other places in the codebase to look for its related functionality:
|
||||
|
||||
- pkg/windows/settings.go: the Settings Window is the UI owner of
|
||||
- pkg/windows/settings.go: the Settings Window is the UI owner of
|
||||
this feature, it adjusts the usercfg.Current struct and Saves the
|
||||
changes to disk.
|
||||
*/
|
||||
|
@ -45,6 +45,7 @@ type Settings struct {
|
|||
ShowHiddenDoodads bool `json:",omitempty"`
|
||||
WriteLockOverride bool `json:",omitempty"`
|
||||
JSONIndent bool `json:",omitempty"`
|
||||
EnableCheatsMenu bool `json:",omitempty"`
|
||||
|
||||
// Bookkeeping.
|
||||
UpdatedAt time.Time
|
||||
|
|
372
pkg/windows/cheats_menu.go
Normal file
372
pkg/windows/cheats_menu.go
Normal file
|
@ -0,0 +1,372 @@
|
|||
package windows
|
||||
|
||||
import (
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/balance"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
|
||||
magicform "git.kirsle.net/SketchyMaze/doodle/pkg/uix/magic-form"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/usercfg"
|
||||
"git.kirsle.net/go/render"
|
||||
"git.kirsle.net/go/ui"
|
||||
)
|
||||
|
||||
// CheatsMenu window.
|
||||
type CheatsMenu struct {
|
||||
// Settings passed in by doodle
|
||||
Supervisor *ui.Supervisor
|
||||
Engine render.Engine
|
||||
|
||||
// SceneName: the caller will provide a fresh SceneName since
|
||||
// the cheats window could span multiple scenes.
|
||||
SceneName func() string
|
||||
|
||||
// Window wants to run a developer shell command (e.g. cheat codes).
|
||||
RunCommand func(string)
|
||||
OnSetPlayerCharacter func(string)
|
||||
}
|
||||
|
||||
// MakeCheatsMenu initializes a settings window for any scene.
|
||||
// The window width/height are the actual SDL2 window dimensions.
|
||||
func MakeCheatsMenu(cfg CheatsMenu) *ui.Window {
|
||||
var (
|
||||
// Application window width/height to center our window
|
||||
// _, h = shmem.CurrentRenderEngine.WindowSize()
|
||||
)
|
||||
|
||||
win := NewCheatsWindow(cfg)
|
||||
win.Compute(cfg.Engine)
|
||||
win.Supervise(cfg.Supervisor)
|
||||
|
||||
// Center the window.
|
||||
// size := win.Size()
|
||||
win.MoveTo(render.Point{
|
||||
X: 20,
|
||||
Y: 40,
|
||||
})
|
||||
|
||||
return win
|
||||
}
|
||||
|
||||
// NewCheatsWindow initializes the window.
|
||||
func NewCheatsWindow(cfg CheatsMenu) *ui.Window {
|
||||
var (
|
||||
Width = 200
|
||||
Height = 300
|
||||
)
|
||||
|
||||
window := ui.NewWindow("Cheats Menu")
|
||||
window.SetButtons(ui.CloseButton)
|
||||
window.Configure(ui.Config{
|
||||
Width: Width,
|
||||
Height: Height,
|
||||
Background: balance.CheatsMenuBackground,
|
||||
})
|
||||
|
||||
///////////
|
||||
// Tab Bar
|
||||
tabFrame := ui.NewTabFrame("Tab Frame")
|
||||
tabFrame.SetBackground(balance.CheatsMenuBackground)
|
||||
window.Pack(tabFrame, ui.Pack{
|
||||
Side: ui.N,
|
||||
FillX: true,
|
||||
})
|
||||
|
||||
// Make the tabs
|
||||
cfg.makePlayModeTab(tabFrame, Width, Height)
|
||||
cfg.makeMiscTab(tabFrame, Width, Height)
|
||||
|
||||
tabFrame.Supervise(cfg.Supervisor)
|
||||
|
||||
return window
|
||||
}
|
||||
|
||||
// Cheats Menu "Play Mode" Tab
|
||||
func (c CheatsMenu) makePlayModeTab(tabFrame *ui.TabFrame, Width, Height int) *ui.Frame {
|
||||
tab := tabFrame.AddTab("Gameplay", ui.NewLabel(ui.Label{
|
||||
Text: "Gameplay",
|
||||
Font: balance.TabFont,
|
||||
}))
|
||||
tab.Resize(render.NewRect(Width-4, Height-tab.Size().H-46))
|
||||
|
||||
// Run a command on the developer shell.
|
||||
run := func(command string) {
|
||||
if c.RunCommand != nil {
|
||||
c.RunCommand(command)
|
||||
} else {
|
||||
shmem.FlashError("CheatsMenu: RunCommand() handler not available")
|
||||
}
|
||||
}
|
||||
|
||||
// Dummy variable for the "play as" dropdown.
|
||||
var playAs string
|
||||
|
||||
form := magicform.Form{
|
||||
Supervisor: c.Supervisor,
|
||||
Engine: c.Engine,
|
||||
Vertical: true,
|
||||
LabelWidth: 90,
|
||||
PadY: 0,
|
||||
PadX: 0,
|
||||
}
|
||||
form.Create(tab, []magicform.Field{
|
||||
{
|
||||
Label: "These cheats are available\n" +
|
||||
"only during level gameplay.",
|
||||
Font: balance.UIFont,
|
||||
},
|
||||
{
|
||||
Label: "Play as:",
|
||||
TextVariable: &playAs,
|
||||
Options: balance.CheatMenuActors,
|
||||
Font: balance.UIFont,
|
||||
OnSelect: func(v interface{}) {
|
||||
doodad := v.(string)
|
||||
if c.OnSetPlayerCharacter != nil {
|
||||
c.OnSetPlayerCharacter(doodad)
|
||||
} else {
|
||||
shmem.FlashError("OnSetPlayerCharacter(%s): handler not ready", doodad)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Buttons: []magicform.Field{
|
||||
{
|
||||
Label: "God Mode",
|
||||
Font: balance.SmallFont,
|
||||
ButtonStyle: &balance.ButtonDanger,
|
||||
Tooltip: ui.Tooltip{
|
||||
Text: "Makes you invulnerable to damage and fire.",
|
||||
},
|
||||
OnClick: func() {
|
||||
run(balance.CheatGodMode)
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Show hidden actors",
|
||||
Font: balance.SmallFont,
|
||||
OnClick: func() {
|
||||
run(balance.CheatShowAllActors)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Inventory",
|
||||
Font: balance.LabelFont,
|
||||
},
|
||||
{
|
||||
Buttons: []magicform.Field{
|
||||
{
|
||||
Label: "Give Keys",
|
||||
Font: balance.SmallFont,
|
||||
Tooltip: ui.Tooltip{
|
||||
Text: "Get all four colored keys and\n99x small keys",
|
||||
},
|
||||
OnClick: func() {
|
||||
run(balance.CheatGiveKeys)
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Give Gems",
|
||||
Font: balance.SmallFont,
|
||||
Tooltip: ui.Tooltip{
|
||||
Text: "Get 1x of each of the four Gemstones.",
|
||||
},
|
||||
OnClick: func() {
|
||||
run(balance.CheatGiveGems)
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Drop All",
|
||||
Font: balance.SmallFont,
|
||||
ButtonStyle: &balance.ButtonDanger,
|
||||
Tooltip: ui.Tooltip{
|
||||
Text: "Remove ALL items from your inventory.",
|
||||
},
|
||||
OnClick: func() {
|
||||
run(balance.CheatDropItems)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Physics",
|
||||
Font: balance.LabelFont,
|
||||
},
|
||||
{
|
||||
Buttons: []magicform.Field{
|
||||
{
|
||||
Label: "Antigravity",
|
||||
Font: balance.SmallFont,
|
||||
Tooltip: ui.Tooltip{
|
||||
Text: "Allows free movement in four directions",
|
||||
},
|
||||
OnClick: func() {
|
||||
run(balance.CheatAntigravity)
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "NoClip",
|
||||
Font: balance.SmallFont,
|
||||
Tooltip: ui.Tooltip{
|
||||
Text: "Toggle physical collision\n" +
|
||||
"checks with level and actors.",
|
||||
},
|
||||
OnClick: func() {
|
||||
run(balance.CheatNoclip)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Buttons: []magicform.Field{
|
||||
{
|
||||
Label: "Skip this level",
|
||||
Font: balance.SmallFont,
|
||||
ButtonStyle: &balance.ButtonDanger,
|
||||
Tooltip: ui.Tooltip{
|
||||
Text: "Consider the current level a win.",
|
||||
},
|
||||
OnClick: func() {
|
||||
run(balance.CheatSkipLevel)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return tab
|
||||
}
|
||||
|
||||
// Cheats Menu "Misc" Tab
|
||||
func (c CheatsMenu) makeMiscTab(tabFrame *ui.TabFrame, Width, Height int) *ui.Frame {
|
||||
tab := tabFrame.AddTab("Misc", ui.NewLabel(ui.Label{
|
||||
Text: "Misc",
|
||||
Font: balance.TabFont,
|
||||
}))
|
||||
tab.Resize(render.NewRect(Width-4, Height-tab.Size().H-46))
|
||||
|
||||
// Run a command on the developer shell.
|
||||
run := func(command string) {
|
||||
if c.RunCommand != nil {
|
||||
c.RunCommand(command)
|
||||
} else {
|
||||
shmem.FlashError("CheatsMenu: RunCommand() handler not available")
|
||||
}
|
||||
}
|
||||
|
||||
form := magicform.Form{
|
||||
Supervisor: c.Supervisor,
|
||||
Engine: c.Engine,
|
||||
Vertical: true,
|
||||
LabelWidth: 90,
|
||||
PadY: 0,
|
||||
PadX: 0,
|
||||
}
|
||||
form.Create(tab, []magicform.Field{
|
||||
{
|
||||
Label: "Enable cheats menu",
|
||||
BoolVariable: &usercfg.Current.EnableCheatsMenu,
|
||||
Tooltip: ui.Tooltip{
|
||||
Text: "Enables a Help->Cheats Menu during gameplay.",
|
||||
},
|
||||
OnClick: func() {
|
||||
saveGameSettings()
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Level Editor",
|
||||
Font: balance.LabelFont,
|
||||
},
|
||||
{
|
||||
Buttons: []magicform.Field{
|
||||
{
|
||||
Label: "Show hidden doodads",
|
||||
Font: balance.SmallFont,
|
||||
Tooltip: ui.Tooltip{
|
||||
Text: "Enable hidden built-in doodads (such as Boy)\n" +
|
||||
"to be used in the Level Editor.",
|
||||
Edge: ui.Bottom,
|
||||
},
|
||||
OnClick: func() {
|
||||
// Like `boolProp show-hidden-doodads true`
|
||||
var bp = "show-hidden-doodads"
|
||||
if v, err := balance.GetBoolProp(bp); err == nil {
|
||||
v = !v
|
||||
balance.BoolProp(bp, v)
|
||||
if v {
|
||||
shmem.Flash("Hidden doodads will appear when you next reload the level editor.")
|
||||
} else {
|
||||
shmem.Flash("Hidden doodads are again hidden from the level editor.")
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Testing",
|
||||
Font: balance.LabelFont,
|
||||
},
|
||||
{
|
||||
Buttons: []magicform.Field{
|
||||
{
|
||||
Label: "Load Screen",
|
||||
Font: balance.SmallFont,
|
||||
OnClick: func() {
|
||||
run(balance.CheatDebugLoadScreen)
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Wait Screen",
|
||||
Font: balance.SmallFont,
|
||||
OnClick: func() {
|
||||
run(balance.CheatDebugWaitScreen)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Level Progression",
|
||||
Font: balance.LabelFont,
|
||||
},
|
||||
{
|
||||
Buttons: []magicform.Field{
|
||||
{
|
||||
Label: "Unlock all levels",
|
||||
Font: balance.SmallFont,
|
||||
Tooltip: ui.Tooltip{
|
||||
Text: "For this play session, any level may be opened\n" +
|
||||
"from Story Mode regardless of the padlock icon.",
|
||||
},
|
||||
OnClick: func() {
|
||||
run(balance.CheatUnlockLevels)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Debugging",
|
||||
Font: balance.LabelFont,
|
||||
},
|
||||
{
|
||||
Buttons: []magicform.Field{
|
||||
{
|
||||
Label: "Debug overlay",
|
||||
Font: balance.SmallFont,
|
||||
OnClick: func() {
|
||||
run("boolprop DO flip")
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: "Show hitboxes",
|
||||
Font: balance.SmallFont,
|
||||
OnClick: func() {
|
||||
run("boolprop DC flip")
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return tab
|
||||
}
|
|
@ -7,6 +7,7 @@ import (
|
|||
"git.kirsle.net/SketchyMaze/doodle/pkg/gamepad"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/native"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
|
||||
magicform "git.kirsle.net/SketchyMaze/doodle/pkg/uix/magic-form"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/usercfg"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/userdir"
|
||||
|
@ -35,6 +36,10 @@ type Settings struct {
|
|||
SceneName string // name of scene which called this window
|
||||
ActiveTab string // specify the tab to open
|
||||
OnApply func()
|
||||
OnOpenCheatsWindow func() *ui.Window // user opens the Cheats Menu
|
||||
|
||||
// The Settings window owns the Cheats window to ensure only one opens at a time.
|
||||
cheatsWindow *ui.Window
|
||||
}
|
||||
|
||||
// MakeSettingsWindow initializes a settings window for any scene.
|
||||
|
@ -452,6 +457,42 @@ func (c Settings) makeExperimentalTab(tabFrame *ui.TabFrame, Width, Height int)
|
|||
Label: "Restart the game for changes to take effect.",
|
||||
Font: balance.UIFont,
|
||||
},
|
||||
{
|
||||
Label: "Cheat Codes",
|
||||
Font: balance.LabelFont,
|
||||
},
|
||||
{
|
||||
Label: "The ` (or ~) key will open a developer console into which you\n" +
|
||||
"can enter cheat codes (see your guidebook). For touch-only\n" +
|
||||
"devices, most of the useful cheats may be toggled via the\n" +
|
||||
"Cheats Menu which you can launch by clicking below:",
|
||||
Font: balance.UIFont,
|
||||
},
|
||||
{
|
||||
Buttons: []magicform.Field{
|
||||
{
|
||||
ButtonStyle: &balance.ButtonPrimary,
|
||||
Label: "Open Cheats Window",
|
||||
Font: balance.UIFont.Update(render.Text{
|
||||
PadY: 0,
|
||||
}),
|
||||
OnClick: func() {
|
||||
if c.OnOpenCheatsWindow != nil {
|
||||
if c.cheatsWindow != nil {
|
||||
c.cheatsWindow.Hide()
|
||||
c.cheatsWindow.Destroy()
|
||||
c.cheatsWindow = nil
|
||||
}
|
||||
|
||||
c.cheatsWindow = c.OnOpenCheatsWindow()
|
||||
c.cheatsWindow.Show()
|
||||
} else {
|
||||
shmem.FlashError("OnOpenCheatsWindow not handled")
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return tab
|
||||
|
|
Loading…
Reference in New Issue
Block a user