This commit is contained in:
mark 2006-06-15 04:14:30 +00:00
commit 47711d616e
2644 changed files with 479454 additions and 0 deletions

View file

@ -0,0 +1,46 @@
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using Server;
using Server.Misc;
namespace Server
{
public class AccessRestrictions
{
public static void Initialize()
{
EventSink.SocketConnect += new SocketConnectEventHandler( EventSink_SocketConnect );
}
private static void EventSink_SocketConnect( SocketConnectEventArgs e )
{
try
{
IPAddress ip = ((IPEndPoint)e.Socket.RemoteEndPoint).Address;
if ( Firewall.IsBlocked( ip ) )
{
Console.WriteLine( "Client: {0}: Firewall blocked connection attempt.", ip );
e.AllowConnection = false;
return;
}
else if ( IPLimiter.SocketBlock && !IPLimiter.Verify( ip ) )
{
Console.WriteLine( "Client: {0}: Past IP limit threshold", ip );
using ( StreamWriter op = new StreamWriter( "ipLimits.log", true ) )
op.WriteLine( "{0}\tPast IP limit threshold\t{1}", ip, DateTime.Now );
e.AllowConnection = false;
return;
}
}
catch
{
e.AllowConnection = false;
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,142 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using Server;
using Server.Network;
namespace Server.Accounting
{
public class AccountAttackLimiter
{
public static bool Enabled = true;
public static void Initialize()
{
if ( !Enabled )
return;
RegisterThrottler( 0x80 );
RegisterThrottler( 0x91 );
RegisterThrottler( 0xCF );
}
public static void RegisterThrottler( int packetID )
{
PacketHandler ph = PacketHandlers.GetHandler( packetID );
if ( ph == null )
return;
ph.ThrottleCallback = new ThrottlePacketCallback( Throttle_Callback );
}
public static bool Throttle_Callback( NetState ns )
{
InvalidAccountAccessLog accessLog = FindAccessLog( ns );
if ( accessLog == null )
return true;
return ( DateTime.Now >= (accessLog.LastAccessTime + ComputeThrottle( accessLog.Counts )) );
}
private static List<InvalidAccountAccessLog> m_List = new List<InvalidAccountAccessLog>();
public static InvalidAccountAccessLog FindAccessLog( NetState ns )
{
if ( ns == null )
return null;
IPAddress ipAddress = ns.Address;
for ( int i = 0; i < m_List.Count; ++i )
{
InvalidAccountAccessLog accessLog = m_List[i];
if ( accessLog.HasExpired )
m_List.RemoveAt( i-- );
else if ( accessLog.Address.Equals( ipAddress ) )
return accessLog;
}
return null;
}
public static void RegisterInvalidAccess( NetState ns )
{
if ( ns == null || !Enabled )
return;
InvalidAccountAccessLog accessLog = FindAccessLog( ns );
if ( accessLog == null )
m_List.Add( accessLog = new InvalidAccountAccessLog( ns.Address ) );
accessLog.Counts += 1;
accessLog.RefreshAccessTime();
}
public static TimeSpan ComputeThrottle( int counts )
{
if ( counts >= 15 )
return TimeSpan.FromMinutes( 5.0 );
if ( counts >= 10 )
return TimeSpan.FromMinutes( 1.0 );
if ( counts >= 5 )
return TimeSpan.FromSeconds( 20.0 );
if ( counts >= 3 )
return TimeSpan.FromSeconds( 10.0 );
if ( counts >= 1 )
return TimeSpan.FromSeconds( 2.0 );
return TimeSpan.Zero;
}
}
public class InvalidAccountAccessLog
{
private IPAddress m_Address;
private DateTime m_LastAccessTime;
private int m_Counts;
public IPAddress Address
{
get{ return m_Address; }
set{ m_Address = value; }
}
public DateTime LastAccessTime
{
get{ return m_LastAccessTime; }
set{ m_LastAccessTime = value; }
}
public bool HasExpired
{
get{ return ( DateTime.Now >= ( m_LastAccessTime + TimeSpan.FromHours( 1.0 ) ) ); }
}
public int Counts
{
get{ return m_Counts; }
set{ m_Counts = value; }
}
public void RefreshAccessTime()
{
m_LastAccessTime = DateTime.Now;
}
public InvalidAccountAccessLog( IPAddress address )
{
m_Address = address;
RefreshAccessTime();
}
}
}

View file

@ -0,0 +1,77 @@
using System;
using System.Xml;
namespace Server.Accounting
{
public class AccountComment
{
private string m_AddedBy;
private string m_Content;
private DateTime m_LastModified;
/// <summary>
/// A string representing who added this comment.
/// </summary>
public string AddedBy
{
get{ return m_AddedBy; }
}
/// <summary>
/// Gets or sets the body of this comment. Setting this value will reset LastModified.
/// </summary>
public string Content
{
get{ return m_Content; }
set{ m_Content = value; m_LastModified = DateTime.Now; }
}
/// <summary>
/// The date and time when this account was last modified -or- the comment creation time, if never modified.
/// </summary>
public DateTime LastModified
{
get{ return m_LastModified; }
}
/// <summary>
/// Constructs a new AccountComment instance.
/// </summary>
/// <param name="addedBy">Initial AddedBy value.</param>
/// <param name="content">Initial Content value.</param>
public AccountComment( string addedBy, string content )
{
m_AddedBy = addedBy;
m_Content = content;
m_LastModified = DateTime.Now;
}
/// <summary>
/// Deserializes an AccountComment instance from an xml element.
/// </summary>
/// <param name="node">The XmlElement instance from which to deserialize.</param>
public AccountComment( XmlElement node )
{
m_AddedBy = Utility.GetAttribute( node, "addedBy", "empty" );
m_LastModified = Utility.GetDateTime( Utility.GetAttribute( node, "lastModified" ), DateTime.Now );
m_Content = Utility.GetText( node, "" );
}
/// <summary>
/// Serializes this AccountComment instance to an XmlTextWriter.
/// </summary>
/// <param name="xml">The XmlTextWriter instance from which to serialize.</param>
public void Save( XmlTextWriter xml )
{
xml.WriteStartElement( "comment" );
xml.WriteAttributeString( "addedBy", m_AddedBy );
xml.WriteAttributeString( "lastModified", XmlConvert.ToString( m_LastModified, XmlDateTimeSerializationMode.Local ) );
xml.WriteString( m_Content );
xml.WriteEndElement();
}
}
}

View file

@ -0,0 +1,396 @@
using System;
using System.IO;
using System.Net;
using Server;
using Server.Network;
using Server.Accounting;
using Server.Engines.Help;
using System.Collections;
using Server.Commands;
namespace Server.Misc
{
public enum PasswordProtection
{
None,
Crypt,
NewCrypt
}
public class AccountHandler
{
private static int MaxAccountsPerIP = 1;
private static bool AutoAccountCreation = true;
private static bool RestrictDeletion = !TestCenter.Enabled;
private static TimeSpan DeleteDelay = TimeSpan.FromDays( 7.0 );
public static PasswordProtection ProtectPasswords = PasswordProtection.NewCrypt;
private static AccessLevel m_LockdownLevel;
public static AccessLevel LockdownLevel
{
get{ return m_LockdownLevel; }
set{ m_LockdownLevel = value; }
}
private static CityInfo[] StartingCities = new CityInfo[]
{
new CityInfo( "Yew", "The Empath Abbey", 633, 858, 0 ),
new CityInfo( "Minoc", "The Barnacle", 2476, 413, 15 ),
new CityInfo( "Britain", "Sweet Dreams Inn", 1496, 1628, 10 ),
new CityInfo( "Moonglow", "The Scholars Inn", 4408, 1168, 0 ),
new CityInfo( "Trinsic", "The Traveler's Inn", 1845, 2745, 0 ),
new CityInfo( "Magincia", "The Great Horns Tavern", 3734, 2222, 20 ),
new CityInfo( "Jhelom", "The Mercenary Inn", 1374, 3826, 0 ),
new CityInfo( "Skara Brae", "The Falconer's Inn", 618, 2234, 0 ),
new CityInfo( "Vesper", "The Ironwood Inn", 2771, 976, 0 ),
new CityInfo( "Haven", "Buckler's Hideaway", 3667, 2625, 0 )
};
private static bool PasswordCommandEnabled = false;
public static void Initialize()
{
EventSink.DeleteRequest += new DeleteRequestEventHandler( EventSink_DeleteRequest );
EventSink.AccountLogin += new AccountLoginEventHandler( EventSink_AccountLogin );
EventSink.GameLogin += new GameLoginEventHandler( EventSink_GameLogin );
if ( PasswordCommandEnabled )
CommandSystem.Register( "Password", AccessLevel.Player, new CommandEventHandler( Password_OnCommand ) );
if ( Core.AOS )
{
CityInfo haven = new CityInfo( "Haven", "Uzeraan's Mansion", 3618, 2591, 0 );
StartingCities[StartingCities.Length - 1] = haven;
}
}
[Usage( "Password <newPassword> <repeatPassword>" )]
[Description( "Changes the password of the commanding players account. Requires the same C-class IP address as the account's creator." )]
public static void Password_OnCommand( CommandEventArgs e )
{
Mobile from = e.Mobile;
Account acct = from.Account as Account;
if ( acct == null )
return;
IPAddress[] accessList = acct.LoginIPs;
if ( accessList.Length == 0 )
return;
NetState ns = from.NetState;
if ( ns == null )
return;
if ( e.Length == 0 )
{
from.SendMessage( "You must specify the new password." );
return;
}
else if ( e.Length == 1 )
{
from.SendMessage( "To prevent potential typing mistakes, you must type the password twice. Use the format:" );
from.SendMessage( "Password \"(newPassword)\" \"(repeated)\"" );
return;
}
string pass = e.GetString( 0 );
string pass2 = e.GetString( 1 );
if ( pass != pass2 )
{
from.SendMessage( "The passwords do not match." );
return;
}
bool isSafe = true;
for ( int i = 0; isSafe && i < pass.Length; ++i )
isSafe = ( pass[i] >= 0x20 && pass[i] < 0x80 );
if ( !isSafe )
{
from.SendMessage( "That is not a valid password." );
return;
}
try
{
IPAddress ipAddress = ((IPEndPoint)ns.Socket.RemoteEndPoint).Address;
if ( Utility.IPMatchClassC( accessList[0], ipAddress ) )
{
acct.SetPassword( pass );
from.SendMessage( "The password to your account has changed." );
}
else
{
PageEntry entry = PageQueue.GetEntry( from );
if ( entry != null )
{
if ( entry.Message.StartsWith( "[Automated: Change Password]" ) )
from.SendMessage( "You already have a password change request in the help system queue." );
else
from.SendMessage( "Your IP address does not match that which created this account." );
}
else if ( PageQueue.CheckAllowedToPage( from ) )
{
from.SendMessage( "Your IP address does not match that which created this account. A page has been entered into the help system on your behalf." );
from.SendLocalizedMessage( 501234, "", 0x35 ); /* The next available Counselor/Game Master will respond as soon as possible.
* Please check your Journal for messages every few minutes.
*/
PageQueue.Enqueue( new PageEntry( from, String.Format( "[Automated: Change Password]<br>Desired password: {0}<br>Current IP address: {1}<br>Account IP address: {2}", pass, ipAddress, accessList[0] ), PageType.Account ) );
}
}
}
catch
{
}
}
private static void EventSink_DeleteRequest( DeleteRequestEventArgs e )
{
NetState state = e.State;
int index = e.Index;
Account acct = state.Account as Account;
if ( acct == null )
{
state.Dispose();
}
else if ( index < 0 || index >= acct.Length )
{
state.Send( new DeleteResult( DeleteResultType.BadRequest ) );
state.Send( new CharacterListUpdate( acct ) );
}
else
{
Mobile m = acct[index];
if ( m == null )
{
state.Send( new DeleteResult( DeleteResultType.CharNotExist ) );
state.Send( new CharacterListUpdate( acct ) );
}
else if ( m.NetState != null )
{
state.Send( new DeleteResult( DeleteResultType.CharBeingPlayed ) );
state.Send( new CharacterListUpdate( acct ) );
}
else if ( RestrictDeletion && DateTime.Now < (m.CreationTime + DeleteDelay) )
{
state.Send( new DeleteResult( DeleteResultType.CharTooYoung ) );
state.Send( new CharacterListUpdate( acct ) );
}
else
{
Console.WriteLine( "Client: {0}: Deleting character {1} (0x{2:X})", state, index, m.Serial.Value );
acct.Comments.Add( new AccountComment( "System", String.Format( "Character #{0} {1} deleted by {2}", index+1, m, state ) ) );
m.Delete();
state.Send( new CharacterListUpdate( acct ) );
}
}
}
public static bool CanCreate( IPAddress ip )
{
if ( IPTables[ip] == null ) //Sanity
return true;
return ((int)IPTables[ip] < MaxAccountsPerIP);
/*
if ( (int)IPTables[ip] >= MaxAccountsPerIP )
return false;
else
return true;
*/
}
private static Hashtable m_IPTables;
public static Hashtable IPTables
{
get
{
if ( m_IPTables == null )
{
m_IPTables = new Hashtable();
foreach ( Account a in Accounts.GetAccounts() )
{
if ( a.LoginIPs.Length > 0 )
{
IPAddress ip = a.LoginIPs[0];
if ( m_IPTables[ip] == null )
m_IPTables[ip] = 1;
else
m_IPTables[ip] = (int)m_IPTables[ip] + 1;
}
}
}
return m_IPTables;
}
}
private static Account CreateAccount( NetState state, string un, string pw )
{
if ( un.Length == 0 || pw.Length == 0 )
return null;
bool isSafe = true;
for ( int i = 0; isSafe && i < un.Length; ++i )
isSafe = ( un[i] >= 0x20 && un[i] < 0x80 );
for ( int i = 0; isSafe && i < pw.Length; ++i )
isSafe = ( pw[i] >= 0x20 && pw[i] < 0x80 );
if ( !isSafe )
return null;
if ( !CanCreate( state.Address ) )
{
Console.WriteLine( "Login: {0}: Account '{1}' not created, ip already has {2} account{3}.", state, un, MaxAccountsPerIP, MaxAccountsPerIP == 1 ? "" : "s" );
return null;
}
Console.WriteLine( "Login: {0}: Creating new account '{1}'", state, un );
Account a = new Account( un, pw );
return a;
}
public static void EventSink_AccountLogin( AccountLoginEventArgs e )
{
if ( !IPLimiter.SocketBlock && !IPLimiter.Verify( e.State.Address ) )
{
e.Accepted = false;
e.RejectReason = ALRReason.InUse;
Console.WriteLine( "Login: {0}: Past IP limit threshold", e.State );
using ( StreamWriter op = new StreamWriter( "ipLimits.log", true ) )
op.WriteLine( "{0}\tPast IP limit threshold\t{1}", e.State, DateTime.Now );
return;
}
string un = e.Username;
string pw = e.Password;
e.Accepted = false;
Account acct = Accounts.GetAccount( un ) as Account;
if ( acct == null )
{
if ( AutoAccountCreation && un.Trim().Length > 0 ) //To prevent someone from mkaing an account of just '' or a bunch of meaningless spaces
{
e.State.Account = acct = CreateAccount( e.State, un, pw );
e.Accepted = acct == null ? false : acct.CheckAccess( e.State );
if ( !e.Accepted )
e.RejectReason = ALRReason.BadComm;
}
else
{
Console.WriteLine( "Login: {0}: Invalid username '{1}'", e.State, un );
e.RejectReason = ALRReason.Invalid;
}
}
else if ( !acct.HasAccess( e.State ) )
{
Console.WriteLine( "Login: {0}: Access denied for '{1}'", e.State, un );
e.RejectReason = ( m_LockdownLevel > AccessLevel.Player ? ALRReason.BadComm : ALRReason.BadPass );
}
else if ( !acct.CheckPassword( pw ) )
{
Console.WriteLine( "Login: {0}: Invalid password for '{1}'", e.State, un );
e.RejectReason = ALRReason.BadPass;
}
else if ( acct.Banned )
{
Console.WriteLine( "Login: {0}: Banned account '{1}'", e.State, un );
e.RejectReason = ALRReason.Blocked;
}
else
{
Console.WriteLine( "Login: {0}: Valid credentials for '{1}'", e.State, un );
e.State.Account = acct;
e.Accepted = true;
acct.LogAccess( e.State );
}
if ( !e.Accepted )
AccountAttackLimiter.RegisterInvalidAccess( e.State );
}
public static void EventSink_GameLogin( GameLoginEventArgs e )
{
if ( !IPLimiter.SocketBlock && !IPLimiter.Verify( e.State.Address ) )
{
e.Accepted = false;
Console.WriteLine( "Login: {0}: Past IP limit threshold", e.State );
using ( StreamWriter op = new StreamWriter( "ipLimits.log", true ) )
op.WriteLine( "{0}\tPast IP limit threshold\t{1}", e.State, DateTime.Now );
return;
}
string un = e.Username;
string pw = e.Password;
Account acct = Accounts.GetAccount( un ) as Account;
if ( acct == null )
{
e.Accepted = false;
}
else if ( !acct.HasAccess( e.State ) )
{
Console.WriteLine( "Login: {0}: Access denied for '{1}'", e.State, un );
e.Accepted = false;
}
else if ( !acct.CheckPassword( pw ) )
{
Console.WriteLine( "Login: {0}: Invalid password for '{1}'", e.State, un );
e.Accepted = false;
}
else if ( acct.Banned )
{
Console.WriteLine( "Login: {0}: Banned account '{1}'", e.State, un );
e.Accepted = false;
}
else
{
acct.LogAccess( e.State );
Console.WriteLine( "Login: {0}: Account '{1}' at character list", e.State, un );
e.State.Account = acct;
e.Accepted = true;
e.CityInfo = StartingCities;
}
if ( !e.Accepted )
AccountAttackLimiter.RegisterInvalidAccess( e.State );
}
}
}

View file

@ -0,0 +1,61 @@
using System;
using System.Xml;
namespace Server.Accounting
{
public class AccountTag
{
private string m_Name, m_Value;
/// <summary>
/// Gets or sets the name of this tag.
/// </summary>
public string Name
{
get{ return m_Name; }
set{ m_Name = value; }
}
/// <summary>
/// Gets or sets the value of this tag.
/// </summary>
public string Value
{
get{ return m_Value; }
set{ m_Value = value; }
}
/// <summary>
/// Constructs a new AccountTag instance with a specific name and value.
/// </summary>
/// <param name="name">Initial name.</param>
/// <param name="value">Initial value.</param>
public AccountTag( string name, string value )
{
m_Name = name;
m_Value = value;
}
/// <summary>
/// Deserializes an AccountTag instance from an xml element.
/// </summary>
/// <param name="node">The XmlElement instance from which to deserialize.</param>
public AccountTag( XmlElement node )
{
m_Name = Utility.GetAttribute( node, "name", "empty" );
m_Value = Utility.GetText( node, "" );
}
/// <summary>
/// Serializes this AccountTag instance to an XmlTextWriter.
/// </summary>
/// <param name="xml">The XmlTextWriter instance from which to serialize.</param>
public void Save( XmlTextWriter xml )
{
xml.WriteStartElement( "tag" );
xml.WriteAttributeString( "name", m_Name );
xml.WriteString( m_Value );
xml.WriteEndElement();
}
}
}

View file

@ -0,0 +1,106 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml;
namespace Server.Accounting
{
public class Accounts
{
private static Dictionary<string, IAccount> m_Accounts = new Dictionary<string, IAccount>();
public static void Configure()
{
EventSink.WorldLoad += new WorldLoadEventHandler( Load );
EventSink.WorldSave += new WorldSaveEventHandler( Save );
}
static Accounts()
{
}
public static int Count { get { return m_Accounts.Count; } }
public static ICollection<IAccount> GetAccounts()
{
return m_Accounts.Values;
}
public static IAccount GetAccount( string username )
{
IAccount a;
m_Accounts.TryGetValue( username, out a );
return a;
}
public static void Add( IAccount a )
{
m_Accounts[a.Username] = a;
}
public static void Remove( string username )
{
m_Accounts.Remove( username );
}
public static void Load()
{
m_Accounts = new Dictionary<string, IAccount>( 32, StringComparer.OrdinalIgnoreCase );
string filePath = Path.Combine( "Saves/Accounts", "accounts.xml" );
if ( !File.Exists( filePath ) )
return;
XmlDocument doc = new XmlDocument();
doc.Load( filePath );
XmlElement root = doc["accounts"];
foreach ( XmlElement account in root.GetElementsByTagName( "account" ) )
{
try
{
Account acct = new Account( account );
}
catch
{
Console.WriteLine( "Warning: Account instance load failed" );
}
}
}
public static void Save( WorldSaveEventArgs e )
{
if ( !Directory.Exists( "Saves/Accounts" ) )
Directory.CreateDirectory( "Saves/Accounts" );
string filePath = Path.Combine( "Saves/Accounts", "accounts.xml" );
using ( StreamWriter op = new StreamWriter( filePath ) )
{
XmlTextWriter xml = new XmlTextWriter( op );
xml.Formatting = Formatting.Indented;
xml.IndentChar = '\t';
xml.Indentation = 1;
xml.WriteStartDocument( true );
xml.WriteStartElement( "accounts" );
xml.WriteAttributeString( "count", m_Accounts.Count.ToString() );
foreach ( Account a in GetAccounts() )
a.Save( xml );
xml.WriteEndElement();
xml.Close();
}
}
}
}

View file

@ -0,0 +1,131 @@
using System;
using System.Collections;
using System.IO;
using System.Net;
namespace Server
{
public class Firewall
{
private static ArrayList m_Blocked;
static Firewall()
{
m_Blocked = new ArrayList();
string path = "firewall.cfg";
if ( File.Exists( path ) )
{
using ( StreamReader ip = new StreamReader( path ) )
{
string line;
while ( (line = ip.ReadLine()) != null )
{
line = line.Trim();
if ( line.Length == 0 )
continue;
object toAdd;
IPAddress addr;
if( IPAddress.TryParse( line, out addr ) )
toAdd = addr;
else
toAdd = line;
m_Blocked.Add( toAdd.ToString() );
}
}
}
}
public static ArrayList List
{
get
{
return m_Blocked;
}
}
public static void RemoveAt( int index )
{
m_Blocked.RemoveAt( index );
Save();
}
public static void Remove( string pattern )
{
m_Blocked.Remove( pattern );
Save();
}
public static void Remove( IPAddress ip )
{
m_Blocked.Remove( ip );
Save();
}
public static void Add( object obj )
{
if ( !(obj is IPAddress) && !(obj is String) )
return;
if ( !m_Blocked.Contains( obj ) )
m_Blocked.Add( obj );
Save();
}
public static void Add( string pattern )
{
if ( !m_Blocked.Contains( pattern ) )
m_Blocked.Add( pattern );
Save();
}
public static void Add( IPAddress ip )
{
if ( !m_Blocked.Contains( ip ) )
m_Blocked.Add( ip );
Save();
}
public static void Save()
{
string path = "firewall.cfg";
using ( StreamWriter op = new StreamWriter( path ) )
{
for ( int i = 0; i < m_Blocked.Count; ++i )
op.WriteLine( m_Blocked[i] );
}
}
public static bool IsBlocked( IPAddress ip )
{
bool contains = false;
for ( int i = 0; !contains && i < m_Blocked.Count; ++i )
{
if ( m_Blocked[i] is IPAddress )
contains = ip.Equals( m_Blocked[i] );
else if ( m_Blocked[i] is String )
{
string s = (string)m_Blocked[i];
contains = Utility.IPMatchCIDR( s, ip );
if( !contains )
contains = Utility.IPMatch( s, ip );
}
}
return contains;
}
}
}

View file

@ -0,0 +1,59 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using Server;
using Server.Network;
namespace Server.Misc
{
public class IPLimiter
{
public static bool Enabled = true;
public static bool SocketBlock = true; // true to block at connection, false to block at login request
public const int MaxAddresses = 10;
public static IPAddress[] Exemptions = new IPAddress[] //For hosting services where there are cases where IPs can be proxied
{
//IPAddress.Parse( "127.0.0.1" ),
};
public static bool IsExempt( IPAddress ip )
{
for ( int i = 0; i < Exemptions.Length; i++ )
{
if ( ip.Equals( Exemptions[i] ) )
return true;
}
return false;
}
public static bool Verify( IPAddress ourAddress )
{
if ( !Enabled || IsExempt( ourAddress ) )
return true;
List<NetState> netStates = NetState.Instances;
int count = 0;
for ( int i = 0; i < netStates.Count; ++i )
{
NetState compState = (NetState)netStates[i];
if ( ourAddress.Equals( compState.Address ) )
{
++count;
if ( count > MaxAddresses )
return false;
}
}
return true;
}
}
}

606
Scripts/Commands/Add.cs Normal file
View file

@ -0,0 +1,606 @@
using System;
using System.Text;
using System.Reflection;
using System.Collections;
using Server;
using Server.Items;
using Server.Network;
using Server.Targeting;
using CPA = Server.CommandPropertyAttribute;
namespace Server.Commands
{
public class Add
{
public static void Initialize()
{
CommandSystem.Register( "Tile", AccessLevel.GameMaster, new CommandEventHandler( Tile_OnCommand ) );
CommandSystem.Register( "TileRXYZ", AccessLevel.GameMaster, new CommandEventHandler( TileRXYZ_OnCommand ) );
CommandSystem.Register( "TileXYZ", AccessLevel.GameMaster, new CommandEventHandler( TileXYZ_OnCommand ) );
CommandSystem.Register( "TileZ", AccessLevel.GameMaster, new CommandEventHandler( TileZ_OnCommand ) );
}
public static void Invoke( Mobile from, Point3D start, Point3D end, string[] args )
{
Invoke( from, start, end, args, null );
}
public static void Invoke( Mobile from, Point3D start, Point3D end, string[] args, ArrayList packs )
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat( "{0} {1} building ", from.AccessLevel, CommandLogging.Format( from ) );
if ( start == end )
sb.AppendFormat( "at {0} in {1}", start, from.Map );
else
sb.AppendFormat( "from {0} to {1} in {2}", start, end, from.Map );
sb.Append( ":" );
for ( int i = 0; i < args.Length; ++i )
sb.AppendFormat( " \"{0}\"", args[i] );
CommandLogging.WriteLine( from, sb.ToString() );
string name = args[0];
FixArgs( ref args );
string[,] props = null;
for ( int i = 0; i < args.Length; ++i )
{
if ( Insensitive.Equals( args[i], "set" ) )
{
int remains = args.Length - i - 1;
if ( remains >= 2 )
{
props = new string[remains / 2, 2];
remains /= 2;
for ( int j = 0; j < remains; ++j )
{
props[j, 0] = args[i + (j * 2) + 1];
props[j, 1] = args[i + (j * 2) + 2];
}
FixSetString( ref args, i );
}
break;
}
}
Type type = ScriptCompiler.FindTypeByName( name );
if ( type == null )
{
from.SendMessage( "No type with that name was found." );
return;
}
DateTime time = DateTime.Now;
int built = BuildObjects( from, type, start, end, args, props, packs );
if ( built > 0 )
from.SendMessage( "{0} object{1} generated in {2:F1} seconds.", built, built != 1 ? "s" : "", (DateTime.Now - time).TotalSeconds );
else
SendUsage( type, from );
}
public static void FixSetString( ref string[] args, int index )
{
string[] old = args;
args = new string[index];
Array.Copy( old, 0, args, 0, index );
}
public static void FixArgs( ref string[] args )
{
string[] old = args;
args = new string[args.Length - 1];
Array.Copy( old, 1, args, 0, args.Length );
}
public static int BuildObjects( Mobile from, Type type, Point3D start, Point3D end, string[] args, string[,] props, ArrayList packs )
{
Utility.FixPoints( ref start, ref end );
PropertyInfo[] realProps = null;
if ( props != null )
{
realProps = new PropertyInfo[props.GetLength( 0 )];
PropertyInfo[] allProps = type.GetProperties( BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public );
for ( int i = 0; i < realProps.Length; ++i )
{
PropertyInfo thisProp = null;
string propName = props[i, 0];
for ( int j = 0; thisProp == null && j < allProps.Length; ++j )
{
if ( Insensitive.Equals( propName, allProps[j].Name ) )
thisProp = allProps[j];
}
if ( thisProp == null )
{
from.SendMessage( "Property not found: {0}", propName );
}
else
{
CPA attr = Properties.GetCPA( thisProp );
if ( attr == null )
from.SendMessage( "Property ({0}) not found.", propName );
else if ( from.AccessLevel < attr.WriteLevel )
from.SendMessage( "Setting this property ({0}) requires at least {1} access level.", propName, Mobile.GetAccessLevelName( attr.WriteLevel ) );
else if ( !thisProp.CanWrite )
from.SendMessage( "Property ({0}) is read only.", propName );
else
realProps[i] = thisProp;
}
}
}
ConstructorInfo[] ctors = type.GetConstructors();
for ( int i = 0; i < ctors.Length; ++i )
{
ConstructorInfo ctor = ctors[i];
if ( !IsConstructable( ctor ) )
continue;
ParameterInfo[] paramList = ctor.GetParameters();
if ( args.Length == paramList.Length )
{
object[] paramValues = ParseValues( paramList, args );
if ( paramValues == null )
continue;
int built = Build( from, start, end, ctor, paramValues, props, realProps, packs );
if ( built > 0 )
return built;
}
}
return 0;
}
public static object[] ParseValues( ParameterInfo[] paramList, string[] args )
{
object[] values = new object[args.Length];
for ( int i = 0; i < args.Length; ++i )
{
object value = ParseValue( paramList[i].ParameterType, args[i] );
if ( value != null )
values[i] = value;
else
return null;
}
return values;
}
public static object ParseValue( Type type, string value )
{
try
{
if ( IsEnum( type ) )
{
return Enum.Parse( type, value, true );
}
else if ( IsType( type ) )
{
return ScriptCompiler.FindTypeByName( value );
}
else if ( IsParsable( type ) )
{
return ParseParsable( type, value );
}
else
{
object obj = value;
if ( value != null && value.StartsWith( "0x" ) )
{
if ( IsSignedNumeric( type ) )
obj = Convert.ToInt64( value.Substring( 2 ), 16 );
else if ( IsUnsignedNumeric( type ) )
obj = Convert.ToUInt64( value.Substring( 2 ), 16 );
obj = Convert.ToInt32( value.Substring( 2 ), 16 );
}
if ( obj == null && !type.IsValueType )
return null;
else
return Convert.ChangeType( obj, type );
}
}
catch
{
return null;
}
}
public static object Build( Mobile from, ConstructorInfo ctor, object[] values, string[,] props, PropertyInfo[] realProps, ref bool sendError )
{
object built = ctor.Invoke( values );
if ( built != null && realProps != null )
{
bool hadError = false;
for ( int i = 0; i < realProps.Length; ++i )
{
if ( realProps[i] == null )
continue;
string result = Properties.InternalSetValue( from, built, built, realProps[i], props[i, 1], props[i, 1], false );
if ( result != "Property has been set." )
{
if ( sendError )
from.SendMessage( result );
hadError = true;
}
}
if ( hadError )
sendError = false;
}
return built;
}
public static int Build( Mobile from, Point3D start, Point3D end, ConstructorInfo ctor, object[] values, string[,] props, PropertyInfo[] realProps, ArrayList packs )
{
try
{
Map map = from.Map;
int objectCount = ( packs == null ? (((end.X - start.X) + 1) * ((end.Y - start.Y) + 1)) : packs.Count );
if ( objectCount >= 20 )
from.SendMessage( "Constructing {0} objects, please wait.", objectCount );
bool sendError = true;
StringBuilder sb = new StringBuilder();
sb.Append( "Serials: " );
if ( packs != null )
{
for ( int i = 0; i < packs.Count; ++i )
{
object built = Build( from, ctor, values, props, realProps, ref sendError );
if( built is IEntity )
sb.AppendFormat( "0x{0:X}; ", ((IEntity)built).Serial.Value );
else
continue;
if ( built is Item )
{
Container pack = (Container)packs[i];
pack.DropItem( (Item)built );
}
else if ( built is Mobile )
{
Mobile m = (Mobile)built;
m.MoveToWorld( new Point3D( start.X, start.Y, start.Z ), map );
}
}
}
else
{
for ( int x = start.X; x <= end.X; ++x )
{
for ( int y = start.Y; y <= end.Y; ++y )
{
object built = Build( from, ctor, values, props, realProps, ref sendError );
if( built is IEntity )
sb.AppendFormat( "0x{0:X}; ", ((IEntity)built).Serial.Value );
else
continue;
if ( built is Item )
{
Item item = (Item)built;
item.MoveToWorld( new Point3D( x, y, start.Z ), map );
}
else if ( built is Mobile )
{
Mobile m = (Mobile)built;
m.MoveToWorld( new Point3D( x, y, start.Z ), map );
}
}
}
}
CommandLogging.WriteLine( from, sb.ToString() );
return objectCount;
}
catch ( Exception ex )
{
Console.WriteLine(ex);
return 0;
}
}
public static void SendUsage( Type type, Mobile from )
{
ConstructorInfo[] ctors = type.GetConstructors();
bool foundCtor = false;
for ( int i = 0; i < ctors.Length; ++i )
{
ConstructorInfo ctor = ctors[i];
if ( !IsConstructable( ctor ) )
continue;
if ( !foundCtor )
{
foundCtor = true;
from.SendMessage( "Usage:" );
}
SendCtor( type, ctor, from );
}
if ( !foundCtor )
from.SendMessage( "That type is not marked constructable." );
}
public static void SendCtor( Type type, ConstructorInfo ctor, Mobile from )
{
ParameterInfo[] paramList = ctor.GetParameters();
StringBuilder sb = new StringBuilder();
sb.Append( type.Name );
for ( int i = 0; i < paramList.Length; ++i )
{
if ( i != 0 )
sb.Append( ',' );
sb.Append( ' ' );
sb.Append( paramList[i].ParameterType.Name );
sb.Append( ' ' );
sb.Append( paramList[i].Name );
}
from.SendMessage( sb.ToString() );
}
public class AddTarget : Target
{
private string[] m_Args;
public AddTarget( string[] args ) : base( -1, true, TargetFlags.None )
{
m_Args = args;
}
protected override void OnTarget( Mobile from, object o )
{
IPoint3D p = o as IPoint3D;
if ( p != null )
{
if ( p is Item )
p = ((Item)p).GetWorldTop();
else if ( p is Mobile )
p = ((Mobile)p).Location;
Add.Invoke( from, new Point3D( p ), new Point3D( p ), m_Args );
}
}
}
private class TileState
{
public bool m_UseFixedZ;
public int m_FixedZ;
public string[] m_Args;
public TileState( string[] args ) : this( false, 0, args )
{
}
public TileState( int fixedZ, string[] args ) : this( true, fixedZ, args )
{
}
public TileState( bool useFixedZ, int fixedZ, string[] args )
{
m_UseFixedZ = useFixedZ;
m_FixedZ = fixedZ;
m_Args = args;
}
}
private static void TileBox_Callback( Mobile from, Map map, Point3D start, Point3D end, object state )
{
TileState ts = (TileState)state;
if ( ts.m_UseFixedZ )
start.Z = end.Z = ts.m_FixedZ;
Invoke( from, start, end, ts.m_Args );
}
[Usage( "Tile <name> [params] [set {<propertyName> <value> ...}]" )]
[Description( "Tiles an item or npc by name into a targeted bounding box. Optional constructor parameters. Optional set property list." )]
public static void Tile_OnCommand( CommandEventArgs e )
{
if ( e.Length >= 1 )
BoundingBoxPicker.Begin( e.Mobile, new BoundingBoxCallback( TileBox_Callback ), new TileState( e.Arguments ) );
else
e.Mobile.SendMessage( "Format: Add <type> [params] [set {<propertyName> <value> ...}]" );
}
[Usage( "TileRXYZ <x> <y> <w> <h> <z> <name> [params] [set {<propertyName> <value> ...}]" )]
[Description( "Tiles an item or npc by name into a given bounding box, (x, y) parameters are relative to your characters position. Optional constructor parameters. Optional set property list." )]
public static void TileRXYZ_OnCommand( CommandEventArgs e )
{
if ( e.Length >= 6 )
{
Point3D p = new Point3D( e.Mobile.X + e.GetInt32( 0 ), e.Mobile.Y + e.GetInt32( 1 ), e.Mobile.Z + e.GetInt32( 4 ) );
Point3D p2 = new Point3D( p.X + e.GetInt32( 2 ) - 1, p.Y + e.GetInt32( 3 ) - 1, p.Z );
string[] subArgs = new string[e.Length - 5];
for ( int i = 0; i < subArgs.Length; ++i )
subArgs[i] = e.Arguments[i + 5];
Add.Invoke( e.Mobile, p, p2, subArgs );
}
else
{
e.Mobile.SendMessage( "Format: TileRXYZ <x> <y> <w> <h> <z> <type> [params] [set {<propertyName> <value> ...}]" );
}
}
[Usage( "TileXYZ <x> <y> <w> <h> <z> <name> [params] [set {<propertyName> <value> ...}]" )]
[Description( "Tiles an item or npc by name into a given bounding box. Optional constructor parameters. Optional set property list." )]
public static void TileXYZ_OnCommand( CommandEventArgs e )
{
if ( e.Length >= 6 )
{
Point3D p = new Point3D( e.GetInt32( 0 ), e.GetInt32( 1 ), e.GetInt32( 4 ) );
Point3D p2 = new Point3D( p.X + e.GetInt32( 2 ) - 1, p.Y + e.GetInt32( 3 ) - 1, e.GetInt32( 4 ) );
string[] subArgs = new string[e.Length - 5];
for ( int i = 0; i < subArgs.Length; ++i )
subArgs[i] = e.Arguments[i + 5];
Add.Invoke( e.Mobile, p, p2, subArgs );
}
else
{
e.Mobile.SendMessage( "Format: TileXYZ <x> <y> <w> <h> <z> <type> [params] [set {<propertyName> <value> ...}]" );
}
}
[Usage( "TileZ <z> <name> [params] [set {<propertyName> <value> ...}]" )]
[Description( "Tiles an item or npc by name into a targeted bounding box at a fixed Z location. Optional constructor parameters. Optional set property list." )]
public static void TileZ_OnCommand( CommandEventArgs e )
{
if ( e.Length >= 2 )
{
string[] subArgs = new string[e.Length - 1];
for ( int i = 0; i < subArgs.Length; ++i )
subArgs[i] = e.Arguments[i + 1];
BoundingBoxPicker.Begin( e.Mobile, new BoundingBoxCallback( TileBox_Callback ), new TileState( e.GetInt32( 0 ), subArgs ) );
}
else
{
e.Mobile.SendMessage( "Format: TileZ <z> <type> [params] [set {<propertyName> <value> ...}]" );
}
}
private static Type m_ConstructableType = typeof( ConstructableAttribute );
public static bool IsConstructable( ConstructorInfo ctor )
{
return ctor.IsDefined( m_ConstructableType, false );
}
private static Type m_EnumType = typeof( Enum );
public static bool IsEnum( Type type )
{
return type.IsSubclassOf( m_EnumType );
}
private static Type m_TypeType = typeof( Type );
public static bool IsType( Type type )
{
return ( type == m_TypeType || type.IsSubclassOf( m_TypeType ) );
}
private static Type m_ParsableType = typeof( ParsableAttribute );
public static bool IsParsable( Type type )
{
return type.IsDefined( m_ParsableType, false );
}
private static Type[] m_ParseTypes = new Type[]{ typeof( string ) };
private static object[] m_ParseArgs = new object[1];
public static object ParseParsable( Type type, string value )
{
MethodInfo method = type.GetMethod( "Parse", m_ParseTypes );
m_ParseArgs[0] = value;
return method.Invoke( null, m_ParseArgs );
}
private static Type[] m_SignedNumerics = new Type[]
{
typeof( Int64 ),
typeof( Int32 ),
typeof( Int16 ),
typeof( SByte )
};
public static bool IsSignedNumeric( Type type )
{
for ( int i = 0; i < m_SignedNumerics.Length; ++i )
if ( type == m_SignedNumerics[i] )
return true;
return false;
}
private static Type[] m_UnsignedNumerics = new Type[]
{
typeof( UInt64 ),
typeof( UInt32 ),
typeof( UInt16 ),
typeof( Byte )
};
public static bool IsUnsignedNumeric( Type type )
{
for ( int i = 0; i < m_UnsignedNumerics.Length; ++i )
if ( type == m_UnsignedNumerics[i] )
return true;
return false;
}
}
}

View file

@ -0,0 +1,40 @@
using System;
namespace Server
{
public class UsageAttribute : Attribute
{
private string m_Usage;
public string Usage{ get{ return m_Usage; } }
public UsageAttribute( string usage )
{
m_Usage = usage;
}
}
public class DescriptionAttribute : Attribute
{
private string m_Description;
public string Description{ get{ return m_Description; } }
public DescriptionAttribute( string description )
{
m_Description = description;
}
}
public class AliasesAttribute : Attribute
{
private string[] m_Aliases;
public string[] Aliases{ get{ return m_Aliases; } }
public AliasesAttribute( params string[] aliases )
{
m_Aliases = aliases;
}
}
}

458
Scripts/Commands/Batch.cs Normal file
View file

@ -0,0 +1,458 @@
using System;
using System.Reflection;
using System.Collections;
using Server;
using Server.Gumps;
using Server.Network;
using Server.Commands;
using Server.Commands.Generic;
namespace Server.Commands
{
public class Batch : BaseCommand
{
private BaseCommandImplementor m_Scope;
private string m_Condition;
private ArrayList m_BatchCommands;
public BaseCommandImplementor Scope
{
get{ return m_Scope; }
set{ m_Scope = value; }
}
public string Condition
{
get{ return m_Condition; }
set{ m_Condition = value; }
}
public ArrayList BatchCommands
{
get{ return m_BatchCommands; }
}
public Batch()
{
Commands = new string[]{ "Batch" };
ListOptimized = true;
m_BatchCommands = new ArrayList();
m_Condition = "";
}
public override void ExecuteList( CommandEventArgs e, ArrayList list )
{
if ( list.Count == 0 )
{
LogFailure( "Nothing was found to use this command on." );
return;
}
try
{
BaseCommand[] commands = new BaseCommand[m_BatchCommands.Count];
CommandEventArgs[] eventArgs = new CommandEventArgs[m_BatchCommands.Count];
for ( int i = 0; i < m_BatchCommands.Count; ++i )
{
BatchCommand bc = (BatchCommand)m_BatchCommands[i];
string commandString, argString;
string[] args;
bc.GetDetails( out commandString, out argString, out args );
BaseCommand command = (BaseCommand)m_Scope.Commands[commandString];
commands[i] = command;
eventArgs[i] = new CommandEventArgs( e.Mobile, commandString, argString, args );
if ( command == null )
{
e.Mobile.SendMessage( "That is either an invalid command name or one that does not support this modifier: {0}.", commandString );
return;
}
else if ( e.Mobile.AccessLevel < command.AccessLevel )
{
e.Mobile.SendMessage( "You do not have access to that command: {0}.", commandString );
return;
}
else if ( !command.ValidateArgs( m_Scope, eventArgs[i] ) )
{
return;
}
}
for ( int i = 0; i < commands.Length; ++i )
{
BaseCommand command = commands[i];
BatchCommand bc = (BatchCommand)m_BatchCommands[i];
if ( list.Count > 20 )
CommandLogging.Enabled = false;
ArrayList usedList;
if ( Utility.InsensitiveCompare( bc.Object, "Current" ) == 0 )
{
usedList = list;
}
else
{
Hashtable propertyChains = new Hashtable();
usedList = new ArrayList( list.Count );
for ( int j = 0; j < list.Count; ++j )
{
object obj = list[j];
if ( obj == null )
continue;
Type type = obj.GetType();
PropertyInfo[] chain = (PropertyInfo[])propertyChains[type];
string failReason = "";
if ( chain == null && !propertyChains.Contains( type ) )
propertyChains[type] = chain = Properties.GetPropertyInfoChain( e.Mobile, type, bc.Object, PropertyAccess.Read, ref failReason );
if ( chain == null )
continue;
PropertyInfo endProp = Properties.GetPropertyInfo( ref obj, chain, ref failReason );
if ( endProp == null )
continue;
try
{
obj = endProp.GetValue( obj, null );
if ( obj != null )
usedList.Add( obj );
}
catch
{
}
}
}
command.ExecuteList( eventArgs[i], usedList );
if ( list.Count > 20 )
CommandLogging.Enabled = true;
command.Flush( e.Mobile, list.Count > 20 );
}
}
catch ( Exception ex )
{
e.Mobile.SendMessage( ex.Message );
}
}
public bool Run( Mobile from )
{
if ( m_Scope == null )
{
from.SendMessage( "You must select the batch command scope." );
return false;
}
else if ( m_Condition.Length > 0 && !m_Scope.SupportsConditionals )
{
from.SendMessage( "This command scope does not support conditionals." );
return false;
}
else if ( m_Condition.Length > 0 && !Utility.InsensitiveStartsWith( m_Condition, "where" ) )
{
from.SendMessage( "The condition field must start with \"where\"." );
return false;
}
string[] args = CommandSystem.Split( m_Condition );
m_Scope.Process( from, this, args );
return true;
}
public static void Initialize()
{
CommandSystem.Register( "Batch", AccessLevel.Counselor, new CommandEventHandler( Batch_OnCommand ) );
}
[Usage( "Batch" )]
[Description( "Allows multiple commands to be run at the same time." )]
public static void Batch_OnCommand( CommandEventArgs e )
{
Batch batch = new Batch();
e.Mobile.SendGump( new BatchGump( e.Mobile, batch ) );
}
}
public class BatchCommand
{
private string m_Command;
private string m_Object;
public string Command
{
get{ return m_Command; }
set{ m_Command = value; }
}
public string Object
{
get{ return m_Object; }
set{ m_Object = value; }
}
public void GetDetails( out string command, out string argString, out string[] args )
{
int indexOf = m_Command.IndexOf( ' ' );
if ( indexOf >= 0 )
{
argString = m_Command.Substring( indexOf + 1 );
command = m_Command.Substring( 0, indexOf );
args = CommandSystem.Split( argString );
}
else
{
argString = "";
command = m_Command.ToLower();
args = new string[0];
}
}
public BatchCommand( string command, string obj )
{
m_Command = command;
m_Object = obj;
}
}
public class BatchGump : BaseGridGump
{
private Mobile m_From;
private Batch m_Batch;
public BatchGump( Mobile from, Batch batch ) : base( 30, 30 )
{
m_From = from;
m_Batch = batch;
Render();
}
public void Render()
{
AddNewPage();
/* Header */
AddEntryHeader( 20 );
AddEntryHtml( 180, Center( "Batch Commands" ) );
AddEntryHeader( 20 );
AddNewLine();
AddEntryHeader( 9 );
AddEntryLabel( 191, "Run Batch" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, GetButtonID( 1, 0, 0 ), ArrowRightWidth, ArrowRightHeight );
AddNewLine();
AddBlankLine();
/* Scope */
AddEntryHeader( 20 );
AddEntryHtml( 180, Center( "Scope" ) );
AddEntryHeader( 20 );
AddNewLine();
AddEntryHeader( 9 );
AddEntryLabel( 191, m_Batch.Scope == null ? "Select Scope" : m_Batch.Scope.Accessors[0] );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, GetButtonID( 1, 0, 1 ), ArrowRightWidth, ArrowRightHeight );
AddNewLine();
AddBlankLine();
/* Condition */
AddEntryHeader( 20 );
AddEntryHtml( 180, Center( "Condition" ) );
AddEntryHeader( 20 );
AddNewLine();
AddEntryHeader( 9 );
AddEntryText( 202, 0, m_Batch.Condition );
AddEntryHeader( 9 );
AddNewLine();
AddBlankLine();
/* Commands */
AddEntryHeader( 20 );
AddEntryHtml( 180, Center( "Commands" ) );
AddEntryHeader( 20 );
for ( int i = 0; i < m_Batch.BatchCommands.Count; ++i )
{
BatchCommand bc = (BatchCommand)m_Batch.BatchCommands[i];
AddNewLine();
AddImageTiled( CurrentX, CurrentY, 9, 2, 0x24A8 );
AddImageTiled( CurrentX, CurrentY + 2, 2, EntryHeight + OffsetSize + EntryHeight - 4, 0x24A8 );
AddImageTiled( CurrentX, CurrentY + EntryHeight + OffsetSize + EntryHeight - 2, 9, 2, 0x24A8 );
AddImageTiled( CurrentX + 3, CurrentY + 3, 6, EntryHeight + EntryHeight - 4 - OffsetSize, HeaderGumpID );
IncreaseX( 9 );
AddEntryText( 202, 1+(i*2), bc.Command );
AddEntryHeader( 9, 2 );
AddNewLine();
IncreaseX( 9 );
AddEntryText( 202, 2+(i*2), bc.Object );
}
AddNewLine();
AddEntryHeader( 9 );
AddEntryLabel( 191, "Add New Command" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, GetButtonID( 1, 0, 2 ), ArrowRightWidth, ArrowRightHeight );
FinishPage();
}
public override void OnResponse( NetState sender, RelayInfo info )
{
int type, index;
if ( !SplitButtonID( info.ButtonID, 1, out type, out index ) )
return;
TextRelay entry = info.GetTextEntry( 0 );
if ( entry != null )
m_Batch.Condition = entry.Text;
for ( int i = m_Batch.BatchCommands.Count - 1; i >= 0; --i )
{
BatchCommand sc = (BatchCommand)m_Batch.BatchCommands[i];
entry = info.GetTextEntry( 1 + (i * 2) );
if ( entry != null )
sc.Command = entry.Text;
entry = info.GetTextEntry( 2 + (i * 2) );
if ( entry != null )
sc.Object = entry.Text;
if ( sc.Command == "" && sc.Object == "" )
m_Batch.BatchCommands.RemoveAt( i );
}
switch ( type )
{
case 0: // main
{
switch ( index )
{
case 0: // run
{
m_Batch.Run( m_From );
break;
}
case 1: // set scope
{
m_From.SendGump( new BatchScopeGump( m_From, m_Batch ) );
return;
}
case 2: // add command
{
m_Batch.BatchCommands.Add( new BatchCommand( "", "" ) );
break;
}
}
break;
}
}
m_From.SendGump( new BatchGump( m_From, m_Batch ) );
}
}
public class BatchScopeGump : BaseGridGump
{
private Mobile m_From;
private Batch m_Batch;
public BatchScopeGump( Mobile from, Batch batch ) : base( 30, 30 )
{
m_From = from;
m_Batch = batch;
Render();
}
public void Render()
{
AddNewPage();
/* Header */
AddEntryHeader( 20 );
AddEntryHtml( 140, Center( "Change Scope" ) );
AddEntryHeader( 20 );
/* Options */
for ( int i = 0; i < BaseCommandImplementor.Implementors.Count; ++i )
{
BaseCommandImplementor impl = (BaseCommandImplementor)BaseCommandImplementor.Implementors[i];
if ( m_From.AccessLevel < impl.AccessLevel )
continue;
AddNewLine();
AddEntryLabel( 20 + OffsetSize + 140, impl.Accessors[0] );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, GetButtonID( 1, 0, i ), ArrowRightWidth, ArrowRightHeight );
}
FinishPage();
}
public override void OnResponse( NetState sender, RelayInfo info )
{
int type, index;
if ( SplitButtonID( info.ButtonID, 1, out type, out index ) )
{
switch ( type )
{
case 0:
{
if ( index < BaseCommandImplementor.Implementors.Count )
{
BaseCommandImplementor impl = (BaseCommandImplementor)BaseCommandImplementor.Implementors[index];
if ( m_From.AccessLevel >= impl.AccessLevel )
m_Batch.Scope = impl;
}
break;
}
}
}
m_From.SendGump( new BatchGump( m_From, m_Batch ) );
}
}
}

View file

@ -0,0 +1,68 @@
using System;
using Server;
using Server.Targeting;
namespace Server
{
public delegate void BoundingBoxCallback( Mobile from, Map map, Point3D start, Point3D end, object state );
public class BoundingBoxPicker
{
public static void Begin( Mobile from, BoundingBoxCallback callback, object state )
{
from.SendMessage( "Target the first location of the bounding box." );
from.Target = new PickTarget( callback, state );
}
private class PickTarget : Target
{
private Point3D m_Store;
private bool m_First;
private Map m_Map;
private BoundingBoxCallback m_Callback;
private object m_State;
public PickTarget( BoundingBoxCallback callback, object state ) : this( Point3D.Zero, true, null, callback, state )
{
}
public PickTarget( Point3D store, bool first, Map map, BoundingBoxCallback callback, object state ) : base( -1, true, TargetFlags.None )
{
m_Store = store;
m_First = first;
m_Map = map;
m_Callback = callback;
m_State = state;
}
protected override void OnTarget( Mobile from, object targeted )
{
IPoint3D p = targeted as IPoint3D;
if ( p == null )
return;
else if ( p is Item )
p = ((Item)p).GetWorldTop();
if ( m_First )
{
from.SendMessage( "Target another location to complete the bounding box." );
from.Target = new PickTarget( new Point3D( p ), false, from.Map, m_Callback, m_State );
}
else if ( from.Map != m_Map )
{
from.SendMessage( "Both locations must reside on the same map." );
}
else if ( m_Map != null && m_Map != Map.Internal && m_Callback != null )
{
Point3D start = m_Store;
Point3D end = new Point3D( p );
Utility.FixPoints( ref start, ref end );
m_Callback( from, m_Map, start, end, m_State );
}
}
}
}
}

View file

@ -0,0 +1,90 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Commands
{
public class ConvertPlayers
{
public static void Initialize()
{
CommandSystem.Register( "ConvertPlayers", AccessLevel.Administrator, new CommandEventHandler( Convert_OnCommand ) );
}
public static void Convert_OnCommand( CommandEventArgs e )
{
e.Mobile.SendMessage( "Converting all players to PlayerMobile. You will be disconnected. Please Restart the server after the world has finished saving." );
ArrayList mobs = new ArrayList( World.Mobiles.Values );
int count = 0;
foreach ( Mobile m in mobs )
{
if ( m.Player && !(m is PlayerMobile ) )
{
count++;
if ( m.NetState != null )
m.NetState.Dispose();
PlayerMobile pm = new PlayerMobile( m.Serial );
pm.DefaultMobileInit();
List<Item> copy = new List<Item>( m.Items );
for (int i=0;i<copy.Count;i++)
pm.AddItem( copy[i] );
CopyProps( pm, m );
for (int i=0;i<m.Skills.Length;i++)
{
pm.Skills[i].Base = m.Skills[i].Base;
pm.Skills[i].SetLockNoRelay( m.Skills[i].Lock );
}
World.Mobiles[m.Serial] = pm;
}
}
if ( count > 0 )
{
NetState.ProcessDisposedQueue();
World.Save();
Console.WriteLine( "{0} players have been converted to PlayerMobile. Please restart the server.", count );
while ( true )
Console.ReadLine();
}
else
{
e.Mobile.SendMessage( "Couldn't find any Players to convert." );
}
}
private static void CopyProps( Mobile to, Mobile from )
{
Type type = typeof( Mobile );
PropertyInfo[] props = type.GetProperties( BindingFlags.Public | BindingFlags.Instance );
for (int p=0;p<props.Length;p++)
{
PropertyInfo prop = props[p];
if ( prop.CanRead && prop.CanWrite )
{
try
{
prop.SetValue( to, prop.GetValue( from, null ), null );
}
catch
{
}
}
}
}
}
}

1139
Scripts/Commands/Decorate.cs Normal file

File diff suppressed because it is too large Load diff

2404
Scripts/Commands/Docs.cs Normal file

File diff suppressed because it is too large Load diff

145
Scripts/Commands/Dupe.cs Normal file
View file

@ -0,0 +1,145 @@
using System;
using System.Reflection;
using Server.Items;
using Server.Targeting;
namespace Server.Commands
{
public class Dupe
{
public static void Initialize()
{
CommandSystem.Register( "Dupe", AccessLevel.GameMaster, new CommandEventHandler( Dupe_OnCommand ) );
CommandSystem.Register( "DupeInBag", AccessLevel.GameMaster, new CommandEventHandler( DupeInBag_OnCommand ) );
}
[Usage( "Dupe [amount]" )]
[Description( "Dupes a targeted item." )]
private static void Dupe_OnCommand( CommandEventArgs e )
{
int amount = 1;
if ( e.Length >= 1 )
amount = e.GetInt32( 0 );
e.Mobile.Target = new DupeTarget( false, amount > 0 ? amount : 1 );
e.Mobile.SendMessage( "What do you wish to dupe?" );
}
[Usage( "DupeInBag <count>" )]
[Description( "Dupes an item at it's current location (count) number of times." )]
private static void DupeInBag_OnCommand( CommandEventArgs e )
{
int amount = 1;
if ( e.Length >= 1 )
amount = e.GetInt32( 0 );
e.Mobile.Target = new DupeTarget( true, amount > 0 ? amount : 1 );
e.Mobile.SendMessage( "What do you wish to dupe?" );
}
private class DupeTarget : Target
{
private bool m_InBag;
private int m_Amount;
public DupeTarget( bool inbag, int amount )
: base( 15, false, TargetFlags.None )
{
m_InBag = inbag;
m_Amount = amount;
}
protected override void OnTarget( Mobile from, object targ )
{
bool done = false;
if ( !( targ is Item ) )
{
from.SendMessage( "You can only dupe items." );
return;
}
CommandLogging.WriteLine( from, "{0} {1} duping {2} (inBag={3}; amount={4})", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( targ ), m_InBag, m_Amount );
Item copy = (Item)targ;
Container pack;
if ( m_InBag )
{
if ( copy.Parent is Container )
pack = (Container)copy.Parent;
else if ( copy.Parent is Mobile )
pack = ( (Mobile)copy.Parent ).Backpack;
else
pack = null;
}
else
pack = from.Backpack;
Type t = copy.GetType();
//ConstructorInfo[] info = t.GetConstructors();
ConstructorInfo c = t.GetConstructor( Type.EmptyTypes );
if ( c != null )
{
try
{
from.SendMessage( "Duping {0}...", m_Amount );
for ( int i = 0; i < m_Amount; i++ )
{
object o = c.Invoke( null );
if ( o != null && o is Item )
{
Item newItem = (Item)o;
CopyProperties( newItem, copy );//copy.Dupe( item, copy.Amount );
copy.OnAfterDuped( newItem );
newItem.Parent = null;
if ( pack != null )
pack.DropItem( newItem );
else
newItem.MoveToWorld( from.Location, from.Map );
CommandLogging.WriteLine( from, "{0} {1} duped {2} creating {3}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( targ ), CommandLogging.Format( newItem ) );
}
}
from.SendMessage( "Done" );
done = true;
}
catch
{
from.SendMessage( "Error!" );
return;
}
}
if ( !done )
{
from.SendMessage( "Unable to dupe. Item must have a 0 parameter constructor." );
}
}
}
private static void CopyProperties( Item dest, Item src )
{
PropertyInfo[] props = src.GetType().GetProperties();
for ( int i = 0; i < props.Length; i++ )
{
try
{
if ( props[i].CanRead && props[i].CanWrite )
{
//Console.WriteLine( "Setting {0} = {1}", props[i].Name, props[i].GetValue( src, null ) );
props[i].SetValue( dest, props[i].GetValue( src, null ), null );
}
}
catch
{
//Console.WriteLine( "Denied" );
}
}
}
}
}

View file

@ -0,0 +1,83 @@
using System;
using System.Collections;
using System.IO;
using Server;
using Server.Items;
namespace Server.Commands
{
public class ExportCommand
{
private const string ExportFile = @"C:\Uo\WorldForge\items.wsc";
public static void Initialize()
{
CommandSystem.Register( "ExportWSC", AccessLevel.Administrator, new CommandEventHandler( Export_OnCommand ) );
}
public static void Export_OnCommand( CommandEventArgs e )
{
StreamWriter w = new StreamWriter( ExportFile );
ArrayList remove = new ArrayList();
int count = 0;
e.Mobile.SendMessage( "Exporting all static items to \"{0}\"...", ExportFile );
e.Mobile.SendMessage( "This will delete all static items in the world. Please make a backup." );
foreach ( Item item in World.Items.Values )
{
if ( ( item is Static || item is BaseFloor || item is BaseWall )
&& item.RootParent == null )
{
w.WriteLine( "SECTION WORLDITEM {0}", count );
w.WriteLine( "{" );
w.WriteLine( "SERIAL {0}", item.Serial );
w.WriteLine( "NAME #" );
w.WriteLine( "NAME2 #" );
w.WriteLine( "ID {0}", item.ItemID );
w.WriteLine( "X {0}", item.X );
w.WriteLine( "Y {0}", item.Y );
w.WriteLine( "Z {0}", item.Z );
w.WriteLine( "COLOR {0}", item.Hue );
w.WriteLine( "CONT -1" );
w.WriteLine( "TYPE 0" );
w.WriteLine( "AMOUNT 1" );
w.WriteLine( "WEIGHT 255" );
w.WriteLine( "OWNER -1" );
w.WriteLine( "SPAWN -1" );
w.WriteLine( "VALUE 1" );
w.WriteLine( "}" );
w.WriteLine( "" );
count++;
remove.Add( item );
w.Flush();
}
}
w.Close();
foreach( Item item in remove )
item.Delete();
e.Mobile.SendMessage( "Export complete. Exported {0} statics.", count );
}
}
}
/*SECTION WORLDITEM 1
{
SERIAL 1073741830
NAME #
NAME2 #
ID 1709
X 1439
Y 1613
Z 20
CONT -1
TYPE 12
AMOUNT 1
WEIGHT 25500
OWNER -1
SPAWN -1
VALUE 1
}*/

View file

@ -0,0 +1,427 @@
using System;
using System.IO;
using System.Xml;
using System.Collections;
using System.Reflection;
using Server;
using Server.Items;
using Server.Commands;
namespace Server.Commands
{
public class Categorization
{
private static CategoryEntry m_RootItems, m_RootMobiles;
public static CategoryEntry Items
{
get
{
if ( m_RootItems == null )
Load();
return m_RootItems;
}
}
public static CategoryEntry Mobiles
{
get
{
if ( m_RootMobiles == null )
Load();
return m_RootMobiles;
}
}
public static void Initialize()
{
CommandSystem.Register( "RebuildCategorization", AccessLevel.Administrator, new CommandEventHandler( RebuildCategorization_OnCommand ) );
}
[Usage( "RebuildCategorization" )]
[Description( "Rebuilds the categorization data file used by the Add command." )]
public static void RebuildCategorization_OnCommand( CommandEventArgs e )
{
CategoryEntry root = new CategoryEntry( null, "Add Menu", new CategoryEntry[]{ Items, Mobiles } );
Export( root, "Data/objects.xml", "Objects" );
e.Mobile.SendMessage( "Categorization menu rebuilt." );
}
public static void RecurseFindCategories( CategoryEntry ce, ArrayList list )
{
list.Add( ce );
for ( int i = 0; i < ce.SubCategories.Length; ++i )
RecurseFindCategories( ce.SubCategories[i], list );
}
public static void Export( CategoryEntry ce, string fileName, string title )
{
XmlTextWriter xml = new XmlTextWriter( fileName, System.Text.Encoding.UTF8 );
xml.Indentation = 1;
xml.IndentChar = '\t';
xml.Formatting = Formatting.Indented;
xml.WriteStartDocument( true );
RecurseExport( xml, ce );
xml.Flush();
xml.Close();
}
public static void RecurseExport( XmlTextWriter xml, CategoryEntry ce )
{
xml.WriteStartElement( "category" );
xml.WriteAttributeString( "title", ce.Title );
ArrayList subCats = new ArrayList( ce.SubCategories );
subCats.Sort( new CategorySorter() );
for ( int i = 0; i < subCats.Count; ++i )
RecurseExport( xml, (CategoryEntry)subCats[i] );
ce.Matched.Sort( new CategorySorter() );
for ( int i = 0; i < ce.Matched.Count; ++i )
{
CategoryTypeEntry cte = (CategoryTypeEntry)ce.Matched[i];
xml.WriteStartElement( "object" );
xml.WriteAttributeString( "type", cte.Type.ToString() );
object obj = cte.Object;
if ( obj is Item )
{
Item item = (Item)obj;
int itemID = item.ItemID;
if ( item is BaseAddon && ((BaseAddon)item).Components.Count == 1 )
itemID = ((AddonComponent)(((BaseAddon)item).Components[0])).ItemID;
if ( itemID >= 0x4000 )
itemID = 1;
xml.WriteAttributeString( "gfx", XmlConvert.ToString( itemID ) );
int hue = item.Hue & 0x7FFF;
if ( (hue & 0x4000) != 0 )
hue = 0;
if ( hue != 0 )
xml.WriteAttributeString( "hue", XmlConvert.ToString( hue ) );
item.Delete();
}
else if ( obj is Mobile )
{
Mobile mob = (Mobile)obj;
int itemID = ShrinkTable.Lookup( mob, 1 );
xml.WriteAttributeString( "gfx", XmlConvert.ToString( itemID ) );
int hue = mob.Hue & 0x7FFF;
if ( (hue & 0x4000) != 0 )
hue = 0;
if ( hue != 0 )
xml.WriteAttributeString( "hue", XmlConvert.ToString( hue ) );
mob.Delete();
}
xml.WriteEndElement();
}
xml.WriteEndElement();
}
public static void Load()
{
ArrayList types = new ArrayList();
AddTypes( Core.Assembly, types );
for ( int i = 0; i < ScriptCompiler.Assemblies.Length; ++i )
AddTypes( ScriptCompiler.Assemblies[i], types );
m_RootItems = Load( types, "Data/items.cfg" );
m_RootMobiles = Load( types, "Data/mobiles.cfg" );
}
private static CategoryEntry Load( ArrayList types, string config )
{
CategoryLine[] lines = CategoryLine.Load( config );
if ( lines.Length > 0 )
{
int index = 0;
CategoryEntry root = new CategoryEntry( null, lines, ref index );
Fill( root, types );
return root;
}
return new CategoryEntry();
}
private static Type typeofItem = typeof( Item );
private static Type typeofMobile = typeof( Mobile );
private static Type typeofConstructable = typeof( ConstructableAttribute );
private static bool IsConstructable( Type type )
{
if ( !type.IsSubclassOf( typeofItem ) && !type.IsSubclassOf( typeofMobile ) )
return false;
ConstructorInfo ctor = type.GetConstructor( Type.EmptyTypes );
return ( ctor != null && ctor.IsDefined( typeofConstructable, false ) );
}
private static void AddTypes( Assembly asm, ArrayList types )
{
Type[] allTypes = asm.GetTypes();
for ( int i = 0; i < allTypes.Length; ++i )
{
Type type = allTypes[i];
if ( type.IsAbstract )
continue;
if ( IsConstructable( type ) )
types.Add( type );
}
}
private static void Fill( CategoryEntry root, ArrayList list )
{
for ( int i = 0; i < list.Count; ++i )
{
Type type = (Type)list[i];
CategoryEntry match = GetDeepestMatch( root, type );
if ( match == null )
continue;
try
{
match.Matched.Add( new CategoryTypeEntry( type ) );
}
catch
{
}
}
}
private static CategoryEntry GetDeepestMatch( CategoryEntry root, Type type )
{
if ( !root.IsMatch( type ) )
return null;
for ( int i = 0; i < root.SubCategories.Length; ++i )
{
CategoryEntry check = GetDeepestMatch( root.SubCategories[i], type );
if ( check != null )
return check;
}
return root;
}
}
public class CategorySorter : IComparer
{
public int Compare( object x, object y )
{
string a = null, b = null;
if ( x is CategoryEntry )
a = ((CategoryEntry)x).Title;
else if ( x is CategoryTypeEntry )
a = ((CategoryTypeEntry)x).Type.Name;
if ( y is CategoryEntry )
b = ((CategoryEntry)y).Title;
else if ( y is CategoryTypeEntry )
b = ((CategoryTypeEntry)y).Type.Name;
if ( a == null && b == null )
return 0;
if ( a == null )
return 1;
if ( b == null )
return -1;
return a.CompareTo( b );
}
}
public class CategoryTypeEntry
{
private Type m_Type;
private object m_Object;
public Type Type{ get{ return m_Type; } }
public object Object{ get{ return m_Object; } }
public CategoryTypeEntry( Type type )
{
m_Type = type;
m_Object = Activator.CreateInstance( type );
}
}
public class CategoryEntry
{
private string m_Title;
private Type[] m_Matches;
private CategoryEntry[] m_SubCategories;
private CategoryEntry m_Parent;
private ArrayList m_Matched;
public string Title{ get{ return m_Title; } }
public Type[] Matches{ get{ return m_Matches; } }
public CategoryEntry Parent{ get{ return m_Parent; } }
public CategoryEntry[] SubCategories{ get{ return m_SubCategories; } }
public ArrayList Matched{ get{ return m_Matched; } }
public CategoryEntry()
{
m_Title = "(empty)";
m_Matches = new Type[0];
m_SubCategories = new CategoryEntry[0];
m_Matched = new ArrayList();
}
public CategoryEntry( CategoryEntry parent, string title, CategoryEntry[] subCats )
{
m_Parent = parent;
m_Title = title;
m_SubCategories = subCats;
m_Matches = new Type[0];
m_Matched = new ArrayList();
}
public bool IsMatch( Type type )
{
bool isMatch = false;
for ( int i = 0; !isMatch && i < m_Matches.Length; ++i )
isMatch = ( type == m_Matches[i] || type.IsSubclassOf( m_Matches[i] ) );
return isMatch;
}
public CategoryEntry( CategoryEntry parent, CategoryLine[] lines, ref int index )
{
m_Parent = parent;
string text = lines[index].Text;
int start = text.IndexOf( '(' );
if ( start < 0 )
throw new FormatException( String.Format( "Input string not correctly formatted ('{0}')", text ) );
m_Title = text.Substring( 0, start ).Trim();
int end = text.IndexOf( ')', ++start );
if ( end < start )
throw new FormatException( String.Format( "Input string not correctly formatted ('{0}')", text ) );
text = text.Substring( start, end-start );
string[] split = text.Split( ';' );
ArrayList list = new ArrayList();
for ( int i = 0; i < split.Length; ++i )
{
Type type = ScriptCompiler.FindTypeByName( split[i].Trim() );
if ( type == null )
Console.WriteLine( "Match type not found ('{0}')", split[i].Trim() );
else
list.Add( type );
}
m_Matches = (Type[])list.ToArray( typeof( Type ) );
list.Clear();
int ourIndentation = lines[index].Indentation;
++index;
while ( index < lines.Length && lines[index].Indentation > ourIndentation )
list.Add( new CategoryEntry( this, lines, ref index ) );
m_SubCategories = (CategoryEntry[])list.ToArray( typeof( CategoryEntry ) );
list.Clear();
m_Matched = list;
}
}
public class CategoryLine
{
private int m_Indentation;
private string m_Text;
public int Indentation{ get{ return m_Indentation; } }
public string Text{ get{ return m_Text; } }
public CategoryLine( string input )
{
int index;
for ( index = 0; index < input.Length; ++index )
{
if ( Char.IsLetter( input, index ) )
break;
}
if ( index >= input.Length )
throw new FormatException( String.Format( "Input string not correctly formatted ('{0}')", input ) );
m_Indentation = index;
m_Text = input.Substring( index );
}
public static CategoryLine[] Load( string path )
{
ArrayList list = new ArrayList();
if ( File.Exists( path ) )
{
using ( StreamReader ip = new StreamReader( path ) )
{
string line;
while ( (line = ip.ReadLine()) != null )
list.Add( new CategoryLine( line ) );
}
}
return (CategoryLine[])list.ToArray( typeof( CategoryLine ) );
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,205 @@
using System;
using System.Collections;
using Server;
using Server.Gumps;
namespace Server.Commands.Generic
{
public enum ObjectTypes
{
Both,
Items,
Mobiles,
All
}
public abstract class BaseCommand
{
private string[] m_Commands;
private AccessLevel m_AccessLevel;
private CommandSupport m_Implementors;
private ObjectTypes m_ObjectTypes;
private bool m_ListOptimized;
private string m_Usage;
private string m_Description;
public bool ListOptimized
{
get{ return m_ListOptimized; }
set{ m_ListOptimized = value; }
}
public string[] Commands
{
get{ return m_Commands; }
set{ m_Commands = value; }
}
public string Usage
{
get{ return m_Usage; }
set{ m_Usage = value; }
}
public string Description
{
get{ return m_Description; }
set{ m_Description = value; }
}
public AccessLevel AccessLevel
{
get{ return m_AccessLevel; }
set{ m_AccessLevel = value; }
}
public ObjectTypes ObjectTypes
{
get{ return m_ObjectTypes; }
set{ m_ObjectTypes = value; }
}
public CommandSupport Supports
{
get{ return m_Implementors; }
set{ m_Implementors = value; }
}
public BaseCommand()
{
m_Responses = new ArrayList();
m_Failures = new ArrayList();
}
public static bool IsAccessible( Mobile from, object obj )
{
if ( from.AccessLevel >= AccessLevel.Administrator || obj == null )
return true;
Mobile mob;
if ( obj is Mobile )
mob = (Mobile)obj;
else if ( obj is Item )
mob = ((Item)obj).RootParent as Mobile;
else
mob = null;
if ( mob == null || mob == from || from.AccessLevel > mob.AccessLevel )
return true;
return false;
}
public virtual void ExecuteList( CommandEventArgs e, ArrayList list )
{
for ( int i = 0; i < list.Count; ++i )
Execute( e, list[i] );
}
public virtual void Execute( CommandEventArgs e, object obj )
{
}
public virtual bool ValidateArgs( BaseCommandImplementor impl, CommandEventArgs e )
{
return true;
}
private ArrayList m_Responses, m_Failures;
private class MessageEntry
{
public string m_Message;
public int m_Count;
public MessageEntry( string message )
{
m_Message = message;
m_Count = 1;
}
public override string ToString()
{
if ( m_Count > 1 )
return String.Format( "{0} ({1})", m_Message, m_Count );
return m_Message;
}
}
public void AddResponse( string message )
{
for ( int i = 0; i < m_Responses.Count; ++i )
{
MessageEntry entry = (MessageEntry)m_Responses[i];
if ( entry.m_Message == message )
{
++entry.m_Count;
return;
}
}
if ( m_Responses.Count == 10 )
return;
m_Responses.Add( new MessageEntry( message ) );
}
public void AddResponse( Gump gump )
{
m_Responses.Add( gump );
}
public void LogFailure( string message )
{
for ( int i = 0; i < m_Failures.Count; ++i )
{
MessageEntry entry = (MessageEntry)m_Failures[i];
if ( entry.m_Message == message )
{
++entry.m_Count;
return;
}
}
if ( m_Failures.Count == 10 )
return;
m_Failures.Add( new MessageEntry( message ) );
}
public void Flush( Mobile from, bool flushToLog )
{
if ( m_Responses.Count > 0 )
{
for ( int i = 0; i < m_Responses.Count; ++i )
{
object obj = m_Responses[i];
if ( obj is MessageEntry )
{
from.SendMessage( ((MessageEntry)obj).ToString() );
if ( flushToLog )
CommandLogging.WriteLine( from, ((MessageEntry)obj).ToString() );
}
else if ( obj is Gump )
{
from.SendGump( (Gump) obj );
}
}
}
else
{
for ( int i = 0; i < m_Failures.Count; ++i )
from.SendMessage( ((MessageEntry)m_Failures[i]).ToString() );
}
m_Responses.Clear();
m_Failures.Clear();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,570 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Server;
using Server.Gumps;
using Server.Network;
using Server.Targeting;
using Server.Targets;
namespace Server.Commands.Generic
{
public class InterfaceCommand : BaseCommand
{
public InterfaceCommand()
{
AccessLevel = AccessLevel.GameMaster;
Supports = CommandSupport.Complex | CommandSupport.Simple;
Commands = new string[]{ "Interface" };
ObjectTypes = ObjectTypes.Both;
Usage = "Interface [view <properties ...>]";
Description = "Opens an interface to interact with matched objects. Generally used with condition arguments.";
ListOptimized = true;
}
public override void ExecuteList( CommandEventArgs e, ArrayList list )
{
if ( list.Count > 0 )
{
List<string> columns = new List<string>();
columns.Add( "Object" );
if ( e.Length > 0 )
{
int offset = 0;
if ( Insensitive.Equals( e.GetString( 0 ), "view" ) )
++offset;
while ( offset < e.Length )
columns.Add( e.GetString( offset++ ) );
}
e.Mobile.SendGump( new InterfaceGump( e.Mobile, columns.ToArray(), list, 0, null ) );
}
else
{
AddResponse( "No matching objects found." );
}
}
}
public class InterfaceGump : BaseGridGump
{
private Mobile m_From;
private string[] m_Columns;
private ArrayList m_List;
private int m_Page;
private object m_Select;
private const int EntriesPerPage = 15;
public InterfaceGump( Mobile from, string[] columns, ArrayList list, int page, object select ) : base( 30, 30 )
{
m_From = from;
m_Columns = columns;
m_List = list;
m_Page = page;
m_Select = select;
Render();
}
public void Render()
{
AddNewPage();
if ( m_Page > 0 )
AddEntryButton( 20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight );
else
AddEntryHeader( 20 );
AddEntryHtml( 40 + ( m_Columns.Length * 130 ) - 20 + ( ( m_Columns.Length - 2 ) * OffsetSize ), Center( String.Format( "Page {0} of {1}", m_Page+1, (m_List.Count + EntriesPerPage - 1) / EntriesPerPage ) ) );
if ( (m_Page + 1) * EntriesPerPage < m_List.Count )
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight );
else
AddEntryHeader( 20 );
if ( m_Columns.Length > 1 )
{
AddNewLine();
for ( int i = 0; i < m_Columns.Length; ++i )
{
if ( i > 0 && m_List.Count > 0 )
{
object obj = m_List[0];
if ( obj != null )
{
string failReason = null;
PropertyInfo[] chain = Properties.GetPropertyInfoChain( m_From, obj.GetType(), m_Columns[i], PropertyAccess.Read, ref failReason );
if ( chain != null && chain.Length > 0 )
{
m_Columns[i] = "";
for ( int j = 0; j < chain.Length; ++j )
{
if ( j > 0 )
m_Columns[i] += '.';
m_Columns[i] += chain[j].Name;
}
}
}
}
AddEntryHtml( 130 + ( i == 0 ? 40 : 0 ), m_Columns[i] );
}
AddEntryHeader( 20 );
}
for ( int i = m_Page * EntriesPerPage, line = 0; line < EntriesPerPage && i < m_List.Count; ++i, ++line )
{
AddNewLine();
object obj = m_List[i];
bool isDeleted = false;
if ( obj is Item )
{
Item item = (Item)obj;
if ( !(isDeleted = item.Deleted) )
AddEntryHtml( 40 + 130, item.GetType().Name );
}
else if ( obj is Mobile )
{
Mobile mob = (Mobile)obj;
if ( !(isDeleted = mob.Deleted) )
AddEntryHtml( 40 + 130, mob.Name );
}
if ( isDeleted )
{
AddEntryHtml( 40 + 130, "(deleted)" );
for ( int j = 1; j < m_Columns.Length; ++j )
AddEntryHtml( 130, "---" );
AddEntryHeader( 20 );
}
else
{
for ( int j = 1; j < m_Columns.Length; ++j )
{
object src = obj;
string value;
string failReason = "";
PropertyInfo[] chain = Properties.GetPropertyInfoChain( m_From, src.GetType(), m_Columns[j], PropertyAccess.Read, ref failReason );
if ( chain == null || chain.Length == 0 )
{
value = "---";
}
else
{
PropertyInfo p = Properties.GetPropertyInfo( ref src, chain, ref failReason );
if ( p == null )
value = "---";
else
value = PropertiesGump.ValueToString( src, p );
}
AddEntryHtml( 130, value );
}
bool isSelected = ( m_Select != null && obj == m_Select );
AddEntryButton( 20, ( isSelected ? 9762 : ArrowRightID1 ), ( isSelected ? 9763 : ArrowRightID2 ), 3 + i, ArrowRightWidth, ArrowRightHeight );
}
}
FinishPage();
}
public override void OnResponse( NetState sender, RelayInfo info )
{
switch ( info.ButtonID )
{
case 1:
{
if ( m_Page > 0 )
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page - 1, m_Select ) );
break;
}
case 2:
{
if ( (m_Page + 1) * EntriesPerPage < m_List.Count )
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page + 1, m_Select ) );
break;
}
default:
{
int v = info.ButtonID - 3;
if ( v >= 0 && v < m_List.Count )
{
object obj = m_List[v];
if ( !BaseCommand.IsAccessible( m_From, obj ) )
{
m_From.SendMessage( "That is not accessible." );
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Select ) );
break;
}
if ( obj is Item && !((Item)obj).Deleted )
m_From.SendGump( new InterfaceItemGump( m_From, m_Columns, m_List, m_Page, (Item) obj ) );
else if ( obj is Mobile && !((Mobile)obj).Deleted )
m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, (Mobile) obj ) );
else
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Select ) );
}
break;
}
}
}
}
public class InterfaceItemGump : BaseGridGump
{
private Mobile m_From;
private string[] m_Columns;
private ArrayList m_List;
private int m_Page;
private Item m_Item;
public InterfaceItemGump( Mobile from, string[] columns, ArrayList list, int page, Item item ) : base( 30, 30 )
{
m_From = from;
m_Columns = columns;
m_List = list;
m_Page = page;
m_Item = item;
Render();
}
public void Render()
{
AddNewPage();
AddEntryButton( 20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight );
AddEntryHtml( 160, m_Item.GetType().Name );
AddEntryHeader( 20 );
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Properties" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight );
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Delete" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 3, ArrowRightWidth, ArrowRightHeight );
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Go there" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 4, ArrowRightWidth, ArrowRightHeight );
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Move to target" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 5, ArrowRightWidth, ArrowRightHeight );
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Bring to pack" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 6, ArrowRightWidth, ArrowRightHeight );
FinishPage();
}
private void InvokeCommand( string ip )
{
CommandSystem.Handle( m_From, String.Format( "{0}{1}", CommandSystem.Prefix, ip ) );
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( m_Item.Deleted )
{
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Item ) );
return;
}
else if ( !BaseCommand.IsAccessible( m_From, m_Item ) )
{
m_From.SendMessage( "That is no longer accessible." );
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Item ) );
return;
}
switch ( info.ButtonID )
{
case 0:
case 1:
{
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Item ) );
break;
}
case 2: // Properties
{
m_From.SendGump( new InterfaceItemGump( m_From, m_Columns, m_List, m_Page, m_Item ) );
m_From.SendGump( new PropertiesGump( m_From, m_Item ) );
break;
}
case 3: // Delete
{
CommandLogging.WriteLine( m_From, "{0} {1} deleting {2}", m_From.AccessLevel, CommandLogging.Format( m_From ), CommandLogging.Format( m_Item ) );
m_Item.Delete();
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Item ) );
break;
}
case 4: // Go there
{
m_From.SendGump( new InterfaceItemGump( m_From, m_Columns, m_List, m_Page, m_Item ) );
InvokeCommand( String.Format( "Go {0}", m_Item.Serial.Value ) );
break;
}
case 5: // Move to target
{
m_From.SendGump( new InterfaceItemGump( m_From, m_Columns, m_List, m_Page, m_Item ) );
m_From.Target = new MoveTarget( m_Item );
break;
}
case 6: // Bring to pack
{
Mobile owner = m_Item.RootParent as Mobile;
if ( owner != null && (owner.Map != null && owner.Map != Map.Internal) && !BaseCommand.IsAccessible( m_From, owner ) /* !m_From.CanSee( owner )*/ )
{
m_From.SendMessage( "You can not get what you can not see." );
}
else if ( owner != null && (owner.Map == null || owner.Map == Map.Internal) && owner.Hidden && owner.AccessLevel >= m_From.AccessLevel )
{
m_From.SendMessage( "You can not get what you can not see." );
}
else
{
m_From.SendGump( new InterfaceItemGump( m_From, m_Columns, m_List, m_Page, m_Item ) );
m_From.AddToBackpack( m_Item );
}
break;
}
}
}
}
public class InterfaceMobileGump : BaseGridGump
{
private Mobile m_From;
private string[] m_Columns;
private ArrayList m_List;
private int m_Page;
private Mobile m_Mobile;
public InterfaceMobileGump( Mobile from, string[] columns, ArrayList list, int page, Mobile mob )
: base( 30, 30 )
{
m_From = from;
m_Columns = columns;
m_List = list;
m_Page = page;
m_Mobile = mob;
Render();
}
public void Render()
{
AddNewPage();
AddEntryButton( 20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight );
AddEntryHtml( 160, m_Mobile.Name );
AddEntryHeader( 20 );
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Properties" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight );
if ( !m_Mobile.Player )
{
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Delete" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 3, ArrowRightWidth, ArrowRightHeight );
}
if ( m_Mobile != m_From )
{
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Go to there" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 4, ArrowRightWidth, ArrowRightHeight );
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Bring them here" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 5, ArrowRightWidth, ArrowRightHeight );
}
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Move to target" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 6, ArrowRightWidth, ArrowRightHeight );
if ( m_From == m_Mobile || m_From.AccessLevel > m_Mobile.AccessLevel )
{
AddNewLine();
if ( m_Mobile.Alive )
{
AddEntryHtml( 20 + OffsetSize + 160, "Kill" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 7, ArrowRightWidth, ArrowRightHeight );
}
else
{
AddEntryHtml( 20 + OffsetSize + 160, "Resurrect" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 8, ArrowRightWidth, ArrowRightHeight );
}
}
if ( m_Mobile.NetState != null )
{
AddNewLine();
AddEntryHtml( 20 + OffsetSize + 160, "Client" );
AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 9, ArrowRightWidth, ArrowRightHeight );
}
FinishPage();
}
private void InvokeCommand( string ip )
{
CommandSystem.Handle( m_From, String.Format( "{0}{1}", CommandSystem.Prefix, ip ) );
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( m_Mobile.Deleted )
{
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
return;
}
else if ( !BaseCommand.IsAccessible( m_From, m_Mobile ) )
{
m_From.SendMessage( "That is no longer accessible." );
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
return;
}
switch ( info.ButtonID )
{
case 0:
case 1:
{
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
break;
}
case 2: // Properties
{
m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
m_From.SendGump( new PropertiesGump( m_From, m_Mobile ) );
break;
}
case 3: // Delete
{
if ( !m_Mobile.Player )
{
CommandLogging.WriteLine( m_From, "{0} {1} deleting {2}", m_From.AccessLevel, CommandLogging.Format( m_From ), CommandLogging.Format( m_Mobile ) );
m_Mobile.Delete();
m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
}
break;
}
case 4: // Go there
{
m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
InvokeCommand( String.Format( "Go {0}", m_Mobile.Serial.Value ) );
break;
}
case 5: // Bring them here
{
if ( m_From.Map == null || m_From.Map == Map.Internal )
{
m_From.SendMessage( "You cannot bring that person here." );
}
else
{
m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
m_Mobile.MoveToWorld( m_From.Location, m_From.Map );
}
break;
}
case 6: // Move to target
{
m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
m_From.Target = new MoveTarget( m_Mobile );
break;
}
case 7: // Kill
{
if ( m_From == m_Mobile || m_From.AccessLevel > m_Mobile.AccessLevel )
m_Mobile.Kill();
m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
break;
}
case 8: // Res
{
if ( m_From == m_Mobile || m_From.AccessLevel > m_Mobile.AccessLevel )
{
m_Mobile.PlaySound( 0x214 );
m_Mobile.FixedEffect( 0x376A, 10, 16 );
m_Mobile.Resurrect();
}
m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
break;
}
case 9: // Client
{
m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) );
if ( m_Mobile.NetState != null )
m_From.SendGump( new ClientGump( m_From, m_Mobile.NetState ) );
break;
}
}
}
}
}

View file

@ -0,0 +1,184 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace Server.Commands.Generic
{
public delegate BaseExtension ExtensionConstructor();
public sealed class ExtensionInfo
{
private static Dictionary<string, ExtensionInfo> m_Table = new Dictionary<string, ExtensionInfo>( StringComparer.InvariantCultureIgnoreCase );
public static Dictionary<string, ExtensionInfo> Table
{
get { return m_Table; }
}
public static void Register( ExtensionInfo ext )
{
m_Table[ext.m_Name] = ext;
}
private int m_Order;
private string m_Name;
private int m_Size;
private ExtensionConstructor m_Constructor;
public int Order
{
get { return m_Order; }
}
public string Name
{
get { return m_Name; }
}
public int Size
{
get { return m_Size; }
}
public bool IsFixedSize
{
get { return ( m_Size >= 0 ); }
}
public ExtensionConstructor Constructor
{
get { return m_Constructor; }
}
public ExtensionInfo( int order, string name, int size, ExtensionConstructor constructor )
{
m_Name = name;
m_Size = size;
m_Order = order;
m_Constructor = constructor;
}
}
public sealed class Extensions : List<BaseExtension>
{
public Extensions()
{
}
public bool IsValid( object obj )
{
for ( int i = 0; i < this.Count; ++i )
{
if ( !this[i].IsValid( obj ) )
return false;
}
return true;
}
public void Filter( ArrayList list )
{
for ( int i = 0; i < this.Count; ++i )
this[i].Filter( list );
}
public static Extensions Parse( Mobile from, ref string[] args )
{
Extensions parsed = new Extensions();
int size = args.Length;
Type baseType = null;
for ( int i = args.Length - 1; i >= 0; --i )
{
ExtensionInfo extInfo = null;
if ( !ExtensionInfo.Table.TryGetValue( args[i], out extInfo ) )
continue;
if ( extInfo.IsFixedSize && i != ( size - extInfo.Size - 1 ) )
throw new Exception( "Invalid extended argument count." );
BaseExtension ext = extInfo.Constructor();
ext.Parse( from, args, i + 1, size - i - 1 );
if ( ext is WhereExtension )
baseType = ( ext as WhereExtension ).Conditional.Type;
parsed.Add( ext );
size = i;
}
parsed.Sort( delegate( BaseExtension a, BaseExtension b )
{
return ( a.Order - b.Order );
} );
AssemblyEmitter emitter = null;
foreach ( BaseExtension update in parsed )
update.Optimize( from, baseType, ref emitter );
if ( size != args.Length )
{
string[] old = args;
args = new string[size];
for ( int i = 0; i < args.Length; ++i )
args[i] = old[i];
}
return parsed;
}
}
public abstract class BaseExtension
{
public abstract ExtensionInfo Info { get; }
public string Name
{
get { return Info.Name; }
}
public int Size
{
get { return Info.Size; }
}
public bool IsFixedSize
{
get { return Info.IsFixedSize; }
}
public int Order
{
get { return Info.Order; }
}
public virtual void Optimize( Mobile from, Type baseType, ref AssemblyEmitter assembly )
{
}
public virtual void Parse( Mobile from, string[] arguments, int offset, int size )
{
}
public virtual bool IsValid( object obj )
{
return true;
}
public virtual void Filter( ArrayList list )
{
}
}
}

View file

@ -0,0 +1,569 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Globalization;
using System.Text;
using Server;
namespace Server.Commands.Generic
{
public interface IConditional
{
bool Verify( object obj );
}
public interface ICondition
{
// Invoked during the constructor
void Construct( TypeBuilder typeBuilder, ILGenerator il, int index );
// Target object will be loaded on the stack
void Compile( MethodEmitter emitter );
}
public sealed class TypeCondition : ICondition
{
public static TypeCondition Default = new TypeCondition();
void ICondition.Construct( TypeBuilder typeBuilder, ILGenerator il, int index )
{
}
void ICondition.Compile( MethodEmitter emitter )
{
// The object was safely cast to be the conditionals type
// If it's null, then the type cast didn't work...
emitter.LoadNull();
emitter.Compare( OpCodes.Ceq );
emitter.LogicalNot();
}
}
public sealed class PropertyValue
{
private Type m_Type;
private object m_Value;
private FieldInfo m_Field;
public Type Type
{
get { return m_Type; }
}
public object Value
{
get { return m_Value; }
}
public FieldInfo Field
{
get { return m_Field; }
}
public bool HasField
{
get { return ( m_Field != null ); }
}
public PropertyValue( Type type, object value )
{
m_Type = type;
m_Value = value;
}
public void Load( MethodEmitter method )
{
if ( m_Field != null )
{
method.LoadArgument( 0 );
method.LoadField( m_Field );
}
else if ( m_Value == null )
{
method.LoadNull( m_Type );
}
else
{
if ( m_Value is int )
method.Load( (int) m_Value );
else if ( m_Value is long )
method.Load( (long) m_Value );
else if ( m_Value is float )
method.Load( (float) m_Value );
else if ( m_Value is double )
method.Load( (double) m_Value );
else if ( m_Value is char )
method.Load( (char) m_Value );
else if ( m_Value is bool )
method.Load( (bool) m_Value );
else if ( m_Value is string )
method.Load( (string) m_Value );
else if ( m_Value is Enum )
method.Load( (Enum) m_Value );
else
throw new InvalidOperationException( "Unrecognized comparison value." );
}
}
public void Acquire( TypeBuilder typeBuilder, ILGenerator il, string fieldName )
{
if ( m_Value is string )
{
string toParse = (string) m_Value;
if ( !m_Type.IsValueType && toParse == "null" )
{
m_Value = null;
}
else if ( m_Type == typeof( string ) )
{
if ( toParse == @"@""null""" )
toParse = "null";
m_Value = toParse;
}
else if ( m_Type.IsEnum )
{
m_Value = Enum.Parse( m_Type, toParse, true );
}
else
{
MethodInfo parseMethod = null;
object[] parseArgs = null;
MethodInfo parseNumber = m_Type.GetMethod(
"Parse",
BindingFlags.Public | BindingFlags.Static,
null,
new Type[] { typeof( string ), typeof( NumberStyles ) },
null
);
if ( parseNumber != null )
{
NumberStyles style = NumberStyles.Integer;
if ( Insensitive.StartsWith( toParse, "0x" ) )
{
style = NumberStyles.HexNumber;
toParse = toParse.Substring( 2 );
}
parseMethod = parseNumber;
parseArgs = new object[] { toParse, style };
}
else
{
MethodInfo parseGeneral = m_Type.GetMethod(
"Parse",
BindingFlags.Public | BindingFlags.Static,
null,
new Type[] { typeof( string ) },
null
);
parseMethod = parseGeneral;
parseArgs = new object[] { toParse };
}
if ( parseMethod != null )
{
m_Value = parseMethod.Invoke( null, parseArgs );
if ( !m_Type.IsPrimitive )
{
m_Field = typeBuilder.DefineField(
fieldName,
m_Type,
FieldAttributes.Private | FieldAttributes.InitOnly
);
il.Emit( OpCodes.Ldarg_0 );
il.Emit( OpCodes.Ldstr, toParse );
if ( parseArgs.Length == 2 ) // dirty evil hack :-(
il.Emit( OpCodes.Ldc_I4, (int) parseArgs[1] );
il.Emit( OpCodes.Call, parseMethod );
il.Emit( OpCodes.Stfld, m_Field );
}
}
else
{
throw new InvalidOperationException(
String.Format(
"Unable to convert string \"{0}\" into type '{1}'.",
m_Value,
m_Type
)
);
}
}
}
}
}
public abstract class PropertyCondition : ICondition
{
protected Property m_Property;
protected bool m_Not;
public PropertyCondition( Property property, bool not )
{
m_Property = property;
m_Not = not;
}
public abstract void Construct( TypeBuilder typeBuilder, ILGenerator il, int index );
public abstract void Compile( MethodEmitter emitter );
}
public enum StringOperator
{
Equal,
NotEqual,
Contains,
StartsWith,
EndsWith
}
public sealed class StringCondition : PropertyCondition
{
private StringOperator m_Operator;
private PropertyValue m_Value;
private bool m_IgnoreCase;
public StringCondition( Property property, bool not, StringOperator op, object value, bool ignoreCase )
: base( property, not )
{
m_Operator = op;
m_Value = new PropertyValue( property.Type, value );
m_IgnoreCase = ignoreCase;
}
public override void Construct( TypeBuilder typeBuilder, ILGenerator il, int index )
{
m_Value.Acquire( typeBuilder, il, "v" + index );
}
public override void Compile( MethodEmitter emitter )
{
bool inverse = false;
string methodName;
switch ( m_Operator )
{
case StringOperator.Equal:
methodName = "Equals";
break;
case StringOperator.NotEqual:
methodName = "Equals";
inverse = true;
break;
case StringOperator.Contains:
methodName = "Contains";
break;
case StringOperator.StartsWith:
methodName = "StartsWith";
break;
case StringOperator.EndsWith:
methodName = "EndsWith";
break;
default:
throw new InvalidOperationException( "Invalid string comparison operator." );
}
if ( m_IgnoreCase || methodName == "Equals" )
{
Type type = ( m_IgnoreCase ? typeof( Insensitive ) : typeof( String ) );
emitter.BeginCall(
type.GetMethod(
methodName,
BindingFlags.Public | BindingFlags.Static,
null,
new Type[]
{
typeof( string ),
typeof( string )
},
null
)
);
emitter.Chain( m_Property );
m_Value.Load( emitter );
emitter.FinishCall();
}
else
{
Label notNull = emitter.CreateLabel();
Label moveOn = emitter.CreateLabel();
LocalBuilder temp = emitter.AcquireTemp( m_Property.Type );
emitter.Chain( m_Property );
emitter.StoreLocal( temp );
emitter.LoadLocal( temp );
emitter.BranchIfTrue( notNull );
emitter.Load( false );
emitter.Pop();
emitter.Branch( moveOn );
emitter.MarkLabel( notNull );
emitter.LoadLocal( temp );
emitter.BeginCall(
typeof( string ).GetMethod(
methodName,
BindingFlags.Public | BindingFlags.Instance,
null,
new Type[]
{
typeof( string )
},
null
)
);
m_Value.Load( emitter );
emitter.FinishCall();
emitter.MarkLabel( moveOn );
}
if ( m_Not != inverse )
emitter.LogicalNot();
}
}
public enum ComparisonOperator
{
Equal,
NotEqual,
Greater,
GreaterEqual,
Lesser,
LesserEqual
}
public sealed class ComparisonCondition : PropertyCondition
{
private ComparisonOperator m_Operator;
private PropertyValue m_Value;
public ComparisonCondition( Property property, bool not, ComparisonOperator op, object value )
: base( property, not )
{
m_Operator = op;
m_Value = new PropertyValue( property.Type, value );
}
public override void Construct( TypeBuilder typeBuilder, ILGenerator il, int index )
{
m_Value.Acquire( typeBuilder, il, "v" + index );
}
public override void Compile( MethodEmitter emitter )
{
emitter.Chain( m_Property );
bool inverse = false;
bool couldCompare =
emitter.CompareTo( 1, delegate()
{
m_Value.Load( emitter );
} );
if ( couldCompare )
{
emitter.Load( 0 );
switch ( m_Operator )
{
case ComparisonOperator.Equal:
emitter.Compare( OpCodes.Ceq );
break;
case ComparisonOperator.NotEqual:
emitter.Compare( OpCodes.Ceq );
inverse = true;
break;
case ComparisonOperator.Greater:
emitter.Compare( OpCodes.Cgt );
break;
case ComparisonOperator.GreaterEqual:
emitter.Compare( OpCodes.Clt );
inverse = true;
break;
case ComparisonOperator.Lesser:
emitter.Compare( OpCodes.Clt );
break;
case ComparisonOperator.LesserEqual:
emitter.Compare( OpCodes.Cgt );
inverse = true;
break;
default:
throw new InvalidOperationException( "Invalid comparison operator." );
}
}
else
{
// This type is -not- comparable
// We can only support == and != operations
m_Value.Load( emitter );
switch ( m_Operator )
{
case ComparisonOperator.Equal:
emitter.Compare( OpCodes.Ceq );
break;
case ComparisonOperator.NotEqual:
emitter.Compare( OpCodes.Ceq );
inverse = true;
break;
case ComparisonOperator.Greater:
case ComparisonOperator.GreaterEqual:
case ComparisonOperator.Lesser:
case ComparisonOperator.LesserEqual:
throw new InvalidOperationException( "Property does not support relational comparisons." );
default:
throw new InvalidOperationException( "Invalid operator." );
}
}
if ( m_Not != inverse )
emitter.LogicalNot();
}
}
public static class ConditionalCompiler
{
public static IConditional Compile( AssemblyEmitter assembly, Type objectType, ICondition[] conditions, int index )
{
TypeBuilder typeBuilder = assembly.DefineType(
"__conditional" + index,
TypeAttributes.Public,
typeof( object )
);
#region Constructor
{
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
Type.EmptyTypes
);
ILGenerator il = ctor.GetILGenerator();
// : base()
il.Emit( OpCodes.Ldarg_0 );
il.Emit( OpCodes.Call, typeof( object ).GetConstructor( Type.EmptyTypes ) );
for ( int i = 0; i < conditions.Length; ++i )
conditions[i].Construct( typeBuilder, il, i );
// return;
il.Emit( OpCodes.Ret );
}
#endregion
#region IComparer
typeBuilder.AddInterfaceImplementation( typeof( IConditional ) );
MethodBuilder compareMethod;
#region Compare
{
MethodEmitter emitter = new MethodEmitter( typeBuilder );
emitter.Define(
/* name */ "Verify",
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
/* return */ typeof( bool ),
/* params */ new Type[] { typeof( object ) } );
LocalBuilder obj = emitter.CreateLocal( objectType );
LocalBuilder eq = emitter.CreateLocal( typeof( bool ) );
emitter.LoadArgument( 1 );
emitter.CastAs( objectType );
emitter.StoreLocal( obj );
Label done = emitter.CreateLabel();
for ( int i = 0; i < conditions.Length; ++i )
{
if ( i > 0 )
{
emitter.LoadLocal( eq );
emitter.BranchIfFalse( done );
}
emitter.LoadLocal( obj );
conditions[i].Compile( emitter );
emitter.StoreLocal( eq );
}
emitter.MarkLabel( done );
emitter.LoadLocal( eq );
emitter.Return();
typeBuilder.DefineMethodOverride(
emitter.Method,
typeof( IConditional ).GetMethod(
"Verify",
new Type[]
{
typeof( object )
}
)
);
compareMethod = emitter.Method;
}
#endregion
#endregion
Type conditionalType = typeBuilder.CreateType();
return (IConditional) Activator.CreateInstance( conditionalType );
}
}
}

View file

@ -0,0 +1,249 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using Server;
namespace Server.Commands.Generic
{
public static class DistinctCompiler
{
public static IComparer Compile( AssemblyEmitter assembly, Type objectType, Property[] props )
{
TypeBuilder typeBuilder = assembly.DefineType(
"__distinct",
TypeAttributes.Public,
typeof( object )
);
#region Constructor
{
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
Type.EmptyTypes
);
ILGenerator il = ctor.GetILGenerator();
// : base()
il.Emit( OpCodes.Ldarg_0 );
il.Emit( OpCodes.Call, typeof( object ).GetConstructor( Type.EmptyTypes ) );
// return;
il.Emit( OpCodes.Ret );
}
#endregion
#region IComparer
typeBuilder.AddInterfaceImplementation( typeof( IComparer ) );
MethodBuilder compareMethod;
#region Compare
{
MethodEmitter emitter = new MethodEmitter( typeBuilder );
emitter.Define(
/* name */ "Compare",
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
/* return */ typeof( int ),
/* params */ new Type[] { typeof( object ), typeof( object ) } );
LocalBuilder a = emitter.CreateLocal( objectType );
LocalBuilder b = emitter.CreateLocal( objectType );
LocalBuilder v = emitter.CreateLocal( typeof( int ) );
emitter.LoadArgument( 1 );
emitter.CastAs( objectType );
emitter.StoreLocal( a );
emitter.LoadArgument( 2 );
emitter.CastAs( objectType );
emitter.StoreLocal( b );
emitter.Load( 0 );
emitter.StoreLocal( v );
Label end = emitter.CreateLabel();
for ( int i = 0; i < props.Length; ++i )
{
if ( i > 0 )
{
emitter.LoadLocal( v );
emitter.BranchIfTrue( end ); // if ( v != 0 ) return v;
}
Property prop = props[i];
emitter.LoadLocal( a );
emitter.Chain( prop );
bool couldCompare =
emitter.CompareTo( 1, delegate()
{
emitter.LoadLocal( b );
emitter.Chain( prop );
} );
if ( !couldCompare )
throw new InvalidOperationException( "Property is not comparable." );
emitter.StoreLocal( v );
}
emitter.MarkLabel( end );
emitter.LoadLocal( v );
emitter.Return();
typeBuilder.DefineMethodOverride(
emitter.Method,
typeof( IComparer ).GetMethod(
"Compare",
new Type[]
{
typeof( object ),
typeof( object )
}
)
);
compareMethod = emitter.Method;
}
#endregion
#endregion
#region IEqualityComparer
typeBuilder.AddInterfaceImplementation( typeof( IEqualityComparer<object> ) );
#region Equals
{
MethodEmitter emitter = new MethodEmitter( typeBuilder );
emitter.Define(
/* name */ "Equals",
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
/* return */ typeof( bool ),
/* params */ new Type[] { typeof( object ), typeof( object ) } );
emitter.Generator.Emit( OpCodes.Ldarg_0 );
emitter.Generator.Emit( OpCodes.Ldarg_1 );
emitter.Generator.Emit( OpCodes.Ldarg_2 );
emitter.Generator.Emit( OpCodes.Call, compareMethod );
emitter.Generator.Emit( OpCodes.Ldc_I4_0 );
emitter.Generator.Emit( OpCodes.Ceq );
emitter.Generator.Emit( OpCodes.Ret );
typeBuilder.DefineMethodOverride(
emitter.Method,
typeof( IEqualityComparer<object> ).GetMethod(
"Equals",
new Type[]
{
typeof( object ),
typeof( object )
}
)
);
}
#endregion
#region GetHashCode
{
MethodEmitter emitter = new MethodEmitter( typeBuilder );
emitter.Define(
/* name */ "GetHashCode",
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
/* return */ typeof( int ),
/* params */ new Type[] { typeof( object ) } );
LocalBuilder obj = emitter.CreateLocal( objectType );
emitter.LoadArgument( 1 );
emitter.CastAs( objectType );
emitter.StoreLocal( obj );
for ( int i = 0; i < props.Length; ++i )
{
Property prop = props[i];
emitter.LoadLocal( obj );
emitter.Chain( prop );
Type active = emitter.Active;
MethodInfo getHashCode = active.GetMethod( "GetHashCode", Type.EmptyTypes );
if ( getHashCode == null )
getHashCode = typeof( object ).GetMethod( "GetHashCode", Type.EmptyTypes );
if ( active != typeof( int ) )
{
if ( !active.IsValueType )
{
LocalBuilder value = emitter.AcquireTemp( active );
Label valueNotNull = emitter.CreateLabel();
Label done = emitter.CreateLabel();
emitter.StoreLocal( value );
emitter.LoadLocal( value );
emitter.BranchIfTrue( valueNotNull );
emitter.Load( 0 );
emitter.Pop( typeof( int ) );
emitter.Branch( done );
emitter.MarkLabel( valueNotNull );
emitter.LoadLocal( value );
emitter.Call( getHashCode );
emitter.ReleaseTemp( value );
emitter.MarkLabel( done );
}
else
{
emitter.Call( getHashCode );
}
}
if ( i > 0 )
emitter.Xor();
}
emitter.Return();
typeBuilder.DefineMethodOverride(
emitter.Method,
typeof( IEqualityComparer<object> ).GetMethod(
"GetHashCode",
new Type[]
{
typeof( object )
}
)
);
}
#endregion
#endregion
Type comparerType = typeBuilder.CreateType();
return (IComparer) Activator.CreateInstance( comparerType );
}
}
}

View file

@ -0,0 +1,172 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using Server;
namespace Server.Commands.Generic
{
public sealed class OrderInfo
{
private Property m_Property;
private int m_Order;
public Property Property
{
get { return m_Property; }
set { m_Property = value; }
}
public bool IsAscending
{
get { return ( m_Order > 0 ); }
set { m_Order = ( value ? +1 : -1 ); }
}
public bool IsDescending
{
get { return ( m_Order < 0 ); }
set { m_Order = ( value ? -1 : +1 ); }
}
public int Sign
{
get { return Math.Sign( m_Order ); }
set
{
m_Order = Math.Sign( value );
if ( m_Order == 0 )
throw new InvalidOperationException( "Sign cannot be zero." );
}
}
public OrderInfo( Property property, bool isAscending )
{
m_Property = property;
this.IsAscending = isAscending;
}
}
public static class SortCompiler
{
public static IComparer Compile( AssemblyEmitter assembly, Type objectType, OrderInfo[] orders )
{
TypeBuilder typeBuilder = assembly.DefineType(
"__sort",
TypeAttributes.Public,
typeof( object )
);
#region Constructor
{
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
Type.EmptyTypes
);
ILGenerator il = ctor.GetILGenerator();
// : base()
il.Emit( OpCodes.Ldarg_0 );
il.Emit( OpCodes.Call, typeof( object ).GetConstructor( Type.EmptyTypes ) );
// return;
il.Emit( OpCodes.Ret );
}
#endregion
#region IComparer
typeBuilder.AddInterfaceImplementation( typeof( IComparer ) );
MethodBuilder compareMethod;
#region Compare
{
MethodEmitter emitter = new MethodEmitter( typeBuilder );
emitter.Define(
/* name */ "Compare",
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
/* return */ typeof( int ),
/* params */ new Type[] { typeof( object ), typeof( object ) } );
LocalBuilder a = emitter.CreateLocal( objectType );
LocalBuilder b = emitter.CreateLocal( objectType );
LocalBuilder v = emitter.CreateLocal( typeof( int ) );
emitter.LoadArgument( 1 );
emitter.CastAs( objectType );
emitter.StoreLocal( a );
emitter.LoadArgument( 2 );
emitter.CastAs( objectType );
emitter.StoreLocal( b );
emitter.Load( 0 );
emitter.StoreLocal( v );
Label end = emitter.CreateLabel();
for ( int i = 0; i < orders.Length; ++i )
{
if ( i > 0 )
{
emitter.LoadLocal( v );
emitter.BranchIfTrue( end ); // if ( v != 0 ) return v;
}
OrderInfo orderInfo = orders[i];
Property prop = orderInfo.Property;
int sign = orderInfo.Sign;
emitter.LoadLocal( a );
emitter.Chain( prop );
bool couldCompare =
emitter.CompareTo( sign, delegate()
{
emitter.LoadLocal( b );
emitter.Chain( prop );
} );
if ( !couldCompare )
throw new InvalidOperationException( "Property is not comparable." );
emitter.StoreLocal( v );
}
emitter.MarkLabel( end );
emitter.LoadLocal( v );
emitter.Return();
typeBuilder.DefineMethodOverride(
emitter.Method,
typeof( IComparer ).GetMethod(
"Compare",
new Type[]
{
typeof( object ),
typeof( object )
}
)
);
compareMethod = emitter.Method;
}
#endregion
#endregion
Type comparerType = typeBuilder.CreateType();
return (IComparer) Activator.CreateInstance( comparerType );
}
}
}

View file

@ -0,0 +1,89 @@
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace Server.Commands.Generic
{
public sealed class DistinctExtension : BaseExtension
{
public static ExtensionInfo ExtInfo = new ExtensionInfo( 30, "Distinct", -1, delegate() { return new DistinctExtension(); } );
public static void Initialize()
{
ExtensionInfo.Register( ExtInfo );
}
public override ExtensionInfo Info
{
get { return ExtInfo; }
}
private List<Property> m_Properties;
private IComparer m_Comparer;
public DistinctExtension()
{
m_Properties = new List<Property>();
}
public override void Optimize( Mobile from, Type baseType, ref AssemblyEmitter assembly )
{
if ( baseType == null )
throw new Exception( "Distinct extension may only be used in combination with an object conditional." );
foreach ( Property prop in m_Properties )
{
prop.BindTo( baseType, PropertyAccess.Read );
prop.CheckAccess( from );
}
if ( assembly == null )
assembly = new AssemblyEmitter( "__dynamic", false );
m_Comparer = DistinctCompiler.Compile( assembly, baseType, m_Properties.ToArray() );
}
public override void Parse( Mobile from, string[] arguments, int offset, int size )
{
if ( size < 1 )
throw new Exception( "Invalid distinction syntax." );
int end = offset + size;
while ( offset < end )
{
string binding = arguments[offset++];
m_Properties.Add( new Property( binding ) );
}
}
public override void Filter( ArrayList list )
{
if ( m_Comparer == null )
throw new InvalidOperationException( "The extension must first be optimized." );
ArrayList copy = new ArrayList( list );
copy.Sort( m_Comparer );
list.Clear();
object last = null;
for ( int i = 0; i < copy.Count; ++i )
{
object obj = copy[i];
if ( last == null || m_Comparer.Compare( obj, last ) != 0 )
{
list.Add( obj );
last = obj;
}
}
}
}
}

View file

@ -0,0 +1,46 @@
using System;
using System.Collections;
using System.Text;
namespace Server.Commands.Generic
{
public sealed class LimitExtension : BaseExtension
{
public static ExtensionInfo ExtInfo = new ExtensionInfo( 80, "Limit", 1, delegate() { return new LimitExtension(); } );
public static void Initialize()
{
ExtensionInfo.Register( ExtInfo );
}
public override ExtensionInfo Info
{
get { return ExtInfo; }
}
private int m_Limit;
public int Limit
{
get { return m_Limit; }
}
public LimitExtension()
{
}
public override void Parse( Mobile from, string[] arguments, int offset, int size )
{
m_Limit = Utility.ToInt32( arguments[offset] );
if ( m_Limit < 0 )
throw new Exception( "Limit cannot be less than zero." );
}
public override void Filter( ArrayList list )
{
if ( list.Count > m_Limit )
list.RemoveRange( m_Limit, list.Count - m_Limit );
}
}
}

View file

@ -0,0 +1,109 @@
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace Server.Commands.Generic
{
public sealed class SortExtension : BaseExtension
{
public static ExtensionInfo ExtInfo = new ExtensionInfo( 40, "Order", -1, delegate() { return new SortExtension(); } );
public static void Initialize()
{
ExtensionInfo.Register( ExtInfo );
}
public override ExtensionInfo Info
{
get { return ExtInfo; }
}
private List<OrderInfo> m_Orders;
private IComparer m_Comparer;
public SortExtension()
{
m_Orders = new List<OrderInfo>();
}
public override void Optimize( Mobile from, Type baseType, ref AssemblyEmitter assembly )
{
if ( baseType == null )
throw new Exception( "The ordering extension may only be used in combination with an object conditional." );
foreach ( OrderInfo order in m_Orders )
{
order.Property.BindTo( baseType, PropertyAccess.Read );
order.Property.CheckAccess( from );
}
if ( assembly == null )
assembly = new AssemblyEmitter( "__dynamic", false );
m_Comparer = SortCompiler.Compile( assembly, baseType, m_Orders.ToArray() );
}
public override void Parse( Mobile from, string[] arguments, int offset, int size )
{
if ( size < 1 )
throw new Exception( "Invalid ordering syntax." );
if ( Insensitive.Equals( arguments[offset], "by" ) )
{
++offset;
--size;
if ( size < 1 )
throw new Exception( "Invalid ordering syntax." );
}
int end = offset + size;
while ( offset < end )
{
string binding = arguments[offset++];
bool isAscending = true;
if ( offset < end )
{
string next = arguments[offset];
switch ( next.ToLower() )
{
case "+":
case "up":
case "asc":
case "ascending":
isAscending = true;
++offset;
break;
case "-":
case "down":
case "desc":
case "descending":
isAscending = false;
++offset;
break;
}
}
Property property = new Property( binding );
m_Orders.Add( new OrderInfo( property, isAscending ) );
}
}
public override void Filter( ArrayList list )
{
if ( m_Comparer == null )
throw new InvalidOperationException( "The extension must first be optimized." );
list.Sort( m_Comparer );
}
}
}

View file

@ -0,0 +1,55 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Server.Commands;
namespace Server.Commands.Generic
{
public sealed class WhereExtension : BaseExtension
{
public static ExtensionInfo ExtInfo = new ExtensionInfo( 20, "Where", -1, delegate() { return new WhereExtension(); } );
public static void Initialize()
{
ExtensionInfo.Register( ExtInfo );
}
public override ExtensionInfo Info
{
get { return ExtInfo; }
}
private ObjectConditional m_Conditional;
public ObjectConditional Conditional
{
get { return m_Conditional; }
}
public WhereExtension()
{
}
public override void Optimize( Mobile from, Type baseType, ref AssemblyEmitter assembly )
{
if ( baseType == null )
throw new InvalidOperationException( "Insanity." );
m_Conditional.Compile( ref assembly );
}
public override void Parse( Mobile from, string[] arguments, int offset, int size )
{
if ( size < 1 )
throw new Exception( "Invalid condition syntax." );
m_Conditional = ObjectConditional.ParseDirect( from, arguments, offset, size );
}
public override bool IsValid( object obj )
{
return m_Conditional.CheckCondition( obj );
}
}
}

View file

@ -0,0 +1,128 @@
using System;
using System.Collections;
using Server;
using Server.Targeting;
namespace Server.Commands.Generic
{
public class AreaCommandImplementor : BaseCommandImplementor
{
public AreaCommandImplementor()
{
Accessors = new string[]{ "Area", "Group" };
SupportRequirement = CommandSupport.Area;
SupportsConditionals = true;
AccessLevel = AccessLevel.GameMaster;
Usage = "Area <command> [condition]";
Description = "Invokes the command on all appropriate objects in a targeted area. Optional condition arguments can further restrict the set of objects.";
}
public override void Process( Mobile from, BaseCommand command, string[] args )
{
BoundingBoxPicker.Begin( from, new BoundingBoxCallback( OnTarget ), new object[]{ command, args } );
}
public void OnTarget( Mobile from, Map map, Point3D start, Point3D end, object state )
{
try
{
object[] states = (object[])state;
BaseCommand command = (BaseCommand)states[0];
string[] args = (string[])states[1];
Rectangle2D rect = new Rectangle2D( start.X, start.Y, end.X - start.X + 1, end.Y - start.Y + 1 );
Extensions ext = Extensions.Parse( from, ref args );
bool items, mobiles;
if ( !CheckObjectTypes( command, ext, out items, out mobiles ) )
return;
IPooledEnumerable eable;
if ( items && mobiles )
eable = map.GetObjectsInBounds( rect );
else if ( items )
eable = map.GetItemsInBounds( rect );
else if ( mobiles )
eable = map.GetMobilesInBounds( rect );
else
return;
ArrayList objs = new ArrayList();
foreach ( object obj in eable )
{
if ( mobiles && obj is Mobile && !BaseCommand.IsAccessible( from, obj ) )
continue;
if ( ext.IsValid( obj ) )
objs.Add( obj );
}
eable.Free();
ext.Filter( objs );
RunCommand( from, objs, command, args );
}
catch ( Exception ex )
{
from.SendMessage( ex.Message );
}
}
public void OnTarget( Mobile from, object targeted, object state )
{
try
{
object[] states = (object[])state;
BaseCommand command = (BaseCommand)states[0];
string[] args = (string[])states[1];
switch ( command.ObjectTypes )
{
case ObjectTypes.Both:
{
if ( !(targeted is Item) && !(targeted is Mobile) )
{
from.SendMessage( "This command does not work on that." );
return;
}
break;
}
case ObjectTypes.Items:
{
if ( !(targeted is Item) )
{
from.SendMessage( "This command only works on items." );
return;
}
break;
}
case ObjectTypes.Mobiles:
{
if ( !(targeted is Mobile) )
{
from.SendMessage( "This command only works on mobiles." );
return;
}
break;
}
}
RunCommand( from, targeted, command, args );
from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } );
}
catch ( Exception ex )
{
from.SendMessage( ex.Message );
}
}
}
}

View file

@ -0,0 +1,336 @@
using System;
using System.Text;
using System.Collections;
using Server;
namespace Server.Commands.Generic
{
[Flags]
public enum CommandSupport
{
Single = 0x0001,
Global = 0x0002,
Online = 0x0004,
Multi = 0x0008,
Area = 0x0010,
Self = 0x0020,
Region = 0x0040,
Contained = 0x0080,
All = Single | Global | Online | Multi | Area | Self | Region | Contained,
AllMobiles = All & ~Contained,
AllNPCs = All & ~(Online | Self | Contained),
AllItems = All & ~(Online | Self | Region),
Simple = Single | Multi,
Complex = Global | Online | Area | Region | Contained
}
public abstract class BaseCommandImplementor
{
public static void RegisterImplementors()
{
Register( new RegionCommandImplementor() );
Register( new GlobalCommandImplementor() );
Register( new OnlineCommandImplementor() );
Register( new SingleCommandImplementor() );
Register( new SerialCommandImplementor() );
Register( new MultiCommandImplementor() );
Register( new AreaCommandImplementor() );
Register( new SelfCommandImplementor() );
Register( new ContainedCommandImplementor() );
}
private string[] m_Accessors;
private AccessLevel m_AccessLevel;
private CommandSupport m_SupportRequirement;
private Hashtable m_Commands;
private string m_Usage;
private string m_Description;
private bool m_SupportsConditionals;
public bool SupportsConditionals
{
get{ return m_SupportsConditionals; }
set{ m_SupportsConditionals = value; }
}
public string[] Accessors
{
get{ return m_Accessors; }
set{ m_Accessors = value; }
}
public string Usage
{
get{ return m_Usage; }
set{ m_Usage = value; }
}
public string Description
{
get{ return m_Description; }
set{ m_Description = value; }
}
public AccessLevel AccessLevel
{
get{ return m_AccessLevel; }
set{ m_AccessLevel = value; }
}
public CommandSupport SupportRequirement
{
get{ return m_SupportRequirement; }
set{ m_SupportRequirement = value; }
}
public Hashtable Commands
{
get{ return m_Commands; }
}
public BaseCommandImplementor()
{
m_Commands = new Hashtable( StringComparer.OrdinalIgnoreCase );
}
public virtual void Compile( Mobile from, BaseCommand command, ref string[] args, ref object obj )
{
obj = null;
}
public virtual void Register( BaseCommand command )
{
for ( int i = 0; i < command.Commands.Length; ++i )
m_Commands[command.Commands[i]] = command;
}
public bool CheckObjectTypes( BaseCommand command, Extensions ext, out bool items, out bool mobiles )
{
items = mobiles = false;
ObjectConditional cond = ObjectConditional.Empty;
foreach ( BaseExtension check in ext )
{
if ( check is WhereExtension )
{
cond = ( check as WhereExtension ).Conditional;
break;
}
}
bool condIsItem = cond.IsItem;
bool condIsMobile = cond.IsMobile;
switch ( command.ObjectTypes )
{
case ObjectTypes.All:
case ObjectTypes.Both:
{
if ( condIsItem )
items = true;
if ( condIsMobile )
mobiles = true;
break;
}
case ObjectTypes.Items:
{
if ( condIsItem )
{
items = true;
}
else if ( condIsMobile )
{
command.LogFailure( "You may not use a mobile type condition for this command." );
return false;
}
break;
}
case ObjectTypes.Mobiles:
{
if ( condIsMobile )
{
mobiles = true;
}
else if ( condIsItem )
{
command.LogFailure( "You may not use an item type condition for this command." );
return false;
}
break;
}
}
return true;
}
public void RunCommand( Mobile from, BaseCommand command, string[] args )
{
try
{
object obj = null;
Compile( from, command, ref args, ref obj );
RunCommand( from, obj, command, args );
}
catch ( Exception ex )
{
from.SendMessage( ex.Message );
}
}
public string GenerateArgString( string[] args )
{
if ( args.Length == 0 )
return "";
// NOTE: this does not preserve the case where quotation marks are used on a single word
StringBuilder sb = new StringBuilder();
for ( int i = 0; i < args.Length; ++i )
{
if ( i > 0 )
sb.Append( ' ' );
if ( args[i].IndexOf( ' ' ) >= 0 )
{
sb.Append( '"' );
sb.Append( args[i] );
sb.Append( '"' );
}
else
{
sb.Append( args[i] );
}
}
return sb.ToString();
}
public void RunCommand( Mobile from, object obj, BaseCommand command, string[] args )
{
// try
// {
CommandEventArgs e = new CommandEventArgs( from, command.Commands[0], GenerateArgString( args ), args );
if ( !command.ValidateArgs( this, e ) )
return;
bool flushToLog = false;
if ( obj is ArrayList )
{
ArrayList list = (ArrayList)obj;
if ( list.Count > 20 )
CommandLogging.Enabled = false;
else if ( list.Count == 0 )
command.LogFailure( "Nothing was found to use this command on." );
command.ExecuteList( e, list );
if ( list.Count > 20 )
{
flushToLog = true;
CommandLogging.Enabled = true;
}
}
else if ( obj != null )
{
if ( command.ListOptimized )
{
ArrayList list = new ArrayList();
list.Add( obj );
command.ExecuteList( e, list );
}
else
{
command.Execute( e, obj );
}
}
command.Flush( from, flushToLog );
// }
// catch ( Exception ex )
// {
// from.SendMessage( ex.Message );
// }
}
public virtual void Process( Mobile from, BaseCommand command, string[] args )
{
RunCommand( from, command, args );
}
public virtual void Execute( CommandEventArgs e )
{
if ( e.Length >= 1 )
{
BaseCommand command = (BaseCommand)m_Commands[e.GetString( 0 )];
if ( command == null )
{
e.Mobile.SendMessage( "That is either an invalid command name or one that does not support this modifier." );
}
else if ( e.Mobile.AccessLevel < command.AccessLevel )
{
e.Mobile.SendMessage( "You do not have access to that command." );
}
else
{
string[] oldArgs = e.Arguments;
string[] args = new string[oldArgs.Length - 1];
for ( int i = 0; i < args.Length; ++i )
args[i] = oldArgs[i + 1];
Process( e.Mobile, command, args );
}
}
else
{
e.Mobile.SendMessage( "You must supply a command name." );
}
}
public void Register()
{
if ( m_Accessors == null )
return;
for ( int i = 0; i < m_Accessors.Length; ++i )
CommandSystem.Register( m_Accessors[i], m_AccessLevel, new CommandEventHandler( Execute ) );
}
public static void Register( BaseCommandImplementor impl )
{
m_Implementors.Add( impl );
impl.Register();
}
private static ArrayList m_Implementors;
public static ArrayList Implementors
{
get
{
if ( m_Implementors == null )
{
m_Implementors = new ArrayList();
RegisterImplementors();
}
return m_Implementors;
}
}
}
}

View file

@ -0,0 +1,85 @@
using System;
using System.Collections;
using Server;
using Server.Items;
using Server.Targeting;
namespace Server.Commands.Generic
{
public class ContainedCommandImplementor : BaseCommandImplementor
{
public ContainedCommandImplementor()
{
Accessors = new string[]{ "Contained" };
SupportRequirement = CommandSupport.Contained;
AccessLevel = AccessLevel.GameMaster;
Usage = "Contained <command> [condition]";
Description = "Invokes the command on all child items in a targeted container. Optional condition arguments can further restrict the set of objects.";
}
public override void Process( Mobile from, BaseCommand command, string[] args )
{
if ( command.ValidateArgs( this, new CommandEventArgs( from, command.Commands[0], GenerateArgString( args ), args ) ) )
from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } );
}
public void OnTarget( Mobile from, object targeted, object state )
{
if ( !BaseCommand.IsAccessible( from, targeted ) )
{
from.SendMessage( "That is not accessible." );
return;
}
object[] states = (object[])state;
BaseCommand command = (BaseCommand)states[0];
string[] args = (string[])states[1];
if ( command.ObjectTypes == ObjectTypes.Mobiles )
return; // sanity check
if ( !(targeted is Container) )
{
from.SendMessage( "That is not a container." );
}
else
{
try
{
Extensions ext = Extensions.Parse( from, ref args );
bool items, mobiles;
if ( !CheckObjectTypes( command, ext, out items, out mobiles ) )
return;
if ( !items )
{
from.SendMessage( "This command only works on items." );
return;
}
Container cont = (Container)targeted;
Item[] found = cont.FindItemsByType( typeof( Item ), true );
ArrayList list = new ArrayList();
for ( int i = 0; i < found.Length; ++i )
{
if ( ext.IsValid( found[i] ) )
list.Add( found[i] );
}
ext.Filter( list );
RunCommand( from, list, command, args );
}
catch ( Exception e )
{
from.SendMessage( e.Message );
}
}
}
}
}

View file

@ -0,0 +1,60 @@
using System;
using System.Collections;
using Server;
namespace Server.Commands.Generic
{
public class GlobalCommandImplementor : BaseCommandImplementor
{
public GlobalCommandImplementor()
{
Accessors = new string[]{ "Global" };
SupportRequirement = CommandSupport.Global;
SupportsConditionals = true;
AccessLevel = AccessLevel.Administrator;
Usage = "Global <command> [condition]";
Description = "Invokes the command on all appropriate objects in the world. Optional condition arguments can further restrict the set of objects.";
}
public override void Compile( Mobile from, BaseCommand command, ref string[] args, ref object obj )
{
try
{
Extensions ext = Extensions.Parse( from, ref args );
bool items, mobiles;
if ( !CheckObjectTypes( command, ext, out items, out mobiles ) )
return;
ArrayList list = new ArrayList();
if ( items )
{
foreach ( Item item in World.Items.Values )
{
if ( ext.IsValid( item ) )
list.Add( item );
}
}
if ( mobiles )
{
foreach ( Mobile mob in World.Mobiles.Values )
{
if ( ext.IsValid( mob ) )
list.Add( mob );
}
}
ext.Filter( list );
obj = list;
}
catch ( Exception ex )
{
from.SendMessage( ex.Message );
}
}
}
}

View file

@ -0,0 +1,77 @@
using System;
using System.Collections;
using Server;
using Server.Targeting;
namespace Server.Commands.Generic
{
public class MultiCommandImplementor : BaseCommandImplementor
{
public MultiCommandImplementor()
{
Accessors = new string[]{ "Multi", "m" };
SupportRequirement = CommandSupport.Multi;
AccessLevel = AccessLevel.Counselor;
Usage = "Multi <command>";
Description = "Invokes the command on multiple targeted objects.";
}
public override void Process( Mobile from, BaseCommand command, string[] args )
{
if ( command.ValidateArgs( this, new CommandEventArgs( from, command.Commands[0], GenerateArgString( args ), args ) ) )
from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } );
}
public void OnTarget( Mobile from, object targeted, object state )
{
object[] states = (object[])state;
BaseCommand command = (BaseCommand)states[0];
string[] args = (string[])states[1];
if ( !BaseCommand.IsAccessible( from, targeted ) )
{
from.SendMessage( "That is not accessible." );
from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } );
return;
}
switch ( command.ObjectTypes )
{
case ObjectTypes.Both:
{
if ( !(targeted is Item) && !(targeted is Mobile) )
{
from.SendMessage( "This command does not work on that." );
return;
}
break;
}
case ObjectTypes.Items:
{
if ( !(targeted is Item) )
{
from.SendMessage( "This command only works on items." );
return;
}
break;
}
case ObjectTypes.Mobiles:
{
if ( !(targeted is Mobile) )
{
from.SendMessage( "This command only works on mobiles." );
return;
}
break;
}
}
RunCommand( from, targeted, command, args );
from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } );
}
}
}

View file

@ -0,0 +1,266 @@
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using Server;
using Server.Targeting;
using CPA = Server.CommandPropertyAttribute;
namespace Server.Commands.Generic
{
public sealed class ObjectConditional
{
private static readonly Type typeofItem = typeof( Item );
private static readonly Type typeofMobile = typeof( Mobile );
private Type m_ObjectType;
private ICondition[][] m_Conditions;
private IConditional[] m_Conditionals;
public Type Type
{
get { return m_ObjectType; }
}
public bool IsItem
{
get { return ( m_ObjectType == null || m_ObjectType == typeofItem || m_ObjectType.IsSubclassOf( typeofItem ) ); }
}
public bool IsMobile
{
get { return ( m_ObjectType == null || m_ObjectType == typeofMobile || m_ObjectType.IsSubclassOf( typeofMobile ) ); }
}
public static readonly ObjectConditional Empty = new ObjectConditional( null, null );
public bool HasCompiled
{
get { return ( m_Conditionals != null ); }
}
public void Compile( ref AssemblyEmitter emitter )
{
if ( emitter == null )
emitter = new AssemblyEmitter( "__dynamic", false );
m_Conditionals = new IConditional[m_Conditions.Length];
for ( int i = 0; i < m_Conditionals.Length; ++i )
m_Conditionals[i] = ConditionalCompiler.Compile( emitter, m_ObjectType, m_Conditions[i], i );
}
public bool CheckCondition( object obj )
{
if ( m_ObjectType == null )
return true; // null type means no condition
if ( !HasCompiled )
{
AssemblyEmitter emitter = null;
Compile( ref emitter );
}
for ( int i = 0; i < m_Conditionals.Length; ++i )
{
if ( m_Conditionals[i].Verify( obj ) )
return true;
}
return false; // all conditions false
}
public static ObjectConditional Parse( Mobile from, ref string[] args )
{
string[] conditionArgs = null;
for ( int i = 0; i < args.Length; ++i )
{
if ( Insensitive.Equals( args[i], "where" ) )
{
string[] origArgs = args;
args = new string[i];
for ( int j = 0; j < args.Length; ++j )
args[j] = origArgs[j];
conditionArgs = new string[origArgs.Length - i - 1];
for ( int j = 0; j < conditionArgs.Length; ++j )
conditionArgs[j] = origArgs[i + j + 1];
break;
}
}
return ParseDirect( from, conditionArgs, 0, conditionArgs.Length );
}
public static ObjectConditional ParseDirect( Mobile from, string[] args, int offset, int size )
{
if ( args == null || size == 0 )
return ObjectConditional.Empty;
int index = 0;
Type objectType = ScriptCompiler.FindTypeByName( args[offset + index], true );
if ( objectType == null )
throw new Exception( String.Format( "No type with that name ({0}) was found.", args[offset + index] ) );
++index;
List<ICondition[]> conditions = new List<ICondition[]>();
List<ICondition> current = new List<ICondition>();
current.Add( TypeCondition.Default );
while ( index < size )
{
string cur = args[offset + index];
bool inverse = false;
if ( Insensitive.Equals( cur, "not" ) || cur == "!" )
{
inverse = true;
++index;
if ( index >= size )
throw new Exception( "Improperly formatted object conditional." );
}
else if ( Insensitive.Equals( cur, "or" ) || cur == "||" )
{
if ( conditions.Count > 1 )
{
conditions.Add( current.ToArray() );
current.Clear();
current.Add( TypeCondition.Default );
}
++index;
continue;
}
string binding = args[offset + index];
index++;
if ( index >= size )
throw new Exception( "Improperly formatted object conditional." );
string oper = args[offset + index];
index++;
if ( index >= size )
throw new Exception( "Improperly formatted object conditional." );
string val = args[offset + index];
index++;
Property prop = new Property( binding );
prop.BindTo( objectType, PropertyAccess.Read );
prop.CheckAccess( from );
ICondition condition = null;
switch ( oper )
{
#region Equality
case "=":
case "==":
case "is":
condition = new ComparisonCondition( prop, inverse, ComparisonOperator.Equal, val );
break;
case "!=":
condition = new ComparisonCondition( prop, inverse, ComparisonOperator.NotEqual, val );
break;
#endregion
#region Relational
case ">":
condition = new ComparisonCondition( prop, inverse, ComparisonOperator.Greater, val );
break;
case "<":
condition = new ComparisonCondition( prop, inverse, ComparisonOperator.Lesser, val );
break;
case ">=":
condition = new ComparisonCondition( prop, inverse, ComparisonOperator.GreaterEqual, val );
break;
case "<=":
condition = new ComparisonCondition( prop, inverse, ComparisonOperator.LesserEqual, val );
break;
#endregion
#region Strings
case "==~":
case "~==":
case "=~":
case "~=":
case "is~":
case "~is":
condition = new StringCondition( prop, inverse, StringOperator.Equal, val, true );
break;
case "!=~":
case "~!=":
condition = new StringCondition( prop, inverse, StringOperator.NotEqual, val, true );
break;
case "starts":
condition = new StringCondition( prop, inverse, StringOperator.StartsWith, val, false );
break;
case "starts~":
case "~starts":
condition = new StringCondition( prop, inverse, StringOperator.StartsWith, val, true );
break;
case "ends":
condition = new StringCondition( prop, inverse, StringOperator.EndsWith, val, false );
break;
case "ends~":
case "~ends":
condition = new StringCondition( prop, inverse, StringOperator.EndsWith, val, true );
break;
case "contains":
condition = new StringCondition( prop, inverse, StringOperator.Contains, val, false );
break;
case "contains~":
case "~contains":
condition = new StringCondition( prop, inverse, StringOperator.Contains, val, true );
break;
#endregion
}
if ( condition == null )
throw new InvalidOperationException( String.Format( "Unrecognized operator (\"{0}\").", oper ) );
current.Add( condition );
}
conditions.Add( current.ToArray() );
return new ObjectConditional( objectType, conditions.ToArray() );
}
public ObjectConditional( Type objectType, ICondition[][] conditions )
{
m_ObjectType = objectType;
m_Conditions = conditions;
}
}
}

View file

@ -0,0 +1,67 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
using Server.Network;
namespace Server.Commands.Generic
{
public class OnlineCommandImplementor : BaseCommandImplementor
{
public OnlineCommandImplementor()
{
Accessors = new string[]{ "Online" };
SupportRequirement = CommandSupport.Online;
SupportsConditionals = true;
AccessLevel = AccessLevel.GameMaster;
Usage = "Online <command> [condition]";
Description = "Invokes the command on all mobiles that are currently logged in. Optional condition arguments can further restrict the set of objects.";
}
public override void Compile( Mobile from, BaseCommand command, ref string[] args, ref object obj )
{
try
{
Extensions ext = Extensions.Parse( from, ref args );
bool items, mobiles;
if ( !CheckObjectTypes( command, ext, out items, out mobiles ) )
return;
if ( !mobiles ) // sanity check
{
command.LogFailure( "This command does not support mobiles." );
return;
}
ArrayList list = new ArrayList();
List<NetState> states = NetState.Instances;
for ( int i = 0; i < states.Count; ++i )
{
NetState ns = states[i];
Mobile mob = ns.Mobile;
if ( mob == null )
continue;
if( !BaseCommand.IsAccessible( from, mob ) )
continue;
if ( ext.IsValid( mob ) )
list.Add( mob );
}
ext.Filter( list );
obj = list;
}
catch ( Exception ex )
{
from.SendMessage( ex.Message );
}
}
}
}

View file

@ -0,0 +1,61 @@
using System;
using System.Collections;
using Server;
namespace Server.Commands.Generic
{
public class RegionCommandImplementor : BaseCommandImplementor
{
public RegionCommandImplementor()
{
Accessors = new string[]{ "Region" };
SupportRequirement = CommandSupport.Region;
SupportsConditionals = true;
AccessLevel = AccessLevel.GameMaster;
Usage = "Region <command> [condition]";
Description = "Invokes the command on all appropriate mobiles in your current region. Optional condition arguments can further restrict the set of objects.";
}
public override void Compile( Mobile from, BaseCommand command, ref string[] args, ref object obj )
{
try
{
Extensions ext = Extensions.Parse( from, ref args );
bool items, mobiles;
if ( !CheckObjectTypes( command, ext, out items, out mobiles ) )
return;
Region reg = from.Region;
ArrayList list = new ArrayList();
if ( mobiles )
{
foreach ( Mobile mob in reg.GetMobiles() )
{
if( !BaseCommand.IsAccessible( from, mob ) )
continue;
if ( ext.IsValid( mob ) )
list.Add( mob );
}
}
else
{
command.LogFailure( "This command does not support items." );
return;
}
ext.Filter( list );
obj = list;
}
catch ( Exception ex )
{
from.SendMessage( ex.Message );
}
}
}
}

View file

@ -0,0 +1,27 @@
using System;
using System.Collections;
using Server;
using Server.Targeting;
namespace Server.Commands.Generic
{
public class SelfCommandImplementor : BaseCommandImplementor
{
public SelfCommandImplementor()
{
Accessors = new string[]{ "Self" };
SupportRequirement = CommandSupport.Self;
AccessLevel = AccessLevel.Counselor;
Usage = "Self <command>";
Description = "Invokes the command on the commanding player.";
}
public override void Compile( Mobile from, BaseCommand command, ref string[] args, ref object obj )
{
if ( command.ObjectTypes == ObjectTypes.Items )
return; // sanity check
obj = from;
}
}
}

View file

@ -0,0 +1,66 @@
using System;
using System.Collections;
using Server;
using Server.Targeting;
namespace Server.Commands.Generic
{
public class SerialCommandImplementor : BaseCommandImplementor
{
public SerialCommandImplementor()
{
Accessors = new string[]{ "Serial" };
SupportRequirement = CommandSupport.Single;
AccessLevel = AccessLevel.Counselor;
Usage = "Serial <serial> <command>";
Description = "Invokes the command on a single object by serial.";
}
public override void Execute( CommandEventArgs e )
{
if ( e.Length >= 2 )
{
Serial serial = e.GetInt32( 0 );
object obj = null;
if ( serial.IsItem )
obj = World.FindItem( serial );
else if ( serial.IsMobile )
obj = World.FindMobile( serial );
if ( obj == null )
{
e.Mobile.SendMessage( "That is not a valid serial." );
}
else
{
BaseCommand command = (BaseCommand) this.Commands[e.GetString( 1 )];
if ( command == null )
{
e.Mobile.SendMessage( "That is either an invalid command name or one that does not support this modifier." );
}
else if ( e.Mobile.AccessLevel < command.AccessLevel )
{
e.Mobile.SendMessage( "You do not have access to that command." );
}
else
{
string[] oldArgs = e.Arguments;
string[] args = new string[oldArgs.Length - 2];
for ( int i = 0; i < args.Length; ++i )
args[i] = oldArgs[i + 2];
RunCommand( e.Mobile, obj, command, args );
}
}
}
else
{
e.Mobile.SendMessage( "You must supply an object serial and a command name." );
}
}
}
}

View file

@ -0,0 +1,94 @@
using System;
using System.Collections;
using Server;
using Server.Targeting;
namespace Server.Commands.Generic
{
public class SingleCommandImplementor : BaseCommandImplementor
{
public SingleCommandImplementor()
{
Accessors = new string[]{ "Single" };
SupportRequirement = CommandSupport.Single;
AccessLevel = AccessLevel.Counselor;
Usage = "Single <command>";
Description = "Invokes the command on a single targeted object. This is the same as just invoking the command directly.";
}
public override void Register( BaseCommand command )
{
base.Register( command );
for ( int i = 0; i < command.Commands.Length; ++i )
CommandSystem.Register( command.Commands[i], command.AccessLevel, new CommandEventHandler( Redirect ) );
}
public void Redirect( CommandEventArgs e )
{
BaseCommand command = (BaseCommand)Commands[e.Command];
if ( command == null )
e.Mobile.SendMessage( "That is either an invalid command name or one that does not support this modifier." );
else if ( e.Mobile.AccessLevel < command.AccessLevel )
e.Mobile.SendMessage( "You do not have access to that command." );
else if ( command.ValidateArgs( this, e ) )
Process( e.Mobile, command, e.Arguments );
}
public override void Process( Mobile from, BaseCommand command, string[] args )
{
if ( command.ValidateArgs( this, new CommandEventArgs( from, command.Commands[0], GenerateArgString( args ), args ) ) )
from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } );
}
public void OnTarget( Mobile from, object targeted, object state )
{
if ( !BaseCommand.IsAccessible( from, targeted ) )
{
from.SendMessage( "That is not accessible." );
return;
}
object[] states = (object[])state;
BaseCommand command = (BaseCommand)states[0];
string[] args = (string[])states[1];
switch ( command.ObjectTypes )
{
case ObjectTypes.Both:
{
if ( !(targeted is Item) && !(targeted is Mobile) )
{
from.SendMessage( "This command does not work on that." );
return;
}
break;
}
case ObjectTypes.Items:
{
if ( !(targeted is Item) )
{
from.SendMessage( "This command only works on items." );
return;
}
break;
}
case ObjectTypes.Mobiles:
{
if ( !(targeted is Mobile) )
{
from.SendMessage( "This command only works on mobiles." );
return;
}
break;
}
}
RunCommand( from, targeted, command, args );
}
}
}

1496
Scripts/Commands/Handlers.cs Normal file

File diff suppressed because it is too large Load diff

144
Scripts/Commands/Logging.cs Normal file
View file

@ -0,0 +1,144 @@
using System;
using System.IO;
using Server;
using Server.Accounting;
namespace Server.Commands
{
public class CommandLogging
{
private static StreamWriter m_Output;
private static bool m_Enabled = true;
public static bool Enabled{ get{ return m_Enabled; } set{ m_Enabled = value; } }
public static StreamWriter Output{ get{ return m_Output; } }
public static void Initialize()
{
EventSink.Command += new CommandEventHandler( EventSink_Command );
if ( !Directory.Exists( "Logs" ) )
Directory.CreateDirectory( "Logs" );
string directory = "Logs/Commands";
if ( !Directory.Exists( directory ) )
Directory.CreateDirectory( directory );
try
{
m_Output = new StreamWriter( Path.Combine( directory, String.Format( "{0}.log", DateTime.Now.ToLongDateString() ) ), true );
m_Output.AutoFlush = true;
m_Output.WriteLine( "##############################" );
m_Output.WriteLine( "Log started on {0}", DateTime.Now );
m_Output.WriteLine();
}
catch
{
}
}
public static object Format( object o )
{
if ( o is Mobile )
{
Mobile m = (Mobile)o;
if ( m.Account == null )
return String.Format( "{0} (no account)", m );
else
return String.Format( "{0} ('{1}')", m, m.Account.Username );
}
else if ( o is Item )
{
Item item = (Item)o;
return String.Format( "0x{0:X} ({1})", item.Serial.Value, item.GetType().Name );
}
return o;
}
public static void WriteLine( Mobile from, string format, params object[] args )
{
WriteLine( from, String.Format( format, args ) );
}
public static void WriteLine( Mobile from, string text )
{
if ( !m_Enabled )
return;
try
{
m_Output.WriteLine( "{0}: {1}: {2}", DateTime.Now, from.NetState, text );
string path = Core.BaseDirectory;
Account acct = from.Account as Account;
string name = ( acct == null ? from.Name : acct.Username );
AppendPath( ref path, "Logs" );
AppendPath( ref path, "Commands" );
AppendPath( ref path, from.AccessLevel.ToString() );
path = Path.Combine( path, String.Format( "{0}.log", name ) );
using ( StreamWriter sw = new StreamWriter( path, true ) )
sw.WriteLine( "{0}: {1}: {2}", DateTime.Now, from.NetState, text );
}
catch
{
}
}
private static char[] m_NotSafe = new char[]{ '\\', '/', ':', '*', '?', '"', '<', '>', '|' };
public static void AppendPath( ref string path, string toAppend )
{
path = Path.Combine( path, toAppend );
if ( !Directory.Exists( path ) )
Directory.CreateDirectory( path );
}
public static string Safe( string ip )
{
if ( ip == null )
return "null";
ip = ip.Trim();
if ( ip.Length == 0 )
return "empty";
bool isSafe = true;
for ( int i = 0; isSafe && i < m_NotSafe.Length; ++i )
isSafe = ( ip.IndexOf( m_NotSafe[i] ) == -1 );
if ( isSafe )
return ip;
System.Text.StringBuilder sb = new System.Text.StringBuilder( ip );
for ( int i = 0; i < m_NotSafe.Length; ++i )
sb.Replace( m_NotSafe[i], '_' );
return sb.ToString();
}
public static void EventSink_Command( CommandEventArgs e )
{
WriteLine( e.Mobile, "{0} {1} used command '{2} {3}'", e.Mobile.AccessLevel, Format( e.Mobile ), e.Command, e.ArgString );
}
public static void LogChangeProperty( Mobile from, object o, string name, string value )
{
WriteLine( from, "{0} {1} set property '{2}' of {3} to '{4}'", from.AccessLevel, Format( from ), name, Format( o ), value );
}
}
}

View file

@ -0,0 +1,796 @@
using System;
using System.Reflection;
using System.Collections;
using Server;
using Server.Targeting;
using Server.Items;
using Server.Gumps;
using CPA = Server.CommandPropertyAttribute;
using Server.Commands;
using Server.Commands.Generic;
namespace Server.Commands
{
public enum PropertyAccess
{
Read = 0x01,
Write = 0x02,
ReadWrite = Read | Write
}
public class Properties
{
public static void Register()
{
CommandSystem.Register( "Props", AccessLevel.Counselor, new CommandEventHandler( Props_OnCommand ) );
}
private class PropsTarget : Target
{
public PropsTarget() : base( -1, true, TargetFlags.None )
{
}
protected override void OnTarget( Mobile from, object o )
{
if ( !BaseCommand.IsAccessible( from, o ) )
from.SendMessage( "That is not accessible." );
else
from.SendGump( new PropertiesGump( from, o ) );
}
}
[Usage( "Props [serial]" )]
[Description( "Opens a menu where you can view and edit all properties of a targeted (or specified) object." )]
private static void Props_OnCommand( CommandEventArgs e )
{
if ( e.Length == 1 )
{
IEntity ent = World.FindEntity( e.GetInt32( 0 ) );
if ( ent == null )
e.Mobile.SendMessage( "No object with that serial was found." );
else if ( !BaseCommand.IsAccessible( e.Mobile, ent ) )
e.Mobile.SendMessage( "That is not accessible." );
else
e.Mobile.SendGump( new PropertiesGump( e.Mobile, ent ) );
}
else
{
e.Mobile.Target = new PropsTarget();
}
}
private static bool CIEqual( string l, string r )
{
return Insensitive.Equals( l, r );
}
private static Type typeofCPA = typeof( CPA );
public static CPA GetCPA( PropertyInfo p )
{
object[] attrs = p.GetCustomAttributes( typeofCPA, false );
if ( attrs.Length == 0 )
return null;
return attrs[0] as CPA;
}
public static PropertyInfo[] GetPropertyInfoChain( Mobile from, Type type, string propertyString, PropertyAccess endAccess, ref string failReason )
{
string[] split = propertyString.Split( '.' );
if ( split.Length == 0 )
return null;
PropertyInfo[] info = new PropertyInfo[split.Length];
for ( int i = 0; i < info.Length; ++i )
{
string propertyName = split[i];
if ( CIEqual( propertyName, "current" ) )
continue;
PropertyInfo[] props = type.GetProperties( BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public );
bool isFinal = ( i == (info.Length - 1) );
PropertyAccess access = endAccess;
if ( !isFinal )
access |= PropertyAccess.Read;
for ( int j = 0; j < props.Length; ++j )
{
PropertyInfo p = props[j];
if ( CIEqual( p.Name, propertyName ) )
{
CPA attr = GetCPA( p );
if ( attr == null )
{
failReason = String.Format( "Property '{0}' not found.", propertyName );
return null;
}
else if ( (access & PropertyAccess.Read) != 0 && from.AccessLevel < attr.ReadLevel )
{
failReason = String.Format( "You must be at least {0} to get the property '{1}'.",
Mobile.GetAccessLevelName( attr.ReadLevel ), propertyName );
return null;
}
else if ( (access & PropertyAccess.Write) != 0 && from.AccessLevel < attr.WriteLevel )
{
failReason = String.Format( "You must be at least {0} to set the property '{1}'.",
Mobile.GetAccessLevelName( attr.WriteLevel ), propertyName );
return null;
}
else if ( (access & PropertyAccess.Read) != 0 && !p.CanRead )
{
failReason = String.Format( "Property '{0}' is write only.", propertyName );
return null;
}
else if ( (access & PropertyAccess.Write) != 0 && !p.CanWrite && isFinal )
{
failReason = String.Format( "Property '{0}' is read only.", propertyName );
return null;
}
info[i] = p;
type = p.PropertyType;
break;
}
}
if ( info[i] == null )
{
failReason = String.Format( "Property '{0}' not found.", propertyName );
return null;
}
}
return info;
}
public static PropertyInfo GetPropertyInfo( Mobile from, ref object obj, string propertyName, PropertyAccess access, ref string failReason )
{
PropertyInfo[] chain = GetPropertyInfoChain( from, obj.GetType(), propertyName, access, ref failReason );
if ( chain == null )
return null;
return GetPropertyInfo( ref obj, chain, ref failReason );
}
public static PropertyInfo GetPropertyInfo( ref object obj, PropertyInfo[] chain, ref string failReason )
{
if ( chain == null || chain.Length == 0 )
{
failReason = "Property chain is empty.";
return null;
}
for ( int i = 0; i < chain.Length - 1; ++i )
{
if ( chain[i] == null )
continue;
obj = chain[i].GetValue( obj, null );
if ( obj == null )
{
failReason = String.Format( "Property '{0}' is null.", chain[i] );
return null;
}
}
return chain[chain.Length-1];
}
public static string GetValue( Mobile from, object o, string name )
{
string failReason = "";
PropertyInfo[] chain = GetPropertyInfoChain( from, o.GetType(), name, PropertyAccess.Read, ref failReason );
if ( chain == null || chain.Length == 0 )
return failReason;
PropertyInfo p = GetPropertyInfo( ref o, chain, ref failReason );
if ( p == null )
return failReason;
return InternalGetValue( o, p, chain );
}
public static string IncreaseValue( Mobile from, object o, string[] args )
{
Type type = o.GetType();
object[] realObjs = new object[args.Length/2];
PropertyInfo[] realProps = new PropertyInfo[args.Length/2];
int[] realValues = new int[args.Length/2];
bool positive = false, negative = false;
for ( int i = 0; i < realProps.Length; ++i )
{
string name = args[i*2];
try
{
string valueString = args[1 + (i*2)];
if ( valueString.StartsWith( "0x" ) )
{
realValues[i] = Convert.ToInt32( valueString.Substring( 2 ), 16 );
}
else
{
realValues[i] = Convert.ToInt32( valueString );
}
}
catch
{
return "Offset value could not be parsed.";
}
if ( realValues[i] > 0 )
positive = true;
else if ( realValues[i] < 0 )
negative = true;
else
return "Zero is not a valid value to offset.";
string failReason = null;
realObjs[i] = o;
realProps[i] = GetPropertyInfo( from, ref realObjs[i], name, PropertyAccess.ReadWrite, ref failReason );
if ( failReason != null )
return failReason;
if ( realProps[i] == null )
return "Property not found.";
}
for ( int i = 0; i < realProps.Length; ++i )
{
object obj = realProps[i].GetValue( realObjs[i], null );
long v = (long)Convert.ChangeType( obj, TypeCode.Int64 );
v += realValues[i];
realProps[i].SetValue( realObjs[i], Convert.ChangeType( v, realProps[i].PropertyType ), null );
}
if ( realProps.Length == 1 )
{
if ( positive )
return "The property has been increased.";
return "The property has been decreased.";
}
if ( positive && negative )
return "The properties have been changed.";
if ( positive )
return "The properties have been increased.";
return "The properties have been decreased.";
}
private static string InternalGetValue( object o, PropertyInfo p )
{
return InternalGetValue( o, p, null );
}
private static string InternalGetValue( object o, PropertyInfo p, PropertyInfo[] chain )
{
Type type = p.PropertyType;
object value = p.GetValue( o, null );
string toString;
if ( value == null )
toString = "null";
else if ( IsNumeric( type ) )
toString = String.Format( "{0} (0x{0:X})", value );
else if ( IsChar( type ) )
toString = String.Format( "'{0}' ({1} [0x{1:X}])", value, (int) value );
else if ( IsString( type ) )
toString = ( (string) value == "null" ? @"@""null""" : String.Format( "\"{0}\"", value ) );
else
toString = value.ToString();
if ( chain == null )
return String.Format( "{0} = {1}", p.Name, toString );
string[] concat = new string[chain.Length*2+1];
for ( int i = 0; i < chain.Length; ++i )
{
concat[(i*2)+0] = chain[i].Name;
concat[(i*2)+1] = ( i < (chain.Length - 1) ) ? "." : " = ";
}
concat[concat.Length-1] = toString;
return String.Concat( concat );
}
public static string SetValue( Mobile from, object o, string name, string value )
{
object logObject = o;
string failReason = "";
PropertyInfo p = GetPropertyInfo( from, ref o, name, PropertyAccess.Write, ref failReason );
if ( p == null )
return failReason;
return InternalSetValue( from, logObject, o, p, name, value, true );
}
private static Type typeofSerial = typeof( Serial );
private static bool IsSerial( Type t )
{
return ( t == typeofSerial );
}
private static Type typeofType = typeof( Type );
private static bool IsType( Type t )
{
return ( t == typeofType );
}
private static Type typeofChar = typeof( Char );
private static bool IsChar( Type t )
{
return ( t == typeofChar );
}
private static Type typeofString = typeof( String );
private static bool IsString( Type t )
{
return ( t == typeofString );
}
private static bool IsEnum( Type t )
{
return t.IsEnum;
}
private static Type typeofTimeSpan = typeof( TimeSpan );
private static Type typeofParsable = typeof( ParsableAttribute );
private static bool IsParsable( Type t )
{
return ( t == typeofTimeSpan || t.IsDefined( typeofParsable, false ) );
}
private static Type[] m_ParseTypes = new Type[]{ typeof( string ) };
private static object[] m_ParseParams = new object[1];
private static object Parse( object o, Type t, string value )
{
MethodInfo method = t.GetMethod( "Parse", m_ParseTypes );
m_ParseParams[0] = value;
return method.Invoke( o, m_ParseParams );
}
private static Type[] m_NumericTypes = new Type[]
{
typeof( Byte ), typeof( SByte ),
typeof( Int16 ), typeof( UInt16 ),
typeof( Int32 ), typeof( UInt32 ),
typeof( Int64 ), typeof( UInt64 )
};
private static bool IsNumeric( Type t )
{
return ( Array.IndexOf( m_NumericTypes, t ) >= 0 );
}
public static string ConstructFromString( Type type, object obj, string value, ref object constructed )
{
object toSet;
bool isSerial = IsSerial( type );
if ( isSerial ) // mutate into int32
type = m_NumericTypes[4];
if ( value == "(-null-)" && !type.IsValueType )
value = null;
if ( IsEnum( type ) )
{
try
{
toSet = Enum.Parse( type, value, true );
}
catch
{
return "That is not a valid enumeration member.";
}
}
else if ( IsType( type ) )
{
try
{
toSet = ScriptCompiler.FindTypeByName( value );
if ( toSet == null )
return "No type with that name was found.";
}
catch
{
return "No type with that name was found.";
}
}
else if ( IsParsable( type ) )
{
try
{
toSet = Parse( obj, type, value );
}
catch
{
return "That is not properly formatted.";
}
}
else if ( value == null )
{
toSet = null;
}
else if ( value.StartsWith( "0x" ) && IsNumeric( type ) )
{
try
{
toSet = Convert.ChangeType( Convert.ToUInt64( value.Substring( 2 ), 16 ), type );
}
catch
{
return "That is not properly formatted.";
}
}
else
{
try
{
toSet = Convert.ChangeType( value, type );
}
catch
{
return "That is not properly formatted.";
}
}
if ( isSerial ) // mutate back
toSet = (Serial)((Int32)toSet);
constructed = toSet;
return null;
}
public static string SetDirect( Mobile from, object logObject, object obj, PropertyInfo prop, string givenName, object toSet, bool shouldLog )
{
try
{
if ( toSet is AccessLevel )
{
AccessLevel newLevel = (AccessLevel) toSet;
AccessLevel reqLevel = AccessLevel.Administrator;
if ( newLevel == AccessLevel.Administrator )
reqLevel = AccessLevel.Developer;
else if ( newLevel >= AccessLevel.Developer )
reqLevel = AccessLevel.Owner;
if ( from.AccessLevel < reqLevel )
return "You do not have access to that level.";
}
if ( shouldLog )
CommandLogging.LogChangeProperty( from, logObject, givenName, toSet == null ? "(-null-)" : toSet.ToString() );
prop.SetValue( obj, toSet, null );
return "Property has been set.";
}
catch
{
return "An exception was caught, the property may not be set.";
}
}
public static string InternalSetValue( Mobile from, object logobj, object o, PropertyInfo p, string pname, string value, bool shouldLog )
{
object toSet = null;
string result = ConstructFromString( p.PropertyType, o, value, ref toSet );
if ( result != null )
return result;
return SetDirect( from, logobj, o, p, pname, toSet, shouldLog );
}
}
}
namespace Server
{
public abstract class PropertyException : ApplicationException
{
protected Property m_Property;
public Property Property
{
get { return m_Property; }
}
public PropertyException( Property property, string message )
: base( message )
{
m_Property = property;
}
}
public abstract class BindingException : PropertyException
{
public BindingException( Property property, string message )
: base( property, message )
{
}
}
public sealed class NotYetBoundException : BindingException
{
public NotYetBoundException( Property property )
: base( property, String.Format( "Property has not yet been bound." ) )
{
}
}
public sealed class AlreadyBoundException : BindingException
{
public AlreadyBoundException( Property property )
: base( property, String.Format( "Property has already been bound." ) )
{
}
}
public sealed class UnknownPropertyException : BindingException
{
public UnknownPropertyException( Property property, string current )
: base( property, String.Format( "Property '{0}' not found.", current ) )
{
}
}
public sealed class ReadOnlyException : BindingException
{
public ReadOnlyException( Property property )
: base( property, "Property is read-only." )
{
}
}
public sealed class WriteOnlyException : BindingException
{
public WriteOnlyException( Property property )
: base( property, "Property is write-only." )
{
}
}
public abstract class AccessException : PropertyException
{
public AccessException( Property property, string message )
: base( property, message )
{
}
}
public sealed class InternalAccessException : AccessException
{
public InternalAccessException( Property property )
: base( property, "Property is internal." )
{
}
}
public abstract class ClearanceException : AccessException
{
protected AccessLevel m_PlayerAccess;
protected AccessLevel m_NeededAccess;
public AccessLevel PlayerAccess
{
get { return m_PlayerAccess; }
}
public AccessLevel NeededAccess
{
get { return m_NeededAccess; }
}
public ClearanceException( Property property, AccessLevel playerAccess, AccessLevel neededAccess, string accessType )
: base( property, string.Format(
"You must be at least {0} to {1} this property.",
Mobile.GetAccessLevelName( neededAccess ),
accessType
) )
{
}
}
public sealed class ReadAccessException : ClearanceException
{
public ReadAccessException( Property property, AccessLevel playerAccess, AccessLevel neededAccess )
: base( property, playerAccess, neededAccess, "read" )
{
}
}
public sealed class WriteAccessException : ClearanceException
{
public WriteAccessException( Property property, AccessLevel playerAccess, AccessLevel neededAccess )
: base( property, playerAccess, neededAccess, "write" )
{
}
}
public sealed class Property
{
private string m_Binding;
private PropertyInfo[] m_Chain;
private PropertyAccess m_Access;
public string Binding
{
get { return m_Binding; }
}
public bool IsBound
{
get { return ( m_Chain != null ); }
}
public PropertyAccess Access
{
get { return m_Access; }
}
public PropertyInfo[] Chain
{
get
{
if ( !IsBound )
throw new NotYetBoundException( this );
return m_Chain;
}
}
public Type Type
{
get
{
if ( !IsBound )
throw new NotYetBoundException( this );
return m_Chain[m_Chain.Length - 1].PropertyType;
}
}
public bool CheckAccess( Mobile from )
{
if ( !IsBound )
throw new NotYetBoundException( this );
for ( int i = 0; i < m_Chain.Length; ++i )
{
PropertyInfo prop = m_Chain[i];
bool isFinal = ( i == ( m_Chain.Length - 1 ) );
PropertyAccess access = m_Access;
if ( !isFinal )
access |= PropertyAccess.Read;
CPA security = Properties.GetCPA( prop );
if ( security == null )
throw new InternalAccessException( this );
if ( ( access & PropertyAccess.Read ) != 0 && from.AccessLevel < security.ReadLevel )
throw new ReadAccessException( this, from.AccessLevel, security.ReadLevel );
if ( ( access & PropertyAccess.Write ) != 0 && from.AccessLevel < security.WriteLevel )
throw new WriteAccessException( this, from.AccessLevel, security.ReadLevel );
}
return true;
}
public void BindTo( Type objectType, PropertyAccess desiredAccess )
{
if ( IsBound )
throw new AlreadyBoundException( this );
string[] split = m_Binding.Split( '.' );
PropertyInfo[] chain = new PropertyInfo[split.Length];
for ( int i = 0; i < split.Length; ++i )
{
bool isFinal = ( i == ( chain.Length - 1 ) );
chain[i] = objectType.GetProperty( split[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase );
if ( chain[i] == null )
throw new UnknownPropertyException( this, split[i] );
objectType = chain[i].PropertyType;
PropertyAccess access = desiredAccess;
if ( !isFinal )
access |= PropertyAccess.Read;
if ( ( access & PropertyAccess.Read ) != 0 && !chain[i].CanRead )
throw new WriteOnlyException( this );
if ( ( access & PropertyAccess.Write ) != 0 && !chain[i].CanWrite )
throw new ReadOnlyException( this );
}
m_Access = desiredAccess;
m_Chain = chain;
}
public Property( string binding )
{
m_Binding = binding;
}
public Property( PropertyInfo[] chain )
{
m_Chain = chain;
}
public override string ToString()
{
if ( !IsBound )
return m_Binding;
string[] toJoin = new string[m_Chain.Length];
for ( int i = 0; i < toJoin.Length; ++i )
toJoin[i] = m_Chain[i].Name;
return string.Join( ".", toJoin );
}
public static Property Parse( Type type, string binding, PropertyAccess access )
{
Property prop = new Property( binding );
prop.BindTo( type, access );
return prop;
}
}
}

View file

@ -0,0 +1,139 @@
using System;
using System.Collections;
using System.IO;
using Server;
using Server.Items;
namespace Server.Commands
{
public class SignParser
{
private class SignEntry
{
public string m_Text;
public Point3D m_Location;
public int m_ItemID;
public int m_Map;
public SignEntry( string text, Point3D pt, int itemID, int mapLoc )
{
m_Text = text;
m_Location = pt;
m_ItemID = itemID;
m_Map = mapLoc;
}
}
public static void Initialize()
{
CommandSystem.Register( "SignGen", AccessLevel.Administrator, new CommandEventHandler( SignGen_OnCommand ) );
}
[Usage( "SignGen" )]
[Description( "Generates world/shop signs on all facets." )]
public static void SignGen_OnCommand( CommandEventArgs c )
{
Parse( c.Mobile );
}
public static void Parse( Mobile from )
{
string cfg = Path.Combine( Core.BaseDirectory, "Data/signs.cfg" );
if ( File.Exists( cfg ) )
{
ArrayList list = new ArrayList();
from.SendMessage( "Generating signs, please wait." );
using ( StreamReader ip = new StreamReader( cfg ) )
{
string line;
while ( (line = ip.ReadLine()) != null )
{
string[] split = line.Split( ' ' );
SignEntry e = new SignEntry(
line.Substring( split[0].Length + 1 + split[1].Length + 1 + split[2].Length + 1 + split[3].Length + 1 + split[4].Length + 1 ),
new Point3D( Utility.ToInt32( split[2] ), Utility.ToInt32( split[3] ), Utility.ToInt32( split[4] ) ),
Utility.ToInt32( split[1] ), Utility.ToInt32( split[0] ) );
list.Add( e );
}
}
Map[] brit = new Map[]{ Map.Felucca, Map.Trammel };
Map[] fel = new Map[]{ Map.Felucca };
Map[] tram = new Map[]{ Map.Trammel };
Map[] ilsh = new Map[]{ Map.Ilshenar };
Map[] malas = new Map[]{ Map.Malas };
Map[] tokuno = new Map[]{ Map.Tokuno };
for ( int i = 0; i < list.Count; ++i )
{
SignEntry e = (SignEntry)list[i];
Map[] maps = null;
switch ( e.m_Map )
{
case 0: maps = brit; break; // Trammel and Felucca
case 1: maps = fel; break; // Felucca
case 2: maps = tram; break; // Trammel
case 3: maps = ilsh; break; // Ilshenar
case 4: maps = malas; break; // Malas
case 5: maps = tokuno; break; // Tokuno Islands
}
for ( int j = 0; maps != null && j < maps.Length; ++j )
Add_Static( e.m_ItemID, e.m_Location, maps[j], e.m_Text );
}
from.SendMessage( "Sign generating complete." );
}
else
{
from.SendMessage( "{0} not found!", cfg );
}
}
private static Queue m_ToDelete = new Queue();
public static void Add_Static( int itemID, Point3D location, Map map, string name )
{
IPooledEnumerable eable = map.GetItemsInRange( location, 0 );
foreach ( Item item in eable )
{
if ( item is Sign && item.Z == location.Z && item.ItemID == itemID )
m_ToDelete.Enqueue( item );
}
eable.Free();
while ( m_ToDelete.Count > 0 )
((Item)m_ToDelete.Dequeue()).Delete();
Item sign;
if ( name.StartsWith( "#" ) )
{
sign = new LocalizedSign( itemID, Utility.ToInt32( name.Substring( 1 ) ) );
}
else
{
sign = new Sign( itemID );
sign.Name = name;
}
if ( map == Map.Malas )
{
if ( location.X >= 965 && location.Y >= 502 && location.X <= 1012 && location.Y <= 537 )
sign.Hue = 0x47E;
else if ( location.X >= 1960 && location.Y >= 1278 && location.X < 2106 && location.Y < 1413 )
sign.Hue = 0x44E;
}
sign.MoveToWorld( location, map );
}
}
}

152
Scripts/Commands/Skills.cs Normal file
View file

@ -0,0 +1,152 @@
using System;
using System.Collections;
using Server;
using Server.Targeting;
namespace Server.Commands
{
public class SkillsCommand
{
public static void Initialize()
{
CommandSystem.Register( "SetSkill", AccessLevel.GameMaster, new CommandEventHandler( SetSkill_OnCommand ) );
CommandSystem.Register( "GetSkill", AccessLevel.GameMaster, new CommandEventHandler( GetSkill_OnCommand ) );
CommandSystem.Register( "SetAllSkills", AccessLevel.GameMaster, new CommandEventHandler( SetAllSkills_OnCommand ) );
}
[Usage( "SetSkill <name> <value>" )]
[Description( "Sets a skill value by name of a targeted mobile." )]
public static void SetSkill_OnCommand( CommandEventArgs arg )
{
if ( arg.Length != 2 )
{
arg.Mobile.SendMessage( "SetSkill <skill name> <value>" );
}
else
{
SkillName skill;
try
{
skill = (SkillName)Enum.Parse( typeof( SkillName ), arg.GetString( 0 ), true );
}
catch
{
arg.Mobile.SendLocalizedMessage( 1005631 ); // You have specified an invalid skill to set.
return;
}
arg.Mobile.Target = new SkillTarget( skill, arg.GetDouble( 1 ) );
}
}
[Usage( "SetAllSkills <name> <value>" )]
[Description( "Sets all skill values of a targeted mobile." )]
public static void SetAllSkills_OnCommand( CommandEventArgs arg )
{
if ( arg.Length != 1 )
{
arg.Mobile.SendMessage( "SetAllSkills <value>" );
}
else
{
arg.Mobile.Target = new AllSkillsTarget( arg.GetDouble( 0 ) );
}
}
[Usage( "GetSkill <name>" )]
[Description( "Gets a skill value by name of a targeted mobile." )]
public static void GetSkill_OnCommand( CommandEventArgs arg )
{
if ( arg.Length != 1 )
{
arg.Mobile.SendMessage( "GetSkill <skill name>" );
}
else
{
SkillName skill;
try
{
skill = (SkillName)Enum.Parse( typeof( SkillName ), arg.GetString( 0 ), true );
}
catch
{
arg.Mobile.SendLocalizedMessage( 1005631 ); // You have specified an invalid skill to set.
return;
}
arg.Mobile.Target = new SkillTarget( skill );
}
}
public class AllSkillsTarget : Target
{
private double m_Value;
public AllSkillsTarget( double value ) : base( -1, false, TargetFlags.None )
{
m_Value = value;
}
protected override void OnTarget( Mobile from, object targeted )
{
if ( targeted is Mobile )
{
Mobile targ = (Mobile)targeted;
Server.Skills skills = targ.Skills;
for ( int i = 0; i < skills.Length; ++i )
skills[i].Base = m_Value;
CommandLogging.LogChangeProperty( from, targ, "EverySkill.Base", m_Value.ToString() );
}
else
{
from.SendMessage( "That does not have skills!" );
}
}
}
public class SkillTarget : Target
{
private bool m_Set;
private SkillName m_Skill;
private double m_Value;
public SkillTarget( SkillName skill, double value ) : base( -1, false, TargetFlags.None )
{
m_Set = true;
m_Skill = skill;
m_Value = value;
}
public SkillTarget( SkillName skill ) : base( -1, false, TargetFlags.None )
{
m_Set = false;
m_Skill = skill;
}
protected override void OnTarget( Mobile from, object targeted )
{
if ( targeted is Mobile )
{
Mobile targ = (Mobile)targeted;
Skill skill = targ.Skills[m_Skill];
if ( skill == null )
return;
if ( m_Set )
{
skill.Base = m_Value;
CommandLogging.LogChangeProperty( from, targ, String.Format( "{0}.Base", m_Skill ), m_Value.ToString() );
}
from.SendMessage( "{0} : {1} (Base: {2})", m_Skill, skill.Value, skill.Base );
}
else
{
from.SendMessage( "That does not have skills!" );
}
}
}
}
}

View file

@ -0,0 +1,40 @@
using System;
using Server;
using Server.Targeting;
using Server.Gumps;
namespace Server.Commands
{
public class Skills
{
public static void Initialize()
{
Register();
}
public static void Register()
{
CommandSystem.Register( "Skills", AccessLevel.Counselor, new CommandEventHandler( Skills_OnCommand ) );
}
private class SkillsTarget : Target
{
public SkillsTarget( ) : base( -1, true, TargetFlags.None )
{
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
from.SendGump( new SkillsGump( from, (Mobile)o ) );
}
}
[Usage( "Skills" )]
[Description( "Opens a menu where you can view or edit skills of a targeted mobile." )]
private static void Skills_OnCommand( CommandEventArgs e )
{
e.Mobile.Target = new SkillsTarget();
}
}
}

577
Scripts/Commands/Statics.cs Normal file
View file

@ -0,0 +1,577 @@
using System;
using System.IO;
using System.Collections;
using Server;
using Server.Gumps;
using Server.Items;
using Server.Commands;
using Server.Targeting;
namespace Server
{
public class Statics
{
public static void Initialize()
{
CommandSystem.Register( "Freeze", AccessLevel.Administrator, new CommandEventHandler( Freeze_OnCommand ) );
CommandSystem.Register( "FreezeMap", AccessLevel.Administrator, new CommandEventHandler( FreezeMap_OnCommand ) );
CommandSystem.Register( "FreezeWorld", AccessLevel.Administrator, new CommandEventHandler( FreezeWorld_OnCommand ) );
CommandSystem.Register( "Unfreeze", AccessLevel.Administrator, new CommandEventHandler( Unfreeze_OnCommand ) );
CommandSystem.Register( "UnfreezeMap", AccessLevel.Administrator, new CommandEventHandler( UnfreezeMap_OnCommand ) );
CommandSystem.Register( "UnfreezeWorld", AccessLevel.Administrator, new CommandEventHandler( UnfreezeWorld_OnCommand ) );
}
private static Point3D NullP3D = new Point3D( int.MinValue, int.MinValue, int.MinValue );
[Usage( "Freeze" )]
[Description( "Makes a targeted area of dynamic items static." )]
public static void Freeze_OnCommand( CommandEventArgs e )
{
BoundingBoxPicker.Begin( e.Mobile, new BoundingBoxCallback( FreezeBox_Callback ), null );
}
[Usage( "FreezeMap" )]
[Description( "Makes every dynamic item in your map static." )]
public static void FreezeMap_OnCommand( CommandEventArgs e )
{
Map map = e.Mobile.Map;
if ( map != null && map != Map.Internal )
SendWarning( e.Mobile, "You are about to freeze <u>all items in {0}</u>.", BaseFreezeWarning, map, NullP3D, NullP3D, new WarningGumpCallback( FreezeWarning_Callback ) );
}
[Usage( "FreezeWorld" )]
[Description( "Makes every dynamic item on all maps static." )]
public static void FreezeWorld_OnCommand( CommandEventArgs e )
{
SendWarning( e.Mobile, "You are about to freeze <u>every item on every map</u>.", BaseFreezeWarning, null, NullP3D, NullP3D, new WarningGumpCallback( FreezeWarning_Callback ) );
}
public static void SendWarning( Mobile m, string header, string baseWarning, Map map, Point3D start, Point3D end, WarningGumpCallback callback )
{
m.SendGump( new WarningGump( 1060635, 30720, String.Format( baseWarning, String.Format( header, map ) ), 0xFFC000, 420, 400, callback, new StateInfo( map, start, end ) ) );
}
private const string BaseFreezeWarning = "{0} " +
"Those items <u>will be removed from the world</u> and placed into the server data files. " +
"Other players <u>will not see the changes</u> unless you distribute your data files to them.<br><br>" +
"This operation may not complete unless the server and client are using different data files. " +
"If you receive a message stating 'output data files could not be opened,' then you are probably sharing data files. " +
"Create a new directory for the world data files (statics*.mul and staidx*.mul) and add that to Scritps/Misc/DataPath.cs.<br><br>" +
"The change will be in effect immediately on the server, however, you must restart your client and update it's data files for the changes to become visible. " +
"It is strongly recommended that you make backup of the data files mentioned above. " +
"Do you wish to proceed?";
private static void FreezeBox_Callback( Mobile from, Map map, Point3D start, Point3D end, object state )
{
SendWarning( from, "You are about to freeze a section of items.", BaseFreezeWarning, map, start, end, new WarningGumpCallback( FreezeWarning_Callback ) );
}
private static void FreezeWarning_Callback( Mobile from, bool okay, object state )
{
if ( !okay )
return;
StateInfo si = (StateInfo)state;
Freeze( from, si.m_Map, si.m_Start, si.m_End );
}
public static void Freeze( Mobile from, Map targetMap, Point3D start3d, Point3D end3d )
{
Hashtable mapTable = new Hashtable();
if ( start3d == NullP3D && end3d == NullP3D )
{
if ( targetMap == null )
CommandLogging.WriteLine( from, "{0} {1} invoking freeze for every item in every map", from.AccessLevel, CommandLogging.Format( from ) );
else
CommandLogging.WriteLine( from, "{0} {1} invoking freeze for every item in {0}", from.AccessLevel, CommandLogging.Format( from ), targetMap );
foreach ( Item item in World.Items.Values )
{
if ( targetMap != null && item.Map != targetMap )
continue;
if ( item.Parent != null )
continue;
if ( item is Static || item is BaseFloor || item is BaseWall )
{
Map itemMap = item.Map;
if ( itemMap == null || itemMap == Map.Internal )
continue;
Hashtable table = (Hashtable)mapTable[itemMap];
if ( table == null )
mapTable[itemMap] = table = new Hashtable();
Point2D p = new Point2D( item.X >> 3, item.Y >> 3 );
DeltaState state = (DeltaState)table[p];
if ( state == null )
table[p] = state = new DeltaState( p );
state.m_List.Add( item );
}
}
}
else if ( targetMap != null )
{
Point2D start = targetMap.Bound( new Point2D( start3d ) ), end = targetMap.Bound( new Point2D( end3d ) );
CommandLogging.WriteLine( from, "{0} {1} invoking freeze from {2} to {3} in {4}", from.AccessLevel, CommandLogging.Format( from ), start, end, targetMap );
IPooledEnumerable eable = targetMap.GetItemsInBounds( new Rectangle2D( start.X, start.Y, end.X - start.X + 1, end.Y - start.Y + 1 ) );
foreach ( Item item in eable )
{
if ( item is Static || item is BaseFloor || item is BaseWall )
{
Map itemMap = item.Map;
if ( itemMap == null || itemMap == Map.Internal )
continue;
Hashtable table = (Hashtable)mapTable[itemMap];
if ( table == null )
mapTable[itemMap] = table = new Hashtable();
Point2D p = new Point2D( item.X >> 3, item.Y >> 3 );
DeltaState state = (DeltaState)table[p];
if ( state == null )
table[p] = state = new DeltaState( p );
state.m_List.Add( item );
}
}
eable.Free();
}
if ( mapTable.Count == 0 )
{
from.SendGump( new NoticeGump( 1060637, 30720, "No freezable items were found. Only the following item types are frozen:<br> - Static<br> - BaseFloor<br> - BaseWall", 0xFFC000, 320, 240, null, null ) );
return;
}
bool badDataFile = false;
int totalFrozen = 0;
foreach ( DictionaryEntry de in mapTable )
{
Map map = (Map)de.Key;
Hashtable table = (Hashtable)de.Value;
TileMatrix matrix = map.Tiles;
using ( FileStream idxStream = OpenWrite( matrix.IndexStream ) )
{
using ( FileStream mulStream = OpenWrite( matrix.DataStream ) )
{
if ( idxStream == null || mulStream == null )
{
badDataFile = true;
continue;
}
BinaryReader idxReader = new BinaryReader( idxStream );
BinaryWriter idxWriter = new BinaryWriter( idxStream );
BinaryWriter mulWriter = new BinaryWriter( mulStream );
foreach ( DeltaState state in table.Values )
{
int oldTileCount;
StaticTile[] oldTiles = ReadStaticBlock( idxReader, mulStream, state.m_X, state.m_Y, matrix.BlockWidth, matrix.BlockHeight, out oldTileCount );
if ( oldTileCount < 0 )
continue;
int newTileCount = 0;
StaticTile[] newTiles = new StaticTile[state.m_List.Count];
for ( int i = 0; i < state.m_List.Count; ++i )
{
Item item = (Item)state.m_List[i];
int xOffset = item.X - (state.m_X * 8);
int yOffset = item.Y - (state.m_Y * 8);
if ( xOffset < 0 || xOffset >= 8 || yOffset < 0 || yOffset >= 8 )
continue;
StaticTile newTile = new StaticTile();
newTile.m_ID = (short)(item.ItemID & 0x3FFF);
newTile.m_X = (byte)xOffset;
newTile.m_Y = (byte)yOffset;
newTile.m_Z = (sbyte)item.Z;
newTile.m_Hue = (short)item.Hue;
newTiles[newTileCount++] = newTile;
item.Delete();
++totalFrozen;
}
int mulPos = -1;
int length = -1;
int extra = 0;
if ( (oldTileCount + newTileCount) > 0 )
{
mulWriter.Seek( 0, SeekOrigin.End );
mulPos = (int)mulWriter.BaseStream.Position;
length = (oldTileCount + newTileCount) * 7;
extra = 1;
for ( int i = 0; i < oldTileCount; ++i )
{
StaticTile toWrite = oldTiles[i];
mulWriter.Write( (short) toWrite.m_ID );
mulWriter.Write( (byte) toWrite.m_X );
mulWriter.Write( (byte) toWrite.m_Y );
mulWriter.Write( (sbyte) toWrite.m_Z );
mulWriter.Write( (short) toWrite.m_Hue );
}
for ( int i = 0; i < newTileCount; ++i )
{
StaticTile toWrite = newTiles[i];
mulWriter.Write( (short) toWrite.m_ID );
mulWriter.Write( (byte) toWrite.m_X );
mulWriter.Write( (byte) toWrite.m_Y );
mulWriter.Write( (sbyte) toWrite.m_Z );
mulWriter.Write( (short) toWrite.m_Hue );
}
mulWriter.Flush();
}
int idxPos = ((state.m_X * matrix.BlockHeight) + state.m_Y) * 12;
idxWriter.Seek( idxPos, SeekOrigin.Begin );
idxWriter.Write( mulPos );
idxWriter.Write( length );
idxWriter.Write( extra );
idxWriter.Flush();
matrix.SetStaticBlock( state.m_X, state.m_Y, null );
}
}
}
}
if ( totalFrozen == 0 && badDataFile )
from.SendGump( new NoticeGump( 1060637, 30720, "Output data files could not be opened and the freeze operation has been aborted.<br><br>This probably means your server and client are using the same data files. Instructions on how to resolve this can be found in the first warning window.", 0xFFC000, 320, 240, null, null ) );
else
from.SendGump( new NoticeGump( 1060637, 30720, String.Format( "Freeze operation completed successfully.<br><br>{0} item{1} frozen.<br><br>You must restart your client and update it's data files to see the changes.", totalFrozen, totalFrozen != 1 ? "s were" : " was" ), 0xFFC000, 320, 240, null, null ) );
}
private const string BaseUnfreezeWarning = "{0} " +
"Those items <u>will be removed from the static files</u> and exchanged with unmovable dynamic items. " +
"Other players <u>will not see the changes</u> unless you distribute your data files to them.<br><br>" +
"This operation may not complete unless the server and client are using different data files. " +
"If you receive a message stating 'output data files could not be opened,' then you are probably sharing data files. " +
"Create a new directory for the world data files (statics*.mul and staidx*.mul) and add that to Scritps/Misc/DataPath.cs.<br><br>" +
"The change will be in effect immediately on the server, however, you must restart your client and update it's data files for the changes to become visible. " +
"It is strongly recommended that you make backup of the data files mentioned above. " +
"Do you wish to proceed?";
[Usage( "Unfreeze" )]
[Description( "Makes a targeted area of static items dynamic." )]
public static void Unfreeze_OnCommand( CommandEventArgs e )
{
BoundingBoxPicker.Begin( e.Mobile, new BoundingBoxCallback( UnfreezeBox_Callback ), null );
}
[Usage( "UnfreezeMap" )]
[Description( "Makes every static item in your map dynamic." )]
public static void UnfreezeMap_OnCommand( CommandEventArgs e )
{
Map map = e.Mobile.Map;
if ( map != null && map != Map.Internal )
SendWarning( e.Mobile, "You are about to unfreeze <u>all items in {0}</u>.", BaseUnfreezeWarning, map, NullP3D, NullP3D, new WarningGumpCallback( UnfreezeWarning_Callback ) );
}
[Usage( "UnfreezeWorld" )]
[Description( "Makes every static item on all maps dynamic." )]
public static void UnfreezeWorld_OnCommand( CommandEventArgs e )
{
SendWarning( e.Mobile, "You are about to unfreeze <u>every item on every map</u>.", BaseUnfreezeWarning, null, NullP3D, NullP3D, new WarningGumpCallback( UnfreezeWarning_Callback ) );
}
private static void UnfreezeBox_Callback( Mobile from, Map map, Point3D start, Point3D end, object state )
{
SendWarning( from, "You are about to unfreeze a section of items.", BaseUnfreezeWarning, map, start, end, new WarningGumpCallback( UnfreezeWarning_Callback ) );
}
private static void UnfreezeWarning_Callback( Mobile from, bool okay, object state )
{
if ( !okay )
return;
StateInfo si = (StateInfo)state;
Unfreeze( from, si.m_Map, si.m_Start, si.m_End );
}
private static void DoUnfreeze( Map map, Point2D start, Point2D end, ref bool badDataFile, ref int totalUnfrozen )
{
start = map.Bound( start );
end = map.Bound( end );
int xStartBlock = start.X >> 3;
int yStartBlock = start.Y >> 3;
int xEndBlock = end.X >> 3;
int yEndBlock = end.Y >> 3;
int xTileStart = start.X, yTileStart = start.Y;
int xTileWidth = end.X - start.X + 1, yTileHeight = end.Y - start.Y + 1;
TileMatrix matrix = map.Tiles;
using ( FileStream idxStream = OpenWrite( matrix.IndexStream ) )
{
using ( FileStream mulStream = OpenWrite( matrix.DataStream ) )
{
if ( idxStream == null || mulStream == null )
{
badDataFile = true;
return;
}
BinaryReader idxReader = new BinaryReader( idxStream );
BinaryWriter idxWriter = new BinaryWriter( idxStream );
BinaryWriter mulWriter = new BinaryWriter( mulStream );
for ( int x = xStartBlock; x <= xEndBlock; ++x )
{
for ( int y = yStartBlock; y <= yEndBlock; ++y )
{
int oldTileCount;
StaticTile[] oldTiles = ReadStaticBlock( idxReader, mulStream, x, y, matrix.BlockWidth, matrix.BlockHeight, out oldTileCount );
if ( oldTileCount < 0 )
continue;
int newTileCount = 0;
StaticTile[] newTiles = new StaticTile[oldTileCount];
int baseX = (x << 3) - xTileStart, baseY = (y << 3) - yTileStart;
for ( int i = 0; i < oldTileCount; ++i )
{
StaticTile oldTile = oldTiles[i];
int px = baseX + oldTile.m_X;
int py = baseY + oldTile.m_Y;
if ( px < 0 || px >= xTileWidth || py < 0 || py >= yTileHeight )
{
newTiles[newTileCount++] = oldTile;
}
else
{
++totalUnfrozen;
Item item = new Static( oldTile.m_ID & 0x3FFF );
item.Hue = oldTile.m_Hue;
item.MoveToWorld( new Point3D( px + xTileStart, py + yTileStart, oldTile.m_Z ), map );
}
}
int mulPos = -1;
int length = -1;
int extra = 0;
if ( newTileCount > 0 )
{
mulWriter.Seek( 0, SeekOrigin.End );
mulPos = (int)mulWriter.BaseStream.Position;
length = newTileCount * 7;
extra = 1;
for ( int i = 0; i < newTileCount; ++i )
{
StaticTile toWrite = newTiles[i];
mulWriter.Write( (short) toWrite.m_ID );
mulWriter.Write( (byte) toWrite.m_X );
mulWriter.Write( (byte) toWrite.m_Y );
mulWriter.Write( (sbyte) toWrite.m_Z );
mulWriter.Write( (short) toWrite.m_Hue );
}
mulWriter.Flush();
}
int idxPos = ((x * matrix.BlockHeight) + y) * 12;
idxWriter.Seek( idxPos, SeekOrigin.Begin );
idxWriter.Write( mulPos );
idxWriter.Write( length );
idxWriter.Write( extra );
idxWriter.Flush();
matrix.SetStaticBlock( x, y, null );
}
}
}
}
}
public static void DoUnfreeze( Map map, ref bool badDataFile, ref int totalUnfrozen )
{
DoUnfreeze( map, Point2D.Zero, new Point2D( map.Width - 1, map.Height - 1 ), ref badDataFile, ref totalUnfrozen );
}
public static void Unfreeze( Mobile from, Map map, Point3D start, Point3D end )
{
int totalUnfrozen = 0;
bool badDataFile = false;
if ( map == null )
{
CommandLogging.WriteLine( from, "{0} {1} invoking unfreeze for every item in every map", from.AccessLevel, CommandLogging.Format( from ) );
DoUnfreeze( Map.Felucca, ref badDataFile, ref totalUnfrozen );
DoUnfreeze( Map.Trammel, ref badDataFile, ref totalUnfrozen );
DoUnfreeze( Map.Ilshenar, ref badDataFile, ref totalUnfrozen );
DoUnfreeze( Map.Malas, ref badDataFile, ref totalUnfrozen );
DoUnfreeze( Map.Tokuno, ref badDataFile, ref totalUnfrozen );
}
else if ( start == NullP3D && end == NullP3D )
{
CommandLogging.WriteLine( from, "{0} {1} invoking unfreeze for every item in {2}", from.AccessLevel, CommandLogging.Format( from ), map );
DoUnfreeze( map, ref badDataFile, ref totalUnfrozen );
}
else
{
CommandLogging.WriteLine( from, "{0} {1} invoking unfreeze from {2} to {3} in {4}", from.AccessLevel, CommandLogging.Format( from ), new Point2D( start ), new Point2D( end ), map );
DoUnfreeze( map, new Point2D( start ), new Point2D( end ), ref badDataFile, ref totalUnfrozen );
}
if ( totalUnfrozen == 0 && badDataFile )
from.SendGump( new NoticeGump( 1060637, 30720, "Output data files could not be opened and the unfreeze operation has been aborted.<br><br>This probably means your server and client are using the same data files. Instructions on how to resolve this can be found in the first warning window.", 0xFFC000, 320, 240, null, null ) );
else
from.SendGump( new NoticeGump( 1060637, 30720, String.Format( "Unfreeze operation completed successfully.<br><br>{0} item{1} unfrozen.<br><br>You must restart your client and update it's data files to see the changes.", totalUnfrozen, totalUnfrozen != 1 ? "s were" : " was" ), 0xFFC000, 320, 240, null, null ) );
}
private static FileStream OpenWrite( FileStream orig )
{
if ( orig == null )
return null;
try{ return new FileStream( orig.Name, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite ); }
catch{ return null; }
}
private static byte[] m_Buffer;
private static StaticTile[] m_TileBuffer = new StaticTile[128];
private static StaticTile[] ReadStaticBlock( BinaryReader idxReader, FileStream mulStream, int x, int y, int width, int height, out int count )
{
try
{
if ( x < 0 || x >= width || y < 0 || y >= height )
{
count = -1;
return m_TileBuffer;
}
idxReader.BaseStream.Seek( ((x * height) + y) * 12, SeekOrigin.Begin );
int lookup = idxReader.ReadInt32();
int length = idxReader.ReadInt32();
if ( lookup < 0 || length <= 0 )
{
count = 0;
}
else
{
count = length / 7;
mulStream.Seek( lookup, SeekOrigin.Begin );
if ( m_TileBuffer.Length < count )
m_TileBuffer = new StaticTile[count];
StaticTile[] staTiles = m_TileBuffer;
if ( m_Buffer == null || length > m_Buffer.Length )
m_Buffer = new byte[length];
mulStream.Read( m_Buffer, 0, length );
int index = 0;
for ( int i = 0; i < count; ++i )
{
staTiles[i].m_ID = (short)(m_Buffer[index++] | (m_Buffer[index++] << 8));
staTiles[i].m_X = m_Buffer[index++];
staTiles[i].m_Y = m_Buffer[index++];
staTiles[i].m_Z = (sbyte)m_Buffer[index++];
staTiles[i].m_Hue = (short)(m_Buffer[index++] | (m_Buffer[index++] << 8));
}
}
}
catch
{
count = -1;
}
return m_TileBuffer;
}
private class DeltaState
{
public int m_X, m_Y;
public ArrayList m_List;
public DeltaState( Point2D p )
{
m_X = p.X;
m_Y = p.Y;
m_List = new ArrayList();
}
}
private class StateInfo
{
public Map m_Map;
public Point3D m_Start, m_End;
public StateInfo( Map map, Point3D start, Point3D end )
{
m_Map = map;
m_Start = start;
m_End = end;
}
}
}
}

View file

@ -0,0 +1,148 @@
using System;
using System.Collections;
using Server;
using Server.Mobiles;
using Server.Targeting;
using Server.Network;
using System.Collections.Generic;
namespace Server.Commands
{
public class VisibilityList
{
public static void Initialize()
{
EventSink.Login += new LoginEventHandler( OnLogin );
CommandSystem.Register( "Vis", AccessLevel.Counselor, new CommandEventHandler( Vis_OnCommand ) );
CommandSystem.Register( "VisList", AccessLevel.Counselor, new CommandEventHandler( VisList_OnCommand ) );
CommandSystem.Register( "VisClear", AccessLevel.Counselor, new CommandEventHandler( VisClear_OnCommand ) );
}
public static void OnLogin( LoginEventArgs e )
{
if ( e.Mobile is PlayerMobile )
{
PlayerMobile pm = (PlayerMobile)e.Mobile;
pm.VisibilityList.Clear();
}
}
[Usage( "Vis" )]
[Description( "Adds or removes a targeted player from your visibility list. Anyone on your visibility list will be able to see you at all times, even when you're hidden." )]
public static void Vis_OnCommand( CommandEventArgs e )
{
if ( e.Mobile is PlayerMobile )
{
e.Mobile.Target = new VisTarget();
e.Mobile.SendMessage( "Select person to add or remove from your visibility list." );
}
}
[Usage( "VisList" )]
[Description( "Shows the names of everyone in your visibility list." )]
public static void VisList_OnCommand( CommandEventArgs e )
{
if ( e.Mobile is PlayerMobile )
{
PlayerMobile pm = (PlayerMobile)e.Mobile;
List<Mobile> list = pm.VisibilityList;
if ( list.Count > 0 )
{
pm.SendMessage( "You are visible to {0} mobile{1}:", list.Count, list.Count == 1 ? "" : "s" );
for ( int i = 0; i < list.Count; ++i )
pm.SendMessage( "#{0}: {1}", i+1, list[i].Name );
}
else
{
pm.SendMessage( "Your visibility list is empty." );
}
}
}
[Usage( "VisClear" )]
[Description( "Removes everyone from your visibility list." )]
public static void VisClear_OnCommand( CommandEventArgs e )
{
if ( e.Mobile is PlayerMobile )
{
PlayerMobile pm = (PlayerMobile)e.Mobile;
List<Mobile> list = new List<Mobile>( pm.VisibilityList );
pm.VisibilityList.Clear();
pm.SendMessage( "Your visibility list has been cleared." );
for ( int i = 0; i < list.Count; ++i )
{
Mobile m = list[i];
if ( !m.CanSee( pm ) && Utility.InUpdateRange( m, pm ) )
m.Send( pm.RemovePacket );
}
}
}
private class VisTarget : Target
{
public VisTarget() : base( -1, false, TargetFlags.None )
{
}
protected override void OnTarget( Mobile from, object targeted )
{
if ( from is PlayerMobile && targeted is Mobile )
{
PlayerMobile pm = (PlayerMobile)from;
Mobile targ = (Mobile)targeted;
if ( targ.AccessLevel < from.AccessLevel )
{
List<Mobile> list = pm.VisibilityList;
if ( list.Contains( targ ) )
{
list.Remove( targ );
from.SendMessage( "{0} has been removed from your visibility list.", targ.Name );
}
else
{
list.Add( targ );
from.SendMessage( "{0} has been added to your visibility list.", targ.Name );
}
if ( Utility.InUpdateRange( targ, from ) )
{
if ( targ.CanSee( from ) )
{
targ.Send( new Network.MobileIncoming( targ, from ) );
if ( ObjectPropertyList.Enabled )
{
targ.Send( from.OPLPacket );
foreach ( Item item in from.Items )
targ.Send( item.OPLPacket );
}
}
else
{
targ.Send( from.RemovePacket );
}
}
}
else
{
from.SendMessage( "They can already see you!" );
}
}
else
{
from.SendMessage( "Add only mobiles to your visibility list." );
}
}
}
}
}

111
Scripts/Commands/Wipe.cs Normal file
View file

@ -0,0 +1,111 @@
using System;
using System.Collections;
using Server;
using Server.Targeting;
using Server.Items;
using Server.Multis;
namespace Server.Commands
{
public class Wipe
{
[Flags]
public enum WipeType
{
Items = 0x01,
Mobiles = 0x02,
Multis = 0x04,
All = Items | Mobiles | Multis
}
public static void Initialize()
{
CommandSystem.Register( "Wipe", AccessLevel.GameMaster, new CommandEventHandler( WipeAll_OnCommand ) );
CommandSystem.Register( "WipeItems", AccessLevel.GameMaster, new CommandEventHandler( WipeItems_OnCommand ) );
CommandSystem.Register( "WipeNPCs", AccessLevel.GameMaster, new CommandEventHandler( WipeNPCs_OnCommand ) );
CommandSystem.Register( "WipeMultis", AccessLevel.GameMaster, new CommandEventHandler( WipeMultis_OnCommand ) );
}
[Usage( "Wipe" )]
[Description( "Wipes all items and npcs in a targeted bounding box." )]
private static void WipeAll_OnCommand( CommandEventArgs e )
{
BeginWipe( e.Mobile, WipeType.Items | WipeType.Mobiles );
}
[Usage( "WipeItems" )]
[Description( "Wipes all items in a targeted bounding box." )]
private static void WipeItems_OnCommand( CommandEventArgs e )
{
BeginWipe( e.Mobile, WipeType.Items );
}
[Usage( "WipeNPCs" )]
[Description( "Wipes all npcs in a targeted bounding box." )]
private static void WipeNPCs_OnCommand( CommandEventArgs e )
{
BeginWipe( e.Mobile, WipeType.Mobiles );
}
[Usage( "WipeMultis" )]
[Description( "Wipes all multis in a targeted bounding box." )]
private static void WipeMultis_OnCommand( CommandEventArgs e )
{
BeginWipe( e.Mobile, WipeType.Multis );
}
public static void BeginWipe( Mobile from, WipeType type )
{
BoundingBoxPicker.Begin( from, new BoundingBoxCallback( WipeBox_Callback ), type );
}
private static void WipeBox_Callback( Mobile from, Map map, Point3D start, Point3D end, object state )
{
DoWipe( from, map, start, end, (WipeType)state );
}
public static void DoWipe( Mobile from, Map map, Point3D start, Point3D end, WipeType type )
{
CommandLogging.WriteLine( from, "{0} {1} wiping from {2} to {3} in {5} ({4})", from.AccessLevel, CommandLogging.Format( from ), start, end, type, map );
bool mobiles = ( (type & WipeType.Mobiles) != 0 );
bool multis = ( (type & WipeType.Multis) != 0 );
bool items = ( (type & WipeType.Items) != 0 );
ArrayList toDelete = new ArrayList();
Rectangle2D rect = new Rectangle2D( start.X, start.Y, end.X - start.X + 1, end.Y - start.Y + 1 );
IPooledEnumerable eable;
if ( (items || multis) && mobiles )
eable = map.GetObjectsInBounds( rect );
else if ( items || multis )
eable = map.GetItemsInBounds( rect );
else if ( mobiles )
eable = map.GetMobilesInBounds( rect );
else
return;
foreach ( object obj in eable )
{
if ( items && (obj is Item) && !((obj is BaseMulti) || (obj is HouseSign)) )
toDelete.Add( obj );
else if ( multis && (obj is BaseMulti) )
toDelete.Add( obj );
else if ( mobiles && (obj is Mobile) && !((Mobile)obj).Player )
toDelete.Add( obj );
}
eable.Free();
for ( int i = 0; i < toDelete.Count; ++i )
{
if ( toDelete[i] is Item )
((Item)toDelete[i]).Delete();
else if ( toDelete[i] is Mobile )
((Mobile)toDelete[i]).Delete();
}
}
}
}

View file

@ -0,0 +1,63 @@
using System;
using Server.Items;
using Server.Targeting;
namespace Server.ContextMenus
{
public class AddToSpellbookEntry : ContextMenuEntry
{
public AddToSpellbookEntry() : base( 6144, 3 )
{
}
public override void OnClick()
{
if ( Owner.From.CheckAlive() && Owner.Target is SpellScroll )
Owner.From.Target = new InternalTarget( (SpellScroll)Owner.Target );
}
private class InternalTarget : Target
{
private SpellScroll m_Scroll;
public InternalTarget( SpellScroll scroll ) : base( 3, false, TargetFlags.None )
{
m_Scroll = scroll;
}
protected override void OnTarget( Mobile from, object targeted )
{
if ( targeted is Spellbook )
{
if ( from.CheckAlive() && !m_Scroll.Deleted && m_Scroll.Movable && m_Scroll.Amount >= 1 )
{
Spellbook book = (Spellbook)targeted;
SpellbookType type = Spellbook.GetTypeForSpell( m_Scroll.SpellID );
if ( type != book.SpellbookType )
{
}
else if ( book.HasSpell( m_Scroll.SpellID ) )
{
from.SendLocalizedMessage( 500179 ); // That spell is already present in that spellbook.
}
else
{
int val = m_Scroll.SpellID - book.BookOffset;
if ( val >= 0 && val < book.BookCount )
{
book.Content |= (ulong)1 << val;
m_Scroll.Consume();
from.Send( new Network.PlaySound( 0x249, book.GetWorldLocation() ) );
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,25 @@
using System;
using Server.Items;
namespace Server.ContextMenus
{
public class EatEntry : ContextMenuEntry
{
private Mobile m_From;
private Food m_Food;
public EatEntry( Mobile from, Food food ) : base( 6135, 1 )
{
m_From = from;
m_Food = food;
}
public override void OnClick()
{
if ( m_Food.Deleted || !m_Food.Movable || !m_From.CheckAlive() )
return;
m_Food.Eat( m_From );
}
}
}

View file

@ -0,0 +1,33 @@
using System;
using Server.Items;
namespace Server.ContextMenus
{
public class OpenBankEntry : ContextMenuEntry
{
private Mobile m_Banker;
public OpenBankEntry( Mobile from, Mobile banker ) : base( 6105, 12 )
{
m_Banker = banker;
}
public override void OnClick()
{
if ( !Owner.From.CheckAlive() )
return;
if ( Owner.From.Criminal )
{
m_Banker.Say( 500378 ); // Thou art a criminal and cannot access thy bank box.
}
else
{
BankBox box = this.Owner.From.BankBox;
if ( box != null )
box.Open();
}
}
}
}

View file

@ -0,0 +1,30 @@
using System;
using Server.Mobiles;
namespace Server.ContextMenus
{
public class TeachEntry : ContextMenuEntry
{
private SkillName m_Skill;
private BaseCreature m_Mobile;
private Mobile m_From;
public TeachEntry( SkillName skill, BaseCreature m, Mobile from, bool enabled ) : base( 6000 + (int)skill, 4 )
{
m_Skill = skill;
m_Mobile = m;
m_From = from;
if ( !enabled )
Flags |= Network.CMEFlags.Disabled;
}
public override void OnClick()
{
if ( !m_From.CheckAlive() )
return;
m_Mobile.Teach( m_Skill, m_From, 0, false );
}
}
}

View file

@ -0,0 +1,157 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
// Ideas
// When you run on animals the panic
// When if ( distance < 8 && Utility.RandomDouble() * Math.Sqrt( (8 - distance) / 6 ) >= incoming.Skills[SkillName.AnimalTaming].Value )
// More your close, the more it can panic
/*
* AnimalHunterAI, AnimalHidingAI, AnimalDomesticAI...
*
*/
namespace Server.Mobiles
{
public class AnimalAI : BaseAI
{
public AnimalAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
// Old:
#if false
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true))
{
m_Mobile.DebugSay( "There is something near, I go away" );
Action = ActionType.Backoff;
}
else if ( m_Mobile.IsHurt() || m_Mobile.Combatant != null )
{
m_Mobile.DebugSay( "I am hurt or being attacked, I flee" );
Action = ActionType.Flee;
}
else
{
base.DoActionWander();
}
return true;
#endif
// New, only flee @ 10%
double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;
if ( !m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 ) // Less than 10% health
{
m_Mobile.DebugSay( "I am low on health!" );
Action = ActionType.Flee;
}
else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
Mobile combatant = m_Mobile.Combatant;
if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map )
{
m_Mobile.DebugSay( "My combatant is gone.." );
Action = ActionType.Wander;
return true;
}
if ( WalkMobileRange( combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight ) )
{
m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant );
}
else
{
if ( m_Mobile.GetDistanceToSqrt( combatant ) > m_Mobile.RangePerception + 1 )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I cannot find {0}", combatant.Name );
Action = ActionType.Wander;
return true;
}
else
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name );
}
}
if ( !m_Mobile.Controlled && !m_Mobile.Summoned )
{
double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;
if ( hitPercent < 0.1 )
{
m_Mobile.DebugSay( "I am low on health!" );
Action = ActionType.Flee;
}
}
return true;
}
public override bool DoActionBackoff()
{
double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;
if ( !m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 ) // Less than 10% health
{
Action = ActionType.Flee;
}
else
{
if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false , true))
{
if ( WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2) )
{
m_Mobile.DebugSay( "Well, here I am safe" );
Action = ActionType.Wander;
}
}
else
{
m_Mobile.DebugSay( "I have lost my focus, lets relax" );
Action = ActionType.Wander;
}
}
return true;
}
public override bool DoActionFlee()
{
AcquireFocusMob(m_Mobile.RangePerception * 2, m_Mobile.FightMode, true, false, true);
if ( m_Mobile.FocusMob == null )
m_Mobile.FocusMob = m_Mobile.Combatant;
return base.DoActionFlee();
}
}
}

View file

@ -0,0 +1,131 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
using Server.Mobiles;
using Server.Items;
namespace Server.Mobiles
{
public class ArcherAI : BaseAI
{
public ArcherAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
m_Mobile.DebugSay( "I have no combatant" );
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0} and I will attack", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
return base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
if ( m_Mobile.Combatant == null || m_Mobile.Combatant.Deleted || !m_Mobile.Combatant.Alive || m_Mobile.Combatant.IsDeadBondedPet )
{
m_Mobile.DebugSay("My combatant is deleted");
Action = ActionType.Guard;
return true;
}
if ( (m_Mobile.LastMoveTime + TimeSpan.FromSeconds( 1.0 )) < DateTime.Now )
{
if (WalkMobileRange(m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.Weapon.MaxRange))
{
// Be sure to face the combatant
m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant.Location);
}
else
{
if ( m_Mobile.Combatant != null )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I am still not in range of {0}", m_Mobile.Combatant.Name);
if ( (int) m_Mobile.GetDistanceToSqrt( m_Mobile.Combatant ) > m_Mobile.RangePerception + 1 )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have lost {0}", m_Mobile.Combatant.Name);
m_Mobile.Combatant = null;
Action = ActionType.Guard;
return true;
}
}
}
}
// When we have no ammo, we flee
Container pack = m_Mobile.Backpack;
if ( pack == null || pack.FindItemByType( typeof( Arrow ) ) == null )
{
Action = ActionType.Flee;
return true;
}
// At 20% we should check if we must leave
if ( m_Mobile.Hits < m_Mobile.HitsMax*20/100 )
{
bool bFlee = false;
// if my current hits are more than my opponent, i don't care
if ( m_Mobile.Combatant != null && m_Mobile.Hits < m_Mobile.Combatant.Hits)
{
int iDiff = m_Mobile.Combatant.Hits - m_Mobile.Hits;
if ( Utility.Random(0, 100) > 10 + iDiff) // 10% to flee + the diff of hits
{
bFlee = true;
}
}
else if ( m_Mobile.Combatant != null && m_Mobile.Hits >= m_Mobile.Combatant.Hits)
{
if ( Utility.Random(0, 100) > 10 ) // 10% to flee
{
bFlee = true;
}
}
if (bFlee)
{
Action = ActionType.Flee;
}
}
return true;
}
public override bool DoActionGuard()
{
if ( AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionGuard();
}
return true;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,87 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
namespace Server.Mobiles
{
public class BerserkAI : BaseAI
{
public BerserkAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
m_Mobile.DebugSay( "I have No Combatant" );
if( AcquireFocusMob( m_Mobile.RangePerception, FightMode.Closest, false, true, true) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected " + m_Mobile.FocusMob.Name + " and I will attack" );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
if( m_Mobile.Combatant == null || m_Mobile.Combatant.Deleted )
{
m_Mobile.DebugSay("My combatant is deleted");
Action = ActionType.Guard;
return true;
}
if( WalkMobileRange( m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight ) )
{
// Be sure to face the combatant
m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant.Location );
}
else
{
if( m_Mobile.Combatant != null )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay("I am still not in range of " + m_Mobile.Combatant.Name);
if( (int) m_Mobile.GetDistanceToSqrt( m_Mobile.Combatant ) > m_Mobile.RangePerception + 1 )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have lost " + m_Mobile.Combatant.Name );
Action = ActionType.Guard;
return true;
}
}
}
return true;
}
public override bool DoActionGuard()
{
if ( AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, true, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionGuard();
}
return true;
}
}
}

View file

@ -0,0 +1,176 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
using Server.Spells;
using Server.Spells.First;
using Server.Spells.Second;
using Server.Spells.Fourth;
namespace Server.Mobiles
{
public class HealerAI : BaseAI
{
private static NeedDelegate m_Cure = new NeedDelegate( NeedCure );
private static NeedDelegate m_GHeal = new NeedDelegate( NeedGHeal );
private static NeedDelegate m_LHeal = new NeedDelegate( NeedLHeal );
private static NeedDelegate[] m_ACure = new NeedDelegate[] { m_Cure };
private static NeedDelegate[] m_AGHeal = new NeedDelegate[] { m_GHeal };
private static NeedDelegate[] m_ALHeal = new NeedDelegate[] { m_LHeal };
private static NeedDelegate[] m_All = new NeedDelegate[] { m_Cure, m_GHeal, m_LHeal };
public HealerAI( BaseCreature m ) : base( m )
{
}
public override bool Think()
{
if ( m_Mobile.Deleted )
return false;
Target targ = m_Mobile.Target;
if ( targ != null )
{
if ( targ is CureSpell.InternalTarget )
{
ProcessTarget( targ, m_ACure );
}
else if ( targ is GreaterHealSpell.InternalTarget )
{
ProcessTarget( targ, m_AGHeal );
}
else if ( targ is HealSpell.InternalTarget )
{
ProcessTarget( targ, m_ALHeal );
}
else
{
targ.Cancel( m_Mobile, TargetCancelType.Canceled );
}
}
else
{
Mobile toHelp = Find( m_All );
if ( toHelp != null )
{
if ( NeedCure( toHelp ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} needs a cure", toHelp.Name );
if ( !(new CureSpell( m_Mobile, null )).Cast() )
new CureSpell( m_Mobile, null ).Cast();
}
else if ( NeedGHeal( toHelp ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} needs a greater heal", toHelp.Name );
if ( !(new GreaterHealSpell( m_Mobile, null )).Cast() )
new HealSpell( m_Mobile, null ).Cast();
}
else if ( NeedLHeal( toHelp ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} needs a lesser heal", toHelp.Name );
new HealSpell( m_Mobile, null ).Cast();
}
}
else
{
if ( AcquireFocusMob( m_Mobile.RangePerception, FightMode.Weakest, false, true, false ) )
{
WalkMobileRange( m_Mobile.FocusMob, 1, false, 4, 7 );
}
else
{
WalkRandomInHome( 3, 2, 1 );
}
}
}
return true;
}
private delegate bool NeedDelegate( Mobile m );
private void ProcessTarget( Target targ, NeedDelegate[] func )
{
Mobile toHelp = Find( func );
if ( toHelp != null )
{
if ( targ.Range != -1 && !m_Mobile.InRange( toHelp, targ.Range ) )
{
DoMove( m_Mobile.GetDirectionTo( toHelp ) | Direction.Running );
}
else
{
targ.Invoke( m_Mobile, toHelp );
}
}
else
{
targ.Cancel( m_Mobile, TargetCancelType.Canceled );
}
}
private Mobile Find( params NeedDelegate[] funcs )
{
if ( m_Mobile.Deleted )
return null;
Map map = m_Mobile.Map;
if ( map != null )
{
double prio = 0.0;
Mobile found = null;
foreach ( Mobile m in m_Mobile.GetMobilesInRange( m_Mobile.RangePerception ) )
{
if ( !m_Mobile.CanSee( m ) || !(m is BaseCreature) || ((BaseCreature)m).Team != m_Mobile.Team )
continue;
for ( int i = 0; i < funcs.Length; ++i )
{
if ( funcs[i]( m ) )
{
double val = -m_Mobile.GetDistanceToSqrt( m );
if ( found == null || val > prio )
{
prio = val;
found = m;
}
break;
}
}
}
return found;
}
return null;
}
private static bool NeedCure( Mobile m )
{
return m.Poisoned;
}
private static bool NeedGHeal( Mobile m )
{
return m.Hits < m.HitsMax - 40;
}
private static bool NeedLHeal( Mobile m )
{
return m.Hits < m.HitsMax - 10;
}
}
}

View file

@ -0,0 +1,992 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Server.Targeting;
using Server.Network;
using Server.Mobiles;
using Server.Items;
using Server.Spells;
using Server.Spells.First;
using Server.Spells.Second;
using Server.Spells.Third;
using Server.Spells.Fourth;
using Server.Spells.Fifth;
using Server.Spells.Sixth;
using Server.Spells.Seventh;
using Server.Misc;
using Server.Regions;
using Server.SkillHandlers;
namespace Server.Mobiles
{
public class MageAI : BaseAI
{
private DateTime m_NextCastTime;
private DateTime m_NextHealTime;
public MageAI( BaseCreature m ) : base( m )
{
}
public override bool Think()
{
if ( m_Mobile.Deleted )
return false;
if ( ProcessTarget() )
return true;
else
return base.Think();
}
public virtual bool SmartAI
{
get{ return ( m_Mobile is BaseVendor || m_Mobile is BaseEscortable ); }
}
private const double HealChance = 0.10; // 10% chance to heal at gm magery
private const double TeleportChance = 0.05; // 5% chance to teleport at gm magery
private const double DispelChance = 0.75; // 75% chance to dispel at gm magery
public virtual double ScaleByMagery( double v )
{
return m_Mobile.Skills[SkillName.Magery].Value * v * 0.01;
}
public override bool DoActionWander()
{
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I am going to attack {0}", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
m_NextCastTime = DateTime.Now;
}
else if ( SmartAI && m_Mobile.Mana < m_Mobile.ManaMax )
{
m_Mobile.DebugSay( "I am going to meditate" );
m_Mobile.UseSkill( SkillName.Meditation );
}
else
{
m_Mobile.DebugSay( "I am wandering" );
m_Mobile.Warmode = false;
base.DoActionWander();
if ( !m_Mobile.Controlled )
{
Spell spell = CheckCastHealingSpell();
if ( spell != null )
spell.Cast();
}
}
return true;
}
private Spell CheckCastHealingSpell()
{
// If I'm poisoned, always attempt to cure.
if ( m_Mobile.Poisoned )
return new CureSpell( m_Mobile, null );
// Summoned creatures never heal themselves.
if ( m_Mobile.Summoned )
return null;
if ( m_Mobile.Controlled )
{
if ( DateTime.Now < m_NextHealTime )
return null;
}
if ( !SmartAI )
{
if ( ScaleByMagery( HealChance ) < Utility.RandomDouble() )
return null;
}
else
{
if ( Utility.Random( 0, 4 + (m_Mobile.Hits == 0 ? m_Mobile.HitsMax : (m_Mobile.HitsMax / m_Mobile.Hits)) ) < 3 )
return null;
}
Spell spell = null;
if ( m_Mobile.Hits < (m_Mobile.HitsMax - 50) )
{
spell = new GreaterHealSpell( m_Mobile, null );
if ( spell == null )
spell = new HealSpell( m_Mobile, null );
}
else if ( m_Mobile.Hits < (m_Mobile.HitsMax - 10) )
spell = new HealSpell( m_Mobile, null );
double delay;
if ( m_Mobile.Int >= 500 )
delay = Utility.RandomMinMax( 7, 10 );
else
delay = Math.Sqrt( 600 - m_Mobile.Int );
m_NextHealTime = DateTime.Now + TimeSpan.FromSeconds( delay );
return spell;
}
public void RunTo( Mobile m )
{
if ( !SmartAI )
{
if ( !MoveTo( m, true, m_Mobile.RangeFight ) )
OnFailedMove();
return;
}
if ( m.Paralyzed || m.Frozen )
{
if ( m_Mobile.InRange( m, 1 ) )
RunFrom( m );
else if ( !m_Mobile.InRange( m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2 ) && !MoveTo( m, true, 1 ) )
OnFailedMove();
}
else
{
if ( !m_Mobile.InRange( m, m_Mobile.RangeFight ) )
{
if ( !MoveTo( m, true, 1 ) )
OnFailedMove();
}
else if ( m_Mobile.InRange( m, m_Mobile.RangeFight - 1 ) )
{
RunFrom( m );
}
}
}
public void RunFrom( Mobile m )
{
Run( (m_Mobile.GetDirectionTo( m ) - 4) & Direction.Mask );
}
public void OnFailedMove()
{
if ( !m_Mobile.DisallowAllMoves && (SmartAI ? Utility.Random( 4 ) == 0 : ScaleByMagery( TeleportChance ) > Utility.RandomDouble()) )
{
if ( m_Mobile.Target != null )
m_Mobile.Target.Cancel( m_Mobile, TargetCancelType.Canceled );
new TeleportSpell( m_Mobile, null ).Cast();
m_Mobile.DebugSay( "I am stuck, I'm going to try teleporting away" );
}
else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
m_Mobile.DebugSay( "I am stuck" );
}
}
public void Run( Direction d )
{
if ( (m_Mobile.Spell != null && m_Mobile.Spell.IsCasting) || m_Mobile.Paralyzed || m_Mobile.Frozen || m_Mobile.DisallowAllMoves )
return;
m_Mobile.Direction = d | Direction.Running;
if ( !DoMove( m_Mobile.Direction, true ) )
OnFailedMove();
}
public virtual Spell GetRandomDamageSpell()
{
int maxCircle = (int)((m_Mobile.Skills[SkillName.Magery].Value + 20.0) / (100.0 / 7.0));
if ( maxCircle < 1 )
maxCircle = 1;
switch ( Utility.Random( maxCircle*2 ) )
{
case 0: case 1: return new MagicArrowSpell( m_Mobile, null );
case 2: case 3: return new HarmSpell( m_Mobile, null );
case 4: case 5: return new FireballSpell( m_Mobile, null );
case 6: case 7: return new LightningSpell( m_Mobile, null );
case 8: case 9: return new MindBlastSpell( m_Mobile, null );
case 10: return new EnergyBoltSpell( m_Mobile, null );
case 11: return new ExplosionSpell( m_Mobile, null );
default: return new FlameStrikeSpell( m_Mobile, null );
}
}
public virtual Spell GetRandomCurseSpell()
{
if ( Utility.RandomBool() )
{
if ( m_Mobile.Skills[SkillName.Magery].Value >= 40.0 )
return new CurseSpell( m_Mobile, null );
}
switch ( Utility.Random( 3 ) )
{
default:
case 0: return new WeakenSpell( m_Mobile, null );
case 1: return new ClumsySpell( m_Mobile, null );
case 2: return new FeeblemindSpell( m_Mobile, null );
}
}
public virtual Spell GetRandomManaDrainSpell()
{
if ( Utility.RandomBool() )
{
if ( m_Mobile.Skills[SkillName.Magery].Value >= 80.0 )
return new ManaVampireSpell( m_Mobile, null );
}
return new ManaDrainSpell( m_Mobile, null );
}
public virtual Spell DoDispel( Mobile toDispel )
{
if ( !SmartAI )
{
if ( ScaleByMagery( DispelChance ) > Utility.RandomDouble() )
return new DispelSpell( m_Mobile, null );
return ChooseSpell( toDispel );
}
Spell spell = CheckCastHealingSpell();
if ( spell == null )
{
if ( !m_Mobile.DisallowAllMoves && Utility.Random( (int)m_Mobile.GetDistanceToSqrt( toDispel ) ) == 0 )
spell = new TeleportSpell( m_Mobile, null );
else if ( Utility.Random( 3 ) == 0 && !m_Mobile.InRange( toDispel, 3 ) && !toDispel.Paralyzed && !toDispel.Frozen )
spell = new ParalyzeSpell( m_Mobile, null );
else
spell = new DispelSpell( m_Mobile, null );
}
return spell;
}
public virtual Spell ChooseSpell( Mobile c )
{
Spell spell = null;
if ( !SmartAI )
{
spell = CheckCastHealingSpell();
if ( spell != null )
return spell;
switch ( Utility.Random( 16 ) )
{
case 0:
case 1:
case 2: // Poison them
{
m_Mobile.DebugSay( "Attempting to poison" );
if ( !c.Poisoned )
spell = new PoisonSpell( m_Mobile, null );
break;
}
case 3: // Bless ourselves.
{
m_Mobile.DebugSay( "Blessing myself" );
spell = new BlessSpell( m_Mobile, null );
break;
}
case 4:
case 5:
case 6: // Curse them.
{
m_Mobile.DebugSay( "Attempting to curse" );
spell = GetRandomCurseSpell();
break;
}
case 7: // Paralyze them.
{
m_Mobile.DebugSay( "Attempting to paralyze" );
if ( m_Mobile.Skills[SkillName.Magery].Value > 50.0 )
spell = new ParalyzeSpell( m_Mobile, null );
break;
}
case 8: // Drain mana
{
m_Mobile.DebugSay( "Attempting to drain mana" );
spell = GetRandomManaDrainSpell();
break;
}
default: // Damage them.
{
m_Mobile.DebugSay( "Just doing damage" );
spell = GetRandomDamageSpell();
break;
}
}
return spell;
}
spell = CheckCastHealingSpell();
if ( spell != null )
return spell;
switch ( Utility.Random( 3 ) )
{
default:
case 0: // Poison them
{
if ( !c.Poisoned )
spell = new PoisonSpell( m_Mobile, null );
break;
}
case 1: // Deal some damage
{
spell = GetRandomDamageSpell();
break;
}
case 2: // Set up a combo
{
if ( m_Mobile.Mana < 40 && m_Mobile.Mana > 15 )
{
if ( c.Paralyzed && !c.Poisoned )
{
m_Mobile.DebugSay( "I am going to meditate" );
m_Mobile.UseSkill( SkillName.Meditation );
}
else if ( !c.Poisoned )
{
spell = new ParalyzeSpell( m_Mobile, null );
}
}
else if ( m_Mobile.Mana > 60 )
{
if ( Utility.Random( 2 ) == 0 && !c.Paralyzed && !c.Frozen && !c.Poisoned )
{
m_Combo = 0;
spell = new ParalyzeSpell( m_Mobile, null );
}
else
{
m_Combo = 1;
spell = new ExplosionSpell( m_Mobile, null );
}
}
break;
}
}
return spell;
}
protected int m_Combo = -1;
public virtual Spell DoCombo( Mobile c )
{
Spell spell = null;
if ( m_Combo == 0 )
{
spell = new ExplosionSpell( m_Mobile, null );
++m_Combo; // Move to next spell
}
else if ( m_Combo == 1 )
{
spell = new WeakenSpell( m_Mobile, null );
++m_Combo; // Move to next spell
}
else if ( m_Combo == 2 )
{
if ( !c.Poisoned )
spell = new PoisonSpell( m_Mobile, null );
++m_Combo; // Move to next spell
}
if ( m_Combo == 3 && spell == null )
{
switch ( Utility.Random( 3 ) )
{
default:
case 0:
{
if ( c.Int < c.Dex )
spell = new FeeblemindSpell( m_Mobile, null );
else
spell = new ClumsySpell( m_Mobile, null );
++m_Combo; // Move to next spell
break;
}
case 1:
{
spell = new EnergyBoltSpell( m_Mobile, null );
m_Combo = -1; // Reset combo state
break;
}
case 2:
{
spell = new FlameStrikeSpell( m_Mobile, null );
m_Combo = -1; // Reset combo state
break;
}
}
}
else if ( m_Combo == 4 && spell == null )
{
spell = new MindBlastSpell( m_Mobile, null );
m_Combo = -1;
}
return spell;
}
private TimeSpan GetDelay()
{
double del = ScaleByMagery( 3.0 );
double min = 6.0 - (del * 0.75);
double max = 6.0 - (del * 1.25);
return TimeSpan.FromSeconds( min + ((max - min) * Utility.RandomDouble()) );
}
public override bool DoActionCombat()
{
Mobile c = m_Mobile.Combatant;
m_Mobile.Warmode = true;
if ( c == null || c.Deleted || !c.Alive || c.IsDeadBondedPet || !m_Mobile.CanSee( c ) || !m_Mobile.CanBeHarmful( c, false ) || c.Map != m_Mobile.Map )
{
// Our combatant is deleted, dead, hidden, or we cannot hurt them
// Try to find another combatant
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "Something happened to my combatant, so I am going to fight {0}", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = c = m_Mobile.FocusMob;
m_Mobile.FocusMob = null;
}
else
{
m_Mobile.DebugSay( "Something happened to my combatant, and nothing is around. I am on guard." );
Action = ActionType.Guard;
return true;
}
}
if ( !m_Mobile.InLOS( c ) )
{
m_Mobile.DebugSay( "I can't see my target" );
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.DebugSay( "Nobody else is around" );
m_Mobile.Combatant = c = m_Mobile.FocusMob;
m_Mobile.FocusMob = null;
}
}
if ( SmartAI && !m_Mobile.StunReady && m_Mobile.Skills[SkillName.Wrestling].Value >= 80.0 && m_Mobile.Skills[SkillName.Anatomy].Value >= 80.0 )
EventSink.InvokeStunRequest( new StunRequestEventArgs( m_Mobile ) );
if ( !m_Mobile.InRange( c, m_Mobile.RangePerception ) )
{
// They are somewhat far away, can we find something else?
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.Combatant = m_Mobile.FocusMob;
m_Mobile.FocusMob = null;
}
else if ( !m_Mobile.InRange( c, m_Mobile.RangePerception * 3 ) )
{
m_Mobile.Combatant = null;
}
c = m_Mobile.Combatant;
if ( c == null )
{
m_Mobile.DebugSay( "My combatant has fled, so I am on guard" );
Action = ActionType.Guard;
return true;
}
}
if ( !m_Mobile.Controlled && !m_Mobile.Summoned && !m_Mobile.IsParagon )
{
if ( m_Mobile.Hits < m_Mobile.HitsMax * 20/100 )
{
// We are low on health, should we flee?
bool flee = false;
if ( m_Mobile.Hits < c.Hits )
{
// We are more hurt than them
int diff = c.Hits - m_Mobile.Hits;
flee = ( Utility.Random( 0, 100 ) > (10 + diff) ); // (10 + diff)% chance to flee
}
else
{
flee = Utility.Random( 0, 100 ) > 10; // 10% chance to flee
}
if ( flee )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I am going to flee from {0}", c.Name );
Action = ActionType.Flee;
return true;
}
}
}
if ( m_Mobile.Spell == null && DateTime.Now > m_NextCastTime && m_Mobile.InRange( c, 12 ) )
{
// We are ready to cast a spell
Spell spell = null;
Mobile toDispel = FindDispelTarget( true );
if ( m_Mobile.Poisoned ) // Top cast priority is cure
{
m_Mobile.DebugSay( "I am going to cure myself" );
spell = new CureSpell( m_Mobile, null );
}
else if ( toDispel != null ) // Something dispellable is attacking us
{
m_Mobile.DebugSay( "I am going to dispel {0}", toDispel );
spell = DoDispel( toDispel );
}
else if ( SmartAI && m_Combo != -1 ) // We are doing a spell combo
{
spell = DoCombo( c );
}
else if ( SmartAI && (c.Spell is HealSpell || c.Spell is GreaterHealSpell) && !c.Poisoned ) // They have a heal spell out
{
spell = new PoisonSpell( m_Mobile, null );
}
else
{
spell = ChooseSpell( c );
}
// Now we have a spell picked
// Move first before casting
if ( SmartAI && toDispel != null )
{
if ( m_Mobile.InRange( toDispel, 10 ) )
RunFrom( toDispel );
else if ( !m_Mobile.InRange( toDispel, 12 ) )
RunTo( toDispel );
}
else
{
RunTo( c );
}
if ( spell != null )
spell.Cast();
TimeSpan delay;
if ( SmartAI || ( spell is DispelSpell ) )
delay = TimeSpan.FromSeconds( m_Mobile.ActiveSpeed );
else
delay = GetDelay();
m_NextCastTime = DateTime.Now + delay;
}
else if ( m_Mobile.Spell == null || !m_Mobile.Spell.IsCasting )
{
RunTo( c );
}
return true;
}
public override bool DoActionGuard()
{
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.DebugSay( "I am going to attack {0}", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
if ( !m_Mobile.Controlled )
{
ProcessTarget();
Spell spell = CheckCastHealingSpell();
if ( spell != null )
spell.Cast();
}
base.DoActionGuard();
}
return true;
}
public override bool DoActionFlee()
{
Mobile c = m_Mobile.Combatant;
if ( (m_Mobile.Mana > 20 || m_Mobile.Mana == m_Mobile.ManaMax) && m_Mobile.Hits > (m_Mobile.HitsMax / 2) )
{
m_Mobile.DebugSay( "I am stronger now, my guard is up" );
Action = ActionType.Guard;
}
else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I am scared of {0}", m_Mobile.FocusMob.Name );
RunFrom( m_Mobile.FocusMob );
m_Mobile.FocusMob = null;
if ( m_Mobile.Poisoned && Utility.Random( 0, 5 ) == 0 )
new CureSpell( m_Mobile, null ).Cast();
}
else
{
m_Mobile.DebugSay( "Area seems clear, but my guard is up" );
Action = ActionType.Guard;
m_Mobile.Warmode = true;
}
return true;
}
public Mobile FindDispelTarget( bool activeOnly )
{
if ( m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel( m_Mobile ) || m_Mobile.AutoDispel )
return null;
if ( activeOnly )
{
List<AggressorInfo> aggressed = m_Mobile.Aggressed;
List<AggressorInfo> aggressors = m_Mobile.Aggressors;
Mobile active = null;
double activePrio = 0.0;
Mobile comb = m_Mobile.Combatant;
if ( comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && m_Mobile.InRange( comb, 12 ) && CanDispel( comb ) )
{
active = comb;
activePrio = m_Mobile.GetDistanceToSqrt( comb );
if ( activePrio <= 2 )
return active;
}
for ( int i = 0; i < aggressed.Count; ++i )
{
AggressorInfo info = aggressed[i];
Mobile m = info.Defender;
if ( m != comb && m.Combatant == m_Mobile && m_Mobile.InRange( m, 12 ) && CanDispel( m ) )
{
double prio = m_Mobile.GetDistanceToSqrt( m );
if ( active == null || prio < activePrio )
{
active = m;
activePrio = prio;
if ( activePrio <= 2 )
return active;
}
}
}
for ( int i = 0; i < aggressors.Count; ++i )
{
AggressorInfo info = aggressors[i];
Mobile m = info.Attacker;
if ( m != comb && m.Combatant == m_Mobile && m_Mobile.InRange( m, 12 ) && CanDispel( m ) )
{
double prio = m_Mobile.GetDistanceToSqrt( m );
if ( active == null || prio < activePrio )
{
active = m;
activePrio = prio;
if ( activePrio <= 2 )
return active;
}
}
}
return active;
}
else
{
Map map = m_Mobile.Map;
if ( map != null )
{
Mobile active = null, inactive = null;
double actPrio = 0.0, inactPrio = 0.0;
Mobile comb = m_Mobile.Combatant;
if ( comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && CanDispel( comb ) )
{
active = inactive = comb;
actPrio = inactPrio = m_Mobile.GetDistanceToSqrt( comb );
}
foreach ( Mobile m in m_Mobile.GetMobilesInRange( 12 ) )
{
if ( m != m_Mobile && CanDispel( m ) )
{
double prio = m_Mobile.GetDistanceToSqrt( m );
if ( !activeOnly && (inactive == null || prio < inactPrio) )
{
inactive = m;
inactPrio = prio;
}
if ( (m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio) )
{
active = m;
actPrio = prio;
}
}
}
return active != null ? active : inactive;
}
}
return null;
}
public bool CanDispel( Mobile m )
{
return ( m is BaseCreature && ((BaseCreature)m).Summoned && m_Mobile.CanBeHarmful( m, false ) && !((BaseCreature)m).IsAnimatedDead );
}
private static int[] m_Offsets = new int[]
{
-1, -1,
-1, 0,
-1, 1,
0, -1,
0, 1,
1, -1,
1, 0,
1, 1,
-2, -2,
-2, -1,
-2, 0,
-2, 1,
-2, 2,
-1, -2,
-1, 2,
0, -2,
0, 2,
1, -2,
1, 2,
2, -2,
2, -1,
2, 0,
2, 1,
2, 2
};
private bool ProcessTarget()
{
Target targ = m_Mobile.Target;
if ( targ == null )
return false;
bool isDispel = ( targ is DispelSpell.InternalTarget );
bool isParalyze = ( targ is ParalyzeSpell.InternalTarget );
bool isTeleport = ( targ is TeleportSpell.InternalTarget );
bool teleportAway = false;
Mobile toTarget;
if ( isDispel )
{
toTarget = FindDispelTarget( false );
if ( !SmartAI && toTarget != null )
RunTo( toTarget );
else if ( toTarget != null && m_Mobile.InRange( toTarget, 10 ) )
RunFrom( toTarget );
}
else if ( SmartAI && (isParalyze || isTeleport) )
{
toTarget = FindDispelTarget( true );
if ( toTarget == null )
{
toTarget = m_Mobile.Combatant;
if ( toTarget != null )
RunTo( toTarget );
}
else if ( m_Mobile.InRange( toTarget, 10 ) )
{
RunFrom( toTarget );
teleportAway = true;
}
else
{
teleportAway = true;
}
}
else
{
toTarget = m_Mobile.Combatant;
if ( toTarget != null )
RunTo( toTarget );
}
if ( (targ.Flags & TargetFlags.Harmful) != 0 && toTarget != null )
{
if ( (targ.Range == -1 || m_Mobile.InRange( toTarget, targ.Range )) && m_Mobile.CanSee( toTarget ) && m_Mobile.InLOS( toTarget ) )
{
targ.Invoke( m_Mobile, toTarget );
}
else if ( isDispel )
{
targ.Cancel( m_Mobile, TargetCancelType.Canceled );
}
}
else if ( (targ.Flags & TargetFlags.Beneficial) != 0 )
{
targ.Invoke( m_Mobile, m_Mobile );
}
else if ( isTeleport && toTarget != null )
{
Map map = m_Mobile.Map;
if ( map == null )
{
targ.Cancel( m_Mobile, TargetCancelType.Canceled );
return true;
}
int px, py;
if ( teleportAway )
{
int rx = m_Mobile.X - toTarget.X;
int ry = m_Mobile.Y - toTarget.Y;
double d = m_Mobile.GetDistanceToSqrt( toTarget );
px = toTarget.X + (int)(rx * (10 / d));
py = toTarget.Y + (int)(ry * (10 / d));
}
else
{
px = toTarget.X;
py = toTarget.Y;
}
for ( int i = 0; i < m_Offsets.Length; i += 2 )
{
int x = m_Offsets[i], y = m_Offsets[i + 1];
Point3D p = new Point3D( px + x, py + y, 0 );
LandTarget lt = new LandTarget( p, map );
if ( (targ.Range == -1 || m_Mobile.InRange( p, targ.Range )) && m_Mobile.InLOS( lt ) && map.CanSpawnMobile( px + x, py + y, lt.Z ) && !SpellHelper.CheckMulti( p, map ) )
{
targ.Invoke( m_Mobile, lt );
return true;
}
}
int teleRange = targ.Range;
if ( teleRange < 0 )
teleRange = 12;
for ( int i = 0; i < 10; ++i )
{
Point3D randomPoint = new Point3D( m_Mobile.X - teleRange + Utility.Random( teleRange * 2 + 1 ), m_Mobile.Y - teleRange + Utility.Random( teleRange * 2 + 1 ), 0 );
LandTarget lt = new LandTarget( randomPoint, map );
if ( m_Mobile.InLOS( lt ) && map.CanSpawnMobile( lt.X, lt.Y, lt.Z ) && !SpellHelper.CheckMulti( randomPoint, map ) )
{
targ.Invoke( m_Mobile, new LandTarget( randomPoint, map ) );
return true;
}
}
targ.Cancel( m_Mobile, TargetCancelType.Canceled );
}
else
{
targ.Cancel( m_Mobile, TargetCancelType.Canceled );
}
return true;
}
}
}

View file

@ -0,0 +1,183 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
//
// This is a first simple AI
//
//
namespace Server.Mobiles
{
public class MeleeAI : BaseAI
{
public MeleeAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
m_Mobile.DebugSay( "I have no combatant" );
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
Mobile combatant = m_Mobile.Combatant;
if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map || !combatant.Alive || combatant.IsDeadBondedPet )
{
m_Mobile.DebugSay( "My combatant is gone, so my guard is up" );
Action = ActionType.Guard;
return true;
}
if ( !m_Mobile.InRange( combatant, m_Mobile.RangePerception ) )
{
// They are somewhat far away, can we find something else?
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.Combatant = m_Mobile.FocusMob;
m_Mobile.FocusMob = null;
}
else if ( !m_Mobile.InRange( combatant, m_Mobile.RangePerception * 3 ) )
{
m_Mobile.Combatant = null;
}
combatant = m_Mobile.Combatant;
if ( combatant == null )
{
m_Mobile.DebugSay( "My combatant has fled, so I am on guard" );
Action = ActionType.Guard;
return true;
}
}
/*if ( !m_Mobile.InLOS( combatant ) )
{
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.Combatant = combatant = m_Mobile.FocusMob;
m_Mobile.FocusMob = null;
}
}*/
if ( MoveTo( combatant, true, m_Mobile.RangeFight ) )
{
m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant );
}
else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
return true;
}
else if ( m_Mobile.GetDistanceToSqrt( combatant ) > m_Mobile.RangePerception + 1 )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I cannot find {0}, so my guard is up", combatant.Name );
Action = ActionType.Guard;
return true;
}
else
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name );
}
if ( !m_Mobile.Controlled && !m_Mobile.Summoned && !m_Mobile.IsParagon )
{
if ( m_Mobile.Hits < m_Mobile.HitsMax * 20/100 )
{
// We are low on health, should we flee?
bool flee = false;
if ( m_Mobile.Hits < combatant.Hits )
{
// We are more hurt than them
int diff = combatant.Hits - m_Mobile.Hits;
flee = ( Utility.Random( 0, 100 ) < (10 + diff) ); // (10 + diff)% chance to flee
}
else
{
flee = Utility.Random( 0, 100 ) < 10; // 10% chance to flee
}
if ( flee )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I am going to flee from {0}", combatant.Name );
Action = ActionType.Flee;
}
}
}
return true;
}
public override bool DoActionGuard()
{
if ( AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionGuard();
}
return true;
}
public override bool DoActionFlee()
{
if ( m_Mobile.Hits > m_Mobile.HitsMax/2 )
{
m_Mobile.DebugSay( "I am stronger now, so I will continue fighting" );
Action = ActionType.Combat;
}
else
{
m_Mobile.FocusMob = m_Mobile.Combatant;
base.DoActionFlee();
}
return true;
}
}
}

View file

@ -0,0 +1,100 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
/*
* PredatorAI, its an animal that can attack
* Dont flee but dont attack if not hurt or attacked
*
*/
namespace Server.Mobiles
{
public class PredatorAI : BaseAI
{
public PredatorAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
if ( m_Mobile.Combatant != null )
{
m_Mobile.DebugSay( "I am hurt or being attacked, I kill him" );
Action = ActionType.Combat;
}
else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true))
{
m_Mobile.DebugSay( "There is something near, I go away" );
Action = ActionType.Backoff;
}
else
{
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
Mobile combatant = m_Mobile.Combatant;
if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map )
{
m_Mobile.DebugSay( "My combatant is gone, so my guard is up" );
Action = ActionType.Wander;
return true;
}
if ( WalkMobileRange( combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight ) )
{
m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant );
}
else
{
if ( m_Mobile.GetDistanceToSqrt( combatant ) > m_Mobile.RangePerception + 1 )
{
m_Mobile.DebugSay( "I cannot find {0}", combatant.Name );
Action = ActionType.Wander;
return true;
}
else
{
m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name );
}
}
return true;
}
public override bool DoActionBackoff()
{
if ( m_Mobile.IsHurt() || m_Mobile.Combatant != null )
{
Action = ActionType.Combat;
}
else
{
if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false , true))
{
if ( WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2) )
{
m_Mobile.DebugSay( "Well, here I am safe" );
Action = ActionType.Wander;
}
}
else
{
m_Mobile.DebugSay( "I have lost my focus, lets relax" );
Action = ActionType.Wander;
}
}
return true;
}
}
}

View file

@ -0,0 +1,194 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
using Server.Items;
//
// This is a first simple AI
//
//
namespace Server.Mobiles
{
public class ThiefAI : BaseAI
{
public ThiefAI(BaseCreature m) : base (m)
{
}
private Item m_toDisarm;
public override bool DoActionWander()
{
m_Mobile.DebugSay( "I have no combatant" );
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
Mobile combatant = m_Mobile.Combatant;
if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map )
{
m_Mobile.DebugSay( "My combatant is gone, so my guard is up" );
Action = ActionType.Guard;
return true;
}
if ( WalkMobileRange( combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight ) )
{
m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant );
if ( m_toDisarm == null )
m_toDisarm = combatant.FindItemOnLayer( Layer.OneHanded );
if ( m_toDisarm == null )
m_toDisarm = combatant.FindItemOnLayer( Layer.TwoHanded );
if ( m_toDisarm != null && m_toDisarm.IsChildOf( m_Mobile.Backpack ) )
{
m_toDisarm = combatant.FindItemOnLayer( Layer.OneHanded );
if ( m_toDisarm == null )
m_toDisarm = combatant.FindItemOnLayer( Layer.TwoHanded );
}
if ( !m_Mobile.DisarmReady && m_Mobile.Skills[SkillName.Wrestling].Value >= 80.0 && m_Mobile.Skills[SkillName.ArmsLore].Value >= 80.0 && m_toDisarm != null )
EventSink.InvokeDisarmRequest( new DisarmRequestEventArgs( m_Mobile ) );
if ( m_toDisarm != null && m_toDisarm.IsChildOf( combatant.Backpack ) && m_Mobile.NextSkillTime <= DateTime.Now && (m_toDisarm.LootType != LootType.Blessed && m_toDisarm.LootType != LootType.Newbied) )
{
m_Mobile.DebugSay( "Trying to steal from combatant." );
m_Mobile.UseSkill( SkillName.Stealing );
if ( m_Mobile.Target != null )
m_Mobile.Target.Invoke( m_Mobile, m_toDisarm );
}
else if ( m_toDisarm == null && m_Mobile.NextSkillTime <= DateTime.Now )
{
Container cpack = combatant.Backpack;
if ( cpack != null )
{
Item steala = cpack.FindItemByType( typeof ( Bandage ) );
if ( steala != null )
{
m_Mobile.DebugSay( "Trying to steal from combatant." );
m_Mobile.UseSkill( SkillName.Stealing );
if ( m_Mobile.Target != null )
m_Mobile.Target.Invoke( m_Mobile, steala );
}
Item stealb = cpack.FindItemByType( typeof ( Nightshade ) );
if ( stealb != null )
{
m_Mobile.DebugSay( "Trying to steal from combatant." );
m_Mobile.UseSkill( SkillName.Stealing );
if ( m_Mobile.Target != null )
m_Mobile.Target.Invoke( m_Mobile, stealb );
}
Item stealc = cpack.FindItemByType( typeof ( BlackPearl ) );
if ( stealc != null )
{
m_Mobile.DebugSay( "Trying to steal from combatant." );
m_Mobile.UseSkill( SkillName.Stealing );
if ( m_Mobile.Target != null )
m_Mobile.Target.Invoke( m_Mobile, stealc );
}
Item steald = cpack.FindItemByType( typeof ( MandrakeRoot ) );
if ( steald != null )
{
m_Mobile.DebugSay( "Trying to steal from combatant." );
m_Mobile.UseSkill( SkillName.Stealing );
if ( m_Mobile.Target != null )
m_Mobile.Target.Invoke( m_Mobile, steald );
}
else if ( steala == null && stealb == null && stealc == null && steald == null )
{
m_Mobile.DebugSay( "I am going to flee from {0}", combatant.Name );
Action = ActionType.Flee;
}
}
}
}
else
{
m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name );
}
if ( m_Mobile.Hits < m_Mobile.HitsMax * 20/100 && !m_Mobile.IsParagon )
{
// We are low on health, should we flee?
bool flee = false;
if ( m_Mobile.Hits < combatant.Hits )
{
// We are more hurt than them
int diff = combatant.Hits - m_Mobile.Hits;
flee = ( Utility.Random( 0, 100 ) > (10 + diff) ); // (10 + diff)% chance to flee
}
else
{
flee = Utility.Random( 0, 100 ) > 10; // 10% chance to flee
}
if ( flee )
{
m_Mobile.DebugSay( "I am going to flee from {0}", combatant.Name );
Action = ActionType.Flee;
}
}
return true;
}
public override bool DoActionGuard()
{
if ( AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionGuard();
}
return true;
}
public override bool DoActionFlee()
{
if ( m_Mobile.Hits > m_Mobile.HitsMax/2 )
{
m_Mobile.DebugSay( "I am stronger now, so I will continue fighting" );
Action = ActionType.Combat;
}
else
{
m_Mobile.FocusMob = m_Mobile.Combatant;
base.DoActionFlee();
}
return true;
}
}
}

View file

@ -0,0 +1,149 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
//
// This is a first simple AI
//
//
namespace Server.Mobiles
{
public class VendorAI : BaseAI
{
public VendorAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
m_Mobile.DebugSay( "I'm fine" );
if ( m_Mobile.Combatant != null )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} is attacking me", m_Mobile.Combatant.Name );
m_Mobile.Say( Utility.RandomList( 1005305, 501603 ) );
Action = ActionType.Flee;
}
else
{
if ( m_Mobile.FocusMob != null )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} has talked to me", m_Mobile.FocusMob.Name );
Action = ActionType.Interact;
}
else
{
m_Mobile.Warmode = false;
base.DoActionWander();
}
}
return true;
}
public override bool DoActionInteract()
{
Mobile customer = m_Mobile.FocusMob;
if ( m_Mobile.Combatant != null )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} is attacking me", m_Mobile.Combatant.Name );
m_Mobile.Say( Utility.RandomList( 1005305, 501603 ) );
Action = ActionType.Flee;
return true;
}
if ( customer == null || customer.Deleted || customer.Map != m_Mobile.Map )
{
m_Mobile.DebugSay( "My customer have disapeared" );
m_Mobile.FocusMob = null;
Action = ActionType.Wander;
}
else
{
if ( customer.InRange( m_Mobile, m_Mobile.RangeFight ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I am with {0}", customer.Name );
m_Mobile.Direction = m_Mobile.GetDirectionTo( customer );
}
else
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} is gone", customer.Name );
m_Mobile.FocusMob = null;
Action = ActionType.Wander;
}
}
return true;
}
public override bool DoActionGuard()
{
m_Mobile.FocusMob = m_Mobile.Combatant;
return base.DoActionGuard();
}
public override bool HandlesOnSpeech( Mobile from )
{
if ( from.InRange( m_Mobile, 4 ) )
return true;
return base.HandlesOnSpeech( from );
}
// Temporary
public override void OnSpeech( SpeechEventArgs e )
{
base.OnSpeech( e );
Mobile from = e.Mobile;
if ( m_Mobile is BaseVendor && from.InRange( m_Mobile, Core.AOS ? 1 : 4 ) && !e.Handled )
{
if ( e.HasKeyword( 0x14D ) ) // *vendor sell*
{
e.Handled = true;
((BaseVendor)m_Mobile).VendorSell( from );
m_Mobile.FocusMob = from;
}
else if ( e.HasKeyword( 0x3C ) )
{
e.Handled = true;
((BaseVendor)m_Mobile).VendorBuy( from );
m_Mobile.FocusMob = from;
}
else if ( WasNamed( e.Speech ) )
{
e.Handled = true;
if ( e.HasKeyword( 0x177 ) ) // *sell*
((BaseVendor)m_Mobile).VendorSell( from );
else if ( e.HasKeyword( 0x171 ) ) // *buy*
((BaseVendor)m_Mobile).VendorBuy( from );
m_Mobile.FocusMob = from;
}
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,152 @@
using System;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
namespace Server.Mobiles
{
/// <summary>
/// This is a test creature
/// You can set its value in game
/// It die after 5 minutes, so your test server stay clean
/// Create a macro to help your creation "[add Dummy 1 15 7 -1 0.5 2"
///
/// A iTeam of negative will set a faction at random
///
/// Say Kill if you want them to die
///
/// </summary>
public class Dummy : BaseCreature
{
public Timer m_Timer;
[Constructable]
public Dummy(AIType iAI, FightMode iFightMode, int iRangePerception, int iRangeFight, double dActiveSpeed, double dPassiveSpeed) : base(iAI, iFightMode, iRangePerception, iRangeFight, dActiveSpeed, dPassiveSpeed)
{
this.Body = 400 + Utility.Random(2);
this.Hue = Utility.RandomSkinHue();
this.Skills[SkillName.DetectHidden].Base = 100;
this.Skills[SkillName.MagicResist].Base = 120;
Team = Utility.Random(3);
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
Utility.AssignRandomHair( this, iHue );
LeatherGloves glv = new LeatherGloves();
glv.Hue = iHue;
glv.LootType = LootType.Newbied;
AddItem(glv);
Container pack = new Backpack();
pack.Movable = false;
AddItem( pack );
m_Timer = new AutokillTimer(this);
m_Timer.Start();
}
public Dummy( Serial serial ) : base( serial )
{
m_Timer = new AutokillTimer(this);
m_Timer.Start();
}
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 override bool HandlesOnSpeech( Mobile from )
{
if ( from.AccessLevel >= AccessLevel.GameMaster )
return true;
return base.HandlesOnSpeech( from );
}
public override void OnSpeech( SpeechEventArgs e )
{
base.OnSpeech( e );
if (e.Mobile.AccessLevel >= AccessLevel.GameMaster)
{
if (e.Speech == "kill")
{
m_Timer.Stop();
m_Timer.Delay = TimeSpan.FromSeconds( Utility.Random(1, 5) );
m_Timer.Start();
}
}
}
public override void OnTeamChange()
{
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
Item item = FindItemOnLayer( Layer.OuterTorso );
if ( item != null )
item.Hue = jHue;
item = FindItemOnLayer( Layer.Helm );
if ( item != null )
item.Hue = iHue;
item = FindItemOnLayer( Layer.Gloves );
if ( item != null )
item.Hue = iHue;
item = FindItemOnLayer( Layer.Shoes );
if ( item != null )
item.Hue = iHue;
HairHue = iHue;
item = FindItemOnLayer( Layer.MiddleTorso );
if ( item != null )
item.Hue = iHue;
item = FindItemOnLayer( Layer.OuterLegs );
if ( item != null )
item.Hue = iHue;
}
private class AutokillTimer : Timer
{
private Dummy m_Owner;
public AutokillTimer( Dummy owner ) : base( TimeSpan.FromMinutes(5.0) )
{
m_Owner = owner;
Priority = TimerPriority.FiveSeconds;
}
protected override void OnTick()
{
m_Owner.Kill();
Stop();
}
}
}
}

View file

@ -0,0 +1,814 @@
using System;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
namespace Server.Mobiles
{
/// <summary>
/// This is a test creature
/// You can set its value in game
/// It die after 5 minutes, so your test server stay clean
/// Create a macro to help your creation "[add Dummy 1 15 7 -1 0.5 2"
///
/// A iTeam of negative will set a faction at random
///
/// Say Kill if you want them to die
///
/// </summary>
public class DummyMace : Dummy
{
[Constructable]
public DummyMace() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6)
{
// A Dummy Macer
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
// Skills and Stats
this.InitStats( 125, 125, 90 );
this.Skills[SkillName.Macing].Base = 120;
this.Skills[SkillName.Anatomy].Base = 120;
this.Skills[SkillName.Healing].Base = 120;
this.Skills[SkillName.Tactics].Base = 120;
// Name
this.Name = "Macer";
// Equip
WarHammer war = new WarHammer();
war.Movable = true;
war.Crafter = this;
war.Quality = WeaponQuality.Regular;
AddItem( war );
Boots bts = new Boots();
bts.Hue = iHue;
AddItem( bts );
ChainChest cht = new ChainChest();
cht.Movable = false;
cht.LootType = LootType.Newbied;
cht.Crafter = this;
cht.Quality = ArmorQuality.Regular;
AddItem( cht );
ChainLegs chl = new ChainLegs();
chl.Movable = false;
chl.LootType = LootType.Newbied;
chl.Crafter = this;
chl.Quality = ArmorQuality.Regular;
AddItem( chl );
PlateArms pla = new PlateArms();
pla.Movable = false;
pla.LootType = LootType.Newbied;
pla.Crafter = this;
pla.Quality = ArmorQuality.Regular;
AddItem( pla );
Bandage band = new Bandage( 50 );
AddToBackpack( band );
}
public DummyMace( 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 DummyFence : Dummy
{
[Constructable]
public DummyFence() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6)
{
// A Dummy Fencer
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
// Skills and Stats
this.InitStats( 125, 125, 90 );
this.Skills[SkillName.Fencing].Base = 120;
this.Skills[SkillName.Anatomy].Base = 120;
this.Skills[SkillName.Healing].Base = 120;
this.Skills[SkillName.Tactics].Base = 120;
// Name
this.Name = "Fencer";
// Equip
Spear ssp = new Spear();
ssp.Movable = true;
ssp.Crafter = this;
ssp.Quality = WeaponQuality.Regular;
AddItem( ssp );
Boots snd = new Boots();
snd.Hue = iHue;
snd.LootType = LootType.Newbied;
AddItem( snd );
ChainChest cht = new ChainChest();
cht.Movable = false;
cht.LootType = LootType.Newbied;
cht.Crafter = this;
cht.Quality = ArmorQuality.Regular;
AddItem( cht );
ChainLegs chl = new ChainLegs();
chl.Movable = false;
chl.LootType = LootType.Newbied;
chl.Crafter = this;
chl.Quality = ArmorQuality.Regular;
AddItem( chl );
PlateArms pla = new PlateArms();
pla.Movable = false;
pla.LootType = LootType.Newbied;
pla.Crafter = this;
pla.Quality = ArmorQuality.Regular;
AddItem( pla );
Bandage band = new Bandage( 50 );
AddToBackpack( band );
}
public DummyFence( 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 DummySword : Dummy
{
[Constructable]
public DummySword() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6)
{
// A Dummy Swordsman
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
// Skills and Stats
this.InitStats( 125, 125, 90 );
this.Skills[SkillName.Swords].Base = 120;
this.Skills[SkillName.Anatomy].Base = 120;
this.Skills[SkillName.Healing].Base = 120;
this.Skills[SkillName.Tactics].Base = 120;
this.Skills[SkillName.Parry].Base = 120;
// Name
this.Name = "Swordsman";
// Equip
Katana kat = new Katana();
kat.Crafter = this;
kat.Movable = true;
kat.Quality = WeaponQuality.Regular;
AddItem( kat );
Boots bts = new Boots();
bts.Hue = iHue;
AddItem( bts );
ChainChest cht = new ChainChest();
cht.Movable = false;
cht.LootType = LootType.Newbied;
cht.Crafter = this;
cht.Quality = ArmorQuality.Regular;
AddItem( cht );
ChainLegs chl = new ChainLegs();
chl.Movable = false;
chl.LootType = LootType.Newbied;
chl.Crafter = this;
chl.Quality = ArmorQuality.Regular;
AddItem( chl );
PlateArms pla = new PlateArms();
pla.Movable = false;
pla.LootType = LootType.Newbied;
pla.Crafter = this;
pla.Quality = ArmorQuality.Regular;
AddItem( pla );
Bandage band = new Bandage( 50 );
AddToBackpack( band );
}
public DummySword( 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 DummyNox : Dummy
{
[Constructable]
public DummyNox() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6)
{
// A Dummy Nox or Pure Mage
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
// Skills and Stats
this.InitStats( 90, 90, 125 );
this.Skills[SkillName.Magery].Base = 120;
this.Skills[SkillName.EvalInt].Base = 120;
this.Skills[SkillName.Inscribe].Base = 100;
this.Skills[SkillName.Wrestling].Base = 120;
this.Skills[SkillName.Meditation].Base = 120;
this.Skills[SkillName.Poisoning].Base = 100;
// Name
this.Name = "Nox Mage";
// Equip
Spellbook book = new Spellbook();
book.Movable = false;
book.LootType = LootType.Newbied;
book.Content =0xFFFFFFFFFFFFFFFF;
AddItem( book );
Kilt kilt = new Kilt();
kilt.Hue = jHue;
AddItem( kilt );
Sandals snd = new Sandals();
snd.Hue = iHue;
snd.LootType = LootType.Newbied;
AddItem( snd );
SkullCap skc = new SkullCap();
skc.Hue = iHue;
AddItem( skc );
// Spells
AddSpellAttack( typeof(Spells.First.MagicArrowSpell) );
AddSpellAttack( typeof(Spells.First.WeakenSpell) );
AddSpellAttack( typeof(Spells.Third.FireballSpell) );
AddSpellDefense( typeof(Spells.Third.WallOfStoneSpell) );
AddSpellDefense( typeof(Spells.First.HealSpell) );
}
public DummyNox( 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 DummyStun : Dummy
{
[Constructable]
public DummyStun() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6)
{
// A Dummy Stun Mage
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
// Skills and Stats
this.InitStats( 90, 90, 125 );
this.Skills[SkillName.Magery].Base = 100;
this.Skills[SkillName.EvalInt].Base = 120;
this.Skills[SkillName.Anatomy].Base = 80;
this.Skills[SkillName.Wrestling].Base = 80;
this.Skills[SkillName.Meditation].Base = 100;
this.Skills[SkillName.Poisoning].Base = 100;
// Name
this.Name = "Stun Mage";
// Equip
Spellbook book = new Spellbook();
book.Movable = false;
book.LootType = LootType.Newbied;
book.Content =0xFFFFFFFFFFFFFFFF;
AddItem( book );
LeatherArms lea = new LeatherArms();
lea.Movable = false;
lea.LootType = LootType.Newbied;
lea.Crafter = this;
lea.Quality = ArmorQuality.Regular;
AddItem( lea );
LeatherChest lec = new LeatherChest();
lec.Movable = false;
lec.LootType = LootType.Newbied;
lec.Crafter = this;
lec.Quality = ArmorQuality.Regular;
AddItem( lec );
LeatherGorget leg = new LeatherGorget();
leg.Movable = false;
leg.LootType = LootType.Newbied;
leg.Crafter = this;
leg.Quality = ArmorQuality.Regular;
AddItem( leg );
LeatherLegs lel = new LeatherLegs();
lel.Movable = false;
lel.LootType = LootType.Newbied;
lel.Crafter = this;
lel.Quality = ArmorQuality.Regular;
AddItem( lel );
Boots bts = new Boots();
bts.Hue = iHue;
AddItem( bts );
Cap cap = new Cap();
cap.Hue = iHue;
AddItem( cap );
// Spells
AddSpellAttack( typeof(Spells.First.MagicArrowSpell) );
AddSpellAttack( typeof(Spells.First.WeakenSpell) );
AddSpellAttack( typeof(Spells.Third.FireballSpell) );
AddSpellDefense( typeof(Spells.Third.WallOfStoneSpell) );
AddSpellDefense( typeof(Spells.First.HealSpell) );
}
public DummyStun( 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 DummySuper : Dummy
{
[Constructable]
public DummySuper() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6)
{
// A Dummy Super Mage
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
// Skills and Stats
this.InitStats( 125, 125, 125 );
this.Skills[SkillName.Magery].Base = 120;
this.Skills[SkillName.EvalInt].Base = 120;
this.Skills[SkillName.Anatomy].Base = 120;
this.Skills[SkillName.Wrestling].Base = 120;
this.Skills[SkillName.Meditation].Base = 120;
this.Skills[SkillName.Poisoning].Base = 100;
this.Skills[SkillName.Inscribe].Base = 100;
// Name
this.Name = "Super Mage";
// Equip
Spellbook book = new Spellbook();
book.Movable = false;
book.LootType = LootType.Newbied;
book.Content =0xFFFFFFFFFFFFFFFF;
AddItem( book );
LeatherArms lea = new LeatherArms();
lea.Movable = false;
lea.LootType = LootType.Newbied;
lea.Crafter = this;
lea.Quality = ArmorQuality.Regular;
AddItem( lea );
LeatherChest lec = new LeatherChest();
lec.Movable = false;
lec.LootType = LootType.Newbied;
lec.Crafter = this;
lec.Quality = ArmorQuality.Regular;
AddItem( lec );
LeatherGorget leg = new LeatherGorget();
leg.Movable = false;
leg.LootType = LootType.Newbied;
leg.Crafter = this;
leg.Quality = ArmorQuality.Regular;
AddItem( leg );
LeatherLegs lel = new LeatherLegs();
lel.Movable = false;
lel.LootType = LootType.Newbied;
lel.Crafter = this;
lel.Quality = ArmorQuality.Regular;
AddItem( lel );
Sandals snd = new Sandals();
snd.Hue = iHue;
snd.LootType = LootType.Newbied;
AddItem( snd );
JesterHat jhat = new JesterHat();
jhat.Hue = iHue;
AddItem( jhat );
Doublet dblt = new Doublet();
dblt.Hue = iHue;
AddItem( dblt );
// Spells
AddSpellAttack( typeof(Spells.First.MagicArrowSpell) );
AddSpellAttack( typeof(Spells.First.WeakenSpell) );
AddSpellAttack( typeof(Spells.Third.FireballSpell) );
AddSpellDefense( typeof(Spells.Third.WallOfStoneSpell) );
AddSpellDefense( typeof(Spells.First.HealSpell) );
}
public DummySuper( 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 DummyHealer : Dummy
{
[Constructable]
public DummyHealer() : base(AIType.AI_Healer, FightMode.Closest, 15, 1, 0.2, 0.6)
{
// A Dummy Healer Mage
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
// Skills and Stats
this.InitStats( 125, 125, 125 );
this.Skills[SkillName.Magery].Base = 120;
this.Skills[SkillName.EvalInt].Base = 120;
this.Skills[SkillName.Anatomy].Base = 120;
this.Skills[SkillName.Wrestling].Base = 120;
this.Skills[SkillName.Meditation].Base = 120;
this.Skills[SkillName.Healing].Base = 100;
// Name
this.Name = "Healer";
// Equip
Spellbook book = new Spellbook();
book.Movable = false;
book.LootType = LootType.Newbied;
book.Content =0xFFFFFFFFFFFFFFFF;
AddItem( book );
LeatherArms lea = new LeatherArms();
lea.Movable = false;
lea.LootType = LootType.Newbied;
lea.Crafter = this;
lea.Quality = ArmorQuality.Regular;
AddItem( lea );
LeatherChest lec = new LeatherChest();
lec.Movable = false;
lec.LootType = LootType.Newbied;
lec.Crafter = this;
lec.Quality = ArmorQuality.Regular;
AddItem( lec );
LeatherGorget leg = new LeatherGorget();
leg.Movable = false;
leg.LootType = LootType.Newbied;
leg.Crafter = this;
leg.Quality = ArmorQuality.Regular;
AddItem( leg );
LeatherLegs lel = new LeatherLegs();
lel.Movable = false;
lel.LootType = LootType.Newbied;
lel.Crafter = this;
lel.Quality = ArmorQuality.Regular;
AddItem( lel );
Sandals snd = new Sandals();
snd.Hue = iHue;
snd.LootType = LootType.Newbied;
AddItem( snd );
Cap cap = new Cap();
cap.Hue = iHue;
AddItem( cap );
Robe robe = new Robe();
robe.Hue = iHue;
AddItem( robe );
}
public DummyHealer( 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 DummyAssassin : Dummy
{
[Constructable]
public DummyAssassin() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6)
{
// A Dummy Hybrid Assassin
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
// Skills and Stats
this.InitStats( 105, 105, 105 );
this.Skills[SkillName.Magery].Base = 120;
this.Skills[SkillName.EvalInt].Base = 120;
this.Skills[SkillName.Swords].Base = 120;
this.Skills[SkillName.Tactics].Base = 120;
this.Skills[SkillName.Meditation].Base = 120;
this.Skills[SkillName.Poisoning].Base = 100;
// Name
this.Name = "Hybrid Assassin";
// Equip
Spellbook book = new Spellbook();
book.Movable = false;
book.LootType = LootType.Newbied;
book.Content =0xFFFFFFFFFFFFFFFF;
AddToBackpack( book );
Katana kat = new Katana();
kat.Movable = false;
kat.LootType = LootType.Newbied;
kat.Crafter = this;
kat.Poison = Poison.Deadly;
kat.PoisonCharges = 12;
kat.Quality = WeaponQuality.Regular;
AddToBackpack( kat );
LeatherArms lea = new LeatherArms();
lea.Movable = false;
lea.LootType = LootType.Newbied;
lea.Crafter = this;
lea.Quality = ArmorQuality.Regular;
AddItem( lea );
LeatherChest lec = new LeatherChest();
lec.Movable = false;
lec.LootType = LootType.Newbied;
lec.Crafter = this;
lec.Quality = ArmorQuality.Regular;
AddItem( lec );
LeatherGorget leg = new LeatherGorget();
leg.Movable = false;
leg.LootType = LootType.Newbied;
leg.Crafter = this;
leg.Quality = ArmorQuality.Regular;
AddItem( leg );
LeatherLegs lel = new LeatherLegs();
lel.Movable = false;
lel.LootType = LootType.Newbied;
lel.Crafter = this;
lel.Quality = ArmorQuality.Regular;
AddItem( lel );
Sandals snd = new Sandals();
snd.Hue = iHue;
snd.LootType = LootType.Newbied;
AddItem( snd );
Cap cap = new Cap();
cap.Hue = iHue;
AddItem( cap );
Robe robe = new Robe();
robe.Hue = iHue;
AddItem( robe );
DeadlyPoisonPotion pota = new DeadlyPoisonPotion();
pota.LootType = LootType.Newbied;
AddToBackpack( pota );
DeadlyPoisonPotion potb = new DeadlyPoisonPotion();
potb.LootType = LootType.Newbied;
AddToBackpack( potb );
DeadlyPoisonPotion potc = new DeadlyPoisonPotion();
potc.LootType = LootType.Newbied;
AddToBackpack( potc );
DeadlyPoisonPotion potd = new DeadlyPoisonPotion();
potd.LootType = LootType.Newbied;
AddToBackpack( potd );
Bandage band = new Bandage( 50 );
AddToBackpack( band );
}
public DummyAssassin( 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 DummyTheif : Dummy
{
[Constructable]
public DummyTheif() : base(AIType.AI_Thief, FightMode.Closest, 15, 1, 0.2, 0.6)
{
// A Dummy Hybrid Theif
int iHue = 20 + Team * 40;
int jHue = 25 + Team * 40;
// Skills and Stats
this.InitStats( 105, 105, 105 );
this.Skills[SkillName.Healing].Base = 120;
this.Skills[SkillName.Anatomy].Base = 120;
this.Skills[SkillName.Stealing].Base = 120;
this.Skills[SkillName.ArmsLore].Base = 100;
this.Skills[SkillName.Meditation].Base = 120;
this.Skills[SkillName.Wrestling].Base = 120;
// Name
this.Name = "Hybrid Theif";
// Equip
Spellbook book = new Spellbook();
book.Movable = false;
book.LootType = LootType.Newbied;
book.Content =0xFFFFFFFFFFFFFFFF;
AddItem( book );
LeatherArms lea = new LeatherArms();
lea.Movable = false;
lea.LootType = LootType.Newbied;
lea.Crafter = this;
lea.Quality = ArmorQuality.Regular;
AddItem( lea );
LeatherChest lec = new LeatherChest();
lec.Movable = false;
lec.LootType = LootType.Newbied;
lec.Crafter = this;
lec.Quality = ArmorQuality.Regular;
AddItem( lec );
LeatherGorget leg = new LeatherGorget();
leg.Movable = false;
leg.LootType = LootType.Newbied;
leg.Crafter = this;
leg.Quality = ArmorQuality.Regular;
AddItem( leg );
LeatherLegs lel = new LeatherLegs();
lel.Movable = false;
lel.LootType = LootType.Newbied;
lel.Crafter = this;
lel.Quality = ArmorQuality.Regular;
AddItem( lel );
Sandals snd = new Sandals();
snd.Hue = iHue;
snd.LootType = LootType.Newbied;
AddItem( snd );
Cap cap = new Cap();
cap.Hue = iHue;
AddItem( cap );
Robe robe = new Robe();
robe.Hue = iHue;
AddItem( robe );
Bandage band = new Bandage( 50 );
AddToBackpack( band );
}
public DummyTheif( 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();
}
}
}

View file

@ -0,0 +1,140 @@
using System;
using Server;
using Server.Mobiles;
namespace Server
{
public class OppositionGroup
{
private Type[][] m_Types;
public OppositionGroup( Type[][] types )
{
m_Types = types;
}
public bool IsEnemy( object from, object target )
{
int fromGroup = IndexOf( from );
int targGroup = IndexOf( target );
return ( fromGroup != -1 && targGroup != -1 && fromGroup != targGroup );
}
public int IndexOf( object obj )
{
if ( obj == null )
return -1;
Type type = obj.GetType();
for ( int i = 0; i < m_Types.Length; ++i )
{
Type[] group = m_Types[i];
bool contains = false;
for ( int j = 0; !contains && j < group.Length; ++j )
contains = ( type == group[j] );
if ( contains )
return i;
}
return -1;
}
private static OppositionGroup m_TerathansAndOphidians = new OppositionGroup( new Type[][]
{
new Type[]
{
typeof( TerathanAvenger ),
typeof( TerathanDrone ),
typeof( TerathanMatriarch ),
typeof( TerathanWarrior )
},
new Type[]
{
typeof( OphidianArchmage ),
typeof( OphidianKnight ),
typeof( OphidianMage ),
typeof( OphidianMatriarch ),
typeof( OphidianWarrior )
}
} );
public static OppositionGroup TerathansAndOphidians
{
get{ return m_TerathansAndOphidians; }
}
private static OppositionGroup m_SavagesAndOrcs = new OppositionGroup( new Type[][]
{
new Type[]
{
typeof( Orc ),
typeof( OrcBomber ),
typeof( OrcBrute ),
typeof( OrcCaptain ),
typeof( OrcishLord ),
typeof( OrcishMage ),
typeof( SpawnedOrcishLord )
},
new Type[]
{
typeof( Savage ),
typeof( SavageRider ),
typeof( SavageRidgeback ),
typeof( SavageShaman )
}
} );
public static OppositionGroup SavagesAndOrcs
{
get{ return m_SavagesAndOrcs; }
}
private static OppositionGroup m_FeyAndUndead = new OppositionGroup( new Type[][]
{
new Type[]
{
typeof( Centaur ),
typeof( EtherealWarrior ),
typeof( Kirin ),
typeof( LordOaks ),
typeof( Pixie ),
typeof( Silvani ),
typeof( Unicorn ),
typeof( Wisp ),
typeof( Treefellow )
},
new Type[]
{
typeof( AncientLich ),
typeof( Bogle ),
typeof( LichLord ),
typeof( Shade ),
typeof( Spectre ),
typeof( Wraith ),
typeof( BoneKnight ),
typeof( Ghoul ),
typeof( Mummy ),
typeof( SkeletalKnight ),
typeof( Skeleton ),
typeof( Zombie ),
typeof( ShadowKnight ),
typeof( DarknightCreeper ),
typeof( RevenantLion ),
typeof( LadyOfTheSnow ),
typeof( RottingCorpse ),
typeof( SkeletalDragon ),
typeof( Lich )
}
} );
public static OppositionGroup FeyAndUndead
{
get{ return m_FeyAndUndead; }
}
}
}

View file

@ -0,0 +1,182 @@
using System;
using Server;
using Server.Items;
namespace Server.Mobiles
{
public class Paragon
{
public static double ChestChance = .10; // Chance that a paragon will carry a paragon chest
public static Map[] Maps = new Map[] // Maps that paragons will spawn on
{
Map.Ilshenar
};
public static Type[] Artifacts = new Type[]
{
typeof( GoldBricks ), typeof( PhillipsWoodenSteed ),
typeof( AlchemistsBauble ), typeof( ArcticDeathDealer ),
typeof( BlazeOfDeath ), typeof( BowOfTheJukaKing ),
typeof( BurglarsBandana ), typeof( CavortingClub ),
typeof( EnchantedTitanLegBone ), typeof( GwennosHarp ),
typeof( IolosLute ), typeof( LunaLance ),
typeof( NightsKiss ), typeof( NoxRangersHeavyCrossbow ),
typeof( OrcishVisage ), typeof( PolarBearMask ),
typeof( ShieldOfInvulnerability ), typeof( StaffOfPower ),
typeof( VioletCourage ), typeof( HeartOfTheLion ),
typeof( WrathOfTheDryad ), typeof( PixieSwatter ),
typeof( GlovesOfThePugilist )
};
public static int Hue = 0x501; // Paragon hue
// Buffs
public static double HitsBuff = 5.0;
public static double StrBuff = 1.05;
public static double IntBuff = 1.20;
public static double DexBuff = 1.20;
public static double SkillsBuff = 1.20;
public static double SpeedBuff = 1.20;
public static double FameBuff = 1.40;
public static double KarmaBuff = 1.40;
public static int DamageBuff = 5;
public static void Convert( BaseCreature bc )
{
if ( bc.IsParagon )
return;
bc.Hue = Hue;
if ( bc.HitsMaxSeed >= 0 )
bc.HitsMaxSeed = (int)( bc.HitsMaxSeed * HitsBuff );
bc.RawStr = (int)( bc.RawStr * StrBuff );
bc.RawInt = (int)( bc.RawInt * IntBuff );
bc.RawDex = (int)( bc.RawDex * DexBuff );
bc.Hits = bc.HitsMax;
bc.Mana = bc.ManaMax;
bc.Stam = bc.StamMax;
for( int i = 0; i < bc.Skills.Length; i++ )
{
Skill skill = (Skill)bc.Skills[i];
if ( skill.Base > 0.0 )
skill.Base *= SkillsBuff;
}
bc.PassiveSpeed /= SpeedBuff;
bc.ActiveSpeed /= SpeedBuff;
bc.DamageMin += DamageBuff;
bc.DamageMax += DamageBuff;
if ( bc.Fame > 0 )
bc.Fame = (int)( bc.Fame * FameBuff );
if ( bc.Fame > 32000 )
bc.Fame = 32000;
// TODO: Mana regeneration rate = Sqrt( buffedFame ) / 4
if ( bc.Karma != 0 )
{
bc.Karma = (int)( bc.Karma * KarmaBuff );
if( Math.Abs( bc.Karma ) > 32000 )
bc.Karma = 32000 * Math.Sign( bc.Karma );
}
}
public static void UnConvert( BaseCreature bc )
{
if ( !bc.IsParagon )
return;
bc.Hue = 0;
if ( bc.HitsMaxSeed >= 0 )
bc.HitsMaxSeed = (int)( bc.HitsMaxSeed / HitsBuff );
bc.RawStr = (int)( bc.RawStr / StrBuff );
bc.RawInt = (int)( bc.RawInt / IntBuff );
bc.RawDex = (int)( bc.RawDex / DexBuff );
bc.Hits = bc.HitsMax;
bc.Mana = bc.ManaMax;
bc.Stam = bc.StamMax;
for( int i = 0; i < bc.Skills.Length; i++ )
{
Skill skill = (Skill)bc.Skills[i];
if ( skill.Base > 0.0 )
skill.Base /= SkillsBuff;
}
bc.PassiveSpeed *= SpeedBuff;
bc.ActiveSpeed *= SpeedBuff;
bc.DamageMin -= DamageBuff;
bc.DamageMax -= DamageBuff;
if ( bc.Fame > 0 )
bc.Fame = (int)( bc.Fame / FameBuff );
if ( bc.Karma != 0 )
bc.Karma = (int)( bc.Karma / KarmaBuff );
}
public static bool CheckConvert( BaseCreature bc )
{
return CheckConvert( bc, bc.Location, bc.Map );
}
public static bool CheckConvert( BaseCreature bc, Point3D location, Map m )
{
if ( !Core.AOS )
return false;
if ( Array.IndexOf( Maps, m ) == -1 )
return false;
if ( bc is BaseChampion || bc is Harrower || bc is BaseVendor || bc is BaseEscortable || bc is Clone )
return false;
int fame = bc.Fame;
if ( fame > 32000 )
fame = 32000;
double chance = 1 / Math.Round( 20.0 - ( fame / 3200 ));
return ( chance > Utility.RandomDouble() );
}
public static bool CheckArtifactChance( Mobile m, BaseCreature bc )
{
if ( !Core.AOS )
return false;
double fame = (double)bc.Fame;
if ( fame > 32000 )
fame = 32000;
double chance = 1 / ( Math.Max( 10, 100 * ( 0.83 - Math.Round( Math.Log( Math.Round( fame / 6000, 3 ) + 0.001, 10 ), 3 ) ) ) * ( 100 - Math.Sqrt( m.Luck ) ) / 100.0 );
return chance > Utility.RandomDouble();
}
public static void GiveArtifactTo( Mobile m )
{
Item item = (Item)Activator.CreateInstance( Artifacts[Utility.Random(Artifacts.Length)] );
if ( m.AddToBackpack( item ) )
m.SendMessage( "As a reward for slaying the mighty paragon, an artifact has been placed in your backpack." );
else
m.SendMessage( "As your backpack is full, your reward for destroying the legendary paragon has been placed at your feet." );
}
}
}

View file

@ -0,0 +1,213 @@
using System;
using System.Collections;
using Server;
using Server.Mobiles;
using Server.Factions;
namespace Server
{
public class SpeedInfo
{
// Should we use the new method of speeds?
private static bool Enabled = true;
private double m_ActiveSpeed;
private double m_PassiveSpeed;
private Type[] m_Types;
public double ActiveSpeed
{
get{ return m_ActiveSpeed; }
set{ m_ActiveSpeed = value; }
}
public double PassiveSpeed
{
get{ return m_PassiveSpeed; }
set{ m_PassiveSpeed = value; }
}
public Type[] Types
{
get{ return m_Types; }
set{ m_Types = value; }
}
public SpeedInfo( double activeSpeed, double passiveSpeed, Type[] types )
{
m_ActiveSpeed = activeSpeed;
m_PassiveSpeed = passiveSpeed;
m_Types = types;
}
public static bool Contains( object obj )
{
if ( !Enabled )
return false;
if ( m_Table == null )
LoadTable();
SpeedInfo sp = (SpeedInfo)m_Table[obj.GetType()];
return ( sp != null );
}
public static bool GetSpeeds( object obj, ref double activeSpeed, ref double passiveSpeed )
{
if ( !Enabled )
return false;
if ( m_Table == null )
LoadTable();
SpeedInfo sp = (SpeedInfo)m_Table[obj.GetType()];
if ( sp == null )
return false;
activeSpeed = sp.ActiveSpeed;
passiveSpeed = sp.PassiveSpeed;
return true;
}
private static void LoadTable()
{
m_Table = new Hashtable();
for ( int i = 0; i < m_Speeds.Length; ++i )
{
SpeedInfo info = m_Speeds[i];
Type[] types = info.Types;
for ( int j = 0; j < types.Length; ++j )
m_Table[types[j]] = info;
}
}
private static Hashtable m_Table;
private static SpeedInfo[] m_Speeds = new SpeedInfo[]
{
/* Slow */
new SpeedInfo( 0.3, 0.6, new Type[]
{
typeof( AntLion ), typeof( ArcticOgreLord ), typeof( BogThing ),
typeof( Bogle ), typeof( BoneKnight ), typeof( EarthElemental ),
typeof( Ettin ), typeof( FrostOoze ), typeof( FrostTroll ),
typeof( GazerLarva ), typeof( Ghoul ), typeof( Golem ),
typeof( HeadlessOne ), typeof( Jwilson ), typeof( Mummy ),
typeof( Ogre ), typeof( OgreLord ), typeof( PlagueBeast ),
typeof( Quagmire ), typeof( Rat ), typeof( RottingCorpse ),
typeof( Sewerrat ), typeof( Skeleton ), typeof( Slime ),
typeof( Zombie ), typeof( Walrus ), typeof( RestlessSoul ),
typeof( CrystalElemental ), typeof( DarknightCreeper ), typeof( MoundOfMaggots ),
typeof( Juggernaut ), typeof( Yamandon ), typeof( Serado )
} ),
/* Fast */
new SpeedInfo( 0.2, 0.4, new Type[]
{
typeof( LordOaks ), typeof( Silvani ), typeof( AirElemental ),
typeof( AncientWyrm ), typeof( Balron ), typeof( BladeSpirits ),
typeof( DreadSpider ), typeof( Efreet ), typeof( EtherealWarrior ),
typeof( Lich ), typeof( Nightmare ), typeof( OphidianArchmage ),
typeof( OphidianMage ), typeof( OphidianWarrior ), typeof( OphidianMatriarch ),
typeof( OphidianKnight ), typeof( PoisonElemental ), typeof( Revenant ),
typeof( SandVortex ), typeof( SavageRider ), typeof( SavageShaman ),
typeof( SnowElemental ), typeof( WhiteWyrm ), typeof( Wisp ),
typeof( DemonKnight ), typeof( GiantBlackWidow ), typeof( SummonedAirElemental ),
typeof( LesserHiryu ), typeof( Hiryu ), typeof( LadyOfTheSnow ),
typeof( RaiJu ), typeof( Ronin )
} ),
/* Very Fast */
new SpeedInfo( 0.175, 0.350, new Type[]
{
typeof( Barracoon ), typeof( Mephitis ), typeof( Neira ),
typeof( Rikktor ), typeof( Semidar ), typeof( EnergyVortex ),
typeof( Beetle ), typeof( Pixie ), typeof( SilverSerpent ),
typeof( VorpalBunny ), typeof( FleshRenderer ), typeof( KhaldunRevenant ),
typeof( FactionDragoon ), typeof( FactionKnight ), typeof( FactionPaladin ),
typeof( FactionHenchman ), typeof( FactionMercenary ), typeof( FactionNecromancer ),
typeof( FactionSorceress ), typeof( FactionWizard ), typeof( FactionBerserker ),
typeof( FactionPaladin ), typeof( Leviathan ), typeof( FireBeetle ),
typeof( FanDancer ), typeof( EliteNinja )
} ),
/* Medium */
new SpeedInfo( 0.25, 0.5, new Type[]
{
typeof( ToxicElemental ), typeof( AgapiteElemental ), typeof( Alligator ),
typeof( AncientLich ), typeof( Betrayer ), typeof( Bird ),
typeof( BlackBear ), typeof( BlackSolenInfiltratorQueen ), typeof( BlackSolenInfiltratorWarrior ),
typeof( BlackSolenQueen ), typeof( BlackSolenWarrior ), typeof( BlackSolenWorker ),
typeof( BloodElemental ), typeof( Boar ), typeof( Bogling ),
typeof( BoneMagi ), typeof( Brigand ), typeof( BronzeElemental ),
typeof( BrownBear ), typeof( Bull ), typeof( BullFrog ),
typeof( Cat ), typeof( Centaur ), typeof( ChaosDaemon ),
typeof( Chicken ), typeof( GolemController ), typeof( CopperElemental ),
typeof( CopperElemental ), typeof( Cougar ), typeof( Cow ),
typeof( Cyclops ), typeof( Daemon ), typeof( DeepSeaSerpent ),
typeof( DesertOstard ), typeof( DireWolf ), typeof( Dog ),
typeof( Dolphin ), typeof( Dragon ), typeof( Drake ),
typeof( DullCopperElemental ), typeof( Eagle ), typeof( ElderGazer ),
typeof( EvilMage ), typeof( EvilMageLord ), typeof( Executioner ),
typeof( Savage ), typeof( FireElemental ), typeof( FireGargoyle ),
typeof( FireSteed ), typeof( ForestOstard ), typeof( FrenziedOstard ),
typeof( FrostSpider ), typeof( Gargoyle ), typeof( Gazer ),
typeof( IceSerpent ), typeof( GiantRat ), typeof( GiantSerpent ),
typeof( GiantSpider ), typeof( GiantToad ), typeof( Goat ),
typeof( GoldenElemental ), typeof( Gorilla ), typeof( GreatHart ),
typeof( GreyWolf ), typeof( GrizzlyBear ), typeof( Guardian ),
typeof( Harpy ), typeof( Harrower ), typeof( HellHound ),
typeof( Hind ), typeof( HordeMinion ), typeof( Horse ),
typeof( Horse ), typeof( IceElemental ), typeof( IceFiend ),
typeof( IceSnake ), typeof( Imp ), typeof( JackRabbit ),
typeof( Kirin ), typeof( Kraken ), typeof( PredatorHellCat ),
typeof( LavaLizard ), typeof( LavaSerpent ), typeof( LavaSnake ),
typeof( Lizardman ), typeof( Llama ), typeof( Mongbat ),
typeof( StrongMongbat ), typeof( MountainGoat ), typeof( Orc ),
typeof( OrcBomber ), typeof( OrcBrute ), typeof( OrcCaptain ),
typeof( OrcishLord ), typeof( OrcishMage ), typeof( PackHorse ),
typeof( PackLlama ), typeof( Panther ), typeof( Pig ),
typeof( PlagueSpawn ), typeof( PolarBear ), typeof( Rabbit ),
typeof( Ratman ), typeof( RatmanArcher ), typeof( RatmanMage ),
typeof( RedSolenInfiltratorQueen ), typeof( RedSolenInfiltratorWarrior ), typeof( RedSolenQueen ),
typeof( RedSolenWarrior ), typeof( RedSolenWorker ), typeof( RidableLlama ),
typeof( Ridgeback ), typeof( Scorpion ), typeof( SeaSerpent ),
typeof( SerpentineDragon ), typeof( Shade ), typeof( ShadowIronElemental ),
typeof( ShadowWisp ), typeof( ShadowWyrm ), typeof( Sheep ),
typeof( SilverSteed ), typeof( SkeletalDragon ), typeof( SkeletalMage ),
typeof( SkeletalMount ), typeof( HellCat ), typeof( Snake ),
typeof( SnowLeopard ), typeof( SpectralArmour ), typeof( Spectre ),
typeof( StoneGargoyle ), typeof( StoneHarpy ), typeof( SwampDragon ),
typeof( ScaledSwampDragon ), typeof( SwampTentacle ), typeof( TerathanAvenger ),
typeof( TerathanDrone ), typeof( TerathanMatriarch ), typeof( TerathanWarrior ),
typeof( TimberWolf ), typeof( Titan ), typeof( Troll ),
typeof( Unicorn ), typeof( ValoriteElemental ), typeof( VeriteElemental ),
typeof( CoMWarHorse ), typeof( MinaxWarHorse ), typeof( SLWarHorse ),
typeof( TBWarHorse ), typeof( WaterElemental ), typeof( WhippingVine ),
typeof( WhiteWolf ), typeof( Wraith ), typeof( Wyvern ),
typeof( KhaldunZealot ), typeof( KhaldunSummoner ), typeof( SavageRidgeback ),
typeof( LichLord ), typeof( SkeletalKnight ), typeof( SummonedDaemon ),
typeof( SummonedEarthElemental ), typeof( SummonedWaterElemental ), typeof( SummonedFireElemental ),
typeof( MeerWarrior ), typeof( MeerEternal ), typeof( MeerMage ),
typeof( MeerCaptain ), typeof( JukaLord ), typeof( JukaMage ),
typeof( JukaWarrior ), typeof( AbysmalHorror ), typeof( BoneDemon ),
typeof( Devourer ), typeof( FleshGolem ), typeof( Gibberling ),
typeof( GoreFiend ), typeof( Impaler ), typeof( PatchworkSkeleton ),
typeof( Ravager ), typeof( ShadowKnight ), typeof( SkitteringHopper ),
typeof( Treefellow ), typeof( VampireBat ), typeof( WailingBanshee ),
typeof( WandererOfTheVoid ), typeof( Cursed ), typeof( GrimmochDrummel ),
typeof( LysanderGathenwale ), typeof( MorgBergen ), typeof( ShadowFiend ),
typeof( SpectralArmour ), typeof( TavaraSewel ), typeof( ArcaneDaemon ),
typeof( Doppleganger ), typeof( EnslavedGargoyle ), typeof( ExodusMinion ),
typeof( ExodusOverseer ), typeof( GargoyleDestroyer ), typeof( GargoyleEnforcer ),
typeof( Moloch ), typeof( BakeKitsune ), typeof( DeathwatchBeetleHatchling ),
typeof( Kappa ), typeof( KazeKemono ), typeof( DeathwatchBeetle ),
typeof( TsukiWolf ), typeof( YomotsuElder ), typeof( YomotsuPriest ),
typeof( YomotsuWarrior ), typeof( RevenantLion ), typeof( Oni ),
typeof( RuneBeetle ), typeof( Gaman ), typeof( Crane )
} )
};
}
}

View file

@ -0,0 +1,45 @@
using System;
using Server;
using Server.Targeting;
using Server.Mobiles;
using System.Collections;
namespace Server.Targets
{
public class AIControlMobileTarget : Target
{
private ArrayList m_List;
private OrderType m_Order;
public OrderType Order
{
get
{
return m_Order;
}
}
public AIControlMobileTarget( BaseAI ai, OrderType order ) : base( -1, false, ( order == OrderType.Attack ? TargetFlags.Harmful : TargetFlags.None ) )
{
m_List = new ArrayList();
m_Order = order;
AddAI( ai );
}
public void AddAI( BaseAI ai )
{
if ( !m_List.Contains( ai ) )
m_List.Add( ai );
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
for ( int i = 0; i < m_List.Count; ++i )
((BaseAI)m_List[i]).EndPickTarget( from, (Mobile)o, m_Order );
}
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
/*
* NPC could use a team objets..
*
* -List of members
* -List of ennemy teams
* -List of ally team
* -Team could be set automaticaly at mobile creation by the region system
* -Team could be the owner of a common timer instead of one by creature
*
*
*
*/
namespace Server.Mobiles
{
public class Team
{
//private ArrayList m_arAlly;
//private ArrayList m_arFoe;
//private ArrayList m_arMember;
public static void Initialize()
{
}
}
}

View file

@ -0,0 +1,29 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
/*
* NPC could use a faction objets..
*
* -List of members
* -List of ennemy factions
* -List of neutral factions
* -List of ally faction
* -Team could be set automaticaly at mobile creation by the region system
* -Team could be the owner of a common timer instead of one by creature
*
*
*
*/
namespace Server.Mobiles
{
public class TeamRegistry
{
//private ArrayList m_arTeam;
public static void Initialize()
{
}
}
}

View file

@ -0,0 +1,88 @@
using System;
namespace Server.Engines.BulkOrders
{
public class BOBFilter
{
private int m_Type;
private int m_Quality;
private int m_Material;
private int m_Quantity;
public bool IsDefault
{
get{ return ( m_Type == 0 && m_Quality == 0 && m_Material == 0 && m_Quantity == 0 ); }
}
public void Clear()
{
m_Type = 0;
m_Quality = 0;
m_Material = 0;
m_Quantity = 0;
}
public int Type
{
get{ return m_Type; }
set{ m_Type = value; }
}
public int Quality
{
get{ return m_Quality; }
set{ m_Quality = value; }
}
public int Material
{
get{ return m_Material; }
set{ m_Material = value; }
}
public int Quantity
{
get{ return m_Quantity; }
set{ m_Quantity = value; }
}
public BOBFilter()
{
}
public BOBFilter( GenericReader reader )
{
int version = reader.ReadEncodedInt();
switch ( version )
{
case 1:
{
m_Type = reader.ReadEncodedInt();
m_Quality = reader.ReadEncodedInt();
m_Material = reader.ReadEncodedInt();
m_Quantity = reader.ReadEncodedInt();
break;
}
}
}
public void Serialize( GenericWriter writer )
{
if ( IsDefault )
{
writer.WriteEncodedInt( 0 ); // version
}
else
{
writer.WriteEncodedInt( 1 ); // version
writer.WriteEncodedInt( m_Type );
writer.WriteEncodedInt( m_Quality );
writer.WriteEncodedInt( m_Material );
writer.WriteEncodedInt( m_Quantity );
}
}
}
}

View file

@ -0,0 +1,215 @@
using System;
using System.Collections;
using Server;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.BulkOrders
{
public class BOBFilterGump : Gump
{
private PlayerMobile m_From;
private BulkOrderBook m_Book;
private const int LabelColor = 0x7FFF;
private static int[,] m_MaterialFilters = new int[,]
{
{ 1044067, 1 }, // Blacksmithy
{ 1062226, 3 }, // Iron
{ 1018332, 4 }, // Dull Copper
{ 1018333, 5 }, // Shadow Iron
{ 1018334, 6 }, // Copper
{ 1018335, 7 }, // Bronze
{ 0, 0 }, // --Blank--
{ 1018336, 8 }, // Golden
{ 1018337, 9 }, // Agapite
{ 1018338, 10 }, // Verite
{ 1018339, 11 }, // Valorite
{ 0, 0 }, // --Blank--
{ 1044094, 2 }, // Tailoring
{ 1044286, 12 }, // Cloth
{ 1062235, 13 }, // Leather
{ 1062236, 14 }, // Spined
{ 1062237, 15 }, // Horned
{ 1062238, 16 } // Barbed
};
private static int[,] m_TypeFilters = new int[,]
{
{ 1062229, 0 }, // All
{ 1062224, 1 }, // Small
{ 1062225, 2 } // Large
};
private static int[,] m_QualityFilters = new int[,]
{
{ 1062229, 0 }, // All
{ 1011542, 1 }, // Normal
{ 1060636, 2 } // Exceptional
};
private static int[,] m_AmountFilters = new int[,]
{
{ 1062229, 0 }, // All
{ 1049706, 1 }, // 10
{ 1016007, 2 }, // 15
{ 1062239, 3 } // 20
};
private static int[][,] m_Filters = new int[][,]
{
m_TypeFilters,
m_QualityFilters,
m_MaterialFilters,
m_AmountFilters
};
private static int[] m_XOffsets_Type = new int[]{ 0, 75, 170 };
private static int[] m_XOffsets_Quality = new int[]{ 0, 75, 170 };
private static int[] m_XOffsets_Amount = new int[]{ 0, 75, 180, 275 };
private static int[] m_XOffsets_Material = new int[]{ 0, 105, 210, 305, 390, 485 };
private static int[] m_XWidths_Small = new int[]{ 50, 50, 70, 50 };
private static int[] m_XWidths_Large = new int[]{ 80, 50, 50, 50, 50, 50 };
private void AddFilterList( int x, int y, int[] xOffsets, int yOffset, int[,] filters, int[] xWidths, int filterValue, int filterIndex )
{
for ( int i = 0; i < filters.GetLength( 0 ); ++i )
{
int number = filters[i, 0];
if ( number == 0 )
continue;
bool isSelected = ( filters[i, 1] == filterValue );
if ( !isSelected && (i % xOffsets.Length) == 0 )
isSelected = ( filterValue == 0 );
AddHtmlLocalized( x + 35 + xOffsets[i % xOffsets.Length], y + ((i / xOffsets.Length) * yOffset), xWidths[i % xOffsets.Length], 32, number, isSelected ? 16927 : LabelColor, false, false );
AddButton( x + xOffsets[i % xOffsets.Length], y + ((i / xOffsets.Length) * yOffset), 4005, 4007, 4 + filterIndex + (i * 4), GumpButtonType.Reply, 0 );
}
}
public override void OnResponse( Server.Network.NetState sender, RelayInfo info )
{
BOBFilter f = ( m_From.UseOwnFilter ? m_From.BOBFilter : m_Book.Filter );
int index = info.ButtonID;
switch ( index )
{
case 0: // Apply
{
m_From.SendGump( new BOBGump( m_From, m_Book ) );
break;
}
case 1: // Set Book Filter
{
m_From.UseOwnFilter = false;
m_From.SendGump( new BOBFilterGump( m_From, m_Book ) );
break;
}
case 2: // Set Your Filter
{
m_From.UseOwnFilter = true;
m_From.SendGump( new BOBFilterGump( m_From, m_Book ) );
break;
}
case 3: // Clear Filter
{
f.Clear();
m_From.SendGump( new BOBFilterGump( m_From, m_Book ) );
break;
}
default:
{
index -= 4;
int type = index % 4;
index /= 4;
if ( type >= 0 && type < m_Filters.Length )
{
int[,] filters = m_Filters[type];
if ( index >= 0 && index < filters.GetLength( 0 ) )
{
if ( filters[index, 0] == 0 )
break;
switch ( type )
{
case 0: f.Type = filters[index, 1]; break;
case 1: f.Quality = filters[index, 1]; break;
case 2: f.Material = filters[index, 1]; break;
case 3: f.Quantity = filters[index, 1]; break;
}
m_From.SendGump( new BOBFilterGump( m_From, m_Book ) );
}
}
break;
}
}
}
public BOBFilterGump( PlayerMobile from, BulkOrderBook book ) : base( 12, 24 )
{
from.CloseGump( typeof( BOBGump ) );
from.CloseGump( typeof( BOBFilterGump ) );
m_From = from;
m_Book = book;
BOBFilter f = ( from.UseOwnFilter ? from.BOBFilter : book.Filter );
AddPage( 0 );
AddBackground( 10, 10, 600, 439, 5054 );
AddImageTiled( 18, 20, 583, 420, 2624 );
AddAlphaRegion( 18, 20, 583, 420 );
AddImage( 5, 5, 10460 );
AddImage( 585, 5, 10460 );
AddImage( 5, 424, 10460 );
AddImage( 585, 424, 10460 );
AddHtmlLocalized( 270, 32, 200, 32, 1062223, LabelColor, false, false ); // Filter Preference
AddHtmlLocalized( 26, 64, 120, 32, 1062228, LabelColor, false, false ); // Bulk Order Type
AddFilterList( 25, 96, m_XOffsets_Type, 40, m_TypeFilters, m_XWidths_Small, f.Type, 0 );
AddHtmlLocalized( 320, 64, 50, 32, 1062215, LabelColor, false, false ); // Quality
AddFilterList( 320, 96, m_XOffsets_Quality, 40, m_QualityFilters, m_XWidths_Small, f.Quality, 1 );
AddHtmlLocalized( 26, 160, 120, 32, 1062232, LabelColor, false, false ); // Material Type
AddFilterList( 25, 192, m_XOffsets_Material, 40, m_MaterialFilters, m_XWidths_Large, f.Material, 2 );
AddHtmlLocalized( 26, 320, 120, 32, 1062217, LabelColor, false, false ); // Amount
AddFilterList( 25, 352, m_XOffsets_Amount, 40, m_AmountFilters, m_XWidths_Small, f.Quantity, 3 );
AddHtmlLocalized( 75, 416, 120, 32, 1062477, ( from.UseOwnFilter ? LabelColor : 16927 ), false, false ); // Set Book Filter
AddButton( 40, 416, 4005, 4007, 1, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 235, 416, 120, 32, 1062478, ( from.UseOwnFilter ? 16927 : LabelColor ), false, false ); // Set Your Filter
AddButton( 200, 416, 4005, 4007, 2, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 405, 416, 120, 32, 1062231, LabelColor, false, false ); // Clear Filter
AddButton( 370, 416, 4005, 4007, 3, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 540, 416, 50, 32, 1011046, LabelColor, false, false ); // APPLY
AddButton( 505, 416, 4017, 4018, 0, GumpButtonType.Reply, 0 );
}
}
}

View file

@ -0,0 +1,611 @@
using System;
using System.Collections;
using Server;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
using Server.Prompts;
namespace Server.Engines.BulkOrders
{
public class BOBGump : Gump
{
private PlayerMobile m_From;
private BulkOrderBook m_Book;
private ArrayList m_List;
private int m_Page;
private const int LabelColor = 0x7FFF;
public Item Reconstruct( object obj )
{
Item item = null;
if ( obj is BOBLargeEntry )
item = ((BOBLargeEntry)obj).Reconstruct();
else if ( obj is BOBSmallEntry )
item = ((BOBSmallEntry)obj).Reconstruct();
return item;
}
public bool CheckFilter( object obj )
{
if ( obj is BOBLargeEntry )
{
BOBLargeEntry e = (BOBLargeEntry)obj;
return CheckFilter( e.Material, e.AmountMax, true, e.RequireExceptional, e.DeedType, ( e.Entries.Length > 0 ? e.Entries[0].ItemType : null ) );
}
else if ( obj is BOBSmallEntry )
{
BOBSmallEntry e = (BOBSmallEntry)obj;
return CheckFilter( e.Material, e.AmountMax, false, e.RequireExceptional, e.DeedType, e.ItemType );
}
return false;
}
public bool CheckFilter( BulkMaterialType mat, int amountMax, bool isLarge, bool reqExc, BODType deedType, Type itemType )
{
BOBFilter f = ( m_From.UseOwnFilter ? m_From.BOBFilter : m_Book.Filter );
if ( f.IsDefault )
return true;
if ( f.Quality == 1 && reqExc )
return false;
else if ( f.Quality == 2 && !reqExc )
return false;
if ( f.Quantity == 1 && amountMax != 10 )
return false;
else if ( f.Quantity == 2 && amountMax != 15 )
return false;
else if ( f.Quantity == 3 && amountMax != 20 )
return false;
if ( f.Type == 1 && isLarge )
return false;
else if ( f.Type == 2 && !isLarge )
return false;
switch ( f.Material )
{
default:
case 0: return true;
case 1: return ( deedType == BODType.Smith );
case 2: return ( deedType == BODType.Tailor );
case 3: return ( mat == BulkMaterialType.None && BGTClassifier.Classify( deedType, itemType ) == BulkGenericType.Iron );
case 4: return ( mat == BulkMaterialType.DullCopper );
case 5: return ( mat == BulkMaterialType.ShadowIron );
case 6: return ( mat == BulkMaterialType.Copper );
case 7: return ( mat == BulkMaterialType.Bronze );
case 8: return ( mat == BulkMaterialType.Gold );
case 9: return ( mat == BulkMaterialType.Agapite );
case 10: return ( mat == BulkMaterialType.Verite );
case 11: return ( mat == BulkMaterialType.Valorite );
case 12: return ( mat == BulkMaterialType.None && BGTClassifier.Classify( deedType, itemType ) == BulkGenericType.Cloth );
case 13: return ( mat == BulkMaterialType.None && BGTClassifier.Classify( deedType, itemType ) == BulkGenericType.Leather );
case 14: return ( mat == BulkMaterialType.Spined );
case 15: return ( mat == BulkMaterialType.Horned );
case 16: return ( mat == BulkMaterialType.Barbed );
}
}
public int GetIndexForPage( int page )
{
int index = 0;
while ( page-- > 0 )
index += GetCountForIndex( index );
return index;
}
public int GetCountForIndex( int index )
{
int slots = 0;
int count = 0;
ArrayList list = m_List;
for ( int i = index; i >= 0 && i < list.Count; ++i )
{
object obj = list[i];
if ( CheckFilter( obj ) )
{
int add;
if ( obj is BOBLargeEntry )
add = ((BOBLargeEntry)obj).Entries.Length;
else
add = 1;
if ( (slots + add) > 10 )
break;
slots += add;
}
++count;
}
return count;
}
public object GetMaterialName( BulkMaterialType mat, BODType type, Type itemType )
{
switch ( type )
{
case BODType.Smith:
{
switch ( mat )
{
case BulkMaterialType.None: return 1062226;
case BulkMaterialType.DullCopper: return 1018332;
case BulkMaterialType.ShadowIron: return 1018333;
case BulkMaterialType.Copper: return 1018334;
case BulkMaterialType.Bronze: return 1018335;
case BulkMaterialType.Gold: return 1018336;
case BulkMaterialType.Agapite: return 1018337;
case BulkMaterialType.Verite: return 1018338;
case BulkMaterialType.Valorite: return 1018339;
}
break;
}
case BODType.Tailor:
{
switch ( mat )
{
case BulkMaterialType.None:
{
if ( itemType.IsSubclassOf( typeof( BaseArmor ) ) || itemType.IsSubclassOf( typeof( BaseShoes ) ) )
return 1062235;
return 1044286;
}
case BulkMaterialType.Spined: return 1062236;
case BulkMaterialType.Horned: return 1062237;
case BulkMaterialType.Barbed: return 1062238;
}
break;
}
}
return "Invalid";
}
public BOBGump( PlayerMobile from, BulkOrderBook book ) : this( from, book, 0, null )
{
}
public override void OnResponse( Server.Network.NetState sender, RelayInfo info )
{
int index = info.ButtonID;
switch ( index )
{
case 0: // EXIT
{
break;
}
case 1: // Set Filter
{
m_From.SendGump( new BOBFilterGump( m_From, m_Book ) );
break;
}
case 2: // Previous page
{
if ( m_Page > 0 )
m_From.SendGump( new BOBGump( m_From, m_Book, m_Page - 1, m_List ) );
return;
}
case 3: // Next page
{
if ( GetIndexForPage( m_Page + 1 ) < m_List.Count )
m_From.SendGump( new BOBGump( m_From, m_Book, m_Page + 1, m_List ) );
break;
}
case 4: // Price all
{
if ( m_Book.IsChildOf( m_From.Backpack ) )
{
m_From.Prompt = new SetPricePrompt( m_Book, null, m_Page, m_List );
m_From.SendMessage( "Type in a price for all deeds in the book:" );
}
break;
}
default:
{
bool canDrop = m_Book.IsChildOf( m_From.Backpack );
bool canPrice = canDrop || (m_Book.RootParent is PlayerVendor);
index -= 5;
int type = index % 2;
index /= 2;
if ( index < 0 || index >= m_List.Count )
break;
object obj = m_List[index];
if ( !m_Book.Entries.Contains( obj ) )
{
m_From.SendLocalizedMessage( 1062382 ); // The deed selected is not available.
break;
}
if ( type == 0 ) // Drop
{
if ( m_Book.IsChildOf( m_From.Backpack ) )
{
Item item = Reconstruct( obj );
if ( item != null )
{
m_From.AddToBackpack( item );
m_From.SendLocalizedMessage( 1045152 ); // The bulk order deed has been placed in your backpack.
m_Book.Entries.Remove( obj );
m_Book.InvalidateProperties();
if ( m_Book.Entries.Count > 0 )
m_From.SendGump( new BOBGump( m_From, m_Book, 0, null ) );
else
m_From.SendLocalizedMessage( 1062381 ); // The book is empty.
}
else
{
m_From.SendMessage( "Internal error. The bulk order deed could not be reconstructed." );
}
}
}
else // Set Price | Buy
{
if ( m_Book.IsChildOf( m_From.Backpack ) )
{
m_From.Prompt = new SetPricePrompt( m_Book, obj, m_Page, m_List );
m_From.SendLocalizedMessage( 1062383 ); // Type in a price for the deed:
}
else if ( m_Book.RootParent is PlayerVendor )
{
PlayerVendor pv = (PlayerVendor)m_Book.RootParent;
VendorItem vi = pv.GetVendorItem( m_Book );
int price = 0;
if ( vi != null && !vi.IsForSale )
{
if ( obj is BOBLargeEntry )
price = ((BOBLargeEntry)obj).Price;
else if ( obj is BOBSmallEntry )
price = ((BOBSmallEntry)obj).Price;
}
if ( price == 0 )
m_From.SendLocalizedMessage( 1062382 ); // The deed selected is not available.
else
m_From.SendGump( new BODBuyGump( m_From, m_Book, obj, price ) );
}
}
break;
}
}
}
private class SetPricePrompt : Prompt
{
private BulkOrderBook m_Book;
private object m_Object;
private int m_Page;
private ArrayList m_List;
public SetPricePrompt( BulkOrderBook book, object obj, int page, ArrayList list )
{
m_Book = book;
m_Object = obj;
m_Page = page;
m_List = list;
}
public override void OnResponse( Mobile from, string text )
{
if ( m_Object != null && !m_Book.Entries.Contains( m_Object ) )
{
from.SendLocalizedMessage( 1062382 ); // The deed selected is not available.
return;
}
int price = Utility.ToInt32( text );
if ( price < 0 || price > 250000000 )
{
from.SendLocalizedMessage( 1062390 ); // The price you requested is outrageous!
}
else if ( m_Object == null )
{
for ( int i = 0; i < m_List.Count; ++i )
{
object obj = m_List[i];
if ( !m_Book.Entries.Contains( obj ) )
continue;
if ( obj is BOBLargeEntry )
((BOBLargeEntry)obj).Price = price;
else if ( obj is BOBSmallEntry )
((BOBSmallEntry)obj).Price = price;
}
from.SendMessage( "Deed prices set." );
if ( from is PlayerMobile )
from.SendGump( new BOBGump( (PlayerMobile)from, m_Book, m_Page, m_List ) );
}
else if ( m_Object is BOBLargeEntry )
{
((BOBLargeEntry)m_Object).Price = price;
from.SendLocalizedMessage( 1062384 ); // Deed price set.
if ( from is PlayerMobile )
from.SendGump( new BOBGump( (PlayerMobile)from, m_Book, m_Page, m_List ) );
}
else if ( m_Object is BOBSmallEntry )
{
((BOBSmallEntry)m_Object).Price = price;
from.SendLocalizedMessage( 1062384 ); // Deed price set.
if ( from is PlayerMobile )
from.SendGump( new BOBGump( (PlayerMobile)from, m_Book, m_Page, m_List ) );
}
}
}
public BOBGump( PlayerMobile from, BulkOrderBook book, int page, ArrayList list ) : base( 12, 24 )
{
from.CloseGump( typeof( BOBGump ) );
from.CloseGump( typeof( BOBFilterGump ) );
m_From = from;
m_Book = book;
m_Page = page;
if ( list == null )
{
list = new ArrayList( book.Entries.Count );
for ( int i = 0; i < book.Entries.Count; ++i )
{
object obj = book.Entries[i];
if ( CheckFilter( obj ) )
list.Add( obj );
}
}
m_List = list;
int index = GetIndexForPage( page );
int count = GetCountForIndex( index );
int tableIndex = 0;
PlayerVendor pv = book.RootParent as PlayerVendor;
bool canDrop = book.IsChildOf( from.Backpack );
bool canBuy = ( pv != null );
bool canPrice = ( canDrop || canBuy );
if ( canBuy )
{
VendorItem vi = pv.GetVendorItem( book );
canBuy = ( vi != null && !vi.IsForSale );
}
int width = 600;
if ( !canPrice )
width = 516;
X = (624 - width) / 2;
AddPage( 0 );
AddBackground( 10, 10, width, 439, 5054 );
AddImageTiled( 18, 20, width - 17, 420, 2624 );
if ( canPrice )
{
AddImageTiled( 573, 64, 24, 352, 200 );
AddImageTiled( 493, 64, 78, 352, 1416 );
}
if ( canDrop )
AddImageTiled( 24, 64, 32, 352, 1416 );
AddImageTiled( 58, 64, 36, 352, 200 );
AddImageTiled( 96, 64, 133, 352, 1416 );
AddImageTiled( 231, 64, 80, 352, 200 );
AddImageTiled( 313, 64, 100, 352, 1416 );
AddImageTiled( 415, 64, 76, 352, 200 );
for ( int i = index; i < (index + count) && i >= 0 && i < list.Count; ++i )
{
object obj = list[i];
if ( !CheckFilter( obj ) )
continue;
AddImageTiled( 24, 94 + (tableIndex * 32), canPrice ? 573 : 489, 2, 2624 );
if ( obj is BOBLargeEntry )
tableIndex += ((BOBLargeEntry)obj).Entries.Length;
else if ( obj is BOBSmallEntry )
++tableIndex;
}
AddAlphaRegion( 18, 20, width - 17, 420 );
AddImage( 5, 5, 10460 );
AddImage( width - 15, 5, 10460 );
AddImage( 5, 424, 10460 );
AddImage( width - 15, 424, 10460 );
AddHtmlLocalized( canPrice ? 266 : 224, 32, 200, 32, 1062220, LabelColor, false, false ); // Bulk Order Book
AddHtmlLocalized( 63, 64, 200, 32, 1062213, LabelColor, false, false ); // Type
AddHtmlLocalized( 147, 64, 200, 32, 1062214, LabelColor, false, false ); // Item
AddHtmlLocalized( 246, 64, 200, 32, 1062215, LabelColor, false, false ); // Quality
AddHtmlLocalized( 336, 64, 200, 32, 1062216, LabelColor, false, false ); // Material
AddHtmlLocalized( 429, 64, 200, 32, 1062217, LabelColor, false, false ); // Amount
AddButton( 35, 32, 4005, 4007, 1, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 70, 32, 200, 32, 1062476, LabelColor, false, false ); // Set Filter
BOBFilter f = ( from.UseOwnFilter ? from.BOBFilter : book.Filter );
if ( f.IsDefault )
AddHtmlLocalized( canPrice ? 470 : 386, 32, 120, 32, 1062475, 16927, false, false ); // Using No Filter
else if ( from.UseOwnFilter )
AddHtmlLocalized( canPrice ? 470 : 386, 32, 120, 32, 1062451, 16927, false, false ); // Using Your Filter
else
AddHtmlLocalized( canPrice ? 470 : 386, 32, 120, 32, 1062230, 16927, false, false ); // Using Book Filter
AddButton( 375, 416, 4017, 4018, 0, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 410, 416, 120, 20, 1011441, LabelColor, false, false ); // EXIT
if ( canDrop )
AddHtmlLocalized( 26, 64, 50, 32, 1062212, LabelColor, false, false ); // Drop
if ( canPrice )
{
AddHtmlLocalized( 516, 64, 200, 32, 1062218, LabelColor, false, false ); // Price
if ( canBuy )
{
AddHtmlLocalized( 576, 64, 200, 32, 1062219, LabelColor, false, false ); // Buy
}
else
{
AddHtmlLocalized( 576, 64, 200, 32, 1062227, LabelColor, false, false ); // Set
AddButton( 450, 416, 4005, 4007, 4, GumpButtonType.Reply, 0 );
AddHtml( 485, 416, 120, 20, "<BASEFONT COLOR=#FFFFFF>Price all</FONT>", false, false );
}
}
tableIndex = 0;
if ( page > 0 )
{
AddButton( 75, 416, 4014, 4016, 2, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 110, 416, 150, 20, 1011067, LabelColor, false, false ); // Previous page
}
if ( GetIndexForPage( page + 1 ) < list.Count )
{
AddButton( 225, 416, 4005, 4007, 3, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 260, 416, 150, 20, 1011066, LabelColor, false, false ); // Next page
}
for ( int i = index; i < (index + count) && i >= 0 && i < list.Count; ++i )
{
object obj = list[i];
if ( !CheckFilter( obj ) )
continue;
if ( obj is BOBLargeEntry )
{
BOBLargeEntry e = (BOBLargeEntry)obj;
int y = 96 + (tableIndex * 32);
if ( canDrop )
AddButton( 35, y + 2, 5602, 5606, 5 + (i * 2), GumpButtonType.Reply, 0 );
if ( canDrop || (canBuy && e.Price > 0) )
{
AddButton( 579, y + 2, 2117, 2118, 6 + (i * 2), GumpButtonType.Reply, 0 );
AddLabel( 495, y, 1152, e.Price.ToString() );
}
AddHtmlLocalized( 61, y, 50, 32, 1062225, LabelColor, false, false ); // Large
for ( int j = 0; j < e.Entries.Length; ++j )
{
BOBLargeSubEntry sub = e.Entries[j];
AddHtmlLocalized( 103, y, 130, 32, sub.Number, LabelColor, false, false );
if ( e.RequireExceptional )
AddHtmlLocalized( 235, y, 80, 20, 1060636, LabelColor, false, false ); // exceptional
else
AddHtmlLocalized( 235, y, 80, 20, 1011542, LabelColor, false, false ); // normal
object name = GetMaterialName( e.Material, e.DeedType, sub.ItemType );
if ( name is int )
AddHtmlLocalized( 316, y, 100, 20, (int)name, LabelColor, false, false );
else if ( name is string )
AddLabel( 316, y, 1152, (string)name );
AddLabel( 421, y, 1152, String.Format( "{0} / {1}", sub.AmountCur, e.AmountMax ) );
++tableIndex;
y += 32;
}
}
else if ( obj is BOBSmallEntry )
{
BOBSmallEntry e = (BOBSmallEntry)obj;
int y = 96 + (tableIndex++ * 32);
if ( canDrop )
AddButton( 35, y + 2, 5602, 5606, 5 + (i * 2), GumpButtonType.Reply, 0 );
if ( canDrop || (canBuy && e.Price > 0) )
{
AddButton( 579, y + 2, 2117, 2118, 6 + (i * 2), GumpButtonType.Reply, 0 );
AddLabel( 495, y, 1152, e.Price.ToString() );
}
AddHtmlLocalized( 61, y, 50, 32, 1062224, LabelColor, false, false ); // Small
AddHtmlLocalized( 103, y, 130, 32, e.Number, LabelColor, false, false );
if ( e.RequireExceptional )
AddHtmlLocalized( 235, y, 80, 20, 1060636, LabelColor, false, false ); // exceptional
else
AddHtmlLocalized( 235, y, 80, 20, 1011542, LabelColor, false, false ); // normal
object name = GetMaterialName( e.Material, e.DeedType, e.ItemType );
if ( name is int )
AddHtmlLocalized( 316, y, 100, 20, (int)name, LabelColor, false, false );
else if ( name is string )
AddLabel( 316, y, 1152, (string)name );
AddLabel( 421, y, 1152, String.Format( "{0} / {1}", e.AmountCur, e.AmountMax ) );
}
}
}
}
}

View file

@ -0,0 +1,110 @@
using System;
namespace Server.Engines.BulkOrders
{
public class BOBLargeEntry
{
private bool m_RequireExceptional;
private BODType m_DeedType;
private BulkMaterialType m_Material;
private int m_AmountMax;
private int m_Price;
private BOBLargeSubEntry[] m_Entries;
public bool RequireExceptional{ get{ return m_RequireExceptional; } }
public BODType DeedType{ get{ return m_DeedType; } }
public BulkMaterialType Material{ get{ return m_Material; } }
public int AmountMax{ get{ return m_AmountMax; } }
public int Price{ get{ return m_Price; } set{ m_Price = value; } }
public BOBLargeSubEntry[] Entries{ get{ return m_Entries; } }
public Item Reconstruct()
{
LargeBOD bod = null;
if ( m_DeedType == BODType.Smith )
bod = new LargeSmithBOD( m_AmountMax, m_RequireExceptional, m_Material, ReconstructEntries() );
else if ( m_DeedType == BODType.Tailor )
bod = new LargeTailorBOD( m_AmountMax, m_RequireExceptional, m_Material, ReconstructEntries() );
for ( int i = 0; bod != null && i < bod.Entries.Length; ++i )
bod.Entries[i].Owner = bod;
return bod;
}
private LargeBulkEntry[] ReconstructEntries()
{
LargeBulkEntry[] entries = new LargeBulkEntry[m_Entries.Length];
for ( int i = 0; i < m_Entries.Length; ++i )
{
entries[i] = new LargeBulkEntry( null, new SmallBulkEntry( m_Entries[i].ItemType, m_Entries[i].Number, m_Entries[i].Graphic ) );
entries[i].Amount = m_Entries[i].AmountCur;
}
return entries;
}
public BOBLargeEntry( LargeBOD bod )
{
m_RequireExceptional = bod.RequireExceptional;
if ( bod is LargeTailorBOD )
m_DeedType = BODType.Tailor;
else if ( bod is LargeSmithBOD )
m_DeedType = BODType.Smith;
m_Material = bod.Material;
m_AmountMax = bod.AmountMax;
m_Entries = new BOBLargeSubEntry[bod.Entries.Length];
for ( int i = 0; i < m_Entries.Length; ++i )
m_Entries[i] = new BOBLargeSubEntry( bod.Entries[i] );
}
public BOBLargeEntry( GenericReader reader )
{
int version = reader.ReadEncodedInt();
switch ( version )
{
case 0:
{
m_RequireExceptional = reader.ReadBool();
m_DeedType = (BODType)reader.ReadEncodedInt();
m_Material = (BulkMaterialType)reader.ReadEncodedInt();
m_AmountMax = reader.ReadEncodedInt();
m_Price = reader.ReadEncodedInt();
m_Entries = new BOBLargeSubEntry[reader.ReadEncodedInt()];
for ( int i = 0; i < m_Entries.Length; ++i )
m_Entries[i] = new BOBLargeSubEntry( reader );
break;
}
}
}
public void Serialize( GenericWriter writer )
{
writer.WriteEncodedInt( 0 ); // version
writer.Write( (bool) m_RequireExceptional );
writer.WriteEncodedInt( (int) m_DeedType );
writer.WriteEncodedInt( (int) m_Material );
writer.WriteEncodedInt( (int) m_AmountMax );
writer.WriteEncodedInt( (int) m_Price );
writer.WriteEncodedInt( (int) m_Entries.Length );
for ( int i = 0; i < m_Entries.Length; ++i )
m_Entries[i].Serialize( writer );
}
}
}

View file

@ -0,0 +1,58 @@
using System;
namespace Server.Engines.BulkOrders
{
public class BOBLargeSubEntry
{
private Type m_ItemType;
private int m_AmountCur;
private int m_Number;
private int m_Graphic;
public Type ItemType{ get{ return m_ItemType; } }
public int AmountCur{ get{ return m_AmountCur; } }
public int Number{ get{ return m_Number; } }
public int Graphic{ get{ return m_Graphic; } }
public BOBLargeSubEntry( LargeBulkEntry lbe )
{
m_ItemType = lbe.Details.Type;
m_AmountCur = lbe.Amount;
m_Number = lbe.Details.Number;
m_Graphic = lbe.Details.Graphic;
}
public BOBLargeSubEntry( GenericReader reader )
{
int version = reader.ReadEncodedInt();
switch ( version )
{
case 0:
{
string type = reader.ReadString();
if ( type != null )
m_ItemType = ScriptCompiler.FindTypeByFullName( type );
m_AmountCur = reader.ReadEncodedInt();
m_Number = reader.ReadEncodedInt();
m_Graphic = reader.ReadEncodedInt();
break;
}
}
}
public void Serialize( GenericWriter writer )
{
writer.WriteEncodedInt( 0 ); // version
writer.Write( m_ItemType == null ? null : m_ItemType.FullName );
writer.WriteEncodedInt( (int) m_AmountCur );
writer.WriteEncodedInt( (int) m_Number );
writer.WriteEncodedInt( (int) m_Graphic );
}
}
}

View file

@ -0,0 +1,101 @@
using System;
namespace Server.Engines.BulkOrders
{
public class BOBSmallEntry
{
private Type m_ItemType;
private bool m_RequireExceptional;
private BODType m_DeedType;
private BulkMaterialType m_Material;
private int m_AmountCur, m_AmountMax;
private int m_Number;
private int m_Graphic;
private int m_Price;
public Type ItemType{ get{ return m_ItemType; } }
public bool RequireExceptional{ get{ return m_RequireExceptional; } }
public BODType DeedType{ get{ return m_DeedType; } }
public BulkMaterialType Material{ get{ return m_Material; } }
public int AmountCur{ get{ return m_AmountCur; } }
public int AmountMax{ get{ return m_AmountMax; } }
public int Number{ get{ return m_Number; } }
public int Graphic{ get{ return m_Graphic; } }
public int Price{ get{ return m_Price; } set{ m_Price = value; } }
public Item Reconstruct()
{
SmallBOD bod = null;
if ( m_DeedType == BODType.Smith )
bod = new SmallSmithBOD( m_AmountCur, m_AmountMax, m_ItemType, m_Number, m_Graphic, m_RequireExceptional, m_Material );
else if ( m_DeedType == BODType.Tailor )
bod = new SmallTailorBOD( m_AmountCur, m_AmountMax, m_ItemType, m_Number, m_Graphic, m_RequireExceptional, m_Material );
return bod;
}
public BOBSmallEntry( SmallBOD bod )
{
m_ItemType = bod.Type;
m_RequireExceptional = bod.RequireExceptional;
if ( bod is SmallTailorBOD )
m_DeedType = BODType.Tailor;
else if ( bod is SmallSmithBOD )
m_DeedType = BODType.Smith;
m_Material = bod.Material;
m_AmountCur = bod.AmountCur;
m_AmountMax = bod.AmountMax;
m_Number = bod.Number;
m_Graphic = bod.Graphic;
}
public BOBSmallEntry( GenericReader reader )
{
int version = reader.ReadEncodedInt();
switch ( version )
{
case 0:
{
string type = reader.ReadString();
if ( type != null )
m_ItemType = ScriptCompiler.FindTypeByFullName( type );
m_RequireExceptional = reader.ReadBool();
m_DeedType = (BODType)reader.ReadEncodedInt();
m_Material = (BulkMaterialType)reader.ReadEncodedInt();
m_AmountCur = reader.ReadEncodedInt();
m_AmountMax = reader.ReadEncodedInt();
m_Number = reader.ReadEncodedInt();
m_Graphic = reader.ReadEncodedInt();
m_Price = reader.ReadEncodedInt();
break;
}
}
}
public void Serialize( GenericWriter writer )
{
writer.WriteEncodedInt( 0 ); // version
writer.Write( m_ItemType == null ? null : m_ItemType.FullName );
writer.Write( (bool) m_RequireExceptional );
writer.WriteEncodedInt( (int) m_DeedType );
writer.WriteEncodedInt( (int) m_Material );
writer.WriteEncodedInt( (int) m_AmountCur );
writer.WriteEncodedInt( (int) m_AmountMax );
writer.WriteEncodedInt( (int) m_Number );
writer.WriteEncodedInt( (int) m_Graphic );
writer.WriteEncodedInt( (int) m_Price );
}
}
}

View file

@ -0,0 +1,126 @@
using System;
using Server;
using Server.Items;
using Server.Gumps;
using Server.Mobiles;
namespace Server.Engines.BulkOrders
{
public class BODBuyGump : Gump
{
private PlayerMobile m_From;
private BulkOrderBook m_Book;
private object m_Object;
private int m_Price;
public override void OnResponse( Server.Network.NetState sender, RelayInfo info )
{
if ( info.ButtonID == 2 )
{
PlayerVendor pv = m_Book.RootParent as PlayerVendor;
if ( m_Book.Entries.Contains( m_Object ) && pv != null )
{
int price = 0;
VendorItem vi = pv.GetVendorItem( m_Book );
if ( vi != null && !vi.IsForSale )
{
if ( m_Object is BOBLargeEntry )
price = ((BOBLargeEntry)m_Object).Price;
else if ( m_Object is BOBSmallEntry )
price = ((BOBSmallEntry)m_Object).Price;
}
if ( price != m_Price )
{
pv.SayTo( m_From, "The price has been been changed. If you like, you may offer to purchase the item again." );
}
else if ( price == 0 )
{
pv.SayTo( m_From, 1062382 ); // The deed selected is not available.
}
else
{
Item item = null;
if ( m_Object is BOBLargeEntry )
item = ((BOBLargeEntry)m_Object).Reconstruct();
else if ( m_Object is BOBSmallEntry )
item = ((BOBSmallEntry)m_Object).Reconstruct();
if ( item == null )
{
m_From.SendMessage( "Internal error. The bulk order deed could not be reconstructed." );
}
else
{
pv.Say( m_From.Name );
Container pack = m_From.Backpack;
if ( (pack != null && pack.ConsumeTotal( typeof( Gold ), price )) || Banker.Withdraw( m_From, price ) )
{
m_Book.Entries.Remove( m_Object );
m_Book.InvalidateProperties();
pv.HoldGold += price;
if ( m_From.AddToBackpack( item ) )
m_From.SendLocalizedMessage( 1045152 ); // The bulk order deed has been placed in your backpack.
else
pv.SayTo( m_From, 503204 ); // You do not have room in your backpack for this.
if ( m_Book.Entries.Count > 0 )
m_From.SendGump( new BOBGump( m_From, m_Book ) );
else
m_From.SendLocalizedMessage( 1062381 ); // The book is empty.
}
else
{
pv.SayTo( m_From, 503205 ); // You cannot afford this item.
item.Delete();
}
}
}
}
else
{
if ( pv == null )
m_From.SendLocalizedMessage( 1062382 ); // The deed selected is not available.
else
pv.SayTo( m_From, 1062382 ); // The deed selected is not available.
}
}
else
{
m_From.SendLocalizedMessage( 503207 ); // Cancelled purchase.
}
}
public BODBuyGump( PlayerMobile from, BulkOrderBook book, object obj, int price ) : base( 100, 200 )
{
m_From = from;
m_Book = book;
m_Object = obj;
m_Price = price;
AddPage( 0 );
AddBackground( 100, 10, 300, 150, 5054 );
AddHtmlLocalized( 125, 20, 250, 24, 1019070, false, false ); // You have agreed to purchase:
AddHtmlLocalized( 125, 45, 250, 24, 1045151, false, false ); // a bulk order deed
AddHtmlLocalized( 125, 70, 250, 24, 1019071, false, false ); // for the amount of:
AddLabel( 125, 95, 0, price.ToString() );
AddButton( 250, 130, 4005, 4007, 1, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 282, 130, 100, 24, 1011012, false, false ); // CANCEL
AddButton( 120, 130, 4005, 4007, 2, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 152, 130, 100, 24, 1011036, false, false ); // OKAY
}
}
}

View file

@ -0,0 +1,10 @@
using System;
namespace Server.Engines.BulkOrders
{
public enum BODType
{
Smith,
Tailor
}
}

View file

@ -0,0 +1,271 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
using Server.Gumps;
using Server.Multis;
using Server.Prompts;
using Server.Mobiles;
using Server.ContextMenus;
namespace Server.Engines.BulkOrders
{
public class BulkOrderBook : Item, ISecurable
{
private ArrayList m_Entries;
private BOBFilter m_Filter;
private string m_BookName;
private SecureLevel m_Level;
[CommandProperty( AccessLevel.GameMaster )]
public string BookName
{
get{ return m_BookName; }
set{ m_BookName = value; InvalidateProperties(); }
}
[CommandProperty( AccessLevel.GameMaster )]
public SecureLevel Level
{
get{ return m_Level; }
set{ m_Level = value; }
}
public ArrayList Entries
{
get{ return m_Entries; }
}
public BOBFilter Filter
{
get{ return m_Filter; }
}
[Constructable]
public BulkOrderBook() : base( 0x2259 )
{
Weight = 1.0;
LootType = LootType.Blessed;
m_Entries = new ArrayList();
m_Filter = new BOBFilter();
m_Level = SecureLevel.CoOwners;
}
public override void OnDoubleClick( Mobile from )
{
if ( !from.InRange( GetWorldLocation(), 2 ) )
from.LocalOverheadMessage( Network.MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
else if ( m_Entries.Count == 0 )
from.SendLocalizedMessage( 1062381 ); // The book is empty.
else if ( from is PlayerMobile )
from.SendGump( new BOBGump( (PlayerMobile)from, this ) );
}
public override bool OnDragDrop( Mobile from, Item dropped )
{
if ( dropped is LargeBOD )
{
if ( !IsChildOf( from.Backpack ) )
{
from.SendLocalizedMessage( 1062385 ); // You must have the book in your backpack to add deeds to it.
return false;
}
else if ( m_Entries.Count < 500 )
{
m_Entries.Add( new BOBLargeEntry( (LargeBOD)dropped ) );
InvalidateProperties();
from.SendLocalizedMessage( 1062386 ); // Deed added to book.
if ( from is PlayerMobile )
from.SendGump( new BOBGump( (PlayerMobile)from, this ) );
dropped.Delete();
return true;
}
else
{
from.SendLocalizedMessage( 1062387 ); // The book is full of deeds.
return false;
}
}
else if ( dropped is SmallBOD )
{
if ( !IsChildOf( from.Backpack ) )
{
from.SendLocalizedMessage( 1062385 ); // You must have the book in your backpack to add deeds to it.
return false;
}
else if ( m_Entries.Count < 500 )
{
m_Entries.Add( new BOBSmallEntry( (SmallBOD)dropped ) );
InvalidateProperties();
from.SendLocalizedMessage( 1062386 ); // Deed added to book.
if ( from is PlayerMobile )
from.SendGump( new BOBGump( (PlayerMobile)from, this ) );
dropped.Delete();
return true;
}
else
{
from.SendLocalizedMessage( 1062387 ); // The book is full of deeds.
return false;
}
}
from.SendLocalizedMessage( 1062388 ); // That is not a bulk order deed.
return false;
}
public BulkOrderBook( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 1 ); // version
writer.Write( (int) m_Level );
writer.Write( m_BookName );
m_Filter.Serialize( writer );
writer.WriteEncodedInt( (int) m_Entries.Count );
for ( int i = 0; i < m_Entries.Count; ++i )
{
object obj = m_Entries[i];
if ( obj is BOBLargeEntry )
{
writer.WriteEncodedInt( 0 );
((BOBLargeEntry)obj).Serialize( writer );
}
else if ( obj is BOBSmallEntry )
{
writer.WriteEncodedInt( 1 );
((BOBSmallEntry)obj).Serialize( writer );
}
else
{
writer.WriteEncodedInt( -1 );
}
}
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 1:
{
m_Level = (SecureLevel)reader.ReadInt();
goto case 0;
}
case 0:
{
m_BookName = reader.ReadString();
m_Filter = new BOBFilter( reader );
int count = reader.ReadEncodedInt();
m_Entries = new ArrayList( count );
for ( int i = 0; i < count; ++i )
{
int v = reader.ReadEncodedInt();
switch ( v )
{
case 0: m_Entries.Add( new BOBLargeEntry( reader ) ); break;
case 1: m_Entries.Add( new BOBSmallEntry( reader ) ); break;
}
}
break;
}
}
}
public override void GetProperties( ObjectPropertyList list )
{
base.GetProperties( list );
list.Add( 1062344, m_Entries.Count.ToString() ); // Deeds in book: ~1_val~
if ( m_BookName != null && m_BookName.Length > 0 )
list.Add( 1062481, m_BookName ); // Book Name: ~1_val~
}
public override void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
{
base.GetContextMenuEntries( from, list );
if ( from.CheckAlive() && IsChildOf( from.Backpack ) )
list.Add( new NameBookEntry( from, this ) );
SetSecureLevelEntry.AddTo( from, this, list );
}
private class NameBookEntry : ContextMenuEntry
{
private Mobile m_From;
private BulkOrderBook m_Book;
public NameBookEntry( Mobile from, BulkOrderBook book ) : base( 6216 )
{
m_From = from;
m_Book = book;
}
public override void OnClick()
{
if ( m_From.CheckAlive() && m_Book.IsChildOf( m_From.Backpack ) )
{
m_From.Prompt = new NameBookPrompt( m_Book );
m_From.SendLocalizedMessage( 1062479 ); // Type in the new name of the book:
}
}
}
private class NameBookPrompt : Prompt
{
private BulkOrderBook m_Book;
public NameBookPrompt( BulkOrderBook book )
{
m_Book = book;
}
public override void OnResponse( Mobile from, string text )
{
if ( text.Length > 40 )
text = text.Substring( 0, 40 );
if ( from.CheckAlive() && m_Book.IsChildOf( from.Backpack ) )
{
m_Book.BookName = Utility.FixHtml( text.Trim() );
from.SendLocalizedMessage( 1062480 ); // The bulk order book's name has been changed.
}
}
public override void OnCancel( Mobile from )
{
}
}
}
}

View file

@ -0,0 +1,45 @@
using System;
using Server;
using Server.Items;
namespace Server.Engines.BulkOrders
{
public enum BulkMaterialType
{
None,
DullCopper,
ShadowIron,
Copper,
Bronze,
Gold,
Agapite,
Verite,
Valorite,
Spined,
Horned,
Barbed
}
public enum BulkGenericType
{
Iron,
Cloth,
Leather
}
public class BGTClassifier
{
public static BulkGenericType Classify( BODType deedType, Type itemType )
{
if ( deedType == BODType.Tailor )
{
if ( itemType == null || itemType.IsSubclassOf( typeof( BaseArmor ) ) || itemType.IsSubclassOf( typeof( BaseShoes ) ) )
return BulkGenericType.Leather;
return BulkGenericType.Cloth;
}
return BulkGenericType.Iron;
}
}
}

View file

@ -0,0 +1,256 @@
using System;
using System.Collections;
using Server;
using Server.Items;
namespace Server.Engines.BulkOrders
{
[TypeAlias( "Scripts.Engines.BulkOrders.LargeBOD" )]
public abstract class LargeBOD : Item
{
private int m_AmountMax;
private bool m_RequireExceptional;
private BulkMaterialType m_Material;
private LargeBulkEntry[] m_Entries;
[CommandProperty( AccessLevel.GameMaster )]
public int AmountMax{ get{ return m_AmountMax; } set{ m_AmountMax = value; InvalidateProperties(); } }
[CommandProperty( AccessLevel.GameMaster )]
public bool RequireExceptional{ get{ return m_RequireExceptional; } set{ m_RequireExceptional = value; InvalidateProperties(); } }
[CommandProperty( AccessLevel.GameMaster )]
public BulkMaterialType Material{ get{ return m_Material; } set{ m_Material = value; InvalidateProperties(); } }
public LargeBulkEntry[] Entries{ get{ return m_Entries; } set{ m_Entries = value; InvalidateProperties(); } }
[CommandProperty( AccessLevel.GameMaster )]
public bool Complete
{
get
{
for ( int i = 0; i < m_Entries.Length; ++i )
{
if ( m_Entries[i].Amount < m_AmountMax )
return false;
}
return true;
}
}
public abstract ArrayList ComputeRewards( bool full );
public abstract int ComputeGold();
public abstract int ComputeFame();
public virtual void GetRewards( out Item reward, out int gold, out int fame )
{
reward = null;
gold = ComputeGold();
fame = ComputeFame();
ArrayList rewards = ComputeRewards( false );
if ( rewards.Count > 0 )
{
reward = (Item)rewards[Utility.Random( rewards.Count )];
for ( int i = 0; i < rewards.Count; ++i )
{
if ( rewards[i] != reward )
((Item)rewards[i]).Delete();
}
}
}
public static BulkMaterialType GetRandomMaterial( BulkMaterialType start, double[] chances )
{
double random = Utility.RandomDouble();
for ( int i = 0; i < chances.Length; ++i )
{
if ( random < chances[i] )
return ( i == 0 ? BulkMaterialType.None : start + (i - 1) );
random -= chances[i];
}
return BulkMaterialType.None;
}
public override int LabelNumber{ get{ return 1045151; } } // a bulk order deed
public LargeBOD( int hue, int amountMax, bool requireExeptional, BulkMaterialType material, LargeBulkEntry[] entries ) : base( Core.AOS ? 0x2258 : 0x14EF )
{
Weight = 1.0;
Hue = hue; // Blacksmith: 0x44E; Tailoring: 0x483
LootType = LootType.Blessed;
m_AmountMax = amountMax;
m_RequireExceptional = requireExeptional;
m_Material = material;
m_Entries = entries;
}
public LargeBOD() : base( Core.AOS ? 0x2258 : 0x14EF )
{
Weight = 1.0;
LootType = LootType.Blessed;
}
public override void GetProperties( ObjectPropertyList list )
{
base.GetProperties( list );
list.Add( 1060655 ); // large bulk order
if ( m_RequireExceptional )
list.Add( 1045141 ); // All items must be exceptional.
if ( m_Material != BulkMaterialType.None )
list.Add( LargeBODGump.GetMaterialNumberFor( m_Material ) ); // All items must be made with x material.
list.Add( 1060656, m_AmountMax.ToString() ); // amount to make: ~1_val~
for ( int i = 0; i < m_Entries.Length; ++i )
list.Add( 1060658 + i, "#{0}\t{1}", m_Entries[i].Details.Number, m_Entries[i].Amount ); // ~1_val~: ~2_val~
}
public override void OnDoubleClick( Mobile from )
{
if ( IsChildOf( from.Backpack ) )
from.SendGump( new LargeBODGump( from, this ) );
else
from.SendLocalizedMessage( 1045156 ); // You must have the deed in your backpack to use it.
}
public void BeginCombine( Mobile from )
{
if ( !Complete )
from.Target = new LargeBODTarget( this );
else
from.SendLocalizedMessage( 1045166 ); // The maximum amount of requested items have already been combined to this deed.
}
public void EndCombine( Mobile from, object o )
{
if ( o is Item && ((Item)o).IsChildOf( from.Backpack ) )
{
if ( o is SmallBOD )
{
SmallBOD small = (SmallBOD)o;
LargeBulkEntry entry = null;
for ( int i = 0; entry == null && i < m_Entries.Length; ++i )
{
if ( m_Entries[i].Details.Type == small.Type )
entry = m_Entries[i];
}
if ( entry == null )
{
from.SendLocalizedMessage( 1045160 ); // That is not a bulk order for this large request.
}
else if ( m_RequireExceptional && !small.RequireExceptional )
{
from.SendLocalizedMessage( 1045161 ); // Both orders must be of exceptional quality.
}
else if ( m_Material >= BulkMaterialType.DullCopper && m_Material <= BulkMaterialType.Valorite && small.Material != m_Material )
{
from.SendLocalizedMessage( 1045162 ); // Both orders must use the same ore type.
}
else if ( m_Material >= BulkMaterialType.Spined && m_Material <= BulkMaterialType.Barbed && small.Material != m_Material )
{
from.SendLocalizedMessage( 1049351 ); // Both orders must use the same leather type.
}
else if ( m_AmountMax != small.AmountMax )
{
from.SendLocalizedMessage( 1045163 ); // The two orders have different requested amounts and cannot be combined.
}
else if ( small.AmountCur < small.AmountMax )
{
from.SendLocalizedMessage( 1045164 ); // The order to combine with is not completed.
}
else if ( entry.Amount >= m_AmountMax )
{
from.SendLocalizedMessage( 1045166 ); // The maximum amount of requested items have already been combined to this deed.
}
else
{
entry.Amount += small.AmountCur;
small.Delete();
from.SendLocalizedMessage( 1045165 ); // The orders have been combined.
from.SendGump( new LargeBODGump( from, this ) );
if ( !Complete )
BeginCombine( from );
}
}
else
{
from.SendLocalizedMessage( 1045159 ); // That is not a bulk order.
}
}
else
{
from.SendLocalizedMessage( 1045158 ); // You must have the item in your backpack to target it.
}
}
public LargeBOD( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
writer.Write( m_AmountMax );
writer.Write( m_RequireExceptional );
writer.Write( (int) m_Material );
writer.Write( (int) m_Entries.Length );
for ( int i = 0; i < m_Entries.Length; ++i )
m_Entries[i].Serialize( writer );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 0:
{
m_AmountMax = reader.ReadInt();
m_RequireExceptional = reader.ReadBool();
m_Material = (BulkMaterialType)reader.ReadInt();
m_Entries = new LargeBulkEntry[reader.ReadInt()];
for ( int i = 0; i < m_Entries.Length; ++i )
m_Entries[i] = new LargeBulkEntry( this, reader );
break;
}
}
if ( Weight == 0.0 )
Weight = 1.0;
if ( Core.AOS && ItemID == 0x14EF )
ItemID = 0x2258;
if ( Parent == null && Map == Map.Internal && Location == Point3D.Zero )
Delete();
}
}
}

View file

@ -0,0 +1,106 @@
using System;
using Server;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.BulkOrders
{
public class LargeBODAcceptGump : Gump
{
private LargeBOD m_Deed;
private Mobile m_From;
public LargeBODAcceptGump( Mobile from, LargeBOD deed ) : base( 50, 50 )
{
m_From = from;
m_Deed = deed;
m_From.CloseGump( typeof( LargeBODAcceptGump ) );
m_From.CloseGump( typeof( SmallBODAcceptGump ) );
LargeBulkEntry[] entries = deed.Entries;
AddPage( 0 );
AddBackground( 25, 10, 430, 240 + (entries.Length * 24), 5054 );
AddImageTiled( 33, 20, 413, 221 + (entries.Length * 24), 2624 );
AddAlphaRegion( 33, 20, 413, 221 + (entries.Length * 24) );
AddImage( 20, 5, 10460 );
AddImage( 430, 5, 10460 );
AddImage( 20, 225 + (entries.Length * 24), 10460 );
AddImage( 430, 225 + (entries.Length * 24), 10460 );
AddHtmlLocalized( 180, 25, 120, 20, 1045134, 0x7FFF, false, false ); // A large bulk order
AddHtmlLocalized( 40, 48, 350, 20, 1045135, 0x7FFF, false, false ); // Ah! Thanks for the goods! Would you help me out?
AddHtmlLocalized( 40, 72, 210, 20, 1045138, 0x7FFF, false, false ); // Amount to make:
AddLabel( 250, 72, 1152, deed.AmountMax.ToString() );
AddHtmlLocalized( 40, 96, 120, 20, 1045137, 0x7FFF, false, false ); // Items requested:
int y = 120;
for ( int i = 0; i < entries.Length; ++i, y += 24 )
AddHtmlLocalized( 40, y, 210, 20, entries[i].Details.Number, 0x7FFF, false, false );
if ( deed.RequireExceptional || deed.Material != BulkMaterialType.None )
{
AddHtmlLocalized( 40, y, 210, 20, 1045140, 0x7FFF, false, false ); // Special requirements to meet:
y += 24;
if ( deed.RequireExceptional )
{
AddHtmlLocalized( 40, y, 350, 20, 1045141, 0x7FFF, false, false ); // All items must be exceptional.
y += 24;
}
if ( deed.Material != BulkMaterialType.None )
{
AddHtmlLocalized( 40, y, 350, 20, GetMaterialNumberFor( deed.Material ), 0x7FFF, false, false ); // All items must be made with x material.
y += 24;
}
}
AddHtmlLocalized( 40, 192 + (entries.Length * 24), 350, 20, 1045139, 0x7FFF, false, false ); // Do you want to accept this order?
AddButton( 100, 216 + (entries.Length * 24), 4005, 4007, 1, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 135, 216 + (entries.Length * 24), 120, 20, 1006044, 0x7FFF, false, false ); // Ok
AddButton( 275, 216 + (entries.Length * 24), 4005, 4007, 0, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 310, 216 + (entries.Length * 24), 120, 20, 1011012, 0x7FFF, false, false ); // CANCEL
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( info.ButtonID == 1 ) // Ok
{
if ( m_From.PlaceInBackpack( m_Deed ) )
{
m_From.SendLocalizedMessage( 1045152 ); // The bulk order deed has been placed in your backpack.
}
else
{
m_From.SendLocalizedMessage( 1045150 ); // There is not enough room in your backpack for the deed.
m_Deed.Delete();
}
}
else
{
m_Deed.Delete();
}
}
public static int GetMaterialNumberFor( BulkMaterialType material )
{
if ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite )
return 1045142 + (int)(material - BulkMaterialType.DullCopper);
else if ( material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed )
return 1049348 + (int)(material - BulkMaterialType.Spined);
return 0;
}
}
}

View file

@ -0,0 +1,100 @@
using System;
using Server;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.BulkOrders
{
public class LargeBODGump : Gump
{
private LargeBOD m_Deed;
private Mobile m_From;
public LargeBODGump( Mobile from, LargeBOD deed ) : base( 25, 25 )
{
m_From = from;
m_Deed = deed;
m_From.CloseGump( typeof( LargeBODGump ) );
m_From.CloseGump( typeof( SmallBODGump ) );
LargeBulkEntry[] entries = deed.Entries;
AddPage( 0 );
AddBackground( 50, 10, 455, 236 + (entries.Length * 24), 5054 );
AddImageTiled( 58, 20, 438, 217 + (entries.Length * 24), 2624 );
AddAlphaRegion( 58, 20, 438, 217 + (entries.Length * 24) );
AddImage( 45, 5, 10460 );
AddImage( 480, 5, 10460 );
AddImage( 45, 221 + (entries.Length * 24), 10460 );
AddImage( 480, 221 + (entries.Length * 24), 10460 );
AddHtmlLocalized( 225, 25, 120, 20, 1045134, 0x7FFF, false, false ); // A large bulk order
AddHtmlLocalized( 75, 48, 250, 20, 1045138, 0x7FFF, false, false ); // Amount to make:
AddLabel( 275, 48, 1152, deed.AmountMax.ToString() );
AddHtmlLocalized( 75, 72, 120, 20, 1045137, 0x7FFF, false, false ); // Items requested:
AddHtmlLocalized( 275, 76, 200, 20, 1045153, 0x7FFF, false, false ); // Amount finished:
int y = 96;
for ( int i = 0; i < entries.Length; ++i )
{
LargeBulkEntry entry = entries[i];
SmallBulkEntry details = entry.Details;
AddHtmlLocalized( 75, y, 210, 20, details.Number, 0x7FFF, false, false );
AddLabel( 275, y, 0x480, entry.Amount.ToString() );
y += 24;
}
if ( deed.RequireExceptional || deed.Material != BulkMaterialType.None )
{
AddHtmlLocalized( 75, y, 200, 20, 1045140, 0x7FFF, false, false ); // Special requirements to meet:
y += 24;
}
if ( deed.RequireExceptional )
{
AddHtmlLocalized( 75, y, 300, 20, 1045141, 0x7FFF, false, false ); // All items must be exceptional.
y += 24;
}
if ( deed.Material != BulkMaterialType.None )
AddHtmlLocalized( 75, y, 300, 20, GetMaterialNumberFor( deed.Material ), 0x7FFF, false, false ); // All items must be made with x material.
AddButton( 125, 168 + (entries.Length * 24), 4005, 4007, 2, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 160, 168 + (entries.Length * 24), 300, 20, 1045155, 0x7FFF, false, false ); // Combine this deed with another deed.
AddButton( 125, 192 + (entries.Length * 24), 4005, 4007, 1, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 160, 192 + (entries.Length * 24), 120, 20, 1011441, 0x7FFF, false, false ); // EXIT
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( m_Deed.Deleted || !m_Deed.IsChildOf( m_From.Backpack ) )
return;
if ( info.ButtonID == 2 ) // Combine
{
m_From.SendGump( new LargeBODGump( m_From, m_Deed ) );
m_Deed.BeginCombine( m_From );
}
}
public static int GetMaterialNumberFor( BulkMaterialType material )
{
if ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite )
return 1045142 + (int)(material - BulkMaterialType.DullCopper);
else if ( material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed )
return 1049348 + (int)(material - BulkMaterialType.Spined);
return 0;
}
}
}

View file

@ -0,0 +1,25 @@
using System;
using Server;
using Server.Targeting;
using Server.Network;
namespace Server.Engines.BulkOrders
{
public class LargeBODTarget : Target
{
private LargeBOD m_Deed;
public LargeBODTarget( LargeBOD deed ) : base( 18, false, TargetFlags.None )
{
m_Deed = deed;
}
protected override void OnTarget( Mobile from, object targeted )
{
if ( m_Deed.Deleted || !m_Deed.IsChildOf( from.Backpack ) )
return;
m_Deed.EndCombine( from, targeted );
}
}
}

View file

@ -0,0 +1,189 @@
using System;
using System.IO;
using System.Collections;
using Server;
namespace Server.Engines.BulkOrders
{
public class LargeBulkEntry
{
private LargeBOD m_Owner;
private int m_Amount;
private SmallBulkEntry m_Details;
public LargeBOD Owner{ get{ return m_Owner; } set{ m_Owner = value; } }
public int Amount{ get{ return m_Amount; } set{ m_Amount = value; if ( m_Owner != null ) m_Owner.InvalidateProperties(); } }
public SmallBulkEntry Details{ get{ return m_Details; } }
public static SmallBulkEntry[] LargeRing
{
get{ return GetEntries( "Blacksmith", "largering" ); }
}
public static SmallBulkEntry[] LargePlate
{
get{ return GetEntries( "Blacksmith", "largeplate" ); }
}
public static SmallBulkEntry[] LargeChain
{
get{ return GetEntries( "Blacksmith", "largechain" ); }
}
public static SmallBulkEntry[] LargeAxes
{
get{ return GetEntries( "Blacksmith", "largeaxes" ); }
}
public static SmallBulkEntry[] LargeFencing
{
get{ return GetEntries( "Blacksmith", "largefencing" ); }
}
public static SmallBulkEntry[] LargeMaces
{
get{ return GetEntries( "Blacksmith", "largemaces" ); }
}
public static SmallBulkEntry[] LargePolearms
{
get{ return GetEntries( "Blacksmith", "largepolearms" ); }
}
public static SmallBulkEntry[] LargeSwords
{
get{ return GetEntries( "Blacksmith", "largeswords" ); }
}
public static SmallBulkEntry[] BoneSet
{
get{ return GetEntries( "Tailoring", "boneset" ); }
}
public static SmallBulkEntry[] Farmer
{
get{ return GetEntries( "Tailoring", "farmer" ); }
}
public static SmallBulkEntry[] FemaleLeatherSet
{
get{ return GetEntries( "Tailoring", "femaleleatherset" ); }
}
public static SmallBulkEntry[] FisherGirl
{
get{ return GetEntries( "Tailoring", "fishergirl" ); }
}
public static SmallBulkEntry[] Gypsy
{
get{ return GetEntries( "Tailoring", "gypsy" ); }
}
public static SmallBulkEntry[] HatSet
{
get{ return GetEntries( "Tailoring", "hatset" ); }
}
public static SmallBulkEntry[] Jester
{
get{ return GetEntries( "Tailoring", "jester" ); }
}
public static SmallBulkEntry[] Lady
{
get{ return GetEntries( "Tailoring", "lady" ); }
}
public static SmallBulkEntry[] MaleLeatherSet
{
get{ return GetEntries( "Tailoring", "maleleatherset" ); }
}
public static SmallBulkEntry[] Pirate
{
get{ return GetEntries( "Tailoring", "pirate" ); }
}
public static SmallBulkEntry[] ShoeSet
{
get{ return GetEntries( "Tailoring", "shoeset" ); }
}
public static SmallBulkEntry[] StuddedSet
{
get{ return GetEntries( "Tailoring", "studdedset" ); }
}
public static SmallBulkEntry[] TownCrier
{
get{ return GetEntries( "Tailoring", "towncrier" ); }
}
public static SmallBulkEntry[] Wizard
{
get{ return GetEntries( "Tailoring", "wizard" ); }
}
private static Hashtable m_Cache;
public static SmallBulkEntry[] GetEntries( string type, string name )
{
if ( m_Cache == null )
m_Cache = new Hashtable();
Hashtable table = (Hashtable)m_Cache[type];
if ( table == null )
m_Cache[type] = table = new Hashtable();
SmallBulkEntry[] entries = (SmallBulkEntry[])table[name];
if ( entries == null )
table[name] = entries = SmallBulkEntry.LoadEntries( type, name );
return entries;
}
public static LargeBulkEntry[] ConvertEntries( LargeBOD owner, SmallBulkEntry[] small )
{
LargeBulkEntry[] large = new LargeBulkEntry[small.Length];
for ( int i = 0; i < small.Length; ++i )
large[i] = new LargeBulkEntry( owner, small[i] );
return large;
}
public LargeBulkEntry( LargeBOD owner, SmallBulkEntry details )
{
m_Owner = owner;
m_Details = details;
}
public LargeBulkEntry( LargeBOD owner, GenericReader reader )
{
m_Owner = owner;
m_Amount = reader.ReadInt();
Type realType = null;
string type = reader.ReadString();
if ( type != null )
realType = ScriptCompiler.FindTypeByFullName( type );
m_Details = new SmallBulkEntry( realType, reader.ReadInt(), reader.ReadInt() );
}
public void Serialize( GenericWriter writer )
{
writer.Write( m_Amount );
writer.Write( m_Details.Type == null ? null : m_Details.Type.FullName );
writer.Write( m_Details.Number );
writer.Write( m_Details.Graphic );
}
}
}

View file

@ -0,0 +1,139 @@
using System;
using System.Collections;
using Server;
using Server.Items;
using Mat = Server.Engines.BulkOrders.BulkMaterialType;
namespace Server.Engines.BulkOrders
{
[TypeAlias( "Scripts.Engines.BulkOrders.LargeSmithBOD" )]
public class LargeSmithBOD : LargeBOD
{
public static double[] m_BlacksmithMaterialChances = new double[]
{
0.501953125, // None
0.250000000, // Dull Copper
0.125000000, // Shadow Iron
0.062500000, // Copper
0.031250000, // Bronze
0.015625000, // Gold
0.007812500, // Agapite
0.003906250, // Verite
0.001953125 // Valorite
};
public override int ComputeFame()
{
return SmithRewardCalculator.Instance.ComputeFame( this );
}
public override int ComputeGold()
{
return SmithRewardCalculator.Instance.ComputeGold( this );
}
[Constructable]
public LargeSmithBOD()
{
LargeBulkEntry[] entries;
bool useMaterials = true;
int rand = Utility.Random( 8 );
switch ( rand )
{
default:
case 0: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeRing ); break;
case 1: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargePlate ); break;
case 2: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeChain ); break;
case 3: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeAxes ); break;
case 4: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeFencing ); break;
case 5: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeMaces ); break;
case 6: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargePolearms ); break;
case 7: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeSwords ); break;
}
if( rand > 2 && rand < 8 )
useMaterials = false;
int hue = 0x44E;
int amountMax = Utility.RandomList( 10, 15, 20, 20 );
bool reqExceptional = ( 0.825 > Utility.RandomDouble() );
BulkMaterialType material;
if ( useMaterials )
material = GetRandomMaterial( BulkMaterialType.DullCopper, m_BlacksmithMaterialChances );
else
material = BulkMaterialType.None;
this.Hue = hue;
this.AmountMax = amountMax;
this.Entries = entries;
this.RequireExceptional = reqExceptional;
this.Material = material;
}
public LargeSmithBOD( int amountMax, bool reqExceptional, BulkMaterialType mat, LargeBulkEntry[] entries )
{
this.Hue = 0x44E;
this.AmountMax = amountMax;
this.Entries = entries;
this.RequireExceptional = reqExceptional;
this.Material = mat;
}
public override ArrayList ComputeRewards( bool full )
{
ArrayList list = new ArrayList();
RewardGroup rewardGroup = SmithRewardCalculator.Instance.LookupRewards( SmithRewardCalculator.Instance.ComputePoints( this ) );
if ( rewardGroup != null )
{
if ( full )
{
for ( int i = 0; i < rewardGroup.Items.Length; ++i )
{
Item item = rewardGroup.Items[i].Construct();
if ( item != null )
list.Add( item );
}
}
else
{
RewardItem rewardItem = rewardGroup.AcquireItem();
if ( rewardItem != null )
{
Item item = rewardItem.Construct();
if ( item != null )
list.Add( item );
}
}
}
return list;
}
public LargeSmithBOD( 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();
}
}
}

View file

@ -0,0 +1,134 @@
using System;
using System.Collections;
using Server;
using Server.Items;
using Mat = Server.Engines.BulkOrders.BulkMaterialType;
namespace Server.Engines.BulkOrders
{
public class LargeTailorBOD : LargeBOD
{
public static double[] m_TailoringMaterialChances = new double[]
{
0.857421875, // None
0.125000000, // Spined
0.015625000, // Horned
0.001953125 // Barbed
};
public override int ComputeFame()
{
return TailorRewardCalculator.Instance.ComputeFame( this );
}
public override int ComputeGold()
{
return TailorRewardCalculator.Instance.ComputeGold( this );
}
[Constructable]
public LargeTailorBOD()
{
LargeBulkEntry[] entries;
bool useMaterials = false;
switch ( Utility.Random( 14 ) )
{
default:
case 0: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Farmer ); break;
case 1: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.FemaleLeatherSet ); useMaterials = true; break;
case 2: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.FisherGirl ); break;
case 3: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Gypsy ); break;
case 4: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.HatSet ); break;
case 5: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Jester ); break;
case 6: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Lady ); break;
case 7: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.MaleLeatherSet ); useMaterials = true; break;
case 8: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Pirate ); break;
case 9: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.ShoeSet ); break;
case 10: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.StuddedSet ); useMaterials = true; break;
case 11: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.TownCrier ); break;
case 12: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Wizard ); break;
case 13: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.BoneSet ); useMaterials = true; break;
}
int hue = 0x483;
int amountMax = Utility.RandomList( 10, 15, 20, 20 );
bool reqExceptional = ( 0.825 > Utility.RandomDouble() );
BulkMaterialType material;
if ( useMaterials )
material = GetRandomMaterial( BulkMaterialType.Spined, m_TailoringMaterialChances );
else
material = BulkMaterialType.None;
this.Hue = hue;
this.AmountMax = amountMax;
this.Entries = entries;
this.RequireExceptional = reqExceptional;
this.Material = material;
}
public LargeTailorBOD( int amountMax, bool reqExceptional, BulkMaterialType mat, LargeBulkEntry[] entries )
{
this.Hue = 0x483;
this.AmountMax = amountMax;
this.Entries = entries;
this.RequireExceptional = reqExceptional;
this.Material = mat;
}
public override ArrayList ComputeRewards( bool full )
{
ArrayList list = new ArrayList();
RewardGroup rewardGroup = TailorRewardCalculator.Instance.LookupRewards( TailorRewardCalculator.Instance.ComputePoints( this ) );
if ( rewardGroup != null )
{
if ( full )
{
for ( int i = 0; i < rewardGroup.Items.Length; ++i )
{
Item item = rewardGroup.Items[i].Construct();
if ( item != null )
list.Add( item );
}
}
else
{
RewardItem rewardItem = rewardGroup.AcquireItem();
if ( rewardItem != null )
{
Item item = rewardItem.Construct();
if ( item != null )
list.Add( item );
}
}
}
return list;
}
public LargeTailorBOD( 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();
}
}
}

View file

@ -0,0 +1,739 @@
using System;
using Server;
using Server.Items;
namespace Server.Engines.BulkOrders
{
public delegate Item ConstructCallback( int type );
public sealed class RewardType
{
private int m_Points;
private Type[] m_Types;
public int Points{ get{ return m_Points; } }
public Type[] Types{ get{ return m_Types; } }
public RewardType( int points, params Type[] types )
{
m_Points = points;
m_Types = types;
}
public bool Contains( Type type )
{
for ( int i = 0; i < m_Types.Length; ++i )
{
if ( m_Types[i] == type )
return true;
}
return false;
}
}
public sealed class RewardItem
{
private int m_Weight;
private ConstructCallback m_Constructor;
private int m_Type;
public int Weight{ get{ return m_Weight; } }
public ConstructCallback Constructor{ get{ return m_Constructor; } }
public int Type{ get{ return m_Type; } }
public RewardItem( int weight, ConstructCallback constructor ) : this( weight, constructor, 0 )
{
}
public RewardItem( int weight, ConstructCallback constructor, int type )
{
m_Weight = weight;
m_Constructor = constructor;
m_Type = type;
}
public Item Construct()
{
try{ return m_Constructor( m_Type ); }
catch{ return null; }
}
}
public sealed class RewardGroup
{
private int m_Points;
private RewardItem[] m_Items;
public int Points{ get{ return m_Points; } }
public RewardItem[] Items{ get{ return m_Items; } }
public RewardGroup( int points, params RewardItem[] items )
{
m_Points = points;
m_Items = items;
}
public RewardItem AcquireItem()
{
if ( m_Items.Length == 0 )
return null;
else if ( m_Items.Length == 1 )
return m_Items[0];
int totalWeight = 0;
for ( int i = 0; i < m_Items.Length; ++i )
totalWeight += m_Items[i].Weight;
int randomWeight = Utility.Random( totalWeight );
for ( int i = 0; i < m_Items.Length; ++i )
{
RewardItem item = m_Items[i];
if ( randomWeight < item.Weight )
return item;
randomWeight -= item.Weight;
}
return null;
}
}
public abstract class RewardCalculator
{
private RewardGroup[] m_Groups;
public RewardGroup[] Groups{ get{ return m_Groups; } set{ m_Groups = value; } }
public abstract int ComputePoints( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type );
public abstract int ComputeGold( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type );
public virtual int ComputeFame( SmallBOD bod )
{
int points = ComputePoints( bod ) / 50;
return points * points;
}
public virtual int ComputeFame( LargeBOD bod )
{
int points = ComputePoints( bod ) / 50;
return points * points;
}
public virtual int ComputePoints( SmallBOD bod )
{
return ComputePoints( bod.AmountMax, bod.RequireExceptional, bod.Material, 1, bod.Type );
}
public virtual int ComputePoints( LargeBOD bod )
{
return ComputePoints( bod.AmountMax, bod.RequireExceptional, bod.Material, bod.Entries.Length, bod.Entries[0].Details.Type );
}
public virtual int ComputeGold( SmallBOD bod )
{
return ComputeGold( bod.AmountMax, bod.RequireExceptional, bod.Material, 1, bod.Type );
}
public virtual int ComputeGold( LargeBOD bod )
{
return ComputeGold( bod.AmountMax, bod.RequireExceptional, bod.Material, bod.Entries.Length, bod.Entries[0].Details.Type );
}
public virtual RewardGroup LookupRewards( int points )
{
for ( int i = m_Groups.Length - 1; i >= 1; --i )
{
RewardGroup group = m_Groups[i];
if ( points >= group.Points )
return group;
}
return m_Groups[0];
}
public virtual int LookupTypePoints( RewardType[] types, Type type )
{
for ( int i = 0; i < types.Length; ++i )
{
if ( types[i].Contains( type ) )
return types[i].Points;
}
return 0;
}
public RewardCalculator()
{
}
}
public sealed class SmithRewardCalculator : RewardCalculator
{
#region Constructors
private static readonly ConstructCallback SturdyShovel = new ConstructCallback( CreateSturdyShovel );
private static readonly ConstructCallback SturdyPickaxe = new ConstructCallback( CreateSturdyPickaxe );
private static readonly ConstructCallback MiningGloves = new ConstructCallback( CreateMiningGloves );
private static readonly ConstructCallback GargoylesPickaxe = new ConstructCallback( CreateGargoylesPickaxe );
private static readonly ConstructCallback ProspectorsTool = new ConstructCallback( CreateProspectorsTool );
private static readonly ConstructCallback PowderOfTemperament = new ConstructCallback( CreatePowderOfTemperament );
private static readonly ConstructCallback RunicHammer = new ConstructCallback( CreateRunicHammer );
private static readonly ConstructCallback PowerScroll = new ConstructCallback( CreatePowerScroll );
private static readonly ConstructCallback ColoredAnvil = new ConstructCallback( CreateColoredAnvil );
private static readonly ConstructCallback AncientHammer = new ConstructCallback( CreateAncientHammer );
private static Item CreateSturdyShovel( int type )
{
return new SturdyShovel();
}
private static Item CreateSturdyPickaxe( int type )
{
return new SturdyPickaxe();
}
private static Item CreateMiningGloves( int type )
{
if ( type == 1 )
return new LeatherGlovesOfMining( 1 );
else if ( type == 3 )
return new StuddedGlovesOfMining( 3 );
else if ( type == 5 )
return new RingmailGlovesOfMining( 5 );
throw new InvalidOperationException();
}
private static Item CreateGargoylesPickaxe( int type )
{
return new GargoylesPickaxe();
}
private static Item CreateProspectorsTool( int type )
{
return new ProspectorsTool();
}
private static Item CreatePowderOfTemperament( int type )
{
return new PowderOfTemperament();
}
private static Item CreateRunicHammer( int type )
{
if ( type >= 1 && type <= 8 )
return new RunicHammer( CraftResource.Iron + type, Core.AOS ? ( 55 - (type*5) ) : 50 );
throw new InvalidOperationException();
}
private static Item CreatePowerScroll( int type )
{
if ( type == 5 || type == 10 || type == 15 || type == 20 )
return new PowerScroll( SkillName.Blacksmith, 100 + type );
throw new InvalidOperationException();
}
private static Item CreateColoredAnvil( int type )
{
// Generate an anvil deed, not an actual anvil.
//return new ColoredAnvilDeed();
return new ColoredAnvil();
}
private static Item CreateAncientHammer( int type )
{
if ( type == 10 || type == 15 || type == 30 || type == 60 )
return new AncientSmithyHammer( type );
throw new InvalidOperationException();
}
#endregion
public static readonly SmithRewardCalculator Instance = new SmithRewardCalculator();
private RewardType[] m_Types = new RewardType[]
{
// Armors
new RewardType( 200, typeof( RingmailGloves ), typeof( RingmailChest ), typeof( RingmailArms ), typeof( RingmailLegs ) ),
new RewardType( 300, typeof( ChainCoif ), typeof( ChainLegs ), typeof( ChainChest ) ),
new RewardType( 400, typeof( PlateArms ), typeof( PlateLegs ), typeof( PlateHelm ), typeof( PlateGorget ), typeof( PlateGloves ), typeof( PlateChest ) ),
// Weapons
new RewardType( 200, typeof( Bardiche ), typeof( Halberd ) ),
new RewardType( 300, typeof( Dagger ), typeof( ShortSpear ), typeof( Spear ), typeof( WarFork ), typeof( Kryss ) ), //OSI put the dagger in there. Odd, ain't it.
new RewardType( 350, typeof( Axe ), typeof( BattleAxe ), typeof( DoubleAxe ), typeof( ExecutionersAxe ), typeof( LargeBattleAxe ), typeof( TwoHandedAxe ) ),
new RewardType( 350, typeof( Broadsword ), typeof( Cutlass ), typeof( Katana ), typeof( Longsword ), typeof( Scimitar ), typeof( ThinLongsword ), typeof( VikingSword ) ),
new RewardType( 350, typeof( WarAxe ), typeof( HammerPick ), typeof( Mace ), typeof( Maul ), typeof( WarHammer ), typeof( WarMace ) )
};
public override int ComputePoints( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type )
{
int points = 0;
if ( quantity == 10 )
points += 10;
else if ( quantity == 15 )
points += 25;
else if ( quantity == 20 )
points += 50;
if ( exceptional )
points += 200;
if ( itemCount > 1 )
points += LookupTypePoints( m_Types, type );
if ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite )
points += 200 + (50 * (material - BulkMaterialType.DullCopper));
return points;
}
private static int[][][] m_GoldTable = new int[][][]
{
new int[][] // 1-part (regular)
{
new int[]{ 150, 250, 250, 400, 400, 750, 750, 1200, 1200 },
new int[]{ 225, 375, 375, 600, 600, 1125, 1125, 1800, 1800 },
new int[]{ 300, 500, 750, 800, 1050, 1500, 2250, 2400, 4000 }
},
new int[][] // 1-part (exceptional)
{
new int[]{ 250, 400, 400, 750, 750, 1500, 1500, 3000, 3000 },
new int[]{ 375, 600, 600, 1125, 1125, 2250, 2250, 4500, 4500 },
new int[]{ 500, 800, 1200, 1500, 2500, 3000, 6000, 6000, 12000 }
},
new int[][] // Ringmail (regular)
{
new int[]{ 3000, 5000, 5000, 7500, 7500, 10000, 10000, 15000, 15000 },
new int[]{ 4500, 7500, 7500, 11250, 11500, 15000, 15000, 22500, 22500 },
new int[]{ 6000, 10000, 15000, 15000, 20000, 20000, 30000, 30000, 50000 }
},
new int[][] // Ringmail (exceptional)
{
new int[]{ 5000, 10000, 10000, 15000, 15000, 25000, 25000, 50000, 50000 },
new int[]{ 7500, 15000, 15000, 22500, 22500, 37500, 37500, 75000, 75000 },
new int[]{ 10000, 20000, 30000, 30000, 50000, 50000, 100000, 100000, 200000 }
},
new int[][] // Chainmail (regular)
{
new int[]{ 4000, 7500, 7500, 10000, 10000, 15000, 15000, 25000, 25000 },
new int[]{ 6000, 11250, 11250, 15000, 15000, 22500, 22500, 37500, 37500 },
new int[]{ 8000, 15000, 20000, 20000, 30000, 30000, 50000, 50000, 100000 }
},
new int[][] // Chainmail (exceptional)
{
new int[]{ 7500, 15000, 15000, 25000, 25000, 50000, 50000, 100000, 100000 },
new int[]{ 11250, 22500, 22500, 37500, 37500, 75000, 75000, 150000, 150000 },
new int[]{ 15000, 30000, 50000, 50000, 100000, 100000, 200000, 200000, 200000 }
},
new int[][] // Platemail (regular)
{
new int[]{ 5000, 10000, 10000, 15000, 15000, 25000, 25000, 50000, 50000 },
new int[]{ 7500, 15000, 15000, 22500, 22500, 37500, 37500, 75000, 75000 },
new int[]{ 10000, 20000, 30000, 30000, 50000, 50000, 100000, 100000, 200000 }
},
new int[][] // Platemail (exceptional)
{
new int[]{ 10000, 25000, 25000, 50000, 50000, 100000, 100000, 100000, 100000 },
new int[]{ 15000, 37500, 37500, 75000, 75000, 150000, 150000, 150000, 150000 },
new int[]{ 20000, 50000, 100000, 100000, 200000, 200000, 200000, 200000, 200000 }
},
new int[][] // 2-part weapons (regular)
{
new int[]{ 3000, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 4500, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 6000, 0, 0, 0, 0, 0, 0, 0, 0 }
},
new int[][] // 2-part weapons (exceptional)
{
new int[]{ 5000, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 7500, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 10000, 0, 0, 0, 0, 0, 0, 0, 0 }
},
new int[][] // 5-part weapons (regular)
{
new int[]{ 4000, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 6000, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 8000, 0, 0, 0, 0, 0, 0, 0, 0 }
},
new int[][] // 5-part weapons (exceptional)
{
new int[]{ 7500, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 11250, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 15000, 0, 0, 0, 0, 0, 0, 0, 0 }
},
new int[][] // 6-part weapons (regular)
{
new int[]{ 4000, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 6000, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 10000, 0, 0, 0, 0, 0, 0, 0, 0 }
},
new int[][] // 6-part weapons (exceptional)
{
new int[]{ 7500, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 11250, 0, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 15000, 0, 0, 0, 0, 0, 0, 0, 0 }
}
};
private int ComputeType( Type type, int itemCount )
{
// Item count of 1 means it's a small BOD.
if ( itemCount == 1 )
return 0;
int typeIdx;
// Loop through the RewardTypes defined earlier and find the correct one.
for ( typeIdx = 0; typeIdx < 7; ++typeIdx )
{
if ( m_Types[typeIdx].Contains( type ) )
break;
}
// Types 5, 6 and 7 are Large Weapon BODs with the same rewards.
if ( typeIdx > 5 )
typeIdx = 5;
return ( typeIdx + 1 ) * 2;
}
public override int ComputeGold( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type )
{
int[][][] goldTable = m_GoldTable;
int typeIndex = ComputeType( type, itemCount );
int quanIndex = ( quantity == 20 ? 2 : quantity == 15 ? 1 : 0 );
int mtrlIndex = ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite ) ? 1 + (int)(material - BulkMaterialType.DullCopper) : 0;
if ( exceptional )
typeIndex++;
int gold = goldTable[typeIndex][quanIndex][mtrlIndex];
int min = (gold * 9) / 10;
int max = (gold * 10) / 9;
return Utility.RandomMinMax( min, max );
}
public SmithRewardCalculator()
{
Groups = new RewardGroup[]
{
new RewardGroup( 0, new RewardItem( 1, SturdyShovel ) ),
new RewardGroup( 25, new RewardItem( 1, SturdyPickaxe ) ),
new RewardGroup( 50, new RewardItem( 45, SturdyShovel ), new RewardItem( 45, SturdyPickaxe ), new RewardItem( 10, MiningGloves, 1 ) ),
new RewardGroup( 200, new RewardItem( 45, GargoylesPickaxe ), new RewardItem( 45, ProspectorsTool ), new RewardItem( 10, MiningGloves, 3 ) ),
new RewardGroup( 400, new RewardItem( 2, GargoylesPickaxe ), new RewardItem( 2, ProspectorsTool ), new RewardItem( 1, PowderOfTemperament ) ),
new RewardGroup( 450, new RewardItem( 9, PowderOfTemperament ), new RewardItem( 1, MiningGloves, 5 ) ),
new RewardGroup( 500, new RewardItem( 1, RunicHammer, 1 ) ),
new RewardGroup( 550, new RewardItem( 3, RunicHammer, 1 ), new RewardItem( 2, RunicHammer, 2 ) ),
new RewardGroup( 600, new RewardItem( 1, RunicHammer, 2 ) ),
new RewardGroup( 625, new RewardItem( 3, RunicHammer, 2 ), new RewardItem( 6, PowerScroll, 5 ), new RewardItem( 1, ColoredAnvil ) ),
new RewardGroup( 650, new RewardItem( 1, RunicHammer, 3 ) ),
new RewardGroup( 675, new RewardItem( 1, ColoredAnvil ), new RewardItem( 6, PowerScroll, 10 ), new RewardItem( 3, RunicHammer, 3 ) ),
new RewardGroup( 700, new RewardItem( 1, RunicHammer, 4 ) ),
new RewardGroup( 750, new RewardItem( 1, AncientHammer, 10 ) ),
new RewardGroup( 800, new RewardItem( 1, PowerScroll, 15 ) ),
new RewardGroup( 850, new RewardItem( 1, AncientHammer, 15 ) ),
new RewardGroup( 900, new RewardItem( 1, PowerScroll, 20 ) ),
new RewardGroup( 950, new RewardItem( 1, RunicHammer, 5 ) ),
new RewardGroup( 1000, new RewardItem( 1, AncientHammer, 30 ) ),
new RewardGroup( 1050, new RewardItem( 1, RunicHammer, 6 ) ),
new RewardGroup( 1100, new RewardItem( 1, AncientHammer, 60 ) ),
new RewardGroup( 1150, new RewardItem( 1, RunicHammer, 7 ) ),
new RewardGroup( 1200, new RewardItem( 1, RunicHammer, 8 ) )
};
}
}
public sealed class TailorRewardCalculator : RewardCalculator
{
#region Constructors
private static readonly ConstructCallback Cloth = new ConstructCallback( CreateCloth );
private static readonly ConstructCallback Sandals = new ConstructCallback( CreateSandals );
private static readonly ConstructCallback StretchedHide = new ConstructCallback( CreateStretchedHide );
private static readonly ConstructCallback RunicKit = new ConstructCallback( CreateRunicKit );
private static readonly ConstructCallback Tapestry = new ConstructCallback( CreateTapestry );
private static readonly ConstructCallback PowerScroll = new ConstructCallback( CreatePowerScroll );
private static readonly ConstructCallback BearRug = new ConstructCallback( CreateBearRug );
private static readonly ConstructCallback ClothingBlessDeed = new ConstructCallback( CreateCBD );
private static int[][] m_ClothHues = new int[][]
{
new int[]{ 0x483, 0x48C, 0x488, 0x48A },
new int[]{ 0x495, 0x48B, 0x486, 0x485 },
new int[]{ 0x48D, 0x490, 0x48E, 0x491 },
new int[]{ 0x48F, 0x494, 0x484, 0x497 },
new int[]{ 0x489, 0x47F, 0x482, 0x47E }
};
private static Item CreateCloth( int type )
{
if ( type >= 0 && type < m_ClothHues.Length )
{
UncutCloth cloth = new UncutCloth( 100 );
cloth.Hue = m_ClothHues[type][Utility.Random( m_ClothHues[type].Length )];
return cloth;
}
throw new InvalidOperationException();
}
private static int[] m_SandalHues = new int[]
{
0x489, 0x47F, 0x482,
0x47E, 0x48F, 0x494,
0x484, 0x497
};
private static Item CreateSandals( int type )
{
return new Sandals( m_SandalHues[Utility.Random( m_SandalHues.Length )] );
}
private static Item CreateStretchedHide( int type )
{
switch ( Utility.Random( 4 ) )
{
default:
case 0: return new SmallStretchedHideEastDeed();
case 1: return new SmallStretchedHideSouthDeed();
case 2: return new MediumStretchedHideEastDeed();
case 3: return new MediumStretchedHideSouthDeed();
}
}
private static Item CreateTapestry( int type )
{
switch ( Utility.Random( 4 ) )
{
default:
case 0: return new LightFlowerTapestryEastDeed();
case 1: return new LightFlowerTapestrySouthDeed();
case 2: return new DarkFlowerTapestryEastDeed();
case 3: return new DarkFlowerTapestrySouthDeed();
}
}
private static Item CreateBearRug( int type )
{
switch ( Utility.Random( 4 ) )
{
default:
case 0: return new BrownBearRugEastDeed();
case 1: return new BrownBearRugSouthDeed();
case 2: return new PolarBearRugEastDeed();
case 3: return new PolarBearRugSouthDeed();
}
}
private static Item CreateRunicKit( int type )
{
if ( type >= 1 && type <= 3 )
return new RunicSewingKit( CraftResource.RegularLeather + type, 60 - (type*15) );
throw new InvalidOperationException();
}
private static Item CreatePowerScroll( int type )
{
if ( type == 5 || type == 10 || type == 15 || type == 20 )
return new PowerScroll( SkillName.Tailoring, 100 + type );
throw new InvalidOperationException();
}
private static Item CreateCBD( int type )
{
return new ClothingBlessDeed();
}
#endregion
public static readonly TailorRewardCalculator Instance = new TailorRewardCalculator();
public override int ComputePoints( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type )
{
int points = 0;
if ( quantity == 10 )
points += 10;
else if ( quantity == 15 )
points += 25;
else if ( quantity == 20 )
points += 50;
if ( exceptional )
points += 100;
if ( itemCount == 4 )
points += 300;
else if ( itemCount == 5 )
points += 400;
else if ( itemCount == 6 )
points += 500;
if ( material == BulkMaterialType.Spined )
points += 50;
else if ( material == BulkMaterialType.Horned )
points += 100;
else if ( material == BulkMaterialType.Barbed )
points += 150;
return points;
}
private static int[][][] m_AosGoldTable = new int[][][]
{
new int[][] // 1-part (regular)
{
new int[]{ 150, 150, 300, 300 },
new int[]{ 225, 225, 450, 450 },
new int[]{ 300, 400, 600, 750 }
},
new int[][] // 1-part (exceptional)
{
new int[]{ 300, 300, 600, 600 },
new int[]{ 450, 450, 900, 900 },
new int[]{ 600, 750, 1200, 1800 }
},
new int[][] // 4-part (regular)
{
new int[]{ 4000, 4000, 5000, 5000 },
new int[]{ 6000, 6000, 7500, 7500 },
new int[]{ 8000, 10000, 10000, 15000 }
},
new int[][] // 4-part (exceptional)
{
new int[]{ 5000, 5000, 7500, 7500 },
new int[]{ 7500, 7500, 11250, 11250 },
new int[]{ 10000, 15000, 15000, 20000 }
},
new int[][] // 5-part (regular)
{
new int[]{ 5000, 5000, 7500, 7500 },
new int[]{ 7500, 7500, 11250, 11250 },
new int[]{ 10000, 15000, 15000, 20000 }
},
new int[][] // 5-part (exceptional)
{
new int[]{ 7500, 7500, 10000, 10000 },
new int[]{ 11250, 11250, 15000, 15000 },
new int[]{ 15000, 20000, 20000, 30000 }
},
new int[][] // 6-part (regular)
{
new int[]{ 7500, 7500, 10000, 10000 },
new int[]{ 11250, 11250, 15000, 15000 },
new int[]{ 15000, 20000, 20000, 30000 }
},
new int[][] // 6-part (exceptional)
{
new int[]{ 10000, 10000, 15000, 15000 },
new int[]{ 15000, 15000, 22500, 22500 },
new int[]{ 20000, 30000, 30000, 50000 }
}
};
private static int[][][] m_OldGoldTable = new int[][][]
{
new int[][] // 1-part (regular)
{
new int[]{ 150, 150, 300, 300 },
new int[]{ 225, 225, 450, 450 },
new int[]{ 300, 400, 600, 750 }
},
new int[][] // 1-part (exceptional)
{
new int[]{ 300, 300, 600, 600 },
new int[]{ 450, 450, 900, 900 },
new int[]{ 600, 750, 1200, 1800 }
},
new int[][] // 4-part (regular)
{
new int[]{ 3000, 3000, 4000, 4000 },
new int[]{ 4500, 4500, 6000, 6000 },
new int[]{ 6000, 8000, 8000, 10000 }
},
new int[][] // 4-part (exceptional)
{
new int[]{ 4000, 4000, 5000, 5000 },
new int[]{ 6000, 6000, 7500, 7500 },
new int[]{ 8000, 10000, 10000, 15000 }
},
new int[][] // 5-part (regular)
{
new int[]{ 4000, 4000, 5000, 5000 },
new int[]{ 6000, 6000, 7500, 7500 },
new int[]{ 8000, 10000, 10000, 15000 }
},
new int[][] // 5-part (exceptional)
{
new int[]{ 5000, 5000, 7500, 7500 },
new int[]{ 7500, 7500, 11250, 11250 },
new int[]{ 10000, 15000, 15000, 20000 }
},
new int[][] // 6-part (regular)
{
new int[]{ 5000, 5000, 7500, 7500 },
new int[]{ 7500, 7500, 11250, 11250 },
new int[]{ 10000, 15000, 15000, 20000 }
},
new int[][] // 6-part (exceptional)
{
new int[]{ 7500, 7500, 10000, 10000 },
new int[]{ 11250, 11250, 15000, 15000 },
new int[]{ 15000, 20000, 20000, 30000 }
}
};
public override int ComputeGold( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type )
{
int[][][] goldTable = ( Core.AOS ? m_AosGoldTable : m_OldGoldTable );
int typeIndex = (( itemCount == 6 ? 3 : itemCount == 5 ? 2 : itemCount == 4 ? 1 : 0 ) * 2) + (exceptional ? 1 : 0);
int quanIndex = ( quantity == 20 ? 2 : quantity == 15 ? 1 : 0 );
int mtrlIndex = ( material == BulkMaterialType.Barbed ? 3 : material == BulkMaterialType.Horned ? 2 : material == BulkMaterialType.Spined ? 1 : 0 );
int gold = goldTable[typeIndex][quanIndex][mtrlIndex];
int min = (gold * 9) / 10;
int max = (gold * 10) / 9;
return Utility.RandomMinMax( min, max );
}
public TailorRewardCalculator()
{
Groups = new RewardGroup[]
{
new RewardGroup( 0, new RewardItem( 1, Cloth, 0 ) ),
new RewardGroup( 50, new RewardItem( 1, Cloth, 1 ) ),
new RewardGroup( 100, new RewardItem( 1, Cloth, 2 ) ),
new RewardGroup( 150, new RewardItem( 9, Cloth, 3 ), new RewardItem( 1, Sandals ) ),
new RewardGroup( 200, new RewardItem( 4, Cloth, 4 ), new RewardItem( 1, Sandals ) ),
new RewardGroup( 300, new RewardItem( 1, StretchedHide ) ),
new RewardGroup( 350, new RewardItem( 1, RunicKit, 1 ) ),
new RewardGroup( 400, new RewardItem( 2, PowerScroll, 5 ), new RewardItem( 3, Tapestry ) ),
new RewardGroup( 450, new RewardItem( 1, BearRug ) ),
new RewardGroup( 500, new RewardItem( 1, PowerScroll, 10 ) ),
new RewardGroup( 550, new RewardItem( 1, ClothingBlessDeed ) ),
new RewardGroup( 575, new RewardItem( 1, PowerScroll, 15 ) ),
new RewardGroup( 600, new RewardItem( 1, RunicKit, 2 ) ),
new RewardGroup( 650, new RewardItem( 1, PowerScroll, 20 ) ),
new RewardGroup( 700, new RewardItem( 1, RunicKit, 3 ) )
};
}
}
}

View file

@ -0,0 +1,279 @@
using System;
using System.Collections;
using Server;
using Server.Items;
namespace Server.Engines.BulkOrders
{
[TypeAlias( "Scripts.Engines.BulkOrders.SmallBOD" )]
public abstract class SmallBOD : Item
{
private int m_AmountCur, m_AmountMax;
private Type m_Type;
private int m_Number;
private int m_Graphic;
private bool m_RequireExceptional;
private BulkMaterialType m_Material;
[CommandProperty( AccessLevel.GameMaster )]
public int AmountCur{ get{ return m_AmountCur; } set{ m_AmountCur = value; InvalidateProperties(); } }
[CommandProperty( AccessLevel.GameMaster )]
public int AmountMax{ get{ return m_AmountMax; } set{ m_AmountMax = value; InvalidateProperties(); } }
[CommandProperty( AccessLevel.GameMaster )]
public Type Type{ get{ return m_Type; } set{ m_Type = value; } }
[CommandProperty( AccessLevel.GameMaster )]
public int Number{ get{ return m_Number; } set{ m_Number = value; InvalidateProperties(); } }
[CommandProperty( AccessLevel.GameMaster )]
public int Graphic{ get{ return m_Graphic; } set{ m_Graphic = value; } }
[CommandProperty( AccessLevel.GameMaster )]
public bool RequireExceptional{ get{ return m_RequireExceptional; } set{ m_RequireExceptional = value; InvalidateProperties(); } }
[CommandProperty( AccessLevel.GameMaster )]
public BulkMaterialType Material{ get{ return m_Material; } set{ m_Material = value; InvalidateProperties(); } }
[CommandProperty( AccessLevel.GameMaster )]
public bool Complete{ get{ return ( m_AmountCur == m_AmountMax ); } }
public override int LabelNumber{ get{ return 1045151; } } // a bulk order deed
[Constructable]
public SmallBOD( int hue, int amountMax, Type type, int number, int graphic, bool requireExeptional, BulkMaterialType material ) : base( Core.AOS ? 0x2258 : 0x14EF )
{
Weight = 1.0;
Hue = hue; // Blacksmith: 0x44E; Tailoring: 0x483
LootType = LootType.Blessed;
m_AmountMax = amountMax;
m_Type = type;
m_Number = number;
m_Graphic = graphic;
m_RequireExceptional = requireExeptional;
m_Material = material;
}
public SmallBOD() : base( Core.AOS ? 0x2258 : 0x14EF )
{
Weight = 1.0;
LootType = LootType.Blessed;
}
public static BulkMaterialType GetRandomMaterial( BulkMaterialType start, double[] chances )
{
double random = Utility.RandomDouble();
for ( int i = 0; i < chances.Length; ++i )
{
if ( random < chances[i] )
return ( i == 0 ? BulkMaterialType.None : start + (i - 1) );
random -= chances[i];
}
return BulkMaterialType.None;
}
public override void GetProperties( ObjectPropertyList list )
{
base.GetProperties( list );
list.Add( 1060654 ); // small bulk order
if ( m_RequireExceptional )
list.Add( 1045141 ); // All items must be exceptional.
if ( m_Material != BulkMaterialType.None )
list.Add( SmallBODGump.GetMaterialNumberFor( m_Material ) ); // All items must be made with x material.
list.Add( 1060656, m_AmountMax.ToString() ); // amount to make: ~1_val~
list.Add( 1060658, "#{0}\t{1}", m_Number, m_AmountCur ); // ~1_val~: ~2_val~
}
public override void OnDoubleClick( Mobile from )
{
if ( IsChildOf( from.Backpack ) )
from.SendGump( new SmallBODGump( from, this ) );
else
from.SendLocalizedMessage( 1045156 ); // You must have the deed in your backpack to use it.
}
public void BeginCombine( Mobile from )
{
if ( m_AmountCur < m_AmountMax )
from.Target = new SmallBODTarget( this );
else
from.SendLocalizedMessage( 1045166 ); // The maximum amount of requested items have already been combined to this deed.
}
public abstract ArrayList ComputeRewards( bool full );
public abstract int ComputeGold();
public abstract int ComputeFame();
public virtual void GetRewards( out Item reward, out int gold, out int fame )
{
reward = null;
gold = ComputeGold();
fame = ComputeFame();
ArrayList rewards = ComputeRewards( false );
if ( rewards.Count > 0 )
{
reward = (Item)rewards[Utility.Random( rewards.Count )];
for ( int i = 0; i < rewards.Count; ++i )
{
if ( rewards[i] != reward )
((Item)rewards[i]).Delete();
}
}
}
public static BulkMaterialType GetMaterial( CraftResource resource )
{
switch ( resource )
{
case CraftResource.DullCopper: return BulkMaterialType.DullCopper;
case CraftResource.ShadowIron: return BulkMaterialType.ShadowIron;
case CraftResource.Copper: return BulkMaterialType.Copper;
case CraftResource.Bronze: return BulkMaterialType.Bronze;
case CraftResource.Gold: return BulkMaterialType.Gold;
case CraftResource.Agapite: return BulkMaterialType.Agapite;
case CraftResource.Verite: return BulkMaterialType.Verite;
case CraftResource.Valorite: return BulkMaterialType.Valorite;
case CraftResource.SpinedLeather: return BulkMaterialType.Spined;
case CraftResource.HornedLeather: return BulkMaterialType.Horned;
case CraftResource.BarbedLeather: return BulkMaterialType.Barbed;
}
return BulkMaterialType.None;
}
public void EndCombine( Mobile from, object o )
{
if ( o is Item && ((Item)o).IsChildOf( from.Backpack ) )
{
Type objectType = o.GetType();
if ( m_AmountCur >= m_AmountMax )
{
from.SendLocalizedMessage( 1045166 ); // The maximum amount of requested items have already been combined to this deed.
}
else if ( m_Type == null || (objectType != m_Type && !objectType.IsSubclassOf( m_Type )) || (!(o is BaseWeapon) && !(o is BaseArmor) && !(o is BaseClothing)) )
{
from.SendLocalizedMessage( 1045169 ); // The item is not in the request.
}
else
{
BulkMaterialType material = BulkMaterialType.None;
if ( o is BaseArmor )
material = GetMaterial( ((BaseArmor)o).Resource );
else if ( o is BaseClothing )
material = GetMaterial( ((BaseClothing)o).Resource );
if ( m_Material >= BulkMaterialType.DullCopper && m_Material <= BulkMaterialType.Valorite && material != m_Material )
{
from.SendLocalizedMessage( 1045168 ); // The item is not made from the requested ore.
}
else if ( m_Material >= BulkMaterialType.Spined && m_Material <= BulkMaterialType.Barbed && material != m_Material )
{
from.SendLocalizedMessage( 1049352 ); // The item is not made from the requested leather type.
}
else
{
bool isExceptional = false;
if ( o is BaseWeapon )
isExceptional = ( ((BaseWeapon)o).Quality == WeaponQuality.Exceptional );
else if ( o is BaseArmor )
isExceptional = ( ((BaseArmor)o).Quality == ArmorQuality.Exceptional );
else if ( o is BaseClothing )
isExceptional = ( ((BaseClothing)o).Quality == ClothingQuality.Exceptional );
if ( m_RequireExceptional && !isExceptional )
{
from.SendLocalizedMessage( 1045167 ); // The item must be exceptional.
}
else
{
((Item)o).Delete();
++AmountCur;
from.SendLocalizedMessage( 1045170 ); // The item has been combined with the deed.
from.SendGump( new SmallBODGump( from, this ) );
if ( m_AmountCur < m_AmountMax )
BeginCombine( from );
}
}
}
}
else
{
from.SendLocalizedMessage( 1045158 ); // You must have the item in your backpack to target it.
}
}
public SmallBOD( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
writer.Write( m_AmountCur );
writer.Write( m_AmountMax );
writer.Write( m_Type == null ? null : m_Type.FullName );
writer.Write( m_Number );
writer.Write( m_Graphic );
writer.Write( m_RequireExceptional );
writer.Write( (int) m_Material );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 0:
{
m_AmountCur = reader.ReadInt();
m_AmountMax = reader.ReadInt();
string type = reader.ReadString();
if ( type != null )
m_Type = ScriptCompiler.FindTypeByFullName( type );
m_Number = reader.ReadInt();
m_Graphic = reader.ReadInt();
m_RequireExceptional = reader.ReadBool();
m_Material = (BulkMaterialType)reader.ReadInt();
break;
}
}
if ( Weight == 0.0 )
Weight = 1.0;
if ( Core.AOS && ItemID == 0x14EF )
ItemID = 0x2258;
if ( Parent == null && Map == Map.Internal && Location == Point3D.Zero )
Delete();
}
}
}

View file

@ -0,0 +1,93 @@
using System;
using Server;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.BulkOrders
{
public class SmallBODAcceptGump : Gump
{
private SmallBOD m_Deed;
private Mobile m_From;
public SmallBODAcceptGump( Mobile from, SmallBOD deed ) : base( 50, 50 )
{
m_From = from;
m_Deed = deed;
m_From.CloseGump( typeof( LargeBODAcceptGump ) );
m_From.CloseGump( typeof( SmallBODAcceptGump ) );
AddPage( 0 );
AddBackground( 25, 10, 430, 264, 5054 );
AddImageTiled( 33, 20, 413, 245, 2624 );
AddAlphaRegion( 33, 20, 413, 245 );
AddImage( 20, 5, 10460 );
AddImage( 430, 5, 10460 );
AddImage( 20, 249, 10460 );
AddImage( 430, 249, 10460 );
AddHtmlLocalized( 190, 25, 120, 20, 1045133, 0x7FFF, false, false ); // A bulk order
AddHtmlLocalized( 40, 48, 350, 20, 1045135, 0x7FFF, false, false ); // Ah! Thanks for the goods! Would you help me out?
AddHtmlLocalized( 40, 72, 210, 20, 1045138, 0x7FFF, false, false ); // Amount to make:
AddLabel( 250, 72, 1152, deed.AmountMax.ToString() );
AddHtmlLocalized( 40, 96, 120, 20, 1045136, 0x7FFF, false, false ); // Item requested:
AddItem( 385, 96, deed.Graphic );
AddHtmlLocalized( 40, 120, 210, 20, deed.Number, 0xFFFFFF, false, false );
if ( deed.RequireExceptional || deed.Material != BulkMaterialType.None )
{
AddHtmlLocalized( 40, 144, 210, 20, 1045140, 0x7FFF, false, false ); // Special requirements to meet:
if ( deed.RequireExceptional )
AddHtmlLocalized( 40, 168, 350, 20, 1045141, 0x7FFF, false, false ); // All items must be exceptional.
if ( deed.Material != BulkMaterialType.None )
AddHtmlLocalized( 40, deed.RequireExceptional ? 192 : 168, 350, 20, GetMaterialNumberFor( deed.Material ), 0x7FFF, false, false ); // All items must be made with x material.
}
AddHtmlLocalized( 40, 216, 350, 20, 1045139, 0x7FFF, false, false ); // Do you want to accept this order?
AddButton( 100, 240, 4005, 4007, 1, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 135, 240, 120, 20, 1006044, 0x7FFF, false, false ); // Ok
AddButton( 275, 240, 4005, 4007, 0, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 310, 240, 120, 20, 1011012, 0x7FFF, false, false ); // CANCEL
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( info.ButtonID == 1 ) // Ok
{
if ( m_From.PlaceInBackpack( m_Deed ) )
{
m_From.SendLocalizedMessage( 1045152 ); // The bulk order deed has been placed in your backpack.
}
else
{
m_From.SendLocalizedMessage( 1045150 ); // There is not enough room in your backpack for the deed.
m_Deed.Delete();
}
}
else
{
m_Deed.Delete();
}
}
public static int GetMaterialNumberFor( BulkMaterialType material )
{
if ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite )
return 1045142 + (int)(material - BulkMaterialType.DullCopper);
else if ( material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed )
return 1049348 + (int)(material - BulkMaterialType.Spined);
return 0;
}
}
}

View file

@ -0,0 +1,83 @@
using System;
using Server;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.BulkOrders
{
public class SmallBODGump : Gump
{
private SmallBOD m_Deed;
private Mobile m_From;
public SmallBODGump( Mobile from, SmallBOD deed ) : base( 25, 25 )
{
m_From = from;
m_Deed = deed;
m_From.CloseGump( typeof( LargeBODGump ) );
m_From.CloseGump( typeof( SmallBODGump ) );
AddPage( 0 );
AddBackground( 50, 10, 455, 260, 5054 );
AddImageTiled( 58, 20, 438, 241, 2624 );
AddAlphaRegion( 58, 20, 438, 241 );
AddImage( 45, 5, 10460 );
AddImage( 480, 5, 10460 );
AddImage( 45, 245, 10460 );
AddImage( 480, 245, 10460 );
AddHtmlLocalized( 225, 25, 120, 20, 1045133, 0x7FFF, false, false ); // A bulk order
AddHtmlLocalized( 75, 48, 250, 20, 1045138, 0x7FFF, false, false ); // Amount to make:
AddLabel( 275, 48, 1152, deed.AmountMax.ToString() );
AddHtmlLocalized( 275, 76, 200, 20, 1045153, 0x7FFF, false, false ); // Amount finished:
AddHtmlLocalized( 75, 72, 120, 20, 1045136, 0x7FFF, false, false ); // Item requested:
AddItem( 410, 72, deed.Graphic );
AddHtmlLocalized( 75, 96, 210, 20, deed.Number, 0x7FFF, false, false );
AddLabel( 275, 96, 0x480, deed.AmountCur.ToString() );
if ( deed.RequireExceptional || deed.Material != BulkMaterialType.None )
AddHtmlLocalized( 75, 120, 200, 20, 1045140, 0x7FFF, false, false ); // Special requirements to meet:
if ( deed.RequireExceptional )
AddHtmlLocalized( 75, 144, 300, 20, 1045141, 0x7FFF, false, false ); // All items must be exceptional.
if ( deed.Material != BulkMaterialType.None )
AddHtmlLocalized( 75, deed.RequireExceptional ? 168 : 144, 300, 20, GetMaterialNumberFor( deed.Material ), 0x7FFF, false, false ); // All items must be made with x material.
AddButton( 125, 192, 4005, 4007, 2, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 160, 192, 300, 20, 1045154, 0x7FFF, false, false ); // Combine this deed with the item requested.
AddButton( 125, 216, 4005, 4007, 1, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 160, 216, 120, 20, 1011441, 0x7FFF, false, false ); // EXIT
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( m_Deed.Deleted || !m_Deed.IsChildOf( m_From.Backpack ) )
return;
if ( info.ButtonID == 2 ) // Combine
{
m_From.SendGump( new SmallBODGump( m_From, m_Deed ) );
m_Deed.BeginCombine( m_From );
}
}
public static int GetMaterialNumberFor( BulkMaterialType material )
{
if ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite )
return 1045142 + (int)(material - BulkMaterialType.DullCopper);
else if ( material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed )
return 1049348 + (int)(material - BulkMaterialType.Spined);
return 0;
}
}
}

View file

@ -0,0 +1,25 @@
using System;
using Server;
using Server.Targeting;
using Server.Network;
namespace Server.Engines.BulkOrders
{
public class SmallBODTarget : Target
{
private SmallBOD m_Deed;
public SmallBODTarget( SmallBOD deed ) : base( 18, false, TargetFlags.None )
{
m_Deed = deed;
}
protected override void OnTarget( Mobile from, object targeted )
{
if ( m_Deed.Deleted || !m_Deed.IsChildOf( from.Backpack ) )
return;
m_Deed.EndCombine( from, targeted );
}
}
}

View file

@ -0,0 +1,111 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Server;
namespace Server.Engines.BulkOrders
{
public class SmallBulkEntry
{
private Type m_Type;
private int m_Number;
private int m_Graphic;
public Type Type{ get{ return m_Type; } }
public int Number{ get{ return m_Number; } }
public int Graphic{ get{ return m_Graphic; } }
public SmallBulkEntry( Type type, int number, int graphic )
{
m_Type = type;
m_Number = number;
m_Graphic = graphic;
}
public static SmallBulkEntry[] BlacksmithWeapons
{
get{ return GetEntries( "Blacksmith", "weapons" ); }
}
public static SmallBulkEntry[] BlacksmithArmor
{
get{ return GetEntries( "Blacksmith", "armor" ); }
}
public static SmallBulkEntry[] TailorCloth
{
get{ return GetEntries( "Tailoring", "cloth" ); }
}
public static SmallBulkEntry[] TailorLeather
{
get{ return GetEntries( "Tailoring", "leather" ); }
}
private static Hashtable m_Cache;
public static SmallBulkEntry[] GetEntries( string type, string name )
{
if ( m_Cache == null )
m_Cache = new Hashtable();
Hashtable table = (Hashtable)m_Cache[type];
if ( table == null )
m_Cache[type] = table = new Hashtable();
SmallBulkEntry[] entries = (SmallBulkEntry[])table[name];
if ( entries == null )
table[name] = entries = LoadEntries( type, name );
return entries;
}
public static SmallBulkEntry[] LoadEntries( string type, string name )
{
return LoadEntries( String.Format( "Data/Bulk Orders/{0}/{1}.cfg", type, name ) );
}
public static SmallBulkEntry[] LoadEntries( string path )
{
path = Path.Combine( Core.BaseDirectory, path );
List<SmallBulkEntry> list = new List<SmallBulkEntry>();
if ( File.Exists( path ) )
{
using ( StreamReader ip = new StreamReader( path ) )
{
string line;
while ( (line = ip.ReadLine()) != null )
{
if ( line.Length == 0 || line.StartsWith( "#" ) )
continue;
try
{
string[] split = line.Split( '\t' );
if ( split.Length >= 2 )
{
Type type = ScriptCompiler.FindTypeByName( split[0] );
int graphic = Utility.ToInt32( split[split.Length - 1] );
if ( type != null && graphic > 0 )
list.Add( new SmallBulkEntry( type, 1020000 + graphic, graphic ) );
}
}
catch
{
}
}
}
}
return list.ToArray();
}
}
}

View file

@ -0,0 +1,244 @@
using System;
using System.Collections;
using Server;
using Server.Items;
using Server.Engines.Craft;
using Mat = Server.Engines.BulkOrders.BulkMaterialType;
namespace Server.Engines.BulkOrders
{
[TypeAlias( "Scripts.Engines.BulkOrders.SmallSmithBOD" )]
public class SmallSmithBOD : SmallBOD
{
public static double[] m_BlacksmithMaterialChances = new double[]
{
0.501953125, // None
0.250000000, // Dull Copper
0.125000000, // Shadow Iron
0.062500000, // Copper
0.031250000, // Bronze
0.015625000, // Gold
0.007812500, // Agapite
0.003906250, // Verite
0.001953125 // Valorite
};
public override int ComputeFame()
{
return SmithRewardCalculator.Instance.ComputeFame( this );
}
public override int ComputeGold()
{
return SmithRewardCalculator.Instance.ComputeGold( this );
}
public override ArrayList ComputeRewards( bool full )
{
ArrayList list = new ArrayList();
RewardGroup rewardGroup = SmithRewardCalculator.Instance.LookupRewards( SmithRewardCalculator.Instance.ComputePoints( this ) );
if ( rewardGroup != null )
{
if ( full )
{
for ( int i = 0; i < rewardGroup.Items.Length; ++i )
{
Item item = rewardGroup.Items[i].Construct();
if ( item != null )
list.Add( item );
}
}
else
{
RewardItem rewardItem = rewardGroup.AcquireItem();
if ( rewardItem != null )
{
Item item = rewardItem.Construct();
if ( item != null )
list.Add( item );
}
}
}
return list;
}
public static SmallSmithBOD CreateRandomFor( Mobile m )
{
SmallBulkEntry[] entries;
bool useMaterials;
if ( useMaterials = Utility.RandomBool() )
entries = SmallBulkEntry.BlacksmithArmor;
else
entries = SmallBulkEntry.BlacksmithWeapons;
if ( entries.Length > 0 )
{
double theirSkill = m.Skills[SkillName.Blacksmith].Base;
int amountMax;
if ( theirSkill >= 70.1 )
amountMax = Utility.RandomList( 10, 15, 20, 20 );
else if ( theirSkill >= 50.1 )
amountMax = Utility.RandomList( 10, 15, 15, 20 );
else
amountMax = Utility.RandomList( 10, 10, 15, 20 );
BulkMaterialType material = BulkMaterialType.None;
if ( useMaterials && theirSkill >= 70.1 )
{
for ( int i = 0; i < 20; ++i )
{
BulkMaterialType check = GetRandomMaterial( BulkMaterialType.DullCopper, m_BlacksmithMaterialChances );
double skillReq = 0.0;
switch ( check )
{
case BulkMaterialType.DullCopper: skillReq = 65.0; break;
case BulkMaterialType.ShadowIron: skillReq = 70.0; break;
case BulkMaterialType.Copper: skillReq = 75.0; break;
case BulkMaterialType.Bronze: skillReq = 80.0; break;
case BulkMaterialType.Gold: skillReq = 85.0; break;
case BulkMaterialType.Agapite: skillReq = 90.0; break;
case BulkMaterialType.Verite: skillReq = 95.0; break;
case BulkMaterialType.Valorite: skillReq = 100.0; break;
case BulkMaterialType.Spined: skillReq = 65.0; break;
case BulkMaterialType.Horned: skillReq = 80.0; break;
case BulkMaterialType.Barbed: skillReq = 99.0; break;
}
if ( theirSkill >= skillReq )
{
material = check;
break;
}
}
}
double excChance = 0.0;
if ( theirSkill >= 70.1 )
excChance = (theirSkill + 80.0) / 200.0;
bool reqExceptional = ( excChance > Utility.RandomDouble() );
CraftSystem system = DefBlacksmithy.CraftSystem;
ArrayList validEntries = new ArrayList();
for ( int i = 0; i < entries.Length; ++i )
{
CraftItem item = system.CraftItems.SearchFor( entries[i].Type );
if ( item != null )
{
bool allRequiredSkills = true;
double chance = item.GetSuccessChance( m, null, system, false, ref allRequiredSkills );
if ( allRequiredSkills && chance >= 0.0 )
{
if ( reqExceptional )
chance = item.GetExceptionalChance( system, chance, m );
if ( chance > 0.0 )
validEntries.Add( entries[i] );
}
}
}
if ( validEntries.Count > 0 )
{
SmallBulkEntry entry = (SmallBulkEntry)validEntries[Utility.Random( validEntries.Count )];
return new SmallSmithBOD( entry, material, amountMax, reqExceptional );
}
}
return null;
}
private SmallSmithBOD( SmallBulkEntry entry, BulkMaterialType material, int amountMax, bool reqExceptional )
{
this.Hue = 0x44E;
this.AmountMax = amountMax;
this.Type = entry.Type;
this.Number = entry.Number;
this.Graphic = entry.Graphic;
this.RequireExceptional = reqExceptional;
this.Material = material;
}
[Constructable]
public SmallSmithBOD()
{
SmallBulkEntry[] entries;
bool useMaterials;
if ( useMaterials = Utility.RandomBool() )
entries = SmallBulkEntry.BlacksmithArmor;
else
entries = SmallBulkEntry.BlacksmithWeapons;
if ( entries.Length > 0 )
{
int hue = 0x44E;
int amountMax = Utility.RandomList( 10, 15, 20 );
BulkMaterialType material;
if ( useMaterials )
material = GetRandomMaterial( BulkMaterialType.DullCopper, m_BlacksmithMaterialChances );
else
material = BulkMaterialType.None;
bool reqExceptional = Utility.RandomBool() || (material == BulkMaterialType.None);
SmallBulkEntry entry = entries[Utility.Random( entries.Length )];
this.Hue = hue;
this.AmountMax = amountMax;
this.Type = entry.Type;
this.Number = entry.Number;
this.Graphic = entry.Graphic;
this.RequireExceptional = reqExceptional;
this.Material = material;
}
}
public SmallSmithBOD( int amountCur, int amountMax, Type type, int number, int graphic, bool reqExceptional, BulkMaterialType mat )
{
this.Hue = 0x44E;
this.AmountMax = amountMax;
this.AmountCur = amountCur;
this.Type = type;
this.Number = number;
this.Graphic = graphic;
this.RequireExceptional = reqExceptional;
this.Material = mat;
}
public SmallSmithBOD( 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();
}
}
}

View file

@ -0,0 +1,236 @@
using System;
using System.Collections;
using Server;
using Server.Items;
using Server.Engines.Craft;
namespace Server.Engines.BulkOrders
{
public class SmallTailorBOD : SmallBOD
{
public static double[] m_TailoringMaterialChances = new double[]
{
0.857421875, // None
0.125000000, // Spined
0.015625000, // Horned
0.001953125 // Barbed
};
public override int ComputeFame()
{
return TailorRewardCalculator.Instance.ComputeFame( this );
}
public override int ComputeGold()
{
return TailorRewardCalculator.Instance.ComputeGold( this );
}
public override ArrayList ComputeRewards( bool full )
{
ArrayList list = new ArrayList();
RewardGroup rewardGroup = TailorRewardCalculator.Instance.LookupRewards( TailorRewardCalculator.Instance.ComputePoints( this ) );
if ( rewardGroup != null )
{
if ( full )
{
for ( int i = 0; i < rewardGroup.Items.Length; ++i )
{
Item item = rewardGroup.Items[i].Construct();
if ( item != null )
list.Add( item );
}
}
else
{
RewardItem rewardItem = rewardGroup.AcquireItem();
if ( rewardItem != null )
{
Item item = rewardItem.Construct();
if ( item != null )
list.Add( item );
}
}
}
return list;
}
public static SmallTailorBOD CreateRandomFor( Mobile m )
{
SmallBulkEntry[] entries;
bool useMaterials;
double theirSkill = m.Skills[SkillName.Tailoring].Base;
if ( useMaterials = Utility.RandomBool() && theirSkill >= 6.2 ) // Ugly, but the easiest leather BOD is Leather Cap which requires at least 6.2 skill.
entries = SmallBulkEntry.TailorLeather;
else
entries = SmallBulkEntry.TailorCloth;
if ( entries.Length > 0 )
{
int amountMax;
if ( theirSkill >= 70.1 )
amountMax = Utility.RandomList( 10, 15, 20, 20 );
else if ( theirSkill >= 50.1 )
amountMax = Utility.RandomList( 10, 15, 15, 20 );
else
amountMax = Utility.RandomList( 10, 10, 15, 20 );
BulkMaterialType material = BulkMaterialType.None;
if ( useMaterials && theirSkill >= 70.1 )
{
for ( int i = 0; i < 20; ++i )
{
BulkMaterialType check = GetRandomMaterial( BulkMaterialType.Spined, m_TailoringMaterialChances );
double skillReq = 0.0;
switch ( check )
{
case BulkMaterialType.DullCopper: skillReq = 65.0; break;
case BulkMaterialType.Bronze: skillReq = 80.0; break;
case BulkMaterialType.Gold: skillReq = 85.0; break;
case BulkMaterialType.Agapite: skillReq = 90.0; break;
case BulkMaterialType.Verite: skillReq = 95.0; break;
case BulkMaterialType.Valorite: skillReq = 100.0; break;
case BulkMaterialType.Spined: skillReq = 65.0; break;
case BulkMaterialType.Horned: skillReq = 80.0; break;
case BulkMaterialType.Barbed: skillReq = 99.0; break;
}
if ( theirSkill >= skillReq )
{
material = check;
break;
}
}
}
double excChance = 0.0;
if ( theirSkill >= 70.1 )
excChance = (theirSkill + 80.0) / 200.0;
bool reqExceptional = ( excChance > Utility.RandomDouble() );
CraftSystem system = DefTailoring.CraftSystem;
ArrayList validEntries = new ArrayList();
for ( int i = 0; i < entries.Length; ++i )
{
CraftItem item = system.CraftItems.SearchFor( entries[i].Type );
if ( item != null )
{
bool allRequiredSkills = true;
double chance = item.GetSuccessChance( m, null, system, false, ref allRequiredSkills );
if ( allRequiredSkills && chance >= 0.0 )
{
if ( reqExceptional )
chance = item.GetExceptionalChance( system, chance, m );
if ( chance > 0.0 )
validEntries.Add( entries[i] );
}
}
}
if ( validEntries.Count > 0 )
{
SmallBulkEntry entry = (SmallBulkEntry)validEntries[Utility.Random( validEntries.Count )];
return new SmallTailorBOD( entry, material, amountMax, reqExceptional );
}
}
return null;
}
private SmallTailorBOD( SmallBulkEntry entry, BulkMaterialType material, int amountMax, bool reqExceptional )
{
this.Hue = 0x483;
this.AmountMax = amountMax;
this.Type = entry.Type;
this.Number = entry.Number;
this.Graphic = entry.Graphic;
this.RequireExceptional = reqExceptional;
this.Material = material;
}
[Constructable]
public SmallTailorBOD()
{
SmallBulkEntry[] entries;
bool useMaterials;
if ( useMaterials = Utility.RandomBool() )
entries = SmallBulkEntry.TailorLeather;
else
entries = SmallBulkEntry.TailorCloth;
if ( entries.Length > 0 )
{
int hue = 0x483;
int amountMax = Utility.RandomList( 10, 15, 20 );
BulkMaterialType material;
if ( useMaterials )
material = GetRandomMaterial( BulkMaterialType.Spined, m_TailoringMaterialChances );
else
material = BulkMaterialType.None;
bool reqExceptional = Utility.RandomBool() || (material == BulkMaterialType.None);
SmallBulkEntry entry = entries[Utility.Random( entries.Length )];
this.Hue = hue;
this.AmountMax = amountMax;
this.Type = entry.Type;
this.Number = entry.Number;
this.Graphic = entry.Graphic;
this.RequireExceptional = reqExceptional;
this.Material = material;
}
}
public SmallTailorBOD( int amountCur, int amountMax, Type type, int number, int graphic, bool reqExceptional, BulkMaterialType mat )
{
this.Hue = 0x483;
this.AmountMax = amountMax;
this.AmountCur = amountCur;
this.Type = type;
this.Number = number;
this.Graphic = graphic;
this.RequireExceptional = reqExceptional;
this.Material = mat;
}
public SmallTailorBOD( 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();
}
}
}

View file

@ -0,0 +1,58 @@
using System;
using System.Collections;
using Server;
using Server.Items;
namespace Server.Engines.CannedEvil
{
public class ChampionAltar : PentagramAddon
{
private ChampionSpawn m_Spawn;
public ChampionAltar( ChampionSpawn spawn )
{
m_Spawn = spawn;
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if ( m_Spawn != null )
m_Spawn.Delete();
}
public ChampionAltar( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
writer.Write( m_Spawn );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 0:
{
m_Spawn = reader.ReadItem() as ChampionSpawn;
if ( m_Spawn == null )
Delete();
break;
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more