eq2go/internal/object/object.go
2025-08-29 18:25:57 -05:00

330 lines
7.2 KiB
Go

package object
import (
"fmt"
"sync"
"eq2emu/internal/spawn"
)
// Object constants
const (
// Object spawn type
ObjectSpawnType = 2
// Object appearance defaults
ObjectActivityStatus = 64
ObjectPosState = 1
ObjectDifficulty = 0
// Object interaction constants
ObjectShowCommandIcon = 1
// Object states
ObjectStateInactive = 0
ObjectStateActive = 1
// Interaction types
InteractionTypeNone = 0
InteractionTypeCommand = 1
InteractionTypeTransport = 2
InteractionTypeDevice = 3
)
// Object represents a game object that extends spawn functionality
type Object struct {
*spawn.Spawn // Embed spawn functionality
// Object-specific properties
clickable bool // Whether the object can be clicked/interacted with
deviceID int8 // Device ID for interactive objects
// Merchant properties
merchantID int32
merchantType int8
merchantMinLevel int32
merchantMaxLevel int32
isCollector bool
// Transport properties
transporterID int32
// Zone tracking (since spawn doesn't expose zone methods yet)
zoneName string
// Thread safety
mutex sync.RWMutex
}
// NewObject creates a new object with default values
func NewObject() *Object {
// Create base spawn
baseSpawn := spawn.NewSpawn()
// Set object-specific spawn properties
baseSpawn.SetSpawnType(ObjectSpawnType)
// Set object appearance defaults
appearance := baseSpawn.GetAppearanceData()
appearance.ActivityStatus = ObjectActivityStatus
appearance.Pos.State = ObjectPosState
appearance.Difficulty = ObjectDifficulty
return &Object{
Spawn: baseSpawn,
clickable: false,
deviceID: 0,
zoneName: "",
}
}
// Object-specific methods
// IsObject returns true (implements ObjectInterface)
func (o *Object) IsObject() bool {
return true
}
// IsClickable returns whether the object can be clicked
func (o *Object) IsClickable() bool {
o.mutex.RLock()
defer o.mutex.RUnlock()
return o.clickable
}
// SetClickable sets whether the object can be clicked
func (o *Object) SetClickable(clickable bool) {
o.mutex.Lock()
defer o.mutex.Unlock()
o.clickable = clickable
// Update appearance to show/hide command icon
if clickable {
o.GetAppearanceData().ShowCommandIcon = ObjectShowCommandIcon
} else {
o.GetAppearanceData().ShowCommandIcon = 0
}
}
// GetDeviceID returns the device ID
func (o *Object) GetDeviceID() int8 {
o.mutex.RLock()
defer o.mutex.RUnlock()
return o.deviceID
}
// SetDeviceID sets the device ID
func (o *Object) SetDeviceID(deviceID int8) {
o.mutex.Lock()
defer o.mutex.Unlock()
o.deviceID = deviceID
}
// Merchant methods
// GetMerchantID returns the merchant ID
func (o *Object) GetMerchantID() int32 {
o.mutex.RLock()
defer o.mutex.RUnlock()
return o.merchantID
}
// SetMerchantID sets the merchant ID
func (o *Object) SetMerchantID(merchantID int32) {
o.mutex.Lock()
defer o.mutex.Unlock()
o.merchantID = merchantID
}
// GetMerchantType returns the merchant type
func (o *Object) GetMerchantType() int8 {
o.mutex.RLock()
defer o.mutex.RUnlock()
return o.merchantType
}
// SetMerchantType sets the merchant type
func (o *Object) SetMerchantType(merchantType int8) {
o.mutex.Lock()
defer o.mutex.Unlock()
o.merchantType = merchantType
}
// IsMerchant returns whether this object is a merchant
func (o *Object) IsMerchant() bool {
o.mutex.RLock()
defer o.mutex.RUnlock()
return o.merchantID > 0
}
// IsCollector returns whether this object is a collector
func (o *Object) IsCollector() bool {
o.mutex.RLock()
defer o.mutex.RUnlock()
return o.isCollector
}
// SetCollector sets whether this object is a collector
func (o *Object) SetCollector(isCollector bool) {
o.mutex.Lock()
defer o.mutex.Unlock()
o.isCollector = isCollector
}
// Transport methods
// GetTransporterID returns the transporter ID
func (o *Object) GetTransporterID() int32 {
o.mutex.RLock()
defer o.mutex.RUnlock()
return o.transporterID
}
// SetTransporterID sets the transporter ID
func (o *Object) SetTransporterID(transporterID int32) {
o.mutex.Lock()
defer o.mutex.Unlock()
o.transporterID = transporterID
}
// IsTransporter returns whether this object is a transporter
func (o *Object) IsTransporter() bool {
o.mutex.RLock()
defer o.mutex.RUnlock()
return o.transporterID > 0
}
// Interaction methods
// GetInteractionType returns the type of interaction this object supports
func (o *Object) GetInteractionType() int {
o.mutex.RLock()
defer o.mutex.RUnlock()
if o.transporterID > 0 {
return InteractionTypeTransport
}
if o.deviceID > 0 {
return InteractionTypeDevice
}
if o.clickable {
return InteractionTypeCommand
}
return InteractionTypeNone
}
// CanInteract returns whether this object can be interacted with
func (o *Object) CanInteract() bool {
return o.GetInteractionType() != InteractionTypeNone
}
// Zone methods
// GetZone returns the zone name
func (o *Object) GetZone() string {
o.mutex.RLock()
defer o.mutex.RUnlock()
return o.zoneName
}
// SetZone sets the zone name
func (o *Object) SetZone(zoneName string) {
o.mutex.Lock()
defer o.mutex.Unlock()
o.zoneName = zoneName
}
// Utility methods
// GetObjectType returns a string describing the object type
func (o *Object) GetObjectType() string {
switch {
case o.IsTransporter():
return "Transport"
case o.IsMerchant():
return "Merchant"
case o.IsCollector():
return "Collector"
case o.GetDeviceID() > 0:
return "Device"
case o.IsClickable():
return "Interactive"
default:
return "Static"
}
}
// Validate checks if the object is properly configured
func (o *Object) Validate() error {
if o.Spawn == nil {
return fmt.Errorf("object must have spawn data")
}
if o.GetSpawnType() != ObjectSpawnType {
return fmt.Errorf("object must have spawn type %d", ObjectSpawnType)
}
return nil
}
// Clone creates a copy of the object
func (o *Object) Clone() *Object {
o.mutex.RLock()
defer o.mutex.RUnlock()
newObject := &Object{
Spawn: o.Spawn, // Note: This is a shallow copy of the spawn
clickable: o.clickable,
deviceID: o.deviceID,
merchantID: o.merchantID,
merchantType: o.merchantType,
merchantMinLevel: o.merchantMinLevel,
merchantMaxLevel: o.merchantMaxLevel,
isCollector: o.isCollector,
transporterID: o.transporterID,
}
return newObject
}
// Factory functions for different object types
// CreateMerchantObject creates an object configured as a merchant
func CreateMerchantObject(merchantID int32, merchantType int8) *Object {
obj := NewObject()
obj.SetMerchantID(merchantID)
obj.SetMerchantType(merchantType)
obj.SetClickable(true)
return obj
}
// CreateTransportObject creates an object configured as a transporter
func CreateTransportObject(transporterID int32) *Object {
obj := NewObject()
obj.SetTransporterID(transporterID)
obj.SetClickable(true)
return obj
}
// CreateDeviceObject creates an object configured as a device
func CreateDeviceObject(deviceID int8) *Object {
obj := NewObject()
obj.SetDeviceID(deviceID)
obj.SetClickable(true)
return obj
}
// CreateCollectorObject creates an object configured as a collector
func CreateCollectorObject() *Object {
obj := NewObject()
obj.SetCollector(true)
obj.SetClickable(true)
return obj
}
// CreateStaticObject creates a non-interactive object
func CreateStaticObject() *Object {
obj := NewObject()
obj.SetClickable(false)
return obj
}