tass23 submitted a new resource:

Bestiary (Needs updating/fixing) - Listing for all shard mobiles.

This was a great addon for creating html pages for each mob on a shard. With all the recent updates, this addon is completely broken. This download includes the very old Ultima.dll that will run the addon. If anyone feels like updating this, I'm sure it would be a welcome addition to anyone's shard.

NOTES: I noticed that the latest Ultima.dll has removed a few items that this particular addon is looking for, which is why it won't work. The other issue is that mobs that are created as...

Read more about this resource...
 
I got this working fine with my server I want to release it but I still have some updating to do then im going to release it for servuo with updated ultima.dll

my biggest problem am having is I have to add all servuos new monsters so stop causing errors lol
 
I am getting this error when starting it up now after fixing everything else .
----------------------------------------------------------------------------
ServUO - [http://www.servuo.com] Version 0.5, Build 5362.30282
Publish
Core: Optimizing for 4 64-bit processors
RandomImpl: CSPRandom (Software)
OpenUO Error: Client files not found.
Scripts: Compiling C# scripts...done (cached)
Scripts: Skipping VB.NET Scripts...done (use -vb to enable)
Scripts: Verifying...
Finished (3992 items, 998 mobiles, 11 customs) (1.75 seconds)
Regions: Loading...done
World: Loading...done (0 items, 0 mobiles, 0 customs) (0.05 seconds)
Error:
System.Reflection.TargetInvocationException: Exception has been thrown by the ta
rget of an invocation. ---> System.TypeInitializationException: The type initial
izer for 'Server.Bestiary.MobileEntry' threw an exception. ---> System.IO.Direct
oryNotFoundException: Attempted to access a path that is not on the disk.
at Ultima.Client.GetFilePath(String file)
at Ultima.StringList..ctor(String language)
at Server.Bestiary.MobileEntry..cctor()
--- End of inner exception stack trace ---
at Server.Bestiary.MobileEntry..ctor(Type type)
at Server.Bestiary.Bestiary.Generate()
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments,
Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Objec
t[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invoke
Attr, Binder binder, Object[] parameters, CultureInfo culture)
at Server.ScriptCompiler.Invoke(String method)
at Server.Core.Main(String[] args)
This exception is fatal, press return to exit
 
Looks like its not finding your client files. Somewhere in the script it probably looks for a path to your client files and it is set incorrectly.
 
Awesome Dragon! Nice to hear someone picked this up and is working on it. It really is a great addon for any shard. I tied it to an in-game bestiary as well, before it broke.
 
well besides when I take out the Bestiary system servuo loads fine.. so am sure has to do with something in its files if I cant figure it out ill post the code with ultima.dll see if any one can figure it out but am trying :)
 
As I recall, comparing the original Ultima.dll with the current one, there was a few things completely missing from the new one that the bestiary was tied to in the original. A similar problem happened with Xanthos Auction system the last time the Ultima.dll was updated.
 
Well I'm going to post what I have fixed with ultima.dll hoping some one can try fix path error it gives me but besides that system all compiles fine
 
I dont have sources to the Ultima.dll files, but there must be a way to either modify the script to the new dll or rename the old one to be used again for the system, or some variation of that..
 
I've got the old one that works with the system and of course the new one. I think I included the old one and the new one with this package.
 
Its not enough to have the Ultima.dll, we need the source code for it. It appears to be calling a path that is invalid and we need to be able to modify the dll to fix that.

Or figure out what its doing and create a new dll, hehe
 
http://ultimasdk.codeplex.com/ here is the source code was renamed to ultima sdk then renamed to open uo... any way here is what I have done with scripts the ones in the file is much newer then the ones was posted here..like I said the hole server compiles but then when goes to show the ip it crashes
 
Im sure if someone that knows, could decompile the Ultima.dll that was originally used and retrieve the source code in tact just fine. I just have never done anything like that.. but thought I'd through it out there..
 
This could be the Ultima.dll you are wanting. I found it in my archive, dated 2005. It is both the compiled Ultima.dll and source.
 

Attachments

  • Ultima-dll.rar
    48 KB · Views: 16
@Dian Thanks for posting this, it's a step in the right direction. :)
Do you have the source for the updated dll file too by chance? They need to be merged into a new dll for this system to work again. Or the system needs to be re-written to only use the new dll.
 
The new one can be found pretty easy still, I dont think I have it myself. I posted this one thinking it could be used to pull whatever it contained that this system used, and either rewrite it or add it to the new DLL. Or.. just include this one within the Bestiary system as part of it as raw code, I dont know.

I just found this in my vault and realized it is most likely the one this script was written with. Seemed to be about the same time frames.
 
I am not 100% but I think so, like mentioned earlier here, it changed to UltimaSDK and then the OpenUO. Should be able to figure out a way to fix it though with that old DLL source I posted though, I hope. Im pretty sure you wont find that source anywhere on the net..
 
Yeah, I have been unable to locate it so far myself. The old dll you posted @Dian had more than a few systems that depended on various code it contained, this one and Xanthos Auction System as well are two that I know off the top of my head. Mark or Zippy at RunUO might have it though if anyone knows how to reach one of those guys.
 
Im confused, the new one is not the one in OpenUO? Do you have the new dll? If you have the new one and using Dians old one I can probably get you the source code for both
 
The source for the ultimasdk_version 1.0.5 (The one the bestiary uses) and ultimssdk_version 4.3.2 (The one that UOFiddler 4.6 with UOP support uses)
I hope you guys can fix this and repost the new .dll

Download The File Here
 
Here you guys go. Working version. I haven't changed the xml file in there so have no idea if it works with any mobs not using basecreature as suggested in the first post.

Here is an example of the output: http://shard.li/bestiary
 

Attachments

  • Bestiary.rar
    1.6 MB · Views: 58
