doodle/pkg/cheats.go

290 lines
8.4 KiB
Go
Raw Permalink Normal View History

package doodle
import (
"strings"
"time"
2022-09-24 22:17:25 +00:00
"git.kirsle.net/SketchyMaze/doodle/pkg/balance"
"git.kirsle.net/SketchyMaze/doodle/pkg/modal"
2022-09-24 22:17:25 +00:00
"git.kirsle.net/SketchyMaze/doodle/pkg/modal/loadscreen"
"git.kirsle.net/SketchyMaze/doodle/pkg/scripting"
"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
"git.kirsle.net/SketchyMaze/doodle/pkg/windows"
"git.kirsle.net/go/ui"
"github.com/dop251/goja"
)
// 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) {
// If we are in Play Mode, every command out of here is cheating.
if playScene, ok := d.Scene.(*PlayScene); ok {
playScene.SetCheated()
}
d.shell.Execute(command)
},
OnSetPlayerCharacter: func(doodad string) {
if scene, ok := d.Scene.(*PlayScene); ok {
scene.SetCheated()
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
// dummy default doodad sprite (a red "X").
func (d *Doodle) SetPlayerCharacter(filename string) {
balance.PlayerCharacterDoodad = filename
if playScene, isPlay := d.Scene.(*PlayScene); isPlay {
playScene.SetPlayerCharacter(balance.PlayerCharacterDoodad)
}
}
// cheatCommand is a subroutine of the Command.Run() method of the Doodle
// developer shell (commands.go). It looks for special cheat codes entered
// into the command shell and executes them.
//
// Returns true if a cheat was intercepted, false if the command is not a cheat.
func (c Command) cheatCommand(d *Doodle) bool {
// Some cheats only work in Play Mode.
playScene, isPlay := d.Scene.(*PlayScene)
Optimize memory by freeing up SDL2 textures * Added to the F3 Debug Overlay is a "Texture:" label that counts the number of textures currently loaded by the (SDL2) render engine. * Added Teardown() functions to Level, Doodad and the Chunker they both use to free up SDL2 textures for all their cached graphics. * The Canvas.Destroy() function now cleans up all textures that the Canvas is responsible for: calling the Teardown() of the Level or Doodad, calling Destroy() on all level actors, and cleaning up Wallpaper textures. * The Destroy() method of the game's various Scenes will properly Destroy() their canvases to clean up when transitioning to another scene. The MainScene, MenuScene, EditorScene and PlayScene. * Fix the sprites package to actually cache the ui.Image widgets. The game has very few sprites so no need to free them just yet. Some tricky places that were leaking textures have been cleaned up: * Canvas.InstallActors() destroys the canvases of existing actors before it reinitializes the list and installs the replacements. * The DraggableActor when the user is dragging an actor around their level cleans up the blueprint masked drag/drop actor before nulling it out. Misc changes: * The player character cheats during Play Mode will immediately swap out the player character on the current level. * Properly call the Close() function instead of Hide() to dismiss popup windows. The Close() function itself calls Hide() but also triggers WindowClose event handlers. The Doodad Dropper subscribes to its close event to free textures for all its doodad canvases.
2022-04-09 21:41:24 +00:00
// If a character cheat is used during Play Mode, replace the player NOW.
var setPlayerCharacter bool
// Cheat codes
switch c.Raw {
case balance.CheatUncapFPS:
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
case balance.CheatEditDuringPlay:
if isPlay {
playScene.drawing.Editable = true
2022-01-03 00:28:43 +00:00
playScene.SetCheated()
d.Flash("Level canvas is now editable. Don't edit and drive!")
} else {
d.FlashError("Use this cheat in Play Mode to make the level canvas editable.")
}
case balance.CheatScrollDuringPlay:
if isPlay {
playScene.drawing.Scrollable = true
2022-01-03 00:28:43 +00:00
playScene.SetCheated()
d.Flash("Level canvas is now scrollable with the arrow keys.")
} else {
d.FlashError("Use this cheat in Play Mode to make the level scrollable.")
}
case balance.CheatAntigravity:
if isPlay {
2022-01-03 00:28:43 +00:00
playScene.SetCheated()
playScene.antigravity = !playScene.antigravity
playScene.Player.SetGravity(!playScene.antigravity)
if playScene.antigravity {
d.Flash("Gravity disabled for player character.")
} else {
d.Flash("Gravity restored for player character.")
}
} else {
d.FlashError("Use this cheat in Play Mode to disable gravity for the player character.")
}
case balance.CheatNoclip:
if isPlay {
2022-01-03 00:28:43 +00:00
playScene.SetCheated()
playScene.noclip = !playScene.noclip
playScene.Player.SetNoclip(playScene.noclip)
playScene.antigravity = playScene.noclip
playScene.Player.SetGravity(!playScene.antigravity)
if playScene.noclip {
d.Flash("Clipping disabled for player character.")
} else {
d.Flash("Clipping and gravity restored for player character.")
}
} else {
d.FlashError("Use this cheat in Play Mode to disable clipping for the player character.")
}
case balance.CheatShowAllActors:
if isPlay {
2022-01-03 00:28:43 +00:00
playScene.SetCheated()
for _, actor := range playScene.drawing.Actors() {
actor.Show()
}
d.Flash("All invisible actors made visible.")
} else {
d.FlashError("Use this cheat in Play Mode to show hidden actors, such as technical doodads.")
}
case balance.CheatGiveKeys:
if isPlay {
2022-01-03 00:28:43 +00:00
playScene.SetCheated()
playScene.Player.AddItem("key-red.doodad", 0)
playScene.Player.AddItem("key-blue.doodad", 0)
playScene.Player.AddItem("key-green.doodad", 0)
playScene.Player.AddItem("key-yellow.doodad", 0)
playScene.Player.AddItem("small-key.doodad", 99)
d.Flash("Given all keys to the player character.")
} else {
d.FlashError("Use this cheat in Play Mode to get all colored keys.")
}
case balance.CheatGiveGems:
if isPlay {
playScene.SetCheated()
playScene.Player.AddItem("gem-red.doodad", 1)
playScene.Player.AddItem("gem-green.doodad", 1)
playScene.Player.AddItem("gem-blue.doodad", 1)
playScene.Player.AddItem("gem-yellow.doodad", 1)
d.Flash("Given all gemstones to the player character.")
} else {
d.FlashError("Use this cheat in Play Mode to get all gemstones.")
}
case balance.CheatDropItems:
if isPlay {
2022-01-03 00:28:43 +00:00
playScene.SetCheated()
playScene.Player.ClearInventory()
d.Flash("Cleared inventory of player character.")
} else {
d.FlashError("Use this cheat in Play Mode to clear your inventory.")
}
case balance.CheatGodMode:
if isPlay {
d.Flash("God mode toggled")
playScene.SetCheated()
playScene.godMode = !playScene.godMode
if playScene.godMode {
d.FlashError("God mode enabled.")
} else {
d.Flash("God mode disabled.")
}
} else {
d.FlashError("Use this cheat in Play Mode to toggle invincibility.")
}
case balance.CheatFreeEnergy:
if isPlay {
playScene.SetCheated()
d.Flash("Power toggle sent to all actors in the level.")
for _, a := range playScene.Canvas().Actors() {
// Hacky stuff here - just a fun cheat code anyway.
vm := playScene.ScriptSupervisor().To(a.ID())
value := vm.Get("__tesla")
if value == nil || !value.ToBoolean() {
vm.Set("__tesla", true)
value = vm.Get("__tesla")
} else if value.ToBoolean() {
vm.Set("__tesla", false)
value = vm.Get("__tesla")
}
vm.Inbound <- scripting.Message{
Name: "power",
SenderID: a.ID(),
Args: []goja.Value{value},
}
}
} else {
d.FlashError("Use this cheat in Play Mode to send power to all actors (chaotic!).")
}
case balance.CheatDebugLoadScreen:
loadscreen.ShowWithProgress()
loadscreen.SetSubtitle("Loading: /dev/null", "Loadscreen testing.")
go func() {
var i float64
for i = 0; i < 100; i++ {
time.Sleep(100 * time.Millisecond)
loadscreen.SetProgress(i / 100)
}
loadscreen.Hide()
}()
case balance.CheatDebugWaitScreen:
m := modal.Wait("Crunching some numbers...").WithTitle("Please hold").Then(func() {
d.Flash("Wait modal dismissed.")
})
go func() {
time.Sleep(10 * time.Second)
m.Dismiss(true)
}()
case balance.CheatUnlockLevels:
balance.CheatEnabledUnlockLevels = !balance.CheatEnabledUnlockLevels
if balance.CheatEnabledUnlockLevels {
d.Flash("All locked Story Mode levels can now be played.")
} else {
d.Flash("All locked Story Mode levels are again locked.")
}
case balance.CheatSkipLevel:
if isPlay {
playScene.SetCheated()
playScene.ShowEndLevelModal(
true,
"Level Completed",
"Great job, you cheated and 'won' the level!",
)
} else {
d.Flash("Use this cheat in Play Mode to instantly win the level.")
}
default:
// See if it was an endorsed actor cheat.
if filename, ok := balance.CheatActors[strings.ToLower(c.Raw)]; ok {
d.Flash("Set default player character to %s.", filename)
balance.PlayerCharacterDoodad = filename
setPlayerCharacter = true
} else {
// Not a cheat code.
return false
}
}
Optimize memory by freeing up SDL2 textures * Added to the F3 Debug Overlay is a "Texture:" label that counts the number of textures currently loaded by the (SDL2) render engine. * Added Teardown() functions to Level, Doodad and the Chunker they both use to free up SDL2 textures for all their cached graphics. * The Canvas.Destroy() function now cleans up all textures that the Canvas is responsible for: calling the Teardown() of the Level or Doodad, calling Destroy() on all level actors, and cleaning up Wallpaper textures. * The Destroy() method of the game's various Scenes will properly Destroy() their canvases to clean up when transitioning to another scene. The MainScene, MenuScene, EditorScene and PlayScene. * Fix the sprites package to actually cache the ui.Image widgets. The game has very few sprites so no need to free them just yet. Some tricky places that were leaking textures have been cleaned up: * Canvas.InstallActors() destroys the canvases of existing actors before it reinitializes the list and installs the replacements. * The DraggableActor when the user is dragging an actor around their level cleans up the blueprint masked drag/drop actor before nulling it out. Misc changes: * The player character cheats during Play Mode will immediately swap out the player character on the current level. * Properly call the Close() function instead of Hide() to dismiss popup windows. The Close() function itself calls Hide() but also triggers WindowClose event handlers. The Doodad Dropper subscribes to its close event to free textures for all its doodad canvases.
2022-04-09 21:41:24 +00:00
// If we're setting the player character and in Play Mode, do it.
if setPlayerCharacter && isPlay {
playScene.SetCheated()
Optimize memory by freeing up SDL2 textures * Added to the F3 Debug Overlay is a "Texture:" label that counts the number of textures currently loaded by the (SDL2) render engine. * Added Teardown() functions to Level, Doodad and the Chunker they both use to free up SDL2 textures for all their cached graphics. * The Canvas.Destroy() function now cleans up all textures that the Canvas is responsible for: calling the Teardown() of the Level or Doodad, calling Destroy() on all level actors, and cleaning up Wallpaper textures. * The Destroy() method of the game's various Scenes will properly Destroy() their canvases to clean up when transitioning to another scene. The MainScene, MenuScene, EditorScene and PlayScene. * Fix the sprites package to actually cache the ui.Image widgets. The game has very few sprites so no need to free them just yet. Some tricky places that were leaking textures have been cleaned up: * Canvas.InstallActors() destroys the canvases of existing actors before it reinitializes the list and installs the replacements. * The DraggableActor when the user is dragging an actor around their level cleans up the blueprint masked drag/drop actor before nulling it out. Misc changes: * The player character cheats during Play Mode will immediately swap out the player character on the current level. * Properly call the Close() function instead of Hide() to dismiss popup windows. The Close() function itself calls Hide() but also triggers WindowClose event handlers. The Doodad Dropper subscribes to its close event to free textures for all its doodad canvases.
2022-04-09 21:41:24 +00:00
playScene.SetPlayerCharacter(balance.PlayerCharacterDoodad)
}
return true
}