Spit and polish

* New doodad: Invisible Warp Door
* All warp doors require the player to be grounded (if affected by
  gravity) to open them. No jumping or falling thru and opening
  a warp door mid-air!
* Title Screen now randomly selects from a couple of levels.
* Title Screen: if it fails to load a level it sets up a basic
  blank level with a wallpaper instead.
* New developer shell command: titlescreen <level>
  Opens the MainScene with a custom user level as the background.
* Add Auto-save to the Editor to save your drawing every 5 minutes
* Add a MenuBar to the Play Scene for easier navigation to other
  features of the game.
* Doodad JS API: time.Since() now available.
This commit is contained in:
Noah 2022-01-02 22:36:32 -08:00
parent 672ee9641a
commit 9a51ac39f9
20 changed files with 408 additions and 87 deletions

View File

@ -1,5 +1,64 @@
# Changes
## v0.11.0 (TBD)
New features:
* **High scores and level progression:** when playing levels out of
a Level Pack, the game will save your progress and high scores on
each level you play. See details on how scoring works so far, below.
* **Auto-save** for the Editor. Automatically saves your drawing every
5 minutes. Look for e.g. the _autosave.level to recover your drawing
if the game crashed or exited wrongly!
* **Color picker UI:** when asked to choose a color (e.g. for your level
palette) a UI window makes picking a color easy! You can still manually
enter a hexadecimal color value but this is no longer required!
Scoring system:
* The high score on a level is based on how quickly you complete it.
A timer is shown in-game and there are two possible high scores
for each level in a pack:
* Perfect Time (gold): if you complete the level without dying and
restarting at a checkpoint.
* Best Time (silver): if you had used a checkpoint.
* The gold/silver icon is displayed next to the timer in-game; it
starts gold and drops to silver if you die and restart from checkpoint.
It gives you a preview of which high score you'll be competing with.
* If cheat codes are used, the user is not eligible for a high score
but may still mark the level "completed."
* Level Packs may have some of their later levels locked by default,
with only one or a few available immediately. Completing a level will
unlock the next level until they have all been unlocked.
New and changed doodads:
* **Invisible Warp Door:** a technical doodad to create an invisible
Warp Door (press Space/'Use' key to activate).
* All **Warp Doors** now require the player to be grounded before they
can be opened, or else under the effects of antigravity. You shouldn't
be able to open Warp Doors while falling or jumping off the ground
at them.
Revised levels:
* Desert-2of2.level uses a new work-around for the unfortunate glitch
of sometimes getting stuck on two boxes, instead of a cheat code
being necessary to resolve.
* Revised difficulty on Tutorial 2 and Tutorial 3.
Miscellaneous changes:
* Title Screen: picks a random level from a few options, in the future
it will pick random user levels too.
* Play Mode gets a menu bar like the Editor for easier navigation to
other game features.
* New dev shell command: `titlescreen <level name>` to load the Title
Screen with the named level as its background, can be used to load
user levels _now_.
* For the doodads JavaScript API: `time.Since()` is now available (from
the Go standard library)
## v0.10.0 (Dec 30 2021)
New features and changes:

View File

@ -23,6 +23,11 @@ build:
doodad convert -t "Power Source" power-64.png power-source.doodad
doodad install-script power.js power-source.doodad
# Warp Door
doodad convert -t "Invisible Warp Door" warp-door-64.png reg-warp-door.doodad
doodad edit-doodad --tag "color=invisible" reg-warp-door.doodad
doodad install-script ../warp-door/warp-door.js reg-warp-door.doodad
for i in *.doodad; do\
doodad edit-doodad --tag "category=technical" $${i};\
done

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

View File

@ -17,7 +17,7 @@ build:
doodad install-script warp-door.js warp-door-orange.doodad
for i in *.doodad; do\
doodad edit-doodad --tag "category=doors" $${i};\
doodad edit-doodad --tag "category=doors" --hitbox=34,76 $${i};\
done
for i in warp-door-*.doodad; do\
doodad edit-doodad --tag "category=doors,gizmos" $${i};\

View File

