Press "Enter" to skip to content

Lesson 16.3 – Functions to use weapons and potions

Lesson Objectives

At the end of this lesson, you will know…

  • Nothing new. We’re just finishing the program, using the same things you learned in the previous lessons.

 

Now we’ll write the functions the player will use when fighting monsters.

We have two things they can do (besides click on one of the direction buttons, to run away from the battle): use a weapon on the monster or use a healing potion on themselves – if they have one in their inventory.

Here is the pseudo-code for the two functions:

Use a weapon function

  • Get the currently selected weapon from the cboWeapons ComboBox
  • Determine the amount of damage the player does to the monster
  • Apply the damage to the monster’s CurrentHitPoints
    • Display message
  • If the monster is dead (zero hit points remaining)
    • Display a victory message
    • Give player experience points for killing the monster
      • Display message
    • Give player gold for killing the monster
      • Display message
    • Get loot items from the monster
      • Display message for each loot item
      • Add item to player’s inventory
    • Refresh player data on UI
      • Gold and ExperiencePoints
      • Inventory list and ComboBoxes
    • “Move” player to current location
      • This will heal the player and create a new monster
  • If the monster is still alive
    • Determine the amount of damage the monster does to the player
    • Display message
    • Subtract damage from player’s CurrentHitPoints
      • Refresh player data in UI
    • If player is dead (zero hit points remaining)
      • Display message
      • Move player to “Home” location

 

Use a potion function

  • Get currently selected potion from cboPotions ComboBox
  • Add healing amount to player’s CurrentHitPoints
    • CurrentHitPoints cannot exceed player’s MaximumHitPoints
  • Remove the potion from the player’s inventory
  • Display message
  • Monster gets their turn to attack
    • Determine the amount of damage the monster does to the player
    • Display message
    • Subtract damage from player’s CurrentHitPoints
      • Refresh player data in UI
    • If player is dead (zero hit points remaining)
      • Display message
      • Move player to “Home” location
  • Refresh player data in UI

 

These are much simpler functions than the MoveTo() function.

We’ll be able to use some of the smaller functions we created during the refactoring lesson – for example, the AddItemToInventory() function, from the Player class, if the player defeats the monster and receives loot items.

 

Adding functions for monster battles

Step 1: Start Visual Studio Express 2013 for Desktop, and open the solution.

 

Step 2: Right-click on the SuperAdventure.cs form in the SuperAdventure project, to start working with the code for the UI.

To add the ability to use weapons and potions in combat, you can add in the code below, or replace the code for SuperAdventure.cs with the code here: https://gist.github.com/ScottLilly/b20787650f2ab2a78362

 

