Prepare v0.8.0 for release

This commit is contained in:
Noah 2021-09-03 21:35:12 -07:00
parent 7866f618da
commit f446ed9130
8 changed files with 104 additions and 35 deletions

View File

@ -1,15 +1,31 @@
# Changes
## v0.8.0 (TBD)
To Do:
* Thief needs animations
* New levels
## v0.8.0 (September 3, 2021)
This release brings some new features, new doodads, and new levels.
New features:
* **Checkpoints** for gameplay will ease the pain of dying to fire
pixels or Anvils by teleporting you back to the checkpoint instead
of resetting the whole level.
* The **Doodad Properties** window while editing a doodad grants access
to many features which were previously only available via the
`doodad` tool, such as:
* Edit metadata like the Title and Author of your doodad
* Set the default hitbox of your doodad.
* Attach, open, and delete the JavaScript for your doodad
* Manage tags (key/value store) on your doodads: how you can
communicate settings to the JavaScript which can receive the
tags via `Self.GetTag("name")`
* Some **Generic Doodad Scripts** are built in. Using only the in-game
tools, it is possible to create custom doodads which have some basic
in-game logic and you don't need to write any code. The generic
scripts include:
* Generic Solid: the hitbox is solid
* Generic Fire: its hitbox harms the player
* Generic Anvil: harmless, deadly when falling
* Generic Collectible Item: it goes in your inventory
* **All Characters are Playable!** Use the Link Tool to connect your
Start Flag with another doodad on your level, and you will play
**as** that doodad when the level starts. The Creature doodads are
@ -31,6 +47,18 @@ New doodads have been added:
* The **Blue Azulian** is now selectable from the Doodads menu. It
behaves like the Red Azulian but moves at half the speed. The
Azulians can pick up items and open doors.
* The **Checkpoint Flag** will remember the player's spot in the level.
Dying to fire pixels or Anvils no longer forces a restart of the
level - you can resume from your last checkpoint, or the Start Flag
by default.
New levels have been added:
* **Castle.level:** introduces the new Thief character. Castle-themed
level showing off various new doodads.
* **Thief 1.level:** a level where you play as the Thief! You need to
steal Small Keys from dozens of Azulians and even steal items back
from another Thief who has already stolen some of the keys.
Some doodads have changed behavior:
@ -52,12 +80,11 @@ The user interface has been improved:
5. All: a classic view paging over all doodads (and doodads
not fitting any of the above categories).
doodad edit-doodad --tag "categories=doors,gizmos" filename.doodad
New functions are available in the JavaScript API for custom doodads:
* FailLevel(message string): global function that kills the player
with a custom death message.
* SetCheckpoint(Point): set the player respawn location
* Self.MoveTo(Point(x, y int))
* Self.IsPlayer() bool
* Self.SetInventory(bool): turn on or off inventory. Keys and other
@ -69,6 +96,7 @@ New functions are available in the JavaScript API for custom doodads:
* Self.RemoveItem(filename string, quantity int)
* Self.HasItem(filename string)
* Self.Inventory() map[string]int
* Self.Hitbox() - also see Self.Hitbox.IsEmpty()
The Events.OnLeave() callback now receives a CollideEvent argument,
like OnCollide, instead of the useless actor ID string. Notable
@ -87,6 +115,12 @@ Other miscellaneous changes:
* A **death barrier** will prevent Boy from falling forever on unbounded
maps should he somehow fall off the level. The death barrier is a
Y value 1,000 pixels below the lowest pixel on your map.
* Mobile doodads no longer "moonwalk" when they change directions.
* A new color is added to all default palettes: "hint" (pink) for
writing hint notes.
* A maximum scroll speed on the "follow the player character" logic
makes for cooler animations when the character teleports around.
* Levels and Doodads are now sorted on the Open menu.
## v0.7.2 (July 19 2021)

View File

