More map trailer work

This commit is contained in:
2020-06-08 00:24:57 +01:00
parent a6fdbaef2b
commit e8e9811b5d
2 changed files with 107 additions and 27 deletions

View File

@@ -518,8 +518,6 @@ Around 001841A0: mission objectives!
00184240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00184240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
``` ```
The size of the trailer for Chapter01 is 139,483 bytes.
Relative offsets from the start of the trailer, we have: Relative offsets from the start of the trailer, we have:
| Offset | Text | | Offset | Text |
@@ -581,30 +579,38 @@ TINYSQUAD.MAP.Trailer
0000 0050: 00 00 00 32 00 00 00 00 00 00 00 00 00 00 00 00 ...2.... ........ 0000 0050: 00 00 00 32 00 00 00 00 00 00 00 00 00 00 00 00 ...2.... ........
``` ```
here's a first guess at a header: The size of the trailer for Chapter01 is 139,483 bytes, assuming it starts at
`0x163890`. However, things may be a lot more sensible if we drop 3 bytes off
the start of that to get the fields into little-endian alignment. Have I made a
maths error above somewhere? Is it some sort of alignment thing? Do those 3
bytes actually have meaning?
Ignoring them for now, here's a first guess at a header:
| Offset | Size | Meaning | | Offset | Size | Meaning |
| ------ | ---- | ------- | | ------ | ---- | ------- |
| 0 | 2 | ??? - invariant `38 00` | | 0 | 4 | Map maximum X + 1 |
| 2 | 2 | ??? - varies | | 4 | 4 | Map maximum Y + 1 |
| 4 | 4 | ??? - varies | | 8 | 4 | Map minimum X |
| 8 | 4 | ??? - varies | | 12 | 4 | Map minimum Y |
| 12 | 4 | ??? - varies | | 16 | 4 | Number of character records |
| 16 | 4 | Number of character records (58 vs 5) | | 20 | 4 | Padding? - invariant `00 00 00 00` |
| 20 | 4 | ??? - invariant `00 00 00 00` |
| 24 | 2 | ??? - varies. Seems related to character/squad position? | | 24 | 2 | ??? - varies. Seems related to character/squad position? |
| 26 | 2 | ??? - invariant `00 04` | | 26 | 2 | ??? - invariant `00 04` |
| 28 | 4 | ??? - varies (0 vs 5) | | 28 | 4 | ??? - varies (0 vs 5) |
| 32 | 4 | Number of objective/event records (26 vs 1) | | 32 | 4 | Number of thingies (26 vs 1) |
| 36 | 36? | Padding? | | 36 | 20 | Padding? |
56 bytes of data is interesting because the value of that first, ignored byte is
0x38 - perhaps it's a skip value + 2 bytes of padding? It's just weird. Keep
ignoring it for now.
0x4b contains the next non-null byte; is the gap between the the number of 0x4b contains the next non-null byte; is the gap between the the number of
objectives, and it, padding? Minus a bit? 0x50 is another non-null byte. Then thingies, and it, padding? Minus a bit? 0x50 is another non-null byte. Then
it's all zeroes until one byte before the first name at 0xee. it's all zeroes until one byte before the first name at 0xee.
It's hard to say where the alignment should be at this point. We need to compare It's hard to say where the alignment should be at this point. We need to compare
more characters with each other. We might also be able to determine framing by more characters with each other. Other notes...
looking at the *end* of the character block.
Characters are organised into Squads somehow. Characters are organised into Squads somehow.
@@ -615,6 +621,18 @@ per-character records also. There are several candidates for this.
Placing a single character at (64,49) causes those bytes to show up at four Placing a single character at (64,49) causes those bytes to show up at four
offsets - 0x18 (!), 0x1F4, 0x1F8, and 0x6C8. offsets - 0x18 (!), 0x1F4, 0x1F8, and 0x6C8.
Generating a map with no characters at all, the trailer is 2,447 bytes, and the
mission title starts at 0x3B (59). So we can say we have 20 bytes of padding as
a first approximation?
The "trailer trailer", for want of a better term, seems to be organised as:
| Offset | Size | Meaning |
| ----- | ---- | ------- |
| 0 | 255 | Title |
| 255 | 2048 | Briefing |
| 2304 | 85 | ??? - each byte is 1 or 0. Spaced so it may be partly uint32 |
## Soldiers At War ## Soldiers At War
@@ -695,3 +713,11 @@ xxd -s 0xc0 -c 13 -l 260 -g 13 BIGGESTMAP.MAP
000000e7: 00 00 85 01 00 00 00 00 00 ff 00 00 1f ............. 000000e7: 00 00 85 01 00 00 00 00 00 ff 00 00 1f .............
# ... # ...
``` ```
This can be interpreted more or less the same way as the Chaos Gate maps now,
and the `soldiers-at-war` branch contains a hacked-up implementation that kind
of works \o/.
Does the same trailer apply?

