package spells import ( "sync" ) // LevelArray represents spell level requirements for different classes type LevelArray struct { AdventureClass int8 // Adventure class ID TradeskillClass int8 // Tradeskill class ID SpellLevel int16 // Required level ClassicSpellLevel float32 // Classic spell level calculation } // SpellDisplayEffect represents a displayed effect in spell descriptions type SpellDisplayEffect struct { Percentage int8 // Effect percentage Subbullet int8 // Subbullet indicator Description string // Effect description text NeedsDBSave bool // Whether this needs database saving } // LUAData represents Lua script data for spells type LUAData struct { Type int8 // Data type (int, float, bool, string) IntValue int32 // Integer value BoolValue bool // Boolean value FloatValue float32 // Float value StringValue string // String value StringValue2 string // Second string value IntValue2 int32 // Second integer value FloatValue2 float32 // Second float value StringHelper string // Helper string for identification NeedsDBSave bool // Whether this needs database saving } // SpellData contains all core spell information // This is the main spell data structure converted from C++ SpellData type SpellData struct { // Basic identification SpellBookType int32 // Type of spell book this belongs to ID int32 // Unique spell ID InheritedSpellID int32 // ID of spell this inherits from Name string // Spell name Description string // Spell description // Visual information Icon int16 // Spell icon ID IconHeroicOp int16 // Heroic opportunity icon IconBackdrop int16 // Icon backdrop SpellVisual int32 // Visual effect ID // Classification Type int16 // Spell type SpellType int8 // Additional spell type classification ClassSkill int32 // Required class skill MinClassSkillReq int16 // Minimum class skill requirement MasterySkill int32 // Mastery skill required TSLocIndex int8 // Tradeskill location index Tier int8 // Spell tier NumLevels int8 // Number of levels this spell has // Resource requirements HPReq int16 // Health points required HPUpkeep int16 // Health points upkeep PowerReq float32 // Power required to cast PowerByLevel bool // Power requirement scales by level PowerUpkeep int16 // Power upkeep cost SavageryReq int16 // Savagery required SavageryUpkeep int16 // Savagery upkeep DissonanceReq int16 // Dissonance required DissonanceUpkeep int16 // Dissonance upkeep ReqConcentration int16 // Concentration required // Percentage-based requirements PowerReqPercent int8 // Power requirement as percentage of max HPReqPercent int8 // HP requirement as percentage of max SavageryReqPercent int8 // Savagery requirement as percentage DissonanceReqPercent int8 // Dissonance requirement as percentage // Targeting and range TargetType int8 // Type of target (self, enemy, group, etc.) Range float32 // Casting range MinRange float32 // Minimum casting range Radius float32 // Area of effect radius MaxAOETargets int16 // Maximum AoE targets FriendlySpell int8 // Whether this is a friendly spell // Timing CastTime int16 // Cast time in deciseconds OrigCastTime int16 // Original cast time (before modifications) Recovery float32 // Recovery time Recast float32 // Recast delay LinkedTimer int32 // Linked timer ID CallFrequency int32 // How often spell effect is called // Duration and resistibility Duration1 int32 // Primary duration Duration2 int32 // Secondary duration Resistibility float32 // How resistible the spell is DurationUntilCancel bool // Duration lasts until cancelled // Combat and effect properties HitBonus float32 // Hit bonus provided CanEffectRaid int8 // Can affect raid members AffectOnlyGroupMembers int8 // Only affects group members GroupSpell int8 // Is a group spell DetType int8 // Detrimental type Incurable bool // Cannot be cured ControlEffectType int8 // Type of control effect // Behavioral flags CastType int8 // Cast type (normal, toggle) CastingFlags int32 // Various casting flags CastWhileMoving bool // Can cast while moving PersistThroughDeath bool // Persists through death NotMaintained bool // Not a maintained spell IsAA bool // Is an Alternate Advancement ability CanFizzle bool // Can fizzle on cast Interruptable bool // Can be interrupted IsActive bool // Spell is active/enabled // Savage bar (for certain spell types) SavageBar int8 // Savage bar requirement SavageBarSlot int8 // Savage bar slot // Messages SuccessMessage string // Message on successful cast FadeMessage string // Message when spell fades FadeMessageOthers string // Fade message for others EffectMessage string // Effect message // Scripting LuaScript string // Lua script filename // Versioning and classification DisplaySpellTier int8 // Displayed tier SOESpellCRC int32 // SOE spell CRC SpellNameCRC int32 // Spell name CRC TypeGroupSpellID int32 // Type group spell ID GivenBy string // Description of how spell was obtained GivenByType GivenByType // Type of how spell was obtained // Thread safety mutex sync.RWMutex } // NewSpellData creates a new SpellData with default values func NewSpellData() *SpellData { return &SpellData{ SpellBookType: SpellBookTypeSpell, ID: 0, InheritedSpellID: 0, Name: "", Description: "", Icon: 0, IconHeroicOp: 0, IconBackdrop: 0, SpellVisual: 0, Type: 0, SpellType: 0, ClassSkill: 0, MinClassSkillReq: 0, MasterySkill: 0, TSLocIndex: 0, Tier: 1, NumLevels: 1, HPReq: 0, HPUpkeep: 0, PowerReq: 0.0, PowerByLevel: false, PowerUpkeep: 0, SavageryReq: 0, SavageryUpkeep: 0, DissonanceReq: 0, DissonanceUpkeep: 0, ReqConcentration: 0, PowerReqPercent: 0, HPReqPercent: 0, SavageryReqPercent: 0, DissonanceReqPercent: 0, TargetType: SpellTargetSelf, Range: 0.0, MinRange: 0.0, Radius: 0.0, MaxAOETargets: 0, FriendlySpell: 1, CastTime: 0, OrigCastTime: 0, Recovery: 0.0, Recast: 0.0, LinkedTimer: 0, CallFrequency: 0, Duration1: 0, Duration2: 0, Resistibility: 0.0, DurationUntilCancel: false, HitBonus: 0.0, CanEffectRaid: 0, AffectOnlyGroupMembers: 0, GroupSpell: 0, DetType: 0, Incurable: false, ControlEffectType: 0, CastType: SpellCastTypeNormal, CastingFlags: 0, CastWhileMoving: false, PersistThroughDeath: false, NotMaintained: false, IsAA: false, CanFizzle: true, Interruptable: true, IsActive: true, SavageBar: 0, SavageBarSlot: 0, SuccessMessage: "", FadeMessage: "", FadeMessageOthers: "", EffectMessage: "", LuaScript: "", DisplaySpellTier: 1, SOESpellCRC: 0, SpellNameCRC: 0, TypeGroupSpellID: 0, GivenBy: "", GivenByType: GivenByUnset, } } // GetID returns the spell ID (thread-safe) func (sd *SpellData) GetID() int32 { sd.mutex.RLock() defer sd.mutex.RUnlock() return sd.ID } // SetID updates the spell ID (thread-safe) func (sd *SpellData) SetID(id int32) { sd.mutex.Lock() defer sd.mutex.Unlock() sd.ID = id } // GetName returns the spell name (thread-safe) func (sd *SpellData) GetName() string { sd.mutex.RLock() defer sd.mutex.RUnlock() return sd.Name } // SetName updates the spell name (thread-safe) func (sd *SpellData) SetName(name string) { sd.mutex.Lock() defer sd.mutex.Unlock() sd.Name = name } // GetTier returns the spell tier func (sd *SpellData) GetTier() int8 { sd.mutex.RLock() defer sd.mutex.RUnlock() return sd.Tier } // GetDuration returns the primary spell duration func (sd *SpellData) GetDuration() int32 { sd.mutex.RLock() defer sd.mutex.RUnlock() return sd.Duration1 } // GetCastTime returns the cast time func (sd *SpellData) GetCastTime() int16 { sd.mutex.RLock() defer sd.mutex.RUnlock() return sd.CastTime } // GetTargetType returns the target type func (sd *SpellData) GetTargetType() int8 { sd.mutex.RLock() defer sd.mutex.RUnlock() return sd.TargetType } // GetRange returns the casting range func (sd *SpellData) GetRange() float32 { sd.mutex.RLock() defer sd.mutex.RUnlock() return sd.Range } // IsHealSpell determines if this is a healing spell func (sd *SpellData) IsHealSpell() bool { // TODO: Implement based on spell effects or type classification return false } // IsBuffSpell determines if this is a buff spell func (sd *SpellData) IsBuffSpell() bool { // TODO: Implement based on spell effects or duration return sd.GetDuration() > 0 && sd.FriendlySpell == 1 } // IsDamageSpell determines if this is a damage spell func (sd *SpellData) IsDamageSpell() bool { // TODO: Implement based on spell effects return false } // IsControlSpell determines if this is a control spell func (sd *SpellData) IsControlSpell() bool { sd.mutex.RLock() defer sd.mutex.RUnlock() return sd.ControlEffectType > 0 } // IsOffenseSpell determines if this is an offensive spell func (sd *SpellData) IsOffenseSpell() bool { sd.mutex.RLock() defer sd.mutex.RUnlock() return sd.FriendlySpell == 0 } // CanCastWhileStunned returns whether spell can be cast while stunned func (sd *SpellData) CanCastWhileStunned() bool { // Check casting flags for stun immunity return (sd.CastingFlags & 0x01) != 0 } // CanCastWhileMezzed returns whether spell can be cast while mezzed func (sd *SpellData) CanCastWhileMezzed() bool { // Check casting flags for mez immunity return (sd.CastingFlags & 0x02) != 0 } // CanCastWhileStifled returns whether spell can be cast while stifled func (sd *SpellData) CanCastWhileStifled() bool { // Check casting flags for stifle immunity return (sd.CastingFlags & 0x04) != 0 } // CanCastWhileFeared returns whether spell can be cast while feared func (sd *SpellData) CanCastWhileFeared() bool { // Check casting flags for fear immunity return (sd.CastingFlags & 0x08) != 0 } // Clone creates a deep copy of the SpellData func (sd *SpellData) Clone() *SpellData { sd.mutex.RLock() defer sd.mutex.RUnlock() clone := &SpellData{ SpellBookType: sd.SpellBookType, ID: sd.ID, InheritedSpellID: sd.InheritedSpellID, Name: sd.Name, Description: sd.Description, Icon: sd.Icon, IconHeroicOp: sd.IconHeroicOp, IconBackdrop: sd.IconBackdrop, SpellVisual: sd.SpellVisual, Type: sd.Type, SpellType: sd.SpellType, ClassSkill: sd.ClassSkill, MinClassSkillReq: sd.MinClassSkillReq, MasterySkill: sd.MasterySkill, TSLocIndex: sd.TSLocIndex, Tier: sd.Tier, NumLevels: sd.NumLevels, HPReq: sd.HPReq, HPUpkeep: sd.HPUpkeep, PowerReq: sd.PowerReq, PowerByLevel: sd.PowerByLevel, PowerUpkeep: sd.PowerUpkeep, SavageryReq: sd.SavageryReq, SavageryUpkeep: sd.SavageryUpkeep, DissonanceReq: sd.DissonanceReq, DissonanceUpkeep: sd.DissonanceUpkeep, ReqConcentration: sd.ReqConcentration, PowerReqPercent: sd.PowerReqPercent, HPReqPercent: sd.HPReqPercent, SavageryReqPercent: sd.SavageryReqPercent, DissonanceReqPercent: sd.DissonanceReqPercent, TargetType: sd.TargetType, Range: sd.Range, MinRange: sd.MinRange, Radius: sd.Radius, MaxAOETargets: sd.MaxAOETargets, FriendlySpell: sd.FriendlySpell, CastTime: sd.CastTime, OrigCastTime: sd.OrigCastTime, Recovery: sd.Recovery, Recast: sd.Recast, LinkedTimer: sd.LinkedTimer, CallFrequency: sd.CallFrequency, Duration1: sd.Duration1, Duration2: sd.Duration2, Resistibility: sd.Resistibility, DurationUntilCancel: sd.DurationUntilCancel, HitBonus: sd.HitBonus, CanEffectRaid: sd.CanEffectRaid, AffectOnlyGroupMembers: sd.AffectOnlyGroupMembers, GroupSpell: sd.GroupSpell, DetType: sd.DetType, Incurable: sd.Incurable, ControlEffectType: sd.ControlEffectType, CastType: sd.CastType, CastingFlags: sd.CastingFlags, CastWhileMoving: sd.CastWhileMoving, PersistThroughDeath: sd.PersistThroughDeath, NotMaintained: sd.NotMaintained, IsAA: sd.IsAA, CanFizzle: sd.CanFizzle, Interruptable: sd.Interruptable, IsActive: sd.IsActive, SavageBar: sd.SavageBar, SavageBarSlot: sd.SavageBarSlot, SuccessMessage: sd.SuccessMessage, FadeMessage: sd.FadeMessage, FadeMessageOthers: sd.FadeMessageOthers, EffectMessage: sd.EffectMessage, LuaScript: sd.LuaScript, DisplaySpellTier: sd.DisplaySpellTier, SOESpellCRC: sd.SOESpellCRC, SpellNameCRC: sd.SpellNameCRC, TypeGroupSpellID: sd.TypeGroupSpellID, GivenBy: sd.GivenBy, GivenByType: sd.GivenByType, } return clone }