mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-11-14 00:06:45 -05:00
WIP
This commit is contained in:
parent
a33117fb56
commit
5dfca5e9f3
@ -1,20 +0,0 @@
|
||||
package d2enum
|
||||
|
||||
// LayerStreamType represents a layer stream type
|
||||
type LayerStreamType int
|
||||
|
||||
// Layer stream types
|
||||
const (
|
||||
LayerStreamWall1 LayerStreamType = iota
|
||||
LayerStreamWall2
|
||||
LayerStreamWall3
|
||||
LayerStreamWall4
|
||||
LayerStreamOrientation1
|
||||
LayerStreamOrientation2
|
||||
LayerStreamOrientation3
|
||||
LayerStreamOrientation4
|
||||
LayerStreamFloor1
|
||||
LayerStreamFloor2
|
||||
LayerStreamShadow
|
||||
LayerStreamSubstitute
|
||||
)
|
@ -1,2 +1,2 @@
|
||||
// Package d2ds1 provides functionality for loading/processing DS1 files
|
||||
// Package d2ds1 provides functionality for loading/processing DS1 Files
|
||||
package d2ds1
|
||||
|
File diff suppressed because it is too large
Load Diff
432
d2common/d2fileformats/d2ds1/ds1_layers.go
Normal file
432
d2common/d2fileformats/d2ds1/ds1_layers.go
Normal file
@ -0,0 +1,432 @@
|
||||
package d2ds1
|
||||
|
||||
const (
|
||||
maxWallLayers = 4
|
||||
maxOrientationLayers = 4
|
||||
maxFloorLayers = 2
|
||||
maxShadowLayers = 1
|
||||
maxSubstitutionLayers = 1
|
||||
)
|
||||
|
||||
type layerGroupType int
|
||||
|
||||
const (
|
||||
floorLayerGroup layerGroupType = iota
|
||||
wallLayerGroup
|
||||
orientationLayerGroup
|
||||
shadowLayerGroup
|
||||
substitutionLayerGroup
|
||||
)
|
||||
|
||||
type layerGroup []*layer
|
||||
|
||||
type ds1Layers struct {
|
||||
width, height int
|
||||
Floors layerGroup
|
||||
Walls layerGroup
|
||||
Orientations layerGroup
|
||||
Shadows layerGroup
|
||||
Substitutions layerGroup
|
||||
}
|
||||
|
||||
func (l *ds1Layers) ensureInit() {
|
||||
if l.Floors == nil {
|
||||
l.Floors = make(layerGroup, 0)
|
||||
}
|
||||
|
||||
if l.Walls == nil {
|
||||
l.Walls = make(layerGroup, 0)
|
||||
}
|
||||
|
||||
if l.Orientations == nil {
|
||||
l.Orientations = make(layerGroup, 0)
|
||||
}
|
||||
|
||||
if l.Shadows == nil {
|
||||
l.Shadows = make(layerGroup, 0)
|
||||
}
|
||||
|
||||
if l.Substitutions == nil {
|
||||
l.Substitutions = make(layerGroup, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// removes nil layers from all layer groups
|
||||
func (l *ds1Layers) cull() {
|
||||
l.cullNilLayers(floorLayerGroup)
|
||||
l.cullNilLayers(wallLayerGroup)
|
||||
l.cullNilLayers(orientationLayerGroup)
|
||||
l.cullNilLayers(shadowLayerGroup)
|
||||
l.cullNilLayers(substitutionLayerGroup)
|
||||
}
|
||||
|
||||
// removes nil layers of given layer group type
|
||||
func (l *ds1Layers) cullNilLayers(t layerGroupType) {
|
||||
var group *layerGroup
|
||||
|
||||
switch t {
|
||||
case floorLayerGroup:
|
||||
group = &l.Floors
|
||||
case wallLayerGroup:
|
||||
group = &l.Walls
|
||||
case orientationLayerGroup:
|
||||
group = &l.Orientations
|
||||
case shadowLayerGroup:
|
||||
group = &l.Shadows
|
||||
case substitutionLayerGroup:
|
||||
group = &l.Substitutions
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
// from last to first layer, remove first encountered nil layer and restart the culling procedure.
|
||||
// exit culling procedure when no nil layers are found in entire group.
|
||||
culling:
|
||||
for {
|
||||
for idx := len(*group) - 1; idx > 0; idx-- {
|
||||
if (*group)[idx] == nil {
|
||||
*group = (*group)[:idx]
|
||||
continue culling
|
||||
}
|
||||
}
|
||||
|
||||
break culling // encountered no new nil layers
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ds1Layers) Size() (w, h int) {
|
||||
l.ensureInit()
|
||||
l.cull()
|
||||
|
||||
return l.width, l.height
|
||||
}
|
||||
|
||||
func (l *ds1Layers) SetSize(w, h int) {
|
||||
l.width, l.height = w, h
|
||||
|
||||
l.enforceSize(floorLayerGroup)
|
||||
l.enforceSize(wallLayerGroup)
|
||||
l.enforceSize(orientationLayerGroup)
|
||||
l.enforceSize(shadowLayerGroup)
|
||||
l.enforceSize(substitutionLayerGroup)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) enforceSize(t layerGroupType) {
|
||||
l.ensureInit()
|
||||
l.cull()
|
||||
|
||||
var group *layerGroup
|
||||
|
||||
switch t {
|
||||
case floorLayerGroup:
|
||||
group = &l.Floors
|
||||
case wallLayerGroup:
|
||||
group = &l.Walls
|
||||
case orientationLayerGroup:
|
||||
group = &l.Orientations
|
||||
case shadowLayerGroup:
|
||||
group = &l.Shadows
|
||||
case substitutionLayerGroup:
|
||||
group = &l.Substitutions
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
for idx := range *group {
|
||||
(*group)[idx].SetSize(l.width, l.height)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ds1Layers) Width() int {
|
||||
w, _ := l.Size()
|
||||
return w
|
||||
}
|
||||
|
||||
func (l *ds1Layers) SetWidth(w int) {
|
||||
l.SetSize(w, l.height)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) Height() int {
|
||||
_, h := l.Size()
|
||||
return h
|
||||
}
|
||||
|
||||
func (l *ds1Layers) SetHeight(h int) {
|
||||
l.SetSize(l.width, h)
|
||||
}
|
||||
|
||||
// generic push func for all layer types
|
||||
func (l *ds1Layers) push(t layerGroupType, layer *layer) {
|
||||
l.ensureInit()
|
||||
l.cull()
|
||||
|
||||
var group *layerGroup
|
||||
|
||||
var max int
|
||||
|
||||
switch t {
|
||||
case floorLayerGroup:
|
||||
group = &l.Floors
|
||||
max = maxFloorLayers
|
||||
case wallLayerGroup:
|
||||
group = &l.Walls
|
||||
max = maxWallLayers
|
||||
case orientationLayerGroup:
|
||||
group = &l.Orientations
|
||||
max = maxOrientationLayers
|
||||
case shadowLayerGroup:
|
||||
group = &l.Shadows
|
||||
max = maxShadowLayers
|
||||
case substitutionLayerGroup:
|
||||
group = &l.Substitutions
|
||||
max = maxSubstitutionLayers
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
if len(*group) < max {
|
||||
*group = append(*group, layer)
|
||||
}
|
||||
}
|
||||
|
||||
// generic pop func for all layer types
|
||||
func (l *ds1Layers) pop(t layerGroupType) *layer {
|
||||
l.ensureInit()
|
||||
l.cull()
|
||||
|
||||
var group *layerGroup
|
||||
|
||||
var theLayer *layer
|
||||
|
||||
switch t {
|
||||
case floorLayerGroup:
|
||||
group = &l.Floors
|
||||
case wallLayerGroup:
|
||||
group = &l.Walls
|
||||
case orientationLayerGroup:
|
||||
group = &l.Orientations
|
||||
case shadowLayerGroup:
|
||||
group = &l.Shadows
|
||||
case substitutionLayerGroup:
|
||||
group = &l.Substitutions
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
// remove last layer of slice and return it
|
||||
if len(*group) > 0 {
|
||||
lastIdx := len(*group) - 1
|
||||
theLayer = (*group)[lastIdx]
|
||||
*group = (*group)[:lastIdx]
|
||||
|
||||
return theLayer
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *ds1Layers) get(t layerGroupType, idx int) *layer {
|
||||
l.ensureInit()
|
||||
l.cull()
|
||||
|
||||
var group *layerGroup
|
||||
|
||||
switch t {
|
||||
case floorLayerGroup:
|
||||
group = &l.Floors
|
||||
case wallLayerGroup:
|
||||
group = &l.Walls
|
||||
case orientationLayerGroup:
|
||||
group = &l.Orientations
|
||||
case shadowLayerGroup:
|
||||
group = &l.Shadows
|
||||
case substitutionLayerGroup:
|
||||
group = &l.Substitutions
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
if idx >= len(*group) || idx < 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (*group)[idx]
|
||||
}
|
||||
|
||||
func (l *ds1Layers) insert(t layerGroupType, idx int, newLayer *layer) {
|
||||
l.ensureInit()
|
||||
l.cull()
|
||||
|
||||
if newLayer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var group layerGroup
|
||||
|
||||
switch t {
|
||||
case floorLayerGroup:
|
||||
group = l.Floors
|
||||
case wallLayerGroup:
|
||||
group = l.Walls
|
||||
case orientationLayerGroup:
|
||||
group = l.Orientations
|
||||
case shadowLayerGroup:
|
||||
group = l.Shadows
|
||||
case substitutionLayerGroup:
|
||||
group = l.Substitutions
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
if len(group) == 0 {
|
||||
group = append(group, newLayer) // nolint:staticcheck // we possibly use group later
|
||||
return
|
||||
}
|
||||
|
||||
if idx > len(group)-1 {
|
||||
idx = len(group) - 1
|
||||
}
|
||||
|
||||
// example:
|
||||
// suppose
|
||||
// idx=1
|
||||
// newLayer=c
|
||||
// existing layerGroup is [a, b]
|
||||
group = append(group, group[idx:]...) // [a, b] becomes [a, b, b]
|
||||
group[idx] = newLayer // [a, b, b] becomes [a, c, b]
|
||||
}
|
||||
|
||||
func (l *ds1Layers) delete(t layerGroupType, idx int) {
|
||||
l.ensureInit()
|
||||
l.cull()
|
||||
|
||||
var group layerGroup
|
||||
|
||||
switch t {
|
||||
case floorLayerGroup:
|
||||
group = l.Floors
|
||||
case wallLayerGroup:
|
||||
group = l.Walls
|
||||
case orientationLayerGroup:
|
||||
group = l.Orientations
|
||||
case shadowLayerGroup:
|
||||
group = l.Shadows
|
||||
case substitutionLayerGroup:
|
||||
group = l.Substitutions
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
if idx >= len(group) || idx < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
group[idx] = nil
|
||||
|
||||
l.cull()
|
||||
}
|
||||
|
||||
func (l *ds1Layers) GetFloor(idx int) *layer {
|
||||
return l.get(floorLayerGroup, idx)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) PushFloor(floor *layer) *ds1Layers {
|
||||
l.push(floorLayerGroup, floor)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *ds1Layers) PopFloor() *layer {
|
||||
return l.pop(floorLayerGroup)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) InsertFloor(idx int, newFloor *layer) {
|
||||
l.insert(floorLayerGroup, idx, newFloor)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) DeleteFloor(idx int) {
|
||||
l.delete(floorLayerGroup, idx)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) GetWall(idx int) *layer {
|
||||
return l.get(wallLayerGroup, idx)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) PushWall(wall *layer) *ds1Layers {
|
||||
l.push(wallLayerGroup, wall)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *ds1Layers) PopWall() *layer {
|
||||
return l.pop(wallLayerGroup)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) InsertWall(idx int, newWall *layer) {
|
||||
l.insert(wallLayerGroup, idx, newWall)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) DeleteWall(idx int) {
|
||||
l.delete(wallLayerGroup, idx)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) GetOrientation(idx int) *layer {
|
||||
return l.get(orientationLayerGroup, idx)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) PushOrientation(orientation *layer) *ds1Layers {
|
||||
l.push(orientationLayerGroup, orientation)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *ds1Layers) PopOrientation() *layer {
|
||||
return l.pop(orientationLayerGroup)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) InsertOrientation(idx int, newOrientation *layer) {
|
||||
l.insert(orientationLayerGroup, idx, newOrientation)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) DeleteOrientation(idx int) {
|
||||
l.delete(orientationLayerGroup, idx)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) GetShadow(idx int) *layer {
|
||||
return l.get(shadowLayerGroup, idx)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) PushShadow(shadow *layer) *ds1Layers {
|
||||
l.push(shadowLayerGroup, shadow)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *ds1Layers) PopShadow() *layer {
|
||||
return l.pop(shadowLayerGroup)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) InsertShadow(idx int, newShadow *layer) {
|
||||
l.insert(shadowLayerGroup, idx, newShadow)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) DeleteShadow(idx int) {
|
||||
l.delete(shadowLayerGroup, idx)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) GetSubstitution(idx int) *layer {
|
||||
return l.get(substitutionLayerGroup, idx)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) PushSubstitution(sub *layer) *ds1Layers {
|
||||
l.push(substitutionLayerGroup, sub)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *ds1Layers) PopSubstitution() *layer {
|
||||
return l.pop(substitutionLayerGroup)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) InsertSubstitution(idx int, newSubstitution *layer) {
|
||||
l.insert(shadowLayerGroup, idx, newSubstitution)
|
||||
}
|
||||
|
||||
func (l *ds1Layers) DeleteSubstitution(idx int) {
|
||||
l.delete(shadowLayerGroup, idx)
|
||||
}
|
152
d2common/d2fileformats/d2ds1/ds1_layers_test.go
Normal file
152
d2common/d2fileformats/d2ds1/ds1_layers_test.go
Normal file
@ -0,0 +1,152 @@
|
||||
package d2ds1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_ds1Layers_DeleteFloor(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_DeleteOrientation(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_DeleteShadow(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_DeleteSubstitution(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_DeleteWall(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_GetFloor(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_GetOrientation(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_GetShadow(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_GetSubstitution(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_GetWall(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_InsertFloor(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_InsertOrientation(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_InsertShadow(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_InsertSubstitution(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_InsertWall(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_PopFloor(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_PopOrientation(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_PopShadow(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_PopSubstitution(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_PopWall(t *testing.T) {}
|
||||
|
||||
func Test_ds1Layers_Push(t *testing.T) {
|
||||
t.Run("Floor", func(t *testing.T) {
|
||||
test_ds1Layers_PushLayer(floorLayerGroup, t)
|
||||
})
|
||||
|
||||
t.Run("Wall", func(t *testing.T) {
|
||||
test_ds1Layers_PushLayer(wallLayerGroup, t)
|
||||
})
|
||||
|
||||
t.Run("Orientation", func(t *testing.T) {
|
||||
test_ds1Layers_PushLayer(orientationLayerGroup, t)
|
||||
})
|
||||
|
||||
t.Run("Shadow", func(t *testing.T) {
|
||||
test_ds1Layers_PushLayer(shadowLayerGroup, t)
|
||||
})
|
||||
|
||||
t.Run("Substitution", func(t *testing.T) {
|
||||
test_ds1Layers_PushLayer(substitutionLayerGroup, t)
|
||||
})
|
||||
}
|
||||
|
||||
// for all layer types, the test is the same
|
||||
// when we push a layer, we expect an increment, and when we push a bunch of times,
|
||||
// we expect to never exceed the max. we also expect to be able to retrieve a non-nil
|
||||
// layer after we push.
|
||||
func test_ds1Layers_PushLayer(lt layerGroupType, t *testing.T) {
|
||||
layers := &ds1Layers{}
|
||||
|
||||
// we need to set up some shit to handle the test in a generic way
|
||||
var push func()
|
||||
|
||||
var get func(idx int) *layer
|
||||
|
||||
var max int
|
||||
|
||||
var group *layerGroup
|
||||
|
||||
check := func(expected int) {
|
||||
actual := len(*group)
|
||||
got := get(expected - 1)
|
||||
|
||||
if actual != expected {
|
||||
t.Fatalf("unexpected number of layers: expected %d, got %d", expected, actual)
|
||||
}
|
||||
|
||||
if got == nil {
|
||||
t.Fatal("got nil layer")
|
||||
}
|
||||
}
|
||||
|
||||
switch lt {
|
||||
case floorLayerGroup:
|
||||
push = func() { layers.PushFloor(&layer{}) }
|
||||
get = layers.GetFloor
|
||||
max = maxFloorLayers
|
||||
group = &layers.Floors
|
||||
case wallLayerGroup:
|
||||
push = func() { layers.PushWall(&layer{}) }
|
||||
get = layers.GetWall
|
||||
max = maxWallLayers
|
||||
group = &layers.Walls
|
||||
case orientationLayerGroup:
|
||||
push = func() { layers.PushOrientation(&layer{}) }
|
||||
get = layers.GetOrientation
|
||||
max = maxOrientationLayers
|
||||
group = &layers.Orientations
|
||||
case shadowLayerGroup:
|
||||
push = func() { layers.PushShadow(&layer{}) }
|
||||
get = layers.GetShadow
|
||||
max = maxShadowLayers
|
||||
group = &layers.Shadows
|
||||
case substitutionLayerGroup:
|
||||
push = func() { layers.PushSubstitution(&layer{}) }
|
||||
get = layers.GetSubstitution
|
||||
max = maxSubstitutionLayers
|
||||
group = &layers.Substitutions
|
||||
default:
|
||||
t.Fatal("unknown layer type given")
|
||||
}
|
||||
|
||||
// push one time, we expect a single layer to exist
|
||||
push()
|
||||
check(1)
|
||||
|
||||
// if we push a bunch of times, we expect to not exceed the max
|
||||
push()
|
||||
push()
|
||||
push()
|
||||
push()
|
||||
push()
|
||||
push()
|
||||
push()
|
||||
push()
|
||||
push()
|
||||
push()
|
||||
check(max)
|
||||
}
|
||||
|
||||
func test_ds1Layers_PopLayer(lt layerGroupType, t *testing.T) {}
|
||||
|
||||
func test_ds1Layers_InsertLayer(lt layerGroupType, t *testing.T) {}
|
||||
|
||||
func test_ds1Layers_DeleteLayer(lt layerGroupType, t *testing.T) {}
|
||||
|
||||
func test_ds1Layers_GetLayer(lt layerGroupType, t *testing.T) {}
|
@ -1,665 +1 @@
|
||||
package d2ds1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2path"
|
||||
)
|
||||
|
||||
func exampleDS1() *DS1 {
|
||||
return &DS1{
|
||||
files: []string{"a.dt1", "b.dt1"},
|
||||
objects: []Object{
|
||||
{0, 0, 0, 0, 0, nil},
|
||||
{0, 1, 0, 0, 0, []d2path.Path{{}}},
|
||||
{0, 2, 0, 0, 0, nil},
|
||||
{0, 3, 0, 0, 0, nil},
|
||||
},
|
||||
tiles: [][]Tile{ // 2x2
|
||||
{
|
||||
Tile{
|
||||
[]Floor{{}},
|
||||
[]Wall{{}},
|
||||
[]Shadow{{}},
|
||||
[]Substitution{{}},
|
||||
},
|
||||
Tile{
|
||||
[]Floor{{}},
|
||||
[]Wall{{}},
|
||||
[]Shadow{{}},
|
||||
[]Substitution{{}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Tile{
|
||||
[]Floor{{}},
|
||||
[]Wall{{}},
|
||||
[]Shadow{{}},
|
||||
[]Substitution{{}},
|
||||
},
|
||||
Tile{
|
||||
[]Floor{{}},
|
||||
[]Wall{{}},
|
||||
[]Shadow{{}},
|
||||
[]Substitution{{}},
|
||||
},
|
||||
},
|
||||
},
|
||||
substitutionGroups: nil,
|
||||
version: 17,
|
||||
width: 2,
|
||||
height: 2,
|
||||
act: 1,
|
||||
substitutionType: 0,
|
||||
numberOfWallLayers: 1,
|
||||
numberOfFloorLayers: 1,
|
||||
numberOfShadowLayers: 1,
|
||||
numberOfSubstitutionLayers: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// checks, if DS1 structure could be marshaled and unmarshaled
|
||||
func testIfRestorable(ds1 *DS1, test func(ds1 *DS1)) error {
|
||||
test(ds1)
|
||||
|
||||
var err error
|
||||
|
||||
data := ds1.Marshal()
|
||||
|
||||
newDS1, err := LoadDS1(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
test(newDS1)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestDS1_Marshal(t *testing.T) {
|
||||
a := exampleDS1()
|
||||
|
||||
bytes := a.Marshal()
|
||||
|
||||
b, err := LoadDS1(bytes)
|
||||
if err != nil {
|
||||
t.Error("could not load new ds1 from marshaled ds1 data")
|
||||
return
|
||||
}
|
||||
|
||||
if b.width != a.width {
|
||||
t.Error("new ds1 does not match original")
|
||||
}
|
||||
|
||||
if len(b.tiles) != len(a.tiles) {
|
||||
t.Error("new ds1 does not batch original")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_Files(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
files := ds1.Files()
|
||||
|
||||
for idx := range files {
|
||||
if ds1.files[idx] != files[idx] {
|
||||
t.Error("unexpected files from ds1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_AddFile(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
numBefore := len(ds1.files)
|
||||
|
||||
ds1.AddFile("other.ds1")
|
||||
|
||||
numAfter := len(ds1.files)
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if (numBefore + 1) != numAfter {
|
||||
t.Error("unexpected number of files in ds1")
|
||||
}
|
||||
}
|
||||
|
||||
if err := testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_RemoveFile(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
numBefore := len(ds1.files)
|
||||
|
||||
err := ds1.RemoveFile("nonexistant file")
|
||||
if err == nil {
|
||||
t.Fatal("file 'nonexistant file' doesn't exist but ds1.RemoveFile doesn't return error")
|
||||
}
|
||||
|
||||
if len(ds1.files) != numBefore {
|
||||
t.Error("file removed when it should not have been")
|
||||
}
|
||||
|
||||
filename := "c.ds1"
|
||||
|
||||
ds1.AddFile(filename)
|
||||
|
||||
if len(ds1.files) == numBefore {
|
||||
t.Error("file not added when it should have been")
|
||||
}
|
||||
|
||||
err = ds1.RemoveFile(filename)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if len(ds1.files) != numBefore {
|
||||
t.Error("file not removed when it should have been")
|
||||
}
|
||||
}
|
||||
|
||||
if err := testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_Objects(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
objects := ds1.Objects()
|
||||
|
||||
for idx := range ds1.objects {
|
||||
if !ds1.objects[idx].Equals(&objects[idx]) {
|
||||
t.Error("unexpected object")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_AddObject(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
numBefore := len(ds1.objects)
|
||||
|
||||
ds1.AddObject(Object{})
|
||||
|
||||
numAfter := len(ds1.objects)
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if (numBefore + 1) != numAfter {
|
||||
t.Error("unexpected number of objects in ds1")
|
||||
}
|
||||
}
|
||||
|
||||
if err := testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_RemoveObject(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
nice := 69420
|
||||
|
||||
obj := Object{
|
||||
ID: nice,
|
||||
}
|
||||
|
||||
ds1.AddObject(obj)
|
||||
|
||||
numBefore := len(ds1.objects)
|
||||
|
||||
ds1.RemoveObject(obj)
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if len(ds1.objects) == numBefore {
|
||||
t.Error("did not remove object when expected")
|
||||
}
|
||||
}
|
||||
|
||||
if err := testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_Tiles(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
tiles := ds1.Tiles()
|
||||
|
||||
for y := range tiles {
|
||||
for x := range tiles[y] {
|
||||
if len(ds1.tiles[y][x].Floors) != len(tiles[y][x].Floors) {
|
||||
t.Fatal("number of tile's floors returned by ds1.Tiles() isn't same as real number")
|
||||
}
|
||||
|
||||
if ds1.tiles[y][x].Walls[0] != tiles[y][x].Walls[0] {
|
||||
t.Fatal("wall record returned by ds1.Tiles isn't equal to real")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SetTiles(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
exampleTile1 := Tile{
|
||||
Floors: []floorShadow{
|
||||
{8, 7, 2, 3, 4, 55, 33, true, 999},
|
||||
},
|
||||
Walls: []Wall{
|
||||
{2, 3, 4, 5, 3, 2, 3, 0, 33, 99},
|
||||
{2, 3, 4, 5, 3, 2, 3, 0, 33, 99},
|
||||
},
|
||||
Shadows: []floorShadow{
|
||||
{2, 4, 5, 33, 6, 7, 0, false, 1024},
|
||||
},
|
||||
}
|
||||
|
||||
exampleTile2 := Tile{
|
||||
Floors: []floorShadow{
|
||||
{9, 9, 2, 3, 4, 55, 33, true, 999},
|
||||
{9, 8, 2, 3, 102, 55, 33, true, 999},
|
||||
},
|
||||
Walls: []Wall{
|
||||
{2, 3, 4, 5, 3, 2, 3, 0, 33, 99},
|
||||
},
|
||||
Shadows: []floorShadow{
|
||||
{2, 4, 5, 33, 6, 7, 0, false, 1024},
|
||||
},
|
||||
}
|
||||
|
||||
tiles := [][]Tile{{exampleTile1, exampleTile2}, {exampleTile2, exampleTile1}}
|
||||
|
||||
ds1.SetTiles(tiles)
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if ds1.tiles[0][0].Floors[0].Prop1 != exampleTile1.Floors[0].Prop1 {
|
||||
t.Fatal("1,unexpected tile was set")
|
||||
}
|
||||
|
||||
if len(ds1.tiles[0][0].Walls) != len(exampleTile1.Walls) {
|
||||
t.Fatal("2,unexpected tile was set")
|
||||
}
|
||||
|
||||
if ds1.tiles[0][1].Walls[0].Style != exampleTile2.Walls[0].Style {
|
||||
t.Fatal("3,unexpected tile was set")
|
||||
}
|
||||
|
||||
if len(ds1.tiles[0][0].Walls) != len(exampleTile1.Walls) {
|
||||
t.Fatal("4,unexpected tile was set")
|
||||
}
|
||||
}
|
||||
|
||||
if err := testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_Tile(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
x, y := 1, 0
|
||||
|
||||
if ds1.tiles[y][x].Floors[0] != ds1.Tile(x, y).Floors[0] {
|
||||
t.Fatal("ds1.Tile returned invalid value")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SetTile(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
exampleTile := Tile{
|
||||
Floors: []floorShadow{
|
||||
{5, 8, 9, 4, 3, 0, 0, true, 1024},
|
||||
},
|
||||
Walls: []Wall{
|
||||
{2, 0, 4, 5, 3, 2, 3, 0, 33, 99},
|
||||
{5, 8, 9, 4, 3, 0, 0, 124, 221, 12},
|
||||
},
|
||||
Shadows: []floorShadow{
|
||||
{2, 44, 99, 2, 4, 3, 2, true, 933},
|
||||
},
|
||||
}
|
||||
|
||||
ds1.SetTile(0, 0, &exampleTile)
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if ds1.tiles[0][0].Floors[0].Prop1 != exampleTile.Floors[0].Prop1 {
|
||||
t.Fatal("unexpected tile was set")
|
||||
}
|
||||
|
||||
if ds1.tiles[0][0].Walls[0].Zero != exampleTile.Walls[0].Zero {
|
||||
t.Fatal("unexpected tile was set")
|
||||
}
|
||||
|
||||
if len(ds1.tiles[0][0].Walls) != len(exampleTile.Walls) {
|
||||
t.Fatal("unexpected tile was set")
|
||||
}
|
||||
}
|
||||
|
||||
if err := testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_Version(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
version := ds1.version
|
||||
|
||||
if version != int32(ds1.Version()) {
|
||||
t.Fatal("version returned by ds1.Version() and real aren't equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SetVersion(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
newVersion := 8
|
||||
|
||||
ds1.SetVersion(newVersion)
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if newVersion != int(ds1.version) {
|
||||
t.Fatal("ds1.SetVersion set version incorrectly")
|
||||
}
|
||||
}
|
||||
|
||||
if err := testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_Width(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
if int(ds1.width) != ds1.Width() {
|
||||
t.Error("unexpected width")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SetWidth(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
var newWidth int32 = 4
|
||||
|
||||
ds1.SetWidth(int(newWidth))
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if newWidth != ds1.width {
|
||||
t.Fatal("unexpected width after set")
|
||||
}
|
||||
}
|
||||
|
||||
if err := testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_Height(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
if int(ds1.height) != ds1.Height() {
|
||||
t.Error("unexpected height")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SetHeight(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
var newHeight int32 = 5
|
||||
|
||||
ds1.SetHeight(int(newHeight))
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if newHeight != ds1.height {
|
||||
t.Fatal("unexpected heigth after set")
|
||||
}
|
||||
}
|
||||
|
||||
if err := testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_Act(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
if ds1.Act() != int(ds1.act) {
|
||||
t.Error("unexpected value in example ds1")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SetAct(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
ds1.SetAct(-1)
|
||||
|
||||
if ds1.Act() < 0 {
|
||||
t.Error("act cannot be less than 0")
|
||||
}
|
||||
|
||||
nice := 5
|
||||
|
||||
ds1.SetAct(nice)
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if int(ds1.act) != nice {
|
||||
t.Error("unexpected value for act")
|
||||
}
|
||||
}
|
||||
|
||||
if err := testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SubstitutionType(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
st := ds1.substitutionType
|
||||
|
||||
if int(st) != ds1.SubstitutionType() {
|
||||
t.Fatal("unexpected substitution type returned")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SetSubstitutionType(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
newST := 5
|
||||
|
||||
ds1.SetSubstitutionType(newST)
|
||||
|
||||
if ds1.substitutionType != int32(newST) {
|
||||
t.Fatal("unexpected substitutionType was set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_NumberOfWalls(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
if ds1.NumberOfWallLayers() != int(ds1.numberOfWallLayers) {
|
||||
t.Error("unexpected number of wall layers")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SetNumberOfWalls(t *testing.T) {
|
||||
var err error
|
||||
|
||||
ds1 := exampleDS1()
|
||||
|
||||
newNumber := int32(4)
|
||||
|
||||
err = ds1.SetNumberOfWallLayers(newNumber)
|
||||
if err != nil {
|
||||
t.Errorf("error setting number of walls: %v", err)
|
||||
}
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if len(ds1.tiles[0][0].Walls) != int(newNumber) {
|
||||
t.Fatal("unexpected walls length set")
|
||||
}
|
||||
|
||||
if ds1.NumberOfWallLayers() != int(newNumber) {
|
||||
t.Fatal("unexpected walls length set")
|
||||
}
|
||||
}
|
||||
|
||||
if err = testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
|
||||
newNumber = 1
|
||||
|
||||
err = ds1.SetNumberOfWallLayers(newNumber)
|
||||
if err != nil {
|
||||
t.Errorf("error setting number of walls: %v", err)
|
||||
}
|
||||
|
||||
test = func(ds1 *DS1) {
|
||||
if len(ds1.tiles[0][0].Walls) != int(newNumber) {
|
||||
t.Fatal("unexpected walls length set")
|
||||
}
|
||||
|
||||
if ds1.NumberOfWallLayers() != int(newNumber) {
|
||||
t.Fatal("unexpected walls length set")
|
||||
}
|
||||
}
|
||||
|
||||
if err = testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_NumberOfFloors(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
if ds1.NumberOfFloorLayers() != int(ds1.numberOfFloorLayers) {
|
||||
t.Error("unexpected number of floor layers")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SetNumberOfFloors(t *testing.T) {
|
||||
var err error
|
||||
|
||||
ds1 := exampleDS1()
|
||||
|
||||
newNumber := int32(2)
|
||||
|
||||
err = ds1.SetNumberOfFloorLayers(newNumber)
|
||||
if err != nil {
|
||||
t.Errorf("error setting number of floors: %v", err)
|
||||
}
|
||||
|
||||
test := func(ds1 *DS1) {
|
||||
if len(ds1.tiles[0][0].Floors) != int(newNumber) {
|
||||
t.Fatal("unexpected floors length set")
|
||||
}
|
||||
|
||||
if ds1.numberOfFloorLayers != newNumber {
|
||||
t.Fatal("unexpected floors length set")
|
||||
}
|
||||
}
|
||||
|
||||
if err = testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
|
||||
newNumber = 1
|
||||
|
||||
err = ds1.SetNumberOfFloorLayers(newNumber)
|
||||
if err != nil {
|
||||
t.Errorf("error setting number of floors: %v", err)
|
||||
}
|
||||
|
||||
test = func(ds1 *DS1) {
|
||||
if len(ds1.tiles[0][0].Floors) != int(newNumber) {
|
||||
t.Fatal("unexpected floors length set")
|
||||
}
|
||||
|
||||
if ds1.numberOfFloorLayers != newNumber {
|
||||
t.Fatal("unexpected floors length set")
|
||||
}
|
||||
}
|
||||
|
||||
if err = testIfRestorable(ds1, test); err != nil {
|
||||
t.Errorf("unable to restore: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_NumberOfShadowLayers(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
if ds1.NumberOfShadowLayers() != int(ds1.numberOfShadowLayers) {
|
||||
t.Error("unexpected number of shadow layers")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_NumberOfSubstitutionLayers(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
if ds1.NumberOfSubstitutionLayers() != int(ds1.numberOfSubstitutionLayers) {
|
||||
t.Error("unexpected number of substitution layers")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SubstitutionGroups(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
sg := ds1.SubstitutionGroups()
|
||||
|
||||
for i := 0; i < len(ds1.substitutionGroups); i++ {
|
||||
if sg[i] != ds1.substitutionGroups[i] {
|
||||
t.Fatal("unexpected substitution group returned")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_SetSubstitutionGroups(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
newGroup := []SubstitutionGroup{
|
||||
{
|
||||
TileX: 20,
|
||||
TileY: 12,
|
||||
WidthInTiles: 212,
|
||||
HeightInTiles: 334,
|
||||
Unknown: 1024,
|
||||
},
|
||||
}
|
||||
|
||||
ds1.SetSubstitutionGroups(newGroup)
|
||||
|
||||
if ds1.substitutionGroups[0] != newGroup[0] {
|
||||
t.Fatal("unexpected substitution group added")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDS1_GetStreamLayerTypes(t *testing.T) {
|
||||
ds1 := exampleDS1()
|
||||
|
||||
lst := []d2enum.LayerStreamType{
|
||||
d2enum.LayerStreamWall1,
|
||||
d2enum.LayerStreamOrientation1,
|
||||
d2enum.LayerStreamFloor1,
|
||||
d2enum.LayerStreamShadow,
|
||||
d2enum.LayerStreamSubstitute,
|
||||
}
|
||||
|
||||
layerStreamTypes := ds1.GetStreamLayerTypes()
|
||||
|
||||
if len(lst) != len(layerStreamTypes) {
|
||||
t.Fatal("unexpected length")
|
||||
}
|
||||
|
||||
for i := range lst {
|
||||
if lst[i] != layerStreamTypes[i] {
|
||||
t.Fatal("Unexpected type was set")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
59
d2common/d2fileformats/d2ds1/ds1_version.go
Normal file
59
d2common/d2fileformats/d2ds1/ds1_version.go
Normal file
@ -0,0 +1,59 @@
|
||||
package d2ds1
|
||||
|
||||
type ds1version int
|
||||
|
||||
const (
|
||||
v3 ds1version = 3
|
||||
v4 = 4
|
||||
v7 = 7
|
||||
v8 = 8
|
||||
v9 = 9
|
||||
v10 = 10
|
||||
v12 = 12
|
||||
v13 = 13
|
||||
v14 = 14
|
||||
v15 = 15
|
||||
v16 = 16
|
||||
v18 = 18
|
||||
)
|
||||
|
||||
func (v ds1version) hasUnknown1Bytes() bool {
|
||||
// just after the header will be some meaningless (?) bytes
|
||||
return v >= v9 && v <= v13
|
||||
}
|
||||
|
||||
func (v ds1version) hasUnknown2Bytes() bool {
|
||||
return v >= v18
|
||||
}
|
||||
|
||||
func (v ds1version) specifiesAct() bool {
|
||||
// in the header
|
||||
return v >= v8
|
||||
}
|
||||
|
||||
func (v ds1version) specifiesSubstitutionType() bool {
|
||||
// in the header
|
||||
return v >= v10
|
||||
}
|
||||
|
||||
func (v ds1version) specifiesWalls() bool {
|
||||
// just after header, specifies number of Walls
|
||||
return v >= v4
|
||||
}
|
||||
|
||||
func (v ds1version) specifiesFloors() bool {
|
||||
// just after header, specifies number of Floors
|
||||
return v >= v16
|
||||
}
|
||||
|
||||
func (v ds1version) hasFileList() bool {
|
||||
return v >= v3
|
||||
}
|
||||
|
||||
func (v ds1version) hasObjects() bool {
|
||||
return v >= v3
|
||||
}
|
||||
|
||||
func (v ds1version) hasSubstitutions() bool {
|
||||
return v >= v12
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
package d2ds1
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils"
|
||||
)
|
||||
|
||||
const (
|
||||
prop1Bitmask = 0x000000FF
|
||||
prop1Offset = 0
|
||||
prop1Length = 8
|
||||
|
||||
sequenceBitmask = 0x00003F00
|
||||
sequenceOffset = 8
|
||||
sequenceLength = 6
|
||||
|
||||
unknown1Bitmask = 0x000FC000
|
||||
unknown1Offset = 14
|
||||
unknown1Length = 6
|
||||
|
||||
styleBitmask = 0x03F00000
|
||||
styleOffset = 20
|
||||
styleLength = 6
|
||||
|
||||
unknown2Bitmask = 0x7C000000
|
||||
unknown2Offset = 26
|
||||
unknown2Length = 5
|
||||
|
||||
hiddenBitmask = 0x80000000
|
||||
hiddenOffset = 31
|
||||
hiddenLength = 1
|
||||
)
|
||||
|
||||
type floorShadow struct {
|
||||
Prop1 byte
|
||||
Sequence byte
|
||||
Unknown1 byte
|
||||
Style byte
|
||||
Unknown2 byte
|
||||
HiddenBytes byte
|
||||
RandomIndex byte
|
||||
Animated bool
|
||||
YAdjust int
|
||||
}
|
||||
|
||||
// Floor represents a floor record in a DS1 file. (it is just an alias of floorShadow).
|
||||
type Floor = floorShadow
|
||||
|
||||
// Shadow represents a shadow record in a DS1 file. (it is just an alias of floorShadow).
|
||||
type Shadow = floorShadow
|
||||
|
||||
// Hidden returns if floor/shadow is hidden
|
||||
func (f *Floor) Hidden() bool {
|
||||
return f.HiddenBytes > 0
|
||||
}
|
||||
|
||||
// Decode decodes floor-shadow record
|
||||
func (f *floorShadow) Decode(dw uint32) {
|
||||
f.Prop1 = byte((dw & prop1Bitmask) >> prop1Offset)
|
||||
f.Sequence = byte((dw & sequenceBitmask) >> sequenceOffset)
|
||||
f.Unknown1 = byte((dw & unknown1Bitmask) >> unknown1Offset)
|
||||
f.Style = byte((dw & styleBitmask) >> styleOffset)
|
||||
f.Unknown2 = byte((dw & unknown2Bitmask) >> unknown2Offset)
|
||||
f.HiddenBytes = byte((dw & hiddenBitmask) >> hiddenOffset)
|
||||
}
|
||||
|
||||
// Encode adds Floor's bits to stream writter given
|
||||
func (f *floorShadow) Encode(sw *d2datautils.StreamWriter) {
|
||||
sw.PushBits32(uint32(f.Prop1), prop1Length)
|
||||
sw.PushBits32(uint32(f.Sequence), sequenceLength)
|
||||
sw.PushBits32(uint32(f.Unknown1), unknown1Length)
|
||||
sw.PushBits32(uint32(f.Style), styleLength)
|
||||
sw.PushBits32(uint32(f.Unknown2), unknown2Length)
|
||||
sw.PushBits32(uint32(f.HiddenBytes), hiddenLength)
|
||||
}
|
143
d2common/d2fileformats/d2ds1/layer.go
Normal file
143
d2common/d2fileformats/d2ds1/layer.go
Normal file
@ -0,0 +1,143 @@
|
||||
package d2ds1
|
||||
|
||||
// layerStreamType represents a layer stream type
|
||||
type layerStreamType int
|
||||
|
||||
// Layer stream types
|
||||
const (
|
||||
layerStreamWall1 layerStreamType = iota
|
||||
layerStreamWall2
|
||||
layerStreamWall3
|
||||
layerStreamWall4
|
||||
layerStreamOrientation1
|
||||
layerStreamOrientation2
|
||||
layerStreamOrientation3
|
||||
layerStreamOrientation4
|
||||
layerStreamFloor1
|
||||
layerStreamFloor2
|
||||
layerStreamShadow1
|
||||
layerStreamSubstitute1
|
||||
)
|
||||
|
||||
type tileRow []Tile // index is x coordinate
|
||||
type tileGrid []tileRow // index is y coordinate
|
||||
|
||||
type grid interface {
|
||||
Width() int
|
||||
SetWidth(w int) grid
|
||||
|
||||
Height() int
|
||||
SetHeight(h int) grid
|
||||
|
||||
Size() (w, h int)
|
||||
SetSize(w, h int) grid
|
||||
|
||||
Tile(x, y int) *Tile
|
||||
SetTile(x, y int, t *Tile)
|
||||
}
|
||||
|
||||
type layer struct {
|
||||
tiles tileGrid
|
||||
}
|
||||
|
||||
func (l *layer) Tile(x, y int) *Tile {
|
||||
if l.Width() < x || l.Height() < y {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &l.tiles[y][x]
|
||||
}
|
||||
|
||||
func (l *layer) SetTile(x, y int, t *Tile) {
|
||||
if l.Width() > x || l.Height() > y {
|
||||
return
|
||||
}
|
||||
|
||||
l.tiles[y][x] = *t
|
||||
}
|
||||
|
||||
func (l *layer) Width() int {
|
||||
if len(l.tiles[0]) < 1 {
|
||||
l.SetWidth(1)
|
||||
}
|
||||
|
||||
return len(l.tiles[0])
|
||||
}
|
||||
|
||||
func (l *layer) SetWidth(w int) grid {
|
||||
if w < 1 {
|
||||
w = 1
|
||||
}
|
||||
|
||||
// ensure at least one row
|
||||
if len(l.tiles) < 1 {
|
||||
l.tiles = make(tileGrid, 1)
|
||||
}
|
||||
|
||||
// create/copy tiles as required to satisfy width
|
||||
for y := range l.tiles {
|
||||
if (w - len(l.tiles[y])) == 0 { // if requested width same as row width
|
||||
continue
|
||||
}
|
||||
|
||||
tmpRow := make(tileRow, w)
|
||||
|
||||
for x := range tmpRow {
|
||||
if x < len(l.tiles[y]) { // if tile exists
|
||||
tmpRow[x] = l.tiles[y][x] // copy it
|
||||
}
|
||||
}
|
||||
|
||||
l.tiles[y] = tmpRow
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *layer) Height() int {
|
||||
if len(l.tiles) < 1 {
|
||||
l.SetHeight(1)
|
||||
}
|
||||
|
||||
return len(l.tiles)
|
||||
}
|
||||
|
||||
func (l *layer) SetHeight(h int) grid {
|
||||
if h < 1 {
|
||||
h = 1
|
||||
}
|
||||
|
||||
// make tmpGrid to move existing tiles into
|
||||
tmpGrid := make(tileGrid, h)
|
||||
|
||||
for y := range tmpGrid {
|
||||
tmpGrid[y] = make(tileRow, l.Width())
|
||||
}
|
||||
|
||||
// move existing tiles over
|
||||
for y := range l.tiles {
|
||||
if y >= len(tmpGrid) {
|
||||
continue
|
||||
}
|
||||
|
||||
for x := range l.tiles[y] {
|
||||
if x >= len(tmpGrid[y]) {
|
||||
continue
|
||||
}
|
||||
|
||||
tmpGrid[y][x] = l.tiles[y][x]
|
||||
}
|
||||
}
|
||||
|
||||
l.tiles = tmpGrid
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *layer) Size() (w, h int) {
|
||||
return l.Width(), l.Height()
|
||||
}
|
||||
|
||||
func (l *layer) SetSize(w, h int) grid {
|
||||
return l.SetWidth(w).SetHeight(h)
|
||||
}
|
29
d2common/d2fileformats/d2ds1/layer_test.go
Normal file
29
d2common/d2fileformats/d2ds1/layer_test.go
Normal file
@ -0,0 +1,29 @@
|
||||
package d2ds1
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_layers(t *testing.T) {
|
||||
const (
|
||||
fmtWidthHeightError = "unexpected wall layer width/height: %dx%d"
|
||||
)
|
||||
|
||||
l := &layer{}
|
||||
|
||||
l.SetSize(0, 0)
|
||||
|
||||
if l.Width() != 1 || l.Height() != 1 {
|
||||
t.Fatalf(fmtWidthHeightError, l.Width(), l.Height())
|
||||
}
|
||||
|
||||
l.SetSize(4, 5)
|
||||
|
||||
if l.Width() != 4 || l.Height() != 5 {
|
||||
t.Fatalf(fmtWidthHeightError, l.Width(), l.Height())
|
||||
}
|
||||
|
||||
l.SetSize(4, 3)
|
||||
|
||||
if l.Width() != 4 || l.Height() != 3 {
|
||||
t.Fatalf(fmtWidthHeightError, l.Width(), l.Height())
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package d2ds1
|
||||
|
||||
// Substitution represents a substitution record in a DS1 file.
|
||||
type Substitution struct {
|
||||
Unknown uint32
|
||||
}
|
@ -1,18 +1,123 @@
|
||||
package d2ds1
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
)
|
||||
|
||||
const (
|
||||
prop1Bitmask = 0x000000FF
|
||||
prop1Offset = 0
|
||||
prop1Length = 8
|
||||
|
||||
sequenceBitmask = 0x00003F00
|
||||
sequenceOffset = 8
|
||||
sequenceLength = 6
|
||||
|
||||
unknown1Bitmask = 0x000FC000
|
||||
unknown1Offset = 14
|
||||
unknown1Length = 6
|
||||
|
||||
styleBitmask = 0x03F00000
|
||||
styleOffset = 20
|
||||
styleLength = 6
|
||||
|
||||
unknown2Bitmask = 0x7C000000
|
||||
unknown2Offset = 26
|
||||
unknown2Length = 5
|
||||
|
||||
hiddenBitmask = 0x80000000
|
||||
hiddenOffset = 31
|
||||
hiddenLength = 1
|
||||
)
|
||||
|
||||
type tileCommonFields struct {
|
||||
Type d2enum.TileType
|
||||
Zero byte
|
||||
Prop1 byte
|
||||
Sequence byte
|
||||
Unknown1 byte
|
||||
Style byte
|
||||
Unknown2 byte
|
||||
HiddenBytes byte
|
||||
RandomIndex byte
|
||||
YAdjust int
|
||||
}
|
||||
|
||||
type tileFloorShadowFields struct {
|
||||
Animated bool
|
||||
}
|
||||
|
||||
type tileSubstitutionFields struct {
|
||||
Substitution uint32 // unknown
|
||||
}
|
||||
|
||||
// Tile represents a tile record in a DS1 file.
|
||||
type Tile struct {
|
||||
Floors []Floor // Collection of floor records
|
||||
Walls []Wall // Collection of wall records
|
||||
Shadows []Shadow // Collection of shadow records
|
||||
Substitutions []Substitution // Collection of substitutions
|
||||
tileCommonFields
|
||||
tileFloorShadowFields
|
||||
tileSubstitutionFields
|
||||
}
|
||||
|
||||
func makeDefaultTile() Tile {
|
||||
return Tile{
|
||||
Floors: []Floor{{}},
|
||||
Walls: []Wall{{}},
|
||||
Shadows: []Shadow{{}},
|
||||
Substitutions: []Substitution{{}},
|
||||
}
|
||||
// Hidden returns if wall is hidden
|
||||
func (t *Tile) Hidden() bool {
|
||||
return t.HiddenBytes > 0
|
||||
}
|
||||
|
||||
// DecodeWall decodes as a wall record
|
||||
func (t *Tile) DecodeWall(dw uint32) {
|
||||
t.Prop1 = byte((dw & prop1Bitmask) >> prop1Offset)
|
||||
t.Sequence = byte((dw & sequenceBitmask) >> sequenceOffset)
|
||||
t.Unknown1 = byte((dw & unknown1Bitmask) >> unknown1Offset)
|
||||
t.Style = byte((dw & styleBitmask) >> styleOffset)
|
||||
t.Unknown2 = byte((dw & unknown2Bitmask) >> unknown2Offset)
|
||||
t.HiddenBytes = byte((dw & hiddenBitmask) >> hiddenOffset)
|
||||
}
|
||||
|
||||
// EncodeWall adds wall's record's bytes into stream writer given
|
||||
func (t *Tile) EncodeWall(sw *d2datautils.StreamWriter) {
|
||||
sw.PushBits32(uint32(t.Prop1), prop1Length)
|
||||
sw.PushBits32(uint32(t.Sequence), sequenceLength)
|
||||
sw.PushBits32(uint32(t.Unknown1), unknown1Length)
|
||||
sw.PushBits32(uint32(t.Style), styleLength)
|
||||
sw.PushBits32(uint32(t.Unknown2), unknown2Length)
|
||||
sw.PushBits32(uint32(t.HiddenBytes), hiddenLength)
|
||||
}
|
||||
|
||||
func (t *Tile) decodeFloorShadow(dw uint32) {
|
||||
t.Prop1 = byte((dw & prop1Bitmask) >> prop1Offset)
|
||||
t.Sequence = byte((dw & sequenceBitmask) >> sequenceOffset)
|
||||
t.Unknown1 = byte((dw & unknown1Bitmask) >> unknown1Offset)
|
||||
t.Style = byte((dw & styleBitmask) >> styleOffset)
|
||||
t.Unknown2 = byte((dw & unknown2Bitmask) >> unknown2Offset)
|
||||
t.HiddenBytes = byte((dw & hiddenBitmask) >> hiddenOffset)
|
||||
}
|
||||
|
||||
func (t *Tile) encodeFloorShadow(sw *d2datautils.StreamWriter) {
|
||||
sw.PushBits32(uint32(t.Prop1), prop1Length)
|
||||
sw.PushBits32(uint32(t.Sequence), sequenceLength)
|
||||
sw.PushBits32(uint32(t.Unknown1), unknown1Length)
|
||||
sw.PushBits32(uint32(t.Style), styleLength)
|
||||
sw.PushBits32(uint32(t.Unknown2), unknown2Length)
|
||||
sw.PushBits32(uint32(t.HiddenBytes), hiddenLength)
|
||||
}
|
||||
|
||||
// DecodeFloor decodes as a floor record
|
||||
func (t *Tile) DecodeFloor(dw uint32) {
|
||||
t.decodeFloorShadow(dw)
|
||||
}
|
||||
|
||||
// EncodeFloor adds Floor's bits to stream writer given
|
||||
func (t *Tile) EncodeFloor(sw *d2datautils.StreamWriter) {
|
||||
t.encodeFloorShadow(sw)
|
||||
}
|
||||
|
||||
// DecodeShadow decodes as a shadow record
|
||||
func (t *Tile) DecodeShadow(dw uint32) {
|
||||
t.decodeFloorShadow(dw)
|
||||
}
|
||||
|
||||
// EncodeShadow adds shadow's bits to stream writer given
|
||||
func (t *Tile) EncodeShadow(sw *d2datautils.StreamWriter) {
|
||||
t.encodeFloorShadow(sw)
|
||||
}
|
||||
|
@ -1,45 +0,0 @@
|
||||
package d2ds1
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
)
|
||||
|
||||
// Wall represents a wall record.
|
||||
type Wall struct {
|
||||
Type d2enum.TileType
|
||||
Zero byte
|
||||
Prop1 byte
|
||||
Sequence byte
|
||||
Unknown1 byte
|
||||
Style byte
|
||||
Unknown2 byte
|
||||
HiddenBytes byte
|
||||
RandomIndex byte
|
||||
YAdjust int
|
||||
}
|
||||
|
||||
// Hidden returns if wall is hidden
|
||||
func (w *Wall) Hidden() bool {
|
||||
return w.HiddenBytes > 0
|
||||
}
|
||||
|
||||
// Decode decodes wall record
|
||||
func (w *Wall) Decode(dw uint32) {
|
||||
w.Prop1 = byte((dw & prop1Bitmask) >> prop1Offset)
|
||||
w.Sequence = byte((dw & sequenceBitmask) >> sequenceOffset)
|
||||
w.Unknown1 = byte((dw & unknown1Bitmask) >> unknown1Offset)
|
||||
w.Style = byte((dw & styleBitmask) >> styleOffset)
|
||||
w.Unknown2 = byte((dw & unknown2Bitmask) >> unknown2Offset)
|
||||
w.HiddenBytes = byte((dw & hiddenBitmask) >> hiddenOffset)
|
||||
}
|
||||
|
||||
// Encode adds wall's record's bytes into stream writer given
|
||||
func (w *Wall) Encode(sw *d2datautils.StreamWriter) {
|
||||
sw.PushBits32(uint32(w.Prop1), prop1Length)
|
||||
sw.PushBits32(uint32(w.Sequence), sequenceLength)
|
||||
sw.PushBits32(uint32(w.Unknown1), unknown1Length)
|
||||
sw.PushBits32(uint32(w.Style), styleLength)
|
||||
sw.PushBits32(uint32(w.Unknown2), unknown2Length)
|
||||
sw.PushBits32(uint32(w.HiddenBytes), hiddenLength)
|
||||
}
|
@ -517,7 +517,7 @@ func (am *AssetManager) LoadDS1(ds1Path string) (*d2ds1.DS1, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds1, err := d2ds1.LoadDS1(fileData)
|
||||
ds1, err := d2ds1.Unmarshal(fileData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -118,8 +118,8 @@ func (m *MapEngine) AddDS1(fileName string) {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
|
||||
for idx := range ds1.Files() {
|
||||
dt1File := ds1.Files()[idx]
|
||||
for idx := range ds1.Files {
|
||||
dt1File := ds1.Files[idx]
|
||||
dt1File = strings.ToLower(dt1File)
|
||||
dt1File = strings.ReplaceAll(dt1File, "c:", "") // Yes they did...
|
||||
dt1File = strings.ReplaceAll(dt1File, ".tg1", ".dt1") // Yes they did...
|
||||
|
@ -2,13 +2,14 @@ package d2mapengine
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapstamp"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
|
||||
)
|
||||
|
||||
// MapTile is a tile placed on the map
|
||||
type MapTile struct {
|
||||
Components d2ds1.Tile
|
||||
Components d2mapstamp.Tile
|
||||
RegionType d2enum.RegionIdType
|
||||
SubTiles [25]d2dt1.SubTileFlags
|
||||
}
|
||||
|
@ -284,7 +284,9 @@ func (g *MapGenerator) generateWilderness1Contents(rect d2geom.Rectangle) {
|
||||
for x := 0; x < rect.Width; x++ {
|
||||
tile := g.engine.Tile(rect.Left+x, rect.Top+y)
|
||||
tile.RegionType = d2enum.RegionIdType(levelDetails.LevelType)
|
||||
tile.Components.Floors = []d2ds1.Floor{{Prop1: 1, Style: 0, Sequence: 0}} // wildernessGrass
|
||||
floorTile := d2ds1.Tile{}
|
||||
floorTile.Prop1 = 1
|
||||
tile.Components.Floors = []d2ds1.Tile{floorTile} // wildernessGrass
|
||||
tile.PrepareTile(x, y, g.engine)
|
||||
}
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ func (mr *MapRenderer) renderTilePass3(tile *d2mapengine.MapTile, target d2inter
|
||||
}
|
||||
}
|
||||
|
||||
func (mr *MapRenderer) renderFloor(tile d2ds1.Floor, target d2interface.Surface) {
|
||||
func (mr *MapRenderer) renderFloor(tile d2ds1.Tile, target d2interface.Surface) {
|
||||
var img d2interface.Surface
|
||||
if !tile.Animated {
|
||||
img = mr.getImageCacheRecord(tile.Style, tile.Sequence, 0, tile.RandomIndex)
|
||||
@ -415,7 +415,7 @@ func (mr *MapRenderer) renderFloor(tile d2ds1.Floor, target d2interface.Surface)
|
||||
target.Render(img)
|
||||
}
|
||||
|
||||
func (mr *MapRenderer) renderWall(tile d2ds1.Wall, viewport *Viewport, target d2interface.Surface) {
|
||||
func (mr *MapRenderer) renderWall(tile d2ds1.Tile, viewport *Viewport, target d2interface.Surface) {
|
||||
img := mr.getImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tile.RandomIndex)
|
||||
if img == nil {
|
||||
mr.Warningf("Render called on uncached wall {%v,%v,%v}", tile.Style, tile.Sequence, tile.Type)
|
||||
@ -431,7 +431,7 @@ func (mr *MapRenderer) renderWall(tile d2ds1.Wall, viewport *Viewport, target d2
|
||||
target.Render(img)
|
||||
}
|
||||
|
||||
func (mr *MapRenderer) renderShadow(tile d2ds1.Shadow, target d2interface.Surface) {
|
||||
func (mr *MapRenderer) renderShadow(tile d2ds1.Tile, target d2interface.Surface) {
|
||||
img := mr.getImageCacheRecord(tile.Style, tile.Sequence, 13, tile.RandomIndex)
|
||||
if img == nil {
|
||||
mr.Warningf("Render called on uncached shadow {%v,%v}", tile.Style, tile.Sequence)
|
||||
|
@ -53,7 +53,7 @@ func (mr *MapRenderer) generateTileCache() {
|
||||
}
|
||||
}
|
||||
|
||||
func (mr *MapRenderer) generateFloorCache(tile *d2ds1.Floor) {
|
||||
func (mr *MapRenderer) generateFloorCache(tile *d2ds1.Tile) {
|
||||
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), 0)
|
||||
|
||||
var tileData []*d2dt1.Tile
|
||||
@ -110,7 +110,7 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.Floor) {
|
||||
}
|
||||
}
|
||||
|
||||
func (mr *MapRenderer) generateShadowCache(tile *d2ds1.Shadow) {
|
||||
func (mr *MapRenderer) generateShadowCache(tile *d2ds1.Tile) {
|
||||
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), d2enum.TileShadow)
|
||||
|
||||
var tileData *d2dt1.Tile
|
||||
@ -153,7 +153,7 @@ func (mr *MapRenderer) generateShadowCache(tile *d2ds1.Shadow) {
|
||||
mr.setImageCacheRecord(tile.Style, tile.Sequence, d2enum.TileShadow, tile.RandomIndex, image)
|
||||
}
|
||||
|
||||
func (mr *MapRenderer) generateWallCache(tile *d2ds1.Wall) {
|
||||
func (mr *MapRenderer) generateWallCache(tile *d2ds1.Tile) {
|
||||
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), tile.Type)
|
||||
|
||||
var tileData *d2dt1.Tile
|
||||
|
@ -87,7 +87,7 @@ func (f *StampFactory) LoadStamp(levelType d2enum.RegionIdType, levelPreset, fil
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stamp.ds1, err = d2ds1.LoadDS1(fileData)
|
||||
stamp.ds1, err = d2ds1.Unmarshal(fileData)
|
||||
if err != nil {
|
||||
f.Error(err.Error())
|
||||
return nil
|
||||
|
@ -54,9 +54,45 @@ func (mr *Stamp) RegionPath() string {
|
||||
return mr.regionPath
|
||||
}
|
||||
|
||||
type Tile struct {
|
||||
Walls []d2ds1.Tile
|
||||
Orientations []d2ds1.Tile
|
||||
Floors []d2ds1.Tile
|
||||
Shadows []d2ds1.Tile
|
||||
Substitutions []d2ds1.Tile
|
||||
}
|
||||
|
||||
// Tile returns the tile at the given x and y tile coordinates.
|
||||
func (mr *Stamp) Tile(x, y int) *d2ds1.Tile {
|
||||
return mr.ds1.Tile(x, y)
|
||||
func (mr *Stamp) Tile(x, y int) *Tile {
|
||||
t := &Tile{
|
||||
Walls: make([]d2ds1.Tile, len(mr.ds1.Walls)),
|
||||
Orientations: make([]d2ds1.Tile, len(mr.ds1.Orientations)),
|
||||
Floors: make([]d2ds1.Tile, len(mr.ds1.Floors)),
|
||||
Shadows: make([]d2ds1.Tile, len(mr.ds1.Shadows)),
|
||||
Substitutions: make([]d2ds1.Tile, len(mr.ds1.Substitutions)),
|
||||
}
|
||||
|
||||
for idx := range mr.ds1.Walls {
|
||||
t.Walls[idx] = *mr.ds1.Walls[idx].Tile(x, y)
|
||||
}
|
||||
|
||||
for idx := range mr.ds1.Orientations {
|
||||
t.Orientations[idx] = *mr.ds1.Orientations[idx].Tile(x, y)
|
||||
}
|
||||
|
||||
for idx := range mr.ds1.Floors {
|
||||
t.Floors[idx] = *mr.ds1.Floors[idx].Tile(x, y)
|
||||
}
|
||||
|
||||
for idx := range mr.ds1.Shadows {
|
||||
t.Shadows[idx] = *mr.ds1.Shadows[idx].Tile(x, y)
|
||||
}
|
||||
|
||||
for idx := range mr.ds1.Substitutions {
|
||||
t.Substitutions[idx] = *mr.ds1.Substitutions[idx].Tile(x, y)
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// TileData returns the tile data for the tile with given style, sequence and type.
|
||||
@ -75,9 +111,9 @@ func (mr *Stamp) TileData(style, sequence int32, tileType d2enum.TileType) *d2dt
|
||||
func (mr *Stamp) Entities(tileOffsetX, tileOffsetY int) []d2interface.MapEntity {
|
||||
entities := make([]d2interface.MapEntity, 0)
|
||||
|
||||
for _, object := range mr.ds1.Objects() {
|
||||
for _, object := range mr.ds1.Objects {
|
||||
if object.Type == int(d2enum.ObjectTypeCharacter) {
|
||||
monPreset := mr.factory.asset.Records.Monster.Presets[int32(mr.ds1.Act())][object.ID]
|
||||
monPreset := mr.factory.asset.Records.Monster.Presets[mr.ds1.Act][object.ID]
|
||||
monstat := mr.factory.asset.Records.Monster.Stats[monPreset]
|
||||
// If monstat is nil here it is a place_ type object, idk how to handle those yet.
|
||||
// (See monpreset and monplace txts for reference)
|
||||
@ -97,7 +133,7 @@ func (mr *Stamp) Entities(tileOffsetX, tileOffsetY int) []d2interface.MapEntity
|
||||
if object.Type == int(d2enum.ObjectTypeItem) {
|
||||
// For objects the DS1 ID to objectID is hardcoded in the game
|
||||
// use the lookup table
|
||||
lookup := mr.factory.asset.Records.LookupObject(mr.ds1.Act(), object.Type, object.ID)
|
||||
lookup := mr.factory.asset.Records.LookupObject(int(mr.ds1.Act), object.Type, object.ID)
|
||||
|
||||
if lookup == nil {
|
||||
continue
|
||||
|
73
et
Normal file
73
et
Normal file
@ -0,0 +1,73 @@
|
||||
[1mdiff --git a/d2common/d2fileformats/d2ds1/ds1_test.go b/d2common/d2fileformats/d2ds1/ds1_test.go[m
|
||||
[1mindex 23035a50..d17527f0 100644[m
|
||||
[1m--- a/d2common/d2fileformats/d2ds1/ds1_test.go[m
|
||||
[1m+++ b/d2common/d2fileformats/d2ds1/ds1_test.go[m
|
||||
[36m@@ -575,6 +575,24 @@[m [mfunc TestDS1_SetNumberOfFloors(t *testing.T) {[m
|
||||
if err := testIfRestorable(ds1, test); err != nil {[m
|
||||
t.Errorf("unable to restore: %v", err)[m
|
||||
}[m
|
||||
[32m+[m
|
||||
[32m+[m [32mnewNumber = 10[m
|
||||
[32m+[m
|
||||
[32m+[m [32mds1.SetNumberOfFloorLayers(newNumber)[m
|
||||
[32m+[m
|
||||
[32m+[m [32mtest = func(ds1 *DS1) {[m
|
||||
[32m+[m [32mif len(ds1.tiles[0][0].Floors) != int(newNumber) {[m
|
||||
[32m+[m [32mt.Fatal("unexpected floors length set")[m
|
||||
[32m+[m [32m}[m
|
||||
[32m+[m
|
||||
[32m+[m [32mif ds1.numberOfFloorLayers != newNumber {[m
|
||||
[32m+[m [32mt.Fatal("unexpected floors length set")[m
|
||||
[32m+[m [32m}[m
|
||||
[32m+[m [32m}[m
|
||||
[32m+[m
|
||||
[32m+[m [32mif err := testIfRestorable(ds1, test); err != nil {[m
|
||||
[32m+[m [32mt.Errorf("unable to restore: %v", err)[m
|
||||
[32m+[m [32m}[m
|
||||
}[m
|
||||
[m
|
||||
func TestDS1_NumberOfShadowLayers(t *testing.T) {[m
|
||||
[1mdiff --git a/d2common/d2fileformats/d2ds1/layers.go b/d2common/d2fileformats/d2ds1/layers.go[m
|
||||
[1mindex f69ef7f1..b0488a34 100644[m
|
||||
[1m--- a/d2common/d2fileformats/d2ds1/layers.go[m
|
||||
[1m+++ b/d2common/d2fileformats/d2ds1/layers.go[m
|
||||
[36m@@ -1 +1,39 @@[m
|
||||
package d2ds1[m
|
||||
[32m+[m
|
||||
[32m+[m[32mconst ([m
|
||||
[32m+[m [32mmaxWalls = 4[m
|
||||
[32m+[m[32m)[m
|
||||
[32m+[m
|
||||
[32m+[m[32mtype WallLayer [][]*Wall[m
|
||||
[32m+[m[32mtype FloorLayer [][]*Floor[m
|
||||
[32m+[m[32mtype ShadowLayer [][]*Shadow[m
|
||||
[32m+[m
|
||||
[32m+[m[32mtype layers struct {[m
|
||||
[32m+[m [32mWalls []WallLayer[m
|
||||
[32m+[m [32mFloors []FloorLayer[m
|
||||
[32m+[m [32mShadows []ShadowLayer[m
|
||||
[32m+[m[32m}[m
|
||||
[32m+[m
|
||||
[32m+[m[32mfunc (l *layers) PushWallLayer() {[m
|
||||
[32m+[m
|
||||
[32m+[m[32m}[m
|
||||
[32m+[m
|
||||
[32m+[m[32mfunc (l *layers) PopWallLayer() WallLayer {[m
|
||||
[32m+[m
|
||||
[32m+[m[32m}[m
|
||||
[32m+[m
|
||||
[32m+[m[32mfunc (l *layers) PushFloorLayer() {[m
|
||||
[32m+[m
|
||||
[32m+[m[32m}[m
|
||||
[32m+[m
|
||||
[32m+[m[32mfunc (l *layers) PopFloorLayer() FloorLayer {[m
|
||||
[32m+[m
|
||||
[32m+[m[32m}[m
|
||||
[32m+[m
|
||||
[32m+[m[32mfunc (l *layers) PushShadowLayer() {[m
|
||||
[32m+[m
|
||||
[32m+[m[32m}[m
|
||||
[32m+[m
|
||||
[32m+[m[32mfunc (l *layers) PopShadowLayer() ShadowLayer {[m
|
||||
[32m+[m
|
||||
[32m+[m[32m}[m
|
Loading…
Reference in New Issue
Block a user