Tutorial: Making Status Icons - rspforhp/WildfrostModdingDocumentation GitHub Wiki
By
: @Hopeless_phan (
)
(Click to expand)
-
1. Prior Setup
- 1.1 Subscribe to VFX Tools
- 1.2 Add VFX Tools as a Project Reference
- 1.3 IMPORTANT! Set VFX Tools as a Dependency
- 1.4 Update
usings - 1.5 The SpriteAsset
-
2. Designing the icon
- 2.1 General visual guidelines
- 2.2 Templates
- 3. Using StatusIconBuilders
- 4. Testing
Hello reader! I've made a straightforward way to make status icons using a custom databuilder, relying on the VFX Tools mod [Link].
You can test a simple mod that does this on the workshop: [Link], or see [the example code]
(Click to expand)
Steps to follow if you haven't used VFX Tools or made icons before
1.1 Subscribe to VFX Tools [Link]
If you haven't yet, make sure you are subscribed to the VFX Tools mod [Link]
This will be a similar process to the Basic Project Setup; Locate the DLLs of VFX Tools by opening the mods menu in-game, and pressing the Folder button.
This should open your File Explorer to the directory, which looks something like this. We can ignore everything except two DLLs:
- VFX_Tests.dll
- WildfrostHopeMod.Utils.dll

Now we just choose our favourite way to reference these into the project. I personally recommend this:
- Right click while selecting the DLLs, and choose "Copy as path" or press
SHIFT + CTRL + C. This will copy their filepaths to clipboard.
- In the IDE, go to Add references (see Basic Project Setup again for how)
- Choose to browse for files, and CTRL+V to paste the filepaths. Usually, this would be
"C:\Program Files (x86)\Steam\steamapps\workshop\content\1811990\3157544232\WildfrostHopeMod.Utils.dll" "C:\Program Files (x86)\Steam\steamapps\workshop\content\1811990\3157544232\VFX_Tests.dll"

Setting any mod as a dependency is done in two steps:
- Add the dependency mod's GUID (in this case,
"hope.wildfrost.vfx") to your mod class'sDependsarray. So your mod code would start with something like this:
public override string GUID => "hope.wildfrost.tutorial";
public override string[] Depends => new string[] { "hope.wildfrost.vfx" }; // This is what's needed for icons!
public override string Title => "Tutorial: Creating Status Icons";
public override string Description => "Learn how to make a new status effect with a custom icon!";- Add VFX Tools as a Required item on your mod's workshop page. This should be done automatically if you did the previous step and try uploading your mod with the Mod Uploader [Link]. You should still check this regardless.
When you've uploaded your mod to the workshop, your mod's workshop page will have owner controls which let you add required items. Here you'll have to navigate to your Subscribed items. Find and add VFX Tools as required.
Before going further, we have to add some usings. At the top of your project file, you should have at least these:
using Deadpan.Enums.Engine.Components.Modding;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using TMPro; // Declares TMP_SpriteAsset
using WildfrostHopeMod.Utils; // Creates TMP_SpriteAsset
using WildfrostHopeMod.VFX; // Declares StatusIconBuilderSpriteAssets will be required for icons to show up in text and effect descriptions. Assuming you've done the Initial setup in Tutorial 2, you need to declare some new variables:
// Already declared in Tutorial2
public static List<object> assets = new List<object>();
private bool preLoaded = false;
// TODO: This allows for icons in descriptions
public override TMP_SpriteAsset SpriteAsset => spriteAsset;
internal static TMP_SpriteAsset spriteAsset;Next create a basic sprite asset in Load(), then register it.
public override void Load()
{
if (!preLoaded)
{
// TODO: the spriteAsset has to be defined before any icons are made!
spriteAsset = HopeUtils.CreateSpriteAsset(Title);
CreateModAssets(); // <- where icons are made
preLoaded = true;
}
// TODO: Let our sprites automatically show up for icon descriptions
SpriteAsset.RegisterSpriteAsset();
base.Load();
}... and unregister in Unload()
public override void Unload()
{
// TODO: Prevent our icons from accidentally showing up in descriptions when not loaded
SpriteAsset.UnRegisterSpriteAsset();
base.Unload();
}
(Click to expand)
TLDR: Make sure there's at least 10% transparent padding around your icon! Template PSDs provided.
- Padding!!: All vanilla icons in the game come in a square format, with about 10% transparent padding around them. E.g., a 170x170 icon would have 17 pixels of padding.
- Visual clarity: Stackable vanilla icons (that show numbers) usually have flatter colors in the area where numbers appear (the black triangle in the example below). The numbers' shadow color usually share this flat color.

