-
Notifications
You must be signed in to change notification settings - Fork 5
Development: Upgrades
The upgrade system is critical to character progression. In a roguelike it is necessary to have a large number of possible upgrades so that the play can take many different paths through the game. This document describes the upgrade system.
Recipes are how we describe upgrades. They are Scriptable Objects which describe the upgrade in detail. The majority of information is in the AbstractRecipe class. Upgrade specific information is in an appropriate class that extends AbstractRecipe.
They are created using the Create -> Rogue Wave -> Recipe -> RECIPE TYPE menu options.
There are two broad categories of recipes:
- Item recipes - these will typically produce an in-game item, such as a weapon, a health pack or ammunition
- Stat recipes - there alter a game statistic in some way, such as increase movement speed, or ammunition damage
Once an Item Recipe is acquired the player will usually need to build the item using the recipe as a separate action. Stat recipes, however, will often be applied upon recipe of the recipe.
In this section we will document a few examples of different types of upgrades to illustrate how they are built. We'll start off by looking at a Stat Recipe and then look at an Item Recipe.
All stat recipes implement BaseStatRecipeYour implementation will likely want to override the following:
internal override void Apply() { ... } // REQUIRED: The logic for applying the stat when the recipe is followed
public override string Category => "Your category name"; // RECOMMENDED: Used in the UI to group similar recipes, failure to specify this will put the recipe in a "Base Stat" categorty.
public override string TechnicalSummary() { ... } // OPTIONAL: used to generate a description of what the recipe does for display in the UI. A generic description will be provided if this is not implemented.Let's take a look at some examples.
A HealthRecipe one is very easy to implement, we simply need to tell the BaseStatRecipe which component contains the stat to be modified. To do this add the following Apply() implementation;
internal override void Apply()
{
Apply(FpsSoloCharacter.localPlayerCharacter.GetComponentInChildren<BasicHealthManager>() as MonoBehaviour);
}We won't add a TechnicalSummary() override as the default will be just fine in this case. We will, however, add a category:
public override string Category => "Health";That's it, from a code perspective. That's not everything though, we now need to create the actual stat recipe. If you look at the source for the above you will see that it includes a CreateAssetMenu attribute like this:
[CreateAssetMenu(fileName = "Health Recipe", menuName = "Rogue Wave/Recipe/Health Recipe", order = 10)]Right click on the project view and select Rogue Wave -> Recipe -> Health Recipe. Now you can configure the settings. We'll not go over everything in this object, there are tooltips to help guide you. The bit we really care about is at the bottom of the inspector:

As you can see we are using a "Named Parameter" this is why we don't need to do anything other than pass through the component that is being used. This single Scriptable Object will work for any parameter that is on the BasicHealthManager or any subclass of it. The Parameter Name is critical, this is the parameter we want to change. It must match the name of the parameter in the class exactly. Next, we have a modifier a value that is added to the parameter, use negative values to subtract from the value, and a multiplier, a value used to multiply the parameter (use >1 to increase the parameter and <1 to decrease it). Finally, there is a Repeat Every value. If set to a non-zero value this change will be applied every time this many seconds tick by.
So, in the image above we are adding 10 to the healthMax parameter. It's really that easy. Once you have configured the other fields this will be picked up by the engine and offered in game without further work. Here's another example, this time increasing the healthMax by 10%.

And for good measure, here is one that increases the players health by 1 every 5 seconds.

Let's look at a slightly more complicated stat recipe. This one will allow us to modify the stats on a passive weapon. There are many PassiveWeapons, we might want to create Stat Recipes that will upgrade all passive weapons, in which case we can implement it in the same way as above, though we will need to iterate over all PassiveWeapons in the Apply() method. But what if we want to create an upgrade for a specific weapon. Well that's easy too.
In your PassiveWeaponStatRecipe simply add a field for the weapon prototype, then when you are iterating over the available weapons use this as a filter and send only that weapon to the base.Apply(Monobehaviour) method. An alternative approach would be to filter on weapon type (affecting a subset of PassiveWeapons). In fact you can filter the list of weapons in any way desired.
Here's the recipe for the Pistol weapon:

We try to ensure that there are tooltips for all fields and thus we will not describe each field in full here, instead we will describe the purpose of groups of fields, see tooltips for more details on specific fields.
The first section is fairly self-explanatory. It is the data for the UI.
Next up we have the metadata that defines when the recipe should be considered as an offering for the player. This information is used by the system to decide which of the recipes are best to be offered in any given circumstance.
The build section describes how the game should treat the recipe. That is, whether the item is consumable (use once) or not, whether the player can stack multiple versions of the recipe (e.g. 3 of the +10% speed upgrades gives 3 distinct 10% boosts, compounding), etc.
The feedback section describes the visual and audio feedbacks that should be used when the recipe is offered or built.
If the recipe produces an item, as this one does, then the item is defined as a NeoFPS pickup.
The final section here is unique to weapons and defines the associated Ammo recipe for this weapon.
Most of the content is the same for stat recipes, but the final section describes the modifier to apply rather than the item that should be built.

Sometimes you need to ensure that a character has a specific recipe in order to test things. You can easily do this in the Assets/_Dev/Scenes Dev/Nanobot Dev scene. It's also possible to do it in normal gameplay.
You can add recipes to the character spawned into the test scene by adding them to the Rogue Wave Game Mode:
When you create your game you can add recipes to the character in the Recipe selection hub scene:

To do so find the Recipe Selector UI on the RW_HubSceneCanvas object:

Add the recipes you want to test in the Test Recipes field and click the Add test recipes button. They will be added to your players permanent recipes.