161 lines
3.8 KiB
Go
161 lines
3.8 KiB
Go
package level
|
|
|
|
import "github.com/inkyblackness/hacked/ss1/content/object"
|
|
|
|
const (
|
|
// ObjectMainEntrySize describes the size, in bytes, of a ObjectMainEntry.
|
|
ObjectMainEntrySize = 27
|
|
|
|
defaultObjectMainEntryCount = 872
|
|
)
|
|
|
|
// ObjectMainEntryModifier is a function that changes properties.
|
|
type ObjectMainEntryModifier func(*ObjectMainEntry)
|
|
|
|
// ObjectMainEntry describes an object in the level.
|
|
type ObjectMainEntry struct {
|
|
InUse byte
|
|
|
|
Class object.Class
|
|
Subclass object.Subclass
|
|
|
|
ClassTableIndex int16
|
|
CrossReferenceTableIndex int16
|
|
Next ObjectID
|
|
Prev ObjectID
|
|
|
|
X Coordinate
|
|
Y Coordinate
|
|
Z HeightUnit
|
|
XRotation RotationUnit
|
|
ZRotation RotationUnit
|
|
YRotation RotationUnit
|
|
|
|
_ byte
|
|
|
|
Type object.Type
|
|
|
|
Hitpoints int16
|
|
|
|
Extra [4]byte
|
|
}
|
|
|
|
// Triple returns the unique identifier of the entry.
|
|
func (entry ObjectMainEntry) Triple() object.Triple {
|
|
return object.TripleFrom(int(entry.Class), int(entry.Subclass), int(entry.Type))
|
|
}
|
|
|
|
// TilePosition returns the tile coordinates of the object.
|
|
func (entry ObjectMainEntry) TilePosition() TilePosition {
|
|
return TilePosition{X: entry.X.Tile(), Y: entry.Y.Tile()}
|
|
}
|
|
|
|
// FinePosition returns the coordinates of the object within the tile.
|
|
func (entry ObjectMainEntry) FinePosition() FinePosition {
|
|
return FinePosition{X: entry.X.Fine(), Y: entry.Y.Fine()}
|
|
}
|
|
|
|
// Reset clears the entry and resets all members.
|
|
func (entry *ObjectMainEntry) Reset() {
|
|
*entry = ObjectMainEntry{}
|
|
}
|
|
|
|
// ObjectMainTable is a list of entries.
|
|
// The first entry is reserved for internal use. For the reserved entry,
|
|
// the Next field refers to the head of the single-linked free chain,
|
|
// and the CrossReferenceTableIndex refers to the head of the double-linked used chain.
|
|
type ObjectMainTable []ObjectMainEntry
|
|
|
|
// DefaultObjectMainTable returns an initialized table with a default size.
|
|
func DefaultObjectMainTable() ObjectMainTable {
|
|
table := make(ObjectMainTable, defaultObjectMainEntryCount)
|
|
table.Reset()
|
|
return table
|
|
}
|
|
|
|
// Capacity returns the number of how many objects the table can hold.
|
|
func (table ObjectMainTable) Capacity() int {
|
|
size := len(table)
|
|
if size < 2 {
|
|
return 0
|
|
}
|
|
return size - 1
|
|
}
|
|
|
|
// AllocatedCount returns the number of how many objects are currently allocated in the table.
|
|
func (table ObjectMainTable) AllocatedCount() int {
|
|
capacity := table.Capacity()
|
|
if capacity == 0 {
|
|
return 0
|
|
}
|
|
index := int(table[0].CrossReferenceTableIndex)
|
|
count := 0
|
|
for (index != 0) && (count < capacity) {
|
|
count++
|
|
index = int(table[index].Next)
|
|
}
|
|
return count
|
|
}
|
|
|
|
// Reset wipes the entire table and initializes all links.
|
|
func (table ObjectMainTable) Reset() {
|
|
tableLen := len(table)
|
|
for i := 0; i < tableLen; i++ {
|
|
entry := &table[i]
|
|
entry.Reset()
|
|
entry.Next = ObjectID(i + 1)
|
|
}
|
|
if tableLen > 0 {
|
|
table[tableLen-1].Next = 0
|
|
}
|
|
}
|
|
|
|
// Allocate attempts to find an available entry in the table and activates it.
|
|
// Returns 0 if not possible (exhausted).
|
|
func (table ObjectMainTable) Allocate() ObjectID {
|
|
if len(table) < 2 {
|
|
return 0
|
|
}
|
|
start := &table[0]
|
|
if start.Next == 0 {
|
|
return 0
|
|
}
|
|
id := start.Next
|
|
entry := &table[id]
|
|
start.Next = entry.Next
|
|
|
|
entry.Reset()
|
|
entry.Next = ObjectID(start.CrossReferenceTableIndex)
|
|
table[start.CrossReferenceTableIndex].Prev = id
|
|
entry.Prev = 0
|
|
start.CrossReferenceTableIndex = int16(id)
|
|
|
|
entry.InUse = 1
|
|
|
|
return id
|
|
}
|
|
|
|
// Release deactivates the entry with given ID.
|
|
func (table ObjectMainTable) Release(id ObjectID) {
|
|
if (id < 1) || (int(id) >= len(table)) {
|
|
return
|
|
}
|
|
start := &table[0]
|
|
entry := &table[id]
|
|
|
|
if entry.InUse == 0 {
|
|
return
|
|
}
|
|
|
|
if entry.Prev == 0 {
|
|
start.CrossReferenceTableIndex = int16(entry.Next)
|
|
} else {
|
|
table[entry.Prev].Next = entry.Next
|
|
}
|
|
table[entry.Next].Prev = entry.Prev
|
|
|
|
entry.Reset()
|
|
entry.Next = start.Next
|
|
start.Next = id
|
|
}
|