182 lines
6.6 KiB
Markdown
182 lines
6.6 KiB
Markdown
# EQ2Go Event System
|
|
|
|
A simplified event-driven system for handling game logic without the complexity of a full scripting engine.
|
|
|
|
## Overview
|
|
|
|
The event system provides:
|
|
- Simple event registration and execution
|
|
- Context-based parameter passing
|
|
- 100+ built-in EQ2 game functions organized by domain
|
|
- Thread-safe operations
|
|
- Minimal overhead
|
|
- Domain-specific function organization
|
|
|
|
## Basic Usage
|
|
|
|
```go
|
|
// Create event handler
|
|
handler := NewEventHandler()
|
|
|
|
// Register all EQ2 functions (100+ functions organized by domain)
|
|
err := functions.RegisterAllEQ2Functions(handler)
|
|
|
|
// Create context and execute event
|
|
ctx := NewEventContext(EventTypeSpawn, "SetCurrentHP", "heal_spell").
|
|
WithSpawn(player).
|
|
WithParameter("hp", 150.0)
|
|
|
|
err = handler.Execute(ctx)
|
|
```
|
|
|
|
## Event Context
|
|
|
|
The `EventContext` provides:
|
|
- Game objects: `Caster`, `Target`, `Spawn`, `Quest`
|
|
- Parameters: Type-safe parameter access
|
|
- Results: Return values from event functions
|
|
- Logging: Built-in debug/info/warn/error logging
|
|
|
|
### Fluent API
|
|
|
|
```go
|
|
ctx := NewEventContext(EventTypeSpell, "heal", "cast").
|
|
WithCaster(caster).
|
|
WithTarget(target).
|
|
WithParameter("spell_id", 123).
|
|
WithParameter("power_cost", 50)
|
|
```
|
|
|
|
### Parameter Access
|
|
|
|
```go
|
|
func MyEvent(ctx *EventContext) error {
|
|
spellID := ctx.GetParameterInt("spell_id", 0)
|
|
message := ctx.GetParameterString("message", "default")
|
|
amount := ctx.GetParameterFloat("amount", 0.0)
|
|
enabled := ctx.GetParameterBool("enabled", false)
|
|
|
|
// Set results
|
|
ctx.SetResult("damage_dealt", 150)
|
|
|
|
return nil
|
|
}
|
|
```
|
|
|
|
## Available EQ2 Functions
|
|
|
|
The system provides 100+ functions organized by domain:
|
|
|
|
### Health Domain (23 functions)
|
|
- **HP Management**: `SetCurrentHP`, `SetMaxHP`, `SetMaxHPBase`, `GetCurrentHP`, `GetMaxHP`, `GetMaxHPBase`
|
|
- **Power Management**: `SetCurrentPower`, `SetMaxPower`, `SetMaxPowerBase`, `GetCurrentPower`, `GetMaxPower`, `GetMaxPowerBase`
|
|
- **Modifiers**: `ModifyHP`, `ModifyPower`, `ModifyMaxHP`, `ModifyMaxPower`, `ModifyTotalHP`, `ModifyTotalPower`
|
|
- **Percentages**: `GetPCTOfHP`, `GetPCTOfPower`
|
|
- **Healing**: `SpellHeal`, `SpellHealPct`
|
|
- **State**: `IsAlive`
|
|
|
|
### Attributes Domain (24 functions)
|
|
- **Stats**: `SetInt`, `SetWis`, `SetSta`, `SetStr`, `SetAgi`, `GetInt`, `GetWis`, `GetSta`, `GetStr`, `GetAgi`
|
|
- **Base Stats**: `SetIntBase`, `SetWisBase`, `SetStaBase`, `SetStrBase`, `SetAgiBase`, `GetIntBase`, `GetWisBase`, `GetStaBase`, `GetStrBase`, `GetAgiBase`
|
|
- **Character Info**: `GetLevel`, `SetLevel`, `SetPlayerLevel`, `GetDifficulty`, `GetClass`, `SetClass`, `SetAdventureClass`
|
|
- **Classes**: `GetTradeskillClass`, `SetTradeskillClass`, `GetTradeskillLevel`, `SetTradeskillLevel`
|
|
- **Identity**: `GetRace`, `GetGender`, `GetModelType`, `SetModelType`, `GetDeity`, `SetDeity`, `GetAlignment`, `SetAlignment`
|
|
- **Bonuses**: `AddSpellBonus`, `RemoveSpellBonus`, `AddSkillBonus`, `RemoveSkillBonus`
|
|
|
|
### Movement Domain (27 functions)
|
|
- **Position**: `SetPosition`, `GetPosition`, `GetX`, `GetY`, `GetZ`, `GetHeading`, `SetHeading`
|
|
- **Original Position**: `GetOrigX`, `GetOrigY`, `GetOrigZ`
|
|
- **Distance & Facing**: `GetDistance`, `FaceTarget`
|
|
- **Speed**: `GetSpeed`, `SetSpeed`, `SetSpeedMultiplier`, `HasMoved`, `IsRunning`
|
|
- **Movement**: `MoveToLocation`, `ClearRunningLocations`, `SpawnMove`, `MovementLoopAdd`, `PauseMovement`, `StopMovement`
|
|
- **Mounts**: `SetMount`, `GetMount`, `SetMountColor`, `StartAutoMount`, `EndAutoMount`, `IsOnAutoMount`
|
|
- **Waypoints**: `AddWaypoint`, `RemoveWaypoint`, `SendWaypoints`
|
|
- **Transport**: `Evac`, `Bind`, `Gate`
|
|
|
|
### Combat Domain (36 functions)
|
|
- **Basic Combat**: `Attack`, `AddHate`, `ClearHate`, `GetMostHated`, `SetTarget`, `GetTarget`
|
|
- **Combat State**: `IsInCombat`, `SetInCombat`, `IsCasting`, `HasRecovered`
|
|
- **Damage**: `SpellDamage`, `SpellDamageExt`, `DamageSpawn`, `ProcDamage`, `ProcHate`
|
|
- **Effects**: `Knockback`, `Interrupt`
|
|
- **Processing**: `ProcessMelee`, `ProcessSpell`, `LastSpellAttackHit`
|
|
- **Positioning**: `IsBehind`, `IsFlanking`, `InFront`
|
|
- **Encounters**: `GetEncounterSize`, `GetEncounter`, `GetHateList`, `ClearEncounter`
|
|
- **AI**: `ClearRunback`, `Runback`, `GetRunbackDistance`, `CompareSpawns`
|
|
- **Life/Death**: `KillSpawn`, `KillSpawnByDistance`, `Resurrect`
|
|
- **Invulnerability**: `IsInvulnerable`, `SetInvulnerable`, `SetAttackable`
|
|
|
|
### Miscellaneous Domain (27 functions)
|
|
- **Messaging**: `SendMessage`, `LogMessage`
|
|
- **Utility**: `MakeRandomInt`, `MakeRandomFloat`, `ParseInt`
|
|
- **Identity**: `GetName`, `GetID`, `GetSpawnID`, `IsPlayer`, `IsNPC`, `IsEntity`, `IsDead`, `GetCharacterID`
|
|
- **Spawning**: `Despawn`, `Spawn`, `SpawnByLocationID`, `SpawnGroupByID`, `DespawnByLocationID`
|
|
- **Groups**: `GetSpawnByLocationID`, `GetSpawnByGroupID`, `GetSpawnGroupID`, `SetSpawnGroupID`, `AddSpawnToGroup`, `IsSpawnGroupAlive`
|
|
- **Location**: `GetSpawnLocationID`, `GetSpawnLocationPlacementID`, `SetGridID`
|
|
- **Spawn Management**: `SpawnSet`, `SpawnSetByDistance`
|
|
- **Variables**: `GetVariableValue`, `SetServerVariable`, `GetServerVariable`, `SetTempVariable`, `GetTempVariable`
|
|
- **Line of Sight**: `CheckLOS`, `CheckLOSByCoordinates`
|
|
|
|
## Function Organization
|
|
|
|
Access functions by domain using the `functions` package:
|
|
|
|
```go
|
|
import "eq2emu/internal/events/functions"
|
|
|
|
// Register all functions at once
|
|
handler := events.NewEventHandler()
|
|
err := functions.RegisterAllEQ2Functions(handler)
|
|
|
|
// Get functions organized by domain
|
|
domains := functions.GetFunctionsByDomain()
|
|
healthFunctions := domains["health"] // 23 functions
|
|
combatFunctions := domains["combat"] // 36 functions
|
|
movementFunctions := domains["movement"] // 27 functions
|
|
// ... etc
|
|
```
|
|
|
|
## Custom Events
|
|
|
|
```go
|
|
// Register custom event
|
|
handler.Register("my_custom_event", func(ctx *events.EventContext) error {
|
|
spawn := ctx.GetSpawn()
|
|
if spawn == nil {
|
|
return fmt.Errorf("no spawn provided")
|
|
}
|
|
|
|
// Custom logic here
|
|
ctx.Debug("Custom event executed for %s", spawn.GetName())
|
|
return nil
|
|
})
|
|
|
|
// Execute custom event
|
|
ctx := events.NewEventContext(events.EventTypeSpawn, "my_custom_event", "trigger").
|
|
WithSpawn(someSpawn)
|
|
|
|
err := handler.Execute(ctx)
|
|
```
|
|
|
|
## Event Types
|
|
|
|
- `EventTypeSpell` - Spell-related events
|
|
- `EventTypeSpawn` - Spawn-related events
|
|
- `EventTypeQuest` - Quest-related events
|
|
- `EventTypeCombat` - Combat-related events
|
|
- `EventTypeZone` - Zone-related events
|
|
- `EventTypeItem` - Item-related events
|
|
|
|
## Thread Safety
|
|
|
|
All operations are thread-safe:
|
|
- Event registration/unregistration
|
|
- Context parameter/result access
|
|
- Event execution
|
|
|
|
## Performance
|
|
|
|
The event system is designed for minimal overhead:
|
|
- No complex registry or statistics
|
|
- Direct function calls
|
|
- Simple context passing
|
|
- Optional timeout support |