eq2go/internal/npc/interfaces.go

571 lines
15 KiB
Go

package npc
// 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 ...interface{})
LogError(message string, args ...interface{})
LogDebug(message string, args ...interface{})
LogWarning(message string, args ...interface{})
}
// 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 ...interface{}) error
}
// SpellManager interface for spell system integration
type SpellManager interface {
GetSpell(spellID int32, tier int8) Spell
CastSpell(caster *NPC, target interface{}, spell Spell) error
GetSpellEffect(entity interface{}, spellID int32) SpellEffect
ProcessSpell(spell Spell, caster *NPC, target interface{}) 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 interface{}, skillID int32, bonus float32) error
RemoveSkillBonus(entity interface{}, 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 interface{}) error
EndCombat(npc *NPC) error
ProcessCombatRound(npc *NPC) error
CalculateDamage(attacker *NPC, target interface{}) int32
ApplyDamage(target interface{}, 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 interface{}, 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 interface{}) 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 interface{}, 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 interface{}) 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 interface{}, 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 interface{}) 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)
}