@ -48,7 +48,7 @@ func init() {
},
Action: func(c *cli.Context) error {
if c.NArg() < 2 {
return cli.NewExitError(
return cli.Exit(
"Usage: doodad convert <input.png...> <output.doodad>\n"+
" Image file types: png, bmp\n"+
" Drawing file types: level, doodad",
@ -59,7 +59,7 @@ func init() {
// Parse the chroma key.
chroma, err := render.HexColor(c.String("key"))
if err != nil {
return cli.NewExitError(
return cli.Exit(
"Chrome key not a valid color: "+err.Error(),
1,
)
@ -76,22 +76,22 @@ func init() {
if inputType == extPNG || inputType == extBMP {
if outputType == extLevel || outputType == extDoodad {
if err := imageToDrawing(c, chroma, inputFiles, outputFile); err != nil {
return cli.NewExitError(err.Error(), 1)
return cli.Exit(err.Error(), 1)
}
return nil
}
return cli.NewExitError("Image inputs can only output to Doodle drawings", 1)
return cli.Exit("Image inputs can only output to Doodle drawings", 1)
} else if inputType == extLevel || inputType == extDoodad {
if outputType == extPNG || outputType == extBMP {
if err := drawingToImage(c, chroma, inputFiles, outputFile); err != nil {
return cli.NewExitError(err.Error(), 1)
return cli.Exit(err.Error(), 1)
}
return nil
}
return cli.NewExitError("Doodle drawing inputs can only output to image files", 1)
return cli.Exit("Doodle drawing inputs can only output to image files", 1)
}
return cli.NewExitError("File types must be: png, bmp, level, doodad", 1)
return cli.Exit("File types must be: png, bmp, level, doodad", 1)
},
}
}
@ -107,13 +107,13 @@ func imageToDrawing(c *cli.Context, chroma render.Color, inputFiles []string, ou
for i, filename := range inputFiles {
reader, err := os.Open(filename)
if err != nil {
return cli.NewExitError(err.Error(), 1)
return cli.Exit(err.Error(), 1)
}
img, format, err := image.Decode(reader)
log.Info("Parsed image %d of %d. Format: %s", i+1, len(inputFiles), format)
if err != nil {
return cli.NewExitError(err.Error(), 1)
return cli.Exit(err.Error(), 1)
}
// Get the bounding box information of the source image.
@ -131,7 +131,7 @@ func imageToDrawing(c *cli.Context, chroma render.Color, inputFiles []string, ou
chunkSize = imageSize.Y
}
} else if imageSize != imageBounds {
return cli.NewExitError("your source images are not all the same dimensions", 1)
return cli.Exit("your source images are not all the same dimensions", 1)
}
images = append(images, img)
@ -177,7 +177,7 @@ func imageToDrawing(c *cli.Context, chroma render.Color, inputFiles []string, ou
err := doodad.WriteJSON(outputFile)
if err != nil {
return cli.NewExitError(err.Error(), 1)
return cli.Exit(err.Error(), 1)
}
case extLevel:
log.Info("Output is a Level file: %s", outputFile)
@ -198,10 +198,10 @@ func imageToDrawing(c *cli.Context, chroma render.Color, inputFiles []string, ou
err := lvl.WriteJSON(outputFile)
if err != nil {
return cli.NewExitError(err.Error(), 1)
return cli.Exit(err.Error(), 1)
}
default:
return cli.NewExitError("invalid output file: not a Doodle drawing", 1)
return cli.Exit("invalid output file: not a Doodle drawing", 1)
}
return nil

View File

@ -3,10 +3,12 @@ package commands
import (
"fmt"
"os"
"strconv"
"strings"
"git.kirsle.net/apps/doodle/pkg/doodads"
"git.kirsle.net/apps/doodle/pkg/log"
"git.kirsle.net/go/render"
"github.com/urfave/cli/v2"
)
@ -32,6 +34,10 @@ func init() {
Name: "author",
Usage: "set the doodad author",
},
&cli.StringFlag{
Name: "hitbox",
Usage: "set the doodad hitbox (X,Y,W,H or W,H format)",
},
&cli.StringSliceFlag{
Name: "tag",
Aliases: []string{"t"},
@ -56,7 +62,7 @@ func init() {
},
Action: func(c *cli.Context) error {
if c.NArg() < 1 {
return cli.NewExitError(
return cli.Exit(
"Usage: doodad edit-doodad <filename.doodad>",
1,
)
@ -100,6 +106,34 @@ func editDoodad(c *cli.Context, filename string) error {
modified = true
}
if c.String("hitbox") != "" {
// Setting a hitbox, parse it out.
parts := strings.Split(c.String("hitbox"), ",")
var ints []int
for _, part := range parts {
a, err := strconv.Atoi(strings.TrimSpace(part))
if err != nil {
return err
}
ints = append(ints, a)
}
if len(ints) == 2 {
dd.Hitbox = render.NewRect(ints[0], ints[1])
modified = true
} else if len(ints) == 4 {
dd.Hitbox = render.Rect{
X: ints[0],
Y: ints[1],
W: ints[2],
H: ints[3],
}
modified = true
} else {
return cli.Exit("Hitbox should be in X,Y,W,H or just W,H format, 2 or 4 numbers.", 1)
}
}
// Tags.
tags := c.StringSlice("tag")
if len(tags) > 0 {
@ -152,7 +186,7 @@ func editDoodad(c *cli.Context, filename string) error {
if modified {
if err := dd.WriteJSON(filename); err != nil {
return cli.NewExitError(fmt.Sprintf("Write error: %s", err), 1)
return cli.Exit(fmt.Sprintf("Write error: %s", err), 1)
}
} else {
log.Warn("Note: No changes made to level")

View File

@ -58,7 +58,7 @@ func init() {
},
Action: func(c *cli.Context) error {
if c.NArg() < 1 {
return cli.NewExitError(
return cli.Exit(
"Usage: doodad edit-level <filename.level>",
1,
)
@ -151,7 +151,7 @@ func editLevel(c *cli.Context, filename string) error {
if modified {
if err := lvl.WriteFile(filename); err != nil {
return cli.NewExitError(fmt.Sprintf("Write error: %s", err), 1)
return cli.Exit(fmt.Sprintf("Write error: %s", err), 1)
}
} else {
log.Warn("Note: No changes made to level")

View File

@ -26,7 +26,7 @@ func init() {
},
Action: func(c *cli.Context) error {
if c.NArg() != 2 {
return cli.NewExitError(
return cli.Exit(
"Usage: doodad install-script <script.js> <filename.doodad>",
1,
)
@ -41,12 +41,12 @@ func init() {
// Read the JavaScript source.
javascript, err := ioutil.ReadFile(scriptFile)
if err != nil {
return cli.NewExitError(err.Error(), 1)
return cli.Exit(err.Error(), 1)
}
doodad, err := doodads.LoadJSON(doodadFile)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to read doodad file: %s", err),
1,
)

View File

@ -46,7 +46,7 @@ func init() {
},
Action: func(c *cli.Context) error {
if c.NArg() < 1 {
return cli.NewExitError(
return cli.Exit(
"Usage: doodad show <.level .doodad ...>",
1,
)
@ -58,12 +58,12 @@ func init() {
case enum.LevelExt:
if err := showLevel(c, filename); err != nil {
log.Error(err.Error())
return cli.NewExitError("Error", 1)
return cli.Exit("Error", 1)
}
case enum.DoodadExt:
if err := showDoodad(c, filename); err != nil {
log.Error(err.Error())
return cli.NewExitError("Error", 1)
return cli.Exit("Error", 1)
}
default:
log.Error("File %s: not a level or doodad", filename)
@ -172,6 +172,7 @@ func showDoodad(c *cli.Context, filename string) error {
fmt.Printf(" Game version: %s\n", dd.GameVersion)
fmt.Printf(" Doodad title: %s\n", dd.Title)
fmt.Printf(" Author: %s\n", dd.Author)
fmt.Printf(" Hitbox: %s\n", dd.Hitbox)
fmt.Printf(" Locked: %+v\n", dd.Locked)
fmt.Printf(" Hidden: %+v\n", dd.Hidden)
fmt.Printf(" Script size: %d bytes\n", len(dd.Script))

View File

@ -4,7 +4,7 @@ package branding
const (
AppName = "Sketchy Maze"
Summary = "A drawing-based maze game"
Version = "0.7.2"
Version = "0.8.0"
Website = "https://www.sketchymaze.com"
Copyright = "2021 Noah Petherbridge"
Byline = "a game by Noah Petherbridge."

View File

@ -385,8 +385,8 @@ func (s *MainScene) Draw(d *Doodle) error {
// Version label
s.labelVersion.MoveTo(render.Point{
X: (d.width / 2) - (s.labelVersion.Size().W / 2),
Y: s.labelSubtitle.Point().Y + s.labelSubtitle.Size().H + 8,
X: (d.width) - (s.labelVersion.Size().W) - 20,
Y: 20,
})
s.labelVersion.Present(d.Engine, s.labelVersion.Point())