diff --git a/Content/extensions/Duel Realm/json/realms/realm/duels.jsonc b/Content/extensions/Duel Realm/json/realms/realm/duels.jsonc index 6ec518c7ff..b68e9aadc6 100644 --- a/Content/extensions/Duel Realm/json/realms/realm/duels.jsonc +++ b/Content/extensions/Duel Realm/json/realms/realm/duels.jsonc @@ -8,5 +8,6 @@ "IsNeutralZone": true, "CanInteractWithNeutralZone": true, "HideoutEnabled": false - } + }, + "apply_rulesets": [ "pvp-damage" ] } diff --git a/Content/extensions/Duel Realm/json/realms/ruleset/pvp-damage.jsonc b/Content/extensions/Duel Realm/json/realms/ruleset/pvp-damage.jsonc new file mode 100644 index 0000000000..5fa04cc7d1 --- /dev/null +++ b/Content/extensions/Duel Realm/json/realms/ruleset/pvp-damage.jsonc @@ -0,0 +1,92 @@ +{ + "name": "Pvp Damage Ruleset", + "type": "Ruleset", + "properties": { + "Core": { + "Realm": { + "Description": "This server has custom pvp damage configurable options." + } + }, + "Pvp": { + "Damage": { + "IgnoreMagicArmorPvpScalar": 1, + "IgnoreMagicResistPvpScalar": 1, + "CloakMaxDmgMitigation": 50, + "CsCritrateMod": 1, + "DmgMod2h": 1.1, + "DmgMod2hAr": 1, + "DmgMod2hCb": 2, + "DmgMod2hCbCrit": 0.55, + "DmgMod2hCs": 1.65, + "DmgMod2hHollow": 1, + "DmgMod2hPhantom": 1, + "DmgModAr": 1, + "DmgModCb": 1, + "DmgModCs": 1, + "DmgModHollow": 0.7, + "DmgModPhantom": 0.8, + "DmgModBow": 1.2, + "DmgModBowAr": 1.05, + "DmgModBowCb": 1.3, + "DmgModBowCbCrit": 0.92, + "DmgModBowCs": 1.85, + "DmgModBowHollow": 1, + "DmgModBowPhantom": 1, + "DmgModFw": 1.1, + "DmgModFwAr": 1, + "DmgModFwCb": 1.5, + "DmgModFwCbCrit": 0.8, + "DmgModFwCs": 1.55, + "DmgModFwHollow": 1, + "DmgModFwPhantom": 1, + "DmgModHw": 1.1, + "DmgModHwAr": 1.05, + "DmgModHwCb": 1.5, + "DmgModHwCbCrit": 0.8, + "DmgModHwCbCritMultistrike": 0.9, + "DmgModHwCs": 1.55, + "DmgModHwHollow": 1, + "DmgModHwMultistrike": 0.9, + "DmgModHwPhantom": 1, + "DmgModLw": 1.1, + "DmgModLwAr": 1, + "DmgModLwCb": 1.5, + "DmgModLwCbCrit": 0.8, + "DmgModLwCbCritTriplestrike": 0.9, + "DmgModLwCs": 1.55, + "DmgModLwHollow": 1, + "DmgModLwPhantom": 1, + "DmgModLwTriplestrike": 0.97, + "DmgModTw": 1.2, + "DmgModTwAr": 1.05, + "DmgModTwCb": 1.3, + "DmgModTwCbCrit": 0.92, + "DmgModTwCs": 1.85, + "DmgModTwHollow": 1, + "DmgModTwPhantom": 1, + "DmgModXbow": 1.2, + "DmgModXbowAr": 1.05, + "DmgModXbowCb": 1.3, + "DmgModXbowCbCrit": 0.92, + "DmgModXbowCs": 1.85, + "DmgModXbowHollow": 1, + "DmgModXbowPhantom": 1, + "DmgModVoid": 0.85, + "DmgModVoidCbCrit": 0.45, + "DmgModVoidCrit": 1, + "DmgModVoidDot": 0.65, + "DmgModVoidDotRatingReduction": 0.25, + "DmgModVoidStreak": 0.45, + "DmgModVoidVariance": 0.5, + "VoidHybridMod": 0.65, + "DmgModWar": 1.1, + "DmgModWarBlast": 0.6, + "DmgModWarCbCrit": 0.45, + "DmgModWarCsCrit": 0.95, + "DmgModWarCsDmg": 1.1, + "DmgModWarStreak": 0.68, + "DmgModWarVariance": 0.4 + } + } + } +} diff --git a/Source/ACE.Entity/Models/PropertiesEnchantmentRegistry.cs b/Source/ACE.Entity/Models/PropertiesEnchantmentRegistry.cs index 64bacb4c88..15ea464054 100644 --- a/Source/ACE.Entity/Models/PropertiesEnchantmentRegistry.cs +++ b/Source/ACE.Entity/Models/PropertiesEnchantmentRegistry.cs @@ -22,5 +22,6 @@ public class PropertiesEnchantmentRegistry public uint StatModKey { get; set; } public float StatModValue { get; set; } public EquipmentSet SpellSetId { get; set; } + public bool IsPvP { get; internal set; } } } diff --git a/Source/ACE.Server/Command/Handlers/AdminCommands.cs b/Source/ACE.Server/Command/Handlers/AdminCommands.cs index 2ea270ad88..77fceb64af 100644 --- a/Source/ACE.Server/Command/Handlers/AdminCommands.cs +++ b/Source/ACE.Server/Command/Handlers/AdminCommands.cs @@ -4455,7 +4455,8 @@ public static void HandleModifyServerBoolProperty(ISession session, params strin if (parameters[0] == "pk_server" || parameters[0] == "pkl_server") { - PlayerManager.UpdatePKStatusForAllPlayers(parameters[0], boolVal); + // ACRealms derives PK-only status from realm rulesets; do not apply server-wide PK status changes here. + //PlayerManager.UpdatePKStatusForAllPlayers(parameters[0], boolVal); } } else diff --git a/Source/ACE.Server/Command/Handlers/AdvocateCommands.cs b/Source/ACE.Server/Command/Handlers/AdvocateCommands.cs index 62a53267e3..ae1a68cf2e 100644 --- a/Source/ACE.Server/Command/Handlers/AdvocateCommands.cs +++ b/Source/ACE.Server/Command/Handlers/AdvocateCommands.cs @@ -75,7 +75,7 @@ public static void HandleBestow(ISession session, params string[] parameters) // return; //} - if (player.IsPK || PropertyManager.GetBool("pk_server").Item) + if (player.IsPK || player.IsInPkServerRealm) { session.Network.EnqueueSend(new GameMessageSystemChat($"{playerToFind.Name} in a Player Killer and cannot be an Advocate.", ChatMessageType.Broadcast)); return; diff --git a/Source/ACE.Server/Entity/Cloak.cs b/Source/ACE.Server/Entity/Cloak.cs index bcf472753d..7bfe9d8bcd 100644 --- a/Source/ACE.Server/Entity/Cloak.cs +++ b/Source/ACE.Server/Entity/Cloak.cs @@ -5,6 +5,7 @@ using ACE.Server.Managers; using ACE.Server.Network.GameMessages.Messages; using ACE.Server.WorldObjects; +using ACRealms; namespace ACE.Server.Entity { @@ -206,7 +207,7 @@ public static int GetDamageReductionAmount(WorldObject source) // https://asheron.fandom.com/wiki/Master_of_Arms // Cloaks with the chance to reduce incoming damage by 200 have been reduced to 100 for PvP circumstances. if (source is Player) - damageReductionAmount /= 2; + damageReductionAmount = (int)Math.Round(Props.Pvp.Damage.CloakMaxDmgMitigation(source.RealmRuleset)); return damageReductionAmount; } diff --git a/Source/ACE.Server/Entity/DamageEvent.cs b/Source/ACE.Server/Entity/DamageEvent.cs index 480677d047..d044785167 100644 --- a/Source/ACE.Server/Entity/DamageEvent.cs +++ b/Source/ACE.Server/Entity/DamageEvent.cs @@ -11,6 +11,7 @@ using ACE.Server.Managers; using ACE.Server.Network.GameMessages.Messages; using ACE.Server.WorldObjects; +using ACRealms; namespace ACE.Server.Entity { @@ -230,6 +231,15 @@ private float DoCalculateDamage(Creature attacker, Creature defender, WorldObjec // ratings DamageRatingBaseMod = Creature.GetPositiveRatingMod(attacker.GetDamageRating()); + + //Apply custom PvP Dmg rating scaling + var pvpDmgRatingMod = Props.Pvp.Damage.RatingsModDmg(attacker.RealmRuleset); + if (pkBattle) + { + int dmgRatingBase = Creature.ModToRating(DamageRatingBaseMod); + DamageRatingBaseMod = Creature.GetPositiveRatingMod((int)Math.Round(dmgRatingBase * pvpDmgRatingMod)); + } + RecklessnessMod = Creature.GetRecklessnessMod(attacker, defender); SneakAttackMod = attacker.GetSneakAttackMod(defender); HeritageMod = attacker.GetHeritageBonus(Weapon) ? 1.05f : 1.0f; @@ -277,6 +287,14 @@ private float DoCalculateDamage(Creature attacker, Creature defender, WorldObjec CriticalDamageRatingMod = Creature.GetPositiveRatingMod(attacker.GetCritDamageRating()); + //Apply custom PvP CD rating scaling + var pvpCdRatingMod = Props.Pvp.Damage.RatingsModCritdmg(attacker.RealmRuleset); + if (pkBattle) + { + int cdRatingBase = Creature.ModToRating(CriticalDamageRatingMod); + CriticalDamageRatingMod = Creature.GetPositiveRatingMod((int)Math.Round(cdRatingBase * pvpCdRatingMod)); + } + // recklessness excluded from crits RecklessnessMod = 1.0f; DamageRatingMod = Creature.AdditiveCombine(DamageRatingBaseMod, CriticalDamageRatingMod, SneakAttackMod, HeritageMod); @@ -344,10 +362,25 @@ private float DoCalculateDamage(Creature attacker, Creature defender, WorldObjec // damage resistance rating DamageResistanceRatingMod = DamageResistanceRatingBaseMod = defender.GetDamageResistRatingMod(CombatType); + //Apply custom PvP DRR rating scaling + if (pkBattle) + { + int drrRatingBase = Math.Abs(Creature.ModToRating(DamageResistanceRatingBaseMod)); + DamageResistanceRatingMod = DamageResistanceRatingBaseMod = Creature.GetNegativeRatingMod((int)Math.Round(drrRatingBase * pvpDmgRatingMod)); + } + if (IsCritical) { CriticalDamageResistanceRatingMod = Creature.GetNegativeRatingMod(defender.GetCritDamageResistRating()); + //Apply custom PvP CDR rating scaling + var pvpCdrRatingMod = Props.Pvp.Damage.RatingsModCritdmg(attacker.RealmRuleset); + if (pkBattle) + { + int cdrRatingBase = Math.Abs(Creature.ModToRating(CriticalDamageResistanceRatingMod)); + CriticalDamageResistanceRatingMod = Creature.GetNegativeRatingMod((int)Math.Round(cdrRatingBase * pvpCdrRatingMod)); + } + DamageResistanceRatingMod = Creature.AdditiveCombine(DamageResistanceRatingBaseMod, CriticalDamageResistanceRatingMod); } @@ -364,6 +397,282 @@ private float DoCalculateDamage(Creature attacker, Creature defender, WorldObjec // calculate final output damage Damage = DamageBeforeMitigation * ArmorMod * ShieldMod * ResistanceMod * DamageResistanceRatingMod; + if (playerAttacker != null && playerDefender != null) + { + float config_mod = 1; + + if (Weapon != null) + { + try + { + switch (Weapon.WeaponSkill) + { + case Skill.FinesseWeapons: + config_mod = (float)Props.Pvp.Damage.DmgModFw(attacker.RealmRuleset); + break; + case Skill.LightWeapons: + config_mod = (float)Props.Pvp.Damage.DmgModLw(attacker.RealmRuleset); + if (Weapon.W_AttackType == AttackType.TripleStrike) + { + config_mod *= (float)Props.Pvp.Damage.DmgModLwTriplestrike(attacker.RealmRuleset); + } + break; + case Skill.HeavyWeapons: + config_mod = (float)Props.Pvp.Damage.DmgModHw(attacker.RealmRuleset); + if (AttackType.MultiStrike.HasFlag(Weapon.W_AttackType)) + { + config_mod *= (float)Props.Pvp.Damage.DmgModHwMultistrike(attacker.RealmRuleset); + } + break; + case Skill.TwoHandedCombat: + config_mod = (float)Props.Pvp.Damage.DmgMod2h(attacker.RealmRuleset); + break; + case Skill.MissileWeapons: + if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Bow) + { + config_mod = (float)Props.Pvp.Damage.DmgModBow(attacker.RealmRuleset); + } + else if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Crossbow) + { + config_mod = (float)Props.Pvp.Damage.DmgModXbow(attacker.RealmRuleset); + } + else if (Weapon.IsThrownWeapon || Weapon.IsAtlatl) + { + config_mod = (float)Props.Pvp.Damage.DmgModTw(attacker.RealmRuleset); + } + + break; + + } + + if (Weapon.HasImbuedEffect(ImbuedEffectType.ArmorRending)) + { + config_mod *= (float)Props.Pvp.Damage.DmgModAr(attacker.RealmRuleset); + switch (Weapon.WeaponSkill) + { + case Skill.FinesseWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModFwAr(attacker.RealmRuleset); + break; + case Skill.LightWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModLwAr(attacker.RealmRuleset); + break; + case Skill.HeavyWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModHwAr(attacker.RealmRuleset); + break; + case Skill.TwoHandedCombat: + config_mod *= (float)Props.Pvp.Damage.DmgMod2hAr(attacker.RealmRuleset); + break; + case Skill.MissileWeapons: + if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Bow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModBowAr(attacker.RealmRuleset); + } + else if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Crossbow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModXbowAr(attacker.RealmRuleset); + } + else if (Weapon.IsThrownWeapon || Weapon.IsAtlatl) + { + config_mod *= (float)Props.Pvp.Damage.DmgModTwAr(attacker.RealmRuleset); + } + + break; + + } + } + else if (Weapon.HasImbuedEffect(ImbuedEffectType.CripplingBlow)) + { + config_mod *= (float)Props.Pvp.Damage.DmgModCb(attacker.RealmRuleset); + switch (Weapon.WeaponSkill) + { + case Skill.FinesseWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModFwCb(attacker.RealmRuleset); + break; + case Skill.LightWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModLwCb(attacker.RealmRuleset); + if (Weapon.W_AttackType == AttackType.TripleStrike) + { + if (IsCritical) + { + config_mod *= (float)Props.Pvp.Damage.DmgModLwCbCritTriplestrike(attacker.RealmRuleset); + } + } + break; + case Skill.HeavyWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModHwCb(attacker.RealmRuleset); + if (AttackType.MultiStrike.HasFlag(Weapon.W_AttackType)) + { + if (IsCritical) + { + config_mod *= (float)Props.Pvp.Damage.DmgModHwCbCritMultistrike(attacker.RealmRuleset); + } + } + break; + case Skill.TwoHandedCombat: + config_mod *= (float)Props.Pvp.Damage.DmgMod2hCb(attacker.RealmRuleset); + break; + case Skill.MissileWeapons: + if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Bow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModBowCb(attacker.RealmRuleset); + } + else if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Crossbow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModXbowCb(attacker.RealmRuleset); + } + else if (Weapon.IsThrownWeapon || Weapon.IsAtlatl) + { + config_mod *= (float)Props.Pvp.Damage.DmgModTwCb(attacker.RealmRuleset); + } + break; + + } + + if (IsCritical) + { + switch (Weapon.WeaponSkill) + { + case Skill.FinesseWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModFwCbCrit(attacker.RealmRuleset); + break; + case Skill.LightWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModLwCbCrit(attacker.RealmRuleset); + break; + case Skill.HeavyWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModHwCbCrit(attacker.RealmRuleset); + break; + case Skill.TwoHandedCombat: + config_mod *= (float)Props.Pvp.Damage.DmgMod2hCbCrit(attacker.RealmRuleset); + break; + case Skill.MissileWeapons: + if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Bow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModBowCbCrit(attacker.RealmRuleset); + } + else if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Crossbow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModXbowCbCrit(attacker.RealmRuleset); + } + else if (Weapon.IsThrownWeapon || Weapon.IsAtlatl) + { + config_mod *= (float)Props.Pvp.Damage.DmgModTwCbCrit(attacker.RealmRuleset); + } + break; + + } + } + } + else if (Weapon.HasImbuedEffect(ImbuedEffectType.CriticalStrike)) + { + config_mod *= (float)Props.Pvp.Damage.DmgModCs(attacker.RealmRuleset); + switch (Weapon.WeaponSkill) + { + case Skill.FinesseWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModFwCs(attacker.RealmRuleset); + break; + case Skill.LightWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModLwCs(attacker.RealmRuleset); + break; + case Skill.HeavyWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModHwCs(attacker.RealmRuleset); + break; + case Skill.TwoHandedCombat: + config_mod *= (float)Props.Pvp.Damage.DmgMod2hCs(attacker.RealmRuleset); + break; + case Skill.MissileWeapons: + if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Bow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModBowCs(attacker.RealmRuleset); + } + else if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Crossbow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModXbowCs(attacker.RealmRuleset); + } + else if (Weapon.IsThrownWeapon || Weapon.IsAtlatl) + { + config_mod *= (float)Props.Pvp.Damage.DmgModTwCs(attacker.RealmRuleset); + } + break; + + } + } + else if (Weapon.IgnoreMagicArmor && Weapon.IgnoreMagicResist) + { + config_mod *= (float)Props.Pvp.Damage.DmgModHollow(attacker.RealmRuleset); + switch (Weapon.WeaponSkill) + { + case Skill.FinesseWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModFwHollow(attacker.RealmRuleset); + break; + case Skill.LightWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModLwHollow(attacker.RealmRuleset); + break; + case Skill.HeavyWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModHwHollow(attacker.RealmRuleset); + break; + case Skill.TwoHandedCombat: + config_mod *= (float)Props.Pvp.Damage.DmgMod2hHollow(attacker.RealmRuleset); + break; + case Skill.MissileWeapons: + if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Bow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModBowHollow(attacker.RealmRuleset); + } + else if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Crossbow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModXbowHollow(attacker.RealmRuleset); + } + else if (Weapon.IsThrownWeapon || Weapon.IsAtlatl) + { + config_mod *= (float)Props.Pvp.Damage.DmgModTwHollow(attacker.RealmRuleset); + } + break; + + } + } + else if (Weapon.HasImbuedEffect(ImbuedEffectType.IgnoreAllArmor)) + { + config_mod *= (float)Props.Pvp.Damage.DmgModPhantom(attacker.RealmRuleset); + switch (Weapon.WeaponSkill) + { + case Skill.FinesseWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModFwPhantom(attacker.RealmRuleset); + break; + case Skill.LightWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModLwPhantom(attacker.RealmRuleset); + break; + case Skill.HeavyWeapons: + config_mod *= (float)Props.Pvp.Damage.DmgModHwPhantom(attacker.RealmRuleset); + break; + case Skill.TwoHandedCombat: + config_mod *= (float)Props.Pvp.Damage.DmgMod2hPhantom(attacker.RealmRuleset); + break; + case Skill.MissileWeapons: + if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Bow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModBowPhantom(attacker.RealmRuleset); + } + else if (Weapon.DefaultCombatStyle != null && Weapon.DefaultCombatStyle == CombatStyle.Crossbow) + { + config_mod *= (float)Props.Pvp.Damage.DmgModXbowPhantom(attacker.RealmRuleset); + } + else if (Weapon.IsThrownWeapon || Weapon.IsAtlatl) + { + config_mod *= (float)Props.Pvp.Damage.DmgModTwPhantom(attacker.RealmRuleset); + } + break; + } + } + + Damage = Damage * config_mod; + } + catch (Exception ex) + { + log.Error($"Failed applying server configured pvp mods. Ex: {ex}"); + } + } + } + DamageMitigated = DamageBeforeMitigation - Damage; return Damage; diff --git a/Source/ACE.Server/Factories/PlayerFactory.cs b/Source/ACE.Server/Factories/PlayerFactory.cs index d82191121d..3401405e14 100644 --- a/Source/ACE.Server/Factories/PlayerFactory.cs +++ b/Source/ACE.Server/Factories/PlayerFactory.cs @@ -414,6 +414,9 @@ public static CreateResult Create(CharacterCreateInfo characterCreateInfo, Weeni spellFreeRide.PositionAnglesX.Value, spellFreeRide.PositionAnglesY.Value, spellFreeRide.PositionAnglesZ.Value, spellFreeRide.PositionAnglesW.Value), iid); player.Instantiation = new InstancedPosition(instantiation); + + if (Props.Pvp.World.IsPkOnly(defaultRealm.StandardRules)) + player.SetProperty(PropertyInt.PlayerKillerStatus, (int)PlayerKillerStatus.PK); } else { diff --git a/Source/ACE.Server/Managers/PropertyManager.cs b/Source/ACE.Server/Managers/PropertyManager.cs index c62247c79d..406d0cc3ca 100644 --- a/Source/ACE.Server/Managers/PropertyManager.cs +++ b/Source/ACE.Server/Managers/PropertyManager.cs @@ -668,6 +668,83 @@ public static void LoadDefaultProperties() ("encounter_regen_interval", new Property(600, "the number of seconds a generator for regions at which spawns its next set of objects")), ("equipmentsetid_drop_rate", new Property(1.0, "Modifier for EquipmentSetID drop rate, 1 being normal")), ("fast_missile_modifier", new Property(1.2, "The speed multiplier applied to fast missiles. Defaults to retail value of 1.2")), + ("pvp_cloak_max_dmg_mitigation", new Property(100, "The maximum amount of damage a cloak proc can mitigate")), + ("pvp_dmg_mod_war", new Property(1, "Scales the amount of damage for war magic")), + ("pvp_dmg_mod_war_variance", new Property(1, "Scales the low end for war magic bolts and arcs without effecting top end. Values under 1 will reduce the variance and increase min dmg by the amount the variance was reduced. Values over 1 will increase variance and reduce min dmg to match.")), + ("pvp_dmg_mod_war_streak", new Property(1, "Scales the amount of damage for war streaks")), + ("pvp_dmg_mod_war_blast", new Property(1, "Scales the amount of damage for war blasts")), + ("pvp_dmg_mod_war_cb_crit", new Property(1, "Scales the amount of CB crit damage for war magic.")), + ("pvp_dmg_mod_war_cs_crit", new Property(1, "Scales the amount of CS crit damage for war magic.")), + ("pvp_dmg_mod_war_cs_dmg", new Property(1, "Scales the amount of CS damage for war magic for all hits (both crits and non-crits).")), + ("pvp_dmg_mod_void", new Property(1, "Scales the amount of damage players take from Void Magic (not including streaks and DOTs which have their own mods)")), + ("pvp_dmg_mod_void_streak", new Property(1, "Scales the amount of damage for void streaks.")), + ("pvp_dmg_mod_void_dot", new Property(1, "Scales the amount of damage for void DOTs.")), + ("pvp_dmg_mod_void_crit", new Property(1, "Scales the amount of crit damage for void magic.")), + ("pvp_dmg_mod_void_cb_crit", new Property(1, "Scales the amount of CB crit damage for void magic.")), + ("pvp_dmg_mod_void_variance", new Property(1, "Scales the low end for void magic bolts and arcs without effecting top end. Values under 1 will reduce the variance and increase min dmg by the amount the variance was reduced. Values over 1 will increase variance and reduce min dmg to match.")), + ("pvp_dmg_mod_phantom", new Property(1, "Scales the amount of damage for phantom")), + ("pvp_dmg_mod_hollow", new Property(1, "Scales the amount of damage for hollow")), + ("pvp_dmg_mod_cb", new Property(1, "Scales the amount of damage for crippling blow")), + ("pvp_dmg_mod_ar", new Property(1, "Scales the amount of damage for armor rending")), + ("pvp_dmg_mod_cs", new Property(1, "Scales the amount of damage for critical strike")), + ("pvp_dmg_mod_fw", new Property(1, "Scales the amount of damage for Finesse Weapons")), + ("pvp_dmg_mod_fw_cb", new Property(1, "Scales the amount of damage for FW CB.")), + ("pvp_dmg_mod_fw_cb_crit", new Property(1, "Scales the amount of damage for FW CB Crit.")), + ("pvp_dmg_mod_fw_cs", new Property(1, "Scales the amount of damage for FW CS.")), + ("pvp_dmg_mod_fw_ar", new Property(1, "Scales the amount of damage for FW AR.")), + ("pvp_dmg_mod_fw_hollow", new Property(1, "Scales the amount of damage for FW Hollow.")), + ("pvp_dmg_mod_fw_phantom", new Property(1, "Scales the amount of damage for war FW Phantom.")), + ("pvp_dmg_mod_lw", new Property(1, "Scales the amount of damage for Light Weapons")), + ("pvp_dmg_mod_lw_cb", new Property(1, "Scales the amount of damage for LW CB.")), + ("pvp_dmg_mod_lw_cb_crit", new Property(1, "Scales the amount of damage for LW CB Crit.")), + ("pvp_dmg_mod_lw_cs", new Property(1, "Scales the amount of damage for LW CS.")), + ("pvp_dmg_mod_lw_ar", new Property(1, "Scales the amount of damage for LW AR.")), + ("pvp_dmg_mod_lw_hollow", new Property(1, "Scales the amount of damage for LW Hollow.")), + ("pvp_dmg_mod_lw_phantom", new Property(1, "Scales the amount of damage for LW Phantom.")), + ("pvp_dmg_mod_lw_triplestrike", new Property(1, "Scales the amount of damage for LW Triple Strike weapons.")), + ("pvp_dmg_mod_lw_cb_crit_triplestrike", new Property(1, "Scales the amount of Crit damage for LW Triple Strike weapons.")), + ("pvp_dmg_mod_hw", new Property(1, "Scales the amount of damage for Heavy Weapons")), + ("pvp_dmg_mod_hw_cb", new Property(1, "Scales the amount of damage for HW CB.")), + ("pvp_dmg_mod_hw_cb_crit", new Property(1, "Scales the amount of damage for HW CB Crit.")), + ("pvp_dmg_mod_hw_cs", new Property(1, "Scales the amount of damage for HW CS.")), + ("pvp_dmg_mod_hw_ar", new Property(1, "Scales the amount of damage for HW AR.")), + ("pvp_dmg_mod_hw_hollow", new Property(1, "Scales the amount of damage for HW Hollow.")), + ("pvp_dmg_mod_hw_phantom", new Property(1, "Scales the amount of damage for HW Phantom.")), + ("pvp_dmg_mod_hw_multistrike", new Property(1, "Scales the amount of damage for HW Multi Strike weapons.")), + ("pvp_dmg_mod_hw_cb_crit_multistrike", new Property(1, "Scales the amount of Crit damage for HW Multi Strike weapons.")), + ("pvp_dmg_mod_2h", new Property(1, "Scales the amount of damage for Two Handed Weapons")), + ("pvp_dmg_mod_2h_cb", new Property(1, "Scales the amount of damage for v CB.")), + ("pvp_dmg_mod_2h_cb_crit", new Property(1, "Scales the amount of damage for 2H CB Crit.")), + ("pvp_dmg_mod_2h_cs", new Property(1, "Scales the amount of damage for 2H CS.")), + ("pvp_dmg_mod_2h_ar", new Property(1, "Scales the amount of damage for 2H AR.")), + ("pvp_dmg_mod_2h_hollow", new Property(1, "Scales the amount of damage for 2H Hollow.")), + ("pvp_dmg_mod_2h_phantom", new Property(1, "Scales the amount of damage for 2H Phantom.")), + ("pvp_dmg_mod_xbow", new Property(1, "Scales the amount of damage for Xbow")), + ("pvp_dmg_mod_xbow_cb", new Property(1, "Scales the amount of damage for Xbow CB.")), + ("pvp_dmg_mod_xbow_cb_crit", new Property(1, "Scales the amount of damage for Xbow CB Crit.")), + ("pvp_dmg_mod_xbow_cs", new Property(1, "Scales the amount of damage for Xbow CS.")), + ("pvp_dmg_mod_xbow_ar", new Property(1, "Scales the amount of damage for Xbow AR.")), + ("pvp_dmg_mod_xbow_hollow", new Property(1, "Scales the amount of damage for Xbow Hollow.")), + ("pvp_dmg_mod_xbow_phantom", new Property(1, "Scales the amount of damage for Xbow Phantom.")), + ("pvp_dmg_mod_bow", new Property(1, "Scales the amount of damage for hollow")), + ("pvp_dmg_mod_bow_cb", new Property(1, "Scales the amount of damage for Bow CB.")), + ("pvp_dmg_mod_bow_cb_crit", new Property(1, "Scales the amount of damage for Bow CB Crit.")), + ("pvp_dmg_mod_bow_cs", new Property(1, "Scales the amount of damage for Bow CS.")), + ("pvp_dmg_mod_bow_ar", new Property(1, "Scales the amount of damage for Bow AR.")), + ("pvp_dmg_mod_bow_hollow", new Property(1, "Scales the amount of damage for Bow Hollow.")), + ("pvp_dmg_mod_bow_phantom", new Property(1, "Scales the amount of damage for Bow Phantom.")), + ("pvp_dmg_mod_tw", new Property(1, "Scales the amount of damage for hollow")), + ("pvp_dmg_mod_tw_cb", new Property(1, "Scales the amount of damage for TW CB.")), + ("pvp_dmg_mod_tw_cb_crit", new Property(1, "Scales the amount of damage for TW CB Crit.")), + ("pvp_dmg_mod_tw_cs", new Property(1, "Scales the amount of damage for TW CS.")), + ("pvp_dmg_mod_tw_ar", new Property(1, "Scales the amount of damage for TW AR.")), + ("pvp_dmg_mod_tw_hollow", new Property(1, "Scales the amount of damage for TW Hollow.")), + ("pvp_dmg_mod_tw_phantom", new Property(1, "Scales the amount of damage for TW Phantom.")), + ("pvp_cs_critrate_mod", new Property(1, "Scales the crit rate for CS")), + ("pvp_void_hybrid_mod", new Property(1, "Scales the amount of DOT damage when a player is a hybrid void.")), + ("pvp_dmg_mod_void_dot_rating_reduction", new Property(1, "Scales the amount of rating reduction received from a void DOT that's cast by a PK on another player.")), + ("pvp_ratings_mod_dmg", new Property(1, "Scales the bonus received from dmg and dmg reduction ratings during pvp")), + ("pvp_ratings_mod_critdmg", new Property(1, "Scales the bonus received from crit dmg and crit dmg reduction ratings during pvp")), ("ignore_magic_armor_pvp_scalar", new Property(1.0, "Scales the effectiveness of IgnoreMagicArmor (ie. hollow weapons) in pvp battles. 1.0 = full effectiveness / ignore all enchantments on armor (default), 0.5 = half effectiveness / use half enchantments from armor, 0.0 = no effectiveness / use full enchantments from armor")), ("ignore_magic_resist_pvp_scalar", new Property(1.0, "Scales the effectiveness of IgnoreMagicResist (ie. hollow weapons) in pvp battles. 1.0 = full effectiveness / ignore all resistances from life enchantments (default), 0.5 = half effectiveness / use half resistances from life enchantments, 0.0 = no effectiveness / use full resistances from life enchantments")), ("luminance_modifier", new Property(1.0, "Scales the amount of luminance received by players")), diff --git a/Source/ACE.Server/WorldObjects/ACRealms/Player_Location_ACRealms.cs b/Source/ACE.Server/WorldObjects/ACRealms/Player_Location_ACRealms.cs index bc37554e81..3f7e6b8ee9 100644 --- a/Source/ACE.Server/WorldObjects/ACRealms/Player_Location_ACRealms.cs +++ b/Source/ACE.Server/WorldObjects/ACRealms/Player_Location_ACRealms.cs @@ -36,5 +36,6 @@ public bool IsInOwnedClassicalInstance } public bool IsInEphemeralRealm => CurrentLandblock.IsEphemeral; + public bool IsInPkServerRealm => CurrentLandblock.RealmHelpers.IsPkOnly; } } diff --git a/Source/ACE.Server/WorldObjects/Creature_Properties.cs b/Source/ACE.Server/WorldObjects/Creature_Properties.cs index 7c5317bf4d..e87f201e49 100644 --- a/Source/ACE.Server/WorldObjects/Creature_Properties.cs +++ b/Source/ACE.Server/WorldObjects/Creature_Properties.cs @@ -104,7 +104,7 @@ public float GetResistanceMod(DamageType damageType, WorldObject attacker, World // hollow weapons also ignore player natural resistances if (ignoreMagicResist) { - if (!(attacker is Player) || !(this is Player) || PropertyManager.GetDouble("ignore_magic_resist_pvp_scalar").Item == 1.0) + if (!(attacker is Player) || !(this is Player) || Props.Pvp.Damage.IgnoreMagicResistPvpScalar(attacker.RealmRuleset) == 1.0) return weaponResistanceMod; } diff --git a/Source/ACE.Server/WorldObjects/Managers/EnchantmentManager.cs b/Source/ACE.Server/WorldObjects/Managers/EnchantmentManager.cs index e962af11b0..b21db8505d 100644 --- a/Source/ACE.Server/WorldObjects/Managers/EnchantmentManager.cs +++ b/Source/ACE.Server/WorldObjects/Managers/EnchantmentManager.cs @@ -14,6 +14,8 @@ using ACE.Server.Network.GameEvent.Events; using ACE.Server.Network.Structure; using ACE.Server.WorldObjects.Entity; +using ACRealms; +using log4net; namespace ACE.Server.WorldObjects.Managers { @@ -28,6 +30,8 @@ public enum StackType public class EnchantmentManager { + private ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + public WorldObject WorldObject { get; } public Player Player { get; } @@ -275,6 +279,16 @@ private PropertiesEnchantmentRegistry BuildEntry(Spell spell, WorldObject caster entry.SpellSetId = (EquipmentSet)caster.EquipmentSetId; } + if (caster != null && + caster.PlayerKillerStatus == PlayerKillerStatus.PK && + spell.IsHarmful && + !spell.IsSelfTargeted && + this.Player != null && + this.Player.PlayerKillerStatus == PlayerKillerStatus.PK) + { + entry.IsPvP = true; + } + return entry; } @@ -1157,7 +1171,12 @@ public virtual int GetNetherDotDamageRating() // normally we could just use netherDot.StatModValue here, // but in case WorldObject has a non-default HeartbeatInterval, // we want this value to still be based on the damage per default heartbeat interval - totalBaseDamage += GetDamagePerTick(netherDot, 5.0); + var ratingDamage = GetDamagePerTick(netherDot, 5.0); + + if (netherDot.IsPvP) + ratingDamage *= (float)Props.Pvp.Damage.DmgModVoidDotRatingReduction((WorldObject).RealmRuleset); + + totalBaseDamage += ratingDamage; } var rating = (int)Math.Round(totalBaseDamage / 8.0f); // thanks to Xenocide for this formula! //Console.WriteLine($"{WorldObject.Name}.NetherDotDamageRating: {rating}"); @@ -1371,8 +1390,47 @@ public void ApplyDamageTick(List enchantments, Da //Console.WriteLine("DRR: " + Creature.NegativeModToRating(damageResistRatingMod)); //Console.WriteLine("NRR: " + Creature.NegativeModToRating(netherResistRatingMod)); + var pvpDmgMod = 1.0f; + if (damageType == DamageType.Nether && sourcePlayer != null && targetPlayer != null) + pvpDmgMod = (float)Props.Pvp.Damage.DmgModVoidDot(damager.RealmRuleset); + tickAmount *= resistanceMod * damageResistRatingMod * dotResistRatingMod; + //Add an additional modifier for hybrid void characters in pvp + if (sourcePlayer != null && targetPlayer != null && damageType == DamageType.Nether) + { + try + { + var isHybrid = false; + foreach (var playerSkill in sourcePlayer.Skills) + { + if (playerSkill.Key == Skill.FinesseWeapons || + playerSkill.Key == Skill.HeavyWeapons || + playerSkill.Key == Skill.LightWeapons || + playerSkill.Key == Skill.WarMagic || + playerSkill.Key == Skill.MissileWeapons || + playerSkill.Key == Skill.TwoHandedCombat) + { + if (playerSkill.Value.AdvancementClass == SkillAdvancementClass.Trained || playerSkill.Value.AdvancementClass == SkillAdvancementClass.Specialized) + { + isHybrid = true; + break; + } + } + } + + if (isHybrid) + { + var hybridMod = Props.Pvp.Damage.VoidHybridMod(damager.RealmRuleset); + tickAmount = tickAmount * (float)hybridMod; + } + } + catch (Exception ex) + { + log.Error($"Error in EnchantmentManager.ApplyDamageTick while applying pvp_void_hybrid_mod. Ex: {ex}"); + } + } + // make sure the target's current health is not exceeded if (tickAmountTotal + tickAmount >= creature.Health.Current) { diff --git a/Source/ACE.Server/WorldObjects/Monster_Melee.cs b/Source/ACE.Server/WorldObjects/Monster_Melee.cs index b02e7f5871..e0f4e39e46 100644 --- a/Source/ACE.Server/WorldObjects/Monster_Melee.cs +++ b/Source/ACE.Server/WorldObjects/Monster_Melee.cs @@ -463,7 +463,7 @@ public float IgnoreMagicArmorScaled(float enchantments) if (!(this is Player)) return 0.0f; - var scalar = PropertyManager.GetDouble("ignore_magic_armor_pvp_scalar").Item; + var scalar = Props.Pvp.Damage.IgnoreMagicArmorPvpScalar(this.RealmRuleset); if (scalar != 1.0) return (float)(enchantments * (1.0 - scalar)); @@ -476,7 +476,7 @@ public int IgnoreMagicResistScaled(int enchantments) if (!(this is Player)) return 0; - var scalar = PropertyManager.GetDouble("ignore_magic_resist_pvp_scalar").Item; + var scalar = Props.Pvp.Damage.IgnoreMagicResistPvpScalar(this.RealmRuleset); if (scalar != 1.0) return (int)Math.Round(enchantments * (1.0 - scalar)); diff --git a/Source/ACE.Server/WorldObjects/Player_Death.cs b/Source/ACE.Server/WorldObjects/Player_Death.cs index 22e99d0810..f8fc25393e 100644 --- a/Source/ACE.Server/WorldObjects/Player_Death.cs +++ b/Source/ACE.Server/WorldObjects/Player_Death.cs @@ -987,7 +987,7 @@ public void PK_DeathTick() if (MinimumTimeSincePk == null || (PropertyManager.GetBool("pk_server_safe_training_academy").Item && RecallsDisabled)) return; - if (PkLevel == PKLevel.NPK && !Props.Pvp.World.IsPkOnly(RealmRuleset) && !PropertyManager.GetBool("pkl_server").Item) + if (PkLevel == PKLevel.NPK && !IsInPkServerRealm && !PropertyManager.GetBool("pkl_server").Item) { MinimumTimeSincePk = null; return; diff --git a/Source/ACE.Server/WorldObjects/Player_Location.cs b/Source/ACE.Server/WorldObjects/Player_Location.cs index f487136054..70e7bac064 100644 --- a/Source/ACE.Server/WorldObjects/Player_Location.cs +++ b/Source/ACE.Server/WorldObjects/Player_Location.cs @@ -867,16 +867,19 @@ private bool OnTransitionToNewInstance(ushort prevRealmId, ushort newRealmId, In EphemeralRealmLastEnteredDrop = null; } - var pk = false; + var isDuelInstance = false; + var isPkOnlyRealm = false; if (newLocation.IsEphemeralRealm) { var lb = LandblockManager.GetLandblockUnsafe(newLocation.LandblockId, newLocation.Instance); - if (lb.RealmHelpers.IsDuel || lb.RealmHelpers.IsPkOnly) - pk = true; + isDuelInstance = lb.RealmHelpers.IsDuel; + isPkOnlyRealm = lb.RealmHelpers.IsPkOnly; } if (Props.Pvp.World.IsPkOnly(newRealm.StandardRules)) - pk = true; + isPkOnlyRealm = true; + + var pk = isDuelInstance || (isPkOnlyRealm && MinimumTimeSincePk == null); PlayerKillerStatus = pk ? PlayerKillerStatus.PK : PlayerKillerStatus.NPK; EnqueueBroadcast(new GameMessagePublicUpdatePropertyInt(this, PropertyInt.PlayerKillerStatus, (int)PlayerKillerStatus)); diff --git a/Source/ACE.Server/WorldObjects/SpellProjectile.cs b/Source/ACE.Server/WorldObjects/SpellProjectile.cs index 10a05e3605..1acf0c2ebd 100644 --- a/Source/ACE.Server/WorldObjects/SpellProjectile.cs +++ b/Source/ACE.Server/WorldObjects/SpellProjectile.cs @@ -13,6 +13,7 @@ using ACE.Server.Network.GameMessages.Messages; using ACE.Server.Realms; using ACE.Server.WorldObjects.Entity; +using ACRealms; namespace ACE.Server.WorldObjects { @@ -535,6 +536,23 @@ public override void OnCollideObject(WorldObject target) skillBonus = Spell.MinDamage * percentageBonus; } } + + var minDmg = Spell.MinDamage; + var spellType = GetProjectileSpellType(Spell.Id); + if (isPVP && Spell.School == MagicSchool.WarMagic && (spellType == ProjectileSpellType.Arc || spellType == ProjectileSpellType.Bolt)) + { + var warVarianceMod = Props.Pvp.Damage.DmgModWarVariance(source.RealmRuleset); + var modifiedVariance = Convert.ToInt32(Math.Round(Spell.Variance * warVarianceMod)); + minDmg = Spell.MaxDamage - modifiedVariance; + } + + if (isPVP && Spell.School == MagicSchool.VoidMagic && (spellType == ProjectileSpellType.Arc || spellType == ProjectileSpellType.Bolt)) + { + var voidVarianceMod = Props.Pvp.Damage.DmgModVoidVariance(source.RealmRuleset); + var modifiedVariance = Convert.ToInt32(Math.Round(Spell.Variance * voidVarianceMod)); + minDmg = Spell.MaxDamage - modifiedVariance; + } + baseDamage = ThreadSafeRandom.Next(Spell.MinDamage, Spell.MaxDamage); weaponResistanceMod = GetWeaponResistanceModifier(weapon, sourceCreature, attackSkill, Spell.DamageType); @@ -567,6 +585,60 @@ public override void OnCollideObject(WorldObject target) { ShowInfo(target, Spell, attackSkill, criticalChance, criticalHit, critDefended, overpower, weaponCritDamageMod, skillBonus, baseDamage, critDamageBonus, elementalDamageMod, slayerMod, weaponResistanceMod, resistanceMod, absorbMod, LifeProjectileDamage, lifeMagicDamage, finalDamage); } + + //Apply pvp dmg mods for war and void (not including DOTs which are in EnchantmentManager.ApplyDamageTick) + float dmgMod = 1; + if (sourcePlayer != null && targetPlayer != null) + { + if (Spell.School == MagicSchool.WarMagic) + { + dmgMod = (float)Props.Pvp.Damage.DmgModWar(source.RealmRuleset); + + if (SpellType == ProjectileSpellType.Streak) + dmgMod = (float)Props.Pvp.Damage.DmgModWarStreak(source.RealmRuleset); // scales war streak damages + + if (SpellType == ProjectileSpellType.Blast) + dmgMod = (float)Props.Pvp.Damage.DmgModWarBlast(source.RealmRuleset); // scales war blast damages + + if (criticalHit && weapon.HasImbuedEffect(ImbuedEffectType.CripplingBlow)) + { + dmgMod *= (float)Props.Pvp.Damage.DmgModWarCbCrit(source.RealmRuleset); + } + + if (weapon.HasImbuedEffect(ImbuedEffectType.CriticalStrike)) + { + dmgMod *= (float)Props.Pvp.Damage.DmgModWarCsDmg(source.RealmRuleset); + + if (criticalHit) + { + dmgMod *= (float)Props.Pvp.Damage.DmgModWarCsCrit(source.RealmRuleset); + } + } + + finalDamage = finalDamage * dmgMod; + } + else if (Spell.DamageType == DamageType.Nether) + { + dmgMod = (float)Props.Pvp.Damage.DmgModVoid(source.RealmRuleset); + + if (SpellType == ProjectileSpellType.Streak) + { + dmgMod = (float)Props.Pvp.Damage.DmgModVoidStreak(source.RealmRuleset); // scales void streak damages + } + + if (criticalHit) + { + dmgMod *= (float)Props.Pvp.Damage.DmgModVoidCrit(source.RealmRuleset); + if (weapon.HasImbuedEffect(ImbuedEffectType.CripplingBlow)) + { + dmgMod *= (float)Props.Pvp.Damage.DmgModVoidCbCrit(source.RealmRuleset); + } + } + + finalDamage = finalDamage * dmgMod; + } + } + return finalDamage; } @@ -737,15 +809,40 @@ public void DamageTarget(Creature target, float damage, bool critical, bool crit } var damageRating = sourceCreature?.GetDamageRating() ?? 0; + + //Apply custom PvP Dmg rating scaling + var pvpDmgRatingModifierConfig = Props.Pvp.Damage.RatingsModDmg((sourceCreature ?? ProjectileSource ?? this).RealmRuleset); + if (pkBattle) + { + damageRating = (int)Math.Round(damageRating * pvpDmgRatingModifierConfig); + } + damageRatingMod = Creature.AdditiveCombine(Creature.GetPositiveRatingMod(damageRating), heritageMod, sneakAttackMod); damageResistRatingMod = target.GetDamageResistRatingMod(CombatType.Magic); + //Apply custom PvP DRR rating scaling + if (pkBattle) + { + int drrRatingBase = Math.Abs(Creature.ModToRating(damageResistRatingMod)); + damageResistRatingMod = Creature.GetNegativeRatingMod((int)Math.Round(drrRatingBase * pvpDmgRatingModifierConfig)); + } + if (critical) { critDamageRatingMod = Creature.GetPositiveRatingMod(sourceCreature?.GetCritDamageRating() ?? 0); critDamageResistRatingMod = Creature.GetNegativeRatingMod(target.GetCritDamageResistRating()); + if (pkBattle) + { + var pvpCritRatingModifierConfig = Props.Pvp.Damage.RatingsModCritdmg((sourceCreature ?? ProjectileSource ?? this).RealmRuleset); + int cdRatingBase = Math.Abs(Creature.ModToRating(critDamageRatingMod)); + critDamageRatingMod = Creature.GetPositiveRatingMod((int)Math.Round(cdRatingBase * pvpCritRatingModifierConfig)); + + int cdrRatingBase = Math.Abs(Creature.ModToRating(critDamageResistRatingMod)); + critDamageResistRatingMod = Creature.GetNegativeRatingMod((int)Math.Round(cdrRatingBase * pvpCritRatingModifierConfig)); + } + damageRatingMod = Creature.AdditiveCombine(damageRatingMod, critDamageRatingMod); damageResistRatingMod = Creature.AdditiveCombine(damageResistRatingMod, critDamageResistRatingMod); } diff --git a/Source/ACRealms.RealmProps/PropDefs/json/Pvp/Damage.jsonc b/Source/ACRealms.RealmProps/PropDefs/json/Pvp/Damage.jsonc new file mode 100644 index 0000000000..f0587a229c --- /dev/null +++ b/Source/ACRealms.RealmProps/PropDefs/json/Pvp/Damage.jsonc @@ -0,0 +1,639 @@ +{ + "$schema_version": 1, + "namespace": "Pvp.Damage", + "description": "Properties related to player damage mods, affecting PvP only", + "properties": { + "IgnoreMagicResistPvpScalar": { + "type": "float", + "description": "Scales the effectiveness of IgnoreMagicResist (ie. hollow weapons) in pvp battles. 1.0 = full effectiveness / ignore all resistances from life enchantments (default), 0.5 = half effectiveness / use half resistances from life enchantments, 0.0 = no effectiveness / use full resistances from life enchantments", + "default_from_server_property": "ignore_magic_resist_pvp_scalar", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "IgnoreMagicArmorPvpScalar": { + "type": "float", + "description": "Scales the effectiveness of IgnoreMagicArmor (ie. hollow weapons) in pvp battles. 1.0 = full effectiveness / ignore all enchantments on armor (default), 0.5 = half effectiveness / use half enchantments from armor, 0.0 = no effectiveness / use full enchantments from armor", + "default_from_server_property": "ignore_magic_armor_pvp_scalar", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "CloakMaxDmgMitigation": { + "type": "float", + "description": "The maximum amount of damage a cloak proc can mitigate", + "default_from_server_property": "pvp_cloak_max_dmg_mitigation", + "default": 100, + "min_value": 0, + "max_value": 10000 + }, + "DmgModWar": { + "type": "float", + "description": "Scales the amount of damage for war magic", + "default_from_server_property": "pvp_dmg_mod_war", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModWarVariance": { + "type": "float", + "description": "Scales the low end for war magic bolts and arcs without effecting top end. Values under 1 will reduce the variance and increase min dmg by the amount the variance was reduced. Values over 1 will increase variance and reduce min dmg to match.", + "default_from_server_property": "pvp_dmg_mod_war_variance", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModWarStreak": { + "type": "float", + "description": "Scales the amount of damage for war streaks", + "default_from_server_property": "pvp_dmg_mod_war_streak", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModWarBlast": { + "type": "float", + "description": "Scales the amount of damage for war blasts", + "default_from_server_property": "pvp_dmg_mod_war_blast", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModWarCbCrit": { + "type": "float", + "description": "Scales the amount of CB crit damage for war magic.", + "default_from_server_property": "pvp_dmg_mod_war_cb_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModWarCsCrit": { + "type": "float", + "description": "Scales the amount of CS crit damage for war magic.", + "default_from_server_property": "pvp_dmg_mod_war_cs_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModWarCsDmg": { + "type": "float", + "description": "Scales the amount of CS damage for war magic for all hits (both crits and non-crits).", + "default_from_server_property": "pvp_dmg_mod_war_cs_dmg", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModVoid": { + "type": "float", + "description": "Scales the amount of damage players take from Void Magic (not including streaks and DOTs which have their own mods)", + "default_from_server_property": "pvp_dmg_mod_void", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModVoidStreak": { + "type": "float", + "description": "Scales the amount of damage for void streaks.", + "default_from_server_property": "pvp_dmg_mod_void_streak", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModVoidDot": { + "type": "float", + "description": "Scales the amount of damage for void DOTs.", + "default_from_server_property": "pvp_dmg_mod_void_dot", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModVoidCrit": { + "type": "float", + "description": "Scales the amount of crit damage for void magic.", + "default_from_server_property": "pvp_dmg_mod_void_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModVoidCbCrit": { + "type": "float", + "description": "Scales the amount of CB crit damage for void magic.", + "default_from_server_property": "pvp_dmg_mod_void_cb_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModVoidVariance": { + "type": "float", + "description": "Scales the low end for void magic bolts and arcs without effecting top end. Values under 1 will reduce the variance and increase min dmg by the amount the variance was reduced. Values over 1 will increase variance and reduce min dmg to match.", + "default_from_server_property": "pvp_dmg_mod_void_variance", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModPhantom": { + "type": "float", + "description": "Scales the amount of damage for phantom", + "default_from_server_property": "pvp_dmg_mod_phantom", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModHollow": { + "type": "float", + "description": "Scales the amount of damage for hollow", + "default_from_server_property": "pvp_dmg_mod_hollow", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModCb": { + "type": "float", + "description": "Scales the amount of damage for crippling blow", + "default_from_server_property": "pvp_dmg_mod_cb", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModAr": { + "type": "float", + "description": "Scales the amount of damage for armor rending", + "default_from_server_property": "pvp_dmg_mod_ar", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModCs": { + "type": "float", + "description": "Scales the amount of damage for critical strike", + "default_from_server_property": "pvp_dmg_mod_cs", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModFw": { + "type": "float", + "description": "Scales the amount of damage for Finesse Weapons", + "default_from_server_property": "pvp_dmg_mod_fw", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModFwCb": { + "type": "float", + "description": "Scales the amount of damage for FW CB.", + "default_from_server_property": "pvp_dmg_mod_fw_cb", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModFwCbCrit": { + "type": "float", + "description": "Scales the amount of damage for FW CB Crit.", + "default_from_server_property": "pvp_dmg_mod_fw_cb_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModFwCs": { + "type": "float", + "description": "Scales the amount of damage for FW CS.", + "default_from_server_property": "pvp_dmg_mod_fw_cs", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModFwAr": { + "type": "float", + "description": "Scales the amount of damage for FW AR.", + "default_from_server_property": "pvp_dmg_mod_fw_ar", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModFwHollow": { + "type": "float", + "description": "Scales the amount of damage for FW Hollow.", + "default_from_server_property": "pvp_dmg_mod_fw_hollow", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModFwPhantom": { + "type": "float", + "description": "Scales the amount of damage for war FW Phantom.", + "default_from_server_property": "pvp_dmg_mod_fw_phantom", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModLw": { + "type": "float", + "description": "Scales the amount of damage for Light Weapons", + "default_from_server_property": "pvp_dmg_mod_lw", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModLwCb": { + "type": "float", + "description": "Scales the amount of damage for LW CB.", + "default_from_server_property": "pvp_dmg_mod_lw_cb", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModLwCbCrit": { + "type": "float", + "description": "Scales the amount of damage for LW CB Crit.", + "default_from_server_property": "pvp_dmg_mod_lw_cb_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModLwCs": { + "type": "float", + "description": "Scales the amount of damage for LW CS.", + "default_from_server_property": "pvp_dmg_mod_lw_cs", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModLwAr": { + "type": "float", + "description": "Scales the amount of damage for LW AR.", + "default_from_server_property": "pvp_dmg_mod_lw_ar", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModLwHollow": { + "type": "float", + "description": "Scales the amount of damage for LW Hollow.", + "default_from_server_property": "pvp_dmg_mod_lw_hollow", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModLwPhantom": { + "type": "float", + "description": "Scales the amount of damage for LW Phantom.", + "default_from_server_property": "pvp_dmg_mod_lw_phantom", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModLwTriplestrike": { + "type": "float", + "description": "Scales the amount of damage for LW Triple Strike weapons.", + "default_from_server_property": "pvp_dmg_mod_lw_triplestrike", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModLwCbCritTriplestrike": { + "type": "float", + "description": "Scales the amount of Crit damage for LW Triple Strike weapons.", + "default_from_server_property": "pvp_dmg_mod_lw_cb_crit_triplestrike", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModHw": { + "type": "float", + "description": "Scales the amount of damage for Heavy Weapons", + "default_from_server_property": "pvp_dmg_mod_hw", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModHwCb": { + "type": "float", + "description": "Scales the amount of damage for HW CB.", + "default_from_server_property": "pvp_dmg_mod_hw_cb", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModHwCbCrit": { + "type": "float", + "description": "Scales the amount of damage for HW CB Crit.", + "default_from_server_property": "pvp_dmg_mod_hw_cb_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModHwCs": { + "type": "float", + "description": "Scales the amount of damage for HW CS.", + "default_from_server_property": "pvp_dmg_mod_hw_cs", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModHwAr": { + "type": "float", + "description": "Scales the amount of damage for HW AR.", + "default_from_server_property": "pvp_dmg_mod_hw_ar", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModHwHollow": { + "type": "float", + "description": "Scales the amount of damage for HW Hollow.", + "default_from_server_property": "pvp_dmg_mod_hw_hollow", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModHwPhantom": { + "type": "float", + "description": "Scales the amount of damage for HW Phantom.", + "default_from_server_property": "pvp_dmg_mod_hw_phantom", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModHwMultistrike": { + "type": "float", + "description": "Scales the amount of damage for HW Multi Strike weapons.", + "default_from_server_property": "pvp_dmg_mod_hw_multistrike", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModHwCbCritMultistrike": { + "type": "float", + "description": "Scales the amount of Crit damage for HW Multi Strike weapons.", + "default_from_server_property": "pvp_dmg_mod_hw_cb_crit_multistrike", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgMod2h": { + "type": "float", + "description": "Scales the amount of damage for Two Handed Weapons", + "default_from_server_property": "pvp_dmg_mod_2h", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgMod2hCb": { + "type": "float", + "description": "Scales the amount of damage for v CB.", + "default_from_server_property": "pvp_dmg_mod_2h_cb", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgMod2hCbCrit": { + "type": "float", + "description": "Scales the amount of damage for 2H CB Crit.", + "default_from_server_property": "pvp_dmg_mod_2h_cb_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgMod2hCs": { + "type": "float", + "description": "Scales the amount of damage for 2H CS.", + "default_from_server_property": "pvp_dmg_mod_2h_cs", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgMod2hAr": { + "type": "float", + "description": "Scales the amount of damage for 2H AR.", + "default_from_server_property": "pvp_dmg_mod_2h_ar", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgMod2hHollow": { + "type": "float", + "description": "Scales the amount of damage for 2H Hollow.", + "default_from_server_property": "pvp_dmg_mod_2h_hollow", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgMod2hPhantom": { + "type": "float", + "description": "Scales the amount of damage for 2H Phantom.", + "default_from_server_property": "pvp_dmg_mod_2h_phantom", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModXbow": { + "type": "float", + "description": "Scales the amount of damage for Xbow", + "default_from_server_property": "pvp_dmg_mod_xbow", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModXbowCb": { + "type": "float", + "description": "Scales the amount of damage for Xbow CB.", + "default_from_server_property": "pvp_dmg_mod_xbow_cb", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModXbowCbCrit": { + "type": "float", + "description": "Scales the amount of damage for Xbow CB Crit.", + "default_from_server_property": "pvp_dmg_mod_xbow_cb_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModXbowCs": { + "type": "float", + "description": "Scales the amount of damage for Xbow CS.", + "default_from_server_property": "pvp_dmg_mod_xbow_cs", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModXbowAr": { + "type": "float", + "description": "Scales the amount of damage for Xbow AR.", + "default_from_server_property": "pvp_dmg_mod_xbow_ar", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModXbowHollow": { + "type": "float", + "description": "Scales the amount of damage for Xbow Hollow.", + "default_from_server_property": "pvp_dmg_mod_xbow_hollow", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModXbowPhantom": { + "type": "float", + "description": "Scales the amount of damage for Xbow Phantom.", + "default_from_server_property": "pvp_dmg_mod_xbow_phantom", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModBow": { + "type": "float", + "description": "Scales the amount of damage for hollow", + "default_from_server_property": "pvp_dmg_mod_bow", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModBowCb": { + "type": "float", + "description": "Scales the amount of damage for Bow CB.", + "default_from_server_property": "pvp_dmg_mod_bow_cb", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModBowCbCrit": { + "type": "float", + "description": "Scales the amount of damage for Bow CB Crit.", + "default_from_server_property": "pvp_dmg_mod_bow_cb_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModBowCs": { + "type": "float", + "description": "Scales the amount of damage for Bow CS.", + "default_from_server_property": "pvp_dmg_mod_bow_cs", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModBowAr": { + "type": "float", + "description": "Scales the amount of damage for Bow AR.", + "default_from_server_property": "pvp_dmg_mod_bow_ar", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModBowHollow": { + "type": "float", + "description": "Scales the amount of damage for Bow Hollow.", + "default_from_server_property": "pvp_dmg_mod_bow_hollow", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModBowPhantom": { + "type": "float", + "description": "Scales the amount of damage for Bow Phantom.", + "default_from_server_property": "pvp_dmg_mod_bow_phantom", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModTw": { + "type": "float", + "description": "Scales the amount of damage for hollow", + "default_from_server_property": "pvp_dmg_mod_tw", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModTwCb": { + "type": "float", + "description": "Scales the amount of damage for TW CB.", + "default_from_server_property": "pvp_dmg_mod_tw_cb", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModTwCbCrit": { + "type": "float", + "description": "Scales the amount of damage for TW CB Crit.", + "default_from_server_property": "pvp_dmg_mod_tw_cb_crit", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModTwCs": { + "type": "float", + "description": "Scales the amount of damage for TW CS.", + "default_from_server_property": "pvp_dmg_mod_tw_cs", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModTwAr": { + "type": "float", + "description": "Scales the amount of damage for TW AR.", + "default_from_server_property": "pvp_dmg_mod_tw_ar", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModTwHollow": { + "type": "float", + "description": "Scales the amount of damage for TW Hollow.", + "default_from_server_property": "pvp_dmg_mod_tw_hollow", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModTwPhantom": { + "type": "float", + "description": "Scales the amount of damage for TW Phantom.", + "default_from_server_property": "pvp_dmg_mod_tw_phantom", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "CsCritrateMod": { + "type": "float", + "description": "Scales the crit rate for CS", + "default_from_server_property": "pvp_cs_critrate_mod", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "VoidHybridMod": { + "type": "float", + "description": "Scales the amount of DOT damage when a player is a hybrid void.", + "default_from_server_property": "pvp_void_hybrid_mod", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "DmgModVoidDotRatingReduction": { + "type": "float", + "description": "Scales the amount of rating reduction received from a void DOT that's cast by a PK on another player.", + "default_from_server_property": "pvp_dmg_mod_void_dot_rating_reduction", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "RatingsModDmg": { + "type": "float", + "description": "Scales the bonus received from dmg and dmg reduction ratings during pvp", + "default_from_server_property": "pvp_ratings_mod_dmg", + "default": 1, + "min_value": 0, + "max_value": 100 + }, + "RatingsModCritdmg": { + "type": "float", + "description": "Scales the bonus received from crit dmg and crit dmg reduction ratings during pvp", + "default_from_server_property": "pvp_ratings_mod_critdmg", + "default": 1, + "min_value": 0, + "max_value": 100 + } + } +} \ No newline at end of file diff --git a/Source/ACRealms.RealmProps/PropDefs/json/Pvp/World.jsonc b/Source/ACRealms.RealmProps/PropDefs/json/Pvp/World.jsonc index 0c18de70c8..9edf890995 100644 --- a/Source/ACRealms.RealmProps/PropDefs/json/Pvp/World.jsonc +++ b/Source/ACRealms.RealmProps/PropDefs/json/Pvp/World.jsonc @@ -2,14 +2,17 @@ "$schema_version": 1, "namespace": "Pvp.World", "description": "Properties related to world settings for PvP", - "groups": [ - { + "properties": { + "IsPkOnly": { "type": "boolean", - "default": false, - "properties": { - "IsPkOnly": "Standard 'Red server' rules. Players are always Player Killer status unless recently killed by a player killer", - "IsDuelingRealm": "Set this to true to designate this realm as the dueling realm. Allows /rebuff command, all summoned portals lead to ephemeral instances, and no vitae." - } + "description": "Standard 'Red server' rules. Players are always Player Killer status unless recently killed by a player killer", + "default_from_server_property": "pk_server", + "default": false + }, + "IsDuelingRealm": { + "type": "boolean", + "description": "Set this to true to designate this realm as the dueling realm. Allows /rebuff command, all summoned portals lead to ephemeral instances, and no vitae.", + "default": false } - ] -} \ No newline at end of file + } +}