diff --git a/Scripts/Items/Addons/ArcaneCircleAddon.cs b/Scripts/Items/Addons/ArcaneCircleAddon.cs index c76bcda3f..128c0e61f 100644 --- a/Scripts/Items/Addons/ArcaneCircleAddon.cs +++ b/Scripts/Items/Addons/ArcaneCircleAddon.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Server; namespace Server.Items @@ -29,7 +30,32 @@ namespace Server.Items { base.Serialize( writer ); - writer.WriteEncodedInt( 0 ); // version + writer.WriteEncodedInt( 1 ); // version + } + + private static List m_ToFix; + + public static void Configure() + { + m_ToFix = new List(); + } + + public static void Initialize() + { + foreach ( ArcaneCircleAddon ac in m_ToFix ) + { + foreach ( AddonComponent c in ac.Components ) + { + if ( c.ItemID == 0x3083 ) + { + c.Offset = new Point3D( -1, -1, 0 ); + c.MoveToWorld( new Point3D( ac.X + c.Offset.X, ac.Y + c.Offset.Y, ac.Z + c.Offset.Z ), ac.Map ); + } + } + } + + m_ToFix.Clear(); + m_ToFix = null; } public override void Deserialize( GenericReader reader ) @@ -37,6 +63,9 @@ namespace Server.Items base.Deserialize( reader ); int version = reader.ReadEncodedInt(); + + if ( version == 0 ) + m_ToFix.Add( this ); } } diff --git a/Scripts/Items/Misc/Corpses/Corpse.cs b/Scripts/Items/Misc/Corpses/Corpse.cs index cd8c19bb2..82024ef90 100644 --- a/Scripts/Items/Misc/Corpses/Corpse.cs +++ b/Scripts/Items/Misc/Corpses/Corpse.cs @@ -58,6 +58,11 @@ namespace Server.Items /// Has this corpse been animated? /// Animated = 0x00000040, + + /// + /// Has this corpse been self looted? + /// + SelfLooted = 0x00000080, } public class Corpse : Container, ICarvable @@ -67,7 +72,8 @@ namespace Server.Items private CorpseFlag m_Flags; // @see CorpseFlag private List m_Looters; // Who's looted this corpse? - private List m_EquipItems; // List of items equiped when the owner died. Ingame, these items display /on/ the corpse, not just inside + private List m_EquipItems; // List of dropped equipment when the owner died. Ingame, these items display /on/ the corpse, not just inside + private List m_RestoreEquip; // List of items equipped when the owner died. Includes insured and blessed items. private List m_Aggressors; // Anyone from this list will be able to loot this corpse; we attacked them, or they attacked us when we were freely attackable private string m_CorpseName; // Value of the CorpseNameAttribute attached to the owner when he died -or- null if the owner had no CorpseNameAttribute; use "the remains of ~name~" @@ -84,22 +90,22 @@ namespace Server.Items private FacialHairInfo m_FacialHair; // This contains the facial hair of the owner // For Forensics Evaluation - public string m_Forensicist; // Name of the first PlayerMobile who used Forensic Evaluation on the corpse + public string m_Forensicist; // Name of the first PlayerMobile who used Forensic Evaluation on the corpse public static readonly TimeSpan MonsterLootRightSacrifice = TimeSpan.FromMinutes( 2.0 ); public static readonly TimeSpan InstancedCorpseTime = TimeSpan.FromMinutes( 3.0 ); [CommandProperty( AccessLevel.GameMaster )] - public virtual bool InstancedCorpse - { - get + public virtual bool InstancedCorpse + { + get { if ( !Core.SE ) return false; return ( DateTime.Now < (m_TimeOfDeath + InstancedCorpseTime) ); - } + } } private Dictionary m_InstancedItems; @@ -304,6 +310,13 @@ namespace Server.Items set { SetFlag( CorpseFlag.Animated, value ); } } + [CommandProperty( AccessLevel.GameMaster )] + public bool SelfLooted + { + get { return GetFlag( CorpseFlag.SelfLooted ); } + set { SetFlag( CorpseFlag.SelfLooted, value ); } + } + [CommandProperty( AccessLevel.GameMaster )] public AccessLevel AccessLevel { @@ -331,6 +344,12 @@ namespace Server.Items get{ return m_EquipItems; } } + public List RestoreEquip + { + get { return m_RestoreEquip; } + set { m_RestoreEquip = value; } + } + public Guild Guild { get{ return m_Guild; } @@ -470,7 +489,16 @@ namespace Server.Items } if ( !owner.Player ) + { c.AssignInstancedLoot(); + } + else if ( Core.AOS ) + { + PlayerMobile pm = owner as PlayerMobile; + + if ( pm != null ) + c.RestoreEquip = pm.EquipSnapshot; + } } else { @@ -524,7 +552,6 @@ namespace Server.Items m_Hair = hair; m_FacialHair = facialhair; - // This corpse does not turn to bones if: the owner is not a player SetFlag( CorpseFlag.NoBones, !owner.Player ); @@ -607,7 +634,17 @@ namespace Server.Items { base.Serialize( writer ); - writer.Write( (int) 11 ); // version + writer.Write( (int) 12 ); // version + + if ( m_RestoreEquip == null ) + { + writer.Write( false ); + } + else + { + writer.Write( true ); + writer.Write( m_RestoreEquip ); + } writer.Write( (int)m_Flags ); @@ -666,43 +703,50 @@ namespace Server.Items switch ( version ) { + case 12: + { + if ( reader.ReadBool() ) + m_RestoreEquip = reader.ReadStrongItemList(); + + goto case 11; + } case 11: + { + // Version 11, we move all bools to a CorpseFlag + m_Flags = (CorpseFlag)reader.ReadInt(); + + m_TimeOfDeath = reader.ReadDeltaTime(); + + int count = reader.ReadInt(); + + for( int i = 0; i < count; ++i ) { - // Version 11, we move all bools to a CorpseFlag - m_Flags = (CorpseFlag)reader.ReadInt(); - - m_TimeOfDeath = reader.ReadDeltaTime(); - - int count = reader.ReadInt(); - - for( int i = 0; i < count; ++i ) - { - Item item = reader.ReadItem(); - - if( reader.ReadBool() ) - SetRestoreInfo( item, reader.ReadPoint3D() ); - else if( item != null ) - SetRestoreInfo( item, item.Location ); - } + Item item = reader.ReadItem(); if( reader.ReadBool() ) - BeginDecay( reader.ReadDeltaTime() - DateTime.Now ); - - m_Looters = reader.ReadStrongMobileList(); - m_Killer = reader.ReadMobile(); - - m_Aggressors = reader.ReadStrongMobileList(); - m_Owner = reader.ReadMobile(); - - m_CorpseName = reader.ReadString(); - - m_AccessLevel = (AccessLevel)reader.ReadInt(); - reader.ReadInt(); // guild reserve - m_Kills = reader.ReadInt(); - - m_EquipItems = reader.ReadStrongItemList(); - break; + SetRestoreInfo( item, reader.ReadPoint3D() ); + else if( item != null ) + SetRestoreInfo( item, item.Location ); } + + if( reader.ReadBool() ) + BeginDecay( reader.ReadDeltaTime() - DateTime.Now ); + + m_Looters = reader.ReadStrongMobileList(); + m_Killer = reader.ReadMobile(); + + m_Aggressors = reader.ReadStrongMobileList(); + m_Owner = reader.ReadMobile(); + + m_CorpseName = reader.ReadString(); + + m_AccessLevel = (AccessLevel)reader.ReadInt(); + reader.ReadInt(); // guild reserve + m_Kills = reader.ReadInt(); + + m_EquipItems = reader.ReadStrongItemList(); + break; + } case 10: { m_TimeOfDeath = reader.ReadDeltaTime(); @@ -986,58 +1030,53 @@ namespace Server.Items { if ( from.AccessLevel > AccessLevel.Player || from.InRange( this.GetWorldLocation(), 2 ) ) { - #region Self Looting - bool selfLoot = ( checkSelfLoot && ( from == m_Owner ) ); - - if ( selfLoot ) + if ( checkSelfLoot && from == m_Owner && !GetFlag( CorpseFlag.SelfLooted ) && this.Items.Count != 0 ) { - List items = new List( this.Items ); + DeathRobe robe = from.FindItemOnLayer( Layer.OuterTorso ) as DeathRobe; - bool gathered = false; - bool didntFit = false; + if ( robe != null ) + { + Map map = from.Map; + + if ( map != null && map != Map.Internal ) + robe.MoveToWorld( from.Location, map ); + } Container pack = from.Backpack; - bool checkRobe = true; + if ( m_RestoreEquip != null && pack != null ) + { + List packItems = new List( pack.Items ); // Only items in the top-level pack are re-equipped + + for ( int i = 0; i < packItems.Count; i++ ) + { + Item packItem = packItems[i]; + + if ( m_RestoreEquip.Contains( packItem ) && packItem.Movable ) + from.EquipItem( packItem ); + } + } + + List items = new List( this.Items ); + + bool didntFit = false; for ( int i = 0; !didntFit && i < items.Count; ++i ) { Item item = items[i]; Point3D loc = item.Location; - if ( (item.Layer == Layer.Hair || item.Layer == Layer.FacialHair) || !item.Movable || !GetRestoreInfo( item, ref loc ) ) + if ( ( item.Layer == Layer.Hair || item.Layer == Layer.FacialHair ) || !item.Movable || !GetRestoreInfo( item, ref loc ) ) continue; - if ( checkRobe ) - { - DeathRobe robe = from.FindItemOnLayer( Layer.OuterTorso ) as DeathRobe; - - if ( robe != null ) - { - if ( Core.SE ) - { - robe.Delete(); - } - else - { - Map map = from.Map; - - if ( map != null && map != Map.Internal ) - robe.MoveToWorld( from.Location, map ); - } - } - } - - if ( m_EquipItems.Contains( item ) && from.EquipItem( item ) ) - { - gathered = true; - } - else if ( pack != null && pack.CheckHold( from, item, false, true ) ) + if ( pack != null && pack.CheckHold( from, item, false, true ) ) { item.Location = loc; pack.AddItem( item ); - gathered = true; + + if ( m_RestoreEquip != null && m_RestoreEquip.Contains( item ) ) + from.EquipItem( item ); } else { @@ -1045,7 +1084,13 @@ namespace Server.Items } } - if ( gathered && !didntFit ) + from.PlaySound( 0x3E3 ); + + if ( this.Items.Count != 0 ) + { + from.SendLocalizedMessage( 1062472 ); // You gather some of your belongings. The rest remain on the corpse. + } + else { SetFlag( CorpseFlag.Carved, true ); @@ -1058,15 +1103,11 @@ namespace Server.Items ProcessDelta(); } - from.PlaySound( 0x3E3 ); from.SendLocalizedMessage( 1062471 ); // You quickly gather all of your belongings. - return; } - if ( gathered && didntFit ) - from.SendLocalizedMessage( 1062472 ); // You gather some of your belongings. The rest remain on the corpse. + SetFlag( CorpseFlag.SelfLooted, true ); } - #endregion if ( !CheckLoot( from, null ) ) diff --git a/Scripts/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs b/Scripts/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs index 52e81e80b..119f5a3c9 100644 --- a/Scripts/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs +++ b/Scripts/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs @@ -33,12 +33,18 @@ namespace Server.Items if ( !Utility.InRange( old, Location, 2 ) && Utility.InRange( m.Location, Location, 2 ) ) { if ( ItemID == 0x2A69 || ItemID == 0x2A6D ) - Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 0.5 ), 3, new TimerCallback( Up ) ); + { + Up(); + Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 0.5 ), 2, new TimerCallback( Up ) ); + } } else if ( Utility.InRange( old, Location, 2 ) && !Utility.InRange( m.Location, Location, 2 ) ) { if ( ItemID == 0x2A6C || ItemID == 0x2A70 ) - Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 0.5 ), 3, new TimerCallback( Down ) ); + { + Down(); + Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 0.5 ), 2, new TimerCallback( Down ) ); + } } } } @@ -57,7 +63,7 @@ namespace Server.Items { base.Serialize( writer ); - writer.WriteEncodedInt( 0 ); // version + writer.WriteEncodedInt( 1 ); // version } public override void Deserialize( GenericReader reader ) @@ -65,6 +71,9 @@ namespace Server.Items base.Deserialize( reader ); int version = reader.ReadEncodedInt(); + + if ( version == 0 && ItemID != 0x2A69 && ItemID != 0x2A6D ) + ItemID = 0x2A69; } } diff --git a/Scripts/Items/Talismans/BaseTalisman.cs b/Scripts/Items/Talismans/BaseTalisman.cs index dc8931b43..a2264e5a1 100644 --- a/Scripts/Items/Talismans/BaseTalisman.cs +++ b/Scripts/Items/Talismans/BaseTalisman.cs @@ -352,7 +352,7 @@ namespace Server.Items { BaseCreature mob = (BaseCreature)obj; - if ((m_Creature != null && m_Creature.Deleted) || from.Followers + mob.ControlSlots > from.FollowersMax) + if ((m_Creature != null && !m_Creature.Deleted) || from.Followers + mob.ControlSlots > from.FollowersMax) { from.SendLocalizedMessage(1074270); // You have too many followers to summon another one. mob.Delete(); diff --git a/Scripts/Items/Weapons/BaseWeapon.cs b/Scripts/Items/Weapons/BaseWeapon.cs index b60a4bc3f..d566160d0 100644 --- a/Scripts/Items/Weapons/BaseWeapon.cs +++ b/Scripts/Items/Weapons/BaseWeapon.cs @@ -1349,6 +1349,8 @@ namespace Server.Items public virtual void OnHit( Mobile attacker, Mobile defender, double damageBonus ) { + DoKeepScore( attacker, defender, false ); + if ( MirrorImage.HasClone( defender ) && (defender.Skills.Ninjitsu.Value / 150.0) > Utility.RandomDouble() ) { Clone bc; @@ -2060,6 +2062,35 @@ namespace Server.Items return totalRemaining - appliedDamage; } + public virtual void DoKeepScore( Mobile attacker, Mobile defender, bool hit ) + { + PlayerMobile player = ( ( attacker != null ) && !attacker.Deleted && ( attacker is PlayerMobile ) ) ? attacker as PlayerMobile : null; + + if( player != null ) + { + int hits = player.CombatHits; + int miss = player.CombatMiss; + + if( player.countThis != defender ) + { + player.countThis = defender; + + miss = hits = 0; + } + + switch( hit ) + { + case true: hits += 1; break; + case false: miss += 1; break; + } + + player.CombatHits = hits; + player.CombatMiss = miss; + + attacker.Say( string.Format( "hits:{0} miss{1} = {2} percent success", hits, miss, ( hits / ( hits + miss ) ) ) ); + } + } + public virtual void OnMiss( Mobile attacker, Mobile defender ) { PlaySwingAnimation( attacker ); @@ -2078,6 +2109,8 @@ namespace Server.Items if ( defender is IHonorTarget && ((IHonorTarget)defender).ReceivedHonorContext != null ) ((IHonorTarget)defender).ReceivedHonorContext.OnTargetMissed( attacker ); + + DoKeepScore( attacker, defender, false ); } public virtual void GetBaseDamageRange( Mobile attacker, out int min, out int max ) diff --git a/Scripts/Misc/LootPack.cs b/Scripts/Misc/LootPack.cs index b719b1646..59dde63b4 100644 --- a/Scripts/Misc/LootPack.cs +++ b/Scripts/Misc/LootPack.cs @@ -72,14 +72,14 @@ namespace Server { LootPackEntry entry = m_Entries[i]; - bool shouldAdd = ( entry.Chance > Utility.Random( 10000 ) ); + bool shouldAdd = true; // ( entry.Chance > Utility.Random( 10000 ) ); if ( !shouldAdd && checkLuck ) { checkLuck = false; - if ( LootPack.CheckLuck( luckChance ) ) - shouldAdd = ( entry.Chance > Utility.Random( 10000 ) ); + if( LootPack.CheckLuck( luckChance ) ) + shouldAdd = true; // ( entry.Chance > Utility.Random( 10000 ) ); } if ( !shouldAdd ) diff --git a/Scripts/Mobiles/Familiars/BaseFamiliar.cs b/Scripts/Mobiles/Familiars/BaseFamiliar.cs index 88ba57864..028944efc 100644 --- a/Scripts/Mobiles/Familiars/BaseFamiliar.cs +++ b/Scripts/Mobiles/Familiars/BaseFamiliar.cs @@ -123,8 +123,26 @@ namespace Server.Mobiles int version = reader.ReadInt(); - DropPackContents(); - Delete(); + m_ToRemove.Add( this ); + } + + private static List m_ToRemove; + + public static void Configure() + { + m_ToRemove = new List(); + } + + public static void Initialize() + { + foreach( BaseFamiliar f in m_ToRemove ) + { + f.DropPackContents(); + f.Delete(); + } + + m_ToRemove.Clear(); + m_ToRemove = null; } private class ReleaseEntry : ContextMenuEntry diff --git a/Scripts/Mobiles/PlayerMobile.cs b/Scripts/Mobiles/PlayerMobile.cs index e878b1e8f..4eef46444 100644 --- a/Scripts/Mobiles/PlayerMobile.cs +++ b/Scripts/Mobiles/PlayerMobile.cs @@ -91,6 +91,15 @@ namespace Server.Mobiles } } + + public virtual Mobile countThis { get { return m_countThis; } set { m_countThis = value; } } + public virtual int CombatMiss { get { return m_CombatMiss; } set { m_CombatMiss = value; } } + public virtual int CombatHits { get { return m_CombatHits; } set { m_CombatHits = value; } } + + private int m_CombatMiss; + private int m_CombatHits; + private Mobile m_countThis; + private DesignContext m_DesignContext; private NpcGuild m_NpcGuild; @@ -2094,9 +2103,16 @@ namespace Server.Mobiles private int m_InsuranceCost; private int m_InsuranceBonus; + private List m_EquipSnapshot; + + public List EquipSnapshot + { + get { return m_EquipSnapshot; } + } + private bool FindItems_Callback(Item item) { - if (!item.Deleted && (item.LootType == LootType.Blessed || item.Insured == true)) + if (!item.Deleted && (item.LootType == LootType.Blessed || item.Insured)) { if (this.Backpack != item.ParentEntity) { @@ -2125,6 +2141,8 @@ namespace Server.Mobiles } } + m_EquipSnapshot = new List( this.Items ); + m_NonAutoreinsuredItems = 0; m_InsuranceCost = 0; m_InsuranceAward = base.FindMostRecentDamager( false ); @@ -2231,6 +2249,8 @@ namespace Server.Mobiles base.OnDeath(c); + m_EquipSnapshot = null; + HueMod = -1; NameMod = null; SavagePaintExpiration = TimeSpan.Zero;