For the btnUseWeapon_Click function, add this:

        private void btnUseWeapon_Click(object sender, EventArgs e)
        {
            // Get the currently selected weapon from the cboWeapons ComboBox
            Weapon currentWeapon = (Weapon)cboWeapons.SelectedItem;

            // Determine the amount of damage to do to the monster
            int damageToMonster = RandomNumberGenerator.NumberBetween(currentWeapon.MinimumDamage, currentWeapon.MaximumDamage);

            // Apply the damage to the monster's CurrentHitPoints
            _currentMonster.CurrentHitPoints -= damageToMonster;

            // Display message
            rtbMessages.Text += "You hit the " + _currentMonster.Name + " for " + damageToMonster.ToString() + " points." + Environment.NewLine;

            // Check if the monster is dead
            if(_currentMonster.CurrentHitPoints <= 0)
            {
                // Monster is dead
                rtbMessages.Text += Environment.NewLine;
                rtbMessages.Text += "You defeated the " + _currentMonster.Name + Environment.NewLine;

                // Give player experience points for killing the monster
                _player.ExperiencePoints += _currentMonster.RewardExperiencePoints;
                rtbMessages.Text += "You receive " + _currentMonster.RewardExperiencePoints.ToString() + " experience points" + Environment.NewLine;

                // Give player gold for killing the monster 
                _player.Gold += _currentMonster.RewardGold;
                rtbMessages.Text += "You receive " + _currentMonster.RewardGold.ToString() + " gold" + Environment.NewLine;

                // Get random loot items from the monster
                List<InventoryItem> lootedItems = new List<InventoryItem>();

                // Add items to the lootedItems list, comparing a random number to the drop percentage
                foreach(LootItem lootItem in _currentMonster.LootTable)
                {
                    if(RandomNumberGenerator.NumberBetween(1, 100) <= lootItem.DropPercentage)
                    {
                        lootedItems.Add(new InventoryItem(lootItem.Details, 1));
                    }
                }

                // If no items were randomly selected, then add the default loot item(s).
                if(lootedItems.Count == 0)
                {
                    foreach(LootItem lootItem in _currentMonster.LootTable)
                    {
                        if(lootItem.IsDefaultItem)
                        {
                            lootedItems.Add(new InventoryItem(lootItem.Details, 1));
                        }
                    }
                }

                // Add the looted items to the player's inventory
                foreach(InventoryItem inventoryItem in lootedItems)
                {
                    _player.AddItemToInventory(inventoryItem.Details);

                    if(inventoryItem.Quantity == 1)
                    {
                        rtbMessages.Text += "You loot " + inventoryItem.Quantity.ToString() + " " + inventoryItem.Details.Name +Environment.NewLine;
                    }
                    else
                    {
                        rtbMessages.Text += "You loot " + inventoryItem.Quantity.ToString() + " " + inventoryItem.Details.NamePlural + Environment.NewLine;
                    }
                }

                // Refresh player information and inventory controls
                lblHitPoints.Text = _player.CurrentHitPoints.ToString();
                lblGold.Text = _player.Gold.ToString();
                lblExperience.Text = _player.ExperiencePoints.ToString();
                lblLevel.Text = _player.Level.ToString();

                UpdateInventoryListInUI();
                UpdateWeaponListInUI();
                UpdatePotionListInUI();

                // Add a blank line to the messages box, just for appearance.
                rtbMessages.Text += Environment.NewLine;

                // Move player to current location (to heal player and create a new monster to fight)
                MoveTo(_player.CurrentLocation);
            }
            else
            {
                // Monster is still alive

                // Determine the amount of damage the monster does to the player
                int damageToPlayer = RandomNumberGenerator.NumberBetween(0, _currentMonster.MaximumDamage);

                // Display message
                rtbMessages.Text += "The " + _currentMonster.Name + " did " + damageToPlayer.ToString() + " points of damage." + Environment.NewLine;

                // Subtract damage from player
                _player.CurrentHitPoints -= damageToPlayer;

                // Refresh player data in UI
                lblHitPoints.Text = _player.CurrentHitPoints.ToString();

                if(_player.CurrentHitPoints <= 0)
                {
                    // Display message
                    rtbMessages.Text += "The " + _currentMonster.Name + " killed you." + Environment.NewLine;

                    // Move player to "Home"
                    MoveTo(World.LocationByID(World.LOCATION_ID_HOME));
                }
            }
        }

 

Then, for the btnUsePotion_Click function, add this:

        private void btnUsePotion_Click(object sender, EventArgs e)
        {
            // Get the currently selected potion from the combobox
            HealingPotion potion = (HealingPotion)cboPotions.SelectedItem;

            // Add healing amount to the player's current hit points
            _player.CurrentHitPoints = (_player.CurrentHitPoints + potion.AmountToHeal);

            // CurrentHitPoints cannot exceed player's MaximumHitPoints
            if(_player.CurrentHitPoints > _player.MaximumHitPoints)
            {
                _player.CurrentHitPoints = _player.MaximumHitPoints;
            }

            // Remove the potion from the player's inventory
            foreach(InventoryItem ii in _player.Inventory)
            {
                if(ii.Details.ID == potion.ID)
                {
                    ii.Quantity--;
                    break;
                }
            }

            // Display message
            rtbMessages.Text += "You drink a " + potion.Name + Environment.NewLine;

            // Monster gets their turn to attack

            // Determine the amount of damage the monster does to the player
            int damageToPlayer = RandomNumberGenerator.NumberBetween(0, _currentMonster.MaximumDamage);

            // Display message
            rtbMessages.Text += "The " + _currentMonster.Name + " did " + damageToPlayer.ToString() + " points of damage." + Environment.NewLine;

            // Subtract damage from player
            _player.CurrentHitPoints -= damageToPlayer;

            if(_player.CurrentHitPoints <= 0)
            {
                // Display message
                rtbMessages.Text += "The " + _currentMonster.Name + " killed you." + Environment.NewLine;

                // Move player to "Home"
                MoveTo(World.LocationByID(World.LOCATION_ID_HOME));
            }

            // Refresh player data in UI
            lblHitPoints.Text = _player.CurrentHitPoints.ToString();
            UpdateInventoryListInUI();
            UpdatePotionListInUI();
        }

 