It's been awhile since I've installed the system, but I'm sure I've got it installed (going over my notes from the original install).
Code:
Error:
System.Reflection.TargetInvocationException: Exception has been thrown by the ta
rget of an invocation. ---> System.TypeInitializationException: The type initial
izer for 'Server.Bestiary.MobileEntry' threw an exception. ---> System.IO.Direct
oryNotFoundException: Attempted to access a path that is not on the disk.
   at Ultima.Client.GetFilePath(String file)
   at Ultima.StringList..ctor(String language)
   at Server.Bestiary.MobileEntry..cctor()
   --- End of inner exception stack trace ---
   at Server.Bestiary.MobileEntry..ctor(Type type)
   at Server.Bestiary.Bestiary.Generate()
   at Server.Bestiary.Bestiary.Initialize()
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Ob
ject target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAt
tributes, RuntimeType typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Obj
ect target, Object[] arguments, Signature sig, MethodAttributes methodAttributes
, RuntimeType typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invoke
Attr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisib
ilityChecks)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invoke
Attr, Binder binder, Object[] parameters, CultureInfo culture)
   at Server.ScriptCompiler.Invoke(String method)
   at Server.Core.Main(String[] args)

Normally this just means there's a directory path that's incorrect, but nothing in the scripts indicate an issue, so I'm thinking its because of a path in the dll. I'll try it with a clean ServUO package too.

EDIT:
Works on a bare bones ServUO package though. So The question is, what path in the combined dll caused this?
 
Last edited:
It's been awhile since I've installed the system, but I'm sure I've got it installed (going over my notes from the original install).

Normally this just means there's a directory path that's incorrect, but nothing in the scripts indicate an issue, so I'm thinking its because of a path in the dll. I'll try it with a clean ServUO package too.

EDIT:
Works on a bare bones ServUO package though. So The question is, what path in the combined dll caused this?

That is odd that it worked with a fresh install and not your working install. I tried on 3 servuo shards before I uploaded that file and it was working on all 3.

Are you sure you are using ultima.dll from the rar I uploaded?

If I get time this week I will convert the system to use openUO instead of ultima.sdk
 
@dmurphy
Yeah, I tried it with all three dlls I have. The first two wouldn't even get to the World Loading...(no surprise, but thought I'd give it a shot) and the third (the one you combined) bombed out at World Loading with the above error. Now, as I said, that's usually a directory path error, but there's nothing in the scripts that needs changing for that, so it has to be something in the dll file. I just wondered what it was and if it's possible to yank that out and put it in the script (in case people have different installs) then they could just change that path, like for the hues.mul in the Bestiary.cs file.
I'm very thankful you combined the dlls though dude, that is greatly appreciated!
 
@dmurphy
Yeah, I tried it with all three dlls I have. The first two wouldn't even get to the World Loading...(no surprise, but thought I'd give it a shot) and the third (the one you combined) bombed out at World Loading with the above error. Now, as I said, that's usually a directory path error, but there's nothing in the scripts that needs changing for that, so it has to be something in the dll file. I just wondered what it was and if it's possible to yank that out and put it in the script (in case people have different installs) then they could just change that path, like for the hues.mul in the Bestiary.cs file.
I'm very thankful you combined the dlls though dude, that is greatly appreciated!

Yeah it is definitely a directory problem. However the dll file gets the directory from the registry which is what is puzzling me as it would be the same in both the fresh install and the shard it didn't work in.

Unfortunately I hit my head against OpenUO for a few hours today only to find out that the portion that would be needed for this system is not actually finished so that's a dead end and is out of my scope to complete it so we are stuck with using Ultima.dll

That reminds me actually, Ultima.dll can only read the mul files and not the newer file types. You have those, right?
 
Yeah it is definitely a directory problem. However the dll file gets the directory from the registry which is what is puzzling me as it would be the same in both the fresh install and the shard it didn't work in.

Unfortunately I hit my head against OpenUO for a few hours today only to find out that the portion that would be needed for this system is not actually finished so that's a dead end and is out of my scope to complete it so we are stuck with using Ultima.dll

That reminds me actually, Ultima.dll can only read the mul files and not the newer file types. You have those, right?
Yeah, I've got the muls and the uop side-by-side. It's very possible then that the reason this is failing is because the install I'm working with isn't actually installed (it's a copy of my client files that my server is running). This wasn't an issue with the old dll.
 
Yep, old thread, but latest repo, with the updated files now creates this error:
Code:
Errors:
 + Customs/Bestiary/MobileEntry.cs:
    CS1061: Line 616: 'Ultima.StringList' does not contain a definition for 'Tab
le' and no extension method 'Table' accepting a first argument of type 'Ultima.S
tringList' could be found (are you missing a using directive or an assembly refe
rence?)
    CS1501: Line 1012: No overload for method 'GetAnimation' takes 5 arguments
    CS1501: Line 1032: No overload for method 'DrawText' takes 3 arguments
    CS1501: Line 1036: No overload for method 'DrawText' takes 3 arguments
Scripts: One or more scripts failed to compile or no script files were found.

That is using the Ultima.dll Murph fixed and uploaded here.

This is the current MobileEntry.cs:
Code:
//#define DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

using Server.Mobiles;
using Server.Items;

using Ultima;
namespace Server.Bestiary
{
	public enum MetadataToken
	{
		String		= 0x07000000,

		MemberRef	= 0x0A000000,
		MethodRef	= 0x06000000,
		
		Method		= MemberRef | MethodRef
	};

	public delegate void MethodHandler( MobileEntry m, int paramCount );

	public sealed class MobileEntry
	{
		#region [Static]
		private static Bitmap m_BorderImage			= new Bitmap( "Data/Bestiary/layer_top.png" );
		private static Bitmap m_Background			= new Bitmap( "Data/Bestiary/layer_bottom.jpg" );
		private static Bitmap m_WaterMark			= new Bitmap( "Data/Bestiary/watermark.png" );
		private static EncoderParameters m_EncoderParameter = new EncoderParameters();
		private static StringList m_Cliloc			= new StringList( "enu" );
		private static ImageCodecInfo m_Encoder;
		private static Dictionary<string, string> m_Templates = new Dictionary<string, string>();

