RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Some quick help with arrays and lists

typhoonbot

Sorceror
Some quick help with arrays and lists

Before I ask a really complicated question to try and validate my method of creating a system, let me ask one simple question:

Can a dictionary hold various different values in each position

ie, in position 1 of the dictionary I want to store a Mobile, 2 different DateTime variables and a Point3D location (the 2 DateTime variables, and the Point3D location all need to relate to the Mobile stored in the same position.

Is this possible in a dictionary ?

Regards
 
trying to goof me up, changing what you had type while i was typing lol

yes a dictionary can have a list of different things in each position

i.e.
mobile, point3d, int, string, string, int, double for excample
would be
mobile location hue name title bodynumber skillvalue

now how you would set it up, i am not completely familiar with, i have just been dabling with lists and such (and lists can be same way too)

but it is possible
 

Gargouille

Sorceror
Dictionaries only take a key and a value.

But you can do a Dictionary<Mobile, Dictionary<DateTime, Dictionary<DateTime,Point3D>>>

(but imho you may not ^^)

Why dont you just create a data class, something like :

Code:
public Data
{

public DateTime date1;
public DateTime date2;
public Point3D p;

}

And then just make a Dictionary<Mobile, Data>
 

Lichtblitz

Sorceror
For this kind of datatype you should rather use a struct. It has some advantages over class for that scenario and as far as I know it is not considered bad design to have a struct with public members regarding information hiding. But apart from that Gargouille's approach is the same I would use.
 

typhoonbot

Sorceror
Okay, but will the "public Data" method relate to EACH mobile within a LIST OF MOBILES ? and can someone give me the code I will need to use please ?
 

typhoonbot

Sorceror
Here is the whole script I have thrown together:

Code:
using System;
using Server.Mobiles;
using System.IO;
using System.Collections;
using System.Collections.Generic; 
using Server; 
using Server.Misc; 
using Server.Items; 
using Server.Gumps; 
using Server.Network;
using Server.Accounting;
using Server.Targeting;
using Server.ContextMenus;
using Server.Commands;
using Server.Regions;

namespace Server.Commands
{
	public class JailingSystem
  	{
		public static List<Mobile> inMates = new List<Mobile>(); //Needs to be ser / deser
		public static ArrayList cells = new ArrayList();
		
		private DateTime m_JailedTime; //Needs to be ser / deser
		public DateTime JailedTime 
		{ 
			get { return m_JailedTime; } 
			set { m_JailedTime = value; } 
		}
		
		private DateTime m_ReleaseTime; //Needs to be ser / deser
		public DateTime ReleaseTime
		{ 
			get { return m_ReleaseTime; } 
			set { m_ReleaseTime = value; } 
		}
		
		private Point3D m_OffenderPosition; //Needs to be ser / deser
		public DateTime OffenderPosition
		{ 
			get { return m_OffenderPosition; } 
			set { m_OffenderPosition = value; } 
		}
		
		private Mobile m_Offender; //Needs to be ser / deser
		public Mobile Offender 
		{ 
			get { return m_Offender; } 
			set { m_Offender = value; } 
		}
		
		public static void defaultCells()
		{
			cells.Clear();
			cells.Add(new Point3D(5276,1164,0));
			cells.Add(new Point3D(5286,1164,0));
			cells.Add(new Point3D(5296,1164,0));
			cells.Add(new Point3D(5306,1164,0));
			cells.Add(new Point3D(5276,1174,0));
			cells.Add(new Point3D(5286,1174,0));
			cells.Add(new Point3D(5296,1174,0));
			cells.Add(new Point3D(5306,1174,0));
			cells.Add(new Point3D(5283,1184,0));
		}
		
		public void AddInMate( Mobile from )
		{
			if( m_inMates.Contains( from ) ) 
			{
				from.SendMessage(37, "they are already an inmate");
				return;
			}
			else 
			{ 	
				m_inMates.Add( from );
			}
		}
        
        public void RemoveInMate( Mobile from )
		{
			if( m_inMates.Contains( from ) ) 
			{
				m_inMates.Remove( from );
			}
			else 
			{ 
				from.SendMessage(37, "they are not currently an inmate.");
				return;
			}
		}
        
        public static bool IsInMate( Mobile from ) 
		{
			return m_inMates.Contains( from );
		}
        
        public void JailMobile( Mobile offender, DateTime sentance, Point3D posi )
        {
        	AddInMate( offender );
        	JailedTime = DateTime.Now;
        	ReleaseTime = (DateTime.Now + sentance);
        	Offender = offender;
        	OffenderPosition = posi;
        	
        	offender.Location = cells[m_inMates.Position];
        }
        
        public void JailMobileWithTarget( Mobile offender, DateTime released, string reason, string jailedBy )
        {
        	
        }

		public JailingSystem( Serial serial ) : base( serial )
		{
		}

		public override void Serialize( GenericWriter writer )
		{
			base.Serialize( writer );
			writer.Write( (int) 0 );

   			if( m_inMates != null ) 
   			{ 
      				writer.Write( true ); 
      				writer.Write( m_inMates.Count ); 

				foreach( KeyValuePair<Mobile, DateTime, DateTime, Point3D> kvp in m_inMates ) 
				{ 
					writer.Write( kvp.Key ); 
 
					writer.Write( kvp.Value );
				}
			} 

			else 
			{ 
				writer.Write( false ); 
			} 
		}

		public override void Deserialize( GenericReader reader ) 
		{ 
			base.Deserialize( reader ); 
 
			int version = reader.ReadInt(); 
 
			switch( version ) 
			{ 
				case 0: 
				{ 
					bool notNull = reader.ReadBool(); 
 
					if( notNull ) 
					{
						int tableSize = reader.ReadInt();
						for( int i = 0; i < tableSize; i++ ) 
						{ 
							Mobile m = reader.ReadMobile();
							DateTime d = reader.ReadDateTime();
							DateTime dt = reader.ReadDateTime();
							Point3D posi = reader.ReadPoint3D();
							m_inMates.Add( m, d, dt, posi );
						} 
					}
					break;
				}
			}
		}
	}
	
	public class JailTimer : Timer
	{	 

        public JailTimer()
			: base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) )
		{
			Priority = TimerPriority.FiftyMS;
		}

		protected override void OnTick() //every 5 seconds executes code in {}
		{
			if(JailingSystem.ReleaseTime <  DateTime.Now)
            {
				Offender.Location = OffenderPosition;
				RemoveInMate( Offender );
				
				//Timer will need to stop here
            }
		}
	}
}

Now you will see I have created many public fields, to store the ReleaseTime, JailedTime, Offender etc. but, what would be even more Ideal in this situation is to have either a dictionary of mobiles, and then places in the dictionary to store each of these fields that will relate to the specific mobile. But apparently that is not a good idea, and I must use a "data" method to store these fields for each mobile in the list.


My second question is in regards to this line:

Code:
offender.Location = cells[m_inMates.Position];

I made a post about it, but did not submit it, just saved it to ask later, so here is the post on that:

Hey everyone, I am trying to give a PlayerMobile's location property (which is a Point3D variable) a value from a particular position in an Array of Point3D locations. I know this sounds complicated but bare with me, I will try explain.

Say I have an array of Point3D locations called "Locs", and in this array are various different specific Point3D locations in position 1, 2 and 3.

Now I also have a LIST of mobiles lets say with mobiles that full positions 1 and 2.

Now I want 1 of the mobiles from the LIST (lets say number 2) to have his / her "Location" property set to the same value as the Point3D location in the respective position of the "Locs array"

ie: The mobile in position 2 of the "list of mobiles" must have his / her "Location" property set to the same value as the 2nd Point3D location in the "Locs Array".

example:

* Locs Array position 2 is holding the Point3D location: "1542, 3432, 0" (which is the x, y, z co-ords)
* Position 2 of the Mobile List is holding the Mobile "Jonny" (the actual mobile, not just the name)

I want Jonny's Location property to be set to "1542, 3432, 0" (which is the same value as the second position of the Locs Array).

This is what I have done, code wise:

Code:
[I][B]Mobile[/B][/I].Location = [I][B]Location Array[/B][/I][COLOR="Red"][[/COLOR][I][B]m_MobileListName[/B][/I].Position[COLOR="Red"]][/COLOR];

I hope you understand what I am asking, it was quite difficult to explain as I am sure you see...

Thanks in advance

your bot, typhoon ;)

Thanks for any help

Regards
 

Aquatic Elf

Sorceror
The way a Dictionary or a Hashtable works, is that you can add a <Key, Value> pair into a table. You can recover the Value using a key. It's worth mentioning (after looking at your code) that only one Value can be assigned to a Key.

Since you want to associate many values with a single Key, we make the value an Class that can store all the values we need. I suggest using a Class, instead of a Struct, since you can easily initialize everything with the constructor, which cleans up the code significantly.

Code:
public class Data
{
	private DateTime m_Date1;
	private DateTime m_Date2;
	private Point3D m_P;
	
	public DateTime Date1{ get{ return m_Date1; } set{ m_Date1 = value; } }	
	public DateTime Date2{ get{ return m_Date2; } set{ m_Date2 = value; } }	
	public Point3D P{ get{ return m_P; } set{ m_P = value; } }	
	
	public Data( DateTime date1, DateTime date2, Point3D p )
	{
		m_Date1 = date1;
		m_Date2 = date2;
		m_P = p;
	}
}

I suggest picking a better name instead of "Data" for the class though.

Then you can construct a Hashtable/Dictionary via:
Code:
using System.Collections;
using System.Collections.Generic; 

private Dictionary<Mobile, Data> m_MyTable = new Dictionary<Mobile, Data>();

This will create a Dictionary that must have a Mobile for the Key, and Data for the value. The advantage of this Dictionary over the normal Hashtable is that we won't have to type cast variables (since when you get a Value from a Hashtable, it comes back as the type Object).

To add to this Dictionary we can use the following:

Code:
if ( !m_MyTable.ContainsKey( mobile ) )
	m_MyTable.Add( mobile, new Data( DateTime.Now, DateTime.Now + TimeSpan.FromDays( 1.0 ), mobile.Location );

We must check if the table already contains the key before adding. I think an exception may be thrown if the key already exists.

Then we use table.Add( key, value ) as shown above.

If we were using a struct instead of a Class for Data, we'd need a lot of lines to manually set each of the fields of Data, but as you can see, using the constructor cleans up the code significantly.

To recover a Value, we use:

Code:
if ( m_MyTable.ContainsKey( mobile ) )
{
	Data data = m_MyTable[ mobile ];
	
	Console.WriteLine( data.Date1 );
	Console.WriteLine( data.Date2 );
	Console.WriteLine( data.P );
}

You'll notice we use brackets with the key value, to recovery the value we're looking for. Again, if you try to lookup a key, that does not exist in the table, I'm pretty sure an Exception will be thrown.
 

Aquatic Elf

Sorceror
I haven't tested these, but for Serialization:

Code:
writer.Write( m_MyTable.Count );

foreach( KeyValuePair<Mobile, Data> kvp in m_MyTable )
{
	writer.Write( kvp.Key.Serial );		// Notice how we use Serial
	writer.Write( kvp.Value.Date1 );
	writer.Write( kvp.Value.Date2 );
	writer.Write( kvp.Value.P );
}

Basically we loop through every key, and write out the Key (Mobile)'s serial and the data for the Data class.

The other option to is write a special Serialize method for the Class Data, and then call that method here, which makes more sense, since Data should know how to serialize itself, not another class. I'll leave it how it is for simplicity.

Another advantage to having a special serialize method in the Data class, is that if you add more variables to Data, you change the serialize method in that class, instead of hunting down everywhere you serialized the class Data. The same goes for Deserialization.

For Deserialize:

Code:
int count = reader.ReadInt();

if( count > 0 )
{
	m_MyTable = new Dictionary<Mobile, Data>();

	for( int i = 0; i < count; i++ )
	{
		m_MyTable.Add( (Mobile)reader.ReadInt(), new Data( reader.ReadDateTime(), reader.ReadDateTime(), reader.ReadPoint3D() );
	}
}

Again, I haven't tested any of these, and I'm pretty sure that's how it done. I advise testing this on a test shard of course, incase it does mess up your save.

Hopefully if I made any glaring errors, someone will jump on it :).
 

Gargouille

Sorceror
I think that writers values should be casted by their type so you can use the predefined readers:

Code:
writer.Write( [COLOR="Red"] (int)[/COLOR] m_MyTable.Count );

foreach( KeyValuePair<Mobile, Data> kvp in m_MyTable )
{
        //writer.Write( kvp.Key.Serial );		// Notice how we use Serial
        writer.Write( [COLOR="Red"](Mobile)[/COLOR] kvp.Key );	// Notice that the Write method use also Serial to serialize a Mobile
	writer.Write( [COLOR="Red"](DateTime)[/COLOR] kvp.Value.Date1 );
	writer.Write( [COLOR="Red"](DateTime)[/COLOR] kvp.Value.Date2 );
	writer.Write( [COLOR="Red"](Point3D)[/COLOR] kvp.Value.P );
}

And then :
Code:
int count = reader.ReadInt();

[COLOR="Red"]if( count > 0 )// no use cause in the loop we already have  i < count[/COLOR]
{
	[COLOR="Red"]//m_MyTable = new Dictionary<Mobile, Data>();//no use, until it's already declare, and declared as empty yet[/COLOR]

	for( int i = 0; i < count; i++ )
	{
		m_MyTable.Add( (Mobile)reader.ReadInt(), new Data( reader.ReadDateTime(), reader.ReadDateTime(), reader.ReadPoint3D() );
	}
}

So you can try :
Code:
int count = reader.ReadInt();

for( int i = 0; i < count; i++ )
	{
		m_MyTable.Add(reader.ReadMobile(), new Data( reader.ReadDateTime(), reader.ReadDateTime(), reader.ReadPoint3D() );
	}

IMHO
 

typhoonbot

Sorceror
Thanks very much to everyone who replied here, you have helped very much.

Here is how my script looks now:

Code:
using System;
using Server.Mobiles;
using System.IO;
using System.Collections;
using System.Collections.Generic; 
using Server; 
using Server.Misc; 
using Server.Items; 
using Server.Gumps; 
using Server.Network;
using Server.Accounting;
using Server.Targeting;
using Server.ContextMenus;
using Server.Commands;
using Server.Regions;

namespace Server.Commands
{
	public class JailingSystem
  	{
		
		public class MobileFields
		{
			private DateTime m_JailedTime;
			private DateTime m_ReleaseTime;
			private Point3D m_Posi;
	
			public DateTime JailedTime
			{ 
				get{ return m_JailedTime; } 
				set{ m_JailedTime = value; } 
			}
			public DateTime ReleaseTime
			{ 
				get{ return m_ReleaseTime; } 
				set{ m_ReleaseTime = value; } 
			}
			public Point3D Posi
			{ 
				get{ return m_Posi; } 
				set{ m_Posi = value; } 
			}
	
			public MobileFields( DateTime jailedTime, DateTime releaseTime, Point3D posi )
			{
				m_JailedTime = jailedTime;
				m_ReleaseTime = releaseTime;
				m_Posi = posi;
			}
		}
		private Dictionary<Mobile, MobileFields> m_inMates = new Dictionary<Mobile, MobileFields>();
		public static ArrayList cells = new ArrayList();
		
		public static void defaultCells()
		{
			cells.Clear();
			cells.Add(new Point3D(5276,1164,0));
			cells.Add(new Point3D(5286,1164,0));
			cells.Add(new Point3D(5296,1164,0));
			cells.Add(new Point3D(5306,1164,0));
			cells.Add(new Point3D(5276,1174,0));
			cells.Add(new Point3D(5286,1174,0));
			cells.Add(new Point3D(5296,1174,0));
			cells.Add(new Point3D(5306,1174,0));
			cells.Add(new Point3D(5283,1184,0));
		}
		
		public void AddInMate( Mobile from, DateTime TimeJailed, DateTime TimeReleased, Point3D origPos )
		{
			if ( m_inMates.ContainsKey( from ) )
			{
				RemoveInMate( from );
			}
			
			m_inMates.Add( from, new MobileFields( TimeJailed, TimeReleased, origPos ));
		}
        
        public void RemoveInMate( Mobile from )
		{
			if( m_inMates.ContainsKey( from ) ) 
			{
				m_inMates.Remove( from );
			}
		}
        
        public static bool IsInMate( Mobile from ) 
		{
			return m_inMates.ContainsKey( from );
		}
        
        public void JailMobile( Mobile offender, DateTime sentance, Point3D pos )
        {
        	DateTime jailTime = DateTime.Now;
        	DateTime releasedTime = (jailTime + sentance);
        	
        	AddInMate(offender, jailTime, releasedTime, pos);
        	
        	[COLOR="Blue"]//offender.Location = cells[m_inMates.Position];[/COLOR]
        }
        
        public void JailMobileWithTarget( Mobile offender, DateTime released, string reason, string jailedBy )
        {
        	
        }

		public JailingSystem( Serial serial ) : base( serial )
		{
		}

		public override void Serialize( GenericWriter writer )
		{
			base.Serialize( writer );

   			if( m_inMates != null ) 
   			{ 
      			writer.Write( true ); 
      			writer.Write( (int) m_inMates.Count );

				foreach( KeyValuePair<Mobile, MobileFields> kvp in m_inMates )
				{
					writer.Write( kvp.Key.Serial );	// Notice how we use Serial
					writer.Write( (Mobile) kvp.Key ); //Mobile
					writer.Write( (DateTime) kvp.Value.JailedTime );
					writer.Write( (DateTime) kvp.Value.ReleaseTime );
					writer.Write( (Point3D) kvp.Value.Posi );
				}
			} 
			else 
			{ 
				writer.Write( false ); 
			} 
		}

		public override void Deserialize( GenericReader reader ) 
		{ 
			base.Deserialize( reader ); 
 
			int count = reader.ReadInt(); 

			m_inMates = new Dictionary<Mobile, MobileFields>(); //no use, until it's already declare, and declared as empty yet

			for( int i = 0; i < count; i++ )
			{
				m_inMates.Add( reader.ReadMobile(), new Data( reader.ReadDateTime(), reader.ReadDateTime(), reader.ReadPoint3D() ));
			}
		}
	}
	
	public class JailTimer : Timer
	{	 

        public JailTimer()
			: base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) )
		{
			Priority = TimerPriority.FiftyMS;
		}

		protected override void OnTick() //every 5 seconds executes code in {}
		{
			if(JailingSystem.ReleaseTime <  DateTime.Now)
            {
				[COLOR="Red"]Offender[/COLOR].Location = Posi;
				RemoveInMate( [COLOR="Red"]Offender [/COLOR]);
				
				//Timer will need to stop here
            }
		}
	}
}

Okay, the only questions I still have are with the coloured pieces of code :)

Lets start with red :)

Now, in my timer, how will I refer to the "Mobile in jail". Because that timer should check every 5 seconds, if each mobile's ReleaseTime is less than the current time (IE: then they need to be released to the Original Position field value). So, the question is, will I simply use "m_inMates.Key.Position = Posi" or how will I check each mobile in the dictionary, maybe via means of a for loop ?

And now the blue part, I have a whole post saved on this blue line of code, that just can't seem to get answered, maybe everyone's scared of it (I know I am :D)

Here is the Blue line again:

//offender.Location = cells[m_inMates.Position];

And here is the post:

Hey everyone, I am trying to give a PlayerMobile's location property (which is a Point3D variable) a value from a particular position in an Array of Point3D locations. I know this sounds complicated but bare with me, I will try explain.

Say I have an array of Point3D locations called "Locs", and in this array are various different specific Point3D locations in position 1, 2 and 3.

Now I also have a LIST of mobiles lets say with mobiles that full positions 1 and 2.

Now I want 1 of the mobiles from the LIST (lets say number 2) to have his / her "Location" property set to the same value as the Point3D location in the respective position of the "Locs array"

ie: The mobile in position 2 of the "list of mobiles" must have his / her "Location" property set to the same value as the 2nd Point3D location in the "Locs Array".

example:

* Locs Array position 2 is holding the Point3D location: "1542, 3432, 0" (which is the x, y, z co-ords)
* Position 2 of the Mobile List is holding the Mobile "Jonny" (the actual mobile, not just the name)

I want Jonny's Location property to be set to "1542, 3432, 0" (which is the same value as the second position of the Locs Array).

This is what I have done, code wise:

Code:
[I][B]Mobile[/B][/I].Location = [I][B]Location Array[/B][/I][COLOR="Red"][[/COLOR][I][B]m_MobileListName[/B][/I].Position[COLOR="Red"]][/COLOR];

I hope you understand what I am asking, it was quite difficult to explain as I am sure you see...

Thanks in advance

your bot, typhoon ;)

Thanks for your help thus far guys, it has been a real learning curve...
 

Gargouille

Sorceror
I think you're still far away from the final soluce, but let's go step by step.

Note that JailSystem is a class, but that every jailing process will an instance of that class, you got to have a Timer for each process.

At the tick of your timer, you do :
Code:
if(JailingSystem.ReleaseTime <  DateTime.Now)
You got to notice that JailSystem does not declare any ReleaseTime at all.

ReleaseTime is declare in each instance of MobileFields class.

I suggere something like that :
Code:
public class JailTimer : Timer
	{
		private Mobile Jailed;//that one is accessible in OnTick
		
		public JailTimer(Mobile jailed)//you take a reference to the mobile jailed
			: base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) )
		{
			Priority = TimerPriority.FiftyMS;
			
			Jailed = jailed; //assign the value to the private variable Jailed (which is accessible in OnTick)
		}

		protected override void OnTick() //every 5 seconds executes code in {}
		{
			if(JailingSystem.OnTick(Jailed))//if the mob is free, timer stops
				Stop();
		}
	}

And then, in JailSystem class :
Code:
public bool OnTick(Mobile ToBeFree)
		{
			if(IsInMate(ToBeFree))
			{
				if( (m_inMates[ToBeFree]).ReleaseTime > DateTime.Now )
				{
					RemoveInMate( ToBeFree );
					return true;
				}
				return false;
			}
			return false;
		}

Now, look AddInMate in which you create a new MobileFields :
Code:
m_inMates.Add( from, new MobileFields( TimeJailed, TimeReleased, origPos ));

You got to do it like this:
Code:
m_inMates.Add( from, new MobileFields( DateTime.Now, (DateTime.Now + TimeToBeInJail), new Point3D( from.Location, from.Map )));
where TimeToBeInJail is a TimeSpan...

And then launch a Timer !

Something like :
Code:
private static TimeSpan TimeToBeInJail = TimeSpan.FromHours(1);
		public void AddInMate( Mobile from, DateTime TimeJailed, DateTime TimeReleased, Point3D origPos )
		{
			if ( m_inMates.ContainsKey( from ) )
			{
				RemoveInMate( from );
			}
			
			m_inMates.Add( from, new MobileFields( DateTime.Now, (DateTime.Now + TimeToBeInJail), new Point3D( from.Location, from.Map )));
			
			Timer timer = new JailTimer(from);
			timer.Start();
		}
 

typhoonbot

Sorceror
And one further question:

to set my default cells array, would I use a line such as this in my deserialization method:

JailingSystem.defaultCells();

this is the cells array, and defaultCells method:

Code:
public static ArrayList cells = new ArrayList();
		
		public static void defaultCells()
		{
			cells.Clear();
			cells.Add(new Point3D(5276,1164,0));
			cells.Add(new Point3D(5286,1164,0));
			cells.Add(new Point3D(5296,1164,0));
			cells.Add(new Point3D(5306,1164,0));
			cells.Add(new Point3D(5276,1174,0));
			cells.Add(new Point3D(5286,1174,0));
			cells.Add(new Point3D(5296,1174,0));
			cells.Add(new Point3D(5306,1174,0));
			cells.Add(new Point3D(5283,1184,0));
		}

And this is what I did to deserialization:

Code:
public override void Deserialize( GenericReader reader ) 
		{ 
			base.Deserialize( reader ); 
 
			int count = reader.ReadInt(); 
			
			[COLOR="Red"]JailingSystem.defaultCells();[/COLOR]
			
			m_inMates = new Dictionary<Mobile, MobileFields>(); //no use, until it's already declare, and declared as empty yet

			for( int i = 0; i < count; i++ )
			{
				m_inMates.Add( reader.ReadMobile(), new Data( reader.ReadDateTime(), reader.ReadDateTime(), reader.ReadPoint3D() ));
			}
		}
 

Gargouille

Sorceror
I suggere to do it with a simple array of Poin3D instead of an arraylist (array is not dynamic but we here don't care)...

Code:
private static Point3D[] defaultCells = new Point3D[]
		{
			new Point3D( 1481, 1612, 20 ),
			new Point3D( 2708, 2153,  0 ),
			new Point3D( 2249, 1230,  0 ),
			new Point3D( 5197, 3994, 37 ),
			new Point3D( 1412, 3793,  0 ),
			new Point3D( 3688, 2232, 20 ),
			new Point3D( 2578,  604,  0 ),
			new Point3D( 4397, 1089,  0 ),
			new Point3D( 5741, 3218, -2 ),
			new Point3D( 2996, 3441, 15 ),
			new Point3D(  624, 2225,  0 ),
			new Point3D( 1916, 2814,  0 ),
			new Point3D( 2929,  854,  0 ),
			new Point3D(  545,  967,  0 ),
			new Point3D( 3665, 2587,  0 )
		};

Then, no use to fill it... It's done.
 

typhoonbot

Sorceror
very useful - thank you, now another small question

in a Point3D variable, can I store a x-y-z co-ords and a map

IE:

Point3D loc = new Point3D();

and then go

loc = (mobile.Location, mobile.Map);

?
 

Gargouille

Sorceror
Oups, I made a mistake when write :
Code:
m_inMates.Add( from, new MobileFields( DateTime.Now, (DateTime.Now + TimeToBeInJail), new [COLOR="Red"]Point3D( from.Location, from.Map )[/COLOR]));

Of course, there's no Map in a Point3D

What about just adding a Map variable in your MobileFields?
 

typhoonbot

Sorceror
Yes that is what I will have to do :)

but also some more questions:

first look at my script like it is now

Code:
using System;
using Server.Mobiles;
using System.IO;
using System.Collections;
using System.Collections.Generic; 
using Server; 
using Server.Misc; 
using Server.Items; 
using Server.Gumps; 
using Server.Network;
using Server.Accounting;
using Server.Targeting;
using Server.ContextMenus;
using Server.Commands;
using Server.Regions;

namespace Server.Commands
{
	public class JailingSystem
  	{
		
		public class MobileFields
		{
			private DateTime m_JailedTime;
			private DateTime m_ReleaseTime;
			private Point3D m_Posi;
	
			public DateTime JailedTime
			{ 
				get{ return m_JailedTime; } 
				set{ m_JailedTime = value; } 
			}
			public DateTime ReleaseTime
			{ 
				get{ return m_ReleaseTime; } 
				set{ m_ReleaseTime = value; } 
			}
			public Point3D Posi
			{ 
				get{ return m_Posi; } 
				set{ m_Posi = value; } 
			}
	
			public MobileFields( DateTime jailedTime, DateTime releaseTime, Point3D posi )
			{
				m_JailedTime = jailedTime;
				m_ReleaseTime = releaseTime;
				m_Posi = posi;
			}
		}
		private Dictionary<Mobile, MobileFields> m_inMates = new Dictionary<Mobile, MobileFields>();
		
		private static Point3D[] defaultCells = new Point3D[]
		{
			new Point3D(5276,1164,0),
			new Point3D(5286,1164,0),
			new Point3D(5296,1164,0),
			new Point3D(5306,1164,0),
			new Point3D(5276,1174,0),
			new Point3D(5286,1174,0),
			new Point3D(5296,1174,0),
			new Point3D(5306,1174,0),
			new Point3D(5283,1184,0)

		};
		
		public void AddInMate( Mobile from, DateTime TimeJailed, DateTime TimeReleased, Point3D origPos )
		{
			if ( m_inMates.ContainsKey( from ) )
			{
				RemoveInMate( from );
			}
			
			m_inMates.Add( from, new MobileFields( TimeJailed, TimeReleased, origPos ));
			
			Timer timer = new JailingTimer( from );
			timer.Start();
		}
        
        public void RemoveInMate( Mobile from )
		{
			if( m_inMates.ContainsKey( from ) ) 
			{
				m_inMates.Remove( from );
			}
		}
        
        public bool OnTick(Mobile ToBeFree)
		{
			if( IsInMate( ToBeFree ) )
			{
				if( ( m_inMates[ToBeFree] ).ReleaseTime < DateTime.Now )
				{
					RemoveInMate( ToBeFree );
					return true;
				}
				return false;
			}
			return false;
		}
        
        public static bool IsInMate( Mobile from ) 
		{
			return m_inMates.ContainsKey( from );
		}
        
        public void JailMobile( Mobile offender, TimeSpan sentance, Point3D pos )
        {
        	//When calling JailMobile use "JailMobile( mobile, Timespan, (mobile.Location, mobile.Map) );"
        	DateTime jailTime = DateTime.Now;
        	DateTime releasedTime = (jailTime + sentance);
        	
        	AddInMate(offender, jailTime, releasedTime, pos);
        	
        	//offender.Location = cells[m_inMates.Position];
        }
        
