package spells import ( "fmt" "sync" ) // SpellResourceChecker handles checking and consuming spell casting resources type SpellResourceChecker struct { // TODO: Add references to entity system when available // entityManager *EntityManager mutex sync.RWMutex } // ResourceCheckResult represents the result of a resource check type ResourceCheckResult struct { HasSufficient bool // Whether entity has sufficient resources CurrentValue float32 // Current value of the resource RequiredValue float32 // Required value for the spell ResourceType int32 // Type of resource checked ErrorMessage string // Error message if check failed } // NewSpellResourceChecker creates a new resource checker func NewSpellResourceChecker() *SpellResourceChecker { return &SpellResourceChecker{} } // CheckPower verifies if the caster has enough power to cast the spell // Converted from C++ SpellProcess::CheckPower func (src *SpellResourceChecker) CheckPower(luaSpell *LuaSpell, customPowerReq float32) *ResourceCheckResult { if luaSpell == nil || luaSpell.Spell == nil { return &ResourceCheckResult{ HasSufficient: false, CurrentValue: 0, RequiredValue: 0, ResourceType: ResourceCheckPower, ErrorMessage: "Invalid spell", } } powerRequired := customPowerReq if powerRequired == 0 { powerRequired = luaSpell.Spell.GetPowerRequired() } // TODO: Get actual power from entity when entity system is available // For now, assume entity has sufficient power currentPower := float32(1000.0) // Placeholder result := &ResourceCheckResult{ HasSufficient: currentPower >= powerRequired, CurrentValue: currentPower, RequiredValue: powerRequired, ResourceType: ResourceCheckPower, ErrorMessage: "", } if !result.HasSufficient { result.ErrorMessage = fmt.Sprintf("Insufficient power: need %.1f, have %.1f", powerRequired, currentPower) } return result } // TakePower consumes power for spell casting // Converted from C++ SpellProcess::TakePower func (src *SpellResourceChecker) TakePower(luaSpell *LuaSpell, customPowerReq float32) bool { result := src.CheckPower(luaSpell, customPowerReq) if !result.HasSufficient { return false } // TODO: Actually deduct power from entity when entity system is available // This would call something like: // entity.GetInfoStruct().SetPower(currentPower - powerRequired) // entity.GetZone().TriggerCharSheetTimer() // Update client display return true } // CheckHP verifies if the caster has enough health to cast the spell // Converted from C++ SpellProcess::CheckHP func (src *SpellResourceChecker) CheckHP(luaSpell *LuaSpell, customHPReq float32) *ResourceCheckResult { if luaSpell == nil || luaSpell.Spell == nil { return &ResourceCheckResult{ HasSufficient: false, CurrentValue: 0, RequiredValue: 0, ResourceType: ResourceCheckHealth, ErrorMessage: "Invalid spell", } } hpRequired := customHPReq if hpRequired == 0 { hpRequired = float32(luaSpell.Spell.GetHPRequired()) } // TODO: Get actual HP from entity when entity system is available // For now, assume entity has sufficient HP currentHP := float32(1000.0) // Placeholder result := &ResourceCheckResult{ HasSufficient: currentHP >= hpRequired, CurrentValue: currentHP, RequiredValue: hpRequired, ResourceType: ResourceCheckHealth, ErrorMessage: "", } if !result.HasSufficient { result.ErrorMessage = fmt.Sprintf("Insufficient health: need %.1f, have %.1f", hpRequired, currentHP) } return result } // TakeHP consumes health for spell casting // Converted from C++ SpellProcess::TakeHP func (src *SpellResourceChecker) TakeHP(luaSpell *LuaSpell, customHPReq float32) bool { result := src.CheckHP(luaSpell, customHPReq) if !result.HasSufficient { return false } // TODO: Actually deduct HP from entity when entity system is available // This would call something like: // entity.GetInfoStruct().SetHP(currentHP - hpRequired) // entity.GetZone().TriggerCharSheetTimer() // Update client display return true } // CheckConcentration verifies if the caster has enough concentration to cast the spell // Converted from C++ SpellProcess::CheckConcentration func (src *SpellResourceChecker) CheckConcentration(luaSpell *LuaSpell) *ResourceCheckResult { if luaSpell == nil || luaSpell.Spell == nil { return &ResourceCheckResult{ HasSufficient: false, CurrentValue: 0, RequiredValue: 0, ResourceType: ResourceCheckConcentration, ErrorMessage: "Invalid spell", } } spellData := luaSpell.Spell.GetSpellData() if spellData == nil { return &ResourceCheckResult{ HasSufficient: false, CurrentValue: 0, RequiredValue: 0, ResourceType: ResourceCheckConcentration, ErrorMessage: "Invalid spell data", } } concentrationRequired := float32(spellData.ReqConcentration) // TODO: Get actual concentration from entity when entity system is available // For now, assume entity has sufficient concentration currentConcentration := float32(100.0) // Placeholder result := &ResourceCheckResult{ HasSufficient: currentConcentration >= concentrationRequired, CurrentValue: currentConcentration, RequiredValue: concentrationRequired, ResourceType: ResourceCheckConcentration, ErrorMessage: "", } if !result.HasSufficient { result.ErrorMessage = fmt.Sprintf("Insufficient concentration: need %.1f, have %.1f", concentrationRequired, currentConcentration) } return result } // AddConcentration adds concentration for maintained spells // Converted from C++ SpellProcess::AddConcentration func (src *SpellResourceChecker) AddConcentration(luaSpell *LuaSpell) bool { result := src.CheckConcentration(luaSpell) if !result.HasSufficient { return false } // TODO: Actually deduct concentration from entity when entity system is available // This would call something like: // currentConc := entity.GetInfoStruct().GetCurConcentration() // entity.GetInfoStruct().SetCurConcentration(currentConc + concentrationRequired) // entity.GetZone().TriggerCharSheetTimer() // Update client display return true } // CheckSavagery verifies if the caster has enough savagery to cast the spell // Converted from C++ SpellProcess::CheckSavagery func (src *SpellResourceChecker) CheckSavagery(luaSpell *LuaSpell) *ResourceCheckResult { if luaSpell == nil || luaSpell.Spell == nil { return &ResourceCheckResult{ HasSufficient: false, CurrentValue: 0, RequiredValue: 0, ResourceType: ResourceCheckSavagery, ErrorMessage: "Invalid spell", } } savageryRequired := float32(luaSpell.Spell.GetSavageryRequired()) // TODO: Get actual savagery from entity when entity system is available // For now, assume entity has sufficient savagery currentSavagery := float32(100.0) // Placeholder result := &ResourceCheckResult{ HasSufficient: currentSavagery >= savageryRequired, CurrentValue: currentSavagery, RequiredValue: savageryRequired, ResourceType: ResourceCheckSavagery, ErrorMessage: "", } if !result.HasSufficient { result.ErrorMessage = fmt.Sprintf("Insufficient savagery: need %.1f, have %.1f", savageryRequired, currentSavagery) } return result } // TakeSavagery consumes savagery for spell casting // Converted from C++ SpellProcess::TakeSavagery func (src *SpellResourceChecker) TakeSavagery(luaSpell *LuaSpell) bool { result := src.CheckSavagery(luaSpell) if !result.HasSufficient { return false } // TODO: Actually deduct savagery from entity when entity system is available // This would call something like: // entity.GetInfoStruct().SetSavagery(currentSavagery - savageryRequired) // entity.GetZone().TriggerCharSheetTimer() // Update client display return true } // CheckDissonance verifies if the caster has enough dissonance to cast the spell // Converted from C++ SpellProcess::CheckDissonance func (src *SpellResourceChecker) CheckDissonance(luaSpell *LuaSpell) *ResourceCheckResult { if luaSpell == nil || luaSpell.Spell == nil { return &ResourceCheckResult{ HasSufficient: false, CurrentValue: 0, RequiredValue: 0, ResourceType: ResourceCheckDissonance, ErrorMessage: "Invalid spell", } } dissonanceRequired := float32(luaSpell.Spell.GetDissonanceRequired()) // TODO: Get actual dissonance from entity when entity system is available // For now, assume entity has sufficient dissonance currentDissonance := float32(100.0) // Placeholder result := &ResourceCheckResult{ HasSufficient: currentDissonance >= dissonanceRequired, CurrentValue: currentDissonance, RequiredValue: dissonanceRequired, ResourceType: ResourceCheckDissonance, ErrorMessage: "", } if !result.HasSufficient { result.ErrorMessage = fmt.Sprintf("Insufficient dissonance: need %.1f, have %.1f", dissonanceRequired, currentDissonance) } return result } // AddDissonance adds dissonance for spell casting // Converted from C++ SpellProcess::AddDissonance func (src *SpellResourceChecker) AddDissonance(luaSpell *LuaSpell) bool { result := src.CheckDissonance(luaSpell) if !result.HasSufficient { return false } // TODO: Actually add dissonance to entity when entity system is available // This would call something like: // entity.GetInfoStruct().SetDissonance(currentDissonance + dissonanceRequired) // entity.GetZone().TriggerCharSheetTimer() // Update client display return true } // CheckAllResources performs a comprehensive resource check for a spell func (src *SpellResourceChecker) CheckAllResources(luaSpell *LuaSpell, customPowerReq, customHPReq float32) []ResourceCheckResult { results := make([]ResourceCheckResult, 0) // Check power powerResult := src.CheckPower(luaSpell, customPowerReq) if powerResult.RequiredValue > 0 { results = append(results, *powerResult) } // Check health hpResult := src.CheckHP(luaSpell, customHPReq) if hpResult.RequiredValue > 0 { results = append(results, *hpResult) } // Check concentration concResult := src.CheckConcentration(luaSpell) if concResult.RequiredValue > 0 { results = append(results, *concResult) } // Check savagery savageryResult := src.CheckSavagery(luaSpell) if savageryResult.RequiredValue > 0 { results = append(results, *savageryResult) } // Check dissonance dissonanceResult := src.CheckDissonance(luaSpell) if dissonanceResult.RequiredValue > 0 { results = append(results, *dissonanceResult) } return results } // ConsumeAllResources attempts to consume all required resources for a spell func (src *SpellResourceChecker) ConsumeAllResources(luaSpell *LuaSpell, customPowerReq, customHPReq float32) bool { // First check all resources results := src.CheckAllResources(luaSpell, customPowerReq, customHPReq) // Verify all resources are sufficient for _, result := range results { if !result.HasSufficient { return false } } // Consume resources success := true // Take power if required powerResult := src.CheckPower(luaSpell, customPowerReq) if powerResult.RequiredValue > 0 { success = success && src.TakePower(luaSpell, customPowerReq) } // Take health if required hpResult := src.CheckHP(luaSpell, customHPReq) if hpResult.RequiredValue > 0 { success = success && src.TakeHP(luaSpell, customHPReq) } // Add concentration if required (for maintained spells) spellData := luaSpell.Spell.GetSpellData() if spellData != nil && spellData.CastType == SpellCastTypeToggle { concResult := src.CheckConcentration(luaSpell) if concResult.RequiredValue > 0 { success = success && src.AddConcentration(luaSpell) } } // Take savagery if required savageryResult := src.CheckSavagery(luaSpell) if savageryResult.RequiredValue > 0 { success = success && src.TakeSavagery(luaSpell) } // Add dissonance if required dissonanceResult := src.CheckDissonance(luaSpell) if dissonanceResult.RequiredValue > 0 { success = success && src.AddDissonance(luaSpell) } return success } // GetResourceSummary returns a summary of all resource requirements for a spell func (src *SpellResourceChecker) GetResourceSummary(spell *Spell) map[string]float32 { summary := make(map[string]float32) if spell == nil { return summary } summary["power"] = spell.GetPowerRequired() summary["health"] = float32(spell.GetHPRequired()) summary["savagery"] = float32(spell.GetSavageryRequired()) summary["dissonance"] = float32(spell.GetDissonanceRequired()) spellData := spell.GetSpellData() if spellData != nil { summary["concentration"] = float32(spellData.ReqConcentration) } return summary } // ValidateResourceRequirements checks if resource requirements are reasonable func (src *SpellResourceChecker) ValidateResourceRequirements(spell *Spell) []string { errors := make([]string, 0) if spell == nil { errors = append(errors, "Spell is nil") return errors } // Check for negative requirements if spell.GetPowerRequired() < 0 { errors = append(errors, "Power requirement cannot be negative") } if spell.GetHPRequired() < 0 { errors = append(errors, "Health requirement cannot be negative") } if spell.GetSavageryRequired() < 0 { errors = append(errors, "Savagery requirement cannot be negative") } if spell.GetDissonanceRequired() < 0 { errors = append(errors, "Dissonance requirement cannot be negative") } spellData := spell.GetSpellData() if spellData != nil { if spellData.ReqConcentration < 0 { errors = append(errors, "Concentration requirement cannot be negative") } // Check for excessive requirements if spell.GetPowerRequired() > 10000 { errors = append(errors, "Power requirement seems excessive (>10000)") } if spell.GetHPRequired() > 5000 { errors = append(errors, "Health requirement seems excessive (>5000)") } } return errors } // GetFailureReason returns an appropriate failure reason code based on resource check results func (src *SpellResourceChecker) GetFailureReason(results []ResourceCheckResult) int32 { for _, result := range results { if !result.HasSufficient { switch result.ResourceType { case ResourceCheckPower: return FailureReasonInsufficientPower case ResourceCheckHealth: return FailureReasonInsufficientHealth case ResourceCheckConcentration: return FailureReasonInsufficientConc default: return FailureReasonRequirementNotMet } } } return FailureReasonNone }