diff --git a/Projects/UOContent/Engines/Player Murder System/PlayerMurderSystem.cs b/Projects/UOContent/Engines/Player Murder System/PlayerMurderSystem.cs index fd03f7f8a..b5a1b77d5 100644 --- a/Projects/UOContent/Engines/Player Murder System/PlayerMurderSystem.cs +++ b/Projects/UOContent/Engines/Player Murder System/PlayerMurderSystem.cs @@ -5,6 +5,7 @@ using System.Runtime.InteropServices; using ModernUO.CodeGeneratedEvents; using Server.Collections; using Server.Logging; +using Server.Misc; using Server.Mobiles; using Server.SkillHandlers; @@ -298,6 +299,8 @@ public class PlayerMurderSystem : GenericPersistence var wasMurderer = killer.Murderer; OnPlayerMurder(pk); + Titles.SetKarma(pk, pk.Kills * (Core.AOS ? -2000 : -1000), true); + pk.SendLocalizedMessage(1049067); // You have been reported for murder! if (!wasMurderer && killer.Murderer) diff --git a/Projects/UOContent/Engines/Player Murder System/ReportMurdererGump.cs b/Projects/UOContent/Engines/Player Murder System/ReportMurdererGump.cs index 6eeb7bcf8..2ef3e4073 100644 --- a/Projects/UOContent/Engines/Player Murder System/ReportMurdererGump.cs +++ b/Projects/UOContent/Engines/Player Murder System/ReportMurdererGump.cs @@ -60,28 +60,11 @@ public class ReportMurdererGump : StaticGump if (toGive?.Count > 0) { + var (fameAward, _) = Titles.ComputeKillAwards(m, m.Map); + foreach (var g in toGive) { - var n = Notoriety.Compute(g, m); - - var ourKarma = g.Karma; - var innocent = n == Notoriety.Innocent; - var criminal = n is Notoriety.Criminal or Notoriety.Murderer; - - var fameAward = m.Fame / 200; - var karmaAward = 0; - - if (innocent) - { - karmaAward = ourKarma > -2500 ? -850 : -110 - m.Karma / 100; - } - else if (criminal) - { - karmaAward = 50; - } - Titles.AwardFame(g, fameAward, false); - Titles.AwardKarma(g, karmaAward, true); } } diff --git a/Projects/UOContent/Items/Construction/Ankhs.cs b/Projects/UOContent/Items/Construction/Ankhs.cs index 985092f43..80105a16a 100644 --- a/Projects/UOContent/Items/Construction/Ankhs.cs +++ b/Projects/UOContent/Items/Construction/Ankhs.cs @@ -14,7 +14,7 @@ namespace Server.Items public static void GetContextMenuEntries(Mobile from, Item item, ref PooledRefList list) { - if (from is PlayerMobile mobile) + if (Core.UOTD && !Core.AOS && from is PlayerMobile mobile) { list.Add(new LockKarmaEntry(mobile.KarmaLocked)); } diff --git a/Projects/UOContent/Items/Misc/Corpses/Corpse.cs b/Projects/UOContent/Items/Misc/Corpses/Corpse.cs index 534f44b64..d186d7999 100644 --- a/Projects/UOContent/Items/Misc/Corpses/Corpse.cs +++ b/Projects/UOContent/Items/Misc/Corpses/Corpse.cs @@ -409,6 +409,11 @@ public partial class Corpse : Container, ICarvable if (IsCriminalAction(from)) { from.CriminalAction(true); + Titles.AwardKarma(from, -70, true); + } + else + { + Titles.AwardKarma(from, -20, true); } } else if (dead is BaseCreature creature) diff --git a/Projects/UOContent/Items/Skill Items/Misc/Bandage.cs b/Projects/UOContent/Items/Skill Items/Misc/Bandage.cs index 77a7997e2..bcf59d04d 100644 --- a/Projects/UOContent/Items/Skill Items/Misc/Bandage.cs +++ b/Projects/UOContent/Items/Skill Items/Misc/Bandage.cs @@ -4,6 +4,7 @@ using ModernUO.Serialization; using Server.Engines.ConPVP; using Server.Factions; using Server.Gumps; +using Server.Misc; using Server.Mobiles; using Server.Targeting; @@ -443,6 +444,11 @@ public class BandageContext : Timer Healer.CheckSkill(secondarySkill, 0.0, 120.0); Healer.CheckSkill(primarySkill, 0.0, 120.0); } + + if (Healer != Patient && Patient.Karma > 0) + { + Titles.AwardKarma(Healer, Patient.Karma / 5, true); + } } public static BandageContext BeginHeal(Mobile healer, Mobile patient) diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs b/Projects/UOContent/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs index 49950b13c..bf2b302e0 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs @@ -23,7 +23,7 @@ public partial class AnkhOfSacrificeComponent : AddonComponent { base.GetContextMenuEntries(from, ref list); - if (from is PlayerMobile mobile) + if (Core.UOTD && !Core.AOS && from is PlayerMobile mobile) { list.Add(new Ankhs.LockKarmaEntry(mobile.KarmaLocked)); } diff --git a/Projects/UOContent/Misc/Titles.cs b/Projects/UOContent/Misc/Titles.cs index 9595665b5..c5f9f2a18 100644 --- a/Projects/UOContent/Misc/Titles.cs +++ b/Projects/UOContent/Misc/Titles.cs @@ -116,6 +116,20 @@ namespace Server.Misc ) }; + public static (int Fame, int Karma) ComputeKillAwards(Mobile killed, Map map) + { + var totalFame = killed.Fame / 100; + var totalKarma = -killed.Karma / 100; + + if (Core.LBR && map == Map.Felucca) + { + totalFame += totalFame / 10 * 3; + totalKarma += totalKarma / 10 * 3; + } + + return (totalFame, totalKarma); + } + public static void AwardFame(Mobile m, int offset, bool message) { if (offset > 0) @@ -183,13 +197,29 @@ namespace Server.Misc } } + public static void SetKarma(Mobile m, int newKarma, bool message) + { + newKarma = Math.Clamp(newKarma, MinKarma, MaxKarma); + var offset = newKarma - m.Karma; + var wasPositiveKarma = m.Karma >= 0; + + m.Karma = newKarma; + + if (message) + { + SendKarmaMessage(m, offset); + } + + CheckKarmaLock(m, wasPositiveKarma); + } + public static void AwardKarma(Mobile m, int offset, bool message) { var pm = m as PlayerMobile; if (offset > 0) { - if (pm?.KarmaLocked == true) + if (Core.UOTD && !Core.AOS && pm?.KarmaLocked == true) { return; } @@ -224,41 +254,32 @@ namespace Server.Misc if (message) { - if (offset > 40) - { - m.SendLocalizedMessage(1019062); // You have gained a lot of karma. - } - else if (offset > 20) - { - m.SendLocalizedMessage(1019061); // You have gained a good amount of karma. - } - else if (offset > 10) - { - m.SendLocalizedMessage(1019060); // You have gained some karma. - } - else if (offset > 0) - { - m.SendLocalizedMessage(1019059); // You have gained a little karma. - } - else if (offset < -40) - { - m.SendLocalizedMessage(1019066); // You have lost a lot of karma. - } - else if (offset < -20) - { - m.SendLocalizedMessage(1019065); // You have lost a good amount of karma. - } - else if (offset < -10) - { - m.SendLocalizedMessage(1019064); // You have lost some karma. - } - else if (offset < 0) - { - m.SendLocalizedMessage(1019063); // You have lost a little karma. - } + SendKarmaMessage(m, offset); } - if (!Core.AOS && wasPositiveKarma && m.Karma < 0 && pm?.KarmaLocked == false) + CheckKarmaLock(m, wasPositiveKarma); + } + + private static void SendKarmaMessage(Mobile m, int offset) + { + var message = offset switch + { + > 40 => 1019062, // You have gained a lot of karma. + > 20 => 1019061, // You have gained a good amount of karma. + > 10 => 1019060, // You have gained some karma. + > 0 => 1019059, // You have gained a little karma. + < -40 => 1019066, // You have lost a lot of karma. + < -20 => 1019065, // You have lost a good amount of karma. + < -10 => 1019064, // You have lost some karma. + _ => 1019063, // You have lost a little karma. + }; + + m.SendLocalizedMessage(message); + } + + private static void CheckKarmaLock(Mobile m, bool wasPositiveKarma) + { + if (Core.UOTD && !Core.AOS && wasPositiveKarma && m.Karma < 0 && m is PlayerMobile { KarmaLocked: false } pm) { pm.KarmaLocked = true; // Karma is locked. A mantra spoken at a shrine will unlock it again. diff --git a/Projects/UOContent/Mobiles/BaseCreature.cs b/Projects/UOContent/Mobiles/BaseCreature.cs index be1733290..3fc9c0d8d 100644 --- a/Projects/UOContent/Mobiles/BaseCreature.cs +++ b/Projects/UOContent/Mobiles/BaseCreature.cs @@ -3286,14 +3286,7 @@ namespace Server.Mobiles if (!Summoned && !NoKillAwards) { - var totalFame = Fame / 100; - var totalKarma = -Karma / 100; - - if (Map == Map.Felucca) - { - totalFame += totalFame / 10 * 3; - totalKarma += totalKarma / 10 * 3; - } + var (totalFame, totalKarma) = Titles.ComputeKillAwards(this, Map); var list = GetLootingRights(DamageEntries, HitsMax); var titles = new List(); @@ -3313,9 +3306,19 @@ namespace Server.Mobiles continue; } - var party = Engines.PartySystem.Party.Get(ds.m_Mobile); + if (!Core.UOR) + { + var killer = LastKiller is BaseCreature bc ? bc.GetDamageMaster(this) : LastKiller; - if (party != null) + if (ds.m_Mobile == killer) + { + // If the titles system gets feature flagged, it will be supported + titles.Add(ds.m_Mobile); + fame.Add(totalFame); + karma.Add(totalKarma); + } + } + else if (Engines.PartySystem.Party.Get(ds.m_Mobile) is { } party) { var divedFame = totalFame / party.Members.Count; var divedKarma = totalKarma / party.Members.Count; diff --git a/Projects/UOContent/Mobiles/Guards/BaseGuard.cs b/Projects/UOContent/Mobiles/Guards/BaseGuard.cs index ad63338fd..1fe8c89ac 100644 --- a/Projects/UOContent/Mobiles/Guards/BaseGuard.cs +++ b/Projects/UOContent/Mobiles/Guards/BaseGuard.cs @@ -173,7 +173,7 @@ public abstract partial class BaseGuard : Mobile { PlayerMurderSystem.ClearBounty(target); Banker.Deposit(from, bounty); - Titles.AwardKarma(from, 2000, true); + Titles.AwardKarma(from, 20, true); Say(1042855, $"{target.Name}\t{bounty}"); // The bounty on ~1_PLAYER_NAME~ was ~2_AMOUNT~ gold, and has been credited to your account. } diff --git a/Projects/UOContent/Skills/Provocation.cs b/Projects/UOContent/Skills/Provocation.cs index 0cd329333..9215a7f61 100644 --- a/Projects/UOContent/Skills/Provocation.cs +++ b/Projects/UOContent/Skills/Provocation.cs @@ -1,5 +1,6 @@ using System; using Server.Items; +using Server.Misc; using Server.Mobiles; using Server.Targeting; @@ -51,6 +52,13 @@ namespace Server.SkillHandlers 1062488 ); // The instrument you are trying to play is no longer in your backpack! } + else if (Notoriety.Compute(from, creature) == Notoriety.Innocent) + { + // Think not that I fail to see what thou art doing! + creature.Say(501591); + + Titles.AwardKarma(from, -75, true); + } else if (creature.Controlled) { from.SendLocalizedMessage(501590); // They are too loyal to their master to be provoked. diff --git a/Projects/UOContent/Skills/Stealing.cs b/Projects/UOContent/Skills/Stealing.cs index 692376b8b..99c92a4c9 100644 --- a/Projects/UOContent/Skills/Stealing.cs +++ b/Projects/UOContent/Skills/Stealing.cs @@ -5,6 +5,7 @@ using Server.Engines.ConPVP; using Server.Engines.Stealables; using Server.Factions; using Server.Items; +using Server.Misc; using Server.Mobiles; using Server.Spells; using Server.Spells.Fifth; @@ -361,6 +362,8 @@ public static class Stealing _thief.SendLocalizedMessage(502710); // You can't steal that! } + Titles.AwardKarma(from, -50, true); + var mobRoot = root as Mobile; if (stolen != null) diff --git a/Projects/UOContent/Spells/Base/Spell.cs b/Projects/UOContent/Spells/Base/Spell.cs index 50927ae36..d3f666530 100644 --- a/Projects/UOContent/Spells/Base/Spell.cs +++ b/Projects/UOContent/Spells/Base/Spell.cs @@ -847,6 +847,12 @@ namespace Server.Spells if (Caster.CanBeBeneficial(target, true, allowDead) && CheckSequence()) { Caster.DoBeneficial(target); + + if (Caster != target) + { + Titles.AwardKarma(Caster, target.Karma / 5, true); + } + return true; } diff --git a/Projects/UOContent/Spells/Eighth/SummonDaemon.cs b/Projects/UOContent/Spells/Eighth/SummonDaemon.cs index 0edc0de83..022796a11 100644 --- a/Projects/UOContent/Spells/Eighth/SummonDaemon.cs +++ b/Projects/UOContent/Spells/Eighth/SummonDaemon.cs @@ -1,4 +1,5 @@ using System; +using Server.Misc; using Server.Mobiles; namespace Server.Spells.Eighth @@ -51,6 +52,8 @@ namespace Server.Spells.Eighth }; SpellHelper.Summon(new SummonedDaemon(), Caster, 0x216, duration, false, false); + + Titles.AwardKarma(Caster, -70, true); } FinishSequence();