This week I wanted to design an item that is meant to be used post res to refill the users hit points, mana, and stamina. I put this on a 10 minute lock out and if the item is locked out it gives the user a message with about how long until they can use it again. I know my tutorials are probably not as easy to follow as Kyn's tutorials but I figure I would throw the stuff up here incase anyone else is playing around with C#. Here is how I accomplished said feat:
We start out with the usings, namespace, and constructable as we do in any program with an item. I am going to assume at this point anyone reading these posts knows the general setup for this section:
using System;
using Server;
using Server.Items;
using Server.Mobiles;
namespace Server.Items
{
public class AHealersTouch : Item
{
public override string DefaultName{get {return ("A Healer's Touch");}}
[Constructable]
public AHealersTouch() : base(0x1F1C)
{
this.Weight = 1.0;
LootType = LootType.Blessed;
this.Hue = 37;
}
public AHealersTouch( 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();
}
}
}
This generates an item that is blessed and is a red hued powercrystal. I have added my serialize and deserialize. Now I want this item to do something when double clicked from the players back pack. If the user is less then full of any of the 3 stats it will heal that stat for 300 and give the user a message that they have been healed in that stat. Here is how I performed that function:
public override void OnDoubleClick(Mobile m)
{
if (IsChildOf(m.Backpack))//this is to allow the item to only be used from the backpack
{
if (m.Hits < m.HitsMax)//this heals the user for 300 hit points if they are not already full and gives a message saying they were healed.
{
m.Hits += 300;
m.SendMessage("You feel your life return!");
}
if (m.Stam < m.StamMax)//this heals the user for 300 stam if they are not already full and gives a message saying they were healed.
{
m.Stam += 300;
m.SendMessage("You feel your vigor return!");
}
if (m.Mana < m.ManaMax)//this heals the user for 300 mana if they are not already full and gives a message saying they were healed.
{
m.Mana += 300;
m.SendMessage("You feel your magical prowess return!");
}
}
}
The way the item is setup now it could be spammed as fast as a player could double click the item. This is not something I wanted so I added a 10 minute timer and had the double click check to see if the timer state was true. If it is false (default state when declaring a bool variable) it will perform the heals. If it is true, meaning the item is on lock out it returns a message to the user telling them they need to wait.
public static bool m_Used; //Declare a bool for a timer. This is to keep the item from being spammed
public override void OnDoubleClick(Mobile m)
{
if (IsChildOf(m.Backpack))//this is to allow the item to only be used from the backpack
{
if (m_Used == false)//this allows the item to only be used if not on timer lock out
{
if (m.Hits < m.HitsMax)//this heals the user for 300 hit points if they are not already full and gives a message saying they were healed.
{
m.Hits += 300;
m.SendMessage("You feel your life return!");
}
if (m.Stam < m.StamMax)//this heals the user for 300 stam if they are not already full and gives a message saying they were healed.
{
m.Stam += 300;
m.SendMessage("You feel your vigor return!");
}
if (m.Mana < m.ManaMax)//this heals the user for 300 mana if they are not already full and gives a message saying they were healed.
{
m.Mana += 300;
m.SendMessage("You feel your magical prowess return!");
}
m_Used = true;//this sets the timer tick to a lock out state
UsedTimer used = new UsedTimer();//this declares the timer
used.Start();//this starts the timer
}
else
m.SendMessage("You must wait awhile for the crystals power to return");
}
}
public class UsedTimer : Timer//this starts the timer, Timer is set to 10 mintues in an seconds interval to prevent issues with the display of time left.
{
public UsedTimer() : base(TimeSpan.FromSeconds(600))
{
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()//when the timer is up it resets the reuse so the player can use the item again.
{
m_Used = false;
}
}
Now if we put that all together we would have a functioning item that will heal its user once every 10 minutes. Lets take a look at how this looks
using System;
using Server;
using Server.Items;
using Server.Mobiles;
namespace Server.Items
{
public class AHealersTouch : Item
{
public override string DefaultName{get {return ("A Healer's Touch");}}
[Constructable]
public AHealersTouch() : base(0x1F1C)
{
this.Weight = 1.0;
LootType = LootType.Blessed;
this.Hue = 37;
}
public static bool m_Used; //Declare a bool for a timer. This is to keep the item from being spammed
public override void OnDoubleClick(Mobile m)
{
if (IsChildOf(m.Backpack))//this is to allow the item to only be used from the backpack
{
if (m_Used == false)//this allows the item to only be used if not on timer lock out
{
if (m.Hits < m.HitsMax)//this heals the user for 300 hit points if they are not already full and gives a message saying they were healed.
{
m.Hits += 300;
m.SendMessage("You feel your life return!");
}
if (m.Stam < m.StamMax)//this heals the user for 300 stam if they are not already full and gives a message saying they were healed.
{
m.Stam += 300;
m.SendMessage("You feel your vigor return!");
}
if (m.Mana < m.ManaMax)//this heals the user for 300 mana if they are not already full and gives a message saying they were healed.
{
m.Mana += 300;
m.SendMessage("You feel your magical prowess return!");
}
m_Used = true;//this sets the timer tick to a lock out state
UsedTimer used = new UsedTimer();//this declares the timer
used.Start();//this starts the timer
}
else
m.SendMessage("You must wait awhile for the crystals power to return");
}
}
public class UsedTimer : Timer//this starts the timer, Timer is set to 10 mintues in an seconds interval to prevent issues with the display of time left.
{
public UsedTimer() : base(TimeSpan.FromSeconds(600))
{
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()//when the timer is up it resets the reuse so the player can use the item again.
{
m_Used = false;
}
}
public AHealersTouch( 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();
}
}
}
That would give us a fully functional item but I wanted a little bit more out of it. I do not like when I go to use something in a game and it just tells me to wait. Do I wait a minute, a day, a month. Some times an item just does not tell you. For this I decided I would declare a DateTime variable.
public DateTime NextUse;
This allows me the ability to perform a math function to get variable that stores the time of when the item is usable again and I can perform a math function off of that so I can display that to the user.
NextUse = DateTime.Now + TimeSpan.FromSeconds(600);
TimeSpan NextUseInterval = NextUse - DateTime.Now;
The NextUse is put in the double click section. When the user double clicks the item it sets the NextUse to current time + 600 seconds since this is the length of our timer. The TimeSpan NextUseInterval is in the section of the double click if the timer is running, m_Used = true. This TimeSpan variable takes our NextUse variable that we set at the DateTime that our timer would expire and subtract the current DateTime from it. With this we can perform the Math.Truncate function to provide the user with feed back on how long until the timer resets. We are going to place our NextUseInterval into our m.SendMessage line.
m.SendMessage("You must wait " + Math.Truncate(NextUseInterval.TotalMinutes) + " minutes longer for the crystal's power to return");
Now in this basic form we will a message but when the timer is less then 1 minute it will tell us we must wait 0 minutes to use the item again. Also at 1 minute left it will tell us we have 1 minutes remaining. To clean this up I used an inbedded if series. If the time left is > 1 minute give a message otherwise if it is > 0 give a different message otherwise give a 3rd message. This allows the giving of 3 different messages for 2-10 minutes, 1 minute, and finally seconds remaining. This looks like this
if (Math.Truncate(NextUseInterval.TotalMinutes) > 1)
m.SendMessage("You must wait " + Math.Truncate(NextUseInterval.TotalMinutes) + " minutes longer for the crystal's power to return");
else
if (Math.Truncate(NextUseInterval.TotalMinutes) > 0)
m.SendMessage("You must wait " + Math.Truncate(NextUseInterval.TotalMinutes) + " minute longer for the crystal's power to return");
else
m.SendMessage("You must wait " + Math.Truncate(NextUseInterval.TotalSeconds) + " seconds longer for the crystal's power to return");
Now we put all of this together and we end up with an item that heals the users hit points, stamina, and mana for 300 points each once every 10 minutes. I have added comments to all of my code which is the stuff following the // on any line. This should help you understand what each section is and why it is there.
using System;
using Server;
using Server.Items;
using Server.Mobiles;
namespace Server.Items
{
public class AHealersTouch : Item
{
public override string DefaultName{get {return ("A Healer's Touch");}}
[Constructable]
public AHealersTouch() : base(0x1F1C)
{
this.Weight = 1.0;
LootType = LootType.Blessed;
this.Hue = 37;
}
public static bool m_Used; //Declare a bool for a timer. This is to keep the item from being spammed
public DateTime NextUse;//This is to give the user feedback as to about how long until the item can be used again.
public override void OnDoubleClick(Mobile m)
{
if (IsChildOf(m.Backpack))//this is to allow the item to only be used from the backpack
{
if (m_Used == false)//this allows the item to only be used if not on timer lock out
{
if (m.Hits < m.HitsMax)//this heals the user for 300 hit points if they are not already full and gives a message saying they were healed.
{
m.Hits += 300;
m.SendMessage("You feel your life return!");
}
if (m.Stam < m.StamMax)//this heals the user for 300 stam if they are not already full and gives a message saying they were healed.
{
m.Stam += 300;
m.SendMessage("You feel your vigor return!");
}
if (m.Mana < m.ManaMax)//this heals the user for 300 mana if they are not already full and gives a message saying they were healed.
{
m.Mana += 300;
m.SendMessage("You feel your magical prowess return!");
}
m_Used = true;//this sets the timer tick to a lock out state
UsedTimer used = new UsedTimer();//this declares the timer
used.Start();//this starts the timer
NextUse = DateTime.Now + TimeSpan.FromSeconds(600);//this declares the time until the item is useable again.
}
else
{
TimeSpan NextUseInterval = NextUse - DateTime.Now;//this calculates how long until the player has to wait until the item is usable again.
if (Math.Truncate(NextUseInterval.TotalMinutes) > 1)
m.SendMessage("You must wait " + Math.Truncate(NextUseInterval.TotalMinutes) + " minutes longer for the crystal's power to return");//This gives the user the lock out message if the time left is well over 1 minute
else
if (Math.Truncate(NextUseInterval.TotalMinutes) > 0)
m.SendMessage("You must wait " + Math.Truncate(NextUseInterval.TotalMinutes) + " minute longer for the crystal's power to return");//This gives the user a lock out message if the time left is about 1 minute
else
m.SendMessage("You must wait " + Math.Truncate(NextUseInterval.TotalSeconds) + " seconds longer for the crystal's power to return");//this gives the user a lock out message if the time left is less then 1 minute. the message is in seconds
}
}
}
public class UsedTimer : Timer//this starts the timer, Timer is set to 10 mintues in an seconds interval to prevent issues with the display of time left.
{
public UsedTimer() : base(TimeSpan.FromSeconds(600))
{
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()//when the timer is up it resets the reuse so the player can use the item again.
{
m_Used = false;
}
}
public AHealersTouch( 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();
}
}
}