eq2go/internal/npc/ai/custom.go
2025-08-29 17:48:39 -05:00

227 lines
6.7 KiB
Go

package ai
import (
"fmt"
)
// CustomAI defines a Go-based custom AI behavior interface
type CustomAI interface {
// Think is called every AI tick for custom behavior
Think(npc NPC, target Entity, brain Brain) error
// OnCombatStart is called when entering combat
OnCombatStart(npc NPC, target Entity, brain Brain) error
// OnCombatEnd is called when leaving combat
OnCombatEnd(npc NPC, brain Brain) error
// OnDamageReceived is called when NPC takes damage
OnDamageReceived(npc NPC, attacker Entity, damage int32, brain Brain) error
// OnTargetChanged is called when NPC changes target
OnTargetChanged(npc NPC, oldTarget, newTarget Entity, brain Brain) error
}
// CustomBrain allows AI to be controlled by Go-based custom AI implementations
type CustomBrain struct {
*BaseBrain
customAI CustomAI
}
// NewCustomBrain creates a new custom AI brain
func NewCustomBrain(npc NPC, logger Logger, customAI CustomAI) *CustomBrain {
brain := &CustomBrain{
BaseBrain: NewBaseBrain(npc, logger),
customAI: customAI,
}
brain.brainType = BrainTypeCustom
return brain
}
// Think calls the custom AI's Think function
func (cb *CustomBrain) Think() error {
if cb.customAI == nil {
// Fall back to default behavior if no custom AI
return cb.BaseBrain.Think()
}
if cb.npc == nil {
return fmt.Errorf("brain has no body")
}
target := cb.npc.GetTarget()
err := cb.customAI.Think(cb.npc, target, cb)
if err != nil {
if cb.logger != nil {
cb.logger.LogError("Custom AI Think function failed: %v", err)
}
return fmt.Errorf("custom AI Think function failed: %w", err)
}
return nil
}
// SetCustomAI sets the custom AI implementation
func (cb *CustomBrain) SetCustomAI(customAI CustomAI) {
cb.customAI = customAI
}
// GetCustomAI returns the custom AI implementation
func (cb *CustomBrain) GetCustomAI() CustomAI {
return cb.customAI
}
// NotifyCombatStart notifies custom AI of combat start
func (cb *CustomBrain) NotifyCombatStart(target Entity) {
if cb.customAI != nil {
if err := cb.customAI.OnCombatStart(cb.npc, target, cb); err != nil && cb.logger != nil {
cb.logger.LogError("Custom AI OnCombatStart failed: %v", err)
}
}
}
// NotifyCombatEnd notifies custom AI of combat end
func (cb *CustomBrain) NotifyCombatEnd() {
if cb.customAI != nil {
if err := cb.customAI.OnCombatEnd(cb.npc, cb); err != nil && cb.logger != nil {
cb.logger.LogError("Custom AI OnCombatEnd failed: %v", err)
}
}
}
// NotifyDamageReceived notifies custom AI of damage received
func (cb *CustomBrain) NotifyDamageReceived(attacker Entity, damage int32) {
if cb.customAI != nil {
if err := cb.customAI.OnDamageReceived(cb.npc, attacker, damage, cb); err != nil && cb.logger != nil {
cb.logger.LogError("Custom AI OnDamageReceived failed: %v", err)
}
}
}
// NotifyTargetChanged notifies custom AI of target change
func (cb *CustomBrain) NotifyTargetChanged(oldTarget, newTarget Entity) {
if cb.customAI != nil {
if err := cb.customAI.OnTargetChanged(cb.npc, oldTarget, newTarget, cb); err != nil && cb.logger != nil {
cb.logger.LogError("Custom AI OnTargetChanged failed: %v", err)
}
}
}
// Example Custom AI implementations for demonstration
// AggressiveAI implements CustomAI for aggressive behavior
type AggressiveAI struct{}
// Think implements aggressive AI behavior
func (a *AggressiveAI) Think(npc NPC, target Entity, brain Brain) error {
// Always try to attack if we have a target
if target != nil {
distance := npc.GetDistance(target)
if distance <= 25.0 { // Within range
// Force attack more frequently than normal
if npc.PrimaryWeaponReady() {
npc.MeleeAttack(target, distance, true)
}
}
}
// Fall back to base brain behavior for movement, spells, etc.
return brain.(*CustomBrain).BaseBrain.Think()
}
// OnCombatStart implements aggressive combat start
func (a *AggressiveAI) OnCombatStart(npc NPC, target Entity, brain Brain) error {
// Add extra hate when combat starts
if target != nil {
brain.AddHate(target.GetID(), DefaultHateValue*2)
}
return nil
}
// OnCombatEnd implements aggressive combat end
func (a *AggressiveAI) OnCombatEnd(npc NPC, brain Brain) error {
// Stay alert longer after combat
brain.SetThinkTick(FastThinkTick)
return nil
}
// OnDamageReceived implements aggressive damage response
func (a *AggressiveAI) OnDamageReceived(npc NPC, attacker Entity, damage int32, brain Brain) error {
// Add extra hate when damaged
if attacker != nil {
brain.AddHate(attacker.GetID(), damage*2)
}
return nil
}
// OnTargetChanged implements aggressive target change
func (a *AggressiveAI) OnTargetChanged(npc NPC, oldTarget, newTarget Entity, brain Brain) error {
// No special behavior for target changes in aggressive AI
return nil
}
// DefensiveAI implements CustomAI for defensive behavior
type DefensiveAI struct {
fleeThreshold int32 // HP threshold to flee at
}
// NewDefensiveAI creates a defensive AI with flee threshold
func NewDefensiveAI(fleeThreshold int32) *DefensiveAI {
return &DefensiveAI{
fleeThreshold: fleeThreshold,
}
}
// Think implements defensive AI behavior
func (d *DefensiveAI) Think(npc NPC, target Entity, brain Brain) error {
// Check if we should flee
if npc.GetHP() <= d.fleeThreshold {
// Try to run back to spawn point
if npc.ShouldCallRunback() {
npc.Runback(npc.GetRunbackDistance())
}
return nil
}
// Otherwise use normal behavior but with slower think tick
brain.SetThinkTick(SlowThinkTick)
return brain.(*CustomBrain).BaseBrain.Think()
}
// OnCombatStart implements defensive combat start
func (d *DefensiveAI) OnCombatStart(npc NPC, target Entity, brain Brain) error {
// No special behavior for defensive AI
return nil
}
// OnCombatEnd implements defensive combat end
func (d *DefensiveAI) OnCombatEnd(npc NPC, brain Brain) error {
// Slow down thinking after combat
brain.SetThinkTick(SlowThinkTick)
return nil
}
// OnDamageReceived implements defensive damage response
func (d *DefensiveAI) OnDamageReceived(npc NPC, attacker Entity, damage int32, brain Brain) error {
// Check if we should start fleeing
if npc.GetHP() <= d.fleeThreshold && attacker != nil {
// Remove hate and try to flee
brain.ClearHateForEntity(attacker.GetID())
}
return nil
}
// OnTargetChanged implements defensive target change
func (d *DefensiveAI) OnTargetChanged(npc NPC, oldTarget, newTarget Entity, brain Brain) error {
// No special behavior for target changes in defensive AI
return nil
}
// CreateAggressiveBrain creates a brain with aggressive AI behavior
func CreateAggressiveBrain(npc NPC, logger Logger) Brain {
return NewCustomBrain(npc, logger, &AggressiveAI{})
}
// CreateDefensiveBrain creates a brain with defensive AI behavior
func CreateDefensiveBrain(npc NPC, logger Logger, fleeThreshold int32) Brain {
return NewCustomBrain(npc, logger, NewDefensiveAI(fleeThreshold))
}