How-To: Write Augment Tooltips
Every augment can describe itself to the player. You get a generated description for free, you can override the wording anywhere it reads badly, and the numbers stay live either way - an override never goes stale when a value changes, because the numbers come from the data, not from what you typed.
GA_Fireball_C) is never substituted. Titles are rendered as rich text too, so markup works there as well as in descriptions.The three layers
| Layer | Where | Wins over |
|---|---|---|
| Generated | Automatic | Nothing - it is the fallback. |
| Per-step override | Description Override on an action, listener or mutation | The generated clause for that one step. |
| Whole-augment override | Description on the augment asset - the settings row at the top of the Augment tab | Everything. The generated text is discarded entirely. |
Description replaces the generated text completely, so every future change to the augment silently stops being described. A per-step Description Override only replaces that step, and the rest keeps generating itself.Description - are on the settings row at the very top of the stack, which is also what the editor opens on.Tokens
Write {PropertyName} anywhere in an override and it is replaced with that property's current value. Property names are the ones on the action, listener or mutation you are editing - the same names shown in the details panel, without spaces.
Chains to {MaxTargets} nearby foes within {Radius}cm.-> Chains to 2 nearby foes within 600cm.
{Radiuss} in the Tooltip Preview rather than a blank space. That is deliberate: a typo you can see is a typo you can fix.Finding nested values
Some values are not directly on the action. Apply Gameplay Effect keeps its magnitudes in a map keyed by SetByCaller tag, so the Amount you want is one level down. Tokens search inside automatically - a direct property always wins, and only if there is no match does it look deeper.
| Token | Finds |
|---|---|
{Radius} | A property on the action itself. |
{Amount} | The first Amount anywhere inside it, including inside a map entry. |
{Damage.Amount} | When several entries exist, the one whose map key ends in Damage. Keys match on their last segment, so SetByCaller.Damage.Base is addressed as Base. |
Format specifiers
A colon after the name adds formatting. The right form depends on where the token sits in the sentence, which is why there is no single default - "Radius" at the start of a sentence and "radius" in the middle are both correct, in different places.
| Written | Value | Prints | Use for |
|---|---|---|---|
{Radius} | 600 | 600 | The default - up to 2 decimals, trailing zeros trimmed. |
{Radius:0} | 600.4 | 600 | A whole number. Any digit 0-6 sets the decimal places exactly. |
{Radius:2} | 600 | 600.00 | Fixed decimals, padded. |
{Chance:percent} | 0.35 | 35% | A stored 0-1 value written the way a player reads it. |
{Chance:percent,0} | 0.125 | 13% | Percent with the decimals pinned. Order does not matter here. |
{MaxTargets:spaced} | ChainTargets | Chain Targets | Splitting a CamelCase name (bound values print a name, not a number). |
{MaxTargets:lower} | ChainTargets | chaintargets | Mid-sentence. |
{MaxTargets:upper} | ChainTargets | CHAINTARGETS | Headers. |
{MaxTargets:title} | ChainTargets | Chain Targets | Start of a sentence. |
{MaxTargets:spaced,lower} | ChainTargets | chain targets | Specifiers are comma-separated and apply left to right. |
{Amount:style=Damage} | 600 | <Damage>600</> | Rich-text markup. Put it last - it makes the value non-numeric, so a following percent or decimals spec finds nothing to parse. |
{Chance:percent,0} gives 35% - percent first, then round. {Chance:0,percent} rounds 0.35 to 0 first and gives 0%. When in doubt put percent first.Tokens only mutations have
| Token | Resolves to |
|---|---|
{Target} | The display name of whatever the mutation changes - the contract's Display Name for a property, or the attribute's name. Use this instead of typing the stat's name, so renaming it in the contract updates every description. |
Sets your blade alight for {Value} seconds, burning {Target}.-> Sets your blade alight for 5 seconds, burning Attack Power.
Referencing a gate
An event group's gate - its chance and minimum level - is not a property of any single action, so a step's override gets a second pass against the group it belongs to. {Chance} and {MinimumLevel} resolve there.
Chains to {MaxTargets} nearby foes. {Chance:percent} chance.-> Chains to 2 nearby foes. 35% chance.
The generator adds no wording of its own
It will not insert connectives (, or and ), an On Hit: prefix, a 35% chance to prefix, or trailing periods. All of that is phrasing, and phrasing is yours - "Chains to 2 foes. 35% chance." is unreachable if the generator has already committed to "35% chance to chain to 2 foes". Clauses are joined with a single space and carry their own punctuation, so write the punctuation you want inside each override.
Rich text
These descriptions are FText that your widget renders - the plugin never draws them. So markup you type into an override reaches a UCommonRichTextBlock unchanged, and works today with no setup.
Deals {Amount:style=Damage} damage over {Duration:1}s.-> Deals <Damage>600</> damage over 3.0s.
You can also write the tags by hand - "Chains to <Damage>{MaxTargets}</> foes." - if you want the markup around more than one token.
FRichTextStyleRow table your UI reads, and the Augment Editor's preview renders with the game's own styles. Left unset, the preview shows markup literally - deliberately, so you can see your tags are there rather than trusting a look that would not match the game.<Damage>600</> resolves against a row named Damage. Its decorators emit inline widgets - <img id="Skull"/> resolves against a different table, through URichTextBlockImageDecorator. One table does not do the other's job, which is why the preview has two settings.| Style set | Image decorator | |
|---|---|---|
| Markup | <Damage>600</> | <img id="Skull"/> |
| Row type | FRichTextStyleRow | FRichImageRow, or CommonUI's FRichTextIconData |
| Preview setting | Tooltip Preview Style Set | Tooltip Preview Image Set |
The image table's row type is read reflectively, so both shapes work - a Brush, or a ResourceObject plus ImageSize. An <img> whose id is not in the table renders as the literal tag in warning color, the same way an unrecognized {Token} stays visible.
Setting up colored text
- Create the table. Content Browser > Miscellaneous > Data Table, and pick RichTextStyleRow as the row structure.
- Add a row per style. The row name is the tag - a row called
Damageis written<Damage>. Set its Font, Color, and any decoration on the row. - Point your widget at it. On the Rich Text Block in your tooltip widget, set Text Style Set to that table.
- Use it. Write
<Damage>600</>in a Description Override, or let a token do it:{Amount:style=Damage}.
DT_TooltipTextStyles (row structure: RichTextStyleRow)Default <- SRichTextBlock falls back to this; worth addingDamage Font: Bold 12, Color: (1.0, 0.35, 0.25)Buff Font: Bold 12, Color: (0.45, 0.9, 0.5)Description Override:"Deals {Amount:style=Damage} damage."-> Deals <Damage>600</> damage.
Setting up inline images
- Create the table. Data Table with RichImageRow as the row structure (or CommonUI's RichTextIconData if you are using
UCommonRichTextBlock). - Add a row per icon. The row name is the id. Set its Brush - texture plus image size.
- Attach the decorator. On an engine Rich Text Block, add
RichTextBlockImageDecoratorto Decorator Classes and set its Image Set to your table. With CommonUI instead, subclassUCommonUIRichTextData, put your table in its Inline Icon Set, and select that subclass in Project Settings > CommonUI. - Use it - and mind the syntax, which differs between the two.
| Widget | Row structure | Markup |
|---|---|---|
URichTextBlock (engine) | FRichImageRow | <img id="Skull"/> |
UCommonRichTextBlock | FRichTextIconData | <Skull/> |
CommonRichTextBlock.cpp tests RunParseResult.Name), so an icon row called Skull is written <Skull/> - there is no img run and no id key. Writing <img id="Skull"/> into a UCommonRichTextBlock renders nothing. The Augment Editor preview accepts both forms so it matches whichever widget you use.DT_TooltipIcons (row structure: RichImageRow)Skull Brush: T_Icon_Skull, Size: 16 x 16Description Override, engine rich text block:"Executes below <img id=\"Skull\"/> 20% health."Description Override, CommonUI rich text block:"Executes below <Skull/> 20% health."
Bound values print a name, not a number
A value bound to an ability property resolves to whatever is equipped at the time, so outside a live loadout there is no single number to print - it shows the property's name instead. The Augment Editor's Tooltip Preview resolves it for the previewed contract and shows both, as Chain Targets (3).
Reading it from a widget
Call Build Ability Tooltip (category Crimson | Ability | UI) with the ability. Break the result into Title, Description, Stats and Augments. Drive a list from Stats, and tint the rows where bModified is true - that is the flag telling you an augment changed the number.
Drawing it your own way
Build Ability Tooltip returns the whole structure, which suits a UI that draws the whole structure. For anything else, UCrimsonAbilityTooltipStatics (same Crimson | Ability | UI category) takes it apart rather than making you walk Stats yourself.
| You want | Call |
|---|---|
| One number, bound to one property tag | Get Ability Stat - resolves without building the rest of the tooltip |
| The rows for one category, or only the ones that changed | Filter Stats with a Tooltip Stat Filter |
| One section widget per category | Group Stats By Category, ordered by Get Ability Stat Categories |
| Text and tint for a row | Format Stat Value, Format Stat Delta, Get Stat Change Direction |
| One row per augment effect instead of a paragraph | Get Augment Effect Lines For Ability |
| What changes if the player equips this augment | Build Ability Tooltip With Augment, then Diff Tooltips |
Value Type is its shape - Float, Int, Bool, Vector, or Attribute for an ability-scoped attribute adjustment. Its Categories are the semantic type: gameplay tags you author on the contract property (Stat.Offense, Stat.Utility) and which every stat line carries, so a panel asks for "the Offense rows" without knowing a single property tag.Each property also carries a Display block - Suffix, As Percent, Decimals, Higher Is Better, Hide From Tooltip. That is what turns 8.5 into 8.5s, and what lets Get Stat Change Direction say a lower cooldown is an improvement without every widget keeping its own list of inverted stats.
On Ability Properties Changed on the ability system component and rebuild - it fires on server and clients alike when an augment is equipped or unequipped, when an augment or the ability is levelled, and when the augment container replicates.Checking your work
The Augment Editor's Summary tab renders a Tooltip Preview using real numbers for the previewed contract at the toolbar's Preview Level - not placeholders. Change Preview Level and the numbers move with it. It assumes this augment alone is equipped, so a real loadout with several augments touching the same property will read differently - Build Ability Tooltip With Augment is the one that answers the loadout question.
See also
- Concept: Augment System - what mutations, actions and listeners are
- How-To: Add Your Own Augment Event - broadcasting events your game defines
- API Reference - BuildAbilityTooltip, UCrimsonAbilityTooltipStatics and the tooltip structs