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!

[1.0] Harvest System 1.4

G

GoldDraco13

Guest
DarkJustin said:
I was looking through the scripts and I am stumped....

Where is the variable that says when the crop can be harvested and how long it would take to produce maximum yield? HELP! ((I want to set this system up for my shard but I am wanting faster results...I am very impatient as the people on my shard would be...


For the Crops...check CropHelper.cs

if ( cnt++ / 100 > rnd ) // between 10 and 30 minutes

For the Trees....check the TreeHelper.cs

public static TimeSpan SaplingTime = TimeSpan.FromHours( 3 ); // Time spent as a Sapling
public static TimeSpan StumpTime = TimeSpan.FromHours( 1 ); // Time spent as a Stump


Hope this helps :)
 

kriggle

Wanderer
I created wheat as an item, using the same bag image as flour and called it a bag of wheat. I then changed the section of the harvest script for wheat crop to yield a bag of wheat instead of the standard bread loaf. The server compiles the scripts fine and runs fine, until I pick from a wheat plant, at which point it crashes. Here is the code as I changed it in Harvest
Code:
 using System; 
using System.Collections;
using Server.Network; 
using Server.Mobiles; 
using Server.Items; 
using Server.Gumps;

namespace Server.Items.Crops 
{ 
	public class WheatSeed : BaseCrop 
	{ 
		// return true to allow planting on Dirt Item (ItemID 0x32C9)
		// See CropHelper.cs for other overriddable types
		public override bool CanGrowGarden{ get{ return true; } }
		
		[Constructable]
		public WheatSeed() : this( 1 )
		{
		}

		[Constructable]
		public WheatSeed( int amount ) : base( 0xF27 )
		{
			Stackable = true; 
			Weight = .5; 
			Hue = 0x5E2; 

			Movable = true; 
			
			Amount = amount;
			Name = "Wheat Seed"; 
		}
		
		public override Item Dupe( int amount )
		{
			return base.Dupe( new WheatSeed( amount ), amount );
		}		

		public override void OnDoubleClick( Mobile from ) 
		{ 
			if ( from.Mounted && !CropHelper.CanWorkMounted )
			{
				from.SendMessage( "You cannot plant a seed while mounted." ); 
				return; 
			}

			Point3D m_pnt = from.Location;
			Map m_map = from.Map;

			if ( !IsChildOf( from.Backpack ) ) 
			{ 
				from.SendLocalizedMessage( 1042010 ); //You must have the object in your backpack to use it. 
				return; 
			} 

			else if ( !CropHelper.CheckCanGrow( this, m_map, m_pnt.X, m_pnt.Y ) )
			{
				from.SendMessage( "This seed will not grow here." ); 
				return; 
			}
			
			//check for BaseCrop on this tile
			ArrayList cropshere = CropHelper.CheckCrop( m_pnt, m_map, 0 );
			if ( cropshere.Count > 0 )
			{
				from.SendMessage( "There is already a crop growing here." ); 
				return;
			}

			//check for over planting prohibt if 4 maybe 3 neighboring crops
			ArrayList cropsnear = CropHelper.CheckCrop( m_pnt, m_map, 1 );
			if ( ( cropsnear.Count > 3 ) || (( cropsnear.Count == 3 ) && Utility.RandomBool() ) )
			{
				from.SendMessage( "There are too many crops nearby." ); 
				return;
			}

			if ( this.BumpZ ) ++m_pnt.Z;

			if ( !from.Mounted )
				from.Animate( 32, 5, 1, true, false, 0 ); // Bow

			from.SendMessage("You plant the seed."); 
			this.Consume(); 
			Item item = new WheatSeedling( from ); 
			item.Location = m_pnt; 
			item.Map = m_map; 
		
		} 

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

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

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


	public class WheatSeedling : BaseCrop 
	{ 
		private static Mobile m_sower;
		public Timer thisTimer;

		[CommandProperty( AccessLevel.GameMaster )]
		public Mobile Sower{ get{ return m_sower; } set{ m_sower = value; } }
		
		[Constructable] 
		public WheatSeedling( Mobile sower ) : base( Utility.RandomList ( 0xDAE, 0xDAF ) ) 
		{ 
			Movable = false; 
			Name = "Wheat Seedling"; 
			m_sower = sower;
			
			init( this );
		} 

		public static void init( WheatSeedling plant )
		{
			plant.thisTimer = new CropHelper.GrowTimer( plant, typeof(WheatCrop), plant.Sower ); 
			plant.thisTimer.Start(); 
		}

		public override void OnDoubleClick( Mobile from ) 
		{ 
			if ( from.Mounted && !CropHelper.CanWorkMounted )
			{
				from.SendMessage( "The crop is too small to harvest while mounted." ); 
				return; 
			}

			if ( ( Utility.RandomDouble() <= .25 ) && !( m_sower.AccessLevel > AccessLevel.Counselor ) ) 
			{ //25% Chance
				from.SendMessage( "You uproot the seedling." ); 
				thisTimer.Stop();
				this.Delete();
			}
			else from.SendMessage( "This crop is too young to harvest." ); 
		}

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

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

		public override void Deserialize( GenericReader reader ) 
		{ 
			base.Deserialize( reader ); 
			int version = reader.ReadInt(); 
			m_sower = reader.ReadMobile();

			init( this );
		} 
	} 

	public class WheatCrop : BaseCrop 
	{ 
		private const int max = 10;
		private int fullGraphic;
		private int pickedGraphic;
		private DateTime lastpicked;

		private Mobile m_sower;
		private int m_yield;

		public Timer regrowTimer;

		private DateTime m_lastvisit;

		[CommandProperty( AccessLevel.GameMaster )] 
		public DateTime LastSowerVisit{ get{ return m_lastvisit; } }

		[CommandProperty( AccessLevel.GameMaster )] 
		public bool Growing{ get{ return regrowTimer.Running; } }

		[CommandProperty( AccessLevel.GameMaster )]
		public Mobile Sower{ get{ return m_sower; } set{ m_sower = value; } }
		
		[CommandProperty( AccessLevel.GameMaster )]
		public int Yield{ get{ return m_yield; } set{ m_yield = value; } }

		public int Capacity{ get{ return max; } }
		public int FullGraphic{ get{ return fullGraphic; } set{ fullGraphic = value; } }
		public int PickGraphic{ get{ return pickedGraphic; } set{ pickedGraphic = value; } }
		public DateTime LastPick{ get{ return lastpicked; } set{ lastpicked = value; } }
		
		[Constructable] 
		public WheatCrop( Mobile sower ) : base( Utility.RandomList( 0xC55, 0xC56 ) ) 
		{ 
			Movable = false; 
			Name = "Wheat Plant"; 

			m_sower = sower;
			m_lastvisit = DateTime.Now;

			init( this, false );
		}

		public static void init ( WheatCrop plant, bool full )
		{
			plant.PickGraphic = Utility.RandomList( 0xC55, 0xC56, 0xC57, 0xC59 );
			plant.FullGraphic = Utility.RandomList( 0xC58, 0xC5A, 0xC5B );

			plant.LastPick = DateTime.Now;
			plant.regrowTimer = new CropTimer( plant );

			if ( full )
			{
				plant.Yield = plant.Capacity;
				((Item)plant).ItemID = plant.FullGraphic;
			}
			else
			{
				plant.Yield = 0;
				((Item)plant).ItemID = plant.PickGraphic;
				plant.regrowTimer.Start();
			}
		}
		
		public void UpRoot( Mobile from )
		{
			from.SendMessage( "The crop withers away." ); 
			if ( regrowTimer.Running )
				regrowTimer.Stop();

			this.Delete();
		}

		public override void OnDoubleClick( Mobile from ) 
		{ 
			if ( m_sower == null || m_sower.Deleted ) 
				m_sower = from;

			if ( from.Mounted && !CropHelper.CanWorkMounted )
			{
				from.SendMessage( "You cannot harvest a crop while mounted." ); 
				return; 
			}

			if ( DateTime.Now > lastpicked.AddSeconds(3) ) // 3 seconds between picking
			{
				lastpicked = DateTime.Now;
			
				int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 20;
				if ( lumberValue == 0 )
				{
					from.SendMessage( "You have no idea how to harvest this crop." ); 
					return;
				}

				if ( from.InRange( this.GetWorldLocation(), 1 ) ) 
				{ 
					if ( m_yield < 1 )
					{
						from.SendMessage( "There is nothing here to harvest." ); 

						if ( PlayerCanDestroy && !( m_sower.AccessLevel > AccessLevel.Counselor ) )
						{  
							UpRootGump g = new UpRootGump( from, this );
							from.SendGump( g );
						}
					}
					else //check skill and sower
					{
						from.Direction = from.GetDirectionTo( this );

						from.Animate( from.Mounted ? 29:32, 5, 1, true, false, 0 ); 

						if ( from == m_sower ) 
						{
							lumberValue *= 2;
							m_lastvisit = DateTime.Now;
						}

						if ( lumberValue > m_yield ) 
							lumberValue = m_yield + 1;

						int pick = Utility.Random( lumberValue );
						if ( pick == 0 )
						{
							from.SendMessage( "You do not manage to harvest any crops." ); 
							return;
						}
					
						m_yield -= pick;
						from.SendMessage( "You harvest {0} crop{1}!", pick, ( pick == 1 ? "" : "s" ) ); 

						//PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); // use for debuging
						((Item)this).ItemID = pickedGraphic;

						// ********************************
						// *** Wheat does not yet exist ***
						// ********************************
						Wheat crop = new Wheat( pick ); 
						//BreadLoaf crop = new BreadLoaf( pick ); 
						from.AddToBackpack( crop );

						if ( SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !( m_sower.AccessLevel > AccessLevel.Counselor ) )
						{
							this.UpRoot( from );
							return;
						}

						if ( !regrowTimer.Running )
						{
							regrowTimer.Start();
						}
					}
				} 
				else 
				{ 
					from.SendMessage( "You are too far away to harvest anything." ); 
				} 
			}
		} 

		private class CropTimer : Timer
		{
			private WheatCrop i_plant;

			public CropTimer( WheatCrop plant ) : base( TimeSpan.FromSeconds( 600 ), TimeSpan.FromSeconds( 15 ) )
			{
				Priority = TimerPriority.OneSecond;
				i_plant = plant;
			}

			protected override void OnTick()
			{
				if ( ( i_plant != null ) && ( !i_plant.Deleted ) )
				{
					int current = i_plant.Yield;

					if ( ++current >= i_plant.Capacity )
					{
						current = i_plant.Capacity;
						((Item)i_plant).ItemID = i_plant.FullGraphic;
						Stop();
					}
					else if ( current <= 0 )
						current = 1;

					i_plant.Yield = current;
					//i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); // use for debuging
				}
				else Stop();
			}
		}

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

		public override void Serialize( GenericWriter writer ) 
		{ 
			base.Serialize( writer ); 
			writer.Write( (int) 1 ); 
			writer.Write( m_lastvisit );
			writer.Write( m_sower );
		} 

		public override void Deserialize( GenericReader reader ) 
		{ 
			base.Deserialize( reader ); 
			int version = reader.ReadInt(); 
			switch ( version )
			{
				case 1:
				{
					m_lastvisit = reader.ReadDateTime();
					goto case 0;
				}
				case 0:
				{
					m_sower = reader.ReadMobile();
					break;
				}
			}

			if ( version == 0 ) 
				m_lastvisit = DateTime.Now;

			init( this, true );
		} 
	} 
}

This is what I scripted to act as a bag of wheat:
Code:
 public class Wheat : Item
	{
		[Constructable]
		public Wheat() : base( 0x1039 )
		{
			Weight = 1.0;
			Name = "wheat";
			Hue = 46;
		}

		public Wheat( 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 override void OnDoubleClick( Mobile from )
		{
			if ( !Movable )
				return;

#if false
			this.Delete();

			from.AddToBackpack( new SackFlourOpen() );
#endif
		}

	}

And lastly, this is the error message that is logged when the server crashes:
Code:
Exception:
System.Exception: Items array is null--are you calling the serialization constructor? Type=Server.Items.Wheat
   at Server.Item.set_Map(Map value)
   at Server.Item.AddItem(Item item)
   at Server.Items.Container.DropItem(Item dropped)
   at Server.Items.BaseContainer.TryDropItem(Mobile from, Item dropped, Boolean sendFullMessage)
   at Server.Mobile.PlaceInBackpack(Item item)
   at Server.Mobile.AddToBackpack(Item item)
   at Server.Items.Crops.WheatCrop.OnDoubleClick(Mobile from)
   at Server.Mobile.Use(Item item)
   at Server.Network.PacketHandlers.UseReq(NetState state, PacketReader pvSrc)
   at Server.Network.MessagePump.HandleReceive(NetState ns)
   at Server.Network.MessagePump.Slice()
   at Server.Core.Main(String[] args)

Can someone help me out with what I did wrong to cause the crash? When I switch the crop back to bread it works fine again so I am figuring it has to be something wrong with the snippit I added to act as wheat, but unfortunately debugging is not my strong suit. BTW, I'm running 1.0.

-Kriggle-
 

David

Moderate
The Harvest script expects to pass an integer specifing how many of the item to create. You could take that out of the WheatCrop script, but I think changing your Wheat item would be a better approach. Change your constructor a tad and add a new overridden one.
Code:
		[Constructable]
		public Wheat( int amount ) : base( 0x1039 )
		{
			Weight = 1.0;
			Name = "wheat";
			Hue = 46;
			Amount = amount;
		}

		[Constructable]
		public Wheat() : this( 1 )
		{
		}
Then, if you add this line as well (in the first constructor) Stackable = true; along with the following method, you will be able to stack and split stacks of your Wheat item.
Code:
		public override Item Dupe( int amount )
		{
			return base.Dupe( new Wheat( amount ), amount );
		}
 

kriggle

Wanderer
I'm not sure if anyone has tackled this issue or not yet, but I scripted a corn crop based on the corn static tile (itemID 0xc81). As it turns out it is stackable and you can dupe them without a problem...Unfortunately when I try to allow the CornCrop.cs to give more than 1 crop at a time it still only gives one corn. This is the section I scripted for corn
Code:
 //Corn
	public class Corn : Food
	{
		[Constructable]
		public Corn() : this( 1 )
		{
		}

		[Constructable]
		public Corn( int amount ) : base( amount, 0xc81 )
		{
			this.Weight = 1.0;
			this.FillFactor = 1;
		}

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

		public override Item Dupe( int amount )
		{
			return base.Dupe( new Corn(), amount );
		}

		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();
		}
	}

I added it in the Vegetables.cs file after Pumpkins. If it works it would solve the problem of not having corn/wheat (as I was considering just re-hueing the corn to a brown and naming it wheat).

-Kriggle-
 

David

Moderate
In CornCrop.cs at line 300 comment out this
Code:
// *** Limit to one yield until we have Corn item ***
if ( pick > 1 ) pick = 1;
 

KillerBeeZ

Knight
*ReVeNaNt* said:
I have a question: if the sower want to delete a plant, how he can do this?

Thanks

don't think they can.

but it might be a good idea to delete the plant automatically if the dirt patch under it is moved
 

David

Moderate
In CropHelper.cs there is a switch named PlayerCanDestroy, make sure it is set to true. Then harvest a crop until there is no more to harvest, and harvest it again. The player should get a gump asking if they wish to destroy the crop.
 

KillerBeeZ

Knight
David said:
In CropHelper.cs there is a switch named PlayerCanDestroy, make sure it is set to true. Then harvest a crop until there is no more to harvest, and harvest it again. The player should get a gump asking if they wish to destroy the crop.

oh, duh I should have thought of that :D thats what I get for posting before coffee :eek:
 

David

Moderate
I have actually started on version 2.0, in the midst of all my other projects. I'll make sure those make it in. ;)
 

David

Moderate
Well thanks, but this is actually a two year old thread/script. I do appreciate any comments on any of my scripts, but please be careful that you don't necro old threads unless there is a specific question or issue.

(++karma to you for the kudos ;) )
 

koluch

Sorceror
Super!

Minutes I never got to work, used an extended seconds timer - still too fast but better.
Look forward to your update!
 
David

How about you can only harvest it 3 times and it dies. And give the seeds a success/failure rate. Lengthen the time would help. And maybe have it sprout after a couple of hours and then make the owner have to give it a greater heal potion and some water before it finishes growing, so that the expense goes up a bit. Not to mention they have to find someone to supply them with the greater heal potions and/or must train an alchemist but even then they need reagents and bottles. I can't see Razor doing all of that. And plants are far more complicated than I just described. And farming would still be well worth it.

Just a few ideas. Many are on my wishlist :)
 

koluch

Sorceror
Excellent suggestions

Limited number of times you can harvest a crop would be great - also keeps players purchasing seeds and spending their GPs they make from the harvest.
Potions make sense, but why not keep it simple enough, on the scripting end. The only real issue we ever encountered, was players 'milking' the cash - and it is sad but true, it is just a very few players. Most use the system responsibly and as a 'farmer hobby' which is why I liked it to begin with :)
 
Scripting End of Things

Potions make sense, but why not keep it simple enough, on the scripting end. The only real issue we ever encountered, was players 'milking' the cash - and it is sad but true, it is just a very few players. Most use the system responsibly and as a 'farmer hobby' which is why I liked it to begin with :)
I didn't say potion(s). I said 1 heal potion and some water. And the reason I said that is cause it would be easier in the scripting. The plant sprouts and is dormant. You then use a heal potion and some water...then the timer starts for it's growth. Requiring more gold to be spent on farming and less money being milked. And not to mention that they can't use Razor to do all that while they are in bed sleeping (AFK). Hope I clarified that.
 
Top