@ -1,7 +1,5 @@
// Warp Doors
function main() {
Self.SetHitbox(0, 0, 34, 76);
// Are we a blue or orange door? Regular warp door will be 'none'
var color = Self.GetTag("color");
var isStateDoor = color === 'blue' || color === 'orange';
@ -23,6 +21,11 @@ function main() {
Self.AddAnimation("close", animSpeed, ["orange-4", "orange-3", "orange-2", "orange-1"]);
spriteDefault = "orange-1";
spriteDisabled = "orange-off";
} else if (color === 'invisible') {
// Invisible Warp Door region.
Self.Hide();
Self.AddAnimation("open", animSpeed, [0, 0]);
Self.AddAnimation("close", animSpeed, [0, 0]);
} else {
Self.AddAnimation("open", animSpeed, ["door-2", "door-3", "door-4"]);
Self.AddAnimation("close", animSpeed, ["door-4", "door-3", "door-2", "door-1"]);
@ -48,6 +51,10 @@ function main() {
});
}
// For player groundedness work-around
var playerLastY = []; // last sampling of Y values
var lastUsed = time.Now();
// The player Uses the door.
var flashedCooldown = false; // "Locked Door" flashed message.
Events.OnUse(function(e) {
@ -74,6 +81,40 @@ function main() {
return;
}
// The player must be grounded or have no gravity to open the door.
if (!e.Actor.Grounded() && e.Actor.HasGravity()) {
// Work-around: if two Boxes are stacked atop each other the player can
// get stuck if he jumps on top. He may not be Grounded but isn't changing
// effective Y position and a warp door may work as a good way out.
var yValue = e.Actor.Position().Y;
// Collect a sampling of last few Y values. If the player Y position
// is constant the last handful of frames, treat them as if they're
// grounded (or else they can't activate the warp door).
playerLastY.unshift(yValue);
if (playerLastY.length < 6) {
return;
}
// We have enough history.
playerLastY.pop();
// Hasn't moved?
var isGrounded = true;
for (var i = 0; i < playerLastY.length; i++) {
if (yValue !== playerLastY[i]) {
isGrounded = false;
break;
}
}
if (!isGrounded) {
return;
}
// Player was effectively grounded! No change in Y position.
}
// Freeze the player.
e.Actor.Freeze()

View File

@ -59,11 +59,18 @@ var (
DefaultEraserBrushSize = 8
MaxEraserBrushSize = 32 // the bigger, the slower
// Interval for auto-save in the editor
AutoSaveInterval = 5 * time.Minute
// Default player character doodad in Play Mode.
PlayerCharacterDoodad = "boy.doodad"
// Level name for the title screen.
DemoLevelName = "Tutorial 3.level"
// Level names for the title screen.
DemoLevelName = []string{
"Tutorial 1.level",
"Tutorial 2.level",
"Tutorial 3.level",
}
// Level attachment filename for the custom wallpaper.
// NOTE: due to hard-coded "assets/wallpapers/" prefix in uix/canvas.go#LoadLevel.

View File

@ -60,6 +60,8 @@ func (c Command) Run(d *Doodle) error {
return c.Play(d)
case "close":
return c.Close(d)
case "titlescreen":
return c.TitleScreen(d)
case "exit":
case "quit":
return c.Quit()
@ -192,6 +194,9 @@ func (c Command) Help(d *Doodle) error {
d.Flash("Enter a JavaScript shell on the in-game interpreter")
case "boolprop":
d.Flash("Toggle boolean values. `boolProp list` lists available")
case "titlescreen":
d.Flash("Usage: titlescreen <filename.level>")
d.Flash("Open the title screen with a level")
case "help":
d.Flash("Usage: help <command>")
d.Flash("Gets further help on a command")
@ -252,6 +257,20 @@ func (c Command) Play(d *Doodle) error {
return nil
}
// TitleScreen loads the title with a custom user level.
func (c Command) TitleScreen(d *Doodle) error {
if len(c.Args) == 0 {
return errors.New("Usage: titlescreen <level name.level>")
}
filename := c.Args[0]
d.shell.Write("Playing level: " + filename)
d.Goto(&MainScene{
LevelFilename: filename,
})
return nil
}
// Quit the command line shell.
func (c Command) Quit() error {
return nil

44
pkg/common_menubar.go Normal file
View File

@ -0,0 +1,44 @@
package doodle
import (
"git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/apps/doodle/pkg/branding"
"git.kirsle.net/apps/doodle/pkg/native"
"git.kirsle.net/apps/doodle/pkg/windows"
"git.kirsle.net/go/render"
"git.kirsle.net/go/ui"
)
// Common menubars between Play and Edit.
// MakeHelpMenu creates the "Help" menu with its common items
// across any scene.
func (d *Doodle) MakeHelpMenu(menu *ui.MenuBar, supervisor *ui.Supervisor) *ui.MenuButton {
helpMenu := menu.AddMenu("Help")
helpMenu.AddItemAccel("User Manual", "F1", func() {
native.OpenLocalURL(balance.GuidebookPath)
})
helpMenu.AddItem("About", func() {
aboutWindow := windows.NewAboutWindow(windows.About{
Supervisor: supervisor,
Engine: d.Engine,
})
aboutWindow.Compute(d.Engine)
aboutWindow.Supervise(supervisor)
// Center the window.
aboutWindow.MoveTo(render.Point{
X: (d.width / 2) - (aboutWindow.Size().W / 2),
Y: 60,
})
aboutWindow.Show()
})
helpMenu.AddSeparator()
helpMenu.AddItem("Go to Website", func() {
native.OpenURL(branding.Website)
})
helpMenu.AddItem("Guidebook Online", func() {
native.OpenURL(branding.GuidebookURL)
})
return helpMenu
}

View File

@ -245,6 +245,7 @@ func (d *Doodle) MakeSettingsWindow(supervisor *ui.Supervisor) *ui.Window {
CrosshairSize: &usercfg.Current.CrosshairSize,
CrosshairColor: &usercfg.Current.CrosshairColor,
HideTouchHints: &usercfg.Current.HideTouchHints,
DisableAutosave: &usercfg.Current.DisableAutosave,
}
return windows.MakeSettingsWindow(d.width, d.height, cfg)
}

View File

@ -5,7 +5,9 @@ import (
"fmt"
"os"
"strings"
"time"
"git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/apps/doodle/pkg/doodads"
"git.kirsle.net/apps/doodle/pkg/drawtool"
"git.kirsle.net/apps/doodle/pkg/enum"
@ -47,6 +49,8 @@ type EditorScene struct {
// Last saved filename by the user.
filename string
lastAutosaveAt time.Time
}
// Name of the scene.
@ -66,6 +70,9 @@ func (s *EditorScene) Setup(d *Doodle) error {
{"Swatch:", s.debSwatch},
}
// Initialize autosave time.
s.lastAutosaveAt = time.Now()
// Show the loading screen.
loadscreen.ShowWithProgress()
go func() {
@ -424,6 +431,16 @@ func (s *EditorScene) Loop(d *Doodle, ev *event.State) error {
s.UI.Loop(ev)
// Trigger auto-save of the level in case of crash or accidental closure.
if time.Since(s.lastAutosaveAt) > balance.AutoSaveInterval {
s.lastAutosaveAt = time.Now()
if !usercfg.Current.DisableAutosave {
if err := s.AutoSave(); err != nil {
d.FlashError("Autosave error: %s", err)
}
}
}
return nil
}
@ -471,7 +488,6 @@ func (s *EditorScene) LoadLevel(filename string) error {
}
// SaveLevel saves the level to disk.
// TODO: move this into the Canvas?
func (s *EditorScene) SaveLevel(filename string) error {
if s.DrawingType != enum.LevelDrawing {
return errors.New("SaveLevel: current drawing is not a Level type")
@ -500,6 +516,24 @@ func (s *EditorScene) SaveLevel(filename string) error {
return m.WriteFile(filename)
}
// AutoSave takes an autosave snapshot of the level or drawing.
func (s *EditorScene) AutoSave() error {
var filename = "_autosave.level"
switch s.DrawingType {
case enum.LevelDrawing:
s.d.Flash("Automatically saved level to %s", filename)
return s.Level.WriteFile(filename)
case enum.DoodadDrawing:
filename = "_autosave.doodad"
s.d.Flash("Automatically saved doodad to %s", filename)
return s.Doodad.WriteFile(filename)
}
return nil
}
// LoadDoodad loads a doodad from disk.
func (s *EditorScene) LoadDoodad(filename string) error {
s.filename = filename

View File

@ -6,12 +6,13 @@ package doodle
import (
"git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/apps/doodle/pkg/branding"
"git.kirsle.net/apps/doodle/pkg/drawtool"
"git.kirsle.net/apps/doodle/pkg/enum"
"git.kirsle.net/apps/doodle/pkg/level/giant_screenshot"
"git.kirsle.net/apps/doodle/pkg/license"
"git.kirsle.net/apps/doodle/pkg/log"
"git.kirsle.net/apps/doodle/pkg/native"
"git.kirsle.net/apps/doodle/pkg/usercfg"
"git.kirsle.net/apps/doodle/pkg/userdir"
"git.kirsle.net/apps/doodle/pkg/windows"
"git.kirsle.net/go/render"
@ -143,20 +144,22 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
native.OpenLocalURL(userdir.ScreenshotDirectory)
})
levelMenu.AddSeparator()
levelMenu.AddItemAccel("New viewport", "v", func() {
pip := windows.MakePiPWindow(d.width, d.height, windows.PiP{
Supervisor: u.Supervisor,
Engine: u.d.Engine,
Level: u.Scene.Level,
Event: u.d.event,
if usercfg.Current.EnableFeatures {
levelMenu.AddSeparator()
levelMenu.AddItemAccel("New viewport", "v", func() {
pip := windows.MakePiPWindow(d.width, d.height, windows.PiP{
Supervisor: u.Supervisor,
Engine: u.d.Engine,
Level: u.Scene.Level,
Event: u.d.event,
Tool: &u.Scene.UI.Canvas.Tool,
BrushSize: &u.Scene.UI.Canvas.BrushSize,
Tool: &u.Scene.UI.Canvas.Tool,
BrushSize: &u.Scene.UI.Canvas.BrushSize,
})
pip.Show()
})
pip.Show()
})
}
}
////////
@ -261,36 +264,16 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
////////
// Help menu
helpMenu := menu.AddMenu("Help")
helpMenu.AddItemAccel("User Manual", "F1", func() {
native.OpenLocalURL(balance.GuidebookPath)
})
helpMenu.AddItem("Register", func() {
u.licenseWindow.Show()
})
helpMenu.AddItem("About", func() {
if u.aboutWindow == nil {
u.aboutWindow = windows.NewAboutWindow(windows.About{
Supervisor: u.Supervisor,
Engine: d.Engine,
})
u.aboutWindow.Compute(d.Engine)
u.aboutWindow.Supervise(u.Supervisor)
// Center the window.
u.aboutWindow.MoveTo(render.Point{
X: (d.width / 2) - (u.aboutWindow.Size().W / 2),
Y: 60,
})
}
u.aboutWindow.Show()
})
var (
helpMenu = u.d.MakeHelpMenu(menu, u.Supervisor)
registerText = "Register"
)
helpMenu.AddSeparator()
helpMenu.AddItem("Go to Website", func() {
native.OpenURL(branding.Website)
})
helpMenu.AddItem("Guidebook Online", func() {
native.OpenURL(branding.GuidebookURL)
if license.IsRegistered() {
registerText = "Registration"
}
helpMenu.AddItem(registerText, func() {
u.licenseWindow.Show()
})
menu.Supervise(u.Supervisor)

View File

@ -2,6 +2,7 @@ package doodle
import (
"fmt"
"math/rand"
"git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/apps/doodle/pkg/branding"
@ -24,7 +25,8 @@ import (
// MainScene implements the main menu of Doodle.
type MainScene struct {
Supervisor *ui.Supervisor
Supervisor *ui.Supervisor
LevelFilename string // custom level filename to load in background
// Background wallpaper canvas.
scripting *scripting.Supervisor
@ -296,8 +298,16 @@ func (s *MainScene) SetupDemoLevel(d *Doodle) error {
s.scripting = scripting.NewSupervisor()
s.canvas.SetScriptSupervisor(s.scripting)
// Title screen level to load.
if lvl, err := level.LoadFile(balance.DemoLevelName); err == nil {
// Title screen level to load. Pick a random level.
levelName := balance.DemoLevelName[0]
if s.LevelFilename != "" {
levelName = s.LevelFilename
} else if len(balance.DemoLevelName) > 1 {
randIndex := rand.Intn(len(balance.DemoLevelName))
levelName = balance.DemoLevelName[randIndex]
}
if lvl, err := level.LoadFile(levelName); err == nil {
s.canvas.LoadLevel(lvl)
s.canvas.InstallActors(lvl.Actors)
@ -312,6 +322,16 @@ func (s *MainScene) SetupDemoLevel(d *Doodle) error {
}
} else {
log.Error("Error loading demo level %s: %s", balance.DemoLevelName, err)
// Create a basic notebook level.
s.canvas.LoadLevel(&level.Level{
Chunker: level.NewChunker(100),
Palette: level.NewPalette(),
PageType: level.Bounded,
MaxWidth: 42,
MaxHeight: 42,
Wallpaper: "notebook.png",
})
}
return nil

View File

@ -50,9 +50,11 @@ type PlayScene struct {
cheated bool // user has entered a cheat code while playing
// UI widgets.
supervisor *ui.Supervisor
screen *ui.Frame // A window sized invisible frame to position UI elements.
editButton *ui.Button
supervisor *ui.Supervisor
screen *ui.Frame // A window sized invisible frame to position UI elements.
menubar *ui.MenuBar
editButton *ui.Button
winLevelPacks *ui.Window
// Custom debug labels.
debPosition *string
@ -119,6 +121,13 @@ func (s *PlayScene) setupAsync(d *Doodle) error {
s.screen = ui.NewFrame("Screen")
s.screen.Resize(render.NewRect(d.width, d.height))
// Menu Bar
s.menubar = s.setupMenuBar(d)
s.screen.Pack(s.menubar, ui.Pack{
Side: ui.N,
FillX: true,
})
// Level Exit handler.
s.scripting.OnLevelExit(s.BeatLevel)
s.scripting.OnLevelFail(s.FailLevel)
@ -620,6 +629,9 @@ func (s *PlayScene) Draw(d *Doodle) error {
// Visualize the touch regions?
s.DrawTouchable()
// Let Supervisor draw menus
s.supervisor.Present(d.Engine)
return nil
}

79
pkg/play_scene_menubar.go Normal file
View File

@ -0,0 +1,79 @@
package doodle
import (
"git.kirsle.net/apps/doodle/pkg/levelpack"
"git.kirsle.net/apps/doodle/pkg/shmem"
"git.kirsle.net/apps/doodle/pkg/usercfg"
"git.kirsle.net/apps/doodle/pkg/windows"
"git.kirsle.net/go/render"
"git.kirsle.net/go/ui"
)
// Set up the menu bar for Play Scene.
func (u *PlayScene) setupMenuBar(d *Doodle) *ui.MenuBar {
menu := ui.NewMenuBar("Main Menu")
////////
// Game menu
gameMenu := menu.AddMenu("Game")
gameMenu.AddItem("Story Mode", func() {
// TODO: de-duplicate code from MainScene
if u.winLevelPacks == nil {
u.winLevelPacks = windows.NewLevelPackWindow(windows.LevelPack{
Supervisor: u.supervisor,
Engine: d.Engine,
OnPlayLevel: func(lp levelpack.LevelPack, which levelpack.Level) {
if err := d.PlayFromLevelpack(lp, which); err != nil {
shmem.FlashError(err.Error())
}
},
OnCloseWindow: func() {
u.winLevelPacks.Hide()
},
})
}
u.winLevelPacks.MoveTo(render.Point{
X: (d.width / 2) - (u.winLevelPacks.Size().W / 2),
Y: (d.height / 2) - (u.winLevelPacks.Size().H / 2),
})
u.winLevelPacks.Show()
})
gameMenu.AddItemAccel("New drawing", "Ctrl-N", d.GotoNewMenu)
gameMenu.AddItemAccel("Open drawing", "Ctrl-O", d.GotoLoadMenu)
gameMenu.AddSeparator()
gameMenu.AddItem("Quit to menu", func() {
d.Goto(&MainScene{})
})
gameMenu.AddItemAccel("Quit", "Escape", func() {
d.ConfirmExit()
})
////////
// Level menu
levelMenu := menu.AddMenu("Level")
levelMenu.AddItemAccel("Edit level", "E", u.EditLevel)
// Hilariously broken, someday!
if usercfg.Current.EnableFeatures {
levelMenu.AddSeparator()
levelMenu.AddItemAccel("New viewport", "v", func() {
pip := windows.MakePiPWindow(d.width, d.height, windows.PiP{
Supervisor: u.supervisor,
Engine: u.d.Engine,
Level: u.Level,
Event: u.d.event,
})
pip.Show()
})
}
d.MakeHelpMenu(menu, u.supervisor)
menu.Supervise(u.supervisor)
menu.Compute(d.Engine)
return menu
}

View File

@ -28,6 +28,13 @@ func (s *PlayScene) LoopTouchable(ev *event.State) {
cursor = render.NewPoint(ev.CursorX, ev.CursorY)
)
// 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) {
return
}
// Detect if the player is idle.
// Idle means that they are not holding any directional or otherwise input key.
// Keyboard inputs and touch events from this function will set these keys.

View File

@ -42,7 +42,8 @@ func NewJSProxy(vm *VM) JSProxy {
return shmem.Tick
},
"time": map[string]interface{}{
"Now": time.Now,
"Now": time.Now,
"Since": time.Since,
"Add": func(t time.Time, ms int64) time.Time {
return t.Add(time.Duration(ms) * time.Millisecond)
},

View File

@ -36,6 +36,7 @@ type Settings struct {
CrosshairSize int `json:",omitempty"`
CrosshairColor render.Color
HideTouchHints bool `json:",omitempty"`
DisableAutosave bool `json:",omitempty"`
// Secret boolprops from balance/boolprops.go
ShowHiddenDoodads bool `json:",omitempty"`

View File

@ -39,7 +39,7 @@ func NewLevelPackWindow(config LevelPack) *ui.Window {
// size of the popup window
width = 320
height = 340
height = 360
)
// Get the available .levelpack files.
@ -275,7 +275,7 @@ func (config LevelPack) makeDetailScreen(frame *ui.Frame, width, height int, lp
buttonWidth = width - 40
page = 1
perPage = 3
perPage = 4
pages = int(
math.Ceil(
float64(len(lp.Levels)) / float64(perPage),

View File

@ -77,25 +77,37 @@ func NewPiPWindow(cfg PiP) *ui.Window {
canvas.Editable = true
canvas.Resize(render.NewRect(canvasWidth, canvasHeight))
// If we have tool bindings to edit in PiP window
var (
editable bool
curTool drawtool.Tool
curThicc int
)
if cfg.Tool != nil && cfg.BrushSize != nil {
editable = true
curTool = *cfg.Tool
curThicc = *cfg.BrushSize
canvas.Tool = curTool
}
// NOTE: my UI toolkit calls this every tick, if this is "fixed"
// in the future make one that does.
var (
curTool = *cfg.Tool
curThicc = *cfg.BrushSize
)
canvas.Tool = curTool
window.Handle(ui.MouseMove, func(ed ui.EventData) error {
canvas.Loop(cfg.Event)
// Check if bound values have modified.
if *cfg.Tool != curTool {
curTool = *cfg.Tool
canvas.Tool = curTool
}
if *cfg.BrushSize != curThicc {
curThicc = *cfg.BrushSize
canvas.BrushSize = curThicc
// Did we have tool bindings for an editable PiP?
if editable {
// Check if bound values have modified.
if *cfg.Tool != curTool {
curTool = *cfg.Tool
canvas.Tool = curTool
}
if *cfg.BrushSize != curThicc {
curThicc = *cfg.BrushSize
canvas.BrushSize = curThicc
}
}
return nil
})

View File

@ -29,6 +29,7 @@ type Settings struct {
CrosshairSize *int
CrosshairColor *render.Color
HideTouchHints *bool
DisableAutosave *bool
// Configuration options.
SceneName string // name of scene which called this window
@ -142,6 +143,12 @@ func (c Settings) makeOptionsTab(tabFrame *ui.TabFrame, Width, Height int) *ui.F
PadX: 4,
name: "toolbars",
},
{
Boolean: c.DisableAutosave,
Text: "Disable auto-save in the Editor",
PadX: 4,
name: "autosave",
},
{
Integer: c.CrosshairSize,
Text: "Editor: Crosshair size (0 to disable):",
@ -170,9 +177,7 @@ func (c Settings) makeOptionsTab(tabFrame *ui.TabFrame, Width, Height int) *ui.F
},
{
Text: "Levels and doodads you create in-game are placed in your\n" +
"Profile Directory. This is also where you can place content made\n" +
"by others to use them in your game. Click on the button below\n" +
"to (hopefully) be taken to your Profile Directory:",
"Profile Directory, which you can access below:",
},
}
for _, row := range rows {
@ -634,20 +639,11 @@ func (c Settings) makeExperimentalTab(tabFrame *ui.TabFrame, Width, Height int)
PadY: 2,
},
{
Header: "Zoom In/Out",
Header: "Viewport window",
},
{
Text: "This adds Zoom options to the level editor. It has a few\n" +
"bugs around scrolling but may be useful already.",
PadY: 2,
},
{
Header: "Replace Level Palette",
},
{
Text: "This adds an option to the Level Properties dialog to\n" +
"replace your level palette with one of the defaults,\n" +
"like on the New Level screen. It might not actually work.",
Text: "This option in the Level menu opens another view into\n" +
"the level. Has glitchy wallpaper problems.",
PadY: 2,
},
{