|
||
|
|||||||
| FAQ Forum A place to find answers to the most frequently asked questions, and a place to post said answers. Do NOT use this forum to ask questions. |
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 (permalink) |
|
Forum Newbie
Join Date: Sep 2006
Age: 28
Posts: 78
|
Hi all, I didn't know about this sub-forum so I posted this rant in the Script forum, I'll put it here so that more people can find it
![]() Any optimizations are welcome, I'm only a noob... Introduction Ok, I've only been looking through the UO scripting system since yesterday and yeah I've started C# pretty much at the same time. But I tried yesterday to play around with the system and it took me a while to centralize all the information needed to make even the most basic quest... So I'm starting this thread so that you can tell me what I'm doing wrong or what I'm doing right ![]() Take this thread as a learning rant by my part, tell me where I'm wrong or what I've done badly that way I can correct myself ![]() Hopefully the moderators won't be too annoyed but I learnt a bit, wasted lots of time trying to gather in one place this information. If a moderator prefers to delete this thread, don't worry I won't mind ![]() Story of the quest : Basically this is an excuse to play around with the scripting language : Bob is a mobile we'll be creating and he'll give you the opportunity to have fun killing 10 rabbits (cruel world isn't it?). If you say yes then 10 rabbits are created next to Bob, if you say no then he'll just ignore you after that... Now since we're in a MMORPG, it's possible that another player comes around and tries to kill the rabbits, we'll have to handle that later and I'll show two techniques I found to do it ![]() Oh, and I forgot, the reward you get for killing the 10 rabbits is a nice black bear ![]() Ok, so that's for the excuse of the quest, now there are only fourfiles that are going to be attached to this quest. The file explaining who's Bob, the behaviour of Bob's rabbits and the gump you'll get when you talk to bob for the first time and of course a special marker to handle the quest's stage. Configuration First things first, in your RunUO directory, go in the Scripts subdirectory and create a Custom subdirectory. When you'll launch RunUO, it goes through the directories and compiles everything that's new (At least I assume it doesn't try to compile everything from scratch when there's a change...) In this new Custom directory, we'll add a BunnyAttack directory. Thanks to Rosey1's way of putting the files, I made a mobiles, items and gumps directory. I assume it's a classical way of separating types of elements and it does make sense so go ahead and make those three directories. Let's start with the easiest file : BobsQuestMarker.cs that I'll put in a new directory named markers, itself put in the items folder. A marker is basically an invisible object that will help the NPCs (and bunnies) to know where the player is up to in the quest. This marker is like any other item in the game, it inherits from the base class Item and, of course, you can add as many variables that you will need to handle your quest. Some people like to have a certain number of markers to handle their quests. That's ok too but generally it becomes more a hassle to remember what marker is what. Centralizing everything (though you'll be using slightly more memory) is, I think, a good idea... Code : BobsQuestMarker.cs Anyhow, here goes ! The beginning of this file just takes care of the includes, defines what namespace we're in (we're in Server.Items because a marker is an item) and we define our new class BobsQuestMarker. Code:
using System;
using Server.Items;
namespace Server.Items
{
public class BobsQuestMarker : Item
{
Code:
public enum BobsQuestState
{
START,
GETREWARD,
FINISHED,
IGNORE
}
private int pm_counter;
private BobsQuestState pm_state;
Here, we define 4 states : START means the quest is started, GETREWARD that the player did what was necessary and can get the reward, FINISHED means the quest is finished and IGNORE is the state when the NPC should ignore the player (if the player refused the quest for example)... Of course, you can add states or remove a few depending on your needs... Now if you notice, I declared the variables private because, as all Object oriented language, we don't like it when people can just change the values. What if someone tries to change the state to a value not handled ? The solution is to define get/set methods and in C# it's done this way : Code:
public int Counter
{
get {return pm_counter;}
set {pm_counter = value;}
}
public BobsQuestState QuestState
{
get { return pm_state; }
set { pm_state = value; }
}
Code:
//Decrement counter bqm.Counter--; Anyway, next comes the constructor of this object : Code:
public BobsQuestMarker()
: base(0x176B)
{
Weight = 0;
Name = "BobsQuestMarker";
Hue = 0;
pm_counter = 0;
pm_state = BobsQuestState.START;
LootType = LootType.Blessed;
Movable = false;
Visible = false;
}
Of course, the element is not movable, it's blessed so that it doesn't degrade, the counter is put to 0 and the state is the beginning of the quest. We put the weight to 0 and set a name. The name could be a parameter of the constructor to define different markers that have the same kind of information needs (a counter and a state...). Finally we have the serialization and deserialization methods that need to store and load the counter and the state, this is how we can do it : Code:
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int) 0);
writer.Write(pm_counter);
writer.Write((int) pm_state);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
pm_counter = reader.ReadInt();
pm_state = (BobsQuestState) reader.ReadInt();
}
.As you can see, nothing really complicated here but we now have a really nice marker that can count the number of Rabbits we kill and Bob can see where we are at in the quest by looking in this marker. That is already something quite sweet (at least I think so...) If I've done anything wrong, please tell me about it, as I've said, this is my first attempt so I might be doing things the wrong way... The full code is here : Code:
using System;
using Server.Items;
namespace Server.Items
{
public class BobsQuestMarker : Item
{
public enum BobsQuestState
{
START,
GETREWARD,
FINISHED,
IGNORE
}
private int pm_counter;
private BobsQuestState pm_state;
public int Counter
{
get {return pm_counter;}
set {pm_counter = value;}
}
public BobsQuestState QuestState
{
get { return pm_state; }
set { pm_state = value; }
}
public BobsQuestMarker()
: base(0x176B)
{
Weight = 0;
Name = "BobsQuestMarker";
Hue = 0;
pm_counter = 0;
pm_state = BobsQuestState.START;
LootType = LootType.Blessed;
Movable = false;
Visible = false;
}
public BobsQuestMarker(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int) 0);
writer.Write(pm_counter);
writer.Write((int) pm_state);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
pm_counter = reader.ReadInt();
pm_state = (BobsQuestState) reader.ReadInt();
}
}
}
Jc
Last edited by daat99; 09-25-2006 at 07:27 PM. |
|
|
|
|
|
#2 (permalink) |
|
Forum Newbie
Join Date: Sep 2006
Age: 28
Posts: 78
|
Here is the second part :
Introduction Ok, now let's define Bob... This file will define Bob's behaviour towards the player. Basically he has these behaviours : - If he's never seen the player, he'll send a GUMP (a little window) and ask if the player wants to have fun with his rabbits - If the player has accepted the quest but has not finished, he'll tell the player to continue and tell him how many rabbits still need to be killed - If the player has accepted the quest and is waiting for a reward, he'll create a bear and say "Wow, you've done it, here is your surprise!" - If the player has finished the quest (got the reward), he'll say "You've already had fun, now go away" - If the player has refused the quest, he'll say "You refused the quest, it is too late now" So Bob is a mobile, naturally he'll be in the Server.Mobiles namespace. Code file : Bob.cs We start off with a certain number of includes : Code:
using System; using Server; using Server.ContextMenus; using Server.Gumps; using Server.Items; using Server.Mobiles; using System.Collections; using System.Collections.Generic; ![]() Anyway, here's the beginning of the class Code:
namespace Server.Mobiles
{
[CorpseName("a noble corpse")]
public class Bob : Mobile
{
public virtual bool IsInvulnerable { get { return true; } }
![]() Anyway, after that we have the constructor that defines if Bob is a woman or a man, his name, his clothes, his hair color, is he blessed, etc. Code:
[Constructable]
public Bob()
{
Name = "Bob";
Body = 400;
VirtualArmor = 50;
CantWalk = true;
Female = false;
HairItemID = 0x203B;
HairHue = 0x1;
AddItem(new Server.Items.LongPants(0x1));
AddItem(new Server.Items.FancyShirt(0x481)); ;
AddItem(new Server.Items.ThighBoots(0x1));
AddItem(new Server.Items.FeatheredHat(0x1));
AddItem(new Server.Items.Cloak(0x485));
Blessed = true;
}
Code:
public Bob(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();
}
Ok now, what we want is to handle his behavior when we talk to him. What we want to do is add a new entry in the ContextMenu, this is done by adding a BobEntry class and a instance to the ContextMenu : Code:
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
{
base.GetContextMenuEntries(from, list);
list.Add(new BobEntry(from, this));
}
Code:
public class BobEntry : ContextMenuEntry
{
private Mobile m_Mobile;
private Mobile m_Giver;
public BobEntry(Mobile from, Mobile giver)
: base(6146, 3)
{
m_Mobile = from;
m_Giver = giver;
}
- We have two private members that give us the NPC that is clicked on and the player that clicked on the NPC. This is really important since it can give us the possibility to check where the player is up to in the quest... So m_Mobile is the player and m_Giver is the NPC (Bob in our case) - The constructor of BobEntry calls the superclass with two parameters : 6146 is the code to say that it is a TextEntry (but I have been unable to find where all the codes are defined and I only suppose this code is for that). The second parameter is the range for this action. That means that the distance between the player and Bob must be less than 3 to be able to talk to him. Now we implement only one function in this class : OnClick : First thing is to check we have a mobile that has clicked on this NPC (I don't think it's possible that m_Mobile be null but let's be paranoid... Code:
public override void OnClick()
{
PlayerMobile mobile = (PlayerMobile)m_Mobile;
if (mobile != null)
{
Code:
BobsQuestMarker bqm = mobile.Backpack.FindItemByType(typeof(BobsQuestMarker)) as BobsQuestMarker; ![]() If the player does not have the marker bqm will be null. If so, we'll popup a gump (a little window) to ask the player if he wants to start the quest. Needless to say that if the player accepts, the gump will add the marker to the player. If the player refuses then it's your choice. You can either do nothing and, when the player retalks to Bob, he'll ask if the player wants the quest again. Or you can add the marker and set it somehow so that Bob knows the player refused the quest. I chose the later solution since it's a little bit more interesting... Code:
//No marker
if (bqm == null)
{
mobile.SendGump(new StartQuest());
}
Code:
else
{
switch (bqm.QuestState)
{
- If the player has just started the quest or is doing it, the state is START, thus Bob will remind the player how many rabbits still need to be killed : Code:
case BobsQuestMarker.BobsQuestState.START:
m_Giver.Say("You've got work to do : " + bqm.Counter + " rabbits to kill !");
break;
Then, if it's in the START state, Bob will say You've got work to do : 4 rabbits to kill ! for example. This is done using the m_Giver (that's Bob, he's the one who Gives the event). Using the method Say we can make him say something and we'll use the counter in the marker to make him keep count for the player. Next state is when the player has finished killing the monsters : Code:
case BobsQuestMarker.BobsQuestState.GETREWARD:
bqm.QuestState = BobsQuestMarker.BobsQuestState.FINISHED;
m_Giver.Say("Wow, you've done it, here is your surprise!");
m_Giver.Say("A bear!");
Point3D pt = m_Giver.Location;
pt.X += Utility.Random(6) - 3;
pt.Y += Utility.Random(6) - 3;
BlackBear bear = new BlackBear();
bear.MoveToWorld(pt, Map.Trammel);
break;
Next, we make him say two phrases to interact with the player. And now we want to create a bear somewhere nearby. Of course, we could make it appear at a fixed place but I prefer to randomize it and use Bob's current position. This means that an admin can put Bob anywhere in the world and the script will still work ! So we get the location of m_Giver (Bob in our case), we add to the position a random number between [-3,3] (though depending if Random does [0,5] or [0,6], it could be just [-3,5]). That's not really important in this case so I didn't spend too much time looking into the implementation of Random ![]() Once we've decided on the position, we create the BlackBear and move it in the world. There should be a way to get the map Bob is in but I haven't taken the time to look into that yet either. Note: Normally, we should check that the point is in the Map since if Bob is too close to the edge the bear might be out of the map. This can be a problem if the function MoveToWorld doesn't check the position we want to move the bear to. A simple test of the position pt could handle this correctly. Now let's finish this switch ! The state FINISHED makes bob just say something, as does the state IGNORE : Code:
case BobsQuestMarker.BobsQuestState.FINISHED:
m_Giver.Say("You've already had fun, now go away");
break;
case BobsQuestMarker.BobsQuestState.IGNORE:
m_Giver.Say("You refused the quest, it is too late now");
break;
default:
break;
}
}
Again, there are some spots where I'm not sure of myself, if someone could complete or clarify those things, it would be great ! Jc Here's the full code : Code:
using System;
using Server;
using Server.ContextMenus;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
using System.Collections;
using System.Collections.Generic;
namespace Server.Mobiles
{
[CorpseName("a noble corpse")]
public class Bob : Mobile
{
public virtual bool IsInvulnerable { get { return true; } }
[Constructable]
public Bob()
{
Name = "Bob";
Body = 400;
VirtualArmor = 50;
CantWalk = true;
Female = false;
HairItemID = 0x203B;
HairHue = 0x1;
AddItem(new Server.Items.LongPants(0x1));
AddItem(new Server.Items.FancyShirt(0x481)); ;
AddItem(new Server.Items.ThighBoots(0x1));
AddItem(new Server.Items.FeatheredHat(0x1));
AddItem(new Server.Items.Cloak(0x485));
Blessed = true;
}
public Bob(Serial serial)
: base(serial)
{
}
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
{
base.GetContextMenuEntries(from, list);
list.Add(new BobEntry(from, this));
}
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 BobEntry : ContextMenuEntry
{
private Mobile m_Mobile;
private Mobile m_Giver;
public BobEntry(Mobile from, Mobile giver)
: base(6146, 3)
{
m_Mobile = from;
m_Giver = giver;
}
public override void OnClick()
{
PlayerMobile mobile = (PlayerMobile)m_Mobile;
if (mobile != null)
{
BobsQuestMarker bqm = mobile.Backpack.FindItemByType(typeof(BobsQuestMarker)) as BobsQuestMarker;
//No marker
if (bqm == null)
{
mobile.SendGump(new StartQuest());
}
else
{
switch (bqm.QuestState)
{
case BobsQuestMarker.BobsQuestState.START:
m_Giver.Say("You've got work to do : " + bqm.Counter + " rabbits to kill !");
break;
case BobsQuestMarker.BobsQuestState.GETREWARD:
bqm.QuestState = BobsQuestMarker.BobsQuestState.FINISHED;
m_Giver.Say("Wow, you've done it, here is your surprise!");
m_Giver.Say("A bear!");
Point3D pt = m_Giver.Location;
pt.X += Utility.Random(6) - 3;
pt.Y += Utility.Random(6) - 3;
BlackBear bear = new BlackBear();
bear.MoveToWorld(pt, Map.Trammel);
break;
case BobsQuestMarker.BobsQuestState.FINISHED:
m_Giver.Say("You've already had fun, now go away");
break;
case BobsQuestMarker.BobsQuestState.IGNORE:
m_Giver.Say("You refused the quest, it is too late now");
break;
default:
break;
}
}
}
}
}
}
}
Last edited by daat99; 09-25-2006 at 07:26 PM. |
|
|
|
|
|
#3 (permalink) |
|
Forum Newbie
Join Date: Sep 2006
Age: 28
Posts: 78
|
Here is the third part :
Code file : startquest.cs Ok, here's the third file I created for this excuse of a quest : startquest.cs. I'll skip the includes and go to the definition of the class. We are making a GUMP so we are of course in the namespace Server.Gumps : Code:
namespace Server.Gumps
{
public class StartQuest : Gump
{
Code:
const int RABBITNBR = 10; Code:
public StartQuest()
: base( 0, 0 )
{
this.Closable=false;
this.Disposable=true;
this.Dragable=true;
this.Resizable=false;
this.AddPage(0);
this.AddImage(106, 68, 7);
this.AddHtml(139, 103, 230, 105, "Ahhh, want to play a little game ? <br> If you want, I'll take 10 rabbits out of my hat, if you kill them all, you'll get a surprise !", false, true);
Code:
this.AddButton(164, 214, 247, 248, 0, GumpButtonType.Reply, 0); this.AddButton(284, 214, 242, 243, 1, GumpButtonType.Reply, 0); } This means we'll be defining the function OnResponse next ! In our case, we have a OK Button (ID 0) and a Cancel Button (ID 1). Code:
public override void OnResponse(NetState state, RelayInfo info)
{
Mobile from = state.Mobile;
Code:
switch (info.ButtonID)
{
case 0:
![]() Code:
{
from.SendMessage("Good luck!");
//Add the marker
BobsQuestMarker bqm = new BobsQuestMarker();
bqm.Counter = RABBITNBR;
Code:
from.AddToBackpack(bqm); Code:
//Create rabbits
int i;
Point3D pt = from.Location,
rabbitpos = new Point3D();
for (i = 0; i < RABBITNBR; i++)
{
rabbitpos.X = pt.X + Utility.Random(6) - 3;
rabbitpos.Y = pt.Y + Utility.Random(6) - 3;
rabbitpos.Z = pt.Z;
BobsRabbit br = new BobsRabbit();
br.Home = pt;
br.RangeHome = 4;
br.MoveToWorld(rabbitpos, Map.Trammel);
}
break;
}
This makes the rabbits stay in place, otherwise they go away too fast and it's difficult to get them all ! The next case is if you cancel the quest, we then add the marker but set its state to IGNORE : Code:
case 1:
{
from.SendMessage("Fine don't, it doesn't really matter!");
BobsQuestMarker bqm = new BobsQuestMarker();
bqm.QuestState = BobsQuestMarker.BobsQuestState.IGNORE;
from.AddToBackpack(bqm);
break;
}
}
Finally, we close the gump : Code:
from.CloseGump(typeof(StartQuest)); There that's done ! The gump is easy to do once you have the basic layout made by Gump Designer. Once again, any remarks, critics or whatever are welcome ! Jc Here's the full code : Code:
using System;
using Server;
using Server.Accounting;
using Server.Gumps;
using Server.Items;
using Server.Menus;
using Server.Menus.Questions;
using Server.Mobiles;
using Server.Network;
using Server.Prompts;
using Server.Regions;
using Server.Misc;
namespace Server.Gumps
{
public class StartQuest : Gump
{
const int RABBITNBR = 10;
public StartQuest()
: base( 0, 0 )
{
this.Closable=false;
this.Disposable=true;
this.Dragable=true;
this.Resizable=false;
this.AddPage(0);
this.AddImage(106, 68, 7);
this.AddHtml(139, 103, 230, 105, "Ahhh, want to play a little game ? <br> If you want, I'll take 10 rabbits
out of my hat, if you kill them all, you'll get a surprise !", false, true);
this.AddButton(164, 214, 247, 248, 0, GumpButtonType.Reply, 0);
this.AddButton(284, 214, 242, 243, 1, GumpButtonType.Reply, 0);
}
public override void OnResponse(NetState state, RelayInfo info)
{
Mobile from = state.Mobile;
switch (info.ButtonID)
{
case 0:
{
from.SendMessage("Good luck!");
//Add the marker
BobsQuestMarker bqm = new BobsQuestMarker();
bqm.Counter = RABBITNBR;
from.AddToBackpack(bqm);
//Create rabbits
int i;
Point3D pt = from.Location,
rabbitpos = new Point3D();
for (i = 0; i < RABBITNBR; i++)
{
rabbitpos.X = pt.X + Utility.Random(6) - 3;
rabbitpos.Y = pt.Y + Utility.Random(6) - 3;
rabbitpos.Z = pt.Z;
BobsRabbit br = new BobsRabbit();
br.Home = pt;
br.RangeHome = 4;
br.MoveToWorld(rabbitpos, Map.Trammel);
}
break;
}
case 1:
{
from.SendMessage("Fine don't, it doesn't really matter!");
BobsQuestMarker bqm = new BobsQuestMarker();
bqm.QuestState = BobsQuestMarker.BobsQuestState.IGNORE;
from.AddToBackpack(bqm);
break;
}
}
from.CloseGump(typeof(StartQuest));
}
}
}
Last edited by daat99; 09-25-2006 at 07:27 PM. |
|
|
|
|
|
#4 (permalink) |
|
Forum Newbie
Join Date: Sep 2006
Age: 28
Posts: 78
|
Fourth part :
Introduction Ok last post and I hope you're still all following ![]() We now have a definition of Bob, we've got the quest marker AND we have a gump that asks if the player wants the quest. All we need is the rabbits that the player has to kill and we'll be done ! Bob's Rabbits are basically extentions to the normal Rabbit class. We just add a little bit of handling to check if the player has the BobsQuestMarker before doing anything. This means that a player can only damage and kill a rabbit if he/she has the marker, otherwise the rabbit will say something (virtual worlds let rabbits speak!) Code file : BobsRabbit.cs The code starts out saying that BobsRabbit inherits from the basic rabbit : Code:
namespace Server.Mobiles
{
[CorpseName( "a BobsRabbit corpse" )]
public class BobsRabbit : Rabbit
{
Code:
public BobsRabbit() : base()
{
Name = "Bob's rabbit";
}
First thing we'll be doing is checking if there is a player involved or is the rabbit being attacked by a random creature : Code:
public override void Damage(int amount, Mobile from)
{
PlayerMobile pm = null;
if (m is PlayerMobile)
{
pm = m as PlayerMobile;
}
else if (m is BaseCreature)
{
BaseCreature bc = m as BaseCreature;
if (bc.Controlled == true)
{
pm = bc.ControlMaster as PlayerMobile;
}
}
Next, we check if we have the player has the marker, if he does, we'll let the damage function continue by calling the Damage from the class base. Otherwise, we'll say something and not damage the rabbit ! Code:
if (pm != null)
{
BobsQuestMarker bqm = pm.Backpack.FindItemByType(typeof(BobsQuestMarker)) as BobsQuestMarker;
if (bqm)
{
base.Damage(amount, from);
}
else
{
this.Say("Stop it, go see bob if you want to play!");
}
}
}
Ok, now we also have a little bit of work when the rabbit dies. Sometimes and in some games, it's possible to kill a mobile without giving damage. Seems a contradiction ? Not really, Death spells do exist in some games so it's generally a good idea to handle damage in both functions just to be sure... When a mobile dies, it calls the OnDeath method, we'll also customize this function to make it do what we want : Code:
public override void OnDeath(Container c)
{
Mobile m = this.FindMostRecentDamager(false);
PlayerMobile pm = null;
BobsQuestMarker bqm = null;
bool ressurect = true;
The ressurect boolean will tell the end of the function if the rabbit should be ressurected because it was killed by the wrong person... We start off by filling in pm and bqm : Code:
if (m is PlayerMobile)
{
pm = m as PlayerMobile;
}
else if (m is BaseCreature)
{
BaseCreature bc = m as BaseCreature;
if (bc.Controlled == true)
{
pm = bc.ControlMaster as PlayerMobile;
}
}
if(pm != null)
{
bqm = pm.Backpack.FindItemByType(typeof(BobsQuestMarker)) as BobsQuestMarker;
}
Now we see if the player has a marker : Code:
//Ok rabbit died by someone who's got the marker
if (bqm != null)
{
bqm.Counter--;
- The player hasn't yet finished the quest - If he's finished it then he should stop killing the rabbits We first handle the first case : Code:
if (bqm.QuestState < BobsQuestMarker.BobsQuestState.GETREWARD)
{
if (bqm.Counter > 0) //Still doing the quest
{
pm.SendMessage("You've got " + bqm.Counter + " rabbit(s) to kill");
}
else //Finished quest
{
pm.SendMessage("All done, you can go back to Bob");
bqm.QuestState = BobsQuestMarker.BobsQuestState.GETREWARD;
}
ressurect = false;
}
) then we go in the if.We then check the counter, if we haven't killed enough rabbits, we add a message telling how many are left. If we have killed enough, then we change the state to GETREWARD and tell the player to go back to Bob... After that, we put the boolean ressurect to false, that way we won't ressurect the rabbit, it's been killed by the right player. The second case is that we should not have killed the player. Whether it was killed by a random animal or a player not in the quest, the boolean ressurect will remain at true, thus we can create a new rabbit : Code:
if (ressurect) //No marker or finished quest
{
BobsRabbit newrabbit = new BobsRabbit();
Point3D nrpos = this.Location;
nrpos.X += Utility.Random(8) - 4;
nrpos.Y += Utility.Random(8) - 4;
newrabbit.MoveToWorld(nrpos, Map.Trammel);
Once this is done, we check if the player has the marker or not. If he does, that means that he finished the quest, can go get the reward or ignored the quest. The rabbit will remind him of each case : Code:
if (bqm != null)
{
switch (bqm.QuestState)
{
case BobsQuestMarker.BobsQuestState.GETREWARD:
newrabbit.Say("Your quest is finished, go get your reward!");
break;
case BobsQuestMarker.BobsQuestState.IGNORE:
newrabbit.Say("Your ignored the quest, stop it!");
break;
case BobsQuestMarker.BobsQuestState.FINISHED:
newrabbit.Say("Your finished the quest, stop it!");
break;
default:
break;
}
}
else
{
newrabbit.Say("Do not interfere with someone else's quest, go see Bob !");
}
![]() Code:
}
base.OnDeath(c);
}
}
}
Have fun with it and I attached the four files, all you have to do is unzip it in your Custom directory... Jc PS: I wrote this in one go so there might be mistakes a little bit everywhere but I sure hope not too many... PPS: I hope this kind of thing hasn't been done 50 times, I looked around and apart from the 8-ball and the Timer tutorial, I hadn't found much... Here's the code of this file : Code:
using System;
using Server;
using Server.Items;
using Server.Mobiles;
namespace Server.Mobiles
{
[CorpseName( "a hare corpse" )]
public class BobsRabbit : Rabbit
{
public BobsRabbit() : base()
{
Name = "Bob's rabbit";
}
public BobsRabbit(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 override void Damage(int amount, Mobile from)
{
PlayerMobile pm = null;
if (from is PlayerMobile)
{
pm = from as PlayerMobile;
}
else if (from is BaseCreature)
{
BaseCreature bc = from as BaseCreature;
if (bc.Controlled == true)
{
pm = bc.ControlMaster as PlayerMobile;
}
}
if (pm != null)
{
BobsQuestMarker bqm = pm.Backpack.FindItemByType(typeof(BobsQuestMarker)) as BobsQuestMarker;
if (bqm != null)
{
base.Damage(amount, from);
}
else
{
this.Say("Stop it, go see bob if you want to play!");
}
}
}
public override void OnDeath(Container c)
{
Mobile m = this.FindMostRecentDamager(false);
PlayerMobile pm = null;
BobsQuestMarker bqm = null;
bool ressurect = true;
if (m is PlayerMobile)
{
pm = m as PlayerMobile;
}
else if (m is BaseCreature)
{
BaseCreature bc = m as BaseCreature;
if (bc.Controlled == true)
{
pm = bc.ControlMaster as PlayerMobile;
}
}
if (pm != null)
{
bqm = pm.Backpack.FindItemByType(typeof(BobsQuestMarker)) as BobsQuestMarker;
}
//Ok rabbit died by someone who's got the marker
if (bqm != null)
{
bqm.Counter--;
if (bqm.QuestState < BobsQuestMarker.BobsQuestState.GETREWARD)
{
if (bqm.Counter > 0) //Still doing the quest
{
pm.SendMessage("You've got " + bqm.Counter + " rabbit(s) to kill");
}
else //Finished quest
{
pm.SendMessage("All done, you can go back to Bob");
bqm.QuestState = BobsQuestMarker.BobsQuestState.GETREWARD;
}
ressurect = false;
}
}
if (ressurect) //No marker or finished quest
{
BobsRabbit newrabbit = new BobsRabbit();
Point3D nrpos = this.Location;
nrpos.X += Utility.Random(8) - 4;
nrpos.Y += Utility.Random(8) - 4;
newrabbit.MoveToWorld(nrpos, Map.Trammel);
if (bqm != null)
{
switch (bqm.QuestState)
{
case BobsQuestMarker.BobsQuestState.GETREWARD:
newrabbit.Say("Your quest is finished, go get the reward!");
break;
case BobsQuestMarker.BobsQuestState.IGNORE:
newrabbit.Say("Your ignored the quest, stop it!");
break;
case BobsQuestMarker.BobsQuestState.FINISHED:
newrabbit.Say("Your finished the quest, stop it!");
break;
default:
break;
}
}
else
{
newrabbit.Say("Do not interfere with someone else's quest, go see Bob !");
}
}
base.OnDeath(c);
}
}
}
Last edited by daat99; 09-25-2006 at 07:27 PM. |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|