package npc import "fmt" // Database interface for NPC persistence type Database interface { LoadAllNPCs() ([]*NPC, error) SaveNPC(npc *NPC) error DeleteNPC(npcID int32) error LoadNPCSpells(npcID int32) ([]*NPCSpell, error) SaveNPCSpells(npcID int32, spells []*NPCSpell) error LoadNPCSkills(npcID int32) (map[string]*Skill, error) SaveNPCSkills(npcID int32, skills map[string]*Skill) error } // Logger interface for NPC logging type Logger interface { LogInfo(message string, args ...any) LogError(message string, args ...any) LogDebug(message string, args ...any) LogWarning(message string, args ...any) } // Client interface for NPC-related client operations type Client interface { GetPlayer() Player GetVersion() int16 SendNPCUpdate(npcData []byte) error SendCombatUpdate(combatData []byte) error SendSpellCast(spellData []byte) error } // Player interface for NPC-related player operations type Player interface { GetCharacterID() int32 GetName() string GetLevel() int8 GetZoneID() int32 GetX() float32 GetY() float32 GetZ() float32 IsInCombat() bool GetTarget() *NPC SendMessage(message string) } // Zone interface for NPC zone operations type Zone interface { GetZoneID() int32 GetNPCs() []*NPC AddNPC(npc *NPC) error RemoveNPC(npcID int32) error GetPlayersInRange(x, y, z, radius float32) []Player ProcessEntityCommand(command string, client Client, target *NPC) error CallSpawnScript(npc *NPC, scriptType string, args ...any) error } // SpellManager interface for spell system integration type SpellManager interface { GetSpell(spellID int32, tier int8) Spell CastSpell(caster *NPC, target any, spell Spell) error GetSpellEffect(entity any, spellID int32) SpellEffect ProcessSpell(spell Spell, caster *NPC, target any) error } // Spell interface for spell data type Spell interface { GetSpellID() int32 GetName() string GetTier() int8 GetRange() float32 GetMinRange() float32 GetPowerRequired() int32 IsFriendlySpell() bool IsToggleSpell() bool GetCastTime() int32 GetRecastTime() int32 } // SpellEffect interface for active spell effects type SpellEffect interface { GetSpellID() int32 GetTier() int8 GetDuration() int32 GetRemainingTime() int32 IsExpired() bool } // SkillManager interface for skill system integration type SkillManager interface { GetSkill(skillID int32) MasterSkill GetSkillByName(name string) MasterSkill ApplySkillBonus(entity any, skillID int32, bonus float32) error RemoveSkillBonus(entity any, skillID int32, bonus float32) error } // MasterSkill interface for skill definitions type MasterSkill interface { GetSkillID() int32 GetName() string GetDescription() string GetMaxValue() int16 } // AppearanceManager interface for appearance system integration type AppearanceManager interface { GetAppearance(appearanceID int32) Appearance GetAppearancesByName(name string) []Appearance RandomizeAppearance(npc *NPC, flags int32) error } // Appearance interface for appearance data type Appearance interface { GetAppearanceID() int32 GetName() string GetModelType() int16 GetRace() int16 GetGender() int8 } // MovementManager interface for movement system integration type MovementManager interface { StartMovement(npc *NPC, x, y, z float32) error StopMovement(npc *NPC) error SetSpeed(npc *NPC, speed float32) error NavigateToLocation(npc *NPC, x, y, z float32) error IsMoving(npc *NPC) bool } // CombatManager interface for combat system integration type CombatManager interface { StartCombat(npc *NPC, target any) error EndCombat(npc *NPC) error ProcessCombatRound(npc *NPC) error CalculateDamage(attacker *NPC, target any) int32 ApplyDamage(target any, damage int32) error } // NPCAware interface for entities that can interact with NPCs type NPCAware interface { GetNPC() *NPC IsNPC() bool HandleNPCInteraction(npc *NPC, interactionType string) error ReceiveNPCCommand(npc *NPC, command string) error } // EntityAdapter provides NPC functionality for entities type EntityAdapter struct { npc *NPC logger Logger } // NewEntityAdapter creates a new entity adapter func NewEntityAdapter(npc *NPC, logger Logger) *EntityAdapter { return &EntityAdapter{ npc: npc, logger: logger, } } // GetNPC returns the associated NPC func (ea *EntityAdapter) GetNPC() *NPC { return ea.npc } // IsNPC always returns true for entity adapters func (ea *EntityAdapter) IsNPC() bool { return true } // HandleNPCInteraction processes interactions with other NPCs func (ea *EntityAdapter) HandleNPCInteraction(otherNPC *NPC, interactionType string) error { if ea.npc == nil || otherNPC == nil { return fmt.Errorf("invalid NPC for interaction") } // Handle different interaction types switch interactionType { case "aggro": return ea.handleAggroInteraction(otherNPC) case "assist": return ea.handleAssistInteraction(otherNPC) case "trade": return ea.handleTradeInteraction(otherNPC) default: if ea.logger != nil { ea.logger.LogWarning("Unknown NPC interaction type: %s", interactionType) } return fmt.Errorf("unknown interaction type: %s", interactionType) } } // ReceiveNPCCommand processes commands from other NPCs func (ea *EntityAdapter) ReceiveNPCCommand(otherNPC *NPC, command string) error { if ea.npc == nil || otherNPC == nil { return fmt.Errorf("invalid NPC for command") } // Process the command switch command { case "follow": return ea.handleFollowCommand(otherNPC) case "attack": return ea.handleAttackCommand(otherNPC) case "retreat": return ea.handleRetreatCommand(otherNPC) default: if ea.logger != nil { ea.logger.LogWarning("Unknown NPC command: %s", command) } return fmt.Errorf("unknown command: %s", command) } } // handleAggroInteraction processes aggro interactions func (ea *EntityAdapter) handleAggroInteraction(otherNPC *NPC) error { // TODO: Implement aggro logic between NPCs if ea.logger != nil { ea.logger.LogDebug("NPC %d received aggro from NPC %d", ea.npc.GetNPCID(), otherNPC.GetNPCID()) } return nil } // handleAssistInteraction processes assist interactions func (ea *EntityAdapter) handleAssistInteraction(otherNPC *NPC) error { // TODO: Implement assist logic between NPCs if ea.logger != nil { ea.logger.LogDebug("NPC %d received assist request from NPC %d", ea.npc.GetNPCID(), otherNPC.GetNPCID()) } return nil } // handleTradeInteraction processes trade interactions func (ea *EntityAdapter) handleTradeInteraction(otherNPC *NPC) error { // TODO: Implement trade logic between NPCs if ea.logger != nil { ea.logger.LogDebug("NPC %d received trade request from NPC %d", ea.npc.GetNPCID(), otherNPC.GetNPCID()) } return nil } // handleFollowCommand processes follow commands func (ea *EntityAdapter) handleFollowCommand(otherNPC *NPC) error { // TODO: Implement follow logic if ea.logger != nil { ea.logger.LogDebug("NPC %d received follow command from NPC %d", ea.npc.GetNPCID(), otherNPC.GetNPCID()) } return nil } // handleAttackCommand processes attack commands func (ea *EntityAdapter) handleAttackCommand(otherNPC *NPC) error { // TODO: Implement attack logic if ea.logger != nil { ea.logger.LogDebug("NPC %d received attack command from NPC %d", ea.npc.GetNPCID(), otherNPC.GetNPCID()) } return nil } // handleRetreatCommand processes retreat commands func (ea *EntityAdapter) handleRetreatCommand(otherNPC *NPC) error { // TODO: Implement retreat logic if ea.logger != nil { ea.logger.LogDebug("NPC %d received retreat command from NPC %d", ea.npc.GetNPCID(), otherNPC.GetNPCID()) } return nil } // SpellCasterAdapter provides spell casting functionality for NPCs type SpellCasterAdapter struct { npc *NPC spellManager SpellManager logger Logger } // NewSpellCasterAdapter creates a new spell caster adapter func NewSpellCasterAdapter(npc *NPC, spellManager SpellManager, logger Logger) *SpellCasterAdapter { return &SpellCasterAdapter{ npc: npc, spellManager: spellManager, logger: logger, } } // GetNextSpell selects the next spell to cast based on AI strategy func (sca *SpellCasterAdapter) GetNextSpell(target any, distance float32) Spell { if sca.npc == nil || sca.spellManager == nil { return nil } // Check cast-on-aggro spells first if !sca.npc.castOnAggroCompleted { spell := sca.getNextCastOnAggroSpell(target) if spell != nil { return spell } sca.npc.castOnAggroCompleted = true } // Get spells based on AI strategy strategy := sca.npc.GetAIStrategy() return sca.getNextSpellByStrategy(target, distance, strategy) } // GetNextBuffSpell selects the next buff spell to cast func (sca *SpellCasterAdapter) GetNextBuffSpell(target any) Spell { if sca.npc == nil || sca.spellManager == nil { return nil } // Check cast-on-spawn spells first castOnSpells := sca.npc.castOnSpells[CastOnSpawn] for _, npcSpell := range castOnSpells { spell := sca.spellManager.GetSpell(npcSpell.GetSpellID(), npcSpell.GetTier()) if spell != nil { // Check if target already has this effect if effect := sca.spellManager.GetSpellEffect(target, spell.GetSpellID()); effect != nil { if effect.GetTier() < spell.GetTier() { return spell // Upgrade existing effect } } else { return spell // New effect } } } // Check regular spells for buffs for _, npcSpell := range sca.npc.spells { spell := sca.spellManager.GetSpell(npcSpell.GetSpellID(), npcSpell.GetTier()) if spell != nil && spell.IsFriendlySpell() && spell.IsToggleSpell() { // Check if target already has this effect if effect := sca.spellManager.GetSpellEffect(target, spell.GetSpellID()); effect != nil { if effect.GetTier() < spell.GetTier() { return spell // Upgrade existing effect } } else { return spell // New effect } } } return nil } // CastSpell attempts to cast a spell func (sca *SpellCasterAdapter) CastSpell(target any, spell Spell) error { if sca.npc == nil || sca.spellManager == nil || spell == nil { return fmt.Errorf("invalid parameters for spell casting") } // Check casting conditions if err := sca.checkCastingConditions(spell); err != nil { return fmt.Errorf("casting conditions not met: %w", err) } // Cast the spell if err := sca.spellManager.CastSpell(sca.npc, target, spell); err != nil { return fmt.Errorf("failed to cast spell: %w", err) } if sca.logger != nil { sca.logger.LogDebug("NPC %d cast spell %s (%d)", sca.npc.GetNPCID(), spell.GetName(), spell.GetSpellID()) } return nil } // getNextCastOnAggroSpell selects cast-on-aggro spells func (sca *SpellCasterAdapter) getNextCastOnAggroSpell(target any) Spell { castOnSpells := sca.npc.castOnSpells[CastOnAggro] for _, npcSpell := range castOnSpells { spell := sca.spellManager.GetSpell(npcSpell.GetSpellID(), npcSpell.GetTier()) if spell != nil { // Check if target doesn't already have this effect if effect := sca.spellManager.GetSpellEffect(target, spell.GetSpellID()); effect == nil { return spell } } } return nil } // getNextSpellByStrategy selects spells based on AI strategy func (sca *SpellCasterAdapter) getNextSpellByStrategy(target any, distance float32, strategy int8) Spell { // TODO: Implement more sophisticated spell selection based on strategy for _, npcSpell := range sca.npc.spells { // Check HP ratio requirements if npcSpell.GetRequiredHPRatio() != 0 { // TODO: Implement HP ratio checking } spell := sca.spellManager.GetSpell(npcSpell.GetSpellID(), npcSpell.GetTier()) if spell == nil { continue } // Check strategy compatibility if strategy == AIStrategyOffensive && spell.IsFriendlySpell() { continue } if strategy == AIStrategyDefensive && !spell.IsFriendlySpell() { continue } // Check range and power requirements if distance <= spell.GetRange() && distance >= spell.GetMinRange() { // TODO: Check power requirements return spell } } return nil } // checkCastingConditions validates spell casting conditions func (sca *SpellCasterAdapter) checkCastingConditions(spell Spell) error { if sca.npc.Entity == nil { return fmt.Errorf("NPC entity is nil") } // TODO: Implement power checking, cooldown checking, etc. return nil } // CombatAdapter provides combat functionality for NPCs type CombatAdapter struct { npc *NPC combatManager CombatManager logger Logger } // NewCombatAdapter creates a new combat adapter func NewCombatAdapter(npc *NPC, combatManager CombatManager, logger Logger) *CombatAdapter { return &CombatAdapter{ npc: npc, combatManager: combatManager, logger: logger, } } // EnterCombat handles entering combat state func (ca *CombatAdapter) EnterCombat(target any) error { if ca.npc == nil { return fmt.Errorf("NPC is nil") } // Start combat through combat manager if ca.combatManager != nil { if err := ca.combatManager.StartCombat(ca.npc, target); err != nil { return fmt.Errorf("failed to start combat: %w", err) } } // Update NPC state ca.npc.InCombat(true) if ca.logger != nil { ca.logger.LogDebug("NPC %d entered combat", ca.npc.GetNPCID()) } return nil } // ExitCombat handles exiting combat state func (ca *CombatAdapter) ExitCombat() error { if ca.npc == nil { return fmt.Errorf("NPC is nil") } // End combat through combat manager if ca.combatManager != nil { if err := ca.combatManager.EndCombat(ca.npc); err != nil { return fmt.Errorf("failed to end combat: %w", err) } } // Update NPC state ca.npc.InCombat(false) if ca.logger != nil { ca.logger.LogDebug("NPC %d exited combat", ca.npc.GetNPCID()) } return nil } // ProcessCombat handles combat processing func (ca *CombatAdapter) ProcessCombat() error { if ca.npc == nil { return fmt.Errorf("NPC is nil") } if ca.combatManager != nil { return ca.combatManager.ProcessCombatRound(ca.npc) } return nil } // MovementAdapter provides movement functionality for NPCs type MovementAdapter struct { npc *NPC movementManager MovementManager logger Logger } // NewMovementAdapter creates a new movement adapter func NewMovementAdapter(npc *NPC, movementManager MovementManager, logger Logger) *MovementAdapter { return &MovementAdapter{ npc: npc, movementManager: movementManager, logger: logger, } } // MoveToLocation moves the NPC to a specific location func (ma *MovementAdapter) MoveToLocation(x, y, z float32) error { if ma.npc == nil { return fmt.Errorf("NPC is nil") } if ma.movementManager != nil { return ma.movementManager.NavigateToLocation(ma.npc, x, y, z) } return fmt.Errorf("movement manager not available") } // StopMovement stops the NPC's movement func (ma *MovementAdapter) StopMovement() error { if ma.npc == nil { return fmt.Errorf("NPC is nil") } if ma.movementManager != nil { return ma.movementManager.StopMovement(ma.npc) } return fmt.Errorf("movement manager not available") } // IsMoving checks if the NPC is currently moving func (ma *MovementAdapter) IsMoving() bool { if ma.npc == nil || ma.movementManager == nil { return false } return ma.movementManager.IsMoving(ma.npc) } // RunbackToSpawn moves the NPC back to its spawn location func (ma *MovementAdapter) RunbackToSpawn() error { if ma.npc == nil { return fmt.Errorf("NPC is nil") } runbackLocation := ma.npc.GetRunbackLocation() if runbackLocation == nil { return fmt.Errorf("no runback location set") } return ma.MoveToLocation(runbackLocation.X, runbackLocation.Y, runbackLocation.Z) }