package sign import "eq2emu/internal/spawn" // Player interface for sign interactions type Player interface { GetDistance(target *spawn.Spawn) float32 SetX(x float32) SetY(y float32) SetZ(z float32) SetHeading(heading float32) GetZone() Zone GetTarget() *spawn.Spawn } // Client interface for sign interactions type Client interface { GetPlayer() Player GetCharacterID() int32 GetDatabase() Database GetCurrentZone() Zone SetTemporaryTransportID(id int32) SimpleMessage(channel int32, message string) Message(channel int32, format string, args ...any) CheckZoneAccess(zoneName string) bool TryZoneInstance(zoneID int32, useDefaults bool) bool Zone(zoneName string, useDefaults bool) error ProcessTeleport(sign *Sign, destinations []TransportDestination, transporterID int32) error } // Zone interface for sign interactions type Zone interface { GetTransporters(client Client, transporterID int32) ([]TransportDestination, error) ProcessEntityCommand(command *EntityCommand, player Player, target *spawn.Spawn) error } // Database interface for sign persistence type Database interface { GetZoneName(zoneID int32) (string, error) GetCharacterName(charID int32) (string, error) SaveSignMark(charID int32, widgetID int32, charName string, client Client) error LoadSigns(zoneID int32) ([]*Sign, error) SaveSign(sign *Sign) error DeleteSign(signID int32) error } // TransportDestination represents a transport destination type TransportDestination struct { ID int32 Name string Description string ZoneID int32 X float32 Y float32 Z float32 Heading float32 } // EntityCommand represents a command that can be executed on an entity type EntityCommand struct { ID int32 Command string Name string Description string } // Logger interface for sign logging type Logger interface { LogInfo(message string, args ...any) LogError(message string, args ...any) LogDebug(message string, args ...any) LogWarning(message string, args ...any) } // SignSpawn provides sign functionality for spawn entities type SignSpawn struct { *spawn.Spawn *Sign } // NewSignSpawn creates a new sign spawn wrapper func NewSignSpawn(baseSpawn *spawn.Spawn) *SignSpawn { sign := NewSign() sign.Spawn = baseSpawn return &SignSpawn{ Spawn: baseSpawn, Sign: sign, } } // IsSign returns true since this is a sign func (ss *SignSpawn) IsSign() bool { return true } // HandleUse delegates to the sign's HandleUse method func (ss *SignSpawn) HandleUse(client Client, command string) error { return ss.Sign.HandleUse(client, command) } // Copy creates a copy of the sign spawn func (ss *SignSpawn) Copy() *SignSpawn { newSign := ss.Sign.Copy() // TODO: Enable when spawn.Copy() method is implemented // newSpawn := ss.Spawn.Copy() // For now, create a new spawn and copy basic properties newSpawn := spawn.NewSpawn() if ss.Spawn != nil { newSpawn.SetDatabaseID(ss.Spawn.GetDatabaseID()) newSpawn.SetName(ss.Spawn.GetName()) newSpawn.SetLevel(ss.Spawn.GetLevel()) newSpawn.SetX(ss.Spawn.GetX()) newSpawn.SetY(ss.Spawn.GetY(), false) newSpawn.SetZ(ss.Spawn.GetZ()) newSpawn.SetSpawnType(ss.Spawn.GetSpawnType()) newSpawn.SetFactionID(ss.Spawn.GetFactionID()) newSpawn.SetSize(ss.Spawn.GetSize()) } return &SignSpawn{ Spawn: newSpawn, Sign: newSign, } } // SignAware interface for entities that can interact with signs type SignAware interface { GetSign() *Sign IsSign() bool HandleSignUse(client Client, command string) error } // SignAdapter provides sign functionality for any entity type SignAdapter struct { entity Entity sign *Sign logger Logger } // Entity interface for things that can have sign functionality type Entity interface { GetID() int32 GetName() string GetDatabaseID() int32 } // NewSignAdapter creates a new sign adapter func NewSignAdapter(entity Entity, logger Logger) *SignAdapter { return &SignAdapter{ entity: entity, sign: NewSign(), logger: logger, } } // GetSign returns the sign func (sa *SignAdapter) GetSign() *Sign { return sa.sign } // IsSign returns true since this has sign functionality func (sa *SignAdapter) IsSign() bool { return true } // HandleSignUse handles sign usage func (sa *SignAdapter) HandleSignUse(client Client, command string) error { if sa.logger != nil { sa.logger.LogDebug("Entity %d (%s): Handling sign use with command '%s'", sa.entity.GetID(), sa.entity.GetName(), command) } return sa.sign.HandleUse(client, command) } // SetSignTitle sets the sign title func (sa *SignAdapter) SetSignTitle(title string) { sa.sign.SetSignTitle(title) if sa.logger != nil { sa.logger.LogDebug("Entity %d (%s): Set sign title to '%s'", sa.entity.GetID(), sa.entity.GetName(), title) } } // SetSignDescription sets the sign description func (sa *SignAdapter) SetSignDescription(description string) { sa.sign.SetSignDescription(description) if sa.logger != nil { sa.logger.LogDebug("Entity %d (%s): Set sign description", sa.entity.GetID(), sa.entity.GetName()) } } // SetSignType sets the sign type func (sa *SignAdapter) SetSignType(signType int8) { sa.sign.SetSignType(signType) if sa.logger != nil { sa.logger.LogDebug("Entity %d (%s): Set sign type to %d", sa.entity.GetID(), sa.entity.GetName(), signType) } } // SetZoneTransport configures the sign for zone transport func (sa *SignAdapter) SetZoneTransport(zoneID int32, x, y, z, heading float32) { sa.sign.SetSignType(SignTypeZone) sa.sign.SetSignZoneID(zoneID) sa.sign.SetSignZoneX(x) sa.sign.SetSignZoneY(y) sa.sign.SetSignZoneZ(z) sa.sign.SetSignZoneHeading(heading) if sa.logger != nil { sa.logger.LogDebug("Entity %d (%s): Configured zone transport to zone %d at (%.2f, %.2f, %.2f)", sa.entity.GetID(), sa.entity.GetName(), zoneID, x, y, z) } } // SetSignDistance sets the interaction distance func (sa *SignAdapter) SetSignDistance(distance float32) { sa.sign.SetSignDistance(distance) if sa.logger != nil { sa.logger.LogDebug("Entity %d (%s): Set sign distance to %.2f", sa.entity.GetID(), sa.entity.GetName(), distance) } } // Validate validates the sign configuration func (sa *SignAdapter) Validate() []string { return sa.sign.Validate() } // IsValid returns true if the sign is valid func (sa *SignAdapter) IsValid() bool { return sa.sign.IsValid() }