View File

@@ -48,25 +48,40 @@ type Header struct {
// Need to investigate the rest of the header too // Need to investigate the rest of the header too
} }
type Trailer struct { type TrailerHeader struct {
Unknown1 uint16 Discard1 [3]byte // No idea what this lot is
Unknown2 uint16 MaxWidth uint32
Unknown3 uint32 MaxLength uint32
Unknown4 uint32 MinWidth uint32
Unknown5 uint32 MinLength uint32
NumCharacters uint32 NumCharacters uint32
Padding1 uint32
Unknown6 uint16 Unknown1 uint32
Unknown7 uint16 Unknown2 uint16
Unknown8 uint32 Unknown3 uint16
Unknown4 uint32
NumThingies uint32 NumThingies uint32
Padding2 [36]byte Padding1 [20]byte
}
type TrailerTrailer struct {
Title [255]byte
Briefing [2048]byte
Unknown1 [85]uint8 // Maybe? each contains either 0 or 1? Hard to say
} }
type Character struct { type Character struct {
Unknown1 uint32 Unknown1 uint32
} }
type Characters []Character
// TODO. These are triggers/reactors/etc.
type Thingy struct {}
type Thingies []Thingy
func (h Header) Width() int { func (h Header) Width() int {
return int(h.MaxWidth - h.MinWidth) return int(h.MaxWidth - h.MinWidth)
} }
@@ -189,7 +204,14 @@ func (h Header) Check() []error {
type GameMap struct { type GameMap struct {
Header Header
Cells Cells
// TODO: parse this into sections TrailerHeader
Characters
Thingies
TrailerTrailer
// TODO: parse this into sections. This is the text that comes from the
// .TXT file. Maybe we don't need it at all since it should be duplicated in
// the trailer.
Text string Text string
} }
@@ -305,5 +327,37 @@ func loadMapFile(filename string) (*GameMap, error) {
return nil, fmt.Errorf("Error parsing cells for %s: %v", filename, err) return nil, fmt.Errorf("Error parsing cells for %s: %v", filename, err)
} }
if err := binary.Read(zr, binary.LittleEndian, &out.TrailerHeader); err != nil {
return nil, fmt.Errorf("Error parsing trailer header for %s: %v", filename, err)
}
log.Printf("Trailer Header: %#+v", out.TrailerHeader)
/*
// TODO: until we know how large each character record should be, we can't read this lot
out.Characters = make(Characters, int(out.TrailerHeader.NumCharacters))
if err := binary.Read(zr, binary.LittleEndian, &out.Characters); err != nil {
return nil, fmt.Errorf("Error parsing characters for %s: %v", filename, err)
}
out.Thingies = make(Thingies, int(out.TrailerHeader.NumThingies))
if err := binary.Read(zr, binary.LittleEndian, &out.Thingies); err != nil {
return nil, fmt.Errorf("Error parsing thingies for %s: %v", filename, err)
}
if err := binary.Read(zr, binary.LittleEndian, &out.TrailerTrailer); err != nil {
return nil, fmt.Errorf("Error parsing trailer trailer for %s: %v", filename, err)
}
log.Printf("Trailer Trailer: %s", out.TrailerTrailer.String())
*/
return &out, nil return &out, nil
} }
func (t *TrailerTrailer) String() string {
return fmt.Sprintf(
"title=%q briefing=%q rest=%#+v",
strings.TrimRight(string(t.Title[:]), "\x00"),
strings.TrimRight(string(t.Briefing[:]), "\x00"),
t.Unknown1,
)
}