611 lines
15 KiB
Go
611 lines
15 KiB
Go
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
|
|
} |