fix: player corpse notoriety ignores the owner's body at death (#2669)
CorpseNotoriety returned Murderer for a player corpse whenever the corpse body was a monster body. RunUO's check was `body.IsMonster && IsSummoned(owner)`, which is never true for a player; the second half was lost when the branch was simplified (#134). Players who died while polymorphed or in a necromancer form left a corpse with the wrong notoriety. Player corpses also check murderer and criminal status before guild standing again, matching RunUO and MobileNotoriety. Tests: UOContent.Tests 1162 passed (4 new CorpseNotorietyTests).
This commit is contained in:
parent
08dab47413
commit
92ed9c5456
2 changed files with 60 additions and 16 deletions
40
Projects/UOContent.Tests/Tests/Misc/CorpseNotorietyTests.cs
Normal file
40
Projects/UOContent.Tests/Tests/Misc/CorpseNotorietyTests.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using Server;
|
||||
using Server.Items;
|
||||
using Server.Misc;
|
||||
using Server.Mobiles;
|
||||
using Xunit;
|
||||
|
||||
namespace UOContent.Tests;
|
||||
|
||||
[Collection("Sequential UOContent Tests")]
|
||||
public class CorpseNotorietyTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, Notoriety.Innocent)] // Human body
|
||||
[InlineData(746, Notoriety.Innocent)] // Horrific Beast, a monster body
|
||||
[InlineData(0, Notoriety.Murderer, 5)]
|
||||
[InlineData(746, Notoriety.Murderer, 5)]
|
||||
public void PlayerCorpseNotorietyIgnoresTransformedBody(int bodyMod, int expected, int kills = 0)
|
||||
{
|
||||
var victim = new PlayerMobile(World.NewMobile);
|
||||
victim.DefaultMobileInit();
|
||||
victim.Kills = kills;
|
||||
victim.BodyMod = bodyMod;
|
||||
|
||||
var looter = new PlayerMobile(World.NewMobile);
|
||||
looter.DefaultMobileInit();
|
||||
|
||||
var corpse = new Corpse(victim, []);
|
||||
|
||||
try
|
||||
{
|
||||
Assert.Equal(expected, NotorietyHandlers.CorpseNotoriety(looter, corpse));
|
||||
}
|
||||
finally
|
||||
{
|
||||
corpse.Delete();
|
||||
victim.Delete();
|
||||
looter.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -270,7 +270,24 @@ namespace Server.Misc
|
|||
return Notoriety.CanBeAttacked;
|
||||
}
|
||||
|
||||
Body body = target.Amount;
|
||||
// BaseCreatures are deleted on death, so target.Owner is null after a server restart.
|
||||
// The OwnerWasBaseCreature flag is the persisted snapshot that survives the live mobile.
|
||||
var creature = target.Owner as BaseCreature;
|
||||
var ownerWasCreature = target.OwnerWasBaseCreature || creature != null;
|
||||
|
||||
// A player's murderer and criminal status outrank guild standing, as on the live mobile.
|
||||
if (!ownerWasCreature)
|
||||
{
|
||||
if (target.Murderer)
|
||||
{
|
||||
return Notoriety.Murderer;
|
||||
}
|
||||
|
||||
if (target.Criminal && (target.Map?.Rules & MapRules.HarmfulRestrictions) == 0)
|
||||
{
|
||||
return Notoriety.Criminal;
|
||||
}
|
||||
}
|
||||
|
||||
var sourceGuild = GetGuildFor(source.Guild as Guild, source);
|
||||
var targetGuild = GetGuildFor(target.Guild, target.Owner);
|
||||
|
|
@ -292,11 +309,7 @@ namespace Server.Misc
|
|||
}
|
||||
}
|
||||
|
||||
// BaseCreatures are deleted on death, so target.Owner is null after a server restart.
|
||||
// The OwnerWasBaseCreature flag is the persisted snapshot that survives the live mobile.
|
||||
var creature = target.Owner as BaseCreature;
|
||||
|
||||
if (target.OwnerWasBaseCreature || creature != null)
|
||||
if (ownerWasCreature)
|
||||
{
|
||||
if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet)
|
||||
{
|
||||
|
|
@ -309,6 +322,7 @@ namespace Server.Misc
|
|||
}
|
||||
|
||||
var actual = Notoriety.CanBeAttacked;
|
||||
Body body = target.Amount;
|
||||
|
||||
if (target.Murderer || body.IsMonster && target.OwnerWasSummoned || target.OwnerWasAnimatedDead)
|
||||
{
|
||||
|
|
@ -333,16 +347,6 @@ namespace Server.Misc
|
|||
return Notoriety.Innocent;
|
||||
}
|
||||
|
||||
if (target.Murderer || body.IsMonster)
|
||||
{
|
||||
return Notoriety.Murderer;
|
||||
}
|
||||
|
||||
if (target.Criminal && (target.Map?.Rules & MapRules.HarmfulRestrictions) == 0)
|
||||
{
|
||||
return Notoriety.Criminal;
|
||||
}
|
||||
|
||||
if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet)
|
||||
{
|
||||
for (var i = 0; i < list.Count; ++i)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue