Press "Enter" to skip to content

Lesson 19.6 – Increase maximum hit points when the player gains a level

Lesson objectives

At the end of this lesson, you will know…

  • How to ensure all changes for a property go through a shared method of a class

 

One of the most common requests has been to show how to increase the player’s MaximumHitPoints when they gain a level.

We could take the easy way, and add come code to recalculate the player’s MaximumHitPoints after every line where we add to the player’s experience points. However, that could lead to problems.

We’d need to find every place where we add to the player’s experience points. In a small program like this, that isn’t too difficult. In a larger program, that can be a nightmare. Plus, if we ever decide to change the increase for each level (for example, increase by 5 hit points per level, instead of 10), we’d have to go back through all the code again, and make multiple changes.

If you do this in big programs, you are almost guaranteed to miss one place. Then, you’ll spend hours (or days) trying to track down why your program isn’t working the way you expect.

To make this easy to maintain, we’re going to add the code in one place, and make sure the rest of the program has to go through that one place.

 

How to ensure all changes for a property go through a common location

Step 1: Open the SuperAdventure solution in Visual Studio and open the Player.cs class. Go to line 43 and insert this new method:

public void AddExperiencePoints(int experiencePointsToAdd)
{
    ExperiencePoints += experiencePointsToAdd;
    MaximumHitPoints = (Level * 10);
}

 

Step 2: To make sure nowhere else in the program can modify the player’s experience points, we need to make its “set” private. This way, the value can only be set by other methods in the Player class. Go up to the ExperiencePoints property in the Player.cs class (line 13) and change it to this:

public int ExperiencePoints { get; private set; }

 

Step 3: Find all the places in the program that used to directly update the player’s ExperiencePoints property and change them to use the new method.

Since we have a small program, we can cheat a little and build the solution. We’ll get an error for every line that is currently trying to add to ExperiencePoints. If you haven’t modified the program, this should be in two places in SuperAdventure.cs: line 122, when the player gets experience for completing a quest, and line 347, when the player gets experience for killing a monster.

Make these changes:

Line 122

From:

_player.ExperiencePoints += newLocation.QuestAvailableHere.RewardExperiencePoints;

To:

_player.AddExperiencePoints(newLocation.QuestAvailableHere.RewardExperiencePoints);

Line 347

From:

_player.ExperiencePoints += _currentMonster.RewardExperiencePoints;

To:

_player.AddExperiencePoints(_currentMonster.RewardExperiencePoints);

 

Check your work

Build the solution and make sure there are no errors in the “output” box at the bottom of Visual Studio. If you see any problems, double-check the changes you made in this lesson.

 

Summary

There is a programming principle called “DRY – Don’t Repeat Yourself”.

You generally don’t want to have code that does the same thing in multiple places. With repeated code, it takes longer to make changes, and you’ll often end up with bugs, because you missed the change in one place. Do something like this to ensure all your program uses the same logic.

 

Source code for this lesson

Source code on GitHub

Source code on Dropbox

 

Next lesson: Lesson 20.1 – Refactoring the SuperAdventure program

Previous lesson: Lesson 19.5 – Changing dropdown default values

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

8 Comments

  1. Scott
    Scott October 30, 2015

    Great Tutorial! I have a question Ive been trying to add a new ‘race’ to the game.  Right now I have it where you can click a button for Human, or Dwarf.   After they click it populates the variables with the health and magic I specified however after killing a creature and it updates the health to max, it goes back to 10 (I have dwarf at 30 and human at 15).

    • Scott Lilly
      Scott Lilly October 30, 2015

      Hmmmm. This might be a good fit for an idea I had. I want to create some “live-coding” videos, so people can see how someone programs, and follow what their thought process is. So, instead of just seeing what change to make, they could see how to [eventually] make the change themselves. Debugging something might be a good start.

      If you’re willing to have me do that with your code, can you upload it to DropBox and send me the link for it?

  2. Sean
    Sean November 12, 2016

    This seems funky. I am new to programming, so take that with a grain of salt. It would just be weird to me- imagine I am a new developer who is now looking at your code. I look to find where maximumHP is being updated. I go to LivingCreature.cs. Nope. I look around, and of all places it is under the add experience method?

    What if I later have items that add maximum HP, for example? Why are we not using something like the auto-property method we used for calculating level? I realize they are different, because maximumHP is in the base class, while level is in the derived. But there must be a way around that, yeah? Or is this our way around it?

    Sorry for being obtuse, thank you!

    • Scott Lilly
      Scott Lilly November 13, 2016

      To find where a property is used, Visual Studio has some built-in features to help you. You can right-click on a variable, property, function, or class, and select “Find all references” (or, “Find all usages”). That will show you every place in the solution where it is used. The first time you start to work with a new program, you’ll use this very often – I’m doing that with a new project I’m working on a for a new client. When a solution is big, with multiple projects, it can take a long time to determine exactly where/how/when a value is changed. Some of the projects I work on have 100+ projects in a solution, and hundreds of thousands of lines of code. It takes a while to understand the structure of those programs, before you can start making changes.

      You could change the MaximumHitPoints property to use the same technique as the Level property. Or, you could make a function called “UpdateMaximumHitPoints”, and have the AddExperiencePoints function call that. Like most things in programming, there is almost always more than one way to implement a feature.

      Making changes like this is very common thing, when working on a program. You start with a small, simple program, and slowly add features to it. To start, you write the code the simplest way possible. Then, as you add features, you change the existing code to handle the new features. This could involve moving properties/functions into, or out of, a base class.

      This is a big reason for using version control. You get the simple features working, and save a version of the program. Then, you add the next feature. If the changes do not work, you can “revert” (undo) your changes, and return to the simpler, working version – and try your change again.

      Please let me know if you still have questions.

  3. Khaled Y Mohammad
    Khaled Y Mohammad July 16, 2018

    Couldn’t you override the MaximumHitPoints property of LivingCreature in Player and set its get to: Level*10? That’s what I did

    public class Player : LivingCreature
    {
    public int Gold { get; set; }
    public int ExperiencePoints { get; set; }
    public int Level {
    get {
    return ((ExperiencePoints / 100) + 1);
    }
    }
    public Location CurrentLocation { get; set; }
    public List Inventory { get; set; }
    public List Quests { get; set; }
    public int MaximumHitPoints
    {
    get
    {
    return Level * 10;
    }
    }
    ……

    • Scott Lilly
      Scott Lilly July 16, 2018

      Yes, you can. I left it as a normal property, because I was thinking about adding special spells/rings/potions/etc. that could increase the player’s MaximumHitPoints beyond multiplying by their level. However, I never added those features. So, your way would make the code cleaner.

Leave a Reply

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