Formalise a bit in each cell as an "IsActive()" bit
This commit is contained in:
@@ -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) {
|
||||||
|
@@ -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:
|
||||||
|
@@ -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))
|
||||||
|
@@ -70,7 +70,7 @@ 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]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user