Formalise a bit in each cell as an "IsActive()" bit

This commit is contained in:
2018-03-28 01:00:55 +01:00
parent b6dcfafb6d
commit b653c11606
4 changed files with 70 additions and 38 deletions

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"flag" "flag"
"fmt"
"log" "log"
"math" "math"
"os" "os"
@@ -112,26 +113,28 @@ func (e *env) run() {
}) })
} }
func (e *env) getSprite(palette []string, ref maps.ObjRef) *conv.Sprite { func (e *env) getSprite(palette []string, ref maps.ObjRef) (*conv.Sprite, error) {
// There seems to be an active bit that hides many sins
if !ref.IsActive() {
return nil, nil
}
if ref.Index() >= len(palette) { if ref.Index() >= len(palette) {
log.Printf("Palette too small: %v requested", ref.Index()) return nil, fmt.Errorf("Palette too small: %v requested", ref.Index())
return nil
} }
name := palette[ref.Index()] name := palette[ref.Index()]
obj := e.objects[name] obj := e.objects[name]
if obj == nil { if obj == nil {
log.Printf("Failed to find surface sprite %#v -> %q", ref, name) return nil, fmt.Errorf("Failed to find surface sprite %#v -> %q", ref, name)
return nil
} }
if ref.Frame() >= len(obj.Sprites) { if ref.Sprite() >= len(obj.Sprites) {
log.Printf("Out-of-index sprite %v requested for %v", ref.Frame(), name) return nil, fmt.Errorf("Out-of-index sprite %v requested for %v", ref.Sprite(), name)
return nil
} }
return &obj.Sprites[ref.Frame()] return &obj.Sprites[ref.Sprite()], nil
} }
// TODO: build all the sprites in the set into a single spritesheet so we can // TODO: build all the sprites in the set into a single spritesheet so we can
@@ -171,14 +174,29 @@ func (s *state) renderCell(x, y, z int, pWin *pixelgl.Window) {
cell := s.env.gameMap.Cells.At(x, y, z) cell := s.env.gameMap.Cells.At(x, y, z)
sprites = append(sprites, s.env.getSprite(s.env.set.Palette, cell.Surface)) if spr, err := s.env.getSprite(s.env.set.Palette, cell.Surface); err != nil {
log.Printf("%v %v %v surface: %v", x, y, z, err)
} else {
sprites = append(sprites, spr)
}
sprites = append( if spr, err := s.env.getSprite(s.env.set.Palette, cell.Center); err != nil {
sprites, log.Printf("%v %v %v center: %v", x, y, z, err)
s.env.getSprite(s.env.set.Palette, cell.Center), } else {
s.env.getSprite(s.env.set.Palette, cell.Left), sprites = append(sprites, spr)
s.env.getSprite(s.env.set.Palette, cell.Right), }
)
if spr, err := s.env.getSprite(s.env.set.Palette, cell.Left); err != nil {
log.Printf("%v %v %v left: %v", x, y, z, err)
} else {
sprites = append(sprites, spr)
}
if spr, err := s.env.getSprite(s.env.set.Palette, cell.Right); err != nil {
log.Printf("%v %v %v right: %v", x, y, z, err)
} else {
sprites = append(sprites, spr)
}
// Taking the Z index away *seems* to draw the object in the correct place. // Taking the Z index away *seems* to draw the object in the correct place.
// FIXME: There are some artifacts, investigate more // FIXME: There are some artifacts, investigate more
@@ -227,11 +245,14 @@ func (s *state) handleKeys(pWin *pixelgl.Window) {
// FIXME: this suggests we should pass the next state into here and // FIXME: this suggests we should pass the next state into here and
// modify it instead // modify it instead
if pWin.JustPressed(pixelgl.MouseButton1) { if pWin.JustPressed(pixelgl.MouseButton1) {
cell := s.pixToCell(s.cam.Unproject(pWin.MousePosition()))
if s.zIdx != 0 { if s.zIdx != 0 {
log.Printf("WARNING: z-index not yet taken into account") log.Printf("WARNING: z-index not yet taken into account")
} }
log.Printf("X=%v Y=%v, zIdx=%v", cell.X, cell.Y, s.zIdx)
pos := s.pixToCell(s.cam.Unproject(pWin.MousePosition()))
cell := s.env.gameMap.Cells.At(int(pos.X), int(pos.Y), s.zIdx)
log.Printf("X=%v Y=%v, zIdx=%v", pos.X, pos.Y, s.zIdx)
log.Printf("Cell=%#v", cell)
} }
if pWin.Pressed(pixelgl.KeyLeft) { if pWin.Pressed(pixelgl.KeyLeft) {

View File

@@ -400,15 +400,15 @@ Investigation has so far suggested the following:
* 0x40: Animated object * 0x40: Animated object
* `Cell[2]` hasn't been seen with a value > 0 yet * `Cell[2]` hasn't been seen with a value > 0 yet
* `Cell[3]` Object 0 (Surface) Area (Sets/*.set lookup) * `Cell[3]` Object 0 (Surface) Area (Sets/*.set lookup)
* `Cell[4]` Object 0 (Surface) Sprite + ??? * `Cell[4]` Object 0 (Surface) Sprite + active flag
* Bottom bits encode the sprite (frame number in the .obj file) * Bottom bits encode the sprite (frame number in the .obj file)
* 0x80 is set too. A flag? * 0x80 is set too. A flag?
* `Cell[5]` Object 1 (Left) Area (Sets/*.set lookup) * `Cell[5]` Object 1 (Left) Area (Sets/*.set lookup)
* `Cell[6]` Object 1 (Surface) Sprite + ??? * `Cell[6]` Object 1 (Surface) Sprite + active flag
* `Cell[7]` Object 2 (Right) Area (Sets/*.set lookup) * `Cell[7]` Object 2 (Right) Area (Sets/*.set lookup)
* `Cell[6]` Object 2 (Right) Sprite + ??? * `Cell[6]` Object 2 (Right) Sprite + active flag
* `Cell[9]` Object 3 (Center) Area (Sets/*.set lookup) * `Cell[9]` Object 3 (Center) Area (Sets/*.set lookup)
* `Cell[10]` Object 3 (Right) Sprite + ??? * `Cell[10]` Object 3 (Right) Sprite + active flag
* `Cell[11]` all 255? * `Cell[11]` all 255?
* `Cell[12]` all 0? * `Cell[12]` all 0?
* `Cell[13]` all 0? * `Cell[13]` all 0?
@@ -436,6 +436,12 @@ So `CellIdx == 9` points to the center object's Area, looked up in the set file!
It seems the area numbers are absolute indexes into the set, rather than having It seems the area numbers are absolute indexes into the set, rather than having
a new set of indices for each type. a new set of indices for each type.
We have to remove 0x80 from the sprite byte to get a valid reference. This seems
to act as an "active" flag - without it, Chapter01.MAP has a "ghost" of the
template close to the 0,0 boundary. Theory: the devs originally started at 0,0
but then they decided to center smaller maps rather than being there, so the
layout got moved!
With this information, we can render a given Z index for a map quite easily, With this information, we can render a given Z index for a map quite easily,
using the new `view-map` binary. It draws the four objects for every cell, and using the new `view-map` binary. It draws the four objects for every cell, and
gives results like this: gives results like this:

View File

@@ -52,7 +52,7 @@ var transparent = color.RGBA{0, 0, 0, 0}
func spriteToPic(name string, idx int, sprite *data.Sprite) *pixel.PictureData { func spriteToPic(name string, idx int, sprite *data.Sprite) *pixel.PictureData {
pic := pixel.MakePictureData(pixel.R(float64(0), float64(0), float64(sprite.Width), float64(sprite.Height))) pic := pixel.MakePictureData(pixel.R(float64(0), float64(0), float64(sprite.Width), float64(sprite.Height)))
log.Printf("%v %v: width=%v height=%v", name, idx, sprite.Width, sprite.Height) //log.Printf("%v %v: width=%v height=%v", name, idx, sprite.Width, sprite.Height)
for y := 0; y < int(sprite.Height); y++ { for y := 0; y < int(sprite.Height); y++ {
// Start with all bytes transparent // Start with all bytes transparent
@@ -61,7 +61,7 @@ func spriteToPic(name string, idx int, sprite *data.Sprite) *pixel.PictureData {
} }
row := sprite.Rows[y] row := sprite.Rows[y]
log.Printf("%#v", row) //log.Printf("%#v", row)
pixels := row[0 : len(row)-1] // Strip off the record separator (0x00) pixels := row[0 : len(row)-1] // Strip off the record separator (0x00)
// Not really clear on what this does yet. Aligned with sprite width in // Not really clear on what this does yet. Aligned with sprite width in
@@ -79,7 +79,7 @@ func spriteToPic(name string, idx int, sprite *data.Sprite) *pixel.PictureData {
// Do nothing if we're out of pixels // Do nothing if we're out of pixels
if u0 == 0x80 { if u0 == 0x80 {
log.Printf("Handling 0x80: %#v", pixels) //log.Printf("Handling 0x80: %#v", pixels)
xOffset = int(pixels[0]) xOffset = int(pixels[0])
pixels = pixels[1:len(pixels)] pixels = pixels[1:len(pixels)]
@@ -98,10 +98,10 @@ func spriteToPic(name string, idx int, sprite *data.Sprite) *pixel.PictureData {
} }
} }
log.Printf( //log.Printf(
"%v %d: len(row)=%v, len(pixels)=%v sprWidth=%v u0=%v xOffset=%v", // "%v %d: len(row)=%v, len(pixels)=%v sprWidth=%v u0=%v xOffset=%v",
name, idx, len(row), len(pixels), sprite.Width, u0, xOffset, // name, idx, len(row), len(pixels), sprite.Width, u0, xOffset,
) //)
for x, b := range pixels { for x, b := range pixels {
vec := pixel.V(float64(xOffset+x), float64(y)) vec := pixel.V(float64(xOffset+x), float64(y))

View File

@@ -69,8 +69,8 @@ func (h Header) MapSetFilename() string {
} }
type ObjRef struct { type ObjRef struct {
AreaByte byte AreaByte byte
FrameAndUnknownByte byte SpriteAndFlagByte byte
} }
// The index into a set palette to retrieve the object // The index into a set palette to retrieve the object
@@ -78,8 +78,14 @@ func (o ObjRef) Index() int {
return int(o.AreaByte) return int(o.AreaByte)
} }
func (o ObjRef) Frame() int { func (o ObjRef) Sprite() int {
return int(o.FrameAndUnknownByte - 0x80) // The top bit seems to be a flag of some kind
return int(o.SpriteAndFlagByte & 0x7f)
}
// The top bit seems to say whether we should draw or not.
func (o ObjRef) IsActive() bool {
return (o.SpriteAndFlagByte & 0x80) == 0x80
} }
type Cell struct { type Cell struct {
@@ -108,19 +114,19 @@ func (c *Cell) At(n int) byte {
case 3: case 3:
return c.Surface.AreaByte return c.Surface.AreaByte
case 4: case 4:
return c.Surface.FrameAndUnknownByte return c.Surface.SpriteAndFlagByte
case 5: case 5:
return c.Left.AreaByte return c.Left.AreaByte
case 6: case 6:
return c.Left.FrameAndUnknownByte return c.Left.SpriteAndFlagByte
case 7: case 7:
return c.Right.AreaByte return c.Right.AreaByte
case 8: case 8:
return c.Right.FrameAndUnknownByte return c.Right.SpriteAndFlagByte
case 9: case 9:
return c.Center.AreaByte return c.Center.AreaByte
case 10: case 10:
return c.Center.FrameAndUnknownByte return c.Center.SpriteAndFlagByte
case 11: case 11:
return c.Unknown11 return c.Unknown11
case 12: case 12:
@@ -139,7 +145,6 @@ func (c *Cell) At(n int) byte {
// Cells is always a fixed size; use At to get a cell according to x,y,z // Cells is always a fixed size; use At to get a cell according to x,y,z
type Cells []Cell type Cells []Cell
// FIXME: Ordering may be incorrect? I assume z,y,x for now...
func (c Cells) At(x, y, z int) Cell { func (c Cells) At(x, y, z int) Cell {
return c[(z*MaxLength*MaxWidth)+(y*MaxWidth)+x] return c[(z*MaxLength*MaxWidth)+(y*MaxWidth)+x]
} }