* Fix collision detection to allow actors to walk up slopes smoothly, without
losing any horizontal velocity.
* Fix scrolling a level canvas so that chunks near the right or bottom edge
of the viewpoint were getting culled prematurely.
* Centralize JavaScript exception catching logic to attach Go and JS stack
traces where possible to be more useful for debugging.
* Performance: flush all SDL2 textures from memory between scene transitions
in the app. Also add a `flush-textures` dev console command to flush the
textures at any time - they all should regenerate if still needed based on
underlying go.Images which can be garbage collected.
* Rework the Story Mode UI to display level thumbnails.
* Responsive UI: defaults to wide screen mode and shows 3 levels horizontally
but on narrow/mobile display, shows 2 levels per page in portrait.
* Add "Tiny" screenshot size (224x126) to fit the Story Mode UI.
* Make the pager buttons bigger and more touchable.
* Maximize the game window on startup unless the -w option with a specific
window resolution is provided.
Adds some support for "less giant" level screenshots.
* In the Editor, the Level->Take Screenshot menu will render a cropped screen
shot of just the level viewport on screen. Note: it is not an SDL2 screen
copy but generated from scratch from the level data.
* In levels themselves, screenshots can be stored inside the level data in
three different sizes: large (1280x720), medium and small (each a halved
size of the previous).
* The first screenshot is created when the level is saved, starting from
wherever the scroll position in the editor is at, and recording the 720p
view of the level from there.
* The level screenshot can be previewed and updated in the Level Properties
window of the editor: so you can scroll the editor to just the right position
and take a good screenshot to represent your level.
* In the future: these embedded level screenshots will be displayed on the
Story Mode and other screens to see a preview of each level.
Other tweaks:
* When taking a Giant Screenshot: a confirm modal will warn the player that
it may take a while. And during the screenshot, show the new Wait Modal to
block player interaction until the screenshot has finished.
* Overhaul the clunky old alpha Edit Level/Doodad menu with a modernized
version featuring the new ListBox widget.
* The new level loader is a Window that can be spawned from anywhere instead
of on a dedicated MenuScene.
Updates to doodad scripts:
* Actor.IsOnScreen() checks whether an actor's visual sprite box is on-screen
in the level viewport. `Self.IsOnScreen()` will check for the current actor.
Other changes
* PlaySound() to deduplicate the same sound effect from playing at once.
Updates the savegame.json file format:
* Levels now have a UUID value assigned at first save.
* The savegame.json will now track level completion/score based on UUID,
making it robust to filename changes in either levels or levelpacks.
* The savegame file is auto-migrated on startup - for any levels not
found or have no UUID, no change is made, it's backwards compatible.
* Level Properties window adds an "Advanced" tab to show/re-roll UUID.
New JavaScript API for doodad scripts:
* `Actors.CameraFollowPlayer()` tells the camera to return focus to the
player character. Useful for "cutscene" doodads that freeze the player,
call `Self.CameraFollowMe()` and do a thing before unfreezing and sending the
camera back to the player. (Or it will follow them at their next directional
input control).
* `Self.MoveBy(Point(x, y int))` to move the current actor a bit.
New option for the `doodad` command-line tool:
* `doodad resave <.level or .doodad>` will load and re-save a drawing, to
migrate it to the newest file format versions.
Small tweaks:
* On bounded levels, allow the camera to still follow the player if the player
finds themselves WELL far out of bounds (40 pixels margin). So on bounded
levels you can create "interior rooms" out-of-bounds to Warp Door into.
* New wallpaper: "Atmosphere" has a black starscape pattern that fades into a
solid blue atmosphere.
* Camera strictly follows the player the first 20 ticks, not 60 of level start
* If player is frozen, directional inputs do not take the camera focus back.
Add the ability for the free version of the game to allow loading levels that
use embedded custom doodads if those levels are signed.
* Uses the same signing keys as the JWT token for license registrations.
* Levels and Levelpacks can both be signed. So individual levels with embedded
doodads can work in free versions of the game.
* Levelpacks now support embedded doodads properly: the individual levels in
the pack don't need to embed a custom doodad, but if the doodad exists in
the levelpack's doodads/ folder it will load from there instead - for full
versions of the game OR when the levelpack is signed.
Signatures are computed by getting a listing of embedded assets inside the
zipfile (the assets/ folder in levels, and the doodads/ + levels/ folders
in levelpacks). Thus for individual signed levels, the level geometry and
metadata may be changed without breaking the signature but if custom doodads
are changed the signature will break.
The doodle-admin command adds subcommands to `sign-level` and `verify-level`
to manage signatures on levels and levelpacks.
When using the `doodad levelpack create` command, any custom doodads the
levels mention that are found in your profile directory get embedded into
the zipfile by default (with --doodads custom).
* Fix display bug with rectangular doodads scrolling off screen.
* The default Author of new files will be your registration name, if available
before using your $USER name.
Convert the Chunker size to a uint8 so chunk sizes are limited to 255px. This
means that inside of a chunk, uint8's can track the relative pixel coordinates
and result in a great memory savings since all of these uint8's are currently
64-bits wide apiece.
WIP on rectangular shaped doodads:
* You can create such a doodad in the editor and draw it normally.
* It doesn't draw the right size when dragged into your level however:
- In uix.Actor.Size() it gets a rect of the doodad's square Chunker size,
instead of getting the proper doodad.Size rect.
- If you give it the doodad.Size rect, it draws the Canvas size correctly
instead of a square - the full drawing appears and in gameplay its hitbox
(assuming the same large rectangle size) works correctly in-game.
- But, the doodad has scrolling issues when it gets to the top or left edge
of the screen! This old gnarly bug has come back. For some reason square
canvas doodads draw correctly but rectangular ones have the drawing scroll
just a bit - how far it scrolls is proportional to how big the doodad is,
with the Start Flag only scrolling a few pixels before it stops.
* 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`)
* Add a Dockerfile to this repo for self-contained easy releases.
Run it from an x86_64 Linux host and it will produce 64-bit and
32-bit Linux (rpm, deb, AppImage, tar.gz) and Windows releases.
* The `make appimage` command is more self-sufficient: it will
download the appimagetool-x86_64.AppImage program for your $ARCH
for an easy no-dependencies run after you have run `make dist`
The newer goja caused problems calling RunCollide or RunKeypress on
doodad scripts - resulting in a broken player character and no collision
events running on doodad scripts. Investigate later.
* Add new pixel attributes: SemiSolid and Slippery (the latter is WIP)
* SemiSolid pixels are only solid below the player character. You can walk on
them and up and down SemiSolid slopes, but can freely pass through from the
sides or jump through from below.
* Update the Palette Editor UI to replace the Attributes buttons: instead of
text labels they now have smaller icons (w/ tooltips) for the Solid,
SemiSolid, Fire, Water and Slippery attributes.
* Bugfix in Palette Editor: use cropped (24x24) images for the Tex buttons so
that the large Bubbles texture stays within its designated space!
* uix.Actor.SetGrounded() to also set the Y velocity to zero when an actor
becomes grounded. This fixes a minor bug where the player's Y velocity (due
to gravity) was not updated while they were grounded, which may eventually
become useful to allow them to jump down thru a SemiSolid floor. Warp Doors
needed a fix to work around the bug, to set the player's Grounded(false) or
else they would hover a few pixels above the ground at their destination,
since Grounded status paused gravity calculations.
* Add "Options" support for Doodads: these allow for individual Actor instances
on your level to customize properties about the doodad. They're like "Tags"
except the player can customize them on a per-actor basis.
* Doodad Editor: you can specify the Options in the Doodad Properties window.
* Level Editor: when the Actor Tool is selected, on mouse-over of an actor,
clicking on the gear icon will open a new "Actor Properties" window which
shows metadata (title, author, ID, position) and an Options tab to configure
the actor's options.
Updates to the scripting API:
* Self.Options() returns a list of option names defined on the Doodad.
* Self.GetOption(name) returns the value for the named option, or nil if
neither the actor nor its doodad have the option defined. The return type
will be correctly a string, boolean or integer type.
Updates to the doodad command-line tool:
* `doodad show` will print the Options on a .doodad file and, when showing a
.level file with --actors, prints any customized Options with the actors.
* `doodad edit-doodad` adds a --option parameter to define options.
Options added to the game's built-in doodads:
* Warp Doors: "locked (exit only)" will make it so the door can not be opened
by the player, giving the "locked" message (as if it had no linked door),
but the player may still exit from the door if sent by another warp door.
* Electric Door & Electric Trapdoor: "opened" can make the door be opened by
default when the level begins instead of closed. A switch or a button that
removes power will close the door as normal.
* Colored Doors & Small Key Door: "unlocked" will make the door unlocked at
level start, not requiring a key to open it.
* Colored Keys & Small Key: "has gravity" will make the key subject to gravity
and set its Mobile flag so that if it falls onto a button, it will activate.
* Gemstones: they had gravity by default; you can now uncheck "has gravity" to
remove their Gravity and IsMobile status.
* Gemstone Totems: "has gemstone" will set the totem to its unlocked status by
default with the gemstone inserted. No power signal will be emitted; it is
cosmetic only.
* Fire Region: "name" can let you set a name for the fire region similarly to
names for fire pixels: "Watch out for ${name}!"
* Invisible Warp Door: "locked (exit only)" added as well.
* New script API method: Self.CameraFollowMe() to draw camera focus toward
your doodad (it sets the Canvas.FollowActor target.)
* The camera will go back to following the player on any action inputs
(arrow keys, jump, use, etc.); if the player is constantly on the move
the camera stays on him even if another actor is trying to take the focus.
* The first few ticks of Play Mode the player character is always followed,
to allow for Anvils to settle into place without taking the focus.
* Canvas FollowActor: if the actor is 4 times the max scroll speed away,
allow scrolling in greater leaps of 4 times the max scroll speed.
New and Changed Doodads
* Anvils will take the camera focus while they are falling.
* New doodad: "Look At Me" - a 'camera region' technical doodad. Link it to
any power source such as a Button - when this doodad receives power it will
take the camera focus for a few frames. Use it to highlight a door that
opened far off screen by linking the Button to both an Electric Door and
a "Look At Me" near the door.
* Add an exception catcher that pops open a UI window showing errors that
occur in doodad scripts during gameplay.
* Shows a preview of the header of the error (character wrapped) with a
Copy button to copy the full raw text to clipboard for inspection.
* Buttons to dismiss the modal once or stop any further errors from
opening during this gameplay session (until next restart).
* Add developer shell commands to test the exception catcher:
- 'throw <message>' to throw a custom message.
- 'throw2' to stress test a "long" message.
- 'throw3' to throw a realistic message copied from an actual error.
* Scripting engine: console.log() and friends will now insert the script
VM's name in front of its messages (the filename + actor ID).
* Add modal.Wait() that creates a global progress bar modal which is not
dismissable by the user; the caller must Dismiss() the modal
themselves when ready.
* It will be useful in the future in case e.g. saving a Level needs to
take a while to rebalance chunks and the modal prevents ALL
interaction with the game so the user can't further modify the level
while it's busy refactoring itself.
* Cheat code: "test wait screen" to show the Wait modal for 10 seconds.
* Made the loadscreen useful again (give it work to do async so the game
doesn't simply freeze during): does a first call to LoadUnloadChunks
to preload the viewport chunks.
* Hide the mouse cursor when movement keys are pressed.
* On the failure (but still success) dialog on Survival Mode levels
(e.g. Azulian Tag): make the default be to retry the level but
show a "pity" Next Level button below, as the level is marked as
completed (silver score) and the next one is unlocked.
Previously: the Chunker tracks with chunks were gotten during the
current game tick and the N-1 and N-2 ticks, and chunks not accessed in
two ticks were freed immediately.
Now: they go into a "garbage collection" pool with a minimum number of
game ticks to free. So if they're needed again, they're saved from the
gc pool. F3 overlay data shows the count of the gc pool.