435 lines
14 KiB
Go
435 lines
14 KiB
Go
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
|
|
}
|