In these examples, the black area is where numbers will appear for stackable icons. Since Health (
) shows how many stacks it has, its center is simpler compared to Lumin (
) which doesn't need to show numbers.
These are some useful templates when making icons:
- Fonts:
- Icon template PSD: [Link] (Manually press "Download raw file")
- Card with icon template PSD: [Link] (Manually press "Download raw file")
Status Icons generally involve 3 new mod assets: a keyword, a status effect, and the actual icon. When multiple assets are involved for one thing, it's good practice to organise each group of assets in their own code.
Suppose we're making a new icon called "Amber". We could make a CreateAmberIcon() method to call in CreateModAssets() like this:
public void CreateModAssets()
{
CreateAmberIcon();
// anything else
}
public void CreateAmberIcon()
{
// everything Amber-related can go in here now
}
I'll also be putting this Amber icon (
) into a subfolder "Icons" of "Images" in the mod directory. This way I can access it later via ImagePath("Icons/amber.png").
Nothing special is really needed for these, so you should just make them as usual. These two examples will be barebones compared to what you can really do!
Warning
It's worth checking here that your mod's GUID should be all lowercase! If not, the game may not display the keyword popup for your icon.
public void CreateAmberIcon()
{
assets.Add(
new KeywordDataBuilder(this)
.Create("amber") // This cannot have spaces, all lowercase !!
.WithTitle("Amber") // The name that shows up when hovering the icon
.WithDescription("""
Freeze!
|Fossilised tree sap, which we call amber, waited for millions of years...
""")
);
assets.Add(
new StatusEffectDataBuilder(this)
.Create<StatusEffectSnow>("amber effect") // Can be any StatusEffect class
// other code to make the effect
.Subscribe_WithStatusIcon("amber icon") // TODO: Put whatever you want to name the icon builder
);
}Note
Note the addition of Subscribe_WithStatusIcon("amber icon") here. Replace amber icon with whatever you want to name the icon's builder.
As mentioned in the previous section, the example icon builder will have the name "amber icon". If you use a different name here, make sure to change it in the effect builder's Subscribe_WithStatusIcon too!
Now you'll have to choose a statusType that others won't accidentally use -- This can be part of your mod's GUID. Since my mod GUIDs start with hope, I choose to use hope.amber but you're not me. Use something else! >:O
In CreateAmberIcon(),
assets.Add(
new StatusIconBuilder(this)
.Create(name: "amber icon", // Used in StatusEffectDataBuilder.Subscribe_WithStatusIcon()
statusType: "hope.amber", // Use the [creator name].[icon name]
ImagePath("Icons/hope.amber.png")) // I put the image I want to use in [my mod directory]/Images/Icons
// Ideally the filename == status type, but VFX mod will try to adjust it
.WithIconGroupName(StatusIconBuilder.IconGroups.counter) // To show up under counter icons
// Icons without text can skip these two altogether
.WithTextColour(new Color(0.1f, 0f, 0f)) // Reddish-black
.WithTextShadow(new Color(1f, 1f, 0f)) // Opaque yellow shadow
.WithTextboxSprite() // This version reuses the main sprite for the textbox
//.WithTextboxSprite(ImagePath("Icons/amber.png")) // This version is slightly slower, but lets you use other (lower-res) textbox sprites
.WithKeywords(iconKeywordOrNull:"amber") // the "icon keyword" will be adjusted to show the icon's textbox sprite
);Note that most icons would use the same textbox sprite as the actual sprite, so only .WithTextboxSprite() is needed. For certain icons, it makes more sense to use two different sprites. Take this modded status Cat for example:
Pictured: Salvo Kitty from Absent Avalanche (https://steamcommunity.com/sharedfiles/filedetails/?id=3347694881)
Note that VFX Tools mod lets you import gifs and audio files. This lets you choose what visual effect/sound to play when this effect is applied, by adding
.WithApplyVFX(ImagePath("your gif.gif")) // Replace with your own GIF or APNG filepath, in the Images folder
.WithApplySFX(ImagePath("your sound.mp3")) // Replace with your own MP3/WAV/OGG etc filepath, in the Images folderUsing the Another Console mod [Link], you should quickly test that you can do the following commands:
-
add status <statusEffect name>to add the status to a card. If you specified any WithApplyVFX or WithApplySFX, it should also play. -
add attackeffect <statusEffect name>to add "Apply 1
" to the card. This card should then be able to apply the status to the target it triggered against -- if you specified any WithApplyVFX or WithApplySFX, it should also play on this target.

Note
Modded effects cannot be used with .SetAttackEffect() or .SetStartWithEffect as normal; this code runs before any of our effects exist... This is why we have to directly set data.attackEffects and data.startWithEffects.
Once you confirm they exist, move on to putting them in a card's databuilder. This can look like:
new CardDataBuilder(this)
.CreateUnit(name:"BerryPet", englishTitle:"Booshu")
.SetStats(4, 3, 4)
.WithValue(25) // Drop (25/36) = 0 gold as an enemy
.SubscribeToAfterAllBuildEvent(data =>
{
data.attackEffects = new CardData.StatusEffectStacks[]
{
SStack("amber effect", 1), // "Apply 1 Amber"
};
data.startWithEffects = new CardData.StatusEffectStacks[]
{
SStack("On Turn Heal Allies", 3),
SStack("amber effect", 1),
};
})Note
Try hovering over the icon (or card, if you set the attack effect) to see whether your keyword pops up. If not, check that your mod GUID is lowercase!