package object import ( "fmt" "eq2emu/internal/spawn" "eq2emu/internal/common" ) // 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 } // 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.GetAppearance() appearance.ActivityStatus = ObjectActivityStatus appearance.Pos.State = ObjectPosState appearance.Difficulty = ObjectDifficulty baseSpawn.SetAppearance(appearance) 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 { // Copy base spawn newSpawn := os.Spawn.Copy() // Create new object spawn newObjectSpawn := &ObjectSpawn{ Spawn: newSpawn, clickable: os.clickable, deviceID: os.deviceID, } 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.GetTransporterID() object.appearanceShowCommandIcon = int8(0) if os.GetAppearance().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.GetAppearance() if show { appearance.ShowCommandIcon = ObjectShowCommandIcon } else { appearance.ShowCommandIcon = 0 } os.SetAppearance(appearance) } // ShowsCommandIcon returns whether the command icon is shown func (os *ObjectSpawn) ShowsCommandIcon() bool { return os.GetAppearance().ShowCommandIcon == ObjectShowCommandIcon } // GetObjectInfo returns comprehensive information about the object spawn func (os *ObjectSpawn) GetObjectInfo() map[string]interface{} { info := make(map[string]interface{}) // 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.GetTransporterID() info["merchant_id"] = os.GetMerchantID() info["is_collector"] = os.IsCollector() // Add position info appearance := os.GetAppearance() info["x"] = appearance.Pos.X info["y"] = appearance.Pos.Y info["z"] = appearance.Pos.Z info["heading"] = appearance.Pos.Dir1 return info } // ObjectSpawnManager manages object spawns specifically type ObjectSpawnManager struct { spawnManager *spawn.SpawnManager // Reference to global spawn manager objects map[int32]*ObjectSpawn // Object spawns by spawn ID } // NewObjectSpawnManager creates a new object spawn manager func NewObjectSpawnManager(spawnManager *spawn.SpawnManager) *ObjectSpawnManager { return &ObjectSpawnManager{ spawnManager: spawnManager, objects: make(map[int32]*ObjectSpawn), } } // AddObjectSpawn adds an object spawn to both the object and spawn managers func (osm *ObjectSpawnManager) AddObjectSpawn(objectSpawn *ObjectSpawn) error { // Add to spawn manager first if err := osm.spawnManager.AddSpawn(objectSpawn.Spawn); err != nil { return err } // Add to object tracking osm.objects[objectSpawn.GetID()] = objectSpawn return nil } // RemoveObjectSpawn removes an object spawn from both managers func (osm *ObjectSpawnManager) RemoveObjectSpawn(spawnID int32) error { // Remove from object tracking delete(osm.objects, spawnID) // Remove from spawn manager return osm.spawnManager.RemoveSpawn(spawnID) } // 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) // Get all spawns in zone and filter for objects spawns := osm.spawnManager.GetSpawnsByZone(zoneName) for _, spawn := range spawns { if spawn.GetSpawnType() == ObjectSpawnType { if objectSpawn, exists := osm.objects[spawn.GetID()]; exists { result = append(result, objectSpawn) } } } 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.GetAppearance() 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]interface{}) *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 { appearance := objectSpawn.GetAppearance() appearance.Pos.X = x objectSpawn.SetAppearance(appearance) } // TODO: Load other properties as needed return objectSpawn }