There isn’t really anything new in these two functions. Just more “if”s and “foreach”s to handle the player’s actions in battle.

 

Summary

Now you have a working game. The player can move around in the world, get quests, battle monsters, receive loot, and complete quests.

These new functions could use some refactoring, since they are long and do several things. I’ll leave that to you to figure out what refactoring you’d do.

 

Source code for this lesson

Source code on GitHub

Source code on Dropbox

 

 Next lesson: Lesson 17.1 – Running the game on another computer

Previous lesson: Lesson 16.2 – Refactoring the player movement function

All lessons: Learn C# by Building a Simple RPG Index

284 Comments

  1. Chris G.
    Chris G. January 23, 2015

    So, while I think everything was copied right (I even went through the whole tutorial again to try and figure this out) at the end of this lesson, I am able to build into the form application, and everything works out correctly, except for the fact that I cannot move from the starting area. I believe that it might be an issue with how btnNorth (at least that’s the one that isn’t working at this point) interacts with the rest of the program. Help would be greatly appreciated and you’d be helping a young engineer get a head-start in college!

    Thank you for the tutorials! They’re absolutely phenomenal and I hope that you might release higher level tutorials some time in the future.

    • Scott Lilly
      Scott Lilly January 23, 2015

      Hi Chris,

      It does sound like your “North” button may not be connected to the rest of the code. When you added the button to the screen, did you double-click on it, to create the “btnNorth_Click” function, or did you only create that function by pasting in the source code to the SuperAdventure.cs class? If you did not double-click the North button, then there would not be an “event handler” for it, to tell the program what function to run when the button is clicked. The simplest way to fix that would be to delete the functions that handle the buttons clicks, go to the Design page for SuperAdventure.cs (double-click on the SuperAdventure.cs file in the Solution Explorer, then double-click on each of the buttons. That will create the empty functions in the code to handle the click events. Then you’ll need to paste the code for the function into the empty functions.

      If that isn’t the problem, I wrote a post the other day on how to use the debugger (How to Use the Visual Studio 2013 Debugger). If you read that, and set a breakpoint on the btn_North function, you’ll be able to see if the function is called when the player clicks on the button. You’ll also be able to use the F10 key to follow through the rest of the program as it is running. That may help you discover the source of the problem.

      • Chris G.
        Chris G. February 2, 2015

        Awesome! Seems to be working now, it generated a new method stub for all of the buttons under btn(fill in the space here)_Click_1. This would probably be a common problem for those debugging problems by rebuilding the whole solution via copy and paste. Thanks!

        • Scott Lilly
          Scott Lilly February 3, 2015

          Cool. I’m glad to hear you got it working.

  2. Woobster
    Woobster February 12, 2015

    Got one question.
    I added the Club as a drop for spiders and when i loot it, and choose to use it, it changes back to rusty sword, when i change location, and seems it tries to switch over to sword when attacking :/

    • Scott Lilly
      Scott Lilly February 13, 2015

      This happens because when the player moves to a new location, the MoveTo() function (in SuperAdventure.cs) calls the UpdateWeaponListInUI() function, which repopulates the dropdown. Since we don’t store the player’s currently selected weapon, the dropdown selects the first option.

      I’ll work on a new lesson this weekend to show how to have the dropdown show the player’s current weapon. We’ll add a CurrentWeapon property to the Player class, and an “event handler” for when the player selects a new weapon in the dropdown. In the event handler code, we’ll save the new weapon to the player’s CurrentWeapon property. Then, in the UpdateWeaponListInUI() function, we’ll see what the player’s CurrentWeapon is and display it in the dropdown.

  3. Woobster
    Woobster February 13, 2015

    Awesome.
    I did manage to get it to work with good help from a friend of mine.
    But it seems to try and switch every time i use a weapon.
    Ill show how i did it when i get to my pc again.
    Cheers for the reply, and cant wait for the new lesson. 🙂

  4. Peter
    Peter April 30, 2015

    Hi Scott,

    This has been a brilliant learning tool. I cannot find anywhere in the code where we give the play a starting weapon. I’ve lifted ‘player.Inventory.Add(new InventoryItem(World.ItemByID(World.ITEM_ID_RUSTY_SWORD), 1));’ from Lesson 19 and have looked for something similar but haven’t been able to find anything. I’ve not yet been able to work out how to reword this to add it to the inventory.

  5. Peter
    Peter April 30, 2015

    Actually nevermind, I just dumped ‘_player.Inventory.Add(new InventoryItem(World.ItemByID(World.ITEM_ID_RUSTY_SWORD), 1));’ in the Player initialization.
    I’m going to go read everything else you’ve written now!

  6. Graeme
    Graeme May 29, 2015

    Hi,

    Not sure if you still check this but I seem to be having a problem with hitting the enemy, the value always seems to be 0 yet the monster can hit me.

    Any ideas on what the problem could be?

    Thanks in advance,

    Graeme

  7. Graeme
    Graeme May 29, 2015

    Never mind I fixed it, I had:

    int MinimumDamage = minimumDamage;
    int MaximumDamage = maximumDamage;

    in the Weapon class instead of just:

    MinimumDamage = minimumDamage;
    MaximumDamage = maximumDamage;

    Duh!

    Thanks for the great guide though, helped me a lot! 🙂

    • Scott Lilly
      Scott Lilly June 2, 2015

      Cool. I’m sorry I wasn’t able to respond, I’m currently packing up and getting ready to move a few thousands miles. 🙂 If you have any other questions, I’m probably going to be completely offline for the next week (more or less).

  8. Pablo
    Pablo September 8, 2015

    Hi im really enjoyn the tuto so far. but i have a question i hope you can attend.

    when you create an object and in some other place i cant remember you use:

     

    Classname objectName = (Classname).andsomemorestuff

     

    i dont understand when to use this (i mean the class name in parenthesis when you create an object)

     

    thanks, looking forward to end the game!

  9. Ron
    Ron September 11, 2015

    hi, i realy like your helpful Tutorial and i already learned alot but i cant seem to find the solution to the problem im having since lesson 16.1. Visual Studio is saying that there are no errors in the game but when run it it just shows a blank Form in (i think) standard size :(.

    • Ron
      Ron September 11, 2015

      i fixed it by making a new programm and copy pasting my stuff in it, maybe i deleted something by accident?

      • Scott Lilly
        Scott Lilly September 11, 2015

        The values for the UI controls (labels, buttons, datagrids, etc.) are located in the SuperAdventure.Designer.cs file. If you moved/renamed/copied/etc. SuperAdventure.cs, and didn’t also get the Designer.cs file, that might have caused the problem.

        • David
          David December 24, 2015

          How do you fix, that. Do you have to move everything to a new programm?

          • Scott Lilly
            Scott Lilly December 24, 2015

            Usually, when you do refactoring, you do not move everything to a new program. Instead, you make small changes to your current program.

            When you get to lesson 20, you’ll see how I make more small changes to the program, making one feature better each time.

          • David
            David December 24, 2015

            I mean how do you fix it when the UI does have anything on it nothing works it has all the buttons and other items but otherwise its blank

          • Scott Lilly
            Scott Lilly December 24, 2015

            If the buttons are in the UI, and the code for the buttons does not work, there is probably a problem in the Designer.cs file for that UI form. That is the file where the buttons connect to the functions.

            Do you have a place where you can upload your solution? Then I can look at the exact problem and tell you how to make it work? If you do not have a place, you can create a free account on Dropbox to upload your files. Please upload all the files (including the sub-folders under your solutions folder), share the folder, and send me the “share” link.

  10. Nick
    Nick November 4, 2015

    Hey Scott,

    Thanks so much for the tutorial. I’m totally new to programming and C# and this has been a huge help as I begin the learning process.

    I am having one problem though. I cannot seem to get the use weapon button to do anything. I have checked the code for it, it’s exactly as you have it written, and logically it seems like it should work. But it doesn’t do anything. Do you have any idea why this could be?

    • Scott Lilly
      Scott Lilly November 4, 2015

      You’re welcome, Nick.

      If the btnUseWeapon_Click() function is in SuperAdventure.cs, the most likely problem is that the line connecting the button’s “Click” event to the method has been deleted. Try doing this:

      1. Open the SuperAdventure.cs form, in design mode, in Visual Studio.
      2. Click once on the “Use” button for the weapon, to set focus on it.
      3. In the Lower-right corner of Visual Studio, in the “Properties” box, click on the lightning bolt symbol (see the image below).
      4. See if the “Click” event has the value “btnUseWeapon_Click” (the name of the function to run when the user clicks on that button). If that value is missing, follow the next steps. If the value is there, let me know and we’ll try to figure out what else might be causing the problem.
      5. If the “btnUseWeapon_Click” was missing, double-click on the “SuperAdventure.Designer.cs” file (in the Solution Explorer), to edit it.
      6. Scroll down until you see the section for “btnUseWeapon”. Add in this line of code:
      this.btnUseWeapon.Click += new System.EventHandler(this.btnUseWeapon_Click);
      7. Save everything, run the game, and see if the button works now.

      Events for btnUseWeapon

      Screenshot of line to add to SuperAdventure.Designer.cs

      Please let me know if that doesn’t fix it, and we’ll dig deeper.

      • Patrick Nolen
        Patrick Nolen June 20, 2016

        I know this is from a while ago, but I was having issues where the North button was disabled, not clickable, and grayed out.

        Through messing around I found that my Form was not enabled. I changed the value to True, and everything works like a charm.

        I don’t remember changing that value, but this might be a good first place to look for everyone else.

        Great tutorial so far! Thanks!

        • Scott Lilly
          Scott Lilly June 20, 2016

          Thanks for sharing the tip, in case someone else is having the same problem.

  11. Scrib97
    Scrib97 November 11, 2015

    Hey there, awesome tutorial

    i seem to have the same problem that Graeme with the damage that the player deals to the enemy but my weapon class is same as the one you have, as well as all the other classes.

     

    • Scott Lilly
      Scott Lilly November 11, 2015

      Thanks. Can you upload your solution (and all the files/directories under it) to some place like Dropbox? Then I should be able to find out exactly where the problem is.

      Or, if you want to look for the problem yourself, you can see how to do some debugging (for a different problem, but the same concept) in this video on C# debugging in Visual Studio.

  12. Nicolis Miller
    Nicolis Miller November 30, 2015

    Hey I ran into another problem I tried starting the game after all of this lesson and its saying that its “stopped at exception” there no other errors or anything and I don’t know what to do.

    • Scott Lilly
      Scott Lilly November 30, 2015

      If you click on “Build”, instead of the green arrow to run the program, do you see any errors in the bottom section of Visual Studio?

  13. Nicolis Miller
    Nicolis Miller December 1, 2015

    I didn’t get any errors when I tried that.

    • Scott Lilly
      Scott Lilly December 1, 2015

      Can you upload your whole solution (including the files/folder underneath it) to Dropbox, or some other sharing site, and send me the link? Then I can look at it.

  14. Your tutorials are amazing!
    Your tutorials are amazing! January 8, 2016

    Thanks so much for these tutorials, I’ve learnt so much from them. At the moment, when we kill a monster we just re-enter the location, heal and spawn a new monster to fight. How could we do it that we still heal, but the monster doesn’t come back? It would be really cool if we could make it that, for example, there were 3 rats in one room, each with the ability to attack the player, and would only respawn when the player purposely re-enters. Perhaps the player could choose which enemy to attack if there is more than one enemy, for example if the room contains a snake and a giant spider. Sorry for the newbie question, would this be difficult to do?

    • Scott Lilly
      Scott Lilly January 8, 2016

      You’re welcome! To leave the player at the same location, you could modify the UseWeapon function that attacks the monster. Find these lines:

      // Move player to current location (to heal player and create a new monster to fight)
      MoveTo(CurrentLocation);

      and replace them with this:
      // Completely heal the player
      _player.CurrentHitPoints = _player.MaximumHitPoints;

      You may also need to modify the code that makes the “Use” weapon button visible – since you will still have a monster at that location, but it will be dead.

      You could add multiple monsters at a location, but there are several changes you would need to make:
      1. Change the Location MonsterLivingHere property from a Monster datatype to a List datatype (so you could add multiple monsters at a location)
      2. Change the World class, where you set MonsterLivingHere to work with the List version (probably using the “Add” function on the list property)
      3. Add a new combobox near the “Use” weapon button, to display which monster he player will attack. You will need to some extra work here to populate this with the monsters at the location, and remove them from the combobox when one is killed.
      4. Change the code in the “Use” weapon function to allow each monster to attack the player.

      It can be done, but there are many steps to make that change. If you do try it, I suggest you use version control, like Subversion (I have a post here on how to install and use Subversion). Make small changes, one step at a time. After each change, test the program, to ensure it is still working. If it is, check the code into Subversion. This way, if your change breaks something, you can revert the code to how it was before the change.

      • Your tutorials are amazing!
        Your tutorials are amazing! January 9, 2016

        That’s brilliant, thank you so much. I’ve tried the first thing and that works, I think I’ll do your other tutorials first before attempting to add multiple monsters. I’ll look forward to trying this when I get there and I’ll let you know how it goes.

        I’d also really like to add images to each monster. Could I do it like this:

        1) in the Monster.cs class add:

        public string Image { get; set; }

        public Monster(int id, string name, int maximumDamage, int rewardExperiencePoints, int rewardGold, int currentHitPoints, int maximumHitPoints, string image)
        : base(currentHitPoints, maximumHitPoints)
        {

        Image = image;

        }

        2) add the file location in the World.cs section of the Monsters:
        e.g.
        Monster giantSpider = new Monster(MONSTER_ID_GIANT_SPIDER, “Giant spider”, 20, 5, 40, 10, 10, c:\\My Documents\SuperAdventure-master\Images\Spider.jpg);

        3) Add pictureBox1 in the [Design] section and then
        pictureBox1.Image = Image.FromFile(_currentMonster);
        (At the moment this shows a lot of red, maybe there’s something wrong with that?)

        A problem I see with this is that when I change computer etc. the images will need to be in the same place. How can you have it that they are automatically found within the folder?

        Thanks once more for your tutorials, they really are great. It makes it so much easier to get started with programming, learning by doing and working with code that you know will work. (A lot of things online that I found previously don’t seem to work). I hope you don’t mind me running this idea past you, I wanted to check the syntax and logic of it before spending a lot of time on it.(Two months ago I didn’t know the first thing about programming!) Thanks a bunch :-).

        • Scott Lilly
          Scott Lilly January 9, 2016

          Cool! I did not test out the first change on my computer, so you might find other small changes you will need to make. But that should get you close.

          I am about to go to an all-day class, so I will point you to this page (Embedding Image Resources in a Project) to see how to include an image in your project – even if you run it on another computer. “Embedding a resource” means that Visual Studio will include that file with your program, when you run “build”.

          • Your tutorials are amazing!
            Your tutorials are amazing! January 13, 2016

            Great thanks! I hope your day class went well. I couldn’t get the embedding thing working, in the end I managed to include images without embedding by:

            string temp = Environment.CurrentDirectory;
            PictureBox1.Image = Image.FromFile(temp + _currentMonster.ImageFile);

            All monsters, locations and player levels now have associated images, which update automatically. Thanks for your help with this 🙂

            I’d like to make it that the game shows a MessageBox when all Quests are completed.
            How could I do that? (I know how to show a MessageBox, I’m just not sure how to access an “if all quests are completed function”)

            (Also in my version my Quest list only updates when I return to the Location that the Quest is stored in. Do you know why?)

            Thank you so much!

          • Scott Lilly
            Scott Lilly January 13, 2016

            You’re welcome. My answer to your other question shows where the quest completion logic is located (and why the player must return to the original quest location). You could add some more code there, to see if all the quests are completed. If they are, then show the MessageBox.

            If you have questions after looking at that, please let me know.

  15. Your tutorials are amazing!
    Your tutorials are amazing! January 13, 2016

    I’ve created a place that can only be entered if all quests have been completed, that can not be left. Upon entry the MessageBox will appear saying that the game has been completed.

    I’m still not sure why Quest completed true only gets activated when I re-enter the place where that the quest was given though…

    • Scott Lilly
      Scott Lilly January 13, 2016

      The way I designed the game, all the quests are given to the player by someone at a location. They want the player to get them some items, and return the items to them. So, the player must return to the original quest location, in order to “turn in the quest” and complete it.

      Look at the MoveTo function, for this comment:
      // See if the player already has the quest, and if they've completed it
      That is where we start to check if there is a quest at that location that can be completed. If so, we check if the player has all the items. If they do, we complete the quest.

      You could move that logic to the function where the player uses their weapon against a monster. When they defeat the monster, and collect the monster’s loot, we could check if the player has everything needed to complete any of their quests. The code where the player collects the loot starts after this comment:
      // Add the looted items to the player's inventory

      • Your tutorials are amazing!
        Your tutorials are amazing! January 14, 2016

        Great! Thanks, that works! Just had to make sure that the newLocation.QuestAvailableHere != null instead went through _player.CurrentLocation.QuestAvailableHere . Brilliant, thank you!

          • Your tutorials are amazing!
            Your tutorials are amazing! January 14, 2016

            Thank you! I’ve heard that pointers make programs much more efficient. How could we do that here? (I’m not really sure how pointers work in C#)

          • Scott Lilly
            Scott Lilly January 14, 2016

            Usually, pointers are used in C and C++, not C#. They are used to access a variable, by its location in memory. With C#, we access the variable “by reference” or “by value”, and normally do not directly use pointers. Using pointers can make a program faster, or more efficient, but they also make it easier to make some types of mistakes.

            I usually follow the rule to not try to optimize a program until you discover that it needs optimization. Wait until you have a problem, before you start doing special optimizations. You always want to write the program to run as fast, and efficient, as you know how. But don’t put extra effort into making a program 10 milliseconds faster, if it is already faster than the users need.

  16. Your tutorials are amazing!
    Your tutorials are amazing! January 14, 2016

    that’s good to know, thanks 🙂

  17. Your tutorials are amazing!
    Your tutorials are amazing! January 14, 2016

    Would you mind giving an example of when we’ve accessed “by reference” and when we’ve accessed “by value”, please? It will just make it a little clearer for me. Thanks so much!

  18. Frank
    Frank January 16, 2016

    Hi! Firstly, I want to thank you for this tutorial, It helped me much to understand things.
    But I’m stuck. I think I’ve done everything properly, even all the numbers of the lines are correct everywhere. But testing it in Visual Studio or running the executable it throws an exception at / crashes around 3-4 moves, and the buttons doesn’t seem to work as they intended to. My solution is here with all folders ‘Release’ folder included.
    I’ve translated almost everything to my language, but I hope you can still help me. 🙂
    Thanks in advance!

    • Scott Lilly
      Scott Lilly January 16, 2016

      You’re welcome, Frank.

      There are a few small things to fix in RPG762.cs. I think these will make the program work.

      Add this at line 27:

      _jatekos.Inventory.Add(new InventoryTargy(Vilag.ItemByID(Vilag.ITEM_ID_RUSTY_SWORD), 1));

      That will give the player a starting weapon. If the player does not have a weapon, the program will hide the weapons combobox and “Hasznal/Use” button when it executes the UpdateWeaponListInUI() function.

      Change lines 69 and 70 to this:

      button1.Visible = (ujHely.HelyKeletFele != null);
      button2.Visible = (ujHely.HelyDelFele != null);

      The button names were reversed. So, the player saw the “Kelet/East” button, but the location was at the “Del/South”. If you clicked the Kelet button, there was no Hely/Location object, so the program had an error.

      Change lines 257 and 258 to this:

      cboFegyverek.DataSource = fegyverek;
      cboFegyverek.DisplayMember = "Nev";

      Or, change Targy’s “Nev” property to include the accent. The DisplayMember must exactly match the property name.

      Please tell me if that does not fix everything.

      • Frank
        Frank January 17, 2016

        Thanks! It fixed everything. 🙂

  19. Marco
    Marco February 9, 2016

    Hey Scott! Great tutorial!

    I was given this tutorial by a teacher, as he wanted me to learn more about OOP, and it’s done a great job. He gave me one little challenge, though. I had to make it in WPF. I’ve run into some trouble sometimes, but the most pressing one is that I can’t seem to get quests.

    Would you mind looking it through?

    If it helps, I can upload my solution folder to DropBox, and send you a link – Any help would be appreciated, and I’m fairly certain I’ve misplaced something in code.

    • Scott Lilly
      Scott Lilly February 9, 2016

      Thank you! Yes, upload it and send me the link. I will see if I can help you find the problem.

  20. Marco
    Marco February 10, 2016

    Thanks again! Here’s the link

    There’s been some changes to the code you’ve written in your tutorials, and some work-arounds on things that couldn’t work together, but with this, I’m fairly certain I missed a line of code or a segment, and that I’ve now come too far to actually see it.

    Try and run the code, and if you discover any more bugs, please let me know! I’d love to have the chance to figure it out myself!

    • Scott Lilly
      Scott Lilly February 10, 2016

      Hi Marco,

      For the quests, I saw two things in MainWindow.xaml.cs.

      Line 105: Should be “if(playerAlreadyHasQuest)”. You want the first section to run if the player already has the quest, and the “else” section to run if they do not. SO, this line should not have a “!”
      Line 164: This has an extra “}” that needs to be removed from here, and added to line 140. This is causing a problem with your “else”.

      Those changes should fix it so the Quest grid fills up. I think there are some more things you will want to do to the Quest grid, but I will let you try them on your own first. If you have problems, you might find clues in steps 2 and 7 of Lesson 20.3

      Please tell me if you get that working, or if you want a little more help.

      • Marco
        Marco February 29, 2016

        Thank you so much! I got it working, and started filling up the game with more mobs, locations, quests and items. I’ve also thought about what kind of stories I could come up with while using the same engine, but then I’d have to make some modifications to the UI as well, like, adding a new TextBlock to add stories, so people would get to know the quest givers more, or to learn more about the current location they’re standing in, instead of just a few lines in the Messages TextBlock.

        The truth is that I’m having more fun adding in the world, than actually writing the code, as I have a few problems with just understanding the logic, but I feel like I’m getting it, albeit slowly.

        • Scott Lilly
          Scott Lilly February 29, 2016

          You’re welcome! Sometimes it takes a little time to learn a programming technique. But, every time you see it, it is written a little stronger in your brain. Eventually, you can easily understand it.

          It is still the same way for me, after 35 years of programming. When I learn something new, I need to work with it a few times before I truly understand it.

Leave a Reply

Your email address will not be published. Required fields are marked *