OpenDiablo2/d2common/d2fileformats/d2ds1/ds1_layers.go

371 lines
6.9 KiB
Go

package d2ds1
const (
maxWallLayers = 4
maxFloorLayers = 2
maxShadowLayers = 1
maxSubstitutionLayers = 1
)
// LayerGroupType represents a type of layer (floor, wall, shadow, etc)
type LayerGroupType int
// Layer group types
const (
FloorLayerGroup LayerGroupType = iota
WallLayerGroup
ShadowLayerGroup
SubstitutionLayerGroup
)
func (l LayerGroupType) String() string {
switch l {
case FloorLayerGroup:
return "floor"
case WallLayerGroup:
return "wall"
case ShadowLayerGroup:
return "shadow"
case SubstitutionLayerGroup:
return "substitution"
}
// should not be reached
return "unknown"
}
type layerGroup []*Layer
type ds1Layers struct {
width, height int
Floors layerGroup
Walls 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.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(ShadowLayerGroup)
l.cullNilLayers(SubstitutionLayerGroup)
}
// removes nil layers of given layer group type
func (l *ds1Layers) cullNilLayers(t LayerGroupType) {
group := l.GetLayersGroup(t)
if group == nil {
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 = append((*group)[:idx], (*group)[idx+1:]...)
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(ShadowLayerGroup)
l.enforceSize(SubstitutionLayerGroup)
}
func (l *ds1Layers) enforceSize(t LayerGroupType) {
l.ensureInit()
l.cull()
group := l.GetLayersGroup(t)
if group == nil {
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()
layer.SetSize(l.Size())
group := l.GetLayersGroup(t)
max := GetMaxGroupLen(t)
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()
group := l.GetLayersGroup(t)
if group == nil {
return nil
}
var theLayer *Layer
// 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()
group := l.GetLayersGroup(t)
if group == nil {
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
}
newLayer.SetSize(l.Size())
group := l.GetLayersGroup(t)
if group == nil {
return
}
if len(*group)+1 > GetMaxGroupLen(t) {
return
}
if len(*group) == 0 {
*group = append(*group, newLayer) // nolint:staticcheck // we possibly use group later
return
}
if l := len(*group) - 1; idx > l {
idx = l
}
// example:
// suppose
// idx=1
// newLayer=c
// existing layerGroup is [a, b]
*group = append((*group)[:idx], append([]*Layer{newLayer}, (*group)[idx:]...)...)
}
func (l *ds1Layers) delete(t LayerGroupType, idx int) {
l.ensureInit()
l.cull()
group := l.GetLayersGroup(t)
if group == nil {
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) 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(SubstitutionLayerGroup, idx, newSubstitution)
}
func (l *ds1Layers) DeleteSubstitution(idx int) {
l.delete(ShadowLayerGroup, idx)
}
// GetLayersGroup returns layer group depending on type given
func (l *ds1Layers) GetLayersGroup(t LayerGroupType) (group *layerGroup) {
switch t {
case FloorLayerGroup:
group = &l.Floors
case WallLayerGroup:
group = &l.Walls
case ShadowLayerGroup:
group = &l.Shadows
case SubstitutionLayerGroup:
group = &l.Substitutions
default:
return nil
}
return group
}
// GetMaxGroupLen returns maximum length of layer group of type given
func GetMaxGroupLen(t LayerGroupType) (max int) {
switch t {
case FloorLayerGroup:
max = maxFloorLayers
case WallLayerGroup:
max = maxWallLayers
case ShadowLayerGroup:
max = maxShadowLayers
case SubstitutionLayerGroup:
max = maxSubstitutionLayers
default:
return 0
}
return max
}