		internal static ImageAttributes imgAttrs = new ImageAttributes();
		
		internal static float[][] alphaBlendMatrix = new float[][] {
				new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f },	// Red		100%
				new float[] { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f },	// Green	100%
				new float[] { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f },	// Blue		100%
				new float[] { 0.0f, 0.0f, 0.0f, .075f, 0.0f },	// Alpha	7.5%
				new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }	// Gamma	100%
			};

		private static Dictionary<string, MethodHandler> m_Handlers = new Dictionary<string, MethodHandler>();
		private static MethodHandler m_BlankHandler = delegate( MobileEntry m, int paramCount )	{/*supress the unregistered handler message in debug mode, TODO!*/};

		// gets the hue to be applied from a datafile, from Pandora's Box
		public static Hue GetHue( int index )
		{
			string huesFile = Core.FindDataFile( "hues.mul" );

			if( ( huesFile == null ) || !File.Exists( huesFile ) )
			{
				return null;
			}

			Hue hue = null;

			using( FileStream stream = new FileStream( huesFile, FileMode.Open, FileAccess.Read, FileShare.Read ) )
			{
				BinaryReader reader = new BinaryReader( stream );

				int offset = index / 8;
				int remainder = index % 8;
				int range = ( offset * 0x2c4 ) + ( remainder * 0x58 );

				if( ( range + 0x58 ) < stream.Length )
				{
					stream.Seek( (long)range, SeekOrigin.Begin );
					hue = new Hue( index, reader );
				}
			}
			return hue;
		}
		
		static MobileEntry()
		{
			#region [Method handlers]
			m_Handlers[ "set_Body" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_BodyId = m.Pop<int>();
					};

			m_Handlers[ "SetStr" ] =
					delegate( MobileEntry m, int paramCount )
					{
						if( paramCount == 2 )
						{
							m.m_Str[ 0 ] = m.Pop<int>();
							m.m_Str[ 1 ] = m.Pop<int>();
						}
						else
						{
							m.m_Str[ 0 ] = m.m_Str[ 1 ] = m.Pop<int>();
						}
					};

			m_Handlers[ "SetDex" ] =
					delegate( MobileEntry m, int paramCount )
					{
						if( paramCount == 2 )
						{
							m.m_Dex[ 0 ] = m.Pop<int>();
							m.m_Dex[ 1 ] = m.Pop<int>();
						}
						else
						{
							m.m_Dex[ 0 ] = m.m_Dex[ 1 ] = m.Pop<int>();
						}
					};

			m_Handlers[ "SetInt" ] =
					delegate( MobileEntry m, int paramCount )
					{
						if( paramCount == 2 )
						{
							m.m_Int[ 0 ] = m.Pop<int>();
							m.m_Int[ 1 ] = m.Pop<int>();
						}
						else
						{
							m.m_Int[ 0 ] = m.m_Int[ 1 ] = m.Pop<int>();
						}
					};

			m_Handlers[ "SetDamageType" ] =
					delegate( MobileEntry m, int paramCount )
					{
						int value = m.Pop<int>();
						int type = m.Pop<int>();

						switch( type )
						{
							case 0:
								m.m_DamagePhysical = value;
								break;
							case 1:
								m.m_DamageFire = value;
								break;
							case 2:
								m.m_DamageCold = value;
								break;
							case 3:
								m.m_DamagePoison = value;
								break;
							case 4:
								m.m_DamageEnergy = value;
								break;
							default:
								break;
						}
					};

			m_Handlers[ "SetResistance" ] =
					delegate( MobileEntry m, int paramCount )
					{
						int max = m.Pop<int>();
						int min = max;

						if( paramCount == 3 )
						{
							min = m.Pop<int>();
						}

						int type = m.Pop<int>();

						switch( type )
						{
							case 0:
								m.m_Physical = new int[] { min, max };
								break;
							case 1:
								m.m_Fire = new int[] { min, max };
								break;
							case 2:
								m.m_Cold = new int[] { min, max };
								break;
							case 3:
								m.m_Poison = new int[] { min, max };
								break;
							case 4:
								m.m_Energy = new int[] { min, max };
								break;
							default:
								break;
						}
					};

			m_Handlers[ "SetSkill" ] =
					delegate( MobileEntry m, int paramCount )
					{
						double max = m.Pop<double>();
						double min = max;

						if( paramCount == 3 )
						{
							min = m.Pop<double>();
						}

						int type = m.Pop<int>();

						m.m_Skills[ type ] = new double[] { min, max };
					};
				
			m_Handlers[ "set_Fame" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_Fame = m.Pop<int>(  );
					};

			m_Handlers[ "set_VirtualArmor" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_VirtualArmor = m.Pop<int>(  );
					};

			m_Handlers[ "set_Title" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_Title = m.Pop<string>(  );
					};

			m_Handlers[ "set_Karma" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_Karma = m.Pop<int>(  );
					};

			m_Handlers[ "SetDamage" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_Damage[1] = m.Pop<int>(  );
						m.m_Damage[0] = m.Pop<int>();
					};

			m_Handlers[ "set_Hue" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_Hue = m.Pop<int>(  );						
					};

			m_Handlers[ "Utility::RandomDouble" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_Stack.Push( Utility.RandomDouble() );						
					};

			m_Handlers[ "Utility::RandomMinMax" ] =
					delegate( MobileEntry m, int paramCount )
					{
						if( paramCount == 2 )
						{
							m.m_Stack.Push( Utility.RandomMinMax( m.Pop<int>(), m.Pop<int>() ) );
						}						
					};

			m_Handlers[ "Utility::Random" ] =
					delegate( MobileEntry m, int paramCount )
					{
						if( paramCount == 1 )
						{
							m.m_Stack.Push( Utility.Random( m.Pop<int>() ) );
						}
						else if ( paramCount == 2 )
						{
							m.m_Stack.Push( Utility.Random( m.Pop<int>(), m.Pop<int>() ) );
						}
					};

			m_Handlers[ "Utility::RandomBool" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_Stack.Push( Utility.RandomBool() );
					};

			m_Handlers[ "set_MinTameSkill" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_MinToTame = m.Pop<double>();
					};

			m_Handlers[ "set_ControlSlots" ] =
					delegate( MobileEntry m, int paramCount )
					{
						m.m_ControlSlots = m.Pop<int>();
					};

			m_Handlers[ "BaseCreature::.ctor" ] =
					delegate( MobileEntry m, int paramCount )
					{
						double max = m.Pop<double>();
						double min = m.Pop<double>();

						int skip = m.Pop<int>();
						int rangePerception = m.Pop<int>();
						int fightMode = m.Pop<int>();

						m.m_Mode = ( (AIType)m.Pop<int>() ).ToString().Remove( 0, 3 );
					};

			m_Handlers[ "BaseMount::.ctor" ] =
					delegate( MobileEntry m, int paramCount )
					{
						double max = m.Pop<double>();
						double min = m.Pop<double>();

						int skip = m.Pop<int>();
						int rangePerception = m.Pop<int>();
						int fightMode = m.Pop<int>();

						m.m_Mode = ( (AIType)m.Pop<int>() ).ToString().Remove( 0, 3 );
						m.Pop<int>();
						m.m_BodyId = m.Pop<int>();
						m.Pop<string>();// name
					};

			m_Handlers[ "Container::DropItem" ] = m_BlankHandler;
			m_Handlers[ "Utility::RandomList" ] = m_BlankHandler;
			m_Handlers[ "set_Tamable" ] = m_BlankHandler;
			m_Handlers[ "SetHits" ] = m_BlankHandler;
			m_Handlers[ "AddItem" ] = m_BlankHandler;
			m_Handlers[ "set_SpeechHue" ] = m_BlankHandler;
			m_Handlers[ "set_Female" ] = m_BlankHandler;
			m_Handlers[ "Utility::AssignRandomHair" ] = m_BlankHandler;
			m_Handlers[ "Utility::RandomNeutralHue" ] = m_BlankHandler;
			m_Handlers[ "Utility::RandomSkinHue" ] = m_BlankHandler;
			m_Handlers[ "set_BaseSoundID" ] = m_BlankHandler;
			m_Handlers[ "SetMana" ] = m_BlankHandler;
			m_Handlers[ "set_Name" ] = m_BlankHandler;
			m_Handlers[ "PackItem" ] = m_BlankHandler;
			m_Handlers[ "PackArmor" ] = m_BlankHandler;
			m_Handlers[ "PackWeapon" ] = m_BlankHandler;
			m_Handlers[ "Body::op_Implicit" ] = m_BlankHandler;
			m_Handlers[ "Seed::RandomBonsaiSeed" ] = m_BlankHandler;
			#endregion

			ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();

			// find the JPEG encoder.
			foreach( ImageCodecInfo encoder in encoders )
			{
				if( encoder.FormatDescription == "JPEG" )
				{
					m_Encoder = encoder;
					break;
				}
			}

			m_EncoderParameter.Param[ 0 ] = new EncoderParameter( System.Drawing.Imaging.Encoder.Quality, new long[ 1 ] { 0x46 } );
			imgAttrs.SetColorMatrix( new ColorMatrix( alphaBlendMatrix ), ColorMatrixFlag.Default, ColorAdjustType.Bitmap );

			m_Templates.Add( "tableTop", /*"/*<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" +
													"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\">\n" +
													"	<head>\n" +
													"		<title> Twilight-Zone :: Bestiary </title>\n" +
													"		<link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />\n" +
													"		<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n" +
													"	</head>\n" +
													"	<body bgcolor=\"#000000\">\n" +*/
													"		<center>\n" +
													"			<img src=\"../images/{0}.jpg\" border=\"0\" alt=\"{0}\" />\n" +
													"			<br />\n" +
													"			<br />\n" +
													"			<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"mobileEntry\">\n" );
			m_Templates.Add( "nameHeader", "				<tr>\n" +
													"					<td bgcolor=\"#cccccc\" colspan=\"2\" align=\"center\" style=\"padding: 2px; color: #000\">\n" +
													"						<b>{0}</b>\n" +
													"					</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "strenghtOneArg", "				<tr>\n" +
													"					<th>Strength: </th>\n" +
													"					<td>{0}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "strenghtTwoArgs", "				<tr>\n" +
													"					<th>Strength: </th>\n" +
													"					<td>{0} - {1}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "dexterityOneArg", "				<tr>\n" +
													"					<th>Dexterity: </th>\n" +
													"					<td>{0}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "dexterityTwoArgs", "				<tr>\n" +
													"					<th>Dexterity: </th>\n" +
													"					<td>{0} - {1}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "intelligenceOneArg", "				<tr>\n" +
													"					<th>Intelligence: </th>\n" +
													"					<td>{0}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "intelligenceTwoArgs", "				<tr>\n" +
													"					<th>Intelligence: </th>\n" +
													"					<td>{0} - {1}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "damageTypesHeader", "				<tr>\n" +
													"					<th valign=\"top\">Damage types: </th>\n" +
													"					<td>\n" );
			m_Templates.Add( "resistancesHeader", "				<tr>\n" +
													"					<th valign=\"top\">Resistances: </th>\n" +
													"					<td>\n" );
			m_Templates.Add( "damagePhysical", "						<div style=\"border: 1px solid #555; background-image: url('../physical.gif'); width: {0}px; color: #000; font-weight: bold\">\n" +
													"							{0}%\n" +
													"						</div>\n" );
			m_Templates.Add( "damageFire", "						<div style=\"border: 1px solid #555; background-image: url('../fire.gif'); width: {0}px; color: #000; font-weight: bold\">\n" +
													"							{0}%\n" +
													"						</div>\n" );
			m_Templates.Add( "damageCold", "						<div style=\"border: 1px solid #555; background-image: url('../cold.gif'); width: {0}px; color: #000; font-weight: bold\">\n" +
													"							{0}%\n" +
													"						</div>\n" );
			m_Templates.Add( "damagePoison", "						<div style=\"border: 1px solid #555; background-image: url('../poison.gif'); width: {0}px; color: #000; font-weight: bold\">\n" +
													"							{0}%\n" +
													"						</div>\n" );
			m_Templates.Add( "damageEnergy", "						<div style=\"border: 1px solid #555; background-image: url('../energy.gif'); width: {0}px; color: #000; font-weight: bold\">\n" +
													"							{0}%\n" +
													"						</div>\n" );
			m_Templates.Add( "endRow", "						<br />\n" +
													"					</td>\n" +
													"				</tr>" );
			m_Templates.Add( "minMaxDmgOneArg", "				<tr>\n" +
													"					<th>Damage: </th>\n" +
													"					<td>{0}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "minMaxDmgTwoArgs", "				<tr>\n" +
													"					<th>Damage: </th>\n" +
													"					<td>{0} - {1}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "mode", "				<tr>\n" +
													"					<th>Mode: </th>\n" +
													"					<td>{0}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "fame", "				<tr>\n" +
													"					<th>Fame: </th>\n" +
													"					<td>{0}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "karma", "				<tr>\n" +
													"					<th>Karma: </th>\n" +
													"					<td>{0}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "slayer", "				<tr>\n" +
													"					<th>Slayer: </th>\n" +
													"					<td>\n" +
													"						<span style=\"color: #990000\">\n" +
													"							{0}\n" +
													"						</span>\n" +
													"					</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "armour", "				<tr>\n" +
													"					<th>Armour: </th>\n" +
													"					<td>{0}</td>\n" +
													"				</tr>\n" );
			m_Templates.Add( "minToTame", "				<tr>\n" +
										"					<th>Minimal taming: </th>\n" +
										"					<td>{0:F1}</td>\n" +
										"				</tr>\n" );
			m_Templates.Add( "slots", "				<tr>\n" +
										"					<th>Control slots: </th>\n" +
										"					<td>{0}</td>\n" +
										"				</tr>\n" );
			m_Templates.Add( "immunity", "				<tr>\n" +
							"					<th>Poison immunity: </th>\n" +
							"					<td>{0}</td>\n" +
							"				</tr>\n" );
			m_Templates.Add( "barding", "				<tr>\n" +
							"					<th>Barding: </th>\n" +
							"					<td>{0}</td>\n" +
							"				</tr>\n" );
			m_Templates.Add( "skillsHeader", "				<tr>\n" +
													"					<th>Skills: </th>\n" +
													"					<td>\n" );
			m_Templates.Add( "skillRow", "						<b>{0}</b>: {1}<br />\n" );
			m_Templates.Add( "tableFooter", "</table>\n");
												/*	"	</body>\n" +
													"</html>" );*/
		}
		#endregion

		#region [Fields]
		private Module m_Module;
		private Type m_MasterType;
		private int[] m_Str = new int[ 2 ];
		private int[] m_Dex = new int[ 2 ];
		private int[] m_Int = new int[ 2 ];
		private int[] m_Damage = new int[ 2 ];
		private int[] m_Physical = new int[ 2 ];
		private int[] m_Fire = new int[ 2 ];
		private int[] m_Cold = new int[ 2 ];
		private int[] m_Poison = new int[ 2 ];
		private int[] m_Energy = new int[ 2 ];
		private int m_DamagePhysical;
		private int m_DamageFire;
		private int m_DamageCold;
		private int m_DamagePoison;
		private int m_DamageEnergy;
		private int m_BodyId;
		private int m_Hue;
		private int m_Fame;
		private int m_Karma;
		private int m_VirtualArmor;
		private int m_ControlSlots;
		private int m_Barding;
		private double m_Difficulty;
		private double m_MinToTame;
		private string m_Title;
		private string m_Mode;
		private string m_Name;
		private string m_PrevLink, m_NextLink;
		private Poison m_Immunity;
		private SlayerEntry m_Slayer;
		private Stack m_Stack = new Stack();
		private Dictionary<int, double[]> m_Skills = new Dictionary<int, double[]>();
		#endregion

		#region [Properties]
		public string Name { get { return m_Name; } set { m_Name = value; } }
		
		public string PrevLink { get { return m_PrevLink; } set { m_PrevLink = value; } }
		public string NextLink { get { return m_NextLink; } set { m_NextLink = value; } }
		
		public Type MasterType { get { return m_MasterType; } set { m_MasterType = value; } }
		
		// returns the final html code
		public string Html
		{
			get
			{
				StringBuilder sb = new StringBuilder( 0x2000 );

				#region [Header]
				sb.AppendFormat( m_Templates[ "tableTop" ], m_MasterType.Name );
				sb.AppendFormat( m_Templates[ "nameHeader" ], m_Name );
				#endregion

				#region [Stats output]
				if( m_Str[ 0 ] != m_Str[ 1 ] )
				{
					sb.AppendFormat( m_Templates[ "strenghtTwoArgs" ], m_Str[ 1 ], m_Str[ 0 ] );
				}
				else
				{
					sb.AppendFormat( m_Templates[ "strenghtOneArg" ], m_Str[ 0 ] );
				}

				if( m_Dex[ 0 ] != m_Dex[ 1 ] )
				{
					sb.AppendFormat( m_Templates[ "dexterityTwoArgs" ], m_Dex[ 1 ], m_Dex[ 0 ] );
				}
				else
				{
					sb.AppendFormat( m_Templates[ "dexterityOneArg" ], m_Dex[ 0 ] );
				}

				if( m_Int[ 0 ] != m_Int[ 1 ] )
				{
					sb.AppendFormat( m_Templates[ "intelligenceTwoArgs" ], m_Int[ 1 ], m_Int[ 0 ] );
				}
				else
				{
					sb.AppendFormat( m_Templates[ "intelligenceOneArg" ], m_Int[ 0 ] );
				}
				#endregion

				#region [Damage Types]
				sb.Append( m_Templates[ "damageTypesHeader" ] );
				if( m_DamagePhysical != 0 )
					sb.AppendFormat( m_Templates[ "damagePhysical" ], m_DamagePhysical );
				if( m_DamageFire != 0 )
					sb.AppendFormat( m_Templates[ "damageFire" ], m_DamageFire );
				if( m_DamageCold != 0 )
					sb.AppendFormat( m_Templates[ "damageCold" ], m_DamageCold );
				if( m_DamagePoison != 0 )
					sb.AppendFormat( m_Templates[ "damagePoison" ], m_DamagePoison );
				if( m_DamageEnergy != 0 )
					sb.AppendFormat( m_Templates[ "damageEnergy" ], m_DamageEnergy );
				sb.Append( m_Templates[ "endRow" ] );
				#endregion

				#region [Resistances]
				sb.Append( m_Templates[ "resistancesHeader" ] );
				if( m_Physical[ 0 ] != 0 )
					sb.AppendFormat( m_Templates[ "damagePhysical" ], m_Physical[ 0 ] );
				if( m_Fire[ 0 ] != 0 )
					sb.AppendFormat( m_Templates[ "damageFire" ], m_Fire[ 0 ] );
				if( m_Cold[ 0 ] != 0 )
					sb.AppendFormat( m_Templates[ "damageCold" ], m_Cold[ 0 ] );
				if( m_Poison[ 0 ] != 0 )
					sb.AppendFormat( m_Templates[ "damagePoison" ], m_Poison[ 0 ] );
				if( m_Energy[ 0 ] != 0 )
					sb.AppendFormat( m_Templates[ "damageEnergy" ], m_Energy[ 0 ] );
				sb.Append( m_Templates[ "endRow" ] );
				#endregion

				#region [Some stuff]
				if( m_Damage[ 0 ] != m_Damage[ 1 ] )
				{
					sb.AppendFormat( m_Templates[ "minMaxDmgTwoArgs" ], m_Damage[ 0 ], m_Damage[1] );
				}
				else
				{
					sb.AppendFormat( m_Templates[ "minMaxDmgOneArg" ], m_Damage[1] );
				}

				sb.AppendFormat( m_Templates[ "mode" ], m_Mode );
				sb.AppendFormat( m_Templates[ "fame" ], m_Fame );
				sb.AppendFormat( m_Templates[ "karma" ], m_Karma );
				sb.AppendFormat( m_Templates[ "armour" ], m_VirtualArmor );

				if( m_Slayer != null )
				{
					sb.AppendFormat( m_Templates[ "slayer" ], m_Cliloc.Table[ m_Slayer.Title ] );
				}

				if( m_ControlSlots > 0 )
				{
					sb.AppendFormat( m_Templates[ "minToTame" ], m_MinToTame );
					sb.AppendFormat( m_Templates[ "slots" ], m_ControlSlots );
				}

				if( m_Immunity != null )
				{
					sb.AppendFormat( m_Templates[ "immunity" ], m_Immunity.ToString() );
				}

				StringBuilder bard = new StringBuilder( 0x400 );

				if( ( m_Barding & 4 ) != 0 )
				{
					bard.Append( "<b>Bard Immune</b><br />\n" );
				}
				else
				{
					bard.AppendFormat( "<b>Difficulty:</b> {0:F1}<br />\n", m_Difficulty );

					if( ( m_Barding & 1 ) != 0 )
					{
						bard.Append( "<b>Unprovokable</b><br />\n" );
					}

					if( ( m_Barding & 2 ) != 0 )
					{
						bard.Append( "<b>Uncalmable</b><br />\n" );
					}
				}

				sb.AppendFormat( m_Templates[ "barding" ], bard.ToString() );

				#endregion

				#region [Skills]
				sb.Append( m_Templates[ "skillsHeader" ] );
				List<int> keys = new List<int>( m_Skills.Keys );

				for( int i = 0; i < 5 && i < m_Skills.Count; i++ )
				{
					double[] skillVal = m_Skills[ keys[ i ] ];
					string skStrVal = "";

					if( skillVal[ 0 ] == skillVal[ 1 ] )
					{
						skStrVal = string.Format( "{0:F1}", skillVal[ 0 ] );
					}
					else
					{
						skStrVal = string.Format( "{0:F1} - {1:F1}", skillVal[ 0 ], skillVal[ 1 ] );
					}

					sb.AppendFormat( m_Templates[ "skillRow" ], SkillInfo.Table[ keys[ i ] ].Name, skStrVal );
				}
				sb.Append( m_Templates[ "endRow" ] );
				#endregion

				#region [Footer]
				sb.Append( m_Templates[ "tableFooter" ] );
				#endregion
			
				if( m_PrevLink != null )
				{
					sb.AppendFormat( "<span style=\"padding: 3px;border: 1px solid #555; background-color: #333; margin: 2px;\">{0}</span>", m_PrevLink );
				}
				
				if ( m_NextLink != null )
				{
                    sb.AppendFormat("&nbsp;&nbsp;&nbsp;<span style=\"padding: 3px;border: 1px solid #555; background-color: #333; margin: 2px;\">{0}</span>", m_NextLink);
				}
				
				sb.Append("</center><br /><br ?>");

				return sb.ToString();
			}
		}
		
		// Consider the entry being empty if it does have all of the following -zero-: bodyId, str, int or dex.
		public bool GuessEmpty
		{
			get
			{
				return ( 
					m_BodyId == 0 &&
					m_Str[1] == 0 && 
					m_Int[1] == 0 && 
					m_Dex[1] == 0 
				);
			}
		}
		#endregion

		public MobileEntry( Type type )
		{
			m_MasterType = type;
			m_Module = type.Module;
			m_Name = Bestiary.TypeRegistry[ m_MasterType ].Name;
			m_Slayer = this.SlayerGroup();

			ConstructorInfo ctor = this.HandleSpecialType( type );

			this.AnalyseILCode( ctor.GetMethodBody().GetILAsByteArray() );

			#region [Additional data]
			{
				BaseCreature bc = (BaseCreature)Activator.CreateInstance( type );
				if( bc.Unprovokable )
				{
					m_Barding |= 0x1;
				}
				if( bc.Uncalmable)
				{
					m_Barding |= 0x2;
				}
				if( bc.BardImmune )
				{
					m_Barding |= 0x4;
				}
				m_Immunity = bc.PoisonImmune;
				m_Difficulty = Items.BaseInstrument.GetBaseDifficulty( bc );
				bc.Delete();
			}
			#endregion

			if( m_BodyId != 0 )
			{
				GenerateImage();
			}
		}
		
		//----------------------------------------------------------------------------------------------------------------------
		// Predict that the last 0 or 1 pushed onto the stack being the value to be returned.  Returns false on error. Naughty me!
		//----------------------------------------------------------------------------------------------------------------------
		public bool GetBooleanValue( string methodName )
		{
			MethodInfo method = m_MasterType.GetMethod( methodName );
			
			if( method != null )
			{
				byte[] methodData = method.GetMethodBody().GetILAsByteArray();
				
				BinaryReader codeReader = new BinaryReader(
				   new MemoryStream( methodData )
			   	);
			   	
			   	bool lastCode = false;

				while( codeReader.PeekChar() >= 0 )
				{
					OpCode op = OPCodeCache.Hit( codeReader.ReadByte() );
					
					if ( op == OpCodes.Ldc_I4_1 )
					{
						lastCode = true;
					}
					else if ( op == OpCodes.Ldc_I4_0 )
					{
						lastCode = false;
					}
				}
				
				return lastCode;		
			}
			
			return false;
		}
		
		// some ctors may need extra care.
		private ConstructorInfo HandleSpecialType( Type type )
		{
			ConstructorInfo ctor = null;

			if( typeof( BaseMount ).IsAssignableFrom( type ) )
			{
				ctor = type.GetConstructor( new Type[] { typeof( string ) } );
			}

			return ( ctor ?? type.GetConstructor( Type.EmptyTypes ) );
		}

		// heart and soul, yay!
		private void AnalyseILCode( byte[] code )
		{
			BinaryReader codeReader = new BinaryReader(
				   new MemoryStream( code )
			   );

			while( codeReader.PeekChar() >= 0 )
			{
				OpCode op = OPCodeCache.Hit( codeReader.ReadByte() );

				if( op == OpCodes.Ldc_I4 )
				{
					m_Stack.Push( codeReader.ReadInt32() );
				}
				else if( op == OpCodes.Ldc_R8 )
				{
					m_Stack.Push( codeReader.ReadDouble() );
				}
				else if( op == OpCodes.Ldc_R4 )
				{
					m_Stack.Push( codeReader.ReadSingle() );
				}
				else if( op.Value > 0x15 && op.Value < 0x1F )
				{
					m_Stack.Push( op.Value - 0x16 );
				}
				else if( op == OpCodes.Ldc_I4_M1 )
				{
					m_Stack.Push( -1 );
				}
				else if( op == OpCodes.Ldc_I4_S )
				{
					m_Stack.Push( (int)codeReader.ReadByte() );
				}
				else if( op == OpCodes.Ldstr )
				{
					int stringDescriptor = codeReader.ReadInt32();

					if( MatchMetadata( stringDescriptor, MetadataToken.String ) ) // sanity check, am I really a string?
					{
						m_Stack.Push( m_Module.ResolveString( stringDescriptor ) );
					}
					else
					{
						m_Stack.Push( "(error - string value couldn't be resolved.)" );
					}
				}
				else if( op == OpCodes.Call || op == OpCodes.Callvirt )
				{
					int methodDescriptor = codeReader.ReadInt32();

					if( MatchMetadata( methodDescriptor, MetadataToken.Method ) ) // sanity check, am I really a method?
					{
						MethodBase mb = m_Module.ResolveMethod( methodDescriptor );

						if( (mb.DeclaringType.IsSubclassOf( typeof( Mobile ) ) || mb.DeclaringType == typeof( Mobile )) && !mb.IsConstructor )
						{
							Dispatch( mb.Name, mb.GetParameters().Length );
						}
						else
						{
							Dispatch( mb.Name, mb.DeclaringType.Name, mb.GetParameters().Length );
						}
					}
				}
				else
				{
					// all opcodes that push something onto the stack have been taken care of.
					// now we have to check whether the given opcode has an operand or not.
					// if so, we'll skip appropriate amount of bytes.
					
					OperandType operandType = op.OperandType;

					switch( operandType )
					{
						case OperandType.InlineNone:
							{
							}
							break;
						case OperandType.InlineR:
						case OperandType.InlineI8:
							{
								codeReader.ReadInt64();
							}
							break;
						case OperandType.InlineSwitch:
							{
								int switchBranches = codeReader.ReadInt32();

								while( switchBranches-- > 0 )
								{
									codeReader.ReadInt32();
								}
							}
							break;
						case OperandType.ShortInlineR:
						case OperandType.InlineType:
						case OperandType.InlineTok:
						case OperandType.InlineString:
						case OperandType.InlineSig:
						case OperandType.InlineMethod:
						case OperandType.InlineI:
						case OperandType.InlineField:
						case OperandType.InlineBrTarget:
							{
								codeReader.ReadInt32();
							}
							break;
						case OperandType.InlineVar:
							{
								codeReader.ReadInt16();
							}
							break;
						case OperandType.ShortInlineVar:
						case OperandType.ShortInlineI:
						case OperandType.ShortInlineBrTarget:
							{
								codeReader.ReadByte();
							}
							break;
					}
				}
			}
		}

		//----------------------------------------------------------------------------------
		// Pops the value of predicted type <T> outta the stack.
		// otherwise returns a default value.
		//----------------------------------------------------------------------------------
		private T Pop<T>()
		{
			if( m_Stack.Count > 0 )
			{
				object pop = m_Stack.Pop();

				if( pop is T )
				{
					return (T)pop;
				}				
			}

			return default( T );
		}

		// am I really what I'm expected to be, huh?
		private bool MatchMetadata( int descriptor, MetadataToken token )
		{
			return ( descriptor & (int)token ) != 0;
		}

		private SlayerEntry SlayerGroup()
		{
			foreach( SlayerGroup group in Server.Items.SlayerGroup.Groups )
			{
				if( Array.IndexOf<Type>( group.Super.Types, m_MasterType ) != -1 )
				{
					return group.Super;
				}

				foreach( SlayerEntry entry in group.Entries )
				{
					if( Array.IndexOf<Type>( entry.Types, m_MasterType ) != -1 )
					{
						return entry;
					}
				}
			}

			return null;
		}

		// dispatcher!
        private void Dispatch( string methodName, string typeName, int paramCount )
        {
            if (string.IsNullOrEmpty(typeName))
            {
                Dispatch(methodName, paramCount);
            }
            else
            {
				if( typeName != "TimeSpan" ||
					typeName != "DateTime" ||
					typeName != "Map"	   ||
					typeName != "NameList" ||
					typeName != "Loot" ) // ignore several types
				{
					Dispatch( string.Concat( typeName, "::", methodName ), paramCount );
				}
            }
        }

		// switch witch, sandwich .. am I nuts?
		private void Dispatch( string methodName, int paramCount )
		{
			MethodHandler handler;

			if( m_Handlers.TryGetValue( methodName, out handler ) )
			{
				handler( this, paramCount );
			}
			else
			{
#if DEBUG
				Console.WriteLine("Unregistered handler for method: {0} !", methodName);
#endif
			}		
		}

		private void GenerateImage()
		{
			Frame[] animFrames = Animations.GetAnimation( m_BodyId, 0, 1, ( m_Hue - 1 ), false );
			
			Bitmap bmp = null;
			
			if( Bestiary.UseFixes )
			{
				string fixPath = Path.Combine("Bestiary/fixes", m_MasterType.Name + ".jpg");
				
				if( File.Exists(fixPath) )
				{
					bmp = new Bitmap( fixPath );
				}
			}

            if (animFrames != null || bmp != null)
            {
                using (Bitmap mobImage = new Bitmap(bmp ?? animFrames[0].Bitmap))
                {
                    using (Bitmap result = new Bitmap(m_BorderImage.Width, m_BorderImage.Height))
                    {
                        using (Bitmap title = ASCIIText.DrawText(3, m_Name, 0x3B2))
                        {
                            using (Graphics gr = Graphics.FromImage(result))
                            {
                                using (Bitmap tz = ASCIIText.DrawText(3, " - The Retelling - Bestiary -", 1260))
                                {
                                    using (SolidBrush blackBrush = new SolidBrush(Color.FromArgb(60, 1, 1, 1)))
                                    {
                                        if (m_Hue > 0)
                                        {
                                            Hue hue = GetHue(m_Hue - 1);

                                            if (hue != null)
                                            {
												// explicitely apply the hue, GetAnimation method doesn't work for few bodyIds.
                                                hue.ApplyTo(mobImage, false);
                                            }
                                        }

                                        GraphicsUnit unit = GraphicsUnit.Pixel;
                                        RectangleF rect = mobImage.GetBounds(ref unit);
                                        int trX = (214 - (mobImage.Width >> 1));
                                        int trY = (170 - (mobImage.Height >> 1));
                                        int brX = (int)(trX + rect.Width);
                                        int brY = (int)(trY + rect.Height);

										string customBg = Bestiary.TypeRegistry[m_MasterType].Background;
										
										if( !string.IsNullOrEmpty(customBg) )
										{
											using( Bitmap cBg = new Bitmap(customBg) )
											{
												gr.DrawImage(cBg, 0.0f, 0.0f);	
											}
										}
										else
										{									
                                        	gr.DrawImage(m_Background, 0.0f, 0.0f);
                                        }
                                       
                                        gr.FillRectangle(blackBrush, new Rectangle(22, 22, 385, 30));
                                        gr.DrawImage(
                                            m_WaterMark,
                                            new Rectangle(0, 0, m_BorderImage.Width, m_BorderImage.Height),
                                            0,
                                            0,
                                            m_BorderImage.Width,
                                            m_BorderImage.Height,
                                            GraphicsUnit.Pixel,
                                            imgAttrs
                                        );
                                        gr.DrawImage(title, ((brX + trX) >> 1) - (title.Width >> 1), trY - 5 - title.Height);
                                        gr.DrawImage(mobImage, trX, trY);
                                        gr.DrawImage(m_BorderImage, 0, 0, m_BorderImage.Width, m_BorderImage.Height);
                                        gr.DrawImage(tz, 100, 25);

                                        result.Save(Path.Combine("./Bestiary/images/", m_MasterType.Name + ".jpg"), m_Encoder, m_EncoderParameter);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                Console.WriteLine("Couldn't acquire animation frames for bodyID: {0}, {1}", m_BodyId, m_Name);
            }
		}
	};
}
 
Back