package combat import ( "math" "time" ) // PVPManager handles all PVP-related logic and validation type PVPManager struct { config *CombatConfig ruleManager RuleManager } // NewPVPManager creates a new PVP manager func NewPVPManager(config *CombatConfig, ruleManager RuleManager) *PVPManager { return &PVPManager{ config: config, ruleManager: ruleManager, } } // IsPVPAllowed checks if PVP is allowed between two players func (pm *PVPManager) IsPVPAllowed(attacker Entity, victim Entity) bool { if !pm.config.EnablePVP { return false } // Both must be players if !attacker.IsPlayer() || !victim.IsPlayer() { return false } // Cannot attack self if attacker.GetID() == victim.GetID() { return false } // Check if victim is attackable if victim.GetAttackable() == 0 { return false } // Check PVP type restrictions if !pm.checkPVPType(attacker, victim) { return false } // Check level range restrictions if !pm.checkLevelRange(attacker, victim) { return false } // Check zone PVP rules if !pm.checkZonePVPRules(attacker, victim) { return false } // Check faction rules if !pm.checkFactionPVPRules(attacker, victim) { return false } // Check guild rules if !pm.checkGuildPVPRules(attacker, victim) { return false } // Check recent login protection if !pm.checkRecentLoginProtection(victim) { return false } return true } // checkPVPType validates PVP type rules func (pm *PVPManager) checkPVPType(attacker Entity, victim Entity) bool { switch pm.config.PVPType { case PVPTypeNone: return false case PVPTypeOpen: return true case PVPTypeRace: return pm.checkRacePVP(attacker, victim) case PVPTypeClass: return pm.checkClassPVP(attacker, victim) case PVPTypeGuild: return pm.checkGuildWarPVP(attacker, victim) case PVPTypeAlignment: return pm.checkAlignmentPVP(attacker, victim) default: return false } } // checkLevelRange validates level-based PVP restrictions func (pm *PVPManager) checkLevelRange(attacker Entity, victim Entity) bool { if pm.config.PVPLevelRange <= 0 { return true // No level restrictions } levelDiff := int32(math.Abs(float64(attacker.GetLevel() - victim.GetLevel()))) return levelDiff <= pm.config.PVPLevelRange } // checkZonePVPRules validates zone-specific PVP rules func (pm *PVPManager) checkZonePVPRules(attacker Entity, victim Entity) bool { zoneID := attacker.GetZoneID() // Check if PVP is enabled in this zone zonePVPEnabled := pm.ruleManager.GetZoneBool(zoneID, RuleCategoryPVP, RuleAllowPVP) if !zonePVPEnabled { return false } // Check for safe zones or newbie areas if pm.isNewbieZone(zoneID) { maxNewbieLevel := pm.ruleManager.GetZoneInt32(zoneID, RuleCategoryPVP, RulePVPNewbieLevel) if victim.GetLevel() <= maxNewbieLevel { return false } } return true } // checkFactionPVPRules validates faction-based PVP rules func (pm *PVPManager) checkFactionPVPRules(attacker Entity, victim Entity) bool { attackerFaction := attacker.GetFactionID() victimFaction := victim.GetFactionID() // Same faction can only attack in guild wars or specific PVP types if attackerFaction == victimFaction && attackerFaction > 0 { return pm.config.PVPType == PVPTypeGuild || pm.config.PVPType == PVPTypeOpen } // Check faction standings return pm.areFactionHostile(attackerFaction, victimFaction) } // checkGuildPVPRules validates guild-based PVP rules func (pm *PVPManager) checkGuildPVPRules(attacker Entity, victim Entity) bool { // This would integrate with guild system when available // For now, simplified logic // Same guild members cannot attack each other unless in guild war attackerGuildID := pm.getPlayerGuildID(attacker.GetID()) victimGuildID := pm.getPlayerGuildID(victim.GetID()) if attackerGuildID > 0 && attackerGuildID == victimGuildID { // Check if guild war is active return pm.isGuildWarActive(attackerGuildID, victimGuildID) } return true } // checkRecentLoginProtection checks for new player login protection func (pm *PVPManager) checkRecentLoginProtection(victim Entity) bool { // This would check player login time when player system is integrated // For now, assume no protection needed return true } // checkRacePVP validates race-based PVP rules func (pm *PVPManager) checkRacePVP(attacker Entity, victim Entity) bool { // Different races can attack each other return attacker.GetRace() != victim.GetRace() } // checkClassPVP validates class-based PVP rules func (pm *PVPManager) checkClassPVP(attacker Entity, victim Entity) bool { // Different classes can attack each other return attacker.GetClass() != victim.GetClass() } // checkGuildWarPVP validates guild war PVP rules func (pm *PVPManager) checkGuildWarPVP(attacker Entity, victim Entity) bool { attackerGuildID := pm.getPlayerGuildID(attacker.GetID()) victimGuildID := pm.getPlayerGuildID(victim.GetID()) if attackerGuildID == 0 || victimGuildID == 0 { return false // Both must be in guilds } return pm.isGuildWarActive(attackerGuildID, victimGuildID) } // checkAlignmentPVP validates alignment-based PVP rules func (pm *PVPManager) checkAlignmentPVP(attacker Entity, victim Entity) bool { attackerAlignment := attacker.GetInfoStruct().GetAlignment() victimAlignment := victim.GetInfoStruct().GetAlignment() // Evil vs Good, Neutral can attack anyone return pm.areAlignmentsHostile(attackerAlignment, victimAlignment) } // CalculatePVPDamageModifier calculates damage modifiers for PVP combat func (pm *PVPManager) CalculatePVPDamageModifier(attacker Entity, victim Entity) float32 { modifier := float32(1.0) // Level-based modifier levelDiff := float32(attacker.GetLevel() - victim.GetLevel()) if levelDiff > 0 { // Higher level attacker does less damage to lower level victim modifier -= (levelDiff * 0.05) } else if levelDiff < 0 { // Lower level attacker does more damage to higher level victim modifier += (float32(math.Abs(float64(levelDiff))) * 0.02) } // PVP damage reduction pvpDamageMultiplier := pm.ruleManager.GetFloat32(RuleCategoryPVP, RulePVPDamageMultiplier) modifier *= pvpDamageMultiplier // Cap modifiers if modifier > 2.0 { modifier = 2.0 } else if modifier < 0.1 { modifier = 0.1 } return modifier } // CalculatePVPHealingModifier calculates healing modifiers for PVP combat func (pm *PVPManager) CalculatePVPHealingModifier(caster Entity, target Entity) float32 { // Healing is generally less effective in PVP pvpHealingMultiplier := pm.ruleManager.GetFloat32(RuleCategoryPVP, RulePVPHealingMultiplier) modifier := pvpHealingMultiplier if modifier < 0.1 { modifier = 0.1 } else if modifier > 1.0 { modifier = 1.0 } return modifier } // GetPVPExperienceModifier calculates experience modifiers for PVP kills func (pm *PVPManager) GetPVPExperienceModifier(killer Entity, victim Entity) float32 { levelDiff := float32(victim.GetLevel() - killer.GetLevel()) modifier := float32(1.0) // Higher level victims give more experience if levelDiff > 0 { modifier += (levelDiff * 0.1) } else if levelDiff < 0 { // Lower level victims give less experience modifier += (levelDiff * 0.05) } // Cap modifiers if modifier > 3.0 { modifier = 3.0 } else if modifier < 0.1 { modifier = 0.1 } return modifier } // HandlePVPKill processes a PVP kill func (pm *PVPManager) HandlePVPKill(killer Entity, victim Entity) { // This would integrate with experience, faction, and reputation systems // For now, just basic handling // Award PVP experience expModifier := pm.GetPVPExperienceModifier(killer, victim) baseExp := float32(victim.GetLevel() * 100) _ = int32(baseExp * expModifier) // pvpExp - would be used when experience system is integrated // This would call experience system when available // killer.AddExperience(pvpExp) // Handle faction changes if applicable pm.handlePVPFactionChanges(killer, victim) // Handle guild war points if applicable pm.handleGuildWarPoints(killer, victim) } // Helper functions (would integrate with other systems when available) // isNewbieZone checks if a zone is designated as a newbie/starting zone func (pm *PVPManager) isNewbieZone(zoneID int32) bool { // This would check against a list of newbie zones newbieZones := []int32{1, 2, 3, 4} // Example zone IDs for _, newbieZone := range newbieZones { if zoneID == newbieZone { return true } } return false } // areFactionHostile checks if two factions are hostile to each other func (pm *PVPManager) areFactionHostile(faction1, faction2 int32) bool { // This would integrate with faction system // For now, simplified logic: different factions are hostile return faction1 != faction2 } // getPlayerGuildID gets the guild ID for a player func (pm *PVPManager) getPlayerGuildID(playerID int32) int32 { // This would integrate with guild system // For now, return 0 (no guild) return 0 } // isGuildWarActive checks if two guilds are at war func (pm *PVPManager) isGuildWarActive(guild1ID, guild2ID int32) bool { // This would integrate with guild war system // For now, return false return false } // areAlignmentsHostile checks if two alignments are hostile func (pm *PVPManager) areAlignmentsHostile(alignment1, alignment2 int32) bool { // Evil vs Good are always hostile if (alignment1 < 0 && alignment2 > 0) || (alignment1 > 0 && alignment2 < 0) { return true } // Neutral (0) can attack anyone if alignment1 == 0 || alignment2 == 0 { return true } return false } // handlePVPFactionChanges processes faction changes from PVP kills func (pm *PVPManager) handlePVPFactionChanges(killer Entity, victim Entity) { // This would integrate with faction system // Could modify faction standings based on PVP kills } // handleGuildWarPoints processes guild war points from PVP kills func (pm *PVPManager) handleGuildWarPoints(killer Entity, victim Entity) { // This would integrate with guild war system // Could award points for guild vs guild kills } // GetPVPStatistics returns PVP-related statistics func (pm *PVPManager) GetPVPStatistics() map[string]interface{} { return map[string]interface{}{ "pvp_enabled": pm.config.EnablePVP, "pvp_type": pm.config.PVPType, "level_range": pm.config.PVPLevelRange, "damage_modifier": pm.ruleManager.GetFloat32(RuleCategoryPVP, RulePVPDamageMultiplier), } } // ValidateAttack performs comprehensive PVP attack validation func (pm *PVPManager) ValidateAttack(attacker Entity, victim Entity, attackType int8) (bool, string) { if !pm.IsPVPAllowed(attacker, victim) { return false, "PVP not allowed between these players" } // Additional attack-specific validation if attackType == AttackTypeRanged { // Check if ranged PVP is allowed in this zone zoneID := attacker.GetZoneID() if !pm.ruleManager.GetZoneBool(zoneID, RuleCategoryPVP, RulePVPRangedAllowed) { return false, "Ranged attacks not allowed in this zone" } } if attackType == AttackTypeSpell { // Check if spell PVP is allowed if !pm.ruleManager.GetBool(RuleCategoryPVP, RulePVPSpellsAllowed) { return false, "Spell attacks not allowed in PVP" } } return true, "" } // GetPVPCooldown calculates PVP cooldown time after combat func (pm *PVPManager) GetPVPCooldown(player Entity) time.Duration { baseCooldown := pm.ruleManager.GetInt32(RuleCategoryPVP, RulePVPCombatCooldown) return time.Duration(baseCooldown) * time.Second }