Greed System¶
Summary: Greed is a hidden per-item risk meter that escalates with crafting. Every craft on an equippable accrues a hidden 0–100 value; as it crosses tiers (Clean → Touched → Tainted → Corrupting) the chance of consumption rises. On consumption the item is permanently locked from further crafting and gains a rolled Blessing from a curated, loot-sealed pool. The numeric meter is never shown — only the visual tier state and escalating color communicate risk. Solo players get risk-free crafts in the Clean band, so danger only exists when the player chooses to keep pushing. Server-authoritative; rides the item state-module + modifier-pool infrastructure.
Table of Contents¶
- Architecture Overview
- Core Concepts
- Risk Mechanics
- Blessings
- Presentation Layer (UI)
- Crafting Integration
- Replication & Authority
- Public Contracts
- Source References
- Related Systems
- Recent Changes
Architecture Overview¶
┌──────────────────────────────────────────────────────────────┐
│ UGreedConfigDataAsset (DA_GreedConfig) │
│ • tier thresholds (31 / 61 / 86) │
│ • per-tier consumption risk (0 / 4 / 10 / 25 %) │
│ • per-craft gain range (5–15) │
│ • BlessingPool → UModifierPoolDataAsset (sealed) │
└─────────┬────────────────────────────────────────────────────┘
│ loaded on all machines
▼
┌──────────────────────────────────────────────────────────────┐
│ UGreedSubsystem (GameInstanceSubsystem) │
│ • loads config on Initialize │
│ • registers BlessingPool via │
│ UModifierPoolManager::RegisterAuxiliaryPool() │
│ → blessing IDs resolve everywhere (tooltips on clients) │
└─────────┬────────────────────────────────────────────────────┘
│
▼ (server, during a craft)
┌──────────────────────────────────────────────────────────────┐
│ UCraftingContainerComponent::Server_ExecuteCraft │
│ 1. CanExecuteCraft → ItemConsumed gate (blocks if locked) │
│ 2. ApplyOutcome (existing crafting) │
│ 3. UGreedCraftingLibrary::AccrueGreedAndRollConsumption │
│ → FGreedItemState (state module) updated │
│ → on consume: roll Blessing, set bConsumed │
│ 4. Client_OnCraftingComplete(Outcome, Mods, GreedEvent) │
└─────────┬────────────────────────────────────────────────────┘
│
▼ (on equip)
┌──────────────────────────────────────────────────────────────┐
│ FEquipmentFragment::ApplyGlobalModifiersToCharacter │
│ → ApplyGreedBlessingToCharacter() applies the Blessing │
│ GE (+ optional granted proc ability) │
└──────────────────────────────────────────────────────────────┘
Key Design Principles¶
| Principle | Implementation |
|---|---|
| Hidden meter, visible state | GreedValue is server-internal; UI reads only VisualState (EGreedState) and bConsumed |
| No punishment for stopping | Clean band (0–30) is hard-coded 0% risk; risk exists only by choice |
| Server authority | Accrual, consumption roll, and blessing roll all run server-side |
| Reuse item state modules | FGreedItemState rides UItemObject::StateModules — same pattern as Remnant state |
| Generic sealed-pool pattern | Blessings register via RegisterAuxiliaryPool(), reusable by future sealed pools (runes, corrupted mods) |
| Ordered consumption moment | The consumption event is delivered in the crafting-complete RPC payload, not via module replication ordering, so the result panel and the reveal land together |
Core Concepts¶
Why Greed Exists¶
Greed delivers risk/reward depth and scarcity without rarity (GDD Progression, Trading, Player Experience pillars). Power doesn't come from a rarity tier — it comes from how far a player dares push an item before it locks. Consumed items with strong blessings become scarce, tradeable assets. Crucially, because the Clean band is risk-free, the system never punishes a cautious player; the tension is entirely opt-in.
Greed States¶
EGreedState is the only greed signal the UI reads.
| State | Hidden value | Consumption risk | Meaning |
|---|---|---|---|
Clean |
0–30 | 0% | Safe to craft |
Touched |
31–60 | 4% | Mild risk |
Tainted |
61–85 | 10% | Notable risk |
Corrupting |
86–100 | 25% | High risk |
Consumed |
— | locked | No further crafting; Blessing granted |
Greed vs Other Item State¶
Greed is an item-state lifecycle system (peer to Remnant Sealed/Awakened), not a crafting mechanic — it integrates into crafting but owns its own config, subsystem, state module, validation surface, and equip-path application. See Item State Modules for the shared per-instance state pattern.
Risk Mechanics¶
Each executed craft on an equippable:
1. Lazily attach FGreedItemState on first craft (AddStateModule)
2. GreedValue += random in [GainMin, GainMax] (config, e.g. 5–15)
3. VisualState = DeriveState(GreedValue, Config)
4. Roll consumption against current tier's risk %
hit → ConsumeItem(): bConsumed = true, roll Blessing
5. MarkStateModulesDirty() → replicate
Risk is read from the tier the item is in after accrual. The Clean band's 0% is hard-coded in code (not a config field) so it can never be mistuned into a punishing state.
Blessings¶
A Blessing is a single rolled modifier from MP_GreedBlessings — a curated pool of 13 authored definitions (8 stat + 3 per-type + 2 proc), all EModifierType::Unique, EModifierScope::Global, Unique-tier value ranges. Two kinds:
- Stat blessings — a flat/increased attribute bump applied as a GE (the 8 core stat lines plus the 3 per-damage-type "Maw" lines).
- Proc blessings — grant a proc ability (
Blessing_FinalWord,Blessing_RedLedger) alongside the GE. Both reuse existing Echo proc bases, so they added no new C++:Blessing_FinalWordis a config-only child ofUPressureReleaseAbilitytriggered byEvent.Combat.KillCredited(kill → fiery burst);Blessing_RedLedgeris a child ofGA_OnHit_Bleed(a Bleed-on-hit proc).
The blessing pool is registered as an auxiliary pool on UModifierPoolManager (like the Remnant Echo pool): resolvable by ID everywhere for tooltips, but excluded from ordinary loot rolls. Roll selection respects spawn weights and the item's level/tags.
Application happens on equip via FEquipmentFragment::ApplyGreedBlessingToCharacter() — it reads FGreedItemState.Blessing, applies the GE, and grants the optional ability; symmetric removal on unequip. Same handle-storage pattern as Echo Mods.
Presentation Layer (UI)¶
The greed signal the player actually sees is color encoding STATE, never power (GDD). The numeric meter is never surfaced — every UI surface reads only VisualState (EGreedState), bConsumed, and the rolled Blessing, never the hidden GreedValue. Clean renders nothing (its color is White and the surfaces collapse), so a cautious player sees no decoration at all; decoration only appears once the player has chosen to push past the safe band.
State → Color¶
A single shared table, FGreedStateColors, is the one source of truth for the tint so the tooltip and crafting window can never drift. The Consumed tint doubles as the Blessing-line color.
| State | Default tint (linear RGB) | Surface behavior |
|---|---|---|
Clean |
White (none) |
Renders nothing; state line / badge collapsed |
Touched |
(0.85, 0.75, 0.45) muted gold |
State line + badge tinted |
Tainted |
(0.9, 0.5, 0.15) amber |
State line + badge tinted |
Corrupting |
(0.85, 0.2, 0.15) red |
State line + badge tinted |
Consumed |
(0.65, 0.3, 0.9) violet |
State line/badge tint and the Blessing line color |
Defaults live in code (the baked seed in FGreedStateColors) and on DA_GreedConfig (the Presentation category). Designers retune the hues in the config asset — no recompile. The baked seed exists so reads before subsystem init, in tests, and in editor previews (no play world) still get sensible colors.
Color Data Flow¶
┌────────────────────────────────────────────┐
│ UGreedConfigDataAsset (DA_GreedConfig) │
│ Presentation tints: Touched / Tainted / │
│ Corrupting / Consumed │
└───────────────┬─────────────────────────────┘
│ UGreedSubsystem::LoadAndRegisterConfig()
│ → FGreedStateColors::SetFromConfig()
▼
┌────────────────────────────────────────────┐
│ FGreedStateColors (live static table) │
│ seeded with baked defaults │
│ (pre-init / tests / editor previews work) │
└───────┬───────────────────────────┬─────────┘
│ read by │ read by
▼ ▼
ItemTooltipViewModel CraftingViewModel / UCraftingWidget
(greed line tint + (badge tint +
blessing-row color) overlay StateColor)
Surfaces¶
| Surface | What it shows | How |
|---|---|---|
Item tooltip (UItemTooltipWidget) |
A greed state line; a Blessing row for Consumed items | GreedStateText tinted from FGreedStateColors (collapsed on Clean); the rolled Blessing renders in BlessingModifiersBox under a BlessingHeaderText (detailed / Alt header, mirroring the Echo header) |
Crafting window (UCraftingWidget) |
A passive greed badge + a corruption overlay on the target item | GreedStateText badge collapsed when Clean; GreedStateImage is a corruption overlay driven by a MID (Progress scalar + StateColor vector), eased between states rather than hard-cut; re-resolves on cube add / remove / swap and stays live via OnItemStateModulesChanged |
The badge is passive — there is no warning or confirm prompt, because the meter is hidden by design; it is purely a risk signal. The crafting overlay's fill is discrete per state — Clean 0 / Touched .25 / Tainted .5 / Corrupting .75 / Consumed 1 — carried by CraftingViewModel::TargetGreedFill and tweened toward its target by the widget.
Crafting Integration¶
Two touch points in UCraftingContainerComponent, both server-side:
| Point | Behavior |
|---|---|
CanExecuteCraft() |
Adds ECraftingValidationResult::ItemConsumed — any recipe targeting a consumed equippable fails early (feeds Client_OnCraftingFailed) |
After ApplyOutcome() |
For ModifyExisting outcomes on an item with an FEquipmentFragment, calls AccrueGreedAndRollConsumption(), captures the FGreedCraftEvent, and passes it through the extended Client_OnCraftingComplete(Outcome, ResultModifiers, GreedEvent) RPC |
Accrual is per executed craft, not per operation — matching GDD semantics. Only equippables accrue (gated on FEquipmentFragment presence).
Replication & Authority¶
| Operation | Server | Client |
|---|---|---|
| Greed accrual / consumption / blessing roll | ✅ UGreedCraftingLibrary |
❌ |
FGreedItemState transport |
Mutated server-side, MarkStateModulesDirty() |
Reads via OnRep_StateModules |
| Consumption reveal ordering | Delivered in Client_OnCraftingComplete payload |
Receives event with result panel |
| Blessing definition resolution | Registered pool | Registered on all machines (tooltips work client-side) |
| Persistence (trade/save) | FGreedItemState serialized by reflection |
Round-trips like Remnant Awakened state |
Public Contracts¶
UGreedCraftingLibrary (static)¶
| Method | Purpose |
|---|---|
IsItemConsumed(Item) |
Query consumed state (any context) |
DeriveState(GreedValue, Config) |
Hidden value → EGreedState |
AccrueGreedAndRollConsumption(Item, Config) |
Server. One craft's accrual; returns FGreedCraftEvent |
ConsumeItem(Item, Config) |
Server. Lock item + roll Blessing |
UGreedSubsystem (GameInstanceSubsystem)¶
| Member | Purpose |
|---|---|
GetConfig() |
Loaded UGreedConfigDataAsset |
GetConfigFromWorld(WorldContext) |
Static convenience accessor |
Data Types¶
| Type | Purpose |
|---|---|
EGreedState |
Clean / Touched / Tainted / Corrupting / Consumed |
FGreedItemState |
State module: GreedValue (hidden), VisualState, bConsumed, Blessing |
FGreedCraftEvent |
RPC payload: NewState, bConsumptionTriggered, BlessingDescription |
UGreedConfigDataAsset |
Thresholds, per-tier risk, gain range, blessing pool ref |
Source References¶
| Component | Location |
|---|---|
EGreedState, FGreedItemState, FGreedCraftEvent |
Public/Greed/Types/GreedTypes.h |
UGreedConfigDataAsset |
Public/Greed/Data/GreedConfigDataAsset.h |
UGreedSubsystem |
Public/Greed/Subsystems/GreedSubsystem.h |
UGreedCraftingLibrary |
Public/Greed/GreedCraftingLibrary.h |
| Crafting integration | Private/Crafting/Components/CraftingContainerComponent.cpp |
| Blessing apply/remove | Private/Inventory/Items/Fragments/ItemFragment.cpp → ApplyGreedBlessingToCharacter() |
ItemConsumed result |
Public/Crafting/Types/CraftingTypes.h |
| Auxiliary pool API | Public/Inventory/Modifiers/ModifierPoolManager.h → RegisterAuxiliaryPool() |
FGreedStateColors (shared tint table) |
Public/Greed/Types/GreedStateColors.h |
| Presentation tints (config) | Public/Greed/Data/GreedConfigDataAsset.h |
| Color push to live table | Private/Greed/Subsystems/GreedSubsystem.cpp → LoadAndRegisterConfig() |
| Tooltip greed line + blessing row binding | Public/UI/Widgets/Tooltip/ItemTooltipWidget.h |
| Crafting badge / corruption overlay | Public/UI/Widgets/Crafting/CraftingWidget.h + Public/UI/ViewModels/Crafting/CraftingViewModel.h |
| Overlay material / textures | /Game/MaterialLibrary/UI/Greed/M_UI_GreedState, /Game/TextureLibrary/UI/Greed/T_UI_GreedFlow + T_UI_GreedNoise |
| Config asset | /Game/DataAssets/Greed/DA_GreedConfig |
| Blessing pool | /Game/DataAssets/Items/Modifiers/MP_GreedBlessings |
| Tests | Source/ProjectEternal/Private/Tests/GreedSystemSpec.cpp |
Related Systems¶
- Crafting System — recipe matching + outcome application that triggers accrual
- Item State Modules — per-instance state pattern
FGreedItemStaterides - Remnant Item System — the auxiliary/sealed-pool precedent (Echo Mods)
- Conditional Modifiers — sibling itemization channel from the same merge
- Equipment System — blessing GE/ability application on equip
- Widget Library — tooltip + crafting widgets that surface the greed state line, badge, and corruption overlay
Recent Changes¶
| Date | Change | Impact |
|---|---|---|
| 2026-06-11 | Greed system v1 | Hidden per-item meter (FGreedItemState) accrues on craft; tier-gated consumption locks the item and rolls a Blessing from the sealed MP_GreedBlessings pool; UGreedSubsystem registers the pool as auxiliary; ItemConsumed crafting gate; blessings applied on equip |
| 2026-06-17 | Presentation layer | Added the UI surface: shared FGreedStateColors table (seeded defaults, pushed from DA_GreedConfig via UGreedSubsystem::LoadAndRegisterConfig) drives the tooltip greed line + Consumed Blessing row and the crafting badge + eased corruption overlay (discrete fill per state, live via OnItemStateModulesChanged). Color encodes state not power; Clean renders nothing; meter stays hidden |
| 2026-06-17 | Blessing pool finalized | Pool reaches its full 13 authored definitions (8 stat + 3 per-type + 2 proc); the proc pair (Blessing_FinalWord on Event.Combat.KillCredited, Blessing_RedLedger Bleed-on-hit) reuses Echo proc bases, no new C++ |