" + sign.House.Owner.RawName);
+ AddButton(width - 30, y + 3, 0x2716, "House Menu", new GumpStateCallback(HouseMenu), sign.House);
+ }
+ }
+ else
+ {
+ house = (BaseHouse)list[i];
+
+ AddHtml(30, y += 20, width / 2 - 20, "
" + house.Name);
+ AddButton(15, y + 3, 0x2716, "Goto", new GumpStateCallback(Goto), house);
+
+ if (house.Owner != null)
+ {
+ AddHtml(width / 2, y, width / 2 - 40, "
" + house.Owner.RawName);
+ AddButton(width - 30, y + 3, 0x2716, "House Menu", new GumpStateCallback(HouseMenu), house);
+ }
+ }
+ }
+
+ if (pp * (c_Page + 1) < list.Count)
+ AddButton(width / 2 - 10, y += 25, 0x25E8, 0x25E9, "Page Up", new GumpCallback(PageUp));
+
+ if (c_ListPage == ListPage.Town)
+ {
+ AddHtml(0, y += 35, width, "
Add New TownHouse");
+ AddButton(width / 2 - 80, y + 3, 0x2716, "New", new GumpCallback(New));
+ AddButton(width / 2 + 70, y + 3, 0x2716, "New", new GumpCallback(New));
+ }
+
+ AddBackgroundZero(0, 0, width, y + 40, 3600);
+ }
+
+ private void TownHouseMenu(object obj)
+ {
+ if (!(obj is TownHouseSign))
+ return;
+
+ NewGump();
+
+ new TownHouseSetupGump(Owner, (TownHouseSign)obj);
+ }
+
+ private void Page(object obj)
+ {
+ c_ListPage = (ListPage)obj;
+ NewGump();
+ }
+
+ private void Goto(object obj)
+ {
+ if (!(obj is BaseHouse))
+ return;
+
+ Owner.Location = ((BaseHouse)obj).BanLocation;
+ Owner.Map = ((BaseHouse)obj).Map;
+
+ NewGump();
+ }
+
+ private void HouseMenu(object obj)
+ {
+ if (!(obj is BaseHouse))
+ return;
+
+ NewGump();
+
+ Owner.SendGump(new HouseGumpAOS((HouseGumpPageAOS)0, Owner, (BaseHouse)obj));
+ }
+
+ private void New()
+ {
+ TownHouseSign sign = new TownHouseSign();
+ Owner.AddToBackpack(sign);
+ Owner.SendMessage("A new sign is now in your backpack. It will move on it's own during setup, but if you don't complete setup you may want to delete it.");
+
+ NewGump();
+
+ new TownHouseSetupGump(Owner, sign);
+ }
+
+ private void PageUp()
+ {
+ c_Page++;
+ NewGump();
+ }
+
+ private void PageDown()
+ {
+ c_Page--;
+ NewGump();
+ }
+
+ private class InternalSort : IComparer
+ {
+ public InternalSort()
+ {
+ }
+
+ public int Compare(object x, object y)
+ {
+ if (x == null && y == null)
+ return 0;
+
+ if (x is TownHouseSign)
+ {
+ TownHouseSign a = (TownHouseSign)x;
+ TownHouseSign b = (TownHouseSign)y;
+
+ return Insensitive.Compare(a.Name, b.Name);
+ }
+ else
+ {
+ BaseHouse a = (BaseHouse)x;
+ BaseHouse b = (BaseHouse)y;
+
+ if (a.Owner == null && b.Owner != null)
+ return -1;
+ if (a.Owner != null && b.Owner == null)
+ return 1;
+
+ return Insensitive.Compare(a.Owner.RawName, b.Owner.RawName);
+ }
+ }
+ }
+ }
+}
diff --git a/Scripts/Items/Houses/Monopoly/Items/RentalContract.cs b/Scripts/Items/Houses/Monopoly/Items/RentalContract.cs
new file mode 100644
index 0000000..0ee7c42
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/Items/RentalContract.cs
@@ -0,0 +1,318 @@
+using System;
+using System.Collections;
+using Server;
+using Server.Multis;
+using Server.Items;
+
+namespace Knives.TownHouses
+{
+ public class RentalContract : TownHouseSign
+ {
+ private Mobile c_RentalMaster;
+ private Mobile c_RentalClient;
+ private BaseHouse c_ParentHouse;
+ private bool c_Completed, c_EntireHouse;
+
+ public BaseHouse ParentHouse{ get{ return c_ParentHouse; } }
+ public Mobile RentalClient{ get{ return c_RentalClient; } set{ c_RentalClient = value; InvalidateProperties(); } }
+ public Mobile RentalMaster{ get{ return c_RentalMaster; } }
+ public bool Completed{ get{ return c_Completed; } set{ c_Completed = value; } }
+ public bool EntireHouse{ get{ return c_EntireHouse; } set{ c_EntireHouse = value; } }
+
+ public RentalContract() : base()
+ {
+ ItemID = 0x14F0;
+ Movable = true;
+ RentByTime = TimeSpan.FromDays( 1 );
+ RecurRent = true;
+ MaxZ = MinZ;
+ }
+
+ public bool HasContractedArea( Rectangle2D rect, int z )
+ {
+ foreach( Item item in TownHouseSign.AllSigns )
+ if ( item is RentalContract && item != this && item.Map == Map && c_ParentHouse == ((RentalContract)item).ParentHouse )
+ foreach( Rectangle2D rect2 in ((RentalContract)item).Blocks )
+ for( int x = rect.Start.X; x < rect.End.X; ++x )
+ for( int y = rect.Start.Y; y < rect.End.Y; ++y )
+ if ( rect2.Contains( new Point2D( x, y ) ) )
+ if ( ((RentalContract)item).MinZ <= z && ((RentalContract)item).MaxZ >= z )
+ return true;
+
+ return false;
+ }
+
+ public bool HasContractedArea( int z )
+ {
+ foreach( Item item in TownHouseSign.AllSigns )
+ if ( item is RentalContract && item != this && item.Map == Map && c_ParentHouse == ((RentalContract)item).ParentHouse )
+ if ( ((RentalContract)item).MinZ <= z && ((RentalContract)item).MaxZ >= z )
+ return true;
+
+ return false;
+ }
+
+ public void DepositTo( Mobile m )
+ {
+ if ( m == null )
+ return;
+
+ if ( Free )
+ {
+ m.SendMessage( "Since this home is free, you do not receive the deposit." );
+ return;
+ }
+
+ m.BankBox.DropItem( new Gold( Price ) );
+ m.SendMessage( "You have received a {0} gold deposit from your town house.", Price );
+ }
+
+ public override void ValidateOwnership()
+ {
+ if ( c_Completed && c_RentalMaster == null )
+ {
+ Delete();
+ return;
+ }
+
+ if ( c_RentalClient != null && ( c_ParentHouse == null || c_ParentHouse.Deleted ) )
+ {
+ Delete();
+ return;
+ }
+
+ if ( c_RentalClient != null && !Owned )
+ {
+ Delete();
+ return;
+ }
+
+ if ( ParentHouse == null )
+ return;
+
+ if ( !ValidateLocSec() )
+ {
+ if ( DemolishTimer == null )
+ BeginDemolishTimer( TimeSpan.FromHours( 48 ) );
+ }
+ else
+ ClearDemolishTimer();
+ }
+
+ protected override void DemolishAlert()
+ {
+ if ( ParentHouse == null || c_RentalMaster == null || c_RentalClient == null )
+ return;
+
+ c_RentalMaster.SendMessage( "You have begun to use lockdowns reserved for {0}, and their rental unit will collapse in {1}.", c_RentalClient.Name, Math.Round( (DemolishTime-DateTime.Now).TotalHours, 2 ) );
+ c_RentalClient.SendMessage( "Alert your land lord, {0}, they are using storage reserved for you. They have violated the rental agreement, which will end in {1} if nothing is done.", c_RentalMaster.Name, Math.Round( (DemolishTime-DateTime.Now).TotalHours, 2 ) );
+ }
+
+ public void FixLocSec()
+ {
+ int count = 0;
+
+ if ( (count = General.RemainingSecures( c_ParentHouse )+Secures) < Secures )
+ Secures = count;
+
+ if ( (count = General.RemainingLocks( c_ParentHouse )+Locks) < Locks )
+ Locks = count;
+ }
+
+ public bool ValidateLocSec()
+ {
+ if ( General.RemainingSecures( c_ParentHouse )+Secures < Secures )
+ return false;
+
+ if ( General.RemainingLocks( c_ParentHouse )+Locks < Locks )
+ return false;
+
+ return true;
+ }
+
+ public override void ConvertItems( bool keep )
+ {
+ if ( House == null || c_ParentHouse == null || c_RentalMaster == null )
+ return;
+
+ foreach( BaseDoor door in new ArrayList( c_ParentHouse.Doors ) )
+ if ( door.Map == House.Map && House.Region.Contains( door.Location ) )
+ ConvertDoor( door );
+
+ foreach( SecureInfo info in new ArrayList( c_ParentHouse.Secures ) )
+ if ( info.Item.Map == House.Map && House.Region.Contains( info.Item.Location ) )
+ c_ParentHouse.Release( c_RentalMaster, info.Item );
+
+ foreach( Item item in new ArrayList( c_ParentHouse.LockDowns ) )
+ if ( item.Map == House.Map && House.Region.Contains( item.Location ) )
+ c_ParentHouse.Release( c_RentalMaster, item );
+ }
+
+ public override void UnconvertDoors( )
+ {
+ if ( House == null || c_ParentHouse == null )
+ return;
+
+ foreach( BaseDoor door in new ArrayList( House.Doors ) )
+ House.Doors.Remove( door );
+ }
+
+ protected override void OnRentPaid()
+ {
+ if ( c_RentalMaster == null || c_RentalClient == null )
+ return;
+
+ if ( Free )
+ return;
+
+ c_RentalMaster.BankBox.DropItem( new Gold( Price ) );
+ c_RentalMaster.SendMessage( "The bank has transfered your rent from {0}.", c_RentalClient.Name );
+ }
+
+ public override void ClearHouse()
+ {
+ if ( !Deleted )
+ Delete();
+
+ base.ClearHouse();
+ }
+
+ public override void OnDoubleClick( Mobile m )
+ {
+ ValidateOwnership();
+
+ if ( Deleted )
+ return;
+
+ if ( c_RentalMaster == null )
+ c_RentalMaster = m;
+
+ BaseHouse house = BaseHouse.FindHouseAt( m );
+
+ if ( c_ParentHouse == null )
+ c_ParentHouse = house;
+
+ if ( house == null || ( house != c_ParentHouse && house != House ) )
+ {
+ m.SendMessage( "You must be in the home to view this contract." );
+ return;
+ }
+
+ if ( m == c_RentalMaster
+ && !c_Completed
+ && house is TownHouse
+ && ((TownHouse)house).ForSaleSign.PriceType != "Sale" )
+ {
+ c_ParentHouse = null;
+ m.SendMessage( "You can only rent property you own." );
+ return;
+ }
+
+ if ( m == c_RentalMaster && !c_Completed && General.EntireHouseContracted( c_ParentHouse ) )
+ {
+ m.SendMessage( "This entire house already has a rental contract." );
+ return;
+ }
+
+ if ( c_Completed )
+ new ContractConfirmGump( m, this );
+ else if ( m == c_RentalMaster )
+ new ContractSetupGump( m, this );
+ else
+ m.SendMessage( "This rental contract has not yet been completed." );
+ }
+
+ public override void GetProperties( ObjectPropertyList list )
+ {
+ if ( c_RentalClient != null )
+ list.Add( "a house rental contract with " + c_RentalClient.Name );
+ else if ( c_Completed )
+ list.Add( "a completed house rental contract" );
+ else
+ list.Add( "an uncompleted house rental contract" );
+ }
+
+ public override void Delete()
+ {
+ if ( c_ParentHouse == null )
+ {
+ base.Delete();
+ return;
+ }
+
+ if ( !Owned && !c_ParentHouse.IsFriend( c_RentalClient ) )
+ {
+ if ( c_RentalClient != null && c_RentalMaster != null )
+ {
+ c_RentalMaster.SendMessage( "{0} has ended your rental agreement. Because you revoked their access, their last payment will be refunded.", c_RentalMaster.Name );
+ c_RentalClient.SendMessage( "You have ended your rental agreement with {0}. Because your access was revoked, your last payment is refunded.", c_RentalClient.Name );
+ }
+
+ DepositTo( c_RentalClient );
+ }
+ else if ( Owned )
+ {
+ if ( c_RentalClient != null && c_RentalMaster != null )
+ {
+ c_RentalClient.SendMessage( "{0} has ended your rental agreement. Since they broke the contract, your are refunded the last payment.", c_RentalMaster.Name );
+ c_RentalMaster.SendMessage( "You have ended your rental agreement with {0}. They will be refunded their last payment.", c_RentalClient.Name );
+ }
+
+ DepositTo( c_RentalClient );
+
+ /* Fixed for Rental Loop bug */
+ //PackUpHouse();
+ DeleteTest();
+ }
+ else
+ {
+ if ( c_RentalClient != null && c_RentalMaster != null )
+ {
+ c_RentalMaster.SendMessage( "{0} has ended your rental agreement.", c_RentalClient.Name );
+ c_RentalClient.SendMessage( "You have ended your rental agreement with {0}.", c_RentalMaster.Name );
+ }
+
+ DepositTo( c_RentalMaster );
+ }
+
+ ClearRentTimer();
+ base.Delete();
+ }
+
+ public RentalContract( Serial serial ) : base( serial )
+ {
+ RecurRent = true;
+ }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( (int) 1 ); // version
+
+ // Version 1
+
+ writer.Write( c_EntireHouse );
+
+ writer.Write( c_RentalMaster );
+ writer.Write( c_RentalClient );
+ writer.Write( c_ParentHouse );
+ writer.Write( c_Completed );
+ }
+
+ public override void Deserialize( GenericReader reader )
+ {
+ base.Deserialize( reader );
+
+ int version = reader.ReadInt();
+
+ if ( version >= 1 )
+ c_EntireHouse = reader.ReadBool();
+
+ c_RentalMaster = reader.ReadMobile();
+ c_RentalClient = reader.ReadMobile();
+ c_ParentHouse = reader.ReadItem() as BaseHouse;
+ c_Completed = reader.ReadBool();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Items/Houses/Monopoly/Items/RentalContractCopy.cs b/Scripts/Items/Houses/Monopoly/Items/RentalContractCopy.cs
new file mode 100644
index 0000000..f8dccb4
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/Items/RentalContractCopy.cs
@@ -0,0 +1,47 @@
+using System;
+using Server;
+using Server.Items;
+
+namespace Knives.TownHouses
+{
+ public class RentalContractCopy : Item
+ {
+ private RentalContract c_Contract;
+
+ public RentalContractCopy( RentalContract contract )
+ {
+ Name = "rental contract copy";
+ ItemID = 0x14F0;
+ c_Contract = contract;
+ }
+
+ public override void OnDoubleClick( Mobile m )
+ {
+ if ( c_Contract == null || c_Contract.Deleted )
+ {
+ Delete();
+ return;
+ }
+
+ c_Contract.OnDoubleClick( m );
+ }
+
+ public RentalContractCopy( Serial serial ) : base( serial )
+ {
+ }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( (int) 1 ); // version
+ }
+
+ public override void Deserialize( GenericReader reader )
+ {
+ base.Deserialize( reader );
+
+ int version = reader.ReadInt();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Items/Houses/Monopoly/Items/RentalLicense.cs b/Scripts/Items/Houses/Monopoly/Items/RentalLicense.cs
new file mode 100644
index 0000000..ede2fa7
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/Items/RentalLicense.cs
@@ -0,0 +1,53 @@
+using System;
+using Server;
+using Server.Items;
+
+namespace Knives.TownHouses
+{
+ public class RentalLicense : Item
+ {
+ private Mobile c_Owner;
+
+ public Mobile Owner{ get{ return c_Owner; } set{ c_Owner = value; InvalidateProperties(); } }
+
+ public RentalLicense() : base( 0x14F0 )
+ {
+ }
+
+ public override void GetProperties( ObjectPropertyList list )
+ {
+ if ( c_Owner != null )
+ list.Add( "a renter's license belonging to " + c_Owner.Name );
+ else
+ list.Add( "a renter's license" );
+ }
+
+ public override void OnDoubleClick( Mobile m )
+ {
+ if ( c_Owner == null )
+ c_Owner = m;
+ }
+
+ public RentalLicense( Serial serial ) : base( serial )
+ {
+ }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( (int) 0 ); // version
+
+ writer.Write( c_Owner );
+ }
+
+ public override void Deserialize( GenericReader reader )
+ {
+ base.Deserialize( reader );
+
+ int version = reader.ReadInt();
+
+ c_Owner = reader.ReadMobile();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Items/Houses/Monopoly/Items/SignHammer.cs b/Scripts/Items/Houses/Monopoly/Items/SignHammer.cs
new file mode 100644
index 0000000..dc1b053
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/Items/SignHammer.cs
@@ -0,0 +1,299 @@
+using System;
+using System.Collections;
+using Server;
+using Server.Items;
+using Server.Multis;
+using Server.Targeting;
+
+namespace Knives.TownHouses
+{
+ public enum HammerJob{ Flip, Swap }
+
+ public class SignHammer : Item
+ {
+ private static Hashtable s_Table = new Hashtable();
+ private static ArrayList s_List = new ArrayList();
+
+ public static void Initialize()
+ {
+ // Signs
+ s_Table[0xB95] = 0xB96;
+ s_Table[0xB96] = 0xB95;
+ s_Table[0xBA3] = 0xBA4;
+ s_Table[0xBA4] = 0xBA3;
+ s_Table[0xBA5] = 0xBA6;
+ s_Table[0xBA6] = 0xBA5;
+ s_Table[0xBA7] = 0xBA8;
+ s_Table[0xBA8] = 0xBA7;
+ s_Table[0xBA9] = 0xBAA;
+ s_Table[0xBAA] = 0xBA9;
+ s_Table[0xBAB] = 0xBAC;
+ s_Table[0xBAC] = 0xBAB;
+ s_Table[0xBAD] = 0xBAE;
+ s_Table[0xBAE] = 0xBAD;
+ s_Table[0xBAF] = 0xBB0;
+ s_Table[0xBB0] = 0xBAF;
+ s_Table[0xBB1] = 0xBB2;
+ s_Table[0xBB2] = 0xBB1;
+ s_Table[0xBB3] = 0xBB4;
+ s_Table[0xBB4] = 0xBB3;
+ s_Table[0xBB5] = 0xBB6;
+ s_Table[0xBB6] = 0xBB5;
+ s_Table[0xBB7] = 0xBB8;
+ s_Table[0xBB8] = 0xBB7;
+ s_Table[0xBB9] = 0xBBA;
+ s_Table[0xBBA] = 0xBB9;
+ s_Table[0xBBB] = 0xBBC;
+ s_Table[0xBBC] = 0xBBB;
+ s_Table[0xBBD] = 0xBBE;
+ s_Table[0xBBE] = 0xBBD;
+ s_Table[0xBBF] = 0xBC0;
+ s_Table[0xBC0] = 0xBBF;
+ s_Table[0xBC1] = 0xBC2;
+ s_Table[0xBC2] = 0xBC1;
+ s_Table[0xBC3] = 0xBC4;
+ s_Table[0xBC4] = 0xBC3;
+ s_Table[0xBC5] = 0xBC6;
+ s_Table[0xBC6] = 0xBC5;
+ s_Table[0xBC7] = 0xBC8;
+ s_Table[0xBC8] = 0xBC7;
+ s_Table[0xBC9] = 0xBCA;
+ s_Table[0xBCA] = 0xBC9;
+ s_Table[0xBCB] = 0xBCC;
+ s_Table[0xBCC] = 0xBCB;
+ s_Table[0xBCD] = 0xBCE;
+ s_Table[0xBCE] = 0xBCD;
+ s_Table[0xBCF] = 0xBD0;
+ s_Table[0xBD0] = 0xBCF;
+ s_Table[0xBD1] = 0xBD2;
+ s_Table[0xBD2] = 0xBD1;
+ s_Table[0xBD3] = 0xBD4;
+ s_Table[0xBD4] = 0xBD3;
+ s_Table[0xBD5] = 0xBD6;
+ s_Table[0xBD6] = 0xBD5;
+ s_Table[0xBD7] = 0xBD8;
+ s_Table[0xBD8] = 0xBD7;
+ s_Table[0xBD9] = 0xBDA;
+ s_Table[0xBDA] = 0xBD9;
+ s_Table[0xBDB] = 0xBDC;
+ s_Table[0xBDC] = 0xBDB;
+ s_Table[0xBDD] = 0xBDE;
+ s_Table[0xBDE] = 0xBDD;
+ s_Table[0xBDF] = 0xBE0;
+ s_Table[0xBE0] = 0xBDF;
+ s_Table[0xBE1] = 0xBE2;
+ s_Table[0xBE2] = 0xBE1;
+ s_Table[0xBE3] = 0xBE4;
+ s_Table[0xBE4] = 0xBE3;
+ s_Table[0xBE5] = 0xBE6;
+ s_Table[0xBE6] = 0xBE5;
+ s_Table[0xBE7] = 0xBE8;
+ s_Table[0xBE8] = 0xBE7;
+ s_Table[0xBE9] = 0xBEA;
+ s_Table[0xBEA] = 0xBE9;
+ s_Table[0xBEB] = 0xBEC;
+ s_Table[0xBEC] = 0xBEB;
+ s_Table[0xBED] = 0xBEE;
+ s_Table[0xBEE] = 0xBED;
+ s_Table[0xBEF] = 0xBF0;
+ s_Table[0xBF0] = 0xBEF;
+ s_Table[0xBF1] = 0xBF2;
+ s_Table[0xBF2] = 0xBF1;
+ s_Table[0xBF3] = 0xBF4;
+ s_Table[0xBF4] = 0xBF3;
+ s_Table[0xBF5] = 0xBF6;
+ s_Table[0xBF6] = 0xBF5;
+ s_Table[0xBF7] = 0xBF8;
+ s_Table[0xBF8] = 0xBF7;
+ s_Table[0xBF9] = 0xBFA;
+ s_Table[0xBFA] = 0xBF9;
+ s_Table[0xBFB] = 0xBFC;
+ s_Table[0xBFC] = 0xBFB;
+ s_Table[0xBFD] = 0xBFE;
+ s_Table[0xBFE] = 0xBFD;
+ s_Table[0xBFF] = 0xC00;
+ s_Table[0xC00] = 0xBFF;
+ s_Table[0xC01] = 0xC02;
+ s_Table[0xC02] = 0xC01;
+ s_Table[0xC03] = 0xC04;
+ s_Table[0xC04] = 0xC03;
+ s_Table[0xC05] = 0xC06;
+ s_Table[0xC06] = 0xC05;
+ s_Table[0xC07] = 0xC08;
+ s_Table[0xC08] = 0xC07;
+ s_Table[0xC09] = 0xC0A;
+ s_Table[0xC0A] = 0xC09;
+ s_Table[0xC0B] = 0xC0C;
+ s_Table[0xC0C] = 0xC0B;
+ s_Table[0xC0D] = 0xC0E;
+ s_Table[0xC0E] = 0xC0D;
+
+ // Hangers
+ s_Table[0xB97] = 0xB98;
+ s_Table[0xB98] = 0xB97;
+ s_Table[0xB99] = 0xB9A;
+ s_Table[0xB9A] = 0xB99;
+ s_Table[0xB9B] = 0xB9C;
+ s_Table[0xB9C] = 0xB9B;
+ s_Table[0xB9D] = 0xB9E;
+ s_Table[0xB9E] = 0xB9D;
+ s_Table[0xB9F] = 0xBA0;
+ s_Table[0xBA0] = 0xB9F;
+ s_Table[0xBA1] = 0xBA2;
+ s_Table[0xBA2] = 0xBA1;
+
+ // Hangers for swapping
+ s_List.Add(0xB97);
+ s_List.Add(0xB98);
+ s_List.Add(0xB99);
+ s_List.Add(0xB9A);
+ s_List.Add(0xB9B);
+ s_List.Add(0xB9C);
+ s_List.Add(0xB9D);
+ s_List.Add(0xB9E);
+ s_List.Add(0xB9F);
+ s_List.Add(0xBA0);
+ s_List.Add(0xBA1);
+ s_List.Add(0xBA2);
+ }
+
+ private HammerJob c_Job;
+
+ public HammerJob Job { get { return c_Job; } set { c_Job = value; } }
+
+ [Constructable]
+ public SignHammer()
+ : base(0x13E3)
+ {
+ Name = "Sign Hammer";
+ }
+
+ public int GetFlipFor(int id)
+ {
+ return (s_Table[id] == null ? id : (int)s_Table[id]);
+ }
+
+ public int GetNextSign(int id)
+ {
+ if (!s_List.Contains(id))
+ return id;
+
+ int idx = s_List.IndexOf(id);
+
+ if (idx + 2 < s_List.Count)
+ return (int)s_List[idx + 2];
+
+ if (idx % 2 == 0)
+ return (int)s_List[0];
+
+ return (int)s_List[1];
+ }
+
+ public override void OnDoubleClick(Mobile m)
+ {
+ if (RootParent != m)
+ {
+ m.SendMessage("That item must be in your backpack to use.");
+ return;
+ }
+
+ BaseHouse house = BaseHouse.FindHouseAt(m);
+
+ if (m.AccessLevel == AccessLevel.Player && (house == null || house.Owner != m))
+ {
+ m.SendMessage("You have to be inside your house to use this.");
+ return;
+ }
+
+ m.BeginTarget(3, false, TargetFlags.None, new TargetCallback(OnTarget));
+ }
+
+ protected void OnTarget(Mobile m, object obj)
+ {
+ Item item = obj as Item;
+
+ if (item == null)
+ {
+ m.SendMessage("You cannot change that with this.");
+ return;
+ }
+
+ if (item == this)
+ {
+ new SignHammerGump(m, this);
+ return;
+ }
+
+ if (c_Job == HammerJob.Flip)
+ {
+ int id = GetFlipFor(item.ItemID);
+
+ if (id == item.ItemID)
+ m.SendMessage("You cannot change that with this.");
+ else
+ item.ItemID = id;
+ }
+ else
+ {
+ int id = GetNextSign(item.ItemID);
+
+ if (id == item.ItemID)
+ m.SendMessage("You cannot change that with this.");
+ else
+ item.ItemID = id;
+ }
+ }
+
+ public SignHammer(Serial serial)
+ : base(serial)
+ {
+ }
+
+ public override void Serialize(GenericWriter writer)
+ {
+ base.Serialize(writer);
+
+ writer.Write((int)0); // version
+ }
+
+ public override void Deserialize(GenericReader reader)
+ {
+ base.Deserialize(reader);
+
+ int version = reader.ReadInt();
+ }
+ }
+
+ public class SignHammerGump : GumpPlusLight
+ {
+ private SignHammer c_Hammer;
+
+ public SignHammerGump( Mobile m, SignHammer hammer ) : base( m, 100, 100 )
+ {
+ c_Hammer = hammer;
+
+ NewGump();
+ }
+
+ protected override void BuildGump()
+ {
+ AddBackground(0, 0, 200, 200, 2600);
+
+ AddButton(50, 45, 2152, 2154, "Swap", new GumpCallback(Swap));
+ AddHtml( 90, 50, 70, "Swap Hanger");
+
+ AddButton( 50, 95, 2152, 2154, "Flip", new GumpCallback( Flip ) );
+ AddHtml( 90, 100, 70, "Flip Sign or Hanger");
+ }
+
+ private void Swap()
+ {
+ c_Hammer.Job = HammerJob.Swap;
+ }
+
+ private void Flip()
+ {
+ c_Hammer.Job = HammerJob.Flip;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Items/Houses/Monopoly/Items/TownHouse.cs b/Scripts/Items/Houses/Monopoly/Items/TownHouse.cs
new file mode 100644
index 0000000..8c0ec7e
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/Items/TownHouse.cs
@@ -0,0 +1,259 @@
+using System;
+using System.Collections;
+using Server;
+using Server.Items;
+using Server.Multis;
+using Server.Targeting;
+
+namespace Knives.TownHouses
+{
+ public class TownHouse : VersionHouse
+ {
+ private static ArrayList s_TownHouses = new ArrayList();
+ public static ArrayList AllTownHouses{ get{ return s_TownHouses; } }
+
+ private TownHouseSign c_Sign;
+ private Item c_Hanger;
+ private ArrayList c_Sectors = new ArrayList();
+
+ public TownHouseSign ForSaleSign { get { return c_Sign; } }
+
+ public Item Hanger
+ {
+ get
+ {
+ if ( c_Hanger == null )
+ {
+ c_Hanger = new Item( 0xB98 );
+ c_Hanger.Movable = false;
+ c_Hanger.Location = Sign.Location;
+ c_Hanger.Map = Sign.Map;
+ }
+
+ return c_Hanger;
+ }
+ set{ c_Hanger = value; }
+ }
+
+ public TownHouse( Mobile m, TownHouseSign sign, int locks, int secures ) : base( 0x1DD6 | 0x4000, m, locks, secures )
+ {
+ c_Sign = sign;
+
+ SetSign( 0, 0, 0 );
+
+ s_TownHouses.Add( this );
+ }
+
+ public void InitSectorDefinition()
+ {
+ if (c_Sign == null || c_Sign.Blocks.Count == 0)
+ return;
+
+ int minX = ((Rectangle2D)c_Sign.Blocks[0]).Start.X;
+ int minY = ((Rectangle2D)c_Sign.Blocks[0]).Start.Y;
+ int maxX = ((Rectangle2D)c_Sign.Blocks[0]).End.X;
+ int maxY = ((Rectangle2D)c_Sign.Blocks[0]).End.Y;
+
+ foreach( Rectangle2D rect in c_Sign.Blocks )
+ {
+ if ( rect.Start.X < minX )
+ minX = rect.Start.X;
+ if ( rect.Start.Y < minY )
+ minY = rect.Start.Y;
+ if ( rect.End.X > maxX )
+ maxX = rect.End.X;
+ if ( rect.End.Y > maxY )
+ maxY = rect.End.Y;
+ }
+
+ foreach (Sector sector in c_Sectors)
+ sector.OnMultiLeave(this);
+
+ c_Sectors.Clear();
+ for (int x = minX; x < maxX; ++x)
+ for (int y = minY; y < maxY; ++y)
+ if(!c_Sectors.Contains(Map.GetSector(new Point2D(x, y))))
+ c_Sectors.Add(Map.GetSector(new Point2D(x, y)));
+
+ foreach (Sector sector in c_Sectors)
+ sector.OnMultiEnter(this);
+
+ Components.Resize(maxX - minX, maxY - minY);
+ Components.Add(0x520, Components.Width - 1, Components.Height - 1, -5);
+ }
+
+ public override Rectangle2D[] Area
+ {
+ get
+ {
+ if (c_Sign == null)
+ return new Rectangle2D[100];
+
+ Rectangle2D[] rects = new Rectangle2D[c_Sign.Blocks.Count];
+
+ for (int i = 0; i < c_Sign.Blocks.Count && i < rects.Length; ++i)
+ rects[i] = (Rectangle2D)c_Sign.Blocks[i];
+
+ return rects;
+ }
+ }
+
+ public override bool IsInside( Point3D p, int height )
+ {
+ if (c_Sign == null)
+ return false;
+
+ if ( Map == null || Region == null )
+ {
+ Delete();
+ return false;
+ }
+
+ Sector sector = null;
+
+ try
+ {
+ if (c_Sign is RentalContract && Region.Contains(p))
+ return true;
+
+ sector = Map.GetSector(p);
+
+ foreach (BaseMulti m in sector.Multis)
+ {
+ if (m != this
+ && m is TownHouse
+ && ((TownHouse)m).ForSaleSign is RentalContract
+ && ((TownHouse)m).IsInside(p, height))
+ return false;
+ }
+
+ return Region.Contains(p);
+ }
+ catch(Exception e)
+ {
+ Errors.Report("Error occured in IsInside(). More information on the console.");
+ Console.WriteLine("Info:{0}, {1}, {2}", Map, sector, Region, sector != null ? "" + sector.Multis : "**");
+ Console.WriteLine(e.Source);
+ Console.WriteLine(e.Message);
+ Console.WriteLine(e.StackTrace);
+ return false;
+ }
+ }
+
+ public override int GetNewVendorSystemMaxVendors()
+ {
+ return 50;
+ }
+
+ public override int GetAosMaxSecures()
+ {
+ return MaxSecures;
+ }
+
+ public override int GetAosMaxLockdowns()
+ {
+ return MaxLockDowns;
+ }
+
+ public override void OnMapChange()
+ {
+ base.OnMapChange();
+
+ if ( c_Hanger != null )
+ c_Hanger.Map = Map;
+ }
+
+ public override void OnLocationChange( Point3D oldLocation )
+ {
+ base.OnLocationChange( oldLocation );
+
+ if ( c_Hanger != null )
+ c_Hanger.Location = Sign.Location;
+ }
+
+ public override void OnSpeech( SpeechEventArgs e )
+ {
+ if ( e.Mobile != Owner || !IsInside( e.Mobile ) )
+ return;
+
+ if (e.Speech.ToLower() == "check house rent")
+ c_Sign.CheckRentTimer();
+
+ Timer.DelayCall(TimeSpan.Zero, new TimerStateCallback(AfterSpeech), e.Mobile);
+ }
+
+ private void AfterSpeech(object o)
+ {
+ if (!(o is Mobile))
+ return;
+
+ if (((Mobile)o).Target is HouseBanTarget && ForSaleSign != null && ForSaleSign.NoBanning)
+ {
+ ((Mobile)o).Target.Cancel((Mobile)o, TargetCancelType.Canceled);
+ ((Mobile)o).SendMessage(0x161, "You cannot ban people from this house.");
+ }
+ }
+
+ public override void OnDelete()
+ {
+ if (c_Hanger != null)
+ c_Hanger.Delete();
+
+ foreach (Item item in Sign.GetItemsInRange(0))
+ if (item != Sign)
+ item.Visible = true;
+
+ c_Sign.ClearHouse();
+ Doors.Clear();
+
+ s_TownHouses.Remove(this);
+
+ base.OnDelete();
+ }
+
+ public TownHouse(Serial serial)
+ : base(serial)
+ {
+ s_TownHouses.Add(this);
+ }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( 3 );
+
+ // Version 2
+
+ writer.Write( c_Hanger );
+
+ // Version 1
+
+ writer.Write( c_Sign );
+ }
+
+ public override void Deserialize( GenericReader reader )
+ {
+ base.Deserialize( reader );
+
+ int version = reader.ReadInt();
+
+ if ( version >= 2 )
+ c_Hanger = reader.ReadItem();
+
+ c_Sign = (TownHouseSign)reader.ReadItem();
+
+ if (version <= 2)
+ {
+ int count = reader.ReadInt();
+ for (int i = 0; i < count; ++i)
+ reader.ReadRect2D();
+ }
+
+ if( Price == 0 )
+ Price = 1;
+
+ ItemID = 0x1DD6 | 0x4000;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Items/Houses/Monopoly/Items/TownHouseSign.cs b/Scripts/Items/Houses/Monopoly/Items/TownHouseSign.cs
new file mode 100644
index 0000000..4a5fb8f
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/Items/TownHouseSign.cs
@@ -0,0 +1,1334 @@
+using System;
+using System.Collections;
+using Server;
+using Server.Multis;
+using Server.Items;
+using Server.Mobiles;
+
+namespace Knives.TownHouses
+{
+ public enum Intu{ Neither, No, Yes }
+
+ [Flipable( 0xC0B, 0xC0C )]
+ public class TownHouseSign : Item
+ {
+ private static ArrayList s_TownHouseSigns = new ArrayList();
+ public static ArrayList AllSigns{ get{ return s_TownHouseSigns; } }
+
+ private Point3D c_BanLoc, c_SignLoc;
+ private int c_Locks, c_Secures, c_Price, c_MinZ, c_MaxZ, c_MinTotalSkill, c_MaxTotalSkill, c_ItemsPrice, c_RTOPayments;
+ private bool c_YoungOnly, c_RecurRent, c_Relock, c_KeepItems, c_LeaveItems, c_RentToOwn, c_Free, c_ForcePrivate, c_ForcePublic, c_NoTrade, c_NoBanning;
+ private string c_Skill;
+ private double c_SkillReq;
+ private ArrayList c_Blocks, c_DecoreItemInfos, c_PreviewItems;
+ private TownHouse c_House;
+ private Timer c_DemolishTimer, c_RentTimer, c_PreviewTimer;
+ private DateTime c_DemolishTime, c_RentTime;
+ private TimeSpan c_RentByTime, c_OriginalRentTime;
+ private Intu c_Murderers;
+
+ public Point3D BanLoc
+ {
+ get{ return c_BanLoc; }
+ set
+ {
+ c_BanLoc = value;
+ InvalidateProperties();
+ if ( Owned )
+ c_House.Region.GoLocation = value;
+ }
+ }
+
+ public Point3D SignLoc
+ {
+ get{ return c_SignLoc; }
+ set
+ {
+ c_SignLoc = value;
+ InvalidateProperties();
+
+ if ( Owned )
+ {
+ c_House.Sign.Location = value;
+ c_House.Hanger.Location = value;
+ }
+ }
+ }
+
+ public int Locks
+ {
+ get{ return c_Locks; }
+ set
+ {
+ c_Locks = value;
+ InvalidateProperties();
+ if ( Owned )
+ c_House.MaxLockDowns = value;
+ }
+ }
+
+ public int Secures
+ {
+ get{ return c_Secures; }
+ set
+ {
+ c_Secures = value;
+ InvalidateProperties();
+ if ( Owned )
+ c_House.MaxSecures = value;
+ }
+ }
+
+ public int Price
+ {
+ get{ return c_Price; }
+ set
+ {
+ c_Price = value;
+ InvalidateProperties();
+ }
+ }
+
+ public int MinZ
+ {
+ get{ return c_MinZ; }
+ set
+ {
+ if ( value > c_MaxZ )
+ c_MaxZ = value+1;
+
+ c_MinZ = value;
+ if (Owned)
+ RUOVersion.UpdateRegion(this);
+ }
+ }
+
+ public int MaxZ
+ {
+ get{ return c_MaxZ; }
+ set
+ {
+ if ( value < c_MinZ )
+ value = c_MinZ;
+
+ c_MaxZ = value;
+ if (Owned)
+ RUOVersion.UpdateRegion(this);
+ }
+ }
+
+ public int MinTotalSkill
+ {
+ get{ return c_MinTotalSkill; }
+ set
+ {
+ if ( value > c_MaxTotalSkill )
+ value = c_MaxTotalSkill;
+
+ c_MinTotalSkill = value;
+ ValidateOwnership();
+ InvalidateProperties();
+ }
+ }
+
+ public int MaxTotalSkill
+ {
+ get{ return c_MaxTotalSkill; }
+ set
+ {
+ if ( value < c_MinTotalSkill )
+ value = c_MinTotalSkill;
+
+ c_MaxTotalSkill = value;
+ ValidateOwnership();
+ InvalidateProperties();
+ }
+ }
+
+ public bool YoungOnly
+ {
+ get{ return c_YoungOnly; }
+ set
+ {
+ c_YoungOnly = value;
+
+ if ( c_YoungOnly )
+ c_Murderers = Intu.Neither;
+
+ ValidateOwnership();
+ InvalidateProperties();
+ }
+ }
+
+ public TimeSpan RentByTime
+ {
+ get{ return c_RentByTime; }
+ set
+ {
+ c_RentByTime = value;
+ c_OriginalRentTime = value;
+
+ if ( value == TimeSpan.Zero )
+ ClearRentTimer();
+ else
+ {
+ ClearRentTimer();
+ BeginRentTimer( value );
+ }
+
+ InvalidateProperties();
+ }
+ }
+
+ public bool RecurRent
+ {
+ get{ return c_RecurRent; }
+ set
+ {
+ c_RecurRent = value;
+
+ if ( !value )
+ c_RentToOwn = value;
+
+ InvalidateProperties();
+ }
+ }
+
+ public bool KeepItems
+ {
+ get{ return c_KeepItems; }
+ set
+ {
+ c_LeaveItems = false;
+ c_KeepItems = value;
+ InvalidateProperties();
+ }
+ }
+
+ public bool Free
+ {
+ get{ return c_Free; }
+ set
+ {
+ c_Free = value;
+ c_Price = 1;
+ InvalidateProperties();
+ }
+ }
+
+ public Intu Murderers
+ {
+ get{ return c_Murderers; }
+ set
+ {
+ c_Murderers = value;
+
+ ValidateOwnership();
+ InvalidateProperties();
+ }
+ }
+
+ public bool ForcePrivate
+ {
+ get { return c_ForcePrivate; }
+ set
+ {
+ c_ForcePrivate = value;
+
+ if (value)
+ {
+ c_ForcePublic = false;
+
+ if (c_House != null)
+ c_House.Public = false;
+ }
+ }
+ }
+
+ public bool ForcePublic
+ {
+ get { return c_ForcePublic; }
+ set
+ {
+ c_ForcePublic = value;
+
+ if (value)
+ {
+ c_ForcePrivate = false;
+
+ if (c_House != null)
+ c_House.Public = true;
+ }
+ }
+ }
+
+ public bool NoBanning
+ {
+ get { return c_NoBanning; }
+ set
+ {
+ c_NoBanning = value;
+
+ if (value && c_House != null)
+ c_House.Bans.Clear();
+ }
+ }
+
+ public ArrayList Blocks { get { return c_Blocks; } set { c_Blocks = value; } }
+ public string Skill { get { return c_Skill; } set { c_Skill = value; ValidateOwnership(); InvalidateProperties(); } }
+ public double SkillReq { get { return c_SkillReq; } set { c_SkillReq = value; ValidateOwnership(); InvalidateProperties(); } }
+ public bool LeaveItems{ get{ return c_LeaveItems; } set{ c_LeaveItems = value; InvalidateProperties(); } }
+ public bool RentToOwn{ get{ return c_RentToOwn; } set{ c_RentToOwn = value; InvalidateProperties(); } }
+ public bool Relock { get { return c_Relock; } set { c_Relock = value; } }
+ public bool NoTrade { get { return c_NoTrade; } set { c_NoTrade = value; } }
+ public int ItemsPrice { get { return c_ItemsPrice; } set { c_ItemsPrice = value; InvalidateProperties(); } }
+ public TownHouse House{ get{ return c_House; } set{ c_House = value; } }
+ public Timer DemolishTimer{ get{ return c_DemolishTimer; } }
+ public DateTime DemolishTime{ get{ return c_DemolishTime; } }
+
+ public bool Owned{ get{ return c_House != null && !c_House.Deleted; } }
+ public int Floors{ get{ return (c_MaxZ-c_MinZ)/20+1; } }
+
+ public bool BlocksReady{ get{ return Blocks.Count != 0; } }
+ public bool FloorsReady{ get{ return ( BlocksReady && MinZ != short.MinValue ); } }
+ public bool SignReady{ get{ return ( FloorsReady && SignLoc != Point3D.Zero ); } }
+ public bool BanReady{ get{ return ( SignReady && BanLoc != Point3D.Zero ); } }
+ public bool LocSecReady{ get{ return ( BanReady && Locks != 0 && Secures != 0 ); } }
+ public bool ItemsReady{ get{ return LocSecReady; } }
+ public bool LengthReady{ get{ return ItemsReady; } }
+ public bool PriceReady{ get{ return ( LengthReady && Price != 0 ); } }
+
+ public string PriceType
+ {
+ get
+ {
+ if ( c_RentByTime == TimeSpan.Zero )
+ return "Sale";
+ if ( c_RentByTime == TimeSpan.FromDays( 1 ) )
+ return "Daily";
+ if ( c_RentByTime == TimeSpan.FromDays( 7 ) )
+ return "Weekly";
+ if ( c_RentByTime == TimeSpan.FromDays( 30 ) )
+ return "Monthly";
+
+ return "Sale";
+ }
+ }
+
+ public string PriceTypeShort
+ {
+ get
+ {
+ if ( c_RentByTime == TimeSpan.Zero )
+ return "Sale";
+ if ( c_RentByTime == TimeSpan.FromDays( 1 ) )
+ return "Day";
+ if ( c_RentByTime == TimeSpan.FromDays( 7 ) )
+ return "Week";
+ if ( c_RentByTime == TimeSpan.FromDays( 30 ) )
+ return "Month";
+
+ return "Sale";
+ }
+ }
+
+ [Constructable]
+ public TownHouseSign() : base( 0xC0B )
+ {
+ Name = "This building is for sale or rent!";
+ Movable = false;
+
+ c_BanLoc = Point3D.Zero;
+ c_SignLoc = Point3D.Zero;
+ c_Skill = "";
+ c_Blocks = new ArrayList();
+ c_DecoreItemInfos = new ArrayList();
+ c_PreviewItems = new ArrayList();
+ c_DemolishTime = DateTime.Now;
+ c_RentTime = DateTime.Now;
+ c_RentByTime = TimeSpan.Zero;
+ c_RecurRent = true;
+
+ c_MinZ = short.MinValue;
+ c_MaxZ = short.MaxValue;
+
+ s_TownHouseSigns.Add( this );
+ }
+
+ private void SearchForHouse()
+ {
+ foreach( TownHouse house in TownHouse.AllTownHouses )
+ if (house.ForSaleSign == this )
+ c_House = house;
+ }
+
+ public void UpdateBlocks()
+ {
+ if ( !Owned )
+ return;
+
+ if (c_Blocks.Count == 0)
+ UnconvertDoors();
+
+ RUOVersion.UpdateRegion(this);
+ ConvertItems(false);
+ c_House.InitSectorDefinition();
+ }
+
+ public void ShowAreaPreview( Mobile m )
+ {
+ ClearPreview();
+
+ Point2D point = Point2D.Zero;
+ ArrayList blocks = new ArrayList();
+
+ foreach( Rectangle2D rect in c_Blocks )
+ for( int x = rect.Start.X; x < rect.End.X; ++x )
+ for( int y = rect.Start.Y; y < rect.End.Y; ++y )
+ {
+ point = new Point2D( x, y );
+ if ( !blocks.Contains( point ) )
+ blocks.Add( point );
+ }
+
+ if (blocks.Count > 500)
+ {
+ m.SendMessage("Due to size of the area, skipping the preview.");
+ return;
+ }
+
+ Item item = null;
+ int avgz = 0;
+ foreach( Point2D p in blocks )
+ {
+ avgz = Map.GetAverageZ(p.X, p.Y);
+
+ item = new Item( 0x1766 );
+ item.Name = "Area Preview";
+ item.Movable = false;
+ item.Location = new Point3D( p.X, p.Y, (avgz <= m.Z ? m.Z+2 : avgz+2 ) );
+ item.Map = Map;
+
+ c_PreviewItems.Add( item );
+ }
+
+ c_PreviewTimer = Timer.DelayCall( TimeSpan.FromSeconds( 100 ), new TimerCallback( ClearPreview ) );
+ }
+
+ public void ShowSignPreview()
+ {
+ ClearPreview();
+
+ Item sign = new Item( 0xBD2 );
+ sign.Name = "Sign Preview";
+ sign.Movable = false;
+ sign.Location = SignLoc;
+ sign.Map = Map;
+
+ c_PreviewItems.Add( sign );
+
+ sign = new Item( 0xB9C );
+ sign.Name = "Sign Preview";
+ sign.Movable = false;
+ sign.Location = SignLoc;
+ sign.Map = Map;
+
+ c_PreviewItems.Add( sign );
+
+ c_PreviewTimer = Timer.DelayCall( TimeSpan.FromSeconds( 100 ), new TimerCallback( ClearPreview ) );
+ }
+
+ public void ShowBanPreview()
+ {
+ ClearPreview();
+
+ Item ban = new Item( 0x17EE );
+ ban.Name = "Ban Loc Preview";
+ ban.Movable = false;
+ ban.Location = BanLoc;
+ ban.Map = Map;
+
+ c_PreviewItems.Add( ban );
+
+ c_PreviewTimer = Timer.DelayCall( TimeSpan.FromSeconds( 100 ), new TimerCallback( ClearPreview ) );
+ }
+
+ public void ShowFloorsPreview(Mobile m)
+ {
+ ClearPreview();
+
+ Item item = new Item(0x7BD);
+ item.Name = "Bottom Floor Preview";
+ item.Movable = false;
+ item.Location = m.Location;
+ item.Z = c_MinZ;
+ item.Map = Map;
+
+ c_PreviewItems.Add(item);
+
+ item = new Item(0x7BD);
+ item.Name = "Top Floor Preview";
+ item.Movable = false;
+ item.Location = m.Location;
+ item.Z = c_MaxZ;
+ item.Map = Map;
+
+ c_PreviewItems.Add(item);
+
+ c_PreviewTimer = Timer.DelayCall(TimeSpan.FromSeconds(100), new TimerCallback(ClearPreview));
+ }
+
+ public void ClearPreview()
+ {
+ foreach( Item item in new ArrayList( c_PreviewItems ) )
+ {
+ c_PreviewItems.Remove( item );
+ item.Delete();
+ }
+
+ if ( c_PreviewTimer != null )
+ c_PreviewTimer.Stop();
+
+ c_PreviewTimer = null;
+ }
+
+ public void Purchase( Mobile m )
+ {
+ Purchase( m, false );
+ }
+
+ public void Purchase( Mobile m, bool sellitems )
+ {
+ try
+ {
+ if (Owned)
+ {
+ m.SendMessage("Someone already owns this house!");
+ return;
+ }
+
+ if (!PriceReady)
+ {
+ m.SendMessage("The setup for this house is not yet complete.");
+ return;
+ }
+
+ int price = c_Price + (sellitems ? c_ItemsPrice : 0);
+
+ if (c_Free)
+ price = 0;
+
+ if (m.AccessLevel == AccessLevel.Player && !Server.Mobiles.Banker.Withdraw(m, price))
+ {
+ m.SendMessage("You cannot afford this house.");
+ return;
+ }
+
+ if (m.AccessLevel == AccessLevel.Player)
+ m.SendLocalizedMessage(1060398, price.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box.
+
+ Visible = false;
+
+ int minX = ((Rectangle2D)c_Blocks[0]).Start.X;
+ int minY = ((Rectangle2D)c_Blocks[0]).Start.Y;
+ int maxX = ((Rectangle2D)c_Blocks[0]).End.X;
+ int maxY = ((Rectangle2D)c_Blocks[0]).End.Y;
+
+ foreach (Rectangle2D rect in c_Blocks)
+ {
+ if (rect.Start.X < minX)
+ minX = rect.Start.X;
+ if (rect.Start.Y < minY)
+ minY = rect.Start.Y;
+ if (rect.End.X > maxX)
+ maxX = rect.End.X;
+ if (rect.End.Y > maxY)
+ maxY = rect.End.Y;
+ }
+
+ c_House = new TownHouse(m, this, c_Locks, c_Secures);
+
+ c_House.Components.Resize( maxX-minX, maxY-minY );
+ c_House.Components.Add( 0x520, c_House.Components.Width-1, c_House.Components.Height-1, -5 );
+
+ c_House.Location = new Point3D(minX, minY, Map.GetAverageZ(minX, minY));
+ c_House.Map = Map;
+ c_House.Region.GoLocation = c_BanLoc;
+ c_House.Sign.Location = c_SignLoc;
+ c_House.Hanger = new Item(0xB9C);
+ c_House.Hanger.Location = c_SignLoc;
+ c_House.Hanger.Map = Map;
+ c_House.Hanger.Movable = false;
+
+ if (c_ForcePublic)
+ c_House.Public = true;
+
+ c_House.Price = (RentByTime == TimeSpan.FromDays(0) ? c_Price : 1);
+
+ RUOVersion.UpdateRegion(this);
+
+ if (c_House.Price == 0)
+ c_House.Price = 1;
+
+ if (c_RentByTime != TimeSpan.Zero)
+ BeginRentTimer(c_RentByTime);
+
+ c_RTOPayments = 1;
+
+ HideOtherSigns();
+
+ c_DecoreItemInfos = new ArrayList();
+
+ ConvertItems(sellitems);
+ }
+ catch(Exception e)
+ {
+ Errors.Report(String.Format("An error occurred during home purchasing. More information available on the console."));
+ Console.WriteLine(e.Message);
+ Console.WriteLine(e.Source);
+ Console.WriteLine(e.StackTrace);
+ }
+ }
+
+ private void HideOtherSigns()
+ {
+ foreach( Item item in c_House.Sign.GetItemsInRange( 0 ) )
+ if ( !(item is HouseSign) )
+ if ( item.ItemID == 0xB95
+ || item.ItemID == 0xB96
+ || item.ItemID == 0xC43
+ || item.ItemID == 0xC44
+ || ( item.ItemID > 0xBA3 && item.ItemID < 0xC0E ) )
+ item.Visible = false;
+ }
+
+ public virtual void ConvertItems( bool keep )
+ {
+ if ( c_House == null )
+ return;
+
+ ArrayList items = new ArrayList();
+ foreach(Rectangle2D rect in c_Blocks)
+ foreach (Item item in Map.GetItemsInBounds(rect))
+ if (c_House.Region.Contains(item.Location) && item.RootParent == null && !items.Contains(item))
+ items.Add(item);
+
+ foreach (Item item in new ArrayList(items))
+ {
+ if (item is HouseSign
+ || item is BaseMulti
+ || item is BaseAddon
+ || item is AddonComponent
+ || item == c_House.Hanger
+ || !item.Visible
+ || item.IsLockedDown
+ || item.IsSecure
+ || item.Movable
+ || c_PreviewItems.Contains(item))
+ continue;
+
+ if (item is BaseDoor)
+ ConvertDoor((BaseDoor)item);
+ else if (!c_LeaveItems)
+ {
+ c_DecoreItemInfos.Add(new DecoreItemInfo(item.GetType().ToString(), item.Name, item.ItemID, item.Hue, item.Location, item.Map));
+
+ if (!c_KeepItems || !keep)
+ item.Delete();
+ else
+ {
+ item.Movable = true;
+ c_House.LockDown(c_House.Owner, item, false);
+ }
+ }
+ }
+ }
+
+ protected void ConvertDoor( BaseDoor door )
+ {
+ if ( !Owned )
+ return;
+
+ if ( door is Server.Gumps.ISecurable )
+ {
+ door.Locked = false;
+ c_House.Doors.Add( door );
+ return;
+ }
+
+ door.Open = false;
+
+ GenericHouseDoor newdoor = new GenericHouseDoor( (DoorFacing)0, door.ClosedID, door.OpenedSound, door.ClosedSound );
+ newdoor.Offset = door.Offset;
+ newdoor.ClosedID = door.ClosedID;
+ newdoor.OpenedID = door.OpenedID;
+ newdoor.Location = door.Location;
+ newdoor.Map = door.Map;
+
+ door.Delete();
+
+ foreach( Item inneritem in newdoor.GetItemsInRange( 1 ) )
+ if ( inneritem is BaseDoor && inneritem != newdoor && inneritem.Z == newdoor.Z )
+ {
+ ((BaseDoor)inneritem).Link = newdoor;
+ newdoor.Link = (BaseDoor)inneritem;
+ }
+
+ c_House.Doors.Add(newdoor);
+ }
+
+ public virtual void UnconvertDoors()
+ {
+ if ( c_House == null )
+ return;
+
+ BaseDoor newdoor = null;
+
+ foreach (BaseDoor door in new ArrayList(c_House.Doors))
+ {
+ door.Open = false;
+
+ if ( c_Relock )
+ door.Locked = true;
+
+ newdoor = new StrongWoodDoor( (DoorFacing)0 );
+ newdoor.ItemID = door.ItemID;
+ newdoor.ClosedID = door.ClosedID;
+ newdoor.OpenedID = door.OpenedID;
+ newdoor.OpenedSound = door.OpenedSound;
+ newdoor.ClosedSound = door.ClosedSound;
+ newdoor.Offset = door.Offset;
+ newdoor.Location = door.Location;
+ newdoor.Map = door.Map;
+
+ door.Delete();
+
+ foreach( Item inneritem in newdoor.GetItemsInRange( 1 ) )
+ if ( inneritem is BaseDoor && inneritem != newdoor && inneritem.Z == newdoor.Z )
+ {
+ ( (BaseDoor)inneritem ).Link = newdoor;
+ newdoor.Link = (BaseDoor)inneritem;
+ }
+
+ c_House.Doors.Remove( door );
+ }
+ }
+
+ public void RecreateItems()
+ {
+ Item item = null;
+ foreach( DecoreItemInfo info in c_DecoreItemInfos )
+ {
+ item = null;
+
+ if ( info.TypeString.ToLower().IndexOf( "static" ) != -1 )
+ item = new Static( info.ItemID );
+ else
+ {
+ try{
+ item = Activator.CreateInstance( ScriptCompiler.FindTypeByFullName( info.TypeString ) ) as Item;
+ }catch{ continue; }
+ }
+
+ if ( item == null )
+ continue;
+
+ item.ItemID = info.ItemID;
+ item.Name = info.Name;
+ item.Hue = info.Hue;
+ item.Location = info.Location;
+ item.Map = info.Map;
+ item.Movable = false;
+ }
+ }
+
+ public virtual void ClearHouse()
+ {
+ UnconvertDoors();
+ ClearDemolishTimer();
+ ClearRentTimer();
+ PackUpItems();
+ RecreateItems();
+ c_House = null;
+ Visible = true;
+
+ if ( c_RentToOwn )
+ c_RentByTime = c_OriginalRentTime;
+ }
+
+ public virtual void ValidateOwnership()
+ {
+ if ( !Owned )
+ return;
+
+ if ( c_House.Owner == null )
+ {
+ c_House.Delete();
+ return;
+ }
+
+ if ( c_House.Owner.AccessLevel != AccessLevel.Player )
+ return;
+
+ if ( !CanBuyHouse( c_House.Owner ) && c_DemolishTimer == null )
+ BeginDemolishTimer();
+ else
+ ClearDemolishTimer();
+ }
+
+ public int CalcVolume()
+ {
+ int floors = 1;
+ if ( c_MaxZ - c_MinZ < 100 )
+ floors = 1 + Math.Abs( (c_MaxZ - c_MinZ)/20 );
+
+ Point3D point = Point3D.Zero;
+ ArrayList blocks = new ArrayList();
+
+ foreach( Rectangle2D rect in c_Blocks )
+ for( int x = rect.Start.X; x < rect.End.X; ++x )
+ for( int y = rect.Start.Y; y < rect.End.Y; ++y )
+ for( int z = 0; z < floors; z++ )
+ {
+ point = new Point3D( x, y, z );
+ if ( !blocks.Contains( point ) )
+ blocks.Add( point );
+ }
+ return blocks.Count;
+ }
+
+ private void StartTimers()
+ {
+ if (c_DemolishTime > DateTime.Now)
+ BeginDemolishTimer(c_DemolishTime - DateTime.Now);
+ else if (c_RentByTime != TimeSpan.Zero)
+ BeginRentTimer(c_RentByTime);
+ }
+
+ #region Demolish
+
+ public void ClearDemolishTimer()
+ {
+ if ( c_DemolishTimer == null )
+ return;
+
+ c_DemolishTimer.Stop();
+ c_DemolishTimer = null;
+ c_DemolishTime = DateTime.Now;
+
+ if ( !c_House.Deleted && Owned )
+ c_House.Owner.SendMessage( "Demolition canceled." );
+ }
+
+ public void CheckDemolishTimer()
+ {
+ if ( c_DemolishTimer == null || !Owned )
+ return;
+
+ DemolishAlert();
+ }
+
+ protected void BeginDemolishTimer()
+ {
+ BeginDemolishTimer( TimeSpan.FromHours( 24 ) );
+ }
+
+ protected void BeginDemolishTimer( TimeSpan time )
+ {
+ if ( !Owned )
+ return;
+
+ c_DemolishTime = DateTime.Now + time;
+ c_DemolishTimer = Timer.DelayCall( time, new TimerCallback( PackUpHouse ) );
+
+ DemolishAlert();
+ }
+
+ protected virtual void DemolishAlert()
+ {
+ c_House.Owner.SendMessage( "You no longer meet the requirements for your town house, which will be demolished automatically in {0}:{1}:{2}.", (c_DemolishTime-DateTime.Now).Hours, (c_DemolishTime-DateTime.Now).Minutes, (c_DemolishTime-DateTime.Now).Seconds );
+ }
+
+ protected void PackUpHouse()
+ {
+ if ( !Owned || c_House.Deleted )
+ return;
+
+ PackUpItems();
+
+ c_House.Owner.BankBox.DropItem( new BankCheck( c_House.Price ) );
+
+ try
+ {
+ c_House.Delete();
+ }
+ catch
+ {
+ Errors.Report("The infamous SVN bug has occured.");
+ }
+
+ }
+
+ /* Added for fixing Rental Loop Crash bug */
+ protected void DeleteTest()
+ {
+ if ( !Owned || c_House.Deleted )
+ return;
+
+ PackUpItems();
+ c_House.Owner.BankBox.DropItem( new BankCheck( c_House.Price ) );
+ }
+
+ protected void PackUpItems()
+ {
+ if ( c_House == null )
+ return;
+
+ Container bag = new Bag();
+ bag.Name = "Town House Belongings";
+
+ foreach( Item item in new ArrayList( c_House.LockDowns ) )
+ {
+ item.IsLockedDown = false;
+ item.Movable = true;
+ c_House.LockDowns.Remove( item );
+ bag.DropItem( item );
+ }
+
+ foreach( SecureInfo info in new ArrayList( c_House.Secures ) )
+ {
+ info.Item.IsLockedDown = false;
+ info.Item.IsSecure = false;
+ info.Item.Movable = true;
+ info.Item.SetLastMoved();
+ c_House.Secures.Remove( info );
+ bag.DropItem( info.Item );
+ }
+
+ foreach (Rectangle2D rect in c_Blocks)
+ {
+ ArrayList l = new ArrayList();
+ foreach (Item item in Map.GetItemsInBounds(rect))
+ l.Add(item);
+
+ foreach (Item item in l)
+ {
+ if (item is HouseSign
+ || item is BaseDoor
+ || item is BaseMulti
+ || item is BaseAddon
+ || item is AddonComponent
+ || !item.Visible
+ || item.IsLockedDown
+ || item.IsSecure
+ || !item.Movable
+ || item.Map != c_House.Map
+ || !c_House.Region.Contains(item.Location))
+ continue;
+
+ bag.DropItem(item);
+ }
+ }
+
+ if ( bag.Items.Count == 0 )
+ {
+ bag.Delete();
+ return;
+ }
+
+ c_House.Owner.BankBox.DropItem( bag );
+ }
+
+ #endregion
+
+ #region Rent
+
+ public void ClearRentTimer()
+ {
+ if ( c_RentTimer != null )
+ {
+ c_RentTimer.Stop();
+ c_RentTimer = null;
+ }
+
+ c_RentTime = DateTime.Now;
+ }
+
+ private void BeginRentTimer()
+ {
+ BeginRentTimer( TimeSpan.FromDays( 1 ) );
+ }
+
+ private void BeginRentTimer( TimeSpan time )
+ {
+ if ( !Owned )
+ return;
+
+ c_RentTimer = Timer.DelayCall( time, new TimerCallback( RentDue ) );
+ c_RentTime = DateTime.Now + time;
+ }
+
+ public void CheckRentTimer()
+ {
+ if ( c_RentTimer == null || !Owned )
+ return;
+
+ c_House.Owner.SendMessage( "This rent cycle ends in {0} days, {1}:{2}:{3}.", (c_RentTime-DateTime.Now).Days, (c_RentTime-DateTime.Now).Hours, (c_RentTime-DateTime.Now).Minutes, (c_RentTime-DateTime.Now).Seconds );
+ }
+
+ private void RentDue()
+ {
+ if ( !Owned || c_House.Owner == null )
+ return;
+
+ if ( !c_RecurRent )
+ {
+ c_House.Owner.SendMessage( "Your town house rental contract has expired, and the bank has once again taken possession." );
+ PackUpHouse();
+ return;
+ }
+
+ if ( !c_Free && c_House.Owner.AccessLevel == AccessLevel.Player && !Server.Mobiles.Banker.Withdraw( c_House.Owner, c_Price ) )
+ {
+ c_House.Owner.SendMessage( "Since you can not afford the rent, the bank has reclaimed your town house." );
+ PackUpHouse();
+ return;
+ }
+
+ if ( !c_Free )
+ c_House.Owner.SendMessage( "The bank has withdrawn {0} gold rent for your town house.", c_Price );
+
+ OnRentPaid();
+
+ if ( c_RentToOwn )
+ {
+ c_RTOPayments++;
+
+ bool complete = false;
+
+ if ( c_RentByTime == TimeSpan.FromDays( 1 ) && c_RTOPayments >= 60 )
+ {
+ complete = true;
+ c_House.Price = c_Price*60;
+ }
+
+ if ( c_RentByTime == TimeSpan.FromDays( 7 ) && c_RTOPayments >= 9 )
+ {
+ complete = true;
+ c_House.Price = c_Price*9;
+ }
+
+ if ( c_RentByTime == TimeSpan.FromDays( 30 ) && c_RTOPayments >= 2 )
+ {
+ complete = true;
+ c_House.Price = c_Price*2;
+ }
+
+ if ( complete )
+ {
+ c_House.Owner.SendMessage( "You now own your rental home." );
+ c_RentByTime = TimeSpan.FromDays( 0 );
+ return;
+ }
+ }
+
+ BeginRentTimer( c_RentByTime );
+ }
+
+ protected virtual void OnRentPaid()
+ {
+ }
+
+ public void NextPriceType()
+ {
+ if ( c_RentByTime == TimeSpan.Zero )
+ RentByTime = TimeSpan.FromDays( 1 );
+ else if ( c_RentByTime == TimeSpan.FromDays( 1 ) )
+ RentByTime = TimeSpan.FromDays( 7 );
+ else if ( c_RentByTime == TimeSpan.FromDays( 7 ) )
+ RentByTime = TimeSpan.FromDays( 30 );
+ else
+ RentByTime = TimeSpan.Zero;
+ }
+
+ public void PrevPriceType()
+ {
+ if ( c_RentByTime == TimeSpan.Zero )
+ RentByTime = TimeSpan.FromDays( 30 );
+ else if ( c_RentByTime == TimeSpan.FromDays( 30 ) )
+ RentByTime = TimeSpan.FromDays( 7 );
+ else if ( c_RentByTime == TimeSpan.FromDays( 7 ) )
+ RentByTime = TimeSpan.FromDays( 1 );
+ else
+ RentByTime = TimeSpan.Zero;
+ }
+
+ #endregion
+
+ public bool CanBuyHouse( Mobile m )
+ {
+ if ( c_Skill != "" )
+ {
+ try
+ {
+ SkillName index = (SkillName)Enum.Parse( typeof( SkillName ), c_Skill, true );
+ if ( m.Skills[index].Value < c_SkillReq )
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ if ( c_MinTotalSkill != 0 && m.SkillsTotal/10 < c_MinTotalSkill )
+ return false;
+
+ if ( c_MaxTotalSkill != 0 && m.SkillsTotal/10 > c_MaxTotalSkill )
+ return false;
+
+ if ( c_YoungOnly && m.Player && !((PlayerMobile)m).Young )
+ return false;
+
+ if ( c_Murderers == Intu.Yes && m.Kills < 5 )
+ return false;
+
+ if ( c_Murderers == Intu.No && m.Kills >= 5 )
+ return false;
+
+ return true;
+ }
+
+ public override void OnDoubleClick( Mobile m )
+ {
+ if ( m.AccessLevel != AccessLevel.Player )
+ new TownHouseSetupGump( m, this );
+ else if ( !Visible )
+ return;
+ else if ( CanBuyHouse( m ) && !BaseHouse.HasAccountHouse( m ) )
+ new TownHouseConfirmGump( m, this );
+ else
+ m.SendMessage( "You cannot purchase this house." );
+ }
+
+ public override void Delete()
+ {
+ if ( c_House == null || c_House.Deleted )
+ base.Delete();
+ else
+ PublicOverheadMessage( Server.Network.MessageType.Regular, 0x0, true, "You cannot delete this while the home is owned." );
+
+ if ( this.Deleted )
+ s_TownHouseSigns.Remove( this );
+ }
+
+ public override void GetProperties( ObjectPropertyList list )
+ {
+ base.GetProperties( list );
+
+ string cost = String.Format("{0:n0}", c_Price);
+ string cost_items = String.Format("{0:n0}", c_ItemsPrice);
+ string locks = String.Format("{0:n0}", c_Locks);
+ string secures = String.Format("{0:n0}", c_Secures);
+
+ if ( c_Free )
+ list.Add( 1060658, "Price\tFree" );
+ else if ( c_RentByTime == TimeSpan.Zero )
+ list.Add( 1060658, "Price\t{0}{1}", cost, c_KeepItems ? " (+" + cost_items + " for the items)" : "" );
+ else if ( c_RecurRent )
+ list.Add( 1060658, "{0}\t{1}\r{2}", PriceType + (c_RentToOwn ? " Rent-to-Own" : " Recurring"), cost, c_KeepItems ? " (+" + cost_items + " for the items)" : "" );
+ else
+ list.Add( 1060658, "One {0}\t{1}{2}", PriceTypeShort, cost, c_KeepItems ? " (+" + cost_items + " for the items)" : "" );
+
+ list.Add( 1060659, "Lockdowns\t{0}", locks );
+ list.Add( 1060660, "Secures\t{0}", secures );
+
+ if ( c_SkillReq != 0.0 )
+ list.Add( 1060661, "Requires\t{0}", c_SkillReq + " in " + c_Skill );
+ if ( c_MinTotalSkill != 0 )
+ list.Add( 1060662, "Requires more than\t{0} total skills", c_MinTotalSkill );
+ if ( c_MaxTotalSkill != 0 )
+ list.Add( 1060663, "Requires less than\t{0} total skills", c_MaxTotalSkill );
+
+ if ( c_YoungOnly )
+ list.Add( 1063483, "Must be\tYoung" );
+ else if ( c_Murderers == Intu.Yes )
+ list.Add( 1063483, "Must be\ta murderer" );
+ else if ( c_Murderers == Intu.No )
+ list.Add( 1063483, "Must be\tinnocent" );
+ }
+
+ public TownHouseSign( Serial serial ) : base( serial )
+ {
+ }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( 13 );
+
+ // Version 13
+
+ writer.Write(c_ForcePrivate);
+ writer.Write(c_ForcePublic);
+ writer.Write(c_NoTrade);
+
+ // Version 12
+
+ writer.Write( c_Free );
+
+ // Version 11
+
+ writer.Write( (int)c_Murderers );
+
+ // Version 10
+
+ writer.Write( c_LeaveItems );
+
+ // Version 9
+ writer.Write( c_RentToOwn );
+ writer.Write( c_OriginalRentTime );
+ writer.Write( c_RTOPayments );
+
+ // Version 7
+ writer.WriteItemList( c_PreviewItems, true );
+
+ // Version 6
+ writer.Write( c_ItemsPrice );
+ writer.Write( c_KeepItems );
+
+ // Version 5
+ writer.Write( c_DecoreItemInfos.Count );
+ foreach( DecoreItemInfo info in c_DecoreItemInfos )
+ info.Save( writer );
+
+ writer.Write( c_Relock );
+
+ // Version 4
+ writer.Write( c_RecurRent );
+ writer.Write( c_RentByTime );
+ writer.Write( c_RentTime );
+ writer.Write( c_DemolishTime );
+ writer.Write( c_YoungOnly );
+ writer.Write( c_MinTotalSkill );
+ writer.Write( c_MaxTotalSkill );
+
+ // Version 3
+ writer.Write( c_MinZ );
+ writer.Write( c_MaxZ );
+
+ // Version 2
+ writer.Write( c_House );
+
+ // Version 1
+ writer.Write( c_Price );
+ writer.Write( c_Locks );
+ writer.Write( c_Secures );
+ writer.Write( c_BanLoc );
+ writer.Write( c_SignLoc );
+ writer.Write( c_Skill );
+ writer.Write( c_SkillReq );
+ writer.Write( c_Blocks.Count );
+ foreach( Rectangle2D rect in c_Blocks )
+ writer.Write( rect );
+ }
+
+ public override void Deserialize( GenericReader reader )
+ {
+ base.Deserialize( reader );
+
+ int version = reader.ReadInt();
+
+ if (version >= 13)
+ {
+ c_ForcePrivate = reader.ReadBool();
+ c_ForcePublic = reader.ReadBool();
+ c_NoTrade = reader.ReadBool();
+ }
+
+ if (version >= 12)
+ c_Free = reader.ReadBool();
+
+ if ( version >= 11 )
+ c_Murderers = (Intu)reader.ReadInt();
+
+ if ( version >= 10 )
+ c_LeaveItems = reader.ReadBool();
+
+ if ( version >= 9 )
+ {
+ c_RentToOwn = reader.ReadBool();
+ c_OriginalRentTime = reader.ReadTimeSpan();
+ c_RTOPayments = reader.ReadInt();
+ }
+
+ c_PreviewItems = new ArrayList();
+ if ( version >= 7 )
+ c_PreviewItems = reader.ReadItemList();
+
+ if ( version >= 6 )
+ {
+ c_ItemsPrice = reader.ReadInt();
+ c_KeepItems = reader.ReadBool();
+ }
+
+ c_DecoreItemInfos = new ArrayList();
+ if ( version >= 5 )
+ {
+ int decorecount = reader.ReadInt();
+ DecoreItemInfo info;
+ for( int i = 0; i < decorecount; ++i )
+ {
+ info = new DecoreItemInfo();
+ info.Load( reader );
+ c_DecoreItemInfos.Add( info );
+ }
+
+ c_Relock = reader.ReadBool();
+ }
+
+ if ( version >= 4 )
+ {
+ c_RecurRent = reader.ReadBool();
+ c_RentByTime = reader.ReadTimeSpan();
+ c_RentTime = reader.ReadDateTime();
+ c_DemolishTime = reader.ReadDateTime();
+ c_YoungOnly = reader.ReadBool();
+ c_MinTotalSkill = reader.ReadInt();
+ c_MaxTotalSkill = reader.ReadInt();
+ }
+
+ if ( version >= 3 )
+ {
+ c_MinZ = reader.ReadInt();
+ c_MaxZ = reader.ReadInt();
+ }
+
+ if ( version >= 2 )
+ c_House = (TownHouse)reader.ReadItem();
+
+ c_Price = reader.ReadInt();
+ c_Locks = reader.ReadInt();
+ c_Secures = reader.ReadInt();
+ c_BanLoc = reader.ReadPoint3D();
+ c_SignLoc = reader.ReadPoint3D();
+ c_Skill = reader.ReadString();
+ c_SkillReq = reader.ReadDouble();
+
+ c_Blocks = new ArrayList();
+ int count = reader.ReadInt();
+ for ( int i = 0; i < count; ++i )
+ c_Blocks.Add( reader.ReadRect2D() );
+
+ if ( c_RentTime > DateTime.Now )
+ BeginRentTimer( c_RentTime-DateTime.Now );
+
+ Timer.DelayCall(TimeSpan.Zero, new TimerCallback(StartTimers));
+
+ ClearPreview();
+
+ s_TownHouseSigns.Add( this );
+ }
+ }
+}
diff --git a/Scripts/Items/Houses/Monopoly/Misc/CommandInfo.cs b/Scripts/Items/Houses/Monopoly/Misc/CommandInfo.cs
new file mode 100644
index 0000000..93a59ac
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/Misc/CommandInfo.cs
@@ -0,0 +1,36 @@
+using System;
+using Server;
+
+namespace Knives.TownHouses
+{
+ public delegate void TownHouseCommandHandler(CommandInfo info);
+
+ public class CommandInfo
+ {
+ private Mobile c_Mobile;
+ private string c_Command;
+ private string c_ArgString;
+ private string[] c_Arguments;
+
+ public Mobile Mobile { get { return c_Mobile; } }
+ public string Command { get { return c_Command; } }
+ public string ArgString { get { return c_ArgString; } }
+ public string[] Arguments { get { return c_Arguments; } }
+
+ public CommandInfo(Mobile m, string com, string args, string[] arglist)
+ {
+ c_Mobile = m;
+ c_Command = com;
+ c_ArgString = args;
+ c_Arguments = arglist;
+ }
+
+ public string GetString(int num)
+ {
+ if (c_Arguments.Length > num)
+ return c_Arguments[num];
+
+ return "";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Items/Houses/Monopoly/Misc/DecoreItemInfo.cs b/Scripts/Items/Houses/Monopoly/Misc/DecoreItemInfo.cs
new file mode 100644
index 0000000..b5aae3c
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/Misc/DecoreItemInfo.cs
@@ -0,0 +1,64 @@
+using System;
+using Server;
+
+namespace Knives.TownHouses
+{
+ public class DecoreItemInfo
+ {
+ private string c_TypeString;
+ private string c_Name;
+ private int c_ItemID;
+ private int c_Hue;
+ private Point3D c_Location;
+ private Map c_Map;
+
+ public string TypeString{ get{ return c_TypeString; } }
+ public string Name{ get{ return c_Name; } }
+ public int ItemID{ get{ return c_ItemID; } }
+ public int Hue{ get{ return c_Hue; } }
+ public Point3D Location{ get{ return c_Location; } }
+ public Map Map{ get{ return c_Map; } }
+
+ public DecoreItemInfo()
+ {
+ }
+
+ public DecoreItemInfo( string typestring, string name, int itemid, int hue, Point3D loc, Map map )
+ {
+ c_TypeString = typestring;
+ c_ItemID = itemid;
+ c_Location = loc;
+ c_Map = map;
+ }
+
+ public void Save( GenericWriter writer )
+ {
+ writer.Write( (int)1 ); // Version
+
+ // Version 1
+ writer.Write( c_Hue );
+ writer.Write( c_Name );
+
+ writer.Write( c_TypeString );
+ writer.Write( c_ItemID );
+ writer.Write( c_Location );
+ writer.Write( c_Map );
+ }
+
+ public void Load( GenericReader reader )
+ {
+ int version = reader.ReadInt();
+
+ if ( version >= 1 )
+ {
+ c_Hue = reader.ReadInt();
+ c_Name = reader.ReadString();
+ }
+
+ c_TypeString = reader.ReadString();
+ c_ItemID = reader.ReadInt();
+ c_Location = reader.ReadPoint3D();
+ c_Map = reader.ReadMap();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Items/Houses/Monopoly/Misc/General.cs b/Scripts/Items/Houses/Monopoly/Misc/General.cs
new file mode 100644
index 0000000..cd17bf2
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/Misc/General.cs
@@ -0,0 +1,217 @@
+// Check PackUpHouse() for that crash on item delete. It causes a crash in RemoveMulti (Core)
+
+using System;
+using System.Collections;
+using Server;
+using Server.Multis;
+
+namespace Knives.TownHouses
+{
+ public class General
+ {
+ public static string Version{ get { return "2.01"; } }
+
+ // This setting determines the suggested gold value for a single square of a home
+ // which then derives price, lockdowns and secures.
+ public static int SuggestionFactor { get{ return 600; } }
+
+ // This setting determines if players need License in order to rent out their property
+ public static bool RequireRenterLicense{ get{ return false; } }
+
+ public static void Configure()
+ {
+ EventSink.WorldSave += new WorldSaveEventHandler( OnSave );
+ }
+
+ public static void Initialize()
+ {
+ EventSink.Login += new LoginEventHandler( OnLogin );
+ EventSink.Speech += new SpeechEventHandler( HandleSpeech );
+ EventSink.ServerStarted += new ServerStartedEventHandler( OnStarted );
+ }
+
+ private static void OnStarted()
+ {
+ foreach (TownHouse house in TownHouse.AllTownHouses)
+ {
+ house.InitSectorDefinition();
+ RUOVersion.UpdateRegion(house.ForSaleSign);
+ }
+ }
+
+ public static void OnSave( WorldSaveEventArgs e )
+ {
+ foreach( TownHouseSign sign in new ArrayList( TownHouseSign.AllSigns ) )
+ sign.ValidateOwnership();
+
+ foreach( TownHouse house in new ArrayList( TownHouse.AllTownHouses ) )
+ if ( house.Deleted )
+ {
+ TownHouse.AllTownHouses.Remove( house );
+ continue;
+ }
+ }
+
+ private static void OnLogin( LoginEventArgs e )
+ {
+ foreach( BaseHouse house in BaseHouse.GetHouses( e.Mobile ) )
+ if ( house is TownHouse )
+ ((TownHouse)house).ForSaleSign.CheckDemolishTimer();
+ }
+
+ private static void HandleSpeech( SpeechEventArgs e )
+ {
+ ArrayList houses = new ArrayList(BaseHouse.GetHouses( e.Mobile ));
+
+ if ( houses == null )
+ return;
+
+ foreach( BaseHouse house in houses )
+ {
+ if (!RUOVersion.RegionContains(house.Region, e.Mobile))
+ continue;
+
+ if ( house is TownHouse )
+ house.OnSpeech( e );
+
+ if ( house.Owner == e.Mobile
+ && e.Speech.ToLower() == "create rental contract"
+ && CanRent( e.Mobile, house, true ) )
+ {
+ e.Mobile.AddToBackpack( new RentalContract() );
+ e.Mobile.SendMessage( "A rental contract has been placed in your bag." );
+ }
+
+ if ( house.Owner == e.Mobile
+ && e.Speech.ToLower() == "check storage" )
+ {
+ int count = 0;
+
+ e.Mobile.SendMessage( "You have {0} lockdowns and {1} secures available.", RemainingSecures( house ), RemainingLocks( house ) );
+
+ if ( (count = AllRentalLocks( house )) != 0 )
+ e.Mobile.SendMessage( "Current rentals are using {0} of your lockdowns.", count );
+ if ( (count = AllRentalSecures( house )) != 0 )
+ e.Mobile.SendMessage( "Current rentals are using {0} of your secures.", count );
+ }
+ }
+ }
+
+ private static bool CanRent( Mobile m, BaseHouse house, bool say )
+ {
+ if ( house is TownHouse && ((TownHouse)house).ForSaleSign.PriceType != "Sale" )
+ {
+ if ( say )
+ m.SendMessage( "You must own your property to rent it." );
+
+ return false;
+ }
+
+ if ( RequireRenterLicense )
+ {
+ RentalLicense lic = m.Backpack.FindItemByType( typeof( RentalLicense ) ) as RentalLicense;
+
+ if ( lic != null && lic.Owner == null )
+ lic.Owner = m;
+
+ if ( lic == null || lic.Owner != m )
+ {
+ if ( say )
+ m.SendMessage( "You must have a renter's license to rent your property." );
+
+ return false;
+ }
+ }
+
+ if ( EntireHouseContracted( house ) )
+ {
+ if ( say )
+ m.SendMessage( "This entire house already has a rental contract." );
+
+ return false;
+ }
+
+ if ( RemainingSecures( house ) < 0 || RemainingLocks( house ) < 0 )
+ {
+ if ( say )
+ m.SendMessage( "You don't have the storage available to rent property." );
+
+ return false;
+ }
+
+ return true;
+ }
+
+ #region Rental Info
+
+ public static bool EntireHouseContracted( BaseHouse house )
+ {
+ foreach( Item item in TownHouseSign.AllSigns )
+ if ( item is RentalContract && house == ((RentalContract)item).ParentHouse )
+ if ( ((RentalContract)item).EntireHouse )
+ return true;
+
+ return false;
+ }
+
+ public static bool HasContract( BaseHouse house )
+ {
+ foreach( Item item in TownHouseSign.AllSigns )
+ if ( item is RentalContract && house == ((RentalContract)item).ParentHouse )
+ return true;
+
+ return false;
+ }
+
+ public static bool HasOtherContract( BaseHouse house, RentalContract contract )
+ {
+ foreach( Item item in TownHouseSign.AllSigns )
+ if ( item is RentalContract && item != contract && house == ((RentalContract)item).ParentHouse )
+ return true;
+
+ return false;
+ }
+
+ public static int RemainingSecures( BaseHouse house )
+ {
+ if ( house == null )
+ return 0;
+
+ int a, b, c, d;
+
+ return (Core.AOS ? house.GetAosMaxSecures() - house.GetAosCurSecures( out a, out b, out c, out d ) : house.MaxSecures - house.SecureCount) - AllRentalSecures( house );
+ }
+
+ public static int RemainingLocks( BaseHouse house )
+ {
+ if ( house == null )
+ return 0;
+
+ return (Core.AOS ? house.GetAosMaxLockdowns() - house.GetAosCurLockdowns() : house.MaxLockDowns - house.LockDownCount) - AllRentalLocks( house );
+ }
+
+ public static int AllRentalSecures( BaseHouse house )
+ {
+ int count = 0;
+
+ foreach( TownHouseSign sign in TownHouseSign.AllSigns )
+ if ( sign is RentalContract && ((RentalContract)sign).ParentHouse == house )
+ count+=sign.Secures;
+
+ return count;
+ }
+
+ public static int AllRentalLocks( BaseHouse house )
+ {
+ int count = 0;
+
+ foreach( TownHouseSign sign in TownHouseSign.AllSigns )
+ if ( sign is RentalContract && ((RentalContract)sign).ParentHouse == house )
+ count+=sign.Locks;
+
+ return count;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Items/Houses/Monopoly/Misc/GumpResponse.cs b/Scripts/Items/Houses/Monopoly/Misc/GumpResponse.cs
new file mode 100644
index 0000000..3ed1e97
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/Misc/GumpResponse.cs
@@ -0,0 +1,167 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using Server;
+using Server.Network;
+using Server.Gumps;
+
+namespace Knives.TownHouses
+{
+ public class GumpResponse
+ {
+ public static void Initialize()
+ {
+ Timer.DelayCall(TimeSpan.Zero, new TimerCallback(AfterInit));
+ }
+
+ private static void AfterInit()
+ {
+ PacketHandlers.Register(0xB1, 0, true, new OnPacketReceive(DisplayGumpResponse));
+ }
+
+ public static void DisplayGumpResponse(NetState state, PacketReader pvSrc)
+ {
+ int serial = pvSrc.ReadInt32();
+ int typeID = pvSrc.ReadInt32();
+ int buttonID = pvSrc.ReadInt32();
+
+ /* Fixed for SVN */
+ //List gumps = state.Gumps;
+ List gumps = ((List)state.Gumps);
+
+ for (int i = 0; i < gumps.Count; ++i)
+ {
+ Gump gump = gumps[i];
+
+ if (gump.Serial == serial && gump.TypeID == typeID)
+ {
+ int switchCount = pvSrc.ReadInt32();
+
+ if (switchCount < 0)
+ {
+ Console.WriteLine("Client: {0}: Invalid gump response, disconnecting...", state);
+ state.Dispose();
+ return;
+ }
+
+ int[] switches = new int[switchCount];
+
+ for (int j = 0; j < switches.Length; ++j)
+ switches[j] = pvSrc.ReadInt32();
+
+ int textCount = pvSrc.ReadInt32();
+
+ if (textCount < 0)
+ {
+ Console.WriteLine("Client: {0}: Invalid gump response, disconnecting...", state);
+ state.Dispose();
+ return;
+ }
+
+ TextRelay[] textEntries = new TextRelay[textCount];
+
+ for (int j = 0; j < textEntries.Length; ++j)
+ {
+ int entryID = pvSrc.ReadUInt16();
+ int textLength = pvSrc.ReadUInt16();
+
+ if (textLength > 239)
+ return;
+
+ string text = pvSrc.ReadUnicodeStringSafe(textLength);
+ textEntries[j] = new TextRelay(entryID, text);
+ }
+
+ state.RemoveGump(i);
+
+ if (!CheckResponse(gump, state.Mobile, buttonID))
+ return;
+
+ gump.OnResponse(state, new RelayInfo(buttonID, switches, textEntries));
+
+ return;
+ }
+ }
+ }
+
+ private static bool CheckResponse(Gump gump, Mobile m, int id)
+ {
+ if (m == null || !m.Player)
+ return true;
+
+ TownHouse th = null;
+
+ ArrayList list = new ArrayList();
+ foreach (Item item in m.GetItemsInRange(20))
+ if (item is TownHouse)
+ list.Add(item);
+
+ foreach (TownHouse t in list)
+ if (t.Owner == m)
+ {
+ th = t;
+ break;
+ }
+
+ if (th == null || th.ForSaleSign == null)
+ return true;
+
+ if (gump is HouseGumpAOS)
+ {
+ int val = id - 1;
+
+ if (val < 0)
+ return true;
+
+ int type = val % 15;
+ int index = val / 15;
+
+ if (th.ForSaleSign.ForcePublic && type == 3 && index == 12 && th.Public)
+ {
+ m.SendMessage("This house cannot be private.");
+ m.SendGump(gump);
+ return false;
+ }
+
+ if (th.ForSaleSign.ForcePrivate && type == 3 && index == 13 && !th.Public)
+ {
+ m.SendMessage("This house cannot be public.");
+ m.SendGump(gump);
+ return false;
+ }
+
+ if (th.ForSaleSign.NoTrade && type == 6 && index == 1)
+ {
+ m.SendMessage("This house cannot be traded.");
+ m.SendGump(gump);
+ return false;
+ }
+ }
+ else if (gump is HouseGump)
+ {
+ if (th.ForSaleSign.ForcePublic && id == 17 && th.Public)
+ {
+ m.SendMessage("This house cannot be private.");
+ m.SendGump(gump);
+ return false;
+ }
+
+ if (th.ForSaleSign.ForcePrivate && id == 17 && !th.Public)
+ {
+ m.SendMessage("This house cannot be public.");
+ m.SendGump(gump);
+ return false;
+ }
+
+ if (th.ForSaleSign.NoTrade && id == 14)
+ {
+ m.SendMessage("This house cannot be traded.");
+ m.SendGump(gump);
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Items/Houses/Monopoly/RUOVersion.cs b/Scripts/Items/Houses/Monopoly/RUOVersion.cs
new file mode 100644
index 0000000..92fda88
--- /dev/null
+++ b/Scripts/Items/Houses/Monopoly/RUOVersion.cs
@@ -0,0 +1,137 @@
+/*
+ * The two lines following this entry specify what RunUO version you are running.
+ * In order to switch to RunUO 1.0 Final, remove the '//' in front of that setting
+ * and add '//' in front of '#define RunUO_2_RC1'. Warning: If you comment both
+ * out, many commands in this system will not work. Enjoy!
+ */
+
+#define RunUO_2_RC1
+//#define RunUO_1_Final
+
+using System;
+using System.Collections;
+using Server;
+using Server.Multis;
+using Server.Network;
+
+#if (RunUO_2_RC1)
+ using Server.Commands;
+#endif
+
+namespace Knives.TownHouses
+{
+ public class RUOVersion
+ {
+ private static Hashtable s_Commands = new Hashtable();
+
+ public static void AddCommand(string com, AccessLevel acc, TownHouseCommandHandler cch)
+ {
+ s_Commands[com.ToLower()] = cch;
+
+ #if(RunUO_1_Final)
+ Server.Commands.Register(com, acc, new CommandEventHandler(OnCommand));
+ #elif(RunUO_2_RC1)
+ Server.Commands.CommandSystem.Register(com, acc, new CommandEventHandler(OnCommand));
+ #endif
+ }
+
+ public static void OnCommand(CommandEventArgs e)
+ {
+ if (s_Commands[e.Command.ToLower()] == null)
+ return;
+
+ ((TownHouseCommandHandler)s_Commands[e.Command.ToLower()])(new CommandInfo(e.Mobile, e.Command, e.ArgString, e.Arguments));
+ }
+
+ public static void UpdateRegion(TownHouseSign sign)
+ {
+ if (sign.House == null)
+ return;
+
+ #if(RunUO_1_Final)
+ sign.House.Region.Coords = new ArrayList(sign.Blocks);
+ sign.House.Region.MinZ = sign.MinZ;
+ sign.House.Region.MaxZ = sign.MaxZ;
+ sign.House.Region.Unregister();
+ sign.House.Region.Register();
+ sign.House.Region.GoLocation = sign.BanLoc;
+ #elif(RunUO_2_RC1)
+ sign.House.UpdateRegion();
+
+ Rectangle3D rect = new Rectangle3D(Point3D.Zero, Point3D.Zero);
+
+ for (int i = 0; i < sign.House.Region.Area.Length; ++i)
+ {
+ rect = sign.House.Region.Area[i];
+ rect = new Rectangle3D(new Point3D(rect.Start.X - sign.House.X, rect.Start.Y - sign.House.Y, sign.MinZ), new Point3D(rect.End.X - sign.House.X, rect.End.Y - sign.House.Y, sign.MaxZ));
+ sign.House.Region.Area[i] = rect;
+ }
+
+ sign.House.Region.Unregister();
+ sign.House.Region.Register();
+ sign.House.Region.GoLocation = sign.BanLoc;
+
+ #endif
+ }
+
+ public static bool RegionContains(Region region, Mobile m)
+ {
+ #if(RunUO_1_Final)
+ return region.Mobiles.Contains(m);
+ #elif(RunUO_2_RC1)
+ return region.GetMobiles().Contains(m);
+ #endif
+ }
+
+ public static Rectangle3D[] RegionArea(Region region)
+ {
+ #if(RunUO_1_Final)
+
+ Rectangle3D[] rects = new Rectangle3D[region.Coords.Count];
+ Rectangle2D rect = new Rectangle2D(Point2D.Zero, Point2D.Zero);
+
+ for (int i = 0; i < rects.Length && i < region.Coords.Count; ++i)
+ {
+ rect = (Rectangle2D)region.Coords[i];
+ rects[i] = new Rectangle3D(new Point3D(rect.Start.X, rect.Start.Y, region.MinZ), new Point3D(rect.End.X, rect.End.Y, region.MaxZ));
+ }
+
+ return rects;
+
+ #elif(RunUO_2_RC1)
+ return region.Area;
+ #endif
+ }
+ }
+
+ public class VersionHouse : BaseHouse
+ {
+ public VersionHouse(int id, Mobile m, int locks, int secures)
+ : base(id, m, locks, secures)
+ {
+ }
+
+ public override Rectangle2D[] Area { get { return new Rectangle2D[5]; } }
+
+ #if(RunUO_2_RC1)
+
+ public override Point3D BaseBanLocation { get { return Point3D.Zero; } }
+
+ #endif
+
+ public VersionHouse(Serial serial)
+ : base(serial)
+ {
+ }
+
+ public override void Serialize(GenericWriter writer)
+ {
+ base.Serialize(writer);
+ }
+
+ public override void Deserialize(GenericReader reader)
+ {
+ base.Deserialize(reader);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Items/Houses/StaticHouses/StaticHouse.cs b/Scripts/Items/Houses/StaticHouses/StaticHouse.cs
new file mode 100644
index 0000000..3ef9095
--- /dev/null
+++ b/Scripts/Items/Houses/StaticHouses/StaticHouse.cs
@@ -0,0 +1,158 @@
+using System;
+using Server;
+using Server.Multis;
+
+namespace Server.Custom.StaticHousing
+{
+ public class StaticHouse : BaseHouse
+ {
+ private Rectangle2D[] m_CustomAreas;
+ private int m_MinZ;
+ private int m_MaxZ;
+ private int m_CustomLockdowns;
+ private int m_CustomSecures;
+
+ // Dynamically computes the relative coordinates for the core engine based on all blocks
+ public override Rectangle2D[] Area
+ {
+ get
+ {
+ if (m_CustomAreas == null) return new Rectangle2D[0];
+
+ Rectangle2D[] rel = new Rectangle2D[m_CustomAreas.Length];
+ for (int i = 0; i < m_CustomAreas.Length; i++)
+ {
+ rel[i] = new Rectangle2D(
+ m_CustomAreas[i].Start.X - this.X,
+ m_CustomAreas[i].Start.Y - this.Y,
+ m_CustomAreas[i].Width,
+ m_CustomAreas[i].Height);
+ }
+ return rel;
+ }
+ }
+
+ public override Point3D BaseBanLocation
+ {
+ get
+ {
+ if (Sign != null) return new Point3D(Sign.X, Sign.Y + 1, Sign.Z);
+ return Point3D.Zero;
+ }
+ }
+
+ public override double BonusStorageScalar { get { return 1.0; } }
+
+ public StaticHouse(Mobile owner, Rectangle2D[] areas, int minZ, int maxZ, int locks, int secures, int price)
+ : base(0xA28, owner, locks, secures)
+ {
+ RestrictDecay = true;
+ Price = price;
+
+ m_CustomAreas = areas;
+ m_MinZ = minZ;
+ m_MaxZ = maxZ;
+
+ m_CustomLockdowns = locks;
+ m_CustomSecures = secures;
+
+ MaxLockDowns = locks;
+ MaxSecures = secures;
+
+ UpdateFootprint();
+ SetSign(0, 0, 0);
+ }
+
+ public StaticHouse(Serial serial) : base(serial) { }
+
+ public override int GetAosMaxLockdowns() { return m_CustomLockdowns; }
+ public override int GetAosMaxSecures() { return m_CustomSecures; }
+
+ public override bool IsInside(Point3D p, int height)
+ {
+ if (Deleted) return false;
+
+ // Z Check first
+ if (p.Z < m_MinZ || (p.Z + height) > m_MaxZ) return false;
+
+ // Loop through all defined blocks to see if they are in ANY of them
+ foreach (Rectangle2D rect in m_CustomAreas)
+ {
+ if (rect.Contains(new Point2D(p.X, p.Y)))
+ return true;
+ }
+
+ return false;
+ }
+
+ // Stretches the internal physical item bounds over the maximum extremes of all your blocks
+ private void UpdateFootprint()
+ {
+ if (m_CustomAreas == null || m_CustomAreas.Length == 0) return;
+
+ int minX = m_CustomAreas[0].Start.X;
+ int minY = m_CustomAreas[0].Start.Y;
+ int maxX = m_CustomAreas[0].End.X;
+ int maxY = m_CustomAreas[0].End.Y;
+
+ foreach (Rectangle2D rect in m_CustomAreas)
+ {
+ if (rect.Start.X < minX) minX = rect.Start.X;
+ if (rect.Start.Y < minY) minY = rect.Start.Y;
+ if (rect.End.X > maxX) maxX = rect.End.X;
+ if (rect.End.Y > maxY) maxY = rect.End.Y;
+ }
+
+ int width = maxX - minX;
+ int height = maxY - minY;
+
+ if (width < 1) width = 1;
+ if (height < 1) height = 1;
+
+ Components.Resize(width, height);
+ Components.Add(0x520, width - 1, height - 1, -5);
+ }
+
+ public override void Serialize(GenericWriter writer)
+ {
+ base.Serialize(writer);
+ writer.Write((int)1);
+
+ writer.Write(m_CustomAreas.Length);
+ for (int i = 0; i < m_CustomAreas.Length; i++)
+ writer.Write(m_CustomAreas[i]);
+
+ writer.Write(m_MinZ);
+ writer.Write(m_MaxZ);
+ writer.Write(m_CustomLockdowns);
+ writer.Write(m_CustomSecures);
+ }
+
+ public override void Deserialize(GenericReader reader)
+ {
+ base.Deserialize(reader);
+ int version = reader.ReadInt();
+
+ if (version >= 1)
+ {
+ int count = reader.ReadInt();
+ m_CustomAreas = new Rectangle2D[count];
+ for (int i = 0; i < count; i++)
+ m_CustomAreas[i] = reader.ReadRect2D();
+ }
+ else
+ {
+ m_CustomAreas = new Rectangle2D[] { reader.ReadRect2D() };
+ }
+
+ m_MinZ = reader.ReadInt();
+ m_MaxZ = reader.ReadInt();
+ m_CustomLockdowns = reader.ReadInt();
+ m_CustomSecures = reader.ReadInt();
+
+ if (Price <= 0) Price = 1;
+
+ UpdateFootprint();
+ }
+ }
+}
diff --git a/Scripts/Items/Houses/StaticHouses/StaticHouseSign.cs b/Scripts/Items/Houses/StaticHouses/StaticHouseSign.cs
new file mode 100644
index 0000000..9eef56c
--- /dev/null
+++ b/Scripts/Items/Houses/StaticHouses/StaticHouseSign.cs
@@ -0,0 +1,204 @@
+using System;
+using Server;
+using Server.Mobiles;
+using Server.Gumps;
+using Server.Network;
+using Server.Multis;
+
+namespace Server.Custom.StaticHousing
+{
+ public class StaticHouseSign : Item
+ {
+ private Rectangle2D[] m_HouseAreas;
+ private int m_MinZ;
+ private int m_MaxZ;
+ private int m_Price;
+ private int m_CustomLockdowns;
+ private int m_CustomSecures;
+
+ public Rectangle2D[] HouseAreas { get { return m_HouseAreas; } }
+ public int MinZ { get { return m_MinZ; } }
+ public int MaxZ { get { return m_MaxZ; } }
+ public int Price { get { return m_Price; } }
+ public int CustomLockdowns { get { return m_CustomLockdowns; } }
+ public int CustomSecures { get { return m_CustomSecures; } }
+
+ [Constructable]
+ public StaticHouseSign(int itemID, Rectangle2D[] areas, int minZ, int maxZ, int price, int locks, int secures) : base(itemID)
+ {
+ Name = "A Vacant House For Sale";
+ Movable = false;
+
+ m_HouseAreas = areas;
+ m_MinZ = minZ;
+ m_MaxZ = maxZ;
+ m_Price = price;
+ m_CustomLockdowns = locks;
+ m_CustomSecures = secures;
+ }
+
+ public StaticHouseSign(Serial serial) : base(serial)
+ {
+ }
+
+ public override void GetProperties(ObjectPropertyList list)
+ {
+ base.GetProperties(list);
+ list.Add(1060658, "Price\t{0} Gold", m_Price);
+ list.Add(1060659, "Lockdowns\t{0}", m_CustomLockdowns);
+ list.Add(1060660, "Secures\t{0}", m_CustomSecures);
+ }
+
+ /*public override void OnDoubleClick(Mobile from)
+ {
+ if (!from.InRange(GetWorldLocation(), 3))
+ {
+ from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045);
+ return;
+ }
+
+ if (from is PlayerMobile)
+ {
+ from.SendGump(new StaticPurchaseGump((PlayerMobile)from, this));
+ }
+ }*/
+
+ public override void OnDoubleClick(Mobile from)
+ {
+ if (!from.InRange(GetWorldLocation(), 3))
+ {
+ from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045);
+ return;
+ }
+
+ if (from is PlayerMobile)
+ {
+ if (BaseHouse.HasAccountHouse(from))
+ {
+ from.SendMessage(33, "You already own the maximum number of houses allowed on this account.");
+ return;
+ }
+
+ from.SendGump(new StaticPurchaseGump((PlayerMobile)from, this));
+ }
+ }
+
+ public void Purchase(PlayerMobile pm)
+ {
+ if (Deleted) return;
+
+ if (Banker.Withdraw(pm, m_Price))
+ {
+ StaticHouse newHouse = new StaticHouse(pm, m_HouseAreas, m_MinZ, m_MaxZ, m_CustomLockdowns, m_CustomSecures, m_Price);
+
+ // 1. Move the house controller to the exact top-left corner of the property
+ int minX = m_HouseAreas[0].Start.X;
+ int minY = m_HouseAreas[0].Start.Y;
+ foreach (Rectangle2D rect in m_HouseAreas)
+ {
+ if (rect.Start.X < minX) minX = rect.Start.X;
+ if (rect.Start.Y < minY) minY = rect.Start.Y;
+ }
+
+ Point3D houseLoc = new Point3D(minX, minY, m_MinZ);
+ newHouse.MoveToWorld(houseLoc, this.Map);
+
+ // 2. Snap the brass House Sign back and match the orientation
+ if (newHouse.Sign != null)
+ {
+ newHouse.Sign.Location = this.Location;
+
+ if (this.ItemID == 0xC0B)
+ newHouse.Sign.ItemID = 0xBD1; // East Facing
+ else
+ newHouse.Sign.ItemID = 0xBD2; // North Facing
+ }
+
+ // 3. Set the eviction drop point 1 step south of the sign
+ newHouse.BanLocation = new Point3D(this.X, this.Y + 1, this.Z);
+
+ pm.PlaySound(0x249);
+ pm.SendMessage(68, $"You have purchased this home for {m_Price} gold.");
+
+ // Destroy the "For Sale" sign now that the real house sign has spawned!
+ this.Delete();
+ }
+ else
+ {
+ pm.SendMessage(33, $"You need {m_Price} gold in your bank to purchase this home.");
+ }
+ }
+
+ public override void Serialize(GenericWriter writer)
+ {
+ base.Serialize(writer);
+ writer.Write((int)1); // Version bumped to 1 to support arrays!
+
+ writer.Write(m_HouseAreas.Length);
+ for (int i = 0; i < m_HouseAreas.Length; i++)
+ writer.Write(m_HouseAreas[i]);
+
+ writer.Write(m_MinZ);
+ writer.Write(m_MaxZ);
+ writer.Write(m_Price);
+ writer.Write(m_CustomLockdowns);
+ writer.Write(m_CustomSecures);
+ }
+
+ public override void Deserialize(GenericReader reader)
+ {
+ base.Deserialize(reader);
+ int version = reader.ReadInt();
+
+ if (version >= 1)
+ {
+ int count = reader.ReadInt();
+ m_HouseAreas = new Rectangle2D[count];
+ for (int i = 0; i < count; i++)
+ m_HouseAreas[i] = reader.ReadRect2D();
+ }
+ else
+ {
+ // Backwards compatibility for the original houses
+ m_HouseAreas = new Rectangle2D[] { reader.ReadRect2D() };
+ }
+
+ m_MinZ = reader.ReadInt();
+ m_MaxZ = reader.ReadInt();
+ m_Price = reader.ReadInt();
+ m_CustomLockdowns = reader.ReadInt();
+ m_CustomSecures = reader.ReadInt();
+ }
+
+ private class StaticPurchaseGump : Gump
+ {
+ private PlayerMobile m_Player;
+ private StaticHouseSign m_Sign;
+
+ public StaticPurchaseGump(PlayerMobile pm, StaticHouseSign sign) : base(200, 200)
+ {
+ m_Player = pm;
+ m_Sign = sign;
+
+ AddPage(0);
+ AddBackground(0, 0, 300, 150, 9270);
+ AddHtml(0, 15, 300, 20, "Purchase Property?", false, false);
+ AddHtml(20, 50, 260, 40, $"This will deduct {sign.Price} gold from your bank box.", false, false);
+
+ AddButton(40, 100, 4005, 4007, 1, GumpButtonType.Reply, 0);
+ AddHtml(75, 100, 100, 20, "Confirm", false, false);
+
+ AddButton(160, 100, 4005, 4007, 0, GumpButtonType.Reply, 0);
+ AddHtml(195, 100, 100, 20, "Cancel", false, false);
+ }
+
+ public override void OnResponse(NetState sender, RelayInfo info)
+ {
+ if (info.ButtonID == 1 && m_Sign != null && !m_Sign.Deleted)
+ {
+ m_Sign.Purchase(m_Player);
+ }
+ }
+ }
+ }
+}
diff --git a/Scripts/Items/Resources/Blacksmithing/Ore.cs b/Scripts/Items/Resources/Blacksmithing/Ore.cs
index fda62e6..4ef3246 100644
--- a/Scripts/Items/Resources/Blacksmithing/Ore.cs
+++ b/Scripts/Items/Resources/Blacksmithing/Ore.cs
@@ -20,19 +20,18 @@ namespace Server.Items
public abstract BaseIngot GetIngot();
+ public virtual int IngotsPerOre { get{ return 2; } }
+
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
-
- writer.Write( (int) 1 ); // version
-
+ writer.Write( (int) 1 );
writer.Write( (int) m_Resource );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
-
int version = reader.ReadInt();
switch ( version )
@@ -45,7 +44,6 @@ namespace Server.Items
case 0:
{
OreInfo info;
-
switch ( reader.ReadInt() )
{
case 0: info = OreInfo.Iron; break;
@@ -59,7 +57,6 @@ namespace Server.Items
case 8: info = OreInfo.Valorite; break;
default: info = null; break;
}
-
m_Resource = CraftResources.GetFromOreInfo( info );
break;
}
@@ -68,16 +65,7 @@ namespace Server.Items
private static int RandomSize()
{
- double rand = Utility.RandomDouble();
-
- if ( rand < 0.12 )
- return 0x19B7;
- else if ( rand < 0.18 )
- return 0x19B8;
- else if ( rand < 0.25 )
- return 0x19BA;
- else
- return 0x19B9;
+ return 0x19B9;
}
public BaseOre( CraftResource resource ) : this( resource, 1 )
@@ -89,7 +77,7 @@ namespace Server.Items
Stackable = true;
Amount = amount;
Hue = CraftResources.GetHue( resource );
-
+ Weight = 1.0;
m_Resource = resource;
}
@@ -100,9 +88,9 @@ namespace Server.Items
public override void AddNameProperty( ObjectPropertyList list )
{
if ( Amount > 1 )
- list.Add( 1050039, "{0}\t#{1}", Amount, 1026583 ); // ~1_NUMBER~ ~2_ITEMNAME~
+ list.Add( 1050039, "{0}\t#{1}", Amount, 1026583 );
else
- list.Add( 1026583 ); // ore
+ list.Add( 1026583 );
}
public override void GetProperties( ObjectPropertyList list )
@@ -127,7 +115,7 @@ namespace Server.Items
if ( m_Resource >= CraftResource.DullCopper && m_Resource <= CraftResource.Valorite )
return 1042845 + (int)(m_Resource - CraftResource.DullCopper);
- return 1042853; // iron ore;
+ return 1042853;
}
}
@@ -138,26 +126,110 @@ namespace Server.Items
if ( RootParent is BaseCreature )
{
- from.SendLocalizedMessage( 500447 ); // That is not accessible
+ from.SendLocalizedMessage( 500447 );
}
else if ( from.InRange( this.GetWorldLocation(), 2 ) )
{
- from.SendLocalizedMessage( 501971 ); // Select the forge on which to smelt the ore, or another pile of ore with which to combine it.
- from.Target = new InternalTarget( this );
+ from.SendLocalizedMessage( 501971 );
+
+ if ( Utility.RandomDouble() < 0.1 ) from.SendMessage("Target yourself to automatically choose a nearby target");
+
+ from.Target = new InternalTarget( this, from );
}
else
{
- from.SendLocalizedMessage( 501976 ); // The ore is too far away.
+ from.SendLocalizedMessage( 501976 );
}
}
+ public bool SmeltAll(Mobile from, object targeted)
+ {
+ if ( Deleted )
+ return false;
+
+ double difficulty;
+ switch ( m_Resource )
+ {
+ default: difficulty = 50.0; break;
+ case CraftResource.DullCopper: difficulty = 65.0; break;
+ case CraftResource.ShadowIron: difficulty = 70.0; break;
+ case CraftResource.Copper: difficulty = 75.0; break;
+ case CraftResource.Bronze: difficulty = 80.0; break;
+ case CraftResource.Gold: difficulty = 85.0; break;
+ case CraftResource.Agapite: difficulty = 90.0; break;
+ case CraftResource.Verite: difficulty = 95.0; break;
+ case CraftResource.Valorite: difficulty = 99.0; break;
+ }
+
+ double minSkill = difficulty - 25.0;
+ double maxSkill = difficulty + 25.0;
+
+ if (Resource == CraftResource.Iron)
+ {
+ minSkill = 0.0;
+ maxSkill = 75.0;
+ }
+
+ if (Resource == CraftResource.Iron)
+ maxSkill = 65.0 + 10.0;
+
+ if ( difficulty > 50.0 && difficulty > from.Skills[SkillName.Mining].Value || from.Skills[SkillName.Mining].Value < minSkill)
+ {
+ from.SendLocalizedMessage( 501986 );
+ return false;
+ }
+
+ int lost = 0;
+ int remaining = Amount;
+
+ while(0 < remaining)
+ {
+ if (maxSkill < from.Skills[SkillName.Mining].Value) break;
+
+ if (!from.CheckTargetSkill(SkillName.Mining, targeted, minSkill, maxSkill))
+ lost++;
+
+ remaining--;
+ }
+
+ from.PlaySound( 0x2B );
+
+ int ingots = Amount - lost;
+
+ if (0 < lost)
+ {
+ from.SendLocalizedMessage( 501990 ); // You burn away the impurities but are left with less useable metal.
+ }
+ else
+ {
+ from.SendLocalizedMessage( 501988 ); // You smelt the ore removing the impurities and put the metal in your backpack.
+ }
+
+ if (0 < ingots)
+ {
+ BaseIngot ingot = GetIngot();
+ Delete();
+
+ ingot.Amount = ingots * IngotsPerOre;
+ from.AddToBackpack(ingot);
+ }
+ else
+ {
+ Delete();
+ }
+
+ return true;
+ }
+
private class InternalTarget : Target
{
- private BaseOre m_Ore;
+ private readonly BaseOre m_Ore;
+ private readonly Mobile m_From;
- public InternalTarget( BaseOre ore ) : base ( 2, false, TargetFlags.None )
+ public InternalTarget( BaseOre ore, Mobile from ) : base ( 2, false, TargetFlags.None )
{
m_Ore = ore;
+ m_From = from;
}
private bool IsForge( object obj )
@@ -178,193 +250,52 @@ namespace Server.Items
return ( itemID == 4017 || (itemID >= 6522 && itemID <= 6569) );
}
+ private bool UseNearbyForge(Mobile from, int range)
+ {
+ if (from.Map == null) return false;
+
+ IPooledEnumerable eable = from.Map.GetItemsInRange(from.Location, range);
+ foreach (Item item in eable)
+ {
+ if (IsForge(item))
+ {
+ eable.Free();
+ return true;
+ }
+ }
+ eable.Free();
+
+ for (int x = -range; x <= range; ++x)
+ {
+ for (int y = -range; y <= range; ++y)
+ {
+ Server.StaticTile[] tiles = from.Map.Tiles.GetStaticTiles(from.X + x, from.Y + y, true);
+ for (int i = 0; i < tiles.Length; ++i)
+ {
+ int id = tiles[i].ID & 0x3FFF;
+ if (id == 4017 || (id >= 6522 && id <= 6569))
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
protected override void OnTarget( Mobile from, object targeted )
{
- if ( m_Ore.Deleted )
- return;
-
if ( !from.InRange( m_Ore.GetWorldLocation(), 2 ) )
{
from.SendLocalizedMessage( 501976 ); // The ore is too far away.
return;
}
-
- #region Combine Ore
- if ( targeted is BaseOre )
+
+ if ( !IsForge( targeted ) && false == ( targeted == m_From && UseNearbyForge( from, Range ) ) )
{
- BaseOre ore = (BaseOre)targeted;
-
- if ( !ore.Movable )
- {
- return;
- }
- else if ( m_Ore == ore )
- {
- from.SendLocalizedMessage( 501972 ); // Select another pile or ore with which to combine this.
- from.Target = new InternalTarget( ore );
- return;
- }
- else if ( ore.Resource != m_Ore.Resource )
- {
- from.SendLocalizedMessage( 501979 ); // You cannot combine ores of different metals.
- return;
- }
-
- int worth = ore.Amount;
-
- if ( ore.ItemID == 0x19B9 )
- worth *= 8;
- else if ( ore.ItemID == 0x19B7 )
- worth *= 2;
- else
- worth *= 4;
-
- int sourceWorth = m_Ore.Amount;
-
- if ( m_Ore.ItemID == 0x19B9 )
- sourceWorth *= 8;
- else if ( m_Ore.ItemID == 0x19B7 )
- sourceWorth *= 2;
- else
- sourceWorth *= 4;
-
- worth += sourceWorth;
-
- int plusWeight = 0;
- int newID = ore.ItemID;
-
- if ( ore.DefaultWeight != m_Ore.DefaultWeight )
- {
- if ( ore.ItemID == 0x19B7 || m_Ore.ItemID == 0x19B7 )
- {
- newID = 0x19B7;
- }
- else if ( ore.ItemID == 0x19B9 )
- {
- newID = m_Ore.ItemID;
- plusWeight = ore.Amount * 2;
- }
- else
- {
- plusWeight = m_Ore.Amount * 2;
- }
- }
-
- if ( ( ore.ItemID == 0x19B9 && worth > 120000 ) || ( ( ore.ItemID == 0x19B8 || ore.ItemID == 0x19BA ) && worth > 60000 ) || ( ore.ItemID == 0x19B7 && worth > 30000 ) )
- {
- from.SendLocalizedMessage( 1062844 ); // There is too much ore to combine.
- return;
- }
- else if ( ore.RootParent is Mobile && ( plusWeight + ((Mobile)ore.RootParent).Backpack.TotalWeight ) > ((Mobile)ore.RootParent).Backpack.MaxWeight )
- {
- from.SendLocalizedMessage( 501978 ); // The weight is too great to combine in a container.
- return;
- }
-
- ore.ItemID = newID;
-
- if ( ore.ItemID == 0x19B9 )
- ore.Amount = worth / 8;
- else if ( ore.ItemID == 0x19B7 )
- ore.Amount = worth / 2;
- else
- ore.Amount = worth / 4;
-
- m_Ore.Delete();
+ from.SendMessage("That is not a forge.");
return;
}
- #endregion
- if ( IsForge( targeted ) )
- {
- double difficulty;
-
- switch ( m_Ore.Resource )
- {
- default: difficulty = 50.0; break;
- case CraftResource.DullCopper: difficulty = 65.0; break;
- case CraftResource.ShadowIron: difficulty = 70.0; break;
- case CraftResource.Copper: difficulty = 75.0; break;
- case CraftResource.Bronze: difficulty = 80.0; break;
- case CraftResource.Gold: difficulty = 85.0; break;
- case CraftResource.Agapite: difficulty = 90.0; break;
- case CraftResource.Verite: difficulty = 95.0; break;
- case CraftResource.Valorite: difficulty = 99.0; break;
- }
-
- double minSkill = difficulty - 25.0;
- double maxSkill = difficulty + 25.0;
-
- if ( difficulty > 50.0 && difficulty > from.Skills[SkillName.Mining].Value )
- {
- from.SendLocalizedMessage( 501986 ); // You have no idea how to smelt this strange ore!
- return;
- }
-
- if ( m_Ore.ItemID == 0x19B7 && m_Ore.Amount < 2 )
- {
- from.SendLocalizedMessage( 501987 ); // There is not enough metal-bearing ore in this pile to make an ingot.
- return;
- }
-
- if ( from.CheckTargetSkill( SkillName.Mining, targeted, minSkill, maxSkill ) )
- {
- int toConsume = m_Ore.Amount;
-
- if ( toConsume <= 0 )
- {
- from.SendLocalizedMessage( 501987 ); // There is not enough metal-bearing ore in this pile to make an ingot.
- }
- else
- {
- if ( toConsume > 30000 )
- toConsume = 30000;
-
- int ingotAmount;
-
- if ( m_Ore.ItemID == 0x19B7 )
- {
- ingotAmount = toConsume / 2;
-
- if ( toConsume % 2 != 0 )
- --toConsume;
- }
- else if ( m_Ore.ItemID == 0x19B9 )
- {
- ingotAmount = toConsume * 2;
- }
- else
- {
- ingotAmount = toConsume;
- }
-
- BaseIngot ingot = m_Ore.GetIngot();
- ingot.Amount = ingotAmount;
-
- m_Ore.Consume( toConsume );
- from.AddToBackpack( ingot );
- //from.PlaySound( 0x57 );
-
- from.SendLocalizedMessage( 501988 ); // You smelt the ore removing the impurities and put the metal in your backpack.
- }
- }
- else
- {
- if ( m_Ore.Amount < 2 )
- {
- if ( m_Ore.ItemID == 0x19B9 )
- m_Ore.ItemID = 0x19B8;
- else
- m_Ore.ItemID = 0x19B7;
- }
- else
- {
- m_Ore.Amount /= 2;
- }
-
- from.SendLocalizedMessage( 501990 ); // You burn away the impurities but are left with less useable metal.
- }
- }
+ m_Ore.SmeltAll(from, targeted);
}
}
}
@@ -698,4 +629,4 @@ namespace Server.Items
return new ValoriteIngot();
}
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Items/Skill Items/Magical/NecromancerSpellbook.cs b/Scripts/Items/Skill Items/Magical/NecromancerSpellbook.cs
index 7dae771..c8415a6 100644
--- a/Scripts/Items/Skill Items/Magical/NecromancerSpellbook.cs
+++ b/Scripts/Items/Skill Items/Magical/NecromancerSpellbook.cs
@@ -18,7 +18,8 @@ namespace Server.Items
[Constructable]
public NecromancerSpellbook( ulong content ) : base( content, 0x2253 )
{
- Layer = (Core.ML ? Layer.OneHanded : Layer.Invalid);
+ //Layer = (Core.ML ? Layer.OneHanded : Layer.Invalid);
+ Layer = Layer.OneHanded;
}
public NecromancerSpellbook( Serial serial ) : base( serial )
@@ -38,8 +39,8 @@ namespace Server.Items
int version = reader.ReadInt();
- if( version == 0 && Core.ML )
- Layer = Layer.OneHanded;
+ //if( version == 0 && Core.ML )
+ Layer = Layer.OneHanded;
}
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Items/Skill Items/Misc/Bandage.cs b/Scripts/Items/Skill Items/Misc/Bandage.cs
index fc05623..3dfbd8c 100644
--- a/Scripts/Items/Skill Items/Misc/Bandage.cs
+++ b/Scripts/Items/Skill Items/Misc/Bandage.cs
@@ -198,6 +198,7 @@ namespace Server.Items
m_Timer.Stop();
m_Timer = null;
+ BuffInfo.RemoveBuff(m_Healer, BuffIcon.GiftOfRenewal);
}
private static Dictionary m_Table = new Dictionary();
@@ -547,10 +548,18 @@ namespace Server.Items
patient.SendLocalizedMessage( 1008078, false, healer.Name ); // : Attempting to heal you.
healer.SendLocalizedMessage( 500956 ); // You begin applying the bandages.
+ BuffInfo.AddBuff(healer, new BuffInfo(
+ BuffIcon.GiftOfRenewal,
+ 1002082, // Cliloc Title
+ 1002082, // Cliloc Description
+ TimeSpan.FromMilliseconds(seconds),
+ healer,
+ patient.Name
+ ));
return context;
}
return null;
}
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Items/Traps/BaseTrap.cs b/Scripts/Items/Traps/BaseTrap.cs
index 98a599d..2429ba2 100644
--- a/Scripts/Items/Traps/BaseTrap.cs
+++ b/Scripts/Items/Traps/BaseTrap.cs
@@ -15,7 +15,7 @@ namespace Server.Items
{
}
- public override bool HandlesOnMovement{ get{ return true; } } // Tell the core that we implement OnMovement
+ public override bool HandlesOnMovement{ get{ return true; } }
public virtual int GetEffectHue()
{
@@ -38,24 +38,39 @@ namespace Server.Items
&& Utility.InRange( GetWorldLocation(), loc, range );
}
- public override void OnMovement( Mobile m, Point3D oldLocation )
+ public override void OnMovement( Mobile m, Point3D oldLocation )
{
base.OnMovement( m, oldLocation );
if ( m.Location == oldLocation )
return;
- if ( CheckRange( m.Location, oldLocation, 0 ) && DateTime.UtcNow >= m_NextActiveTrigger )
- {
- m_NextActiveTrigger = m_NextPassiveTrigger = DateTime.UtcNow + ResetDelay;
+ bool activeTrigger = CheckRange( m.Location, oldLocation, 0 ) && DateTime.UtcNow >= m_NextActiveTrigger;
+ bool passiveTrigger = !activeTrigger && PassivelyTriggered && CheckRange( m.Location, oldLocation, PassiveTriggerRange ) && DateTime.UtcNow >= m_NextPassiveTrigger;
- OnTrigger( m );
- }
- else if ( PassivelyTriggered && CheckRange( m.Location, oldLocation, PassiveTriggerRange ) && DateTime.UtcNow >= m_NextPassiveTrigger )
+ if ( activeTrigger || passiveTrigger )
{
- m_NextPassiveTrigger = DateTime.UtcNow + PassiveTriggerDelay;
+ if ( m.Alive && m.AccessLevel == AccessLevel.Player )
+ {
+ // m.CheckSkill parameters: (SkillName, Minimum Skill to attempt, Maximum Skill to gain)
+ // This single line calculates their dodge chance AND tells the server to roll for a skill gain!
+ if ( m.CheckSkill( SkillName.RemoveTrap, 0.0, 120.0 ) )
+ {
+ m.SendMessage( 63, "You notice a hidden trap and carefully step around it." );
+ return;
+ }
+ }
- OnTrigger( m );
+ if ( activeTrigger )
+ {
+ m_NextActiveTrigger = m_NextPassiveTrigger = DateTime.UtcNow + ResetDelay;
+ OnTrigger( m );
+ }
+ else if ( passiveTrigger )
+ {
+ m_NextPassiveTrigger = DateTime.UtcNow + PassiveTriggerDelay;
+ OnTrigger( m );
+ }
}
}
@@ -82,4 +97,4 @@ namespace Server.Items
int version = reader.ReadInt();
}
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Misc/BuffIcons.cs b/Scripts/Misc/BuffIcons.cs
index 6da8057..998c13f 100644
--- a/Scripts/Misc/BuffIcons.cs
+++ b/Scripts/Misc/BuffIcons.cs
@@ -8,7 +8,7 @@ namespace Server
{
public class BuffInfo
{
- public static bool Enabled { get { return Core.ML; } }
+ public static bool Enabled { get { return true; } }
public static void Initialize()
{
diff --git a/Scripts/Misc/CharacterCreation.cs b/Scripts/Misc/CharacterCreation.cs
index c1ce145..b61bffb 100644
--- a/Scripts/Misc/CharacterCreation.cs
+++ b/Scripts/Misc/CharacterCreation.cs
@@ -29,9 +29,10 @@ namespace Server.Misc
PackItem( new RedBook( "a book", m.Name, 20, true ) );
if (ValidSettings.StartingGold() > 0)
- PackItem( new Gold( ValidSettings.StartingGold() ) ); // Starting gold can be customized here
+ PackItem( new Gold( ValidSettings.StartingGold() ) );
PackItem( new Dagger() );
PackItem( new Candle() );
+ PackItem( new Scissors() );
}
private static Item MakeNewbie( Item item )
@@ -59,488 +60,6 @@ namespace Server.Misc
return MakeNewbie( keg );
}
- private static void FillBankAOS( Mobile m )
- {
- BankBox bank = m.BankBox;
-
- // The new AOS bankboxes don't have powerscrolls, they are automatically 'applied':
-
- for ( int i = 0; i < PowerScroll.Skills.Count; ++i )
- m.Skills[PowerScroll.Skills[ i ]].Cap = 120.0;
-
- m.StatCap = 250;
-
-
- Container cont;
-
-
- // Begin box of money
- cont = new WoodenBox();
- cont.ItemID = 0xE7D;
- cont.Hue = 0x489;
-
- PlaceItemIn( cont, 16, 51, new BankCheck( 500000 ) );
- PlaceItemIn( cont, 28, 51, new BankCheck( 250000 ) );
- PlaceItemIn( cont, 40, 51, new BankCheck( 100000 ) );
- PlaceItemIn( cont, 52, 51, new BankCheck( 100000 ) );
- PlaceItemIn( cont, 64, 51, new BankCheck( 50000 ) );
-
- PlaceItemIn( cont, 16, 115, new Factions.Silver( 9000 ) );
- PlaceItemIn( cont, 34, 115, new Gold( 60000 ) );
-
- PlaceItemIn( bank, 18, 169, cont );
- // End box of money
-
-
- // Begin bag of potion kegs
- cont = new Backpack();
- cont.Name = "Various Potion Kegs";
-
- PlaceItemIn( cont, 45, 149, MakePotionKeg( PotionEffect.CureGreater, 0x2D ) );
- PlaceItemIn( cont, 69, 149, MakePotionKeg( PotionEffect.HealGreater, 0x499 ) );
- PlaceItemIn( cont, 93, 149, MakePotionKeg( PotionEffect.PoisonDeadly, 0x46 ) );
- PlaceItemIn( cont, 117, 149, MakePotionKeg( PotionEffect.RefreshTotal, 0x21 ) );
- PlaceItemIn( cont, 141, 149, MakePotionKeg( PotionEffect.ExplosionGreater, 0x74 ) );
-
- PlaceItemIn( cont, 93, 82, new Bottle( 1000 ) );
-
- PlaceItemIn( bank, 53, 169, cont );
- // End bag of potion kegs
-
-
- // Begin bag of tools
- cont = new Bag();
- cont.Name = "Tool Bag";
-
- PlaceItemIn( cont, 30, 35, new TinkerTools( 1000 ) );
- PlaceItemIn( cont, 60, 35, new HousePlacementTool() );
- PlaceItemIn( cont, 90, 35, new DovetailSaw( 1000 ) );
- PlaceItemIn( cont, 30, 68, new Scissors() );
- PlaceItemIn( cont, 45, 68, new MortarPestle( 1000 ) );
- PlaceItemIn( cont, 75, 68, new ScribesPen( 1000 ) );
- PlaceItemIn( cont, 90, 68, new SmithHammer( 1000 ) );
- PlaceItemIn( cont, 30, 118, new TwoHandedAxe() );
- PlaceItemIn( cont, 60, 118, new FletcherTools( 1000 ) );
- PlaceItemIn( cont, 90, 118, new SewingKit( 1000 ) );
-
- PlaceItemIn( cont, 36, 51, new RunicHammer( CraftResource.DullCopper, 1000 ) );
- PlaceItemIn( cont, 42, 51, new RunicHammer( CraftResource.ShadowIron, 1000 ) );
- PlaceItemIn( cont, 48, 51, new RunicHammer( CraftResource.Copper, 1000 ) );
- PlaceItemIn( cont, 54, 51, new RunicHammer( CraftResource.Bronze, 1000 ) );
- PlaceItemIn( cont, 61, 51, new RunicHammer( CraftResource.Gold, 1000 ) );
- PlaceItemIn( cont, 67, 51, new RunicHammer( CraftResource.Agapite, 1000 ) );
- PlaceItemIn( cont, 73, 51, new RunicHammer( CraftResource.Verite, 1000 ) );
- PlaceItemIn( cont, 79, 51, new RunicHammer( CraftResource.Valorite, 1000 ) );
-
- PlaceItemIn( cont, 36, 55, new RunicSewingKit( CraftResource.SpinedLeather, 1000 ) );
- PlaceItemIn( cont, 42, 55, new RunicSewingKit( CraftResource.HornedLeather, 1000 ) );
- PlaceItemIn( cont, 48, 55, new RunicSewingKit( CraftResource.BarbedLeather, 1000 ) );
-
- PlaceItemIn( bank, 118, 169, cont );
- // End bag of tools
-
-
- // Begin bag of archery ammo
- cont = new Bag();
- cont.Name = "Bag Of Archery Ammo";
-
- PlaceItemIn( cont, 48, 76, new Arrow( 5000 ) );
- PlaceItemIn( cont, 72, 76, new Bolt( 5000 ) );
-
- PlaceItemIn( bank, 118, 124, cont );
- // End bag of archery ammo
-
-
- // Begin bag of treasure maps
- cont = new Bag();
- cont.Name = "Bag Of Treasure Maps";
-
- PlaceItemIn( cont, 30, 35, new TreasureMap( 1, Map.Trammel ) );
- PlaceItemIn( cont, 45, 35, new TreasureMap( 2, Map.Trammel ) );
- PlaceItemIn( cont, 60, 35, new TreasureMap( 3, Map.Trammel ) );
- PlaceItemIn( cont, 75, 35, new TreasureMap( 4, Map.Trammel ) );
- PlaceItemIn( cont, 90, 35, new TreasureMap( 5, Map.Trammel ) );
- PlaceItemIn( cont, 90, 35, new TreasureMap( 6, Map.Trammel ) );
-
- PlaceItemIn( cont, 30, 50, new TreasureMap( 1, Map.Trammel ) );
- PlaceItemIn( cont, 45, 50, new TreasureMap( 2, Map.Trammel ) );
- PlaceItemIn( cont, 60, 50, new TreasureMap( 3, Map.Trammel ) );
- PlaceItemIn( cont, 75, 50, new TreasureMap( 4, Map.Trammel ) );
- PlaceItemIn( cont, 90, 50, new TreasureMap( 5, Map.Trammel ) );
- PlaceItemIn( cont, 90, 50, new TreasureMap( 6, Map.Trammel ) );
-
- PlaceItemIn( cont, 55, 100, new Lockpick( 30 ) );
- PlaceItemIn( cont, 60, 100, new Pickaxe() );
-
- PlaceItemIn( bank, 98, 124, cont );
- // End bag of treasure maps
-
-
- // Begin bag of raw materials
- cont = new Bag();
- cont.Hue = 0x835;
- cont.Name = "Raw Materials Bag";
-
- PlaceItemIn( cont, 92, 60, new BarbedLeather( 5000 ) );
- PlaceItemIn( cont, 92, 68, new HornedLeather( 5000 ) );
- PlaceItemIn( cont, 92, 76, new SpinedLeather( 5000 ) );
- PlaceItemIn( cont, 92, 84, new Leather( 5000 ) );
-
- PlaceItemIn( cont, 30, 118, new Cloth( 5000 ) );
- PlaceItemIn( cont, 30, 84, new Board( 5000 ) );
- PlaceItemIn( cont, 57, 80, new BlankScroll( 500 ) );
-
- PlaceItemIn( cont, 30, 35, new DullCopperIngot( 5000 ) );
- PlaceItemIn( cont, 37, 35, new ShadowIronIngot( 5000 ) );
- PlaceItemIn( cont, 44, 35, new CopperIngot( 5000 ) );
- PlaceItemIn( cont, 51, 35, new BronzeIngot( 5000 ) );
- PlaceItemIn( cont, 58, 35, new GoldIngot( 5000 ) );
- PlaceItemIn( cont, 65, 35, new AgapiteIngot( 5000 ) );
- PlaceItemIn( cont, 72, 35, new VeriteIngot( 5000 ) );
- PlaceItemIn( cont, 79, 35, new ValoriteIngot( 5000 ) );
- PlaceItemIn( cont, 86, 35, new IronIngot( 5000 ) );
-
- PlaceItemIn( cont, 30, 59, new RedScales( 5000 ) );
- PlaceItemIn( cont, 36, 59, new YellowScales( 5000 ) );
- PlaceItemIn( cont, 42, 59, new BlackScales( 5000 ) );
- PlaceItemIn( cont, 48, 59, new GreenScales( 5000 ) );
- PlaceItemIn( cont, 54, 59, new WhiteScales( 5000 ) );
- PlaceItemIn( cont, 60, 59, new BlueScales( 5000 ) );
-
- PlaceItemIn( bank, 98, 169, cont );
- // End bag of raw materials
-
-
- // Begin bag of spell casting stuff
- cont = new Backpack();
- cont.Hue = 0x480;
- cont.Name = "Spell Casting Stuff";
-
- PlaceItemIn( cont, 45, 105, new Spellbook( UInt64.MaxValue ) );
- PlaceItemIn( cont, 65, 105, new NecromancerSpellbook( (UInt64)0xFFFF ) );
- PlaceItemIn( cont, 85, 105, new BookOfChivalry( (UInt64)0x3FF ) );
- PlaceItemIn( cont, 105, 105, new BookOfBushido() ); //Default ctor = full
- PlaceItemIn( cont, 125, 105, new BookOfNinjitsu() ); //Default ctor = full
-
- Runebook runebook = new Runebook( 10 );
- runebook.CurCharges = runebook.MaxCharges;
- PlaceItemIn( cont, 145, 105, runebook );
-
- Item toHue = new BagOfReagents( 150 );
- toHue.Hue = 0x2D;
- PlaceItemIn( cont, 45, 150, toHue );
-
- toHue = new BagOfNecroReagents( 150 );
- toHue.Hue = 0x488;
- PlaceItemIn( cont, 65, 150, toHue );
-
- PlaceItemIn( cont, 140, 150, new BagOfAllReagents( 500 ) );
-
- for ( int i = 0; i < 9; ++i )
- PlaceItemIn( cont, 45 + (i * 10), 75, new RecallRune() );
-
- PlaceItemIn( cont, 141, 74, new FireHorn() );
-
- PlaceItemIn( bank, 78, 169, cont );
- // End bag of spell casting stuff
-
-
- // Begin bag of ethereals
- cont = new Backpack();
- cont.Hue = 0x490;
- cont.Name = "Bag Of Ethy's!";
-
- PlaceItemIn( cont, 45, 66, new EtherealHorse() );
- PlaceItemIn( cont, 69, 82, new EtherealOstard() );
- PlaceItemIn( cont, 93, 99, new EtherealLlama() );
- PlaceItemIn( cont, 117, 115, new EtherealKirin() );
- PlaceItemIn( cont, 45, 132, new EtherealUnicorn() );
- PlaceItemIn( cont, 69, 66, new EtherealRidgeback() );
- PlaceItemIn( cont, 93, 82, new EtherealSwampDragon() );
- PlaceItemIn( cont, 117, 99, new EtherealBeetle() );
-
- PlaceItemIn( bank, 38, 124, cont );
- // End bag of ethereals
-
-
- // Begin first bag of artifacts
- cont = new Backpack();
- cont.Hue = 0x48F;
- cont.Name = "Bag of Artifacts";
-
- PlaceItemIn( cont, 45, 66, new TitansHammer() );
- PlaceItemIn( cont, 69, 82, new InquisitorsResolution() );
- PlaceItemIn( cont, 93, 99, new BladeOfTheRighteous() );
- PlaceItemIn( cont, 117, 115, new ZyronicClaw() );
-
- PlaceItemIn( bank, 58, 124, cont );
- // End first bag of artifacts
-
-
- // Begin second bag of artifacts
- cont = new Backpack();
- cont.Hue = 0x48F;
- cont.Name = "Bag of Artifacts";
-
- PlaceItemIn( cont, 45, 66, new GauntletsOfNobility() );
- PlaceItemIn( cont, 69, 82, new MidnightBracers() );
- PlaceItemIn( cont, 93, 99, new VoiceOfTheFallenKing() );
- PlaceItemIn( cont, 117, 115, new OrnateCrownOfTheHarrower() );
- PlaceItemIn( cont, 45, 132, new HelmOfInsight() );
- PlaceItemIn( cont, 69, 66, new HolyKnightsBreastplate() );
- PlaceItemIn( cont, 93, 82, new ArmorOfFortune() );
- PlaceItemIn( cont, 117, 99, new TunicOfFire() );
- PlaceItemIn( cont, 45, 115, new LeggingsOfBane() );
- PlaceItemIn( cont, 69, 132, new ArcaneShield() );
- PlaceItemIn( cont, 93, 66, new Aegis() );
- PlaceItemIn( cont, 117, 82, new RingOfTheVile() );
- PlaceItemIn( cont, 45, 99, new BraceletOfHealth() );
- PlaceItemIn( cont, 69, 115, new RingOfTheElements() );
- PlaceItemIn( cont, 93, 132, new OrnamentOfTheMagician() );
- PlaceItemIn( cont, 117, 66, new DivineCountenance() );
- PlaceItemIn( cont, 45, 82, new JackalsCollar() );
- PlaceItemIn( cont, 69, 99, new HuntersHeaddress() );
- PlaceItemIn( cont, 93, 115, new HatOfTheMagi() );
- PlaceItemIn( cont, 117, 132, new ShadowDancerLeggings() );
- PlaceItemIn( cont, 45, 66, new SpiritOfTheTotem() );
- PlaceItemIn( cont, 69, 82, new BladeOfInsanity() );
- PlaceItemIn( cont, 93, 99, new AxeOfTheHeavens() );
- PlaceItemIn( cont, 117, 115, new TheBeserkersMaul() );
- PlaceItemIn( cont, 45, 132, new Frostbringer() );
- PlaceItemIn( cont, 69, 66, new BreathOfTheDead() );
- PlaceItemIn( cont, 93, 82, new TheDragonSlayer() );
- PlaceItemIn( cont, 117, 99, new BoneCrusher() );
- PlaceItemIn( cont, 45, 115, new StaffOfTheMagi() );
- PlaceItemIn( cont, 69, 132, new SerpentsFang() );
- PlaceItemIn( cont, 93, 66, new LegacyOfTheDreadLord() );
- PlaceItemIn( cont, 117, 82, new TheTaskmaster() );
- PlaceItemIn( cont, 45, 99, new TheDryadBow() );
-
- PlaceItemIn( bank, 78, 124, cont );
- // End second bag of artifacts
-
- // Begin bag of minor artifacts
- cont = new Backpack();
- cont.Hue = 0x48F;
- cont.Name = "Bag of Minor Artifacts";
-
-
- PlaceItemIn( cont, 45, 66, new LunaLance() );
- PlaceItemIn( cont, 69, 82, new VioletCourage() );
- PlaceItemIn( cont, 93, 99, new CavortingClub() );
- PlaceItemIn( cont, 117, 115, new CaptainQuacklebushsCutlass() );
- PlaceItemIn( cont, 45, 132, new NightsKiss() );
- PlaceItemIn( cont, 69, 66, new ShipModelOfTheHMSCape() );
- PlaceItemIn( cont, 93, 82, new AdmiralsHeartyRum() );
- PlaceItemIn( cont, 117, 99, new CandelabraOfSouls() );
- PlaceItemIn( cont, 45, 115, new IolosLute() );
- PlaceItemIn( cont, 69, 132, new GwennosHarp() );
- PlaceItemIn( cont, 93, 66, new ArcticDeathDealer() );
- PlaceItemIn( cont, 117, 82, new EnchantedTitanLegBone() );
- PlaceItemIn( cont, 45, 99, new NoxRangersHeavyCrossbow() );
- PlaceItemIn( cont, 69, 115, new BlazeOfDeath() );
- PlaceItemIn( cont, 93, 132, new DreadPirateHat() );
- PlaceItemIn( cont, 117, 66, new BurglarsBandana() );
- PlaceItemIn( cont, 45, 82, new GoldBricks() );
- PlaceItemIn( cont, 69, 99, new AlchemistsBauble() );
- PlaceItemIn( cont, 93, 115, new PhillipsWoodenSteed() );
- PlaceItemIn( cont, 117, 132, new PolarBearMask() );
- PlaceItemIn( cont, 45, 66, new BowOfTheJukaKing() );
- PlaceItemIn( cont, 69, 82, new GlovesOfThePugilist() );
- PlaceItemIn( cont, 93, 99, new OrcishVisage() );
- PlaceItemIn( cont, 117, 115, new StaffOfPower() );
- PlaceItemIn( cont, 45, 132, new ShieldOfInvulnerability() );
- PlaceItemIn( cont, 69, 66, new HeartOfTheLion() );
- PlaceItemIn( cont, 93, 82, new ColdBlood() );
- PlaceItemIn( cont, 117, 99, new GhostShipAnchor() );
- PlaceItemIn( cont, 45, 115, new SeahorseStatuette() );
- PlaceItemIn( cont, 69, 132, new WrathOfTheDryad() );
- PlaceItemIn( cont, 93, 66, new PixieSwatter() );
-
- for( int i = 0; i < 10; i++ )
- PlaceItemIn( cont, 117, 128, new MessageInABottle( Utility.RandomBool() ? Map.Trammel : Map.Felucca, 4 ) );
-
- PlaceItemIn( bank, 18, 124, cont );
-
- if( Core.SE )
- {
- cont = new Bag();
- cont.Hue = 0x501;
- cont.Name = "Tokuno Minor Artifacts";
-
- PlaceItemIn( cont, 42, 70, new Exiler() );
- PlaceItemIn( cont, 38, 53, new HanzosBow() );
- PlaceItemIn( cont, 45, 40, new TheDestroyer() );
- PlaceItemIn( cont, 92, 80, new DragonNunchaku() );
- PlaceItemIn( cont, 42, 56, new PeasantsBokuto() );
- PlaceItemIn( cont, 44, 71, new TomeOfEnlightenment() );
- PlaceItemIn( cont, 35, 35, new ChestOfHeirlooms() );
- PlaceItemIn( cont, 29, 0, new HonorableSwords() );
- PlaceItemIn( cont, 49, 85, new AncientUrn() );
- PlaceItemIn( cont, 51, 58, new FluteOfRenewal() );
- PlaceItemIn( cont, 70, 51, new PigmentsOfTokuno() );
- PlaceItemIn( cont, 40, 79, new AncientSamuraiDo() );
- PlaceItemIn( cont, 51, 61, new LegsOfStability() );
- PlaceItemIn( cont, 88, 78, new GlovesOfTheSun() );
- PlaceItemIn( cont, 55, 62, new AncientFarmersKasa() );
- PlaceItemIn( cont, 55, 83, new ArmsOfTacticalExcellence() );
- PlaceItemIn( cont, 50, 85, new DaimyosHelm() );
- PlaceItemIn( cont, 52, 78, new BlackLotusHood() );
- PlaceItemIn( cont, 52, 79, new DemonForks() );
- PlaceItemIn( cont, 33, 49, new PilferedDancerFans() );
-
- PlaceItemIn( bank, 58, 124, cont );
- }
-
- if( Core.SE ) //This bag came only after SE.
- {
- cont = new Bag();
- cont.Name = "Bag of Bows";
-
- PlaceItemIn( cont, 31, 84, new Bow() );
- PlaceItemIn( cont, 78, 74, new CompositeBow() );
- PlaceItemIn( cont, 53, 71, new Crossbow() );
- PlaceItemIn( cont, 56, 39, new HeavyCrossbow() );
- PlaceItemIn( cont, 82, 72, new RepeatingCrossbow() );
- PlaceItemIn( cont, 49, 45, new Yumi() );
-
- for( int i = 0; i < cont.Items.Count; i++ )
- {
- BaseRanged bow = cont.Items[i] as BaseRanged;
-
- if( bow != null )
- {
- bow.Attributes.WeaponSpeed = 35;
- bow.Attributes.WeaponDamage = 35;
- }
- }
-
- PlaceItemIn( bank, 108, 135, cont );
- }
- }
-
- private static void FillBankbox( Mobile m )
- {
- if ( Core.AOS )
- {
- FillBankAOS( m );
- return;
- }
-
- BankBox bank = m.BankBox;
-
- bank.DropItem( new BankCheck( 1000000 ) );
-
- // Full spellbook
- Spellbook book = new Spellbook();
-
- book.Content = ulong.MaxValue;
-
- bank.DropItem( book );
-
- Bag bag = new Bag();
-
- for ( int i = 0; i < 5; ++i )
- bag.DropItem( new Moonstone( MoonstoneType.Felucca ) );
-
- // Felucca moonstones
- bank.DropItem( bag );
-
- bag = new Bag();
-
- for ( int i = 0; i < 5; ++i )
- bag.DropItem( new Moonstone( MoonstoneType.Trammel ) );
-
- // Trammel moonstones
- bank.DropItem( bag );
-
- // Treasure maps
- bank.DropItem( new TreasureMap( 1, Map.Trammel ) );
- bank.DropItem( new TreasureMap( 2, Map.Trammel ) );
- bank.DropItem( new TreasureMap( 3, Map.Trammel ) );
- bank.DropItem( new TreasureMap( 4, Map.Trammel ) );
- bank.DropItem( new TreasureMap( 5, Map.Trammel ) );
-
- // Bag containing 50 of each reagent
- bank.DropItem( new BagOfReagents( 50 ) );
-
- // Craft tools
- bank.DropItem( MakeNewbie( new Scissors() ) );
- bank.DropItem( MakeNewbie( new SewingKit( 1000 ) ) );
- bank.DropItem( MakeNewbie( new SmithHammer( 1000 ) ) );
- bank.DropItem( MakeNewbie( new FletcherTools( 1000 ) ) );
- bank.DropItem( MakeNewbie( new DovetailSaw( 1000 ) ) );
- bank.DropItem( MakeNewbie( new MortarPestle( 1000 ) ) );
- bank.DropItem( MakeNewbie( new ScribesPen( 1000 ) ) );
- bank.DropItem( MakeNewbie( new TinkerTools( 1000 ) ) );
-
- // A few dye tubs
- bank.DropItem( new Dyes() );
- bank.DropItem( new DyeTub() );
- bank.DropItem( new DyeTub() );
- bank.DropItem( new BlackDyeTub() );
-
- DyeTub darkRedTub = new DyeTub();
-
- darkRedTub.DyedHue = 0x485;
- darkRedTub.Redyable = false;
-
- bank.DropItem( darkRedTub );
-
- // Some food
- bank.DropItem( MakeNewbie( new Apple( 1000 ) ) );
-
- // Resources
- bank.DropItem( MakeNewbie( new Feather( 1000 ) ) );
- bank.DropItem( MakeNewbie( new BoltOfCloth( 1000 ) ) );
- bank.DropItem( MakeNewbie( new BlankScroll( 1000 ) ) );
- bank.DropItem( MakeNewbie( new Hides( 1000 ) ) );
- bank.DropItem( MakeNewbie( new Bandage( 1000 ) ) );
- bank.DropItem( MakeNewbie( new Bottle( 1000 ) ) );
- bank.DropItem( MakeNewbie( new Log( 1000 ) ) );
-
- bank.DropItem( MakeNewbie( new IronIngot( 5000 ) ) );
- bank.DropItem( MakeNewbie( new DullCopperIngot( 5000 ) ) );
- bank.DropItem( MakeNewbie( new ShadowIronIngot( 5000 ) ) );
- bank.DropItem( MakeNewbie( new CopperIngot( 5000 ) ) );
- bank.DropItem( MakeNewbie( new BronzeIngot( 5000 ) ) );
- bank.DropItem( MakeNewbie( new GoldIngot( 5000 ) ) );
- bank.DropItem( MakeNewbie( new AgapiteIngot( 5000 ) ) );
- bank.DropItem( MakeNewbie( new VeriteIngot( 5000 ) ) );
- bank.DropItem( MakeNewbie( new ValoriteIngot( 5000 ) ) );
-
- // Reagents
- bank.DropItem( MakeNewbie( new BlackPearl( 1000 ) ) );
- bank.DropItem( MakeNewbie( new Bloodmoss( 1000 ) ) );
- bank.DropItem( MakeNewbie( new Garlic( 1000 ) ) );
- bank.DropItem( MakeNewbie( new Ginseng( 1000 ) ) );
- bank.DropItem( MakeNewbie( new MandrakeRoot( 1000 ) ) );
- bank.DropItem( MakeNewbie( new Nightshade( 1000 ) ) );
- bank.DropItem( MakeNewbie( new SulfurousAsh( 1000 ) ) );
- bank.DropItem( MakeNewbie( new SpidersSilk( 1000 ) ) );
-
- // Some extra starting gold
- bank.DropItem( MakeNewbie( new Gold( 9000 ) ) );
-
- // 5 blank recall runes
- for ( int i = 0; i < 5; ++i )
- bank.DropItem( MakeNewbie( new RecallRune() ) );
-
- AddPowerScrolls( bank );
- }
-
- private static void AddPowerScrolls( BankBox bank )
- {
- Bag bag = new Bag();
-
- for ( int i = 0; i < PowerScroll.Skills.Count; ++i )
- bag.DropItem( new PowerScroll( PowerScroll.Skills[i], 120.0 ) );
-
- bag.DropItem( new StatCapScroll( 250 ) );
-
- bank.DropItem( bag );
- }
-
private static void AddShirt( Mobile m, int shirtHue )
{
int hue = Utility.ClipDyedHue( shirtHue & 0x3FFF );
@@ -646,6 +165,7 @@ namespace Server.Misc
newChar.Hue = newChar.Race.ClipSkinHue( args.Hue & 0x3FFF ) | 0x8000;
newChar.Hunger = 20;
+ newChar.Thirst = 20;
bool young = false;
@@ -656,7 +176,7 @@ namespace Server.Misc
pm.Profession = args.Profession;
if ( pm.AccessLevel == AccessLevel.Player && ((Account)pm.Account).Young )
- young = pm.Young = true;
+ young = pm.Young = false;
}
SetName( newChar, args.Name );
@@ -687,9 +207,6 @@ namespace Server.Misc
AddShoes( newChar );
}
- if( TestCenter.Enabled )
- FillBankbox( newChar );
-
if ( young )
{
NewPlayerTicket ticket = new NewPlayerTicket();
@@ -699,11 +216,12 @@ namespace Server.Misc
CityInfo city = GetStartLocation( args, young );
- newChar.MoveToWorld( city.Location, city.Map );
+ //newChar.MoveToWorld( city.Location, city.Map );
+ newChar.MoveToWorld( new Point3D( 865, 605, 0 ), Map.Felucca );
Console.WriteLine( "Login: {0}: New character being created (account={1})", state, args.Account.Username );
Console.WriteLine( " - Character: {0} (serial={1})", newChar.Name, newChar.Serial );
- Console.WriteLine( " - Started: {0} {1} in {2}", city.City, city.Location, city.Map.ToString() );
+ Console.WriteLine( " - Started: Bastion (865, 605, 0) in Vaelen" );
new WelcomeTimer( newChar ).Start();
}
@@ -960,14 +478,14 @@ namespace Server.Misc
break;
}
- case 3: // Blacksmith
+ case 3: // Thief Was Blacksmith
{
skills = new SkillNameValue[]
{
- new SkillNameValue( SkillName.Mining, 30 ),
- new SkillNameValue( SkillName.ArmsLore, 30 ),
- new SkillNameValue( SkillName.Blacksmith, 50 ),
- new SkillNameValue( SkillName.Tinkering, 50 )
+ new SkillNameValue( SkillName.Stealing, 30 ),
+ new SkillNameValue( SkillName.Snooping, 30 ),
+ new SkillNameValue( SkillName.Hiding, 50 ),
+ new SkillNameValue( SkillName.Stealth, 50 )
};
break;
@@ -997,25 +515,25 @@ namespace Server.Misc
break;
}
- case 6: //Samurai
+ case 6: // Archer
{
skills = new SkillNameValue[]
{
- new SkillNameValue( SkillName.Bushido, 50 ),
- new SkillNameValue( SkillName.Swords, 50 ),
- new SkillNameValue( SkillName.Anatomy, 30 ),
- new SkillNameValue( SkillName.Healing, 30 )
+ new SkillNameValue( SkillName.Tactics, 50 ),
+ new SkillNameValue( SkillName.Archery, 50 ),
+ new SkillNameValue( SkillName.Fletching, 30 ),
+ new SkillNameValue( SkillName.Lumberjacking, 30 )
};
break;
}
- case 7: //Ninja
+ case 7: //Bard
{
skills = new SkillNameValue[]
{
- new SkillNameValue( SkillName.Ninjitsu, 50 ),
- new SkillNameValue( SkillName.Hiding, 50 ),
- new SkillNameValue( SkillName.Fencing, 30 ),
- new SkillNameValue( SkillName.Stealth, 30 )
+ new SkillNameValue( SkillName.Musicianship, 30 ),
+ new SkillNameValue( SkillName.Peacemaking, 30 ),
+ new SkillNameValue( SkillName.Discordance, 30 ),
+ new SkillNameValue( SkillName.Provocation, 30 )
};
break;
}
@@ -1041,6 +559,16 @@ namespace Server.Misc
EquipItem( new LeatherChest() );
break;
}
+ case 3: // Thief
+ {
+ EquipItem( new Shirt( Utility.RandomNondyedHue() ) );
+ EquipItem( new ShortPants( Utility.RandomNondyedHue() ) );
+ EquipItem( new Bandana( Utility.RandomNondyedHue() ) );
+ EquipItem( new BodySash( Utility.RandomNondyedHue() ) );
+ EquipItem( new Shoes() );
+
+ break;
+ }
case 4: // Necromancer
{
Container regs = new BagOfNecroReagents( 50 );
@@ -1126,50 +654,34 @@ namespace Server.Misc
break;
}
- case 6: // Samurai
+ case 6: // Archer
{
addSkillItems = false;
- EquipItem( new HakamaShita( 0x2C3 ) );
- EquipItem( new Hakama( 0x2C3 ) );
- EquipItem( new SamuraiTabi( 0x2C3 ) );
- EquipItem( new TattsukeHakama( 0x22D ) );
- EquipItem( new Bokuto() );
+ EquipItem( new Boots() );
+ EquipItem( new LeatherChest() );
+ EquipItem( new LeatherArms() );
+ EquipItem( new LeatherGloves() );
+ EquipItem( new LeatherGorget() );
+ EquipItem( new LeatherLegs() );
- if ( elf )
- EquipItem( new RavenHelm() );
- else
- EquipItem( new LeatherJingasa() );
-
- PackItem( new Scissors() );
- PackItem( new Bandage( 50 ) );
-
- Spellbook book = new BookOfBushido();
- PackItem( book );
+ PackItem( new Bow() );
+ PackItem( new Arrow( 50 ) );
+ PackItem( new FletcherTools() );
+ PackItem( new Hatchet() );
break;
}
- case 7: // Ninja
+ case 7: // Bard Was Ninja
{
addSkillItems = false;
- EquipItem( new Kasa() );
+ EquipItem( new FeatheredHat( Utility.RandomNondyedHue() ) );
+ EquipItem( new Surcoat( Utility.RandomNondyedHue() ) );
+ EquipItem( new ShortPants( Utility.RandomNondyedHue() ) );
+ EquipItem( new ThighBoots() );
+ EquipItem( new Cloak( Utility.RandomNondyedHue() ) );
- int[] hues = new int[] { 0x1A8, 0xEC, 0x99, 0x90, 0xB5, 0x336, 0x89 };
- //TODO: Verify that's ALL the hues for that above.
-
- EquipItem( new TattsukeHakama( hues[Utility.Random(hues.Length)] ) );
-
- EquipItem( new HakamaShita( 0x2C3 ) );
- EquipItem( new NinjaTabi( 0x2C3 ) );
-
- if ( elf )
- EquipItem( new AssassinSpike() );
- else
- EquipItem( new Tekagi() );
-
- PackItem( new SmokeBomb() );
-
- Spellbook book = new BookOfNinjitsu();
- PackItem( book );
+ PackItem( new Drums() );
+ PackItem( new Tambourine() );
break;
}
diff --git a/Scripts/Misc/CurrentExpansion.cs b/Scripts/Misc/CurrentExpansion.cs
index 27f9a81..9375933 100644
--- a/Scripts/Misc/CurrentExpansion.cs
+++ b/Scripts/Misc/CurrentExpansion.cs
@@ -7,7 +7,7 @@ namespace Server
{
public class CurrentExpansion
{
- private static readonly Expansion Expansion = Expansion.TOL;
+ private static readonly Expansion Expansion = Expansion.AOS;
public static void Configure()
{
@@ -20,7 +20,7 @@ namespace Server
bool Enabled = Core.AOS;
- Mobile.InsuranceEnabled = Enabled;
+ Mobile.InsuranceEnabled = !Enabled;
ObjectPropertyList.Enabled = Enabled;
Mobile.VisibleDamageType = Enabled ? VisibleDamageType.Related : VisibleDamageType.None;
Mobile.GuildClickMessage = !Enabled;
diff --git a/Scripts/Misc/FoodDecay.cs b/Scripts/Misc/FoodDecay.cs
index d53851d..3940f92 100644
--- a/Scripts/Misc/FoodDecay.cs
+++ b/Scripts/Misc/FoodDecay.cs
@@ -1,45 +1,189 @@
-using System;
-using Server.Network;
-using Server;
-
-namespace Server.Misc
-{
- public class FoodDecayTimer : Timer
- {
- public static void Initialize()
- {
- new FoodDecayTimer().Start();
- }
-
- public FoodDecayTimer() : base( TimeSpan.FromMinutes( 5 ), TimeSpan.FromMinutes( 5 ) )
- {
- Priority = TimerPriority.OneMinute;
- }
-
- protected override void OnTick()
- {
- FoodDecay();
- }
-
- public static void FoodDecay()
- {
- foreach ( NetState state in NetState.Instances )
- {
- HungerDecay( state.Mobile );
- ThirstDecay( state.Mobile );
- }
- }
-
- public static void HungerDecay( Mobile m )
- {
- if ( m != null && m.Hunger >= 1 )
- m.Hunger -= 1;
- }
-
- public static void ThirstDecay( Mobile m )
- {
- if ( m != null && m.Thirst >= 1 )
- m.Thirst -= 1;
- }
- }
-}
\ No newline at end of file
+using System;
+using Server.Network;
+using Server;
+using Server.Mobiles;
+using Server.Regions;
+
+namespace Server.Misc
+{
+ public class FoodDecayTimer : Timer
+ {
+ public static void Initialize()
+ {
+ new FoodDecayTimer().Start();
+ }
+
+ public FoodDecayTimer() : base( TimeSpan.FromMinutes( 5 ), TimeSpan.FromMinutes( 5 ) )
+ {
+ Priority = TimerPriority.OneMinute;
+ }
+
+ protected override void OnTick()
+ {
+ FoodDecay();
+ }
+
+ public static void FoodDecay()
+ {
+ foreach ( NetState state in NetState.Instances )
+ {
+ HungerDecay( state.Mobile );
+ }
+ }
+
+ public static void HungerDecay( Mobile m )
+ {
+ // Ensures it only affects living players
+ if ( m != null && m is PlayerMobile && m.Alive && m.AccessLevel == AccessLevel.Player )
+ {
+ // The Safe Zone Check: Pauses decay if in an Inn or a House
+ if ( !m.Region.IsPartOf(typeof(InnRegion)) && !m.Region.IsPartOf(typeof(HouseRegion)) )
+ {
+ if ( m.Hunger >= 1 )
+ {
+ m.Hunger -= 1;
+ if ( m.Hunger == 15 )
+ m.SendMessage( "Your stomach gives a slight rumble." );
+ else if ( m.Hunger == 10 )
+ m.SendMessage( "You are starting to feel hungry." );
+ else if ( m.Hunger == 5 )
+ m.SendMessage( "You are getting extremely hungry. You should eat soon!" );
+ }
+
+ if ( m.Thirst >= 1 )
+ {
+ m.Thirst -= 1;
+ if ( m.Thirst == 15 )
+ m.SendMessage( "Your mouth feels a little dry." );
+ else if ( m.Thirst == 10 )
+ m.SendMessage( "You are starting to feel thirsty." );
+ else if ( m.Thirst == 5 )
+ m.SendMessage( "You are getting extremely thirsty. You should drink soon!" );
+ }
+ }
+ }
+ }
+ }
+
+ public class EatDecayTimer : Timer
+ {
+ public static void Initialize()
+ {
+ new EatDecayTimer().Start();
+ }
+
+ public EatDecayTimer() : base( TimeSpan.FromSeconds( 11.0 ), TimeSpan.FromSeconds( 11.0 ) )
+ {
+ Priority = TimerPriority.OneSecond;
+ }
+
+ protected override void OnTick()
+ {
+ EatDecay();
+ }
+
+ public static void EatDecay()
+ {
+ foreach ( NetState state in NetState.Instances )
+ {
+ EatDecaying( state.Mobile );
+ }
+ }
+
+ public static void EatDecaying( Mobile m )
+ {
+ if ( m is PlayerMobile && m.Alive )
+ {
+ // If they run into a house or inn, the 11-second starvation damage stops
+ if ( m.Region.IsPartOf(typeof(InnRegion)) || m.Region.IsPartOf(typeof(HouseRegion)) )
+ return;
+
+ // Starvation penalties begin when stats fall below 6 (The 0 to 5 range)
+ if ( m.Hunger < 6 || m.Thirst < 6 )
+ {
+ if ( m.Hunger < 6 )
+ {
+ int hits = 0;
+
+ if ( m.Hunger == 5 ) hits = 2;
+ else if ( m.Hunger == 4 ) hits = 3;
+ else if ( m.Hunger == 3 ) hits = 4;
+ else if ( m.Hunger == 2 ) hits = 5;
+ else
+ {
+ hits = 6;
+ m.SendMessage( "You are starving to death!" );
+ m.LocalOverheadMessage(MessageType.Emote, 1150, true, "I am so hungry!");
+ }
+
+ if ( m.Hits < hits )
+ hits = m.Hits - 1;
+
+ if ( hits > 0 )
+ m.Hits -= hits;
+
+ if ( m.Hunger < 4 && m.Hunger > 0 )
+ {
+ if ( Utility.RandomBool() ) m.SendMessage( "You are getting very hungry!" );
+ if ( Utility.RandomMinMax(1,5) == 1 ) m.LocalOverheadMessage(MessageType.Emote, 1150, true, "I am getting hungry!");
+ }
+ }
+
+ if ( m.Thirst < 6 )
+ {
+ if ( m.Thirst == 5 ) m.Stam -= 2;
+ else if ( m.Thirst == 4 ) m.Stam -= 3;
+ else if ( m.Thirst == 3 ) m.Stam -= 4;
+ else if ( m.Thirst == 2 ) m.Stam -= 5;
+ else
+ {
+ m.Stam -= 6;
+ m.SendMessage( "You are exhausted from thirst!" );
+ m.LocalOverheadMessage(MessageType.Emote, 1150, true, "I am so thirsty!");
+ }
+
+ if ( m.Thirst < 4 && m.Thirst > 0 )
+ {
+ if ( Utility.RandomBool() ) m.SendMessage( "You are getting exhausted from thirst!" );
+ if ( Utility.RandomMinMax(1,5) == 1 ) m.LocalOverheadMessage(MessageType.Emote, 1150, true, "I am getting thirsty!");
+ }
+
+ if ( m.Stam < 0 )
+ m.Stam = 0;
+ }
+
+ int test = m.Thirst;
+ if ( m.Hunger < m.Thirst )
+ test = m.Hunger;
+
+ if ( test == 5 ) m.Mana -= 2;
+ else if ( test == 4 ) m.Mana -= 3;
+ else if ( test == 3 ) m.Mana -= 4;
+ else if ( test == 2 ) m.Mana -= 5;
+ else m.Mana -= 6;
+
+ if ( m.Mana < 0 )
+ m.Mana = 0;
+ }
+ else
+ {
+ // Well-Fed Regeneration starts when stats are 16 or higher (The 16 to 20 range)
+ if ( m.Hunger >= 16 && m.Hits < m.HitsMax )
+ {
+ m.Hits += 2;
+ }
+
+ if ( m.Thirst >= 16 && m.Stam < m.StamMax )
+ {
+ m.Stam += 2;
+ }
+
+ if ( m.Hunger >= 16 && m.Thirst >= 16 && m.Mana < m.ManaMax )
+ {
+ m.Mana += 2;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Scripts/Misc/MapDefinitions.cs b/Scripts/Misc/MapDefinitions.cs
index d13c59e..c26cc25 100644
--- a/Scripts/Misc/MapDefinitions.cs
+++ b/Scripts/Misc/MapDefinitions.cs
@@ -15,7 +15,7 @@ namespace Server.Misc
* 4) Changing or removing any predefined maps may cause server instability.
*/
- RegisterMap( 0, 0, 0, 7168, 4096, 4, "Felucca", MapRules.FeluccaRules );
+ RegisterMap( 0, 0, 0, 7168, 4096, 0, "Vaelen", MapRules.FeluccaRules );
RegisterMap( 1, 1, 1, 7168, 4096, 0, "Trammel", MapRules.TrammelRules );
RegisterMap( 2, 2, 2, 2304, 1600, 1, "Ilshenar", MapRules.TrammelRules );
RegisterMap( 3, 3, 3, 2560, 2048, 1, "Malas", MapRules.TrammelRules );
diff --git a/Scripts/Misc/Notoriety.cs b/Scripts/Misc/Notoriety.cs
index 2e4c321..c04e265 100644
--- a/Scripts/Misc/Notoriety.cs
+++ b/Scripts/Misc/Notoriety.cs
@@ -415,6 +415,29 @@ namespace Server.Misc
if( target.Criminal )
return Notoriety.Criminal;
+ // --- CUSTOM: Hostiles are always red. Peaceful mobs are orange ---
+ if ( target is BaseCreature )
+ {
+ BaseCreature bc = (BaseCreature)target;
+
+ // Protects player pets and summons from changing color
+ if ( !bc.Controlled && !bc.Summoned )
+ {
+ // Hostiles: Negative Karma shows as Red
+ if ( bc.AI != AIType.AI_Animal && bc.Karma < 0 )
+ {
+ return Notoriety.Murderer;
+ }
+
+ // Defensive/Neutral: Aggressor FightMode or >= 0 Karma shows as Orange
+ if ( !target.Body.IsHuman && bc.AI != AIType.AI_Animal && ( bc.FightMode == FightMode.Aggressor || bc.Karma >= 0 ) )
+ {
+ return Notoriety.Enemy;
+ }
+ }
+ }
+ // ---------------------------------------------
+
Guild sourceGuild = GetGuildFor( source.Guild as Guild, source );
Guild targetGuild = GetGuildFor( target.Guild as Guild, target );
@@ -524,4 +547,4 @@ namespace Server.Misc
return false;
}
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Misc/SkillCheck.cs b/Scripts/Misc/SkillCheck.cs
index 40a95ee..efbc115 100644
--- a/Scripts/Misc/SkillCheck.cs
+++ b/Scripts/Misc/SkillCheck.cs
@@ -7,7 +7,7 @@ namespace Server.Misc
{
public class SkillCheck
{
- private static readonly bool AntiMacroCode = !Core.ML; //Change this to false to disable anti-macro code
+ private static readonly bool AntiMacroCode = Settings.S_NoMacroing; //Change this to false to disable anti-macro code
public static TimeSpan AntiMacroExpire = TimeSpan.FromMinutes( 5.0 ); //How long do we remember targets/locations?
public const int Allowance = 3; //How many times may we use the same location/target for gain
@@ -60,7 +60,7 @@ namespace Server.Misc
false,// Fencing = 42,
false,// Wrestling = 43,
true,// Lumberjacking = 44,
- true,// Mining = 45,
+ false,// Mining = 45,
true,// Meditation = 46,
true,// Stealth = 47,
true,// RemoveTrap = 48,
@@ -121,16 +121,19 @@ namespace Server.Misc
{
if ( from.Skills.Cap == 0 )
return false;
- double gainer = 2.0;
- gainer = gainer - ValidSettings.SkillGain();
+
+ double gainer = 2.0;
+ gainer = gainer - ValidSettings.SkillGain();
bool success = ( chance >= Utility.RandomDouble() );
double gc = (double)(from.Skills.Cap - from.Skills.Total) / from.Skills.Cap;
gc += ( skill.Cap - skill.Base ) / skill.Cap;
- gc /= gainer;
+ gc /= gainer;
+ gc /= 2;
gc += ( 1.0 - chance ) * ( success ? 0.5 : (Core.AOS ? 0.0 : 0.2) );
- gc /= gainer;
+ gc /= gainer;
+ gc /= 2;
gc *= skill.Info.GainFactor;
@@ -212,8 +215,9 @@ namespace Server.Misc
toGain = Utility.Random( 4 ) + 1;
Skills skills = from.Skills;
+ bool isSecondarySkill = skill.IsSecondarySkill();
- if ( from.Player && ( skills.Total / skills.Cap ) >= Utility.RandomDouble() )//( skills.Total >= skills.Cap )
+ if ( !isSecondarySkill && from.Player && ( skills.Total / skills.Cap ) >= Utility.RandomDouble() )//( skills.Total >= skills.Cap )
{
for ( int i = 0; i < skills.Length; ++i )
{
@@ -234,7 +238,7 @@ namespace Server.Misc
toGain *= Utility.RandomMinMax(2, 5);
#endregion
- if ( !from.Player || (skills.Total + toGain) <= skills.Cap )
+ if ( !from.Player || isSecondarySkill || (skills.Total + toGain) <= skills.Cap )
{
skill.BaseFixedPoint += toGain;
}
@@ -244,11 +248,11 @@ namespace Server.Misc
{
SkillInfo info = skill.Info;
- if ( from.StrLock == StatLockType.Up && (info.StrGain / ValidSettings.StatGain()) > Utility.RandomDouble() )
+ if ( from.StrLock == StatLockType.Up && (info.StrGain / 33.3) > Utility.RandomDouble() )
GainStat( from, Stat.Str );
- else if ( from.DexLock == StatLockType.Up && (info.DexGain / ValidSettings.StatGain()) > Utility.RandomDouble() )
+ else if ( from.DexLock == StatLockType.Up && (info.DexGain / 33.3) > Utility.RandomDouble() )
GainStat( from, Stat.Dex );
- else if ( from.IntLock == StatLockType.Up && (info.IntGain / ValidSettings.StatGain()) > Utility.RandomDouble() )
+ else if ( from.IntLock == StatLockType.Up && (info.IntGain / 33.3) > Utility.RandomDouble() )
GainStat( from, Stat.Int );
}
}
@@ -337,7 +341,7 @@ namespace Server.Misc
}
}
- private static TimeSpan m_StatGainDelay = ValidSettings.StatGainDelay(); //TimeSpan.FromMinutes( ( Core.ML ) ? 0.05 : 15 );
+ private static TimeSpan m_StatGainDelay = TimeSpan.FromMinutes( ( Core.ML ) ? 0.05 : 15 );
private static TimeSpan m_PetStatGainDelay = TimeSpan.FromMinutes( 5.0 );
public static void GainStat( Mobile from, Stat stat )
diff --git a/Scripts/Misc/ValidSettings.cs b/Scripts/Misc/ValidSettings.cs
index 256ff08..ba026be 100644
--- a/Scripts/Misc/ValidSettings.cs
+++ b/Scripts/Misc/ValidSettings.cs
@@ -101,5 +101,39 @@ namespace Server
return gold;
}
+ public static double FarmSpawnTimer()
+ {
+ if ( Settings.S_FarmSpawnTimer < 1.0 )
+ {
+ Settings.S_FarmSpawnTimer = 1.0;
+ }
+ return Settings.S_FarmSpawnTimer;
+ }
+
+ public static int HarvestRange()
+ {
+ if ( Settings.S_HarvestRange > 3 )
+ {
+ Settings.S_HarvestRange = 3;
+ }
+ else if ( Settings.S_HarvestRange < 1 )
+ {
+ Settings.S_HarvestRange = 1;
+ }
+ return Settings.S_HarvestRange;
+ }
+
+ public static int HousesPerAccount()
+ {
+ if ( Settings.S_HousesPerAccount == 0 )
+ {
+ Settings.S_HousesPerAccount = 1;
+ }
+ else if ( Settings.S_HousesPerAccount < 0 )
+ {
+ Settings.S_HousesPerAccount = -1;
+ }
+ return Settings.S_HousesPerAccount;
+ }
}
}
diff --git a/Scripts/Misc/Weather.cs b/Scripts/Misc/Weather.cs
index 155fea5..a134328 100644
--- a/Scripts/Misc/Weather.cs
+++ b/Scripts/Misc/Weather.cs
@@ -23,14 +23,9 @@ namespace Server.Misc
*/
// ice island
- AddWeather( -15, 100, 5, new Rectangle2D( 3850, 160, 390, 320 ), new Rectangle2D( 3900, 480, 380, 180 ), new Rectangle2D( 4160, 660, 150, 110 ) );
-
- // covetous entrance, around vesper and minoc
- AddWeather( +15, 50, 5, new Rectangle2D( 2425, 725, 250, 250 ) );
-
- // despise entrance, north of britain
- AddWeather( +15, 50, 5, new Rectangle2D( 1245, 1045, 250, 250 ) );
-
+ AddWeather( -15, 75, 10, new Rectangle2D( 1479, 47, 865, 319 ) );
+ // desert island
+ AddWeather( +15, 0, 5, new Rectangle2D(791, 1619, 140, 64 ) );
/* Dynamic weather:
*
@@ -39,7 +34,7 @@ namespace Server.Misc
*/
for ( int i = 0; i < 15; ++i )
- AddDynamicWeather( +15, 100, 5, 8, 400, 400, new Rectangle2D( 0, 0, 5120, 4096 ) );
+ AddDynamicWeather( +15, 25, 5, 8, 400, 400, new Rectangle2D( 0, 0, 2344, 1991 ) );
}
public static List GetWeatherList( Map facet )
@@ -391,4 +386,4 @@ namespace Server.Misc
int version = reader.ReadInt();
}
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Misc/WelcomeTimer.cs b/Scripts/Misc/WelcomeTimer.cs
index 2e1a26f..6bb4b58 100644
--- a/Scripts/Misc/WelcomeTimer.cs
+++ b/Scripts/Misc/WelcomeTimer.cs
@@ -14,7 +14,7 @@ namespace Server.Misc
private static string[] m_Messages =
new string[]
{
- "Welcome to Britannia.",
+ "Welcome to Avatars Conquest.",
"Please enjoy your stay."
};
diff --git a/Scripts/Mobiles/BaseCreature.cs b/Scripts/Mobiles/BaseCreature.cs
index 6ccc50d..5cabc1f 100644
--- a/Scripts/Mobiles/BaseCreature.cs
+++ b/Scripts/Mobiles/BaseCreature.cs
@@ -3424,6 +3424,65 @@ namespace Server.Mobiles
m_AI.OnSpeech( e );
}
+ public static int MyLevel( Mobile m )
+ {
+ int level = 0;
+
+ if ( m is BaseCreature )
+ {
+ BaseCreature bc = (BaseCreature)m;
+
+ int psn = 0;
+
+ if ( bc.HitPoison == Poison.Lesser )
+ psn = 5;
+ else if ( bc.HitPoison == Poison.Regular )
+ psn = 10;
+ else if ( bc.HitPoison == Poison.Greater )
+ psn = 15;
+ else if ( bc.HitPoison == Poison.Deadly )
+ psn = 20;
+ else if ( bc.HitPoison == Poison.Lethal )
+ psn = 25;
+
+ if ( bc.PoisonImmune == Poison.Lesser )
+ psn = psn + 5;
+ else if ( bc.PoisonImmune == Poison.Regular )
+ psn = psn + 10;
+ else if ( bc.PoisonImmune == Poison.Greater )
+ psn = psn + 15;
+ else if ( bc.PoisonImmune == Poison.Deadly )
+ psn = psn + 20;
+ else if ( bc.PoisonImmune == Poison.Lethal )
+ psn = psn + 25;
+
+ int bard = 0;
+
+ if ( bc.BardImmune )
+ bard = 50;
+ else
+ {
+ if ( bc.Unprovokable )
+ bard = bard + 25;
+
+ if ( bc.Uncalmable )
+ bard = bard + 25;
+ }
+
+ int dmg = (int)( bc.DamageMax * 8 );
+ int sts = (int)( m.RawStatTotal / 6 );
+ int fam = (int)( m.Fame / 120 );
+ int arm = (int)( m.VirtualArmor * 2.5 );
+
+ level = psn + dmg + sts + fam + arm + bard;
+
+ if ( level > 1000 ){ level = 1000; }
+ else if ( level < 1 ){ level = 1; }
+ }
+
+ return level;
+ }
+
public override bool IsHarmfulCriminal( Mobile target )
{
if ( (Controlled && target == m_ControlMaster) || (Summoned && target == m_SummonMaster) )
@@ -4063,6 +4122,14 @@ namespace Server.Mobiles
AddLoot( LootPack.UltraRich );
}
+ if ( Fame >= 5000 )
+ {
+ if ( Utility.RandomDouble() < 0.10 )
+ {
+ PackItem( new Server.Items.DungeonPassageRelic() );
+ }
+ }
+
m_Spawning = false;
m_KillersLuck = 0;
}
diff --git a/Scripts/Mobiles/PlayerMobile.cs b/Scripts/Mobiles/PlayerMobile.cs
index d37da4f..3002af4 100644
--- a/Scripts/Mobiles/PlayerMobile.cs
+++ b/Scripts/Mobiles/PlayerMobile.cs
@@ -25,6 +25,7 @@ using Server.Engines.Craft;
using Server.Spells.Spellweaving;
using Server.Engines.PartySystem;
using Server.Engines.MLQuests;
+using Server.Custom.UI;
namespace Server.Mobiles
{
@@ -201,6 +202,14 @@ namespace Server.Mobiles
private List m_AllFollowers;
private List m_RecentlyReported;
+ // -- Inn Room Start
+ private Point3D m_LastInnLocation;
+ private Map m_LastInnMap;
+ // -- Inn Room End
+ // -- Exhaustion System Start
+ private int m_ExhaustionDamageTracker;
+ // -- Exhaustion System End
+
#region Getters & Setters
public List RecentlyReported
@@ -374,6 +383,22 @@ namespace Server.Mobiles
set { CandyCane.SetToothAche( this, value ); }
}
+ // -- Inn Room Start
+ [CommandProperty(AccessLevel.GameMaster)]
+ public Point3D LastInnLocation
+ {
+ get { return m_LastInnLocation; }
+ set { m_LastInnLocation = value; }
+ }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public Map LastInnMap
+ {
+ get { return m_LastInnMap; }
+ set { m_LastInnMap = value; }
+ }
+ // -- Inn Room End
+
#endregion
#region PlayerFlags
@@ -2616,6 +2641,39 @@ namespace Server.Mobiles
if ( willKill && from is PlayerMobile )
Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerCallback( ((PlayerMobile) from).RecoverAmmo ) );
+ // -- Exhaustion System Start
+ if ( this.Alive && amount > 0 )
+ {
+ m_ExhaustionDamageTracker += amount;
+
+ if ( m_ExhaustionDamageTracker >= 200 )
+ {
+ int drops = m_ExhaustionDamageTracker / 200;
+ bool statsDropped = false;
+
+ if ( this.Hunger > 0 )
+ {
+ this.Hunger = Math.Max( 0, this.Hunger - drops );
+ statsDropped = true;
+ }
+
+ if ( this.Thirst > 0 )
+ {
+ this.Thirst = Math.Max( 0, this.Thirst - drops );
+ statsDropped = true;
+ }
+
+ if ( statsDropped )
+ {
+ this.SendMessage( 33, "The physical toll of combat leaves you exhausted and parched." );
+ }
+
+ // Save the leftover damage for the next cycle
+ m_ExhaustionDamageTracker %= 200;
+ }
+ }
+ // -- Exhaustion System End
+
base.OnDamage( amount, from, willKill );
}
@@ -3358,6 +3416,12 @@ namespace Server.Mobiles
switch ( version )
{
+ case 30:
+ {
+ m_LastInnLocation = reader.ReadPoint3D();
+ m_LastInnMap = reader.ReadMap();
+ goto case 29;
+ }
case 29:
{
if (reader.ReadBool())
@@ -3667,7 +3731,12 @@ namespace Server.Mobiles
base.Serialize( writer );
- writer.Write( (int) 29 ); // version
+ writer.Write( (int) 30 ); // version
+
+ // -- Inn Room Start
+ writer.Write(m_LastInnLocation);
+ writer.Write(m_LastInnMap);
+ // -- Inn Room End
if (m_StuckMenuUses != null)
{
@@ -4171,11 +4240,13 @@ namespace Server.Mobiles
public override void OnKarmaChange( int oldValue )
{
InvalidateMyRunUO();
+ StatusBar.Refresh(this);
}
public override void OnFameChange( int oldValue )
{
InvalidateMyRunUO();
+ StatusBar.Refresh(this);
}
public override void OnSkillChange( SkillName skill, double oldBase )
@@ -4194,6 +4265,21 @@ namespace Server.Mobiles
InvalidateMyRunUO();
}
+ public override void OnHungerChange(int oldValue)
+ {
+ StatusBar.Refresh(this);
+ }
+
+ public override void OnThirstChange(int oldValue)
+ {
+ StatusBar.Refresh(this);
+ }
+
+ public override void OnTithingPointsChange(int oldValue)
+ {
+ StatusBar.Refresh(this);
+ }
+
public override void OnAccessLevelChanged( AccessLevel oldLevel )
{
if ( AccessLevel == AccessLevel.Player )
@@ -5175,4 +5261,4 @@ namespace Server.Mobiles
m_AutoStabled.Clear();
}
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Multis/BaseHouse.cs b/Scripts/Multis/BaseHouse.cs
index 107976f..8d206f1 100644
--- a/Scripts/Multis/BaseHouse.cs
+++ b/Scripts/Multis/BaseHouse.cs
@@ -3256,7 +3256,7 @@ namespace Server.Multis
return false;
}
- public static bool HasAccountHouse( Mobile m )
+ /*public static bool HasAccountHouse( Mobile m )
{
Account a = m.Account as Account;
@@ -3268,7 +3268,45 @@ namespace Server.Multis
return true;
return false;
- }
+ }*/
+
+ public static bool HasAccountHouse( Mobile m )
+ {
+ Account a = m.Account as Account;
+
+ if ( a == null )
+ return false;
+
+ int limit = ValidSettings.HousesPerAccount();
+
+ if ( limit < 0 )
+ return false;
+
+ int count = 0;
+
+ for ( int i = 0; i < a.Length; ++i )
+ {
+ Mobile mob = a[i];
+
+ if ( mob != null )
+ {
+ List list = null;
+ m_Table.TryGetValue( mob, out list );
+
+ if ( list != null )
+ {
+ for ( int j = 0; j < list.Count; ++j )
+ {
+ BaseHouse h = list[j];
+
+ if ( !h.Deleted && !(h is Server.Custom.InnRooms.InnRoomHouse) )
+ count++;
+ }
+ }
+ }
+ }
+ return ( count >= limit );
+ }
public bool IsOwner( Mobile m )
{
@@ -3976,4 +4014,4 @@ namespace Server.Multis
return ( from == m_RegionOwner || AccountHandler.CheckAccount( from, m_RegionOwner ) );
}
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Regions/BusinessRegion.cs b/Scripts/Regions/BusinessRegion.cs
new file mode 100644
index 0000000..0c1e2e0
--- /dev/null
+++ b/Scripts/Regions/BusinessRegion.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Xml;
+using Server;
+using Server.Mobiles;
+
+namespace Server.Regions
+{
+ public class BusinessRegion : GuardedRegion
+ {
+ public BusinessRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent )
+ {
+ }
+
+ public override void OnEnter( Mobile m )
+ {
+ base.OnEnter( m );
+ if ( m != null && m.Player )
+ {
+ m.SendMessage( "Welcome to {0}", this.Name );
+ }
+ if ( m != null && m.Player )
+ {
+ Server.Commands.StableMountCommand.ForceDismountAndStore((PlayerMobile)m);
+ }
+ }
+
+ public override void OnExit( Mobile m )
+ {
+ base.OnExit( m );
+ if ( m != null && m.Player )
+ {
+ Server.Commands.RetrieveMountCommand.AutoRemountPlayer((PlayerMobile)m);
+ }
+ }
+ }
+}
diff --git a/Scripts/Regions/CaveRegion.cs b/Scripts/Regions/CaveRegion.cs
new file mode 100644
index 0000000..9562ca1
--- /dev/null
+++ b/Scripts/Regions/CaveRegion.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Xml;
+using Server;
+using Server.Mobiles;
+
+namespace Server.Regions
+{
+ public class CaveRegion : DungeonRegion
+ {
+ public CaveRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent )
+ {
+ }
+
+ public override void OnEnter( Mobile m )
+ {
+ base.OnEnter( m );
+ if ( m != null && m.Player )
+ {
+ m.SendMessage( "You have entered a dark cave" );
+ }
+ }
+
+ public override void OnExit( Mobile m )
+ {
+ base.OnExit( m );
+ }
+ }
+}
diff --git a/Scripts/Regions/DungeonRegion.cs b/Scripts/Regions/DungeonRegion.cs
index 3d907f5..439cc71 100644
--- a/Scripts/Regions/DungeonRegion.cs
+++ b/Scripts/Regions/DungeonRegion.cs
@@ -44,5 +44,36 @@ namespace Server.Regions
return base.CanUseStuckMenu( m );
}
+
+ public override void OnEnter( Mobile m )
+ {
+ base.OnEnter( m );
+ if ( m != null && m.Player )
+ {
+ m.SendMessage( "You have entered {0}", this.Name);
+ Timer.DelayCall( TimeSpan.FromMilliseconds( 100 ), delegate()
+ {
+ if ( m != null && m.Alive )
+ {
+ Server.Commands.StableMountCommand.ForceDismountAndStore((PlayerMobile)m);
+ }
+ });
+ }
+ }
+
+ public override void OnExit( Mobile m )
+ {
+ base.OnExit( m );
+ if ( m != null && m.Player )
+ {
+ Timer.DelayCall( TimeSpan.FromMilliseconds( 100 ), delegate()
+ {
+ if ( m != null && m.Alive )
+ {
+ Server.Commands.RetrieveMountCommand.AutoRemountPlayer((PlayerMobile)m);
+ }
+ });
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Regions/DungeonTrapRegion.cs b/Scripts/Regions/DungeonTrapRegion.cs
new file mode 100644
index 0000000..e6ce63e
--- /dev/null
+++ b/Scripts/Regions/DungeonTrapRegion.cs
@@ -0,0 +1,66 @@
+using System;
+using Server;
+using Server.Mobiles;
+using System.Xml;
+
+namespace Server.Regions
+{
+ public class DungeonTrapRegion : DungeonRegion
+ {
+ public DungeonTrapRegion(XmlElement xml, Map map, Region parent) : base(xml, map, parent)
+ {
+ }
+
+ public override void OnLocationChanged(Mobile m, Point3D oldLocation)
+ {
+ base.OnLocationChanged(m, oldLocation);
+
+ if (m is PlayerMobile pm && pm.Alive && pm.AccessLevel == AccessLevel.Player && m.Location != oldLocation)
+ {
+ // We are using 2% (0.02) base chance per step.
+ if (Utility.RandomDouble() < 0.02)
+ {
+ EvaluateTrapSequence(pm);
+ }
+ }
+ }
+
+ private void EvaluateTrapSequence(PlayerMobile pm)
+ {
+ // --- TIER 1: PASSIVE SEARCHING (Detect Hidden) ---
+ if (pm.Skills[SkillName.DetectHidden].Value >= 5.0)
+ {
+ if (pm.CheckSkill(SkillName.DetectHidden, 0.0, 125.0))
+ {
+ pm.PlaySound(pm.Female ? 778 : 1049); // Plays a female/male gasp or sigh
+ //pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 0x3B2, false, "You notice a hidden floor mechanism and carefully step around it.");
+ return;
+ }
+ }
+
+ // --- TIER 2: TRAP AVOIDANCE (Remove Trap) ---
+ if (pm.Skills[SkillName.RemoveTrap].Value >= 5.0)
+ {
+ if (pm.CheckSkill(SkillName.RemoveTrap, 0.0, 125.0))
+ {
+ pm.PlaySound(0x241);
+ //pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 0x3B2, false, "Your experience with traps allows you to safely bypass a hidden trigger.");
+ return;
+ }
+ }
+
+ // --- TIER 3: LUCK ---
+ // A simple scale: 1000 Luck = 10% chance to avoid. 2000 Luck = 20% chance.
+ double luckChance = pm.Luck / 10000.0;
+ if (Utility.RandomDouble() < luckChance)
+ {
+ pm.PlaySound(0x241);
+ //pm.LocalOverheadMessage(Server.Network.MessageType.Emote, 0x3B2, false, "With luck on your side, the trap mechanism fails to trigger.");
+ return;
+ }
+
+ // If they failed all three avoidance checks the trap is sprung.
+ CustomDungeonTraps.TriggerRandomTrap(pm);
+ }
+ }
+}
diff --git a/Scripts/Regions/FarmRegion.cs b/Scripts/Regions/FarmRegion.cs
new file mode 100644
index 0000000..32814f9
--- /dev/null
+++ b/Scripts/Regions/FarmRegion.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Xml;
+using Server;
+using Server.Mobiles;
+
+namespace Server.Regions
+{
+ public class FarmRegion : BaseRegion
+ {
+ public FarmRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent )
+ {
+ }
+
+ public override void OnEnter( Mobile m )
+ {
+ base.OnEnter( m );
+ if ( m != null && m.Player )
+ {
+ m.SendMessage( "Welcome to {0}", this.Name );
+ }
+ if ( m != null && m.Player )
+ {
+ Server.Commands.StableMountCommand.ForceDismountAndStore((PlayerMobile)m);
+ }
+ }
+
+ public override void OnExit( Mobile m )
+ {
+ base.OnExit( m );
+ if ( m != null && m.Player )
+ {
+ Server.Commands.RetrieveMountCommand.AutoRemountPlayer((PlayerMobile)m);
+ }
+ }
+ }
+}
diff --git a/Scripts/Regions/HouseRegion.cs b/Scripts/Regions/HouseRegion.cs
index c1db4cb..a601d79 100644
--- a/Scripts/Regions/HouseRegion.cs
+++ b/Scripts/Regions/HouseRegion.cs
@@ -428,5 +428,23 @@ namespace Server.Regions
return m_House;
}
}
+
+ public override void OnEnter( Mobile m )
+ {
+ base.OnEnter( m );
+ if ( m != null && m.Player )
+ {
+ Server.Commands.StableMountCommand.ForceDismountAndStore((PlayerMobile)m);
+ }
+ }
+
+ public override void OnExit( Mobile m )
+ {
+ base.OnExit( m );
+ if ( m != null && m.Player )
+ {
+ Server.Commands.RetrieveMountCommand.AutoRemountPlayer((PlayerMobile)m);
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Regions/InnRegion.cs b/Scripts/Regions/InnRegion.cs
new file mode 100644
index 0000000..4711e0f
--- /dev/null
+++ b/Scripts/Regions/InnRegion.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Xml;
+using Server;
+using Server.Mobiles;
+
+namespace Server.Regions
+{
+ public class InnRegion : Region
+ {
+ public InnRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent )
+ {
+ }
+
+ public InnRegion( string name, Map map, int priority, params Rectangle3D[] area ) : base( name, map, priority, area )
+ {
+ }
+
+ public override TimeSpan GetLogoutDelay( Mobile m )
+ {
+ return TimeSpan.Zero;
+ }
+
+ public override bool AllowHousing( Mobile from, Point3D p )
+ {
+ return false;
+ }
+
+ public override void OnEnter( Mobile m )
+ {
+ base.OnEnter( m );
+ if ( m != null && m.Player )
+ {
+ Server.Commands.StableMountCommand.ForceDismountAndStore((PlayerMobile)m);
+ }
+ if ( m != null && m.Player )
+ {
+ m.SendMessage( "Welcome to {0}", this.Name );
+ }
+ }
+
+ public override void OnExit( Mobile m )
+ {
+ base.OnExit( m );
+ if ( m != null && m.Player )
+ {
+ Server.Commands.RetrieveMountCommand.AutoRemountPlayer((PlayerMobile)m);
+ }
+ }
+ }
+}
diff --git a/Scripts/Regions/TownRegion.cs b/Scripts/Regions/TownRegion.cs
index 1f9afc4..0c4dd59 100644
--- a/Scripts/Regions/TownRegion.cs
+++ b/Scripts/Regions/TownRegion.cs
@@ -9,5 +9,21 @@ namespace Server.Regions
public TownRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent )
{
}
+
+ public override void OnEnter( Mobile m )
+ {
+ base.OnEnter( m );
+ if (m != null && m.Player )
+ {
+ m.SendMessage( "You have entered {0}", this.Name );
+ }
+ }
+ public override void OnExit( Mobile m )
+ {
+ if (m != null && m.Player )
+ {
+ m.SendMessage( "You have left {0}", this.Name );
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Settings.cs b/Scripts/Settings.cs
index 7f23a20..b9ee42d 100644
--- a/Scripts/Settings.cs
+++ b/Scripts/Settings.cs
@@ -5,7 +5,7 @@ namespace Server
public static string S_ServerName = "Avatars Conquest";
public static int S_Port = 8008;
public static bool S_RestartOnCrash = false;
- public static double S_ServerSaveMinutes = 5.0; // 5-240 minutes range
+ public static double S_ServerSaveMinutes = 30.0; // 5-240 minutes range
public static double S_ServerSaveWarningSeconds = 15;
public static bool S_SaveOnCharacterLogout = true;
public static int S_MaxAccountsPerIP = 3;
@@ -19,5 +19,10 @@ namespace Server
public static int S_MaxGold = 1000; // maximum is 10,000
public static bool S_CanStealWhileHoldingThings = true;
public static bool S_MonstersSurprise = true;
+ public static bool S_DungeonFloorTraps = false;
+ public static double S_FarmSpawnTimer = 15.0;
+ public static int S_HarvestRange = 1;
+ public static int S_HousesPerAccount = 1;
+ public static bool S_NoMacroing = false;
}
}
diff --git a/Scripts/TaskManager.cs b/Scripts/TaskManager.cs
new file mode 100644
index 0000000..5fe81c1
--- /dev/null
+++ b/Scripts/TaskManager.cs
@@ -0,0 +1,138 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using Server;
+using Server.Items;
+using Server.Custom.StaticHousing;
+
+namespace Server.Scripts.Custom
+{
+ public class TasksManager
+ {
+ public static void Initialize()
+ {
+ Timer.DelayCall(TimeSpan.FromMinutes(1), TimeSpan.FromHours(1), new TimerCallback(ExecuteTasks));
+
+ Console.WriteLine("TasksManager: Hourly automated tasks initialized.");
+ }
+
+ public static void ExecuteTasks()
+ {
+ Console.WriteLine("TasksManager: Running scheduled hourly tasks...");
+
+ if ( Settings.S_DungeonFloorTraps )
+ {
+ ClearSpawnedTraps();
+ }
+ CheckStaticHouses();
+ }
+
+ private static void CheckStaticHouses()
+ {
+ string filePath = Path.Combine(Core.BaseDirectory, "Data", "Config", "statichouses.cfg");
+
+ if (!File.Exists(filePath))
+ {
+ Console.WriteLine("TasksManager: Error - Data/Config/statichouses.cfg not found!");
+ return;
+ }
+
+ int count = 0;
+
+ using (StreamReader ip = new StreamReader(filePath))
+ {
+ string line;
+ while ((line = ip.ReadLine()) != null)
+ {
+ line = line.Trim();
+ if (line.Length == 0 || line.StartsWith("#")) continue;
+
+ string[] split = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
+
+ // Requires 14 parameters (10 base + 4 area variables)
+ if (split.Length >= 14)
+ {
+ try
+ {
+ Map map = Map.Parse(split[0]);
+ Point3D signLoc = new Point3D(int.Parse(split[1]), int.Parse(split[2]), int.Parse(split[3]));
+
+ int minZ = int.Parse(split[4]);
+ int maxZ = int.Parse(split[5]);
+ int price = int.Parse(split[6]);
+ int locks = int.Parse(split[7]);
+ int secures = int.Parse(split[8]);
+
+ int itemID = split[9].StartsWith("0x", StringComparison.OrdinalIgnoreCase)
+ ? Convert.ToInt32(split[9], 16)
+ : int.Parse(split[9]);
+
+ List areas = new List();
+ for (int i = 10; i < split.Length; i += 4)
+ {
+ if (i + 3 < split.Length)
+ {
+ Point2D start = new Point2D(int.Parse(split[i]), int.Parse(split[i + 1]));
+ Point2D end = new Point2D(start.X + int.Parse(split[i + 2]), start.Y + int.Parse(split[i + 3]));
+ areas.Add(new Rectangle2D(start, end));
+ }
+ }
+
+ if (map != null && !CheckForExistingHouse(map, signLoc) && areas.Count > 0)
+ {
+ StaticHouseSign sign = new StaticHouseSign(itemID, areas.ToArray(), minZ, maxZ, price, locks, secures);
+ sign.MoveToWorld(signLoc, map);
+ count++;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"TasksManager: Error parsing statichouses.cfg line: {line}\n{ex.Message}");
+ }
+ }
+ }
+ }
+
+ if (count > 0)
+ Console.WriteLine($"TasksManager: Respawned {count} missing Static House signs.");
+ }
+
+ private static bool CheckForExistingHouse(Map map, Point3D loc)
+ {
+ bool exists = false;
+ IPooledEnumerable eable = map.GetItemsInRange(loc, 0);
+
+ foreach (Item item in eable)
+ {
+ if (item is StaticHouseSign || item is Server.Multis.HouseSign)
+ {
+ exists = true;
+ break;
+ }
+ }
+
+ eable.Free();
+ return exists;
+ }
+
+ private static void ClearSpawnedTraps()
+ {
+ List- trapsToDelete = new List
- ();
+
+ foreach (Item item in World.Items.Values)
+ {
+ if (item is BaseTrap)
+ {
+ trapsToDelete.Add(item);
+ }
+ }
+
+ foreach (Item trap in trapsToDelete)
+ {
+ trap.Delete();
+ }
+
+ Console.WriteLine($"TasksManager: Wiped {trapsToDelete.Count} floor traps. Spawners will now replace them.");
+ }
+ }
+}
diff --git a/Source/Map.cs b/Source/Map.cs
index 3138de3..8545dec 100644
--- a/Source/Map.cs
+++ b/Source/Map.cs
@@ -142,7 +142,7 @@ namespace Server
BeneficialRestrictions = 0x0004, // Disallow performing beneficial actions on criminals/murderers
HarmfulRestrictions = 0x0008, // Disallow performing harmful actions on innocents
TrammelRules = FreeMovement | BeneficialRestrictions | HarmfulRestrictions,
- FeluccaRules = None
+ FeluccaRules = FreeMovement
}
public interface IPooledEnumerable : IEnumerable {
diff --git a/Source/Mobile.cs b/Source/Mobile.cs
index 94791b5..5949470 100644
--- a/Source/Mobile.cs
+++ b/Source/Mobile.cs
@@ -1549,12 +1549,16 @@ namespace Server
if( oldValue != value )
{
m_Hunger = value;
-
+ OnHungerChange(oldValue);
EventSink.InvokeHungerChanged( new HungerChangedEventArgs( this, oldValue ) );
}
}
}
+ public virtual void OnHungerChange(int oldValue)
+ {
+ }
+
[CommandProperty( AccessLevel.GameMaster )]
public int Thirst
{
@@ -1564,10 +1568,19 @@ namespace Server
}
set
{
- m_Thirst = value;
+ int oldValue = m_Thirst;
+ if (oldValue != value)
+ {
+ m_Thirst = value;
+ OnThirstChange(oldValue);
+ }
}
}
+ public virtual void OnThirstChange(int oldValue)
+ {
+ }
+
[CommandProperty( AccessLevel.GameMaster )]
public int BAC
{
@@ -2512,13 +2525,18 @@ namespace Server
{
if( m_TithingPoints != value )
{
+ int oldValue = m_TithingPoints;
m_TithingPoints = value;
-
Delta( MobileDelta.TithingPoints );
+ OnTithingPointsChange(oldValue);
}
}
}
+ public virtual void OnTithingPointsChange(int oldValue)
+ {
+ }
+
[CommandProperty( AccessLevel.GameMaster )]
public int Followers
{
diff --git a/Source/Network/Packets.cs b/Source/Network/Packets.cs
index 5444a9a..f6449a0 100644
--- a/Source/Network/Packets.cs
+++ b/Source/Network/Packets.cs
@@ -2119,7 +2119,7 @@ namespace Server.Network
m_Stream.Write( (ushort) (s.Info.SkillID + 1) );
m_Stream.Write( (ushort) uv );
- m_Stream.Write( (ushort) s.BaseFixedPoint );
+ m_Stream.Write( (ushort) (!s.IsSecondarySkill() ? s.BaseFixedPoint : 0) );
m_Stream.Write( (byte) s.Lock );
m_Stream.Write( (ushort) s.CapFixedPoint );
}
@@ -2153,7 +2153,7 @@ namespace Server.Network
m_Stream.Write( (byte) 0xDF ); // type: delta, capped
m_Stream.Write( (ushort) skill.Info.SkillID );
m_Stream.Write( (ushort) uv );
- m_Stream.Write( (ushort) skill.BaseFixedPoint );
+ m_Stream.Write( (ushort) (!skill.IsSecondarySkill() ? skill.BaseFixedPoint : 0 ) );
m_Stream.Write( (byte) skill.Lock );
m_Stream.Write( (ushort) skill.CapFixedPoint );
@@ -3909,7 +3909,7 @@ namespace Server.Network
{
}
- public CityInfo( string city, string building, int description, int x, int y, int z ) : this( city, building, description, x, y, z, Map.Trammel )
+ public CityInfo( string city, string building, int description, int x, int y, int z ) : this( city, building, description, x, y, z, Map.Trammel)
{
}
diff --git a/Source/Skills.cs b/Source/Skills.cs
index e31b402..d720b08 100644
--- a/Source/Skills.cs
+++ b/Source/Skills.cs
@@ -113,6 +113,31 @@ namespace Server
return String.Format( "[{0}: {1}]", Name, Base );
}
+ public bool IsSecondarySkill()
+ {
+ switch(SkillName)
+ {
+ // Crafting Skills
+ case SkillName.Alchemy:
+ case SkillName.Blacksmith:
+ case SkillName.Fletching:
+ case SkillName.Carpentry:
+ case SkillName.Cooking:
+ case SkillName.Inscribe:
+ case SkillName.Tailoring:
+ case SkillName.Tinkering:
+ return true;
+ // Gathering Skills
+ case SkillName.Forensics:
+ case SkillName.Lumberjacking:
+ case SkillName.Mining:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+
public Skill( Skills owner, SkillInfo info, GenericReader reader )
{
m_Owner = owner;
@@ -283,7 +308,10 @@ namespace Server
if ( m_Base != sv )
{
- m_Owner.Total = (m_Owner.Total - m_Base) + sv;
+ if (!IsSecondarySkill())
+ m_Owner.Total = (m_Owner.Total - m_Base) + sv;
+
+ int delta = value - sv;
m_Base = sv;
@@ -1016,7 +1044,8 @@ namespace Server
else
{
sk.Serialize( writer );
- m_Total += sk.BaseFixedPoint;
+ if (!sk.IsSecondarySkill())
+ m_Total += sk.BaseFixedPoint;
}
}
}
@@ -1072,7 +1101,8 @@ namespace Server
if ( sk.BaseFixedPoint != 0 || sk.CapFixedPoint != 1000 || sk.Lock != SkillLock.Up )
{
m_Skills[i] = sk;
- m_Total += sk.BaseFixedPoint;
+ if (!sk.IsSecondarySkill())
+ m_Total += sk.BaseFixedPoint;
}
}
else
@@ -1120,4 +1150,4 @@ namespace Server
return m_Skills.Where(s => s != null).GetEnumerator();
}
}
-}
\ No newline at end of file
+}