package functions import ( "fmt" "eq2emu/internal/events" ) // Combat and AI Functions // Attack makes the spawn attack a target func Attack(ctx *events.EventContext) error { spawn := ctx.GetSpawn() target := ctx.GetTarget() if spawn == nil { return fmt.Errorf("no spawn in context") } if target == nil { return fmt.Errorf("no target in context") } // TODO: Implement attack system ctx.Debug("Spawn %s attacking target %s (not yet implemented)", spawn.GetName(), target.GetName()) return nil } // AddHate adds hate/threat to the spawn's hate list func AddHate(ctx *events.EventContext) error { spawn := ctx.GetSpawn() target := ctx.GetTarget() if spawn == nil { return fmt.Errorf("no spawn in context") } if target == nil { return fmt.Errorf("no target in context") } hateAmount := ctx.GetParameterFloat("hate", 0) // TODO: Implement hate/threat system ctx.Debug("Added %f hate from %s to %s (not yet implemented)", hateAmount, spawn.GetName(), target.GetName()) return nil } // ClearHate clears the spawn's hate list func ClearHate(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement hate clearing ctx.Debug("Cleared hate list for spawn %s (not yet implemented)", spawn.GetName()) return nil } // GetMostHated gets the most hated target func GetMostHated(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement hate list management // Return nil for now (no most hated) ctx.SetResult("most_hated", nil) return nil } // SetTarget sets the spawn's target func SetTarget(ctx *events.EventContext) error { spawn := ctx.GetSpawn() target := ctx.GetTarget() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement target setting if target != nil { ctx.Debug("Set target for %s to %s (not yet implemented)", spawn.GetName(), target.GetName()) } else { ctx.Debug("Cleared target for %s (not yet implemented)", spawn.GetName()) } return nil } // GetTarget gets the spawn's current target func GetTarget(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement target retrieval ctx.SetResult("target", nil) // No target for now return nil } // IsInCombat checks if the spawn is in combat func IsInCombat(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement combat state tracking ctx.SetResult("in_combat", false) return nil } // SetInCombat sets the spawn's combat state func SetInCombat(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } inCombat := ctx.GetParameterBool("in_combat", false) // TODO: Implement combat state setting ctx.Debug("Set combat state to %t for spawn %s (not yet implemented)", inCombat, spawn.GetName()) return nil } // SpellDamage deals spell damage to a target func SpellDamage(ctx *events.EventContext) error { caster := ctx.GetCaster() target := ctx.GetTarget() if caster == nil { return fmt.Errorf("no caster in context") } if target == nil { return fmt.Errorf("no target in context") } damage := ctx.GetParameterFloat("damage", 0) damageType := ctx.GetParameterInt("damage_type", 0) if damage <= 0 { return fmt.Errorf("damage must be positive") } // TODO: Implement spell damage system with damage types, resistances, etc. ctx.Debug("Spell damage %f (type %d) from %s to %s (not yet implemented)", damage, damageType, caster.GetName(), target.GetName()) ctx.SetResult("damage_dealt", damage) return nil } // SpellDamageExt deals extended spell damage with more options func SpellDamageExt(ctx *events.EventContext) error { caster := ctx.GetCaster() target := ctx.GetTarget() if caster == nil { return fmt.Errorf("no caster in context") } if target == nil { return fmt.Errorf("no target in context") } damage := ctx.GetParameterFloat("damage", 0) damageType := ctx.GetParameterInt("damage_type", 0) hitType := ctx.GetParameterInt("hit_type", 0) spellID := ctx.GetParameterInt("spell_id", 0) if damage <= 0 { return fmt.Errorf("damage must be positive") } // TODO: Implement extended spell damage system ctx.Debug("Extended spell damage %f (type %d, hit %d, spell %d) from %s to %s (not yet implemented)", damage, damageType, hitType, spellID, caster.GetName(), target.GetName()) ctx.SetResult("damage_dealt", damage) return nil } // DamageSpawn deals direct damage to a spawn func DamageSpawn(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } damage := ctx.GetParameterFloat("damage", 0) if damage <= 0 { return fmt.Errorf("damage must be positive") } // Apply damage to HP currentHP := float64(spawn.GetHP()) newHP := currentHP - damage if newHP < 0 { newHP = 0 } spawn.SetHP(int32(newHP)) ctx.SetResult("damage_dealt", damage) ctx.Debug("Dealt %f damage to spawn %s (new HP: %f)", damage, spawn.GetName(), newHP) // Update alive state if necessary if newHP <= 0 && spawn.IsAlive() { spawn.SetAlive(false) ctx.Debug("Spawn %s died from damage", spawn.GetName()) } return nil } // ProcDamage handles proc-based damage func ProcDamage(ctx *events.EventContext) error { caster := ctx.GetCaster() target := ctx.GetTarget() if caster == nil { return fmt.Errorf("no caster in context") } if target == nil { return fmt.Errorf("no target in context") } damage := ctx.GetParameterFloat("damage", 0) damageType := ctx.GetParameterInt("damage_type", 0) if damage <= 0 { return fmt.Errorf("damage must be positive") } // TODO: Implement proc damage system ctx.Debug("Proc damage %f (type %d) from %s to %s (not yet implemented)", damage, damageType, caster.GetName(), target.GetName()) ctx.SetResult("damage_dealt", damage) return nil } // ProcHate handles proc-based hate generation func ProcHate(ctx *events.EventContext) error { caster := ctx.GetCaster() target := ctx.GetTarget() if caster == nil { return fmt.Errorf("no caster in context") } if target == nil { return fmt.Errorf("no target in context") } hateAmount := ctx.GetParameterFloat("hate", 0) // TODO: Implement proc hate system ctx.Debug("Proc hate %f from %s to %s (not yet implemented)", hateAmount, caster.GetName(), target.GetName()) return nil } // Knockback applies knockback effect to target func Knockback(ctx *events.EventContext) error { caster := ctx.GetCaster() target := ctx.GetTarget() if caster == nil { return fmt.Errorf("no caster in context") } if target == nil { return fmt.Errorf("no target in context") } distance := ctx.GetParameterFloat("distance", 5.0) verticalLift := ctx.GetParameterFloat("vertical", 0.0) // TODO: Implement knockback system ctx.Debug("Knockback target %s distance %f with vertical %f from %s (not yet implemented)", target.GetName(), distance, verticalLift, caster.GetName()) return nil } // Interrupt interrupts the target's spell casting func Interrupt(ctx *events.EventContext) error { target := ctx.GetTarget() if target == nil { return fmt.Errorf("no target in context") } // TODO: Implement interrupt system ctx.Debug("Interrupted spell casting for %s (not yet implemented)", target.GetName()) return nil } // IsCasting checks if the spawn is currently casting func IsCasting(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement casting state tracking ctx.SetResult("is_casting", false) return nil } // HasRecovered checks if the spawn has recovered from an action func HasRecovered(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement recovery tracking ctx.SetResult("has_recovered", true) return nil } // ProcessMelee processes melee combat func ProcessMelee(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement melee processing ctx.Debug("Processing melee for spawn %s (not yet implemented)", spawn.GetName()) return nil } // ProcessSpell processes spell casting func ProcessSpell(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement spell processing ctx.Debug("Processing spells for spawn %s (not yet implemented)", spawn.GetName()) return nil } // LastSpellAttackHit checks if last spell attack hit func LastSpellAttackHit(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement spell hit tracking ctx.SetResult("last_spell_hit", false) return nil } // IsBehind checks if spawn is behind target func IsBehind(ctx *events.EventContext) error { spawn := ctx.GetSpawn() target := ctx.GetTarget() if spawn == nil { return fmt.Errorf("no spawn in context") } if target == nil { return fmt.Errorf("no target in context") } // TODO: Implement position-based behind check ctx.SetResult("is_behind", false) return nil } // IsFlanking checks if spawn is flanking target func IsFlanking(ctx *events.EventContext) error { spawn := ctx.GetSpawn() target := ctx.GetTarget() if spawn == nil { return fmt.Errorf("no spawn in context") } if target == nil { return fmt.Errorf("no target in context") } // TODO: Implement position-based flanking check ctx.SetResult("is_flanking", false) return nil } // InFront checks if spawn is in front of target func InFront(ctx *events.EventContext) error { spawn := ctx.GetSpawn() target := ctx.GetTarget() if spawn == nil { return fmt.Errorf("no spawn in context") } if target == nil { return fmt.Errorf("no target in context") } // TODO: Implement position-based front check ctx.SetResult("in_front", false) return nil } // GetEncounterSize gets the size of the current encounter func GetEncounterSize(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement encounter tracking ctx.SetResult("encounter_size", 0) return nil } // GetEncounter gets the current encounter list func GetEncounter(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement encounter retrieval ctx.SetResult("encounter", []interface{}{}) // Empty list for now return nil } // GetHateList gets the spawn's hate list func GetHateList(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement hate list retrieval ctx.SetResult("hate_list", []interface{}{}) // Empty list for now return nil } // ClearEncounter clears the current encounter func ClearEncounter(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement encounter clearing ctx.Debug("Cleared encounter for spawn %s (not yet implemented)", spawn.GetName()) return nil } // ClearRunback clears runback behavior func ClearRunback(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement runback clearing ctx.Debug("Cleared runback for spawn %s (not yet implemented)", spawn.GetName()) return nil } // Runback initiates runback behavior func Runback(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement runback behavior ctx.Debug("Initiated runback for spawn %s (not yet implemented)", spawn.GetName()) return nil } // GetRunbackDistance gets the runback distance func GetRunbackDistance(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement runback distance calculation ctx.SetResult("runback_distance", 50.0) // Default runback distance return nil } // CompareSpawns compares two spawns (for AI decision making) func CompareSpawns(ctx *events.EventContext) error { spawn := ctx.GetSpawn() target := ctx.GetTarget() if spawn == nil { return fmt.Errorf("no spawn in context") } if target == nil { return fmt.Errorf("no target in context") } // TODO: Implement spawn comparison logic ctx.SetResult("comparison_result", 0) // Equal return nil } // KillSpawn instantly kills a spawn func KillSpawn(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } spawn.SetHP(0) spawn.SetAlive(false) ctx.Debug("Killed spawn %s", spawn.GetName()) return nil } // KillSpawnByDistance kills spawns within a distance func KillSpawnByDistance(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } distance := ctx.GetParameterFloat("distance", 10.0) // TODO: Implement distance-based killing ctx.Debug("Killed spawns within distance %f of %s (not yet implemented)", distance, spawn.GetName()) return nil } // Resurrect resurrects a dead spawn func Resurrect(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } hpPercent := ctx.GetParameterFloat("hp_percent", 100.0) powerPercent := ctx.GetParameterFloat("power_percent", 100.0) // Restore HP and power maxHP := float64(spawn.GetTotalHP()) maxPower := float64(spawn.GetTotalPower()) newHP := maxHP * (hpPercent / 100.0) newPower := maxPower * (powerPercent / 100.0) spawn.SetHP(int32(newHP)) spawn.SetPower(int32(newPower)) spawn.SetAlive(true) ctx.Debug("Resurrected spawn %s with %.1f%% HP and %.1f%% power", spawn.GetName(), hpPercent, powerPercent) return nil } // IsInvulnerable checks if spawn is invulnerable func IsInvulnerable(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } // TODO: Implement invulnerability system ctx.SetResult("is_invulnerable", false) return nil } // SetInvulnerable sets spawn's invulnerability func SetInvulnerable(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } invulnerable := ctx.GetParameterBool("invulnerable", false) // TODO: Implement invulnerability system ctx.Debug("Set invulnerable to %t for spawn %s (not yet implemented)", invulnerable, spawn.GetName()) return nil } // SetAttackable sets whether the spawn can be attacked func SetAttackable(ctx *events.EventContext) error { spawn := ctx.GetSpawn() if spawn == nil { return fmt.Errorf("no spawn in context") } attackable := ctx.GetParameterBool("attackable", true) // TODO: Implement attackable flag ctx.Debug("Set attackable to %t for spawn %s (not yet implemented)", attackable, spawn.GetName()) return nil }