        public void JailMobileWithTarget( Mobile offender, DateTime released, string reason, string jailedBy )
        {
        	
        }

		public JailingSystem( Serial serial ) : base( serial )
		{
		}

		public override void Serialize( GenericWriter writer )
		{
			base.Serialize( writer );

   			if( m_inMates != null ) 
   			{ 
      			writer.Write( true ); 
      			writer.Write( (int) m_inMates.Count );

				foreach( KeyValuePair<Mobile, MobileFields> kvp in m_inMates )
				{
					writer.Write( kvp.Key.Serial );	// Notice how we use Serial
					writer.Write( (Mobile) kvp.Key ); //Mobile
					writer.Write( (DateTime) kvp.Value.JailedTime );
					writer.Write( (DateTime) kvp.Value.ReleaseTime );
					writer.Write( (Point3D) kvp.Value.Posi );
				}
			} 
			else 
			{ 
				writer.Write( false ); 
			} 
		}

		public override void Deserialize( GenericReader reader ) 
		{ 
			base.Deserialize( reader ); 
 
			int count = reader.ReadInt(); 
			
			m_inMates = new Dictionary<Mobile, MobileFields>(); //no use, until it's already declare, and declared as empty yet

			for( int i = 0; i < count; i++ )
			{
				m_inMates.Add( reader.ReadMobile(), new Data( reader.ReadDateTime(), reader.ReadDateTime(), reader.ReadPoint3D() ));
			}
		}
	}
	
	public class JailingTimer : Timer
	{
		private Mobile Jailed;//this is accessible in OnTick
		
		public JailingTimer(Mobile jailed)//you take a reference to the mobile jailed
			: base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) )
		{
			Priority = TimerPriority.FiftyMS;
			
			Jailed = jailed; //assign the value to the private variable Jailed (which is accessible in OnTick)
		}

		protected override void OnTick() //every 5 seconds executes code in {}
		{
			if ( JailingSystem.OnTick( Jailed ) ) //if the mobile is free, timer stops
			{
				Stop();
			}
		}
	}
}

Where does the mobile's location actually get reset to the Original location stored in MobileFields ?

and secondly I still need to figure out how to put them into a cell after adding them to dictionary, this line was my attempt:

//offender.Location = defaultCells[m_inMates.Position];

in other words, the cell they must be put into, must be the same number as what position they are in the m_inMates dictionary
 

Gargouille

Sorceror
Now a word about serialization.

RunUo declares serialization methods for three classes, Item, Mobile and Guild.

As your JailSystem is a child class of object, you can't call Serialize and deserialize methods...

A good way would be to create such methods, I'm not able to do so...:p

The easy way I would use, making such a system, would be to make JailSystem as an Item. Just that.

But it's not academic :eek:

You can do it, for example with a Stone like GuildStones, and create one on gree acres... But if it's deleted, all your values will be lost. And if you create two stones, your Dictionary will be serialize twice...

It's not the best way, but maybe the easiest...

Maybe you should wait for another advice.
 

Gargouille

Sorceror
Code:
 public void RemoveInMate( Mobile from )
		{
			if( m_inMates.ContainsKey( from ) ) 
			{
				from.Location = (m_inMates[from]).Posi;[COLOR="Red"]//go to original location[/COLOR]

				m_inMates.Remove( from );
			}
		}

It would be nice if Dictionary[Key].Rank exist, but...

I suggere that ugly way:
Code:
public void AddInMate( Mobile from, DateTime TimeJailed, DateTime TimeReleased, Point3D origPos )
		{
			if ( m_inMates.ContainsKey( from ) )
			{
				RemoveInMate( from );
			}
			
			m_inMates.Add( from, new MobileFields( TimeJailed, TimeReleased, origPos ));
			
			int rank = 0;
			foreach(Mobile key in m_inMates.Keys)//each Mobile in the Key collection
			{
				if(key == from)
					break;
				
				rank++;	
			}
			
			if(rank > (defaultCells.Count-1)
			   rank = 0;//or you got a serious problem
			
			from.Location = defaultCells[rank];
			
			Timer timer = new JailingTimer( from );
			timer.Start();
		}
 
Top