eq2go/internal/object/integration.go
2025-08-05 19:57:01 -05:00

388 lines
11 KiB
Go

package object
import (
"fmt"
"eq2emu/internal/spawn"
)
// ObjectSpawn represents an object that extends spawn functionality
// This properly integrates with the existing spawn system
type ObjectSpawn struct {
*spawn.Spawn // Embed the spawn functionality
// Object-specific properties
clickable bool // Whether the object can be clicked/interacted with
deviceID int8 // Device ID for interactive objects
// Merchant properties (duplicated from spawn since fields are unexported)
merchantID int32
merchantType int8
merchantMinLevel int32
merchantMaxLevel int32
isCollector bool
// Transport properties (duplicated from spawn since fields are unexported)
transporterID int32
}
// NewObjectSpawn creates a new object spawn with default values
func NewObjectSpawn() *ObjectSpawn {
// 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
// Note: No SetAppearance method, but appearance is modified by reference
return &ObjectSpawn{
Spawn: baseSpawn,
clickable: false,
deviceID: DeviceIDNone,
}
}
// SetClickable sets whether the object can be clicked
func (os *ObjectSpawn) SetClickable(clickable bool) {
os.clickable = clickable
}
// IsClickable returns whether the object can be clicked
func (os *ObjectSpawn) IsClickable() bool {
return os.clickable
}
// SetDeviceID sets the device ID for interactive objects
func (os *ObjectSpawn) SetDeviceID(deviceID int8) {
os.deviceID = deviceID
}
// GetDeviceID returns the device ID
func (os *ObjectSpawn) GetDeviceID() int8 {
return os.deviceID
}
// IsObject always returns true for object spawns
func (os *ObjectSpawn) IsObject() bool {
return true
}
// Copy creates a deep copy of the object spawn
func (os *ObjectSpawn) Copy() *ObjectSpawn {
// Create new object spawn with new spawn
newObjectSpawn := NewObjectSpawn()
// Copy properties from original
newObjectSpawn.clickable = os.clickable
newObjectSpawn.deviceID = os.deviceID
// Copy spawn properties
newObjectSpawn.SetDatabaseID(os.GetDatabaseID())
newObjectSpawn.SetID(os.GetID())
newObjectSpawn.SetName(os.GetName())
newObjectSpawn.SetLevel(os.GetLevel())
newObjectSpawn.SetSize(os.GetSize())
newObjectSpawn.SetSpawnType(os.GetSpawnType())
newObjectSpawn.SetX(os.GetX())
newObjectSpawn.SetY(os.GetY(), false)
newObjectSpawn.SetZ(os.GetZ())
newObjectSpawn.SetHeading(int16(os.GetHeading()), int16(os.GetHeading()))
newObjectSpawn.SetFactionID(os.GetFactionID())
newObjectSpawn.SetTarget(os.GetTarget())
newObjectSpawn.SetAlive(os.IsAlive())
// Copy merchant properties if they exist
if os.merchantID > 0 {
newObjectSpawn.merchantID = os.merchantID
newObjectSpawn.merchantType = os.merchantType
newObjectSpawn.merchantMinLevel = os.merchantMinLevel
newObjectSpawn.merchantMaxLevel = os.merchantMaxLevel
}
// Copy transport properties if they exist
if os.transporterID > 0 {
newObjectSpawn.transporterID = os.transporterID
}
newObjectSpawn.isCollector = os.isCollector
return newObjectSpawn
}
// HandleUse processes object interaction by a client
func (os *ObjectSpawn) HandleUse(clientID int32, command string) error {
// Use the base object's HandleUse logic but with spawn integration
object := &Object{}
// Copy relevant properties for handling
object.clickable = os.clickable
object.deviceID = os.deviceID
object.transporterID = os.transporterID
object.appearanceShowCommandIcon = int8(0)
if os.GetAppearanceData().ShowCommandIcon == 1 {
object.appearanceShowCommandIcon = ObjectShowCommandIcon
}
// TODO: Copy command lists when they're integrated with spawn system
return object.HandleUse(clientID, command)
}
// SetShowCommandIcon sets whether to show the command icon
func (os *ObjectSpawn) SetShowCommandIcon(show bool) {
appearance := os.GetAppearanceData()
if show {
appearance.ShowCommandIcon = ObjectShowCommandIcon
} else {
appearance.ShowCommandIcon = 0
}
// Appearance is modified by reference, no need to set it back
}
// ShowsCommandIcon returns whether the command icon is shown
func (os *ObjectSpawn) ShowsCommandIcon() bool {
return os.GetAppearanceData().ShowCommandIcon == ObjectShowCommandIcon
}
// GetObjectInfo returns comprehensive information about the object spawn
func (os *ObjectSpawn) GetObjectInfo() map[string]any {
info := make(map[string]any)
// Add spawn info
info["spawn_id"] = os.GetID()
info["database_id"] = os.GetDatabaseID()
info["zone_name"] = os.GetZoneName()
info["spawn_type"] = os.GetSpawnType()
info["size"] = os.GetSize()
// Add object-specific info
info["clickable"] = os.clickable
info["device_id"] = os.deviceID
info["shows_command_icon"] = os.ShowsCommandIcon()
info["transporter_id"] = os.transporterID
info["merchant_id"] = os.merchantID
info["is_collector"] = os.isCollector
// Add position info
appearance := os.GetAppearanceData()
info["x"] = appearance.Pos.X
info["y"] = appearance.Pos.Y
info["z"] = appearance.Pos.Z
info["heading"] = appearance.Pos.Dir1
return info
}
// Getter and setter methods for object-specific properties
// GetMerchantID returns the merchant ID
func (os *ObjectSpawn) GetMerchantID() int32 {
return os.merchantID
}
// SetMerchantID sets the merchant ID
func (os *ObjectSpawn) SetMerchantID(merchantID int32) {
os.merchantID = merchantID
}
// GetMerchantType returns the merchant type
func (os *ObjectSpawn) GetMerchantType() int8 {
return os.merchantType
}
// SetMerchantType sets the merchant type
func (os *ObjectSpawn) SetMerchantType(merchantType int8) {
os.merchantType = merchantType
}
// GetMerchantMinLevel returns the minimum merchant level
func (os *ObjectSpawn) GetMerchantMinLevel() int8 {
return int8(os.merchantMinLevel)
}
// GetMerchantMaxLevel returns the maximum merchant level
func (os *ObjectSpawn) GetMerchantMaxLevel() int8 {
return int8(os.merchantMaxLevel)
}
// SetMerchantLevelRange sets the merchant level range
func (os *ObjectSpawn) SetMerchantLevelRange(minLevel, maxLevel int8) {
os.merchantMinLevel = int32(minLevel)
os.merchantMaxLevel = int32(maxLevel)
}
// GetTransporterID returns the transporter ID
func (os *ObjectSpawn) GetTransporterID() int32 {
return os.transporterID
}
// SetTransporterID sets the transporter ID
func (os *ObjectSpawn) SetTransporterID(transporterID int32) {
os.transporterID = transporterID
}
// IsCollector returns whether this object is a collector
func (os *ObjectSpawn) IsCollector() bool {
return os.isCollector
}
// SetCollector sets whether this object is a collector
func (os *ObjectSpawn) SetCollector(isCollector bool) {
os.isCollector = isCollector
}
// GetZoneName returns the zone name (from spawn system)
func (os *ObjectSpawn) GetZoneName() string {
// TODO: Implement when zone system is integrated
// For now return empty string
return ""
}
// SetZoneName sets the zone name (placeholder for spawn system)
func (os *ObjectSpawn) SetZoneName(zoneName string) {
// TODO: Implement when zone system is integrated
// This would be handled by the spawn system
}
// ObjectSpawnManager manages object spawns specifically
type ObjectSpawnManager struct {
objects map[int32]*ObjectSpawn // Object spawns by spawn ID
// TODO: Add reference to spawn manager when it exists
}
// NewObjectSpawnManager creates a new object spawn manager
func NewObjectSpawnManager() *ObjectSpawnManager {
return &ObjectSpawnManager{
objects: make(map[int32]*ObjectSpawn),
}
}
// AddObjectSpawn adds an object spawn to the manager
func (osm *ObjectSpawnManager) AddObjectSpawn(objectSpawn *ObjectSpawn) error {
if objectSpawn == nil {
return fmt.Errorf("cannot add nil object spawn")
}
// Add to object tracking
osm.objects[objectSpawn.GetID()] = objectSpawn
// TODO: Add to global spawn manager when it exists
return nil
}
// RemoveObjectSpawn removes an object spawn from the manager
func (osm *ObjectSpawnManager) RemoveObjectSpawn(spawnID int32) error {
// Remove from object tracking
if _, exists := osm.objects[spawnID]; !exists {
return fmt.Errorf("object spawn %d not found", spawnID)
}
delete(osm.objects, spawnID)
// TODO: Remove from global spawn manager when it exists
return nil
}
// GetObjectSpawn retrieves an object spawn by ID
func (osm *ObjectSpawnManager) GetObjectSpawn(spawnID int32) *ObjectSpawn {
return osm.objects[spawnID]
}
// GetObjectSpawnsByZone returns all object spawns in a zone
func (osm *ObjectSpawnManager) GetObjectSpawnsByZone(zoneName string) []*ObjectSpawn {
result := make([]*ObjectSpawn, 0)
// TODO: Filter by zone when zone system is implemented
// For now, return empty slice
return result
}
// GetInteractiveObjectSpawns returns all interactive object spawns
func (osm *ObjectSpawnManager) GetInteractiveObjectSpawns() []*ObjectSpawn {
result := make([]*ObjectSpawn, 0)
for _, objectSpawn := range osm.objects {
if objectSpawn.IsClickable() || objectSpawn.ShowsCommandIcon() {
result = append(result, objectSpawn)
}
}
return result
}
// ProcessObjectInteraction handles interaction with an object spawn
func (osm *ObjectSpawnManager) ProcessObjectInteraction(spawnID, clientID int32, command string) error {
objectSpawn := osm.GetObjectSpawn(spawnID)
if objectSpawn == nil {
return fmt.Errorf("object spawn %d not found", spawnID)
}
return objectSpawn.HandleUse(clientID, command)
}
// ConvertSpawnToObject converts a regular spawn to an object spawn (if applicable)
func ConvertSpawnToObject(spawn *spawn.Spawn) *ObjectSpawn {
if spawn.GetSpawnType() != ObjectSpawnType {
return nil
}
objectSpawn := &ObjectSpawn{
Spawn: spawn,
clickable: false, // Default, should be loaded from data
deviceID: DeviceIDNone,
}
// Set clickable based on appearance flags or other indicators
appearance := spawn.GetAppearanceData()
if appearance.ShowCommandIcon == ObjectShowCommandIcon {
objectSpawn.clickable = true
}
return objectSpawn
}
// LoadObjectSpawnFromData loads object spawn data from database/config
// This would be called when loading spawns from the database
func LoadObjectSpawnFromData(spawnData map[string]any) *ObjectSpawn {
objectSpawn := NewObjectSpawn()
// Load basic spawn data
if databaseID, ok := spawnData["database_id"].(int32); ok {
objectSpawn.SetDatabaseID(databaseID)
}
if zoneName, ok := spawnData["zone"].(string); ok {
objectSpawn.SetZoneName(zoneName)
}
// Load object-specific data
if clickable, ok := spawnData["clickable"].(bool); ok {
objectSpawn.SetClickable(clickable)
}
if deviceID, ok := spawnData["device_id"].(int8); ok {
objectSpawn.SetDeviceID(deviceID)
}
// Load position data
if x, ok := spawnData["x"].(float32); ok {
objectSpawn.SetX(x)
}
if y, ok := spawnData["y"].(float32); ok {
objectSpawn.SetY(y, false)
}
if z, ok := spawnData["z"].(float32); ok {
objectSpawn.SetZ(z)
}
// TODO: Load other properties as needed
return objectSpawn
}