> For the complete documentation index, see [llms.txt](https://modthegungeon.gitbook.io/semi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://modthegungeon.gitbook.io/semi/guides/adding-an-item.md).

# Adding an Item

Adding an item is a great way to familiarize yourself with the basics of making mods. Note: All of the solutions used in these guides are available on the [SemiGuides](https://github.com/modthegungeon/SemiGuides) repo.

Start off by opening your mod's solution.

![Mod template](https://2146063272-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LikZ_pjNOqILUk4RZOG%2F-LnMUHg--ZFZTYhM2oKT%2F-LnMV-hFHkEM0jHG6w8Z%2Fimage.png?alt=media\&token=19657a80-4f67-475c-a2ee-601fdb490349)

Assuming you haven't done it yet, you might want to consider [renaming the solution to your mod's name](https://www.youtube.com/watch?v=4-kSmqUxvd8).

![Solution after all the renaming](https://2146063272-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LikZ_pjNOqILUk4RZOG%2F-LnMUHg--ZFZTYhM2oKT%2F-LnMWKeniYeApZN01-KU%2Fimage.png?alt=media\&token=59be5ce1-7570-4f6e-8c10-7216c734427d)

Make sure that you have your `mod.yml` all set up.

![](https://2146063272-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LikZ_pjNOqILUk4RZOG%2F-LnMia3Iq61lETSY-XNp%2F-LnMii9LJTbBoXcMS2X5%2Fimage.png?alt=media\&token=12e385be-b202-465e-98f6-624239b1a6f2)

We will start off by creating an encounter icon for our item. This is the icon that shows up in the Ammonomicon. We technically could make it different to the actual item's sprite very easily, but for the purpose of this guide we won't.

Semi has a useful shortcut called `RegisterEncounterIcon`, which takes two parameters - the ID of our icon and a sprite path. It will automatically handle everything about the Ammonomicon sprite collection for us, and it's enough for our simple test item.

Note that `RegisterEncounterIcon` has to be ran in registering mode, meaning that we can only use it inside `RegisterContent`.

```csharp
public override void RegisterContent() {
    Logger.Debug($"Registering content.");
    
    RegisterEncounterIcon("@:my_item_icon", "my_item.png");
}
```

I've used a context ID `@:my_item_icon` here, meaning that the real ID of this icon (actually a sprite definition) will end up being `adding_an_item:my_item_icon` (the `adding_an_item` comes from `id` in`mod.yml`). Context IDs are a great way to avoid having to type out long namespaces every time, and they make it very easy to see where IDs are used too.

Now that we have an encounter icon present, we will start with creating the actual item itself. We have to first create its "sprite template" - the object that the game will copy when it wants to spawn the item. To create that sprite template, we need a sprite collection, and for that sprite collection we want a sprite definition containing our image.

If we wanted to just create a new sprite definition from a single image, we'd use the `CreateSpriteDefinition` method. However, that'd load the whole image again. There's a nifty shortcut that we can use - `RegisterEncounterIcon` creates a `SpriteDefinition` under the hood, and returns it at the end of the method. We can then reuse this sprite definition.

So, we've got the sprite definition step handled. Now we need to register the collection. We use `RegisterSpriteCollection` for this, unsurprisingly. ID, and then a list of definitions.

```csharp
public override void RegisterContent() {
    Logger.Debug($"Registering content.");
    
    var def = RegisterEncounterIcon("@:my_item_icon", "my_item.png");
    RegisterSpriteCollection(
        "@:my_item_coll",
        def
    );
}
```

Now we have a sprite collection. If we had more items, we could've put in all of their sprites into one collection, but we don't need that right now. It's time to register the sprite template - `RegisterSpriteTemplate`.

```csharp
public override void RegisterContent() {
    Logger.Debug($"Registering content.");
    
    var def = RegisterEncounterIcon("@:my_item_icon", "my_item.png");
    RegisterSpriteCollection(
        "@:my_item_coll",
        def
    );
    RegisterSpriteTemplate(
        "@:my_item_sprite",
        "@:my_item_coll",
        "@:my_item_icon"
    );
}
```

`RegisterSpriteTemplate` is a bit more high level, in that it takes IDs as opposed to concrete references. This makes the code more obvious at first glance and makes it easier for mods to interact with eachother.

We've now created a sprite template, called `my_item_sprite`, that points to the collection `my_item_coll`'s `my_item_icon` definition. We forgot about something, however - and that's the localization.

Gungeon supports multiple languages, and so naming an item isn't as simple as just giving it an English name. Even if you don't care about other languages, Semi allows mod authors to localize not only their own content but also content from other mods, so it's important that you play by the rules and use the systems present. Semi has its own localization system that is largely based off of Gungeon's one and works transparently with it, while working around some of EtG's localization system's flaws.

We will go ahead now and create an localization file for english. This is a simple text file where `#X` represents a key named `X` and all lines after that that don't start with `#` are considered the key's value. For example:

```
#SOMETHING
Something
```

Creates a key called `SOMETHING` with the value `Something`. Semi extends this basic format to give localization keys IDs, but we'll bring that up in a minute.

For now: minimalize that Visual Studio/Mono Develop window, and go into the `mod` folder in the solution's directory. Then enter `resources`. Create a new file, call it something like `english_items.txt`. In it write this:

```
#MY_ITEM_NAME
My Item
#MY_ITEM_SHORT_DESC
Very Cool Item
#MY_ITEM_LONG_DESC
This Item Is Very Cool
Yes
```

Congratulations! You've created a localization file. Wasn't so hard, was it?

Now we will get it set up so that Semi recognizes it. Localizations are registered using `RegisterLocalization` (you should be noticing a pattern here ;) ).&#x20;

```csharp
public override void RegisterContent() {
    Logger.Debug($"Registering content.");
    
    var def = RegisterEncounterIcon("@:my_item_icon", "my_item.png");
    RegisterSpriteCollection(
        "@:my_item_coll",
        def
    );
    RegisterSpriteTemplate(
        "@:my_item_sprite",
        "@:my_item_coll",
        "@:my_item_icon"
    );
    RegisterLocalization(
		"@:english_items",
		"english_items.txt",
		"gungeon:english",
		I18N.StringTable.Items
	);
}
```

Okay, okay, okay. I hear you. That's quite the number of arguments to load that one simple file. But you see, they are all there for a reason.

The first argument is of course the new localization's ID. It doesn't matter what you pick for this. The second argument is the path to the resource. The third is the target language, in this case English, and the fourth is the string table. There are 6 string tables - Core, Enemies, Intro, Items, Synergies and UI. This is a relic of how Gungeon was made - these string tables are essentially separate files per each language. For example, when obtaining the value `MY_ITEM_NAME` for the name of the item, the game will look in the Items table because it expects item localizations to be there. If it wants to get the name of a synergy, it'll look in the Synergies table. If you ask me, it's a bit of an unnecessary system, and hopefully we can get abstract it away in the future, but we have to use it for now.

While we are on the topic of the `resources` folder already, let's drop in our `my_item.png` into there as well. You can find it [here](https://raw.githubusercontent.com/ModTheGungeon/SemiGuides/master/01_AddingAnItem/mod/resources/my_item.png).

Alright, we've got everything prepared now. It's time to start writing the actual item code. We will create a new Class called `MyItem`. This class will extend from `PassiveItem`.

![](https://2146063272-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LikZ_pjNOqILUk4RZOG%2F-LnMUHg--ZFZTYhM2oKT%2F-LnMdIaFZPBzlYa218dx%2Fimage.png?alt=media\&token=f3cb7e34-500b-4f44-8ea1-57e837b7d4cf)

`PassiveItem` has virtual methods `Pickup` and `Drop`, so we will extend those:

![](https://2146063272-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LikZ_pjNOqILUk4RZOG%2F-LnMUHg--ZFZTYhM2oKT%2F-LnMdiJhIa3xctF_3G9_%2Fimage.png?alt=media\&token=46e72602-d82c-4e77-b854-7109dbc3a8f5)

For simplicity, this item will simply double the player's health. Arguably the most useful tool while modding is intellisense, also known as the autocomplete. If ever you want to accomplish something and you don't want to spend time on looking through the decompiler, just try certain keywords and you might hit jackpot. This is certainly the case here - typing `player.health` points me to `player.healthHaver`, and typing `player.healthHaver.max` points me to the `GetHealthMax` and `SetHealthMaximum` methods. However, sometimes it's worth it to bring out the decompiler - because checking how `BasicStatItem` works has led me to realizing that I can use the StatModifier system to be more in line with what the game expects. Here's how I accomplished doubling health:

```csharp
public class MyItem : PassiveItem {
	public StatModifier Modifier = new StatModifier {
		statToBoost = PlayerStats.StatType.Health,
		amount = 2,
		modifyType = StatModifier.ModifyMethod.MULTIPLICATIVE
	};

	public override void Pickup(PlayerController player) {
		base.Pickup(player);

		player.ownerlessStatModifiers.Add(Modifier);
		player.stats.RecalculateStats(player);
	}

	public override DebrisObject Drop(PlayerController player) {
		player.ownerlessStatModifiers.Remove(Modifier);
		player.stats.RecalculateStats(player);

		return base.Drop(player);
	}
}
```

I made it so that the stat modifier is saved as a property on the item, so that I can remove the modifier when the item is dropped. The code makes sure to recalculate the `PlayerStats` object after adding/removing the modifier to instantly see the difference.

Alright, looks like our item is ready. Time to finally register it with `RegisterItem`.

```csharp
public override void RegisterContent() {
	Logger.Debug($"Registering content.");

	var def = RegisterEncounterIcon("@:my_item_icon", "my_item.png");
	RegisterSpriteCollection(
		"@:my_item_coll",
		def
	);
	RegisterSpriteTemplate(
		"@:my_item_sprite",
		"@:my_item_coll",
		"@:my_item_icon"
	);
	RegisterLocalization(
		"@:english_items",
		"english_items.txt",
		"gungeon:english",
		I18N.StringTable.Items
	);
	
	RegisterItem<MyItem>(
		"@:my_item",
		"@:my_item_icon",
		"@:my_item_sprite",
		"#@:MY_ITEM_NAME",
		"#@:MY_ITEM_SHORT_DESC",
		"#@:MY_ITEM_LONG_DESC"
	);
}
```

We start off with the new item's ID, then we have the ID for the Ammonomicon icon and the ID for the sprite template. After that, we have the localization keys we defined previously. Note how they also have that `@:` context ID namespace - localizations in Semi are namespaced. Localization keys start with `#`, so what we end up with is a combination of both the namespace and the hash symbol. Otherwise, it's pretty much the same as other IDs. The order of the key arguments is as follows: item name, short description and long description.

It looks like we are done here. Build your mod in your IDE of choice, then copy over the `mod` folder to an appropriately named folder in `SemiMods`. Add the ID to `MySemiMods.txt`, and let's run it.

*Note: It seems like older versions of MonoDevelop (or possibly all of them) might not properly follow default compilation targets specified in the config file of the project. Make sure to check the modification date on `mod.dll` after building your mod. If it does not match with the last time you built the solution, try running `xbuild` or `msbuild` from the terminal.*

![SemiMods folder](https://2146063272-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LikZ_pjNOqILUk4RZOG%2F-LnMUHg--ZFZTYhM2oKT%2F-LnMi-7N6l_ITSRkt-N6%2Fimage.png?alt=media\&token=9361a800-03cc-48a9-aba3-869c72809bb1)

![MySemiMods.txt](https://2146063272-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LikZ_pjNOqILUk4RZOG%2F-LnMUHg--ZFZTYhM2oKT%2F-LnMi7gmvZWfVpuj9GQH%2Fimage.png?alt=media\&token=04fb723b-7f90-43d6-b830-120db4153f4d)

Now you can try running the game. Keep an eye on the output log.

If you are using the semi-dev build (which you should if you are writing mods), you can enter the game and open up the debug console (F2). Then, run `give adding_an_item:my_item`. This should give you the item and the effect.

![Before](https://2146063272-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LikZ_pjNOqILUk4RZOG%2F-LnMkniLJcZ9uhnddYQ8%2F-LnMluQy9p7bLCp8Qi_O%2Fimage.png?alt=media\&token=dc63d10f-2cb0-47b1-99c4-5a16938e81f1)

![After](https://2146063272-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LikZ_pjNOqILUk4RZOG%2F-LnMkniLJcZ9uhnddYQ8%2F-LnMmI68TYJRQvjDiqo8%2Fimage.png?alt=media\&token=fe8af35a-b944-4957-a7ce-4a0c6085c047)

(For some reason, the game doesn't give you that last heart filled, which is interesting. We could do that ourselves by healing the player, but this is enough for the tutorial.)

![Ammonomicon](https://2146063272-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LikZ_pjNOqILUk4RZOG%2F-LnMkniLJcZ9uhnddYQ8%2F-LnMmY-7jjxVqFcvfCT5%2Fimage.png?alt=media\&token=49e7ca3f-5c88-4adc-bc32-44dfd2648f70)
