Noah Petherbridge
a10a09a818
* 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`)
373 lines
8.1 KiB
Go
373 lines
8.1 KiB
Go
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
|
|
}
|