eq2go/internal/spells/spell_resources.go

471 lines
14 KiB
Go

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
}