XNA Creators Club Online
Page 1 of 1 (20 items)
Sort Posts: Previous Next

RPG Toolkit How To:

Last post 08-25-2008 3:44 AM by Bixel. 19 replies.
  • 06-26-2008 11:08 AM

    RPG Toolkit How To:

    So as I'm going through the RPG toolkit I thought I'd create a post describing the things I'm changing and how I went about changing them. Others may find this useful as they start modifying this toolkit, and feel free to share modifications that you have done and how you did them.

     

     

  • 06-26-2008 11:42 AM In reply to

    Re: RPG Toolkit How To:

    Drop Rate Quests

    Goal : My plan was to turn this more into an MMO style game instead of the single player style. A common quest in an MMO is a quest that relies on drop rates. ie. Collect x amount of an item from y monster. I wanted the item to ONLY drop when the player has the quest that asks for them, and STOP dropping when they have the desired amount the quest is asking for. It's common to have a < 100% chance for this item, making the player kill more monsters to collect the desired amount. This posses a problem with the way the current game works, not having monster respawns, but I will address that in another post as I get there.

     

    Execution : So here is what I did to achieve my goal.

    1) In the RolePlayingGameWindows project I went into Content->Characters->Monsters. Each monster xml file in here has a section called GearDrops. If I want "gear", ie a Glimmering Ruby, to drop from a monster I would add it to the GearDrops section. The only problem is given the current way the system works, that monster would ALWAYS drop a Glimmering Ruby at the given %. so clearly a change is needed.

    2) Inside each monsters xml file I added another tag to the GearDrops tag. I called it QuestName. The result looked something like:

    <GearDrops> 
              <Item> 
                  <GearName>Items\MinorHealingPotion</GearName> 
                  <DropPercentage>60</DropPercentage> 
                <QuestName></QuestName
              </Item> 
            <Item> 
              <GearName>Items\GlimmeringRuby</GearName> 
              <DropPercentage>100</DropPercentage> 
              <QuestName>The Goblin Brigade</QuestName> 
            </Item> 
          </GearDrops> 

     3) So as you can see the MinorHealingPotion doesn't have anything in the QuestName section, which is fine. Code will be added to the project saying that if the QuestName is blank, just give this item a chance to drop on every kill. Notice the GlimmeringRuby has something in it's QuestName tag. Code will be added to say that if the player is on this quest, then give this item the drop % chance, otherwise don't drop at all.

    4) Bring forth the code. So how did I make this work. First off I have to load and store the new xml tag QuestName. To do this, I needed to modify the GearDrop class in the RolePlayingGameDataWindows. I added another property in there called questName after the other 2 properties (I read somewhere that the order of the properties in your code is important. I think some reflection is being done with this content pipeline). So that looks like:

          

    /// <summary> 
            /// The content name of the gear. 
            /// </summary> 
            private string gearName; 
     
            /// <summary> 
            /// The content name of the gear. 
            /// </summary> 
            public string GearName 
            { 
                get { return gearName; } 
                set { gearName = value; } 
            } 
     
     
            /// <summary> 
            /// The percentage chance that the gear will drop, from 0 to 100. 
            /// </summary> 
            private int dropPercentage; 
     
            /// <summary> 
            /// The percentage chance that the gear will drop, from 0 to 100. 
            /// </summary> 
            public int DropPercentage 
            { 
                get { return dropPercentage; } 
                set { dropPercentage = (value > 100 ? 100 : (value < 0 ? 0 : value)); } 
            } 
     
            /// <summary> 
            /// The content name of the gear. 
            /// </summary> 
            private string questName; 
     
            /// <summary> 
            /// The content name of the gear. 
            /// </summary> 
            public string QuestName 
            { 
                get { return questName; } 
                set { questName = value; } 
            } 

    5) Then in the GearDropReader I added the read in code which looks like:

          

    public class GearDropReader : ContentTypeReader<GearDrop> 
            { 
                protected override GearDrop Read(ContentReader input, 
                    GearDrop existingInstance) 
                { 
                    GearDrop gearDrop = existingInstance; 
                    if (gearDrop == null
                    { 
                        gearDrop = new GearDrop(); 
                    } 
     
                    gearDrop.GearName = input.ReadString(); 
                    gearDrop.DropPercentage = input.ReadInt32(); 
                    gearDrop.QuestName = input.ReadString(); 
     
                    return gearDrop; 
                } 
            } 

    6) Now I have to do the write code. That is found in the RolePlayingGameProcessors project under Gear->GearDropWriter and will look like:

        public class GearDropWriter : RolePlayingGameWriter<GearDrop> 
        { 
            protected override void Write(ContentWriter output, GearDrop value) 
            { 
                output.Write(value.GearName); 
                output.Write(value.DropPercentage); 
                output.Write(value.QuestName); 
            } 
        } 

    7) So that is all that is needed to get the data from the xml file into our project for us to use. So now we have to actually use it. After digging around it seems the Monster is responsible for deciding what it will drop. So we'll modify the Monster class from the RolePlayingGameDataWindows class.There is a function called CalculateGearDrop in Monster.cs. I first needed to know what the current quest the player was on, so I changed the definition to include a Quest object. I'll explain later where I pass this into this function. So in here it's going to loop through each GearDrop item tag in the xml file and use the drop % to determine if the item will drop or not. Well we want some additional logic in here to determine if an item that is specific to a quest should drop at all. Here is what I did to achieve that.

     public List<string> CalculateGearDrop(Random random, Quest q) 
            { 
                List<string> gearRewards = new List<string>(); 
     
                Random useRandom = random; 
                if (useRandom == null
                { 
                    useRandom = new Random(); 
                } 
     
                foreach (GearDrop gearDrop in GearDrops) 
                { 
                    // if the gear drop quest name is blank then just do normal random 
                    // on this item 
                    if (gearDrop.QuestName.Length == 0) 
                    { 
                        if (random.Next(100) < gearDrop.DropPercentage) 
                        { 
                            gearRewards.Add(gearDrop.GearName); 
                        } 
                    } 
                    else 
                    { 
     
                        // if there is a name, then this item will only drop off this 
                        // mob if they are currently on the said quest name 
                        if (q.Name == gearDrop.QuestName) 
                        { 
                        // if we already met our gear requirements, then skip this 

                                        if (q.AreGearRequirementsMet) continue;

     

                        // item from possibly dropping, note that I created the below property from the Quest.AreRequirementsMet method. This method checks if the gear requirements and monster requirements are complete all in once property. I felt it better to split these out into their own properties since in this case I only care about the gear requirements. I then use both new properties inside the AreRequirementsMet property so existing code continues to work.                      if (q.AreGearRequirementsMet)                          continue
                            if (random.Next(100) < gearDrop.DropPercentage) 
                            { 
                                gearRewards.Add(gearDrop.GearName); 
                            } 
                        } 
                    } 
                } 
     
                return gearRewards; 
            } 
     

    8) Alright so this is all fine and dandy but your build will fail because we added another parameter to the function, but the actual call hasn't passed the 2nd parameter yet. So I basically did a Find for the function name CalculateGearDrop. Turns out it's being called in the RolePlayingGameWindows project under Combat->CombatEngine.cs. I modified the function call to look like:

    monster.CalculateGearDrop(Session.Random, Session.Quest) 

    After digging around in the Session object I noticed that the Quest property returned the current quest the player was on.

     That's it. We now have a monster that will drop a Glimmering Ruby ONLY if the player is on the quest. Also, once you have received the amount of Glimmering Rubys the quest requires, more kills of that same monster while on that same quest will not drop a Glimmering Ruby. Feel free to ask question or give comments. More to come...

                  
  • 06-26-2008 9:51 PM In reply to

    Re: RPG Toolkit How To:

    This is an outstanding tutorial!  Nice work!
    Matthew Picioccio
    XNA Developer Connection
  • 06-27-2008 1:48 AM In reply to

    Re: RPG Toolkit How To:

    I've added a link to this tutorial to the a new "Community Resources" section on the Role-Playing Game starter kit page.  :)
    Matthew Picioccio
    XNA Developer Connection
  • 06-27-2008 2:28 PM In reply to

    Re: RPG Toolkit How To:

    Very cool. I'm honored to be the first. :) This is good motivation to keep sharing my ideas. I hope others will join me.

     

    Next on my list are the screens. I have in the works a more non intrusive style of screens for the games inventory, statistics, etc. The screen system is pretty cool, and once you can follow the flow pretty simple to understand.


  • 06-30-2008 3:38 PM In reply to

    Re: RPG Toolkit How To:

    I've been having a great time playing with the RPG starter kit.  I've done a lot of customizations for it, but so many times I've added some classes or changed existing ones just to realize that I could've accomplished the same thing by just changing the XML itself without adding anything to the project code at all.

     This is a super tutorial and it provides a lot of valuable insight as to what is going on inside the ContentLoaders.

  • 07-10-2008 6:48 AM In reply to

    Re: RPG Toolkit How To:

    Hi great post, I like the direction you are taking the starter kit in.

    However, shouldn't the check for AreGearRequirementsMet on the Quest object be done within the if (q.name == gearDrop.QuestName) block?

    Otherwise you could be checking the gear requirements on a different quest ?

  • 07-10-2008 8:20 PM In reply to

    Re: RPG Toolkit How To:

    Good tutorial - it really helped me in my current plan to extend the quest mechanism - the first task being to add a hidden attribute.

    However - I came across a couple of comments, that I thought might be useful.

    The first is not a problem - but you can make an attribute optional by putting '[ContentSerializer(Optional = true)]' between the definition of the attribute type and the definition of the get/setters. Have a look at Quest.cs -> GearRewardContentNames for an example.

    The second comment is that you may have to watch out for custom Clone methods. In the case of Quest - this may need to have the attribute copy added to it as well - in my case, I need to look at the quest details in the QuestLogScreen.cs, so I had to enhance the Quest.Clone to copy across the hidden attribute.

    If anyone is interested, I will post a new thread on my plan and progress on enhancing the Quest functionality.

    Cheers
      Andy Stratton
  • 07-10-2008 11:01 PM In reply to

    Re: RPG Toolkit How To:

    FatalFrenchy:

    Hi great post, I like the direction you are taking the starter kit in.

    However, shouldn't the check for AreGearRequirementsMet on the Quest object be done within the if (q.name == gearDrop.QuestName) block?

    Otherwise you could be checking the gear requirements on a different quest ?

     

    You are correct. I made the change above. The editing of code boxes seems all messed up but I did my best.

  • 07-10-2008 11:02 PM In reply to