package ai import ( "encoding/json" "fmt" "time" ) // AI tick constants const ( DefaultThinkTick int32 = 250 // Default think tick in milliseconds (1/4 second) FastThinkTick int32 = 100 // Fast think tick for active AI SlowThinkTick int32 = 1000 // Slow think tick for idle AI BlankBrainTick int32 = 50000 // Very slow tick for blank brain MaxThinkTick int32 = 60000 // Maximum think tick (1 minute) ) // Combat constants const ( MaxChaseDistance float32 = 150.0 // Default max chase distance MaxCombatRange float32 = 25.0 // Default max combat range RunbackThreshold float32 = 1.0 // Distance threshold for runback ) // Hate system constants const ( MinHateValue int32 = 1 // Minimum hate value (0 or negative is invalid) MaxHateValue int32 = 2147483647 // Maximum hate value (INT_MAX) DefaultHateValue int32 = 100 // Default hate amount MaxHateListSize int = 100 // Maximum entities in hate list ) // Encounter system constants const ( MaxEncounterSize int = 50 // Maximum entities in encounter list ) // Spell recovery constants const ( SpellRecoveryBuffer int32 = 2000 // Additional recovery time buffer (2 seconds) ) // Brain type constants for identification const ( BrainTypeDefault int8 = 0 BrainTypeCombatPet int8 = 1 BrainTypeNonCombatPet int8 = 2 BrainTypeBlank int8 = 3 BrainTypeCustom int8 = 4 BrainTypeDumbFire int8 = 5 ) // Pet movement constants const ( PetMovementFollow int8 = 0 PetMovementStay int8 = 1 PetMovementGuard int8 = 2 ) // Encounter state constants const ( EncounterStateAvailable int8 = 0 EncounterStateLocked int8 = 1 EncounterStateBroken int8 = 2 ) // Combat decision constants const ( MeleeAttackChance int = 70 // Base chance for melee attack SpellCastChance int = 30 // Base chance for spell casting BuffCheckChance int = 50 // Chance to check for buffs ) // AI state flags const ( AIStateIdle int32 = 0 AIStateCombat int32 = 1 AIStateFollowing int32 = 2 AIStateRunback int32 = 3 AIStateCasting int32 = 4 AIStateMoving int32 = 5 ) // Debug levels const ( DebugLevelNone int8 = 0 DebugLevelBasic int8 = 1 DebugLevelDetailed int8 = 2 DebugLevelVerbose int8 = 3 ) // Timer constants const ( MillisecondsPerSecond int32 = 1000 RecoveryTimeMultiple int32 = 10 // Multiply cast/recovery times by 10 ) // MovementLocation represents a location for movement/runback type MovementLocation struct { X float32 Y float32 Z float32 GridID int32 Stage int32 } // Brain interface defines all AI brain capabilities type Brain interface { // Core brain functions Think() error GetBrainType() int8 IsActive() bool SetActive(bool) GetLastThink() int64 SetLastThink(int64) GetThinkTick() int32 SetThinkTick(int32) // Hate management AddHate(entityID, hate int32) GetHate(entityID int32) int32 GetMostHated() int32 ClearHate() ClearHateForEntity(entityID int32) // Encounter management AddToEncounter(entityID, characterID int32, isPlayer, isBot bool) bool RemoveFromEncounter(entityID int32) IsInEncounter(entityID int32) bool ClearEncounter() GetEncounterSize() int // State management GetState() int32 SetState(int32) HasRecovered() bool SetSpellRecovery(int64) // Statistics GetStatistics() *BrainStatistics // Debugging SetDebugLevel(int8) GetDebugLevel() int8 } // Logger interface for AI logging type Logger interface { LogInfo(message string, args ...any) LogError(message string, args ...any) LogDebug(message string, args ...any) LogWarning(message string, args ...any) } // NPC interface defines the required NPC functionality for AI type NPC interface { // Basic NPC information GetID() int32 GetName() string GetHP() int32 GetTotalHP() int32 SetHP(int32) IsAlive() bool // Combat state GetInCombat() bool InCombat(bool) GetTarget() Entity SetTarget(Entity) // Pet functionality IsPet() bool GetOwner() Entity // Movement and positioning GetX() float32 GetY() float32 GetZ() float32 GetDistance(Entity) float32 FaceTarget(Entity, bool) IsFollowing() bool SetFollowing(bool) GetFollowTarget() Spawn SetFollowTarget(Spawn, float32) CalculateRunningLocation(bool) ClearRunningLocations() // Runback functionality IsRunningBack() bool GetRunbackLocation() *MovementLocation GetRunbackDistance() float32 Runback(float32) ShouldCallRunback() bool SetCallRunback(bool) // Status effects IsMezzedOrStunned() bool IsCasting() bool IsDazed() bool IsFeared() bool IsStifled() bool InWater() bool IsWaterCreature() bool IsFlyingCreature() bool // Combat mechanics AttackAllowed(Entity) bool PrimaryWeaponReady() bool SecondaryWeaponReady() bool SetPrimaryLastAttackTime(int64) SetSecondaryLastAttackTime(int64) MeleeAttack(Entity, float32, bool) // Spell casting GetCastPercentage() int8 GetNextSpell(Entity, float32) Spell GetNextBuffSpell(Spawn) Spell SetCastOnAggroCompleted(bool) CheckLoS(Entity) bool // Movement pausing IsPauseMovementTimerActive() bool // Encounter state SetEncounterState(int8) // Scripts GetSpawnScript() string // Utility KillSpawn(NPC) } // Entity interface for combat entities type Entity interface { Spawn GetID() int32 GetName() string GetHP() int32 GetTotalHP() int32 IsPlayer() bool IsBot() bool IsPet() bool GetOwner() Entity InWater() bool } // Spawn interface for basic spawn functionality type Spawn interface { GetID() int32 GetName() string GetX() float32 GetY() float32 GetZ() float32 } // Spell interface for spell data type Spell interface { GetSpellID() int32 GetName() string IsFriendlySpell() bool GetCastTime() int32 GetRecoveryTime() int32 GetRange() float32 GetMinRange() float32 } // Zone interface for zone-related AI operations type Zone interface { GetSpawnByID(int32) Spawn ProcessSpell(spell Spell, caster NPC, target Spawn) error CallSpawnScript(npc NPC, scriptType string, args ...any) error } // Packet types for AI communication type AIPacketType uint8 const ( AIPacketTypeUpdate AIPacketType = 1 AIPacketTypeStateUpdate AIPacketType = 2 AIPacketTypeHateUpdate AIPacketType = 3 AIPacketTypeEncounter AIPacketType = 4 AIPacketTypeCommand AIPacketType = 5 AIPacketTypeBrainType AIPacketType = 6 AIPacketTypeStatistics AIPacketType = 7 AIPacketTypeDebugUpdate AIPacketType = 8 ) // AIPacket represents an AI communication packet type AIPacket struct { Type AIPacketType `json:"type"` EntityID int32 `json:"entity_id"` Timestamp int64 `json:"timestamp"` Data map[string]interface{} `json:"data"` } // AIClient interface for AI communication type AIClient interface { SendPacket(packet *AIPacket) error BroadcastPacket(packet *AIPacket) error } // AIStatistics contains AI system statistics type AIStatistics struct { TotalBrains int `json:"total_brains"` ActiveBrains int `json:"active_brains"` TotalThinks int64 `json:"total_thinks"` BrainsByType map[string]int `json:"brains_by_type"` } // BrainStatistics contains brain performance statistics type BrainStatistics struct { ThinkCycles int64 `json:"think_cycles"` SpellsCast int64 `json:"spells_cast"` MeleeAttacks int64 `json:"melee_attacks"` HateEvents int64 `json:"hate_events"` EncounterEvents int64 `json:"encounter_events"` AverageThinkTime float64 `json:"average_think_time_ms"` LastThinkTime int64 `json:"last_think_time"` TotalActiveTime int64 `json:"total_active_time_ms"` } // NewBrainStatistics creates new brain statistics func NewBrainStatistics() *BrainStatistics { return &BrainStatistics{ ThinkCycles: 0, SpellsCast: 0, MeleeAttacks: 0, HateEvents: 0, EncounterEvents: 0, AverageThinkTime: 0.0, LastThinkTime: time.Now().UnixMilli(), TotalActiveTime: 0, } } // CreateBrain creates the appropriate brain type for an NPC func CreateBrain(npc NPC, brainType int8, logger Logger, options ...any) Brain { switch brainType { case BrainTypeCombatPet: return NewCombatPetBrain(npc, logger) case BrainTypeNonCombatPet: return NewNonCombatPetBrain(npc, logger) case BrainTypeBlank: return NewBlankBrain(npc, logger) case BrainTypeCustom: if len(options) > 0 { if customAI, ok := options[0].(CustomAI); ok { return NewCustomBrain(npc, logger, customAI) } } return NewBaseBrain(npc, logger) // Fallback to default case BrainTypeDumbFire: if len(options) >= 2 { if target, ok := options[0].(Entity); ok { if expireTime, ok := options[1].(int32); ok { return NewDumbFirePetBrain(npc, target, expireTime, logger) } } } return NewBaseBrain(npc, logger) // Fallback to default default: return NewBaseBrain(npc, logger) } } // Helper functions // getBrainTypeName returns the string name for a brain type func getBrainTypeName(brainType int8) string { switch brainType { case BrainTypeDefault: return "default" case BrainTypeCombatPet: return "combat_pet" case BrainTypeNonCombatPet: return "non_combat_pet" case BrainTypeBlank: return "blank" case BrainTypeCustom: return "custom" case BrainTypeDumbFire: return "dumbfire" default: return "unknown" } } // currentTimeMillis returns current time in milliseconds func currentTimeMillis() int64 { return time.Now().UnixMilli() } // CreateAIPacket creates a new AI packet func CreateAIPacket(packetType AIPacketType, entityID int32, data map[string]interface{}) *AIPacket { return &AIPacket{ Type: packetType, EntityID: entityID, Timestamp: currentTimeMillis(), Data: data, } } // ToJSON converts AI packet to JSON func (p *AIPacket) ToJSON() ([]byte, error) { return json.Marshal(p) } // FromJSON creates AI packet from JSON func FromJSON(data []byte) (*AIPacket, error) { var packet AIPacket err := json.Unmarshal(data, &packet) if err != nil { return nil, fmt.Errorf("failed to unmarshal AI packet: %w", err) } return &packet, nil }