Variables
StoryFlow variables are the backbone of dynamic storytelling. They store state that persists throughout your story - tracking player choices, inventory, stats, and any other data your narrative depends on. This guide covers how to interact with them from Unreal Engine.
Variable Types
Every variable in a StoryFlow project carries a set of core properties:
- Id - A generated hash identifier (e.g.,
var_A3F8B21C). Used internally by the runtime. - Name - The human-readable display name. This is the string you pass to getter/setter functions from Blueprint and C++.
- Type - One of the
EStoryFlowVariableTypeenum values. - Value - The current value, stored as an
FStoryFlowVariant. - bIsArray - Whether this variable holds a single value or an array of values.
- EnumValues - For Enum-type variables, the list of valid option strings.
EStoryFlowVariableType Enum
The plugin defines the following variable types:
| Type | Category | Description |
|---|---|---|
Boolean | Core | True or false flags (quest completed, has item, etc.) |
Integer | Core | Whole numbers (gold, health, counts) |
Float | Core | Decimal numbers (percentages, multipliers) |
String | Core | Text values (names, messages, locations) |
Enum | Core | One value from a predefined set of named options |
Image | Asset reference | Reference to an image asset (used internally by the runtime) |
Audio | Asset reference | Reference to an audio asset (used internally by the runtime) |
Character | Asset reference | Reference to a character definition (used internally by the runtime) |
Map | Container | Ordered key-value entries with String, Integer or Enum keys (see Maps). Added in v1.2.0. |
Core vs Asset Types
The five core types (Boolean, Integer, Float, String, Enum) are the ones you will interact with most often from Blueprints and C++. The asset reference types (Image, Audio, Character) are managed internally by the StoryFlow runtime to resolve media references during dialogue execution. You typically do not need to read or write asset-type variables directly. Alongside these scalar types, StoryFlow has two container shapes: any type can be an array (bIsArray) and the Map type holds ordered key-value entries (see Maps).
FStoryFlowVariant
FStoryFlowVariant is the type-safe value container used throughout the plugin. It holds one value at a time along with its type tag, so you always know what kind of data you are working with.
Getter methods return a default if the variant holds a different type:
| Method | Return Type | Default |
|---|---|---|
GetBool() | bool | false |
GetInt() | int32 | 0 |
GetFloat() | float | 0.0f |
GetString() | FString | "" |
GetArray() | TArray<FStoryFlowVariant> | Empty array |
GetMap() | TArray<FStoryFlowMapEntry> | Empty entry array |
GetMap() was added in v1.2.0 and returns the variant's ordered key-value entries (see Maps). Note that map-typed variants render as an empty string in ToString() and in dialogue text interpolation. Display formatting for maps is deliberately deferred, so read entries through GetMap() or GetMapVariable instead.
Factory methods create a variant from a typed value:
// Create variants from typed values
FStoryFlowVariant BoolVal = FStoryFlowVariant::FromBool(true);
FStoryFlowVariant IntVal = FStoryFlowVariant::FromInt(42);
FStoryFlowVariant FloatVal = FStoryFlowVariant::FromFloat(3.14f);
FStoryFlowVariant StringVal = FStoryFlowVariant::FromString(TEXT("Hello"));
// Read values back
bool bValue = BoolVal.GetBool(); // true
int32 iValue = IntVal.GetInt(); // 42
float fValue = FloatVal.GetFloat(); // 3.14
FString sValue = StringVal.GetString(); // "Hello"
// ToString() for display / logging
FString Display = IntVal.ToString(); // "42"
// Array support
TArray<FStoryFlowVariant> Items;
Items.Add(FStoryFlowVariant::FromInt(1));
Items.Add(FStoryFlowVariant::FromInt(2));
FStoryFlowVariant ArrayVal;
ArrayVal.SetArray(Items);
TArray<FStoryFlowVariant> Retrieved = ArrayVal.GetArray(); Local vs Global Scope
StoryFlow variables exist in one of two scopes, and the scope determines their lifetime and visibility:
| Property | Local Variables | Global Variables |
|---|---|---|
| Defined in | Per-script (.sfe file) | Project level (global-variables.json) |
| Lifetime | Copied fresh when a script starts executing | Shared across all components for the entire session |
| Visibility | Only accessible within that script | Accessible from any script, any component |
| Storage | UStoryFlowComponent instance | UStoryFlowSubsystem::GlobalVariables |
| Cross-component | No - each component has its own copy | Yes - changes in one component are visible to all others |
Scope Determines Behavior
The bGlobal parameter on every Get/Set function determines which scope to use. Passing the wrong value means you will read from or write to the wrong variable store. Local variables are per-component and reset on each script load, while global variables persist and are shared across every UStoryFlowComponent in the world via the UStoryFlowSubsystem.
// Reading a local variable (scoped to this component's current script)
bool bHasKey = StoryFlowComponent->GetBoolVariable("hasKey", false);
// Reading a global variable (shared across all components)
int32 PlayerGold = StoryFlowComponent->GetIntVariable("playerGold", true); Reading Variables
The UStoryFlowComponent exposes typed getter functions for reading variable values. All functions are available in both Blueprint and C++ under the category StoryFlow|Variables.
| Function | Parameters | Return Type |
|---|---|---|
GetBoolVariable | FString VariableName, bool bGlobal | bool |
GetIntVariable | FString VariableName, bool bGlobal | int32 |
GetFloatVariable | FString VariableName, bool bGlobal | float |
GetStringVariable | FString VariableName, bool bGlobal | FString |
GetEnumVariable | FString VariableName, bool bGlobal | FString |
Each function looks up the variable by its display name in either the local (component) or global (subsystem) store, then returns the value cast to the appropriate type. If the variable is not found, the type's default value is returned.
// C++ examples
UStoryFlowComponent* SF = GetOwner()->FindComponentByClass<UStoryFlowComponent>();
// Local variables
bool bQuestComplete = SF->GetBoolVariable("questComplete", false);
FString PlayerName = SF->GetStringVariable("playerName", false);
// Global variables
int32 Gold = SF->GetIntVariable("playerGold", true);
float Reputation = SF->GetFloatVariable("reputation", true);
FString Difficulty = SF->GetEnumVariable("difficulty", true); Variable Names
Variable names are the human-readable display names you assign in the StoryFlow Editor (e.g., playerGold, questComplete). You pass these names directly to getter/setter functions - no need to look up internal IDs. The bGlobal parameter disambiguates local and global variables that share the same name.
String Table Resolution
GetStringVariable and GetEnumVariable route their return value through the project's string table using the component's LanguageCode. When the stored value is a string-table key, the caller receives the localized display text rather than the raw key. When the stored value is not a string-table key, it passes through unchanged.
This means that two variables, one assigned a key like "npc.elder.greeting" and another assigned a literal string like "Hello", are both safe to read from the same call site. Localized authoring in the StoryFlow Editor reaches your Unreal UI without an extra resolution step on your side. Setters do not perform any string-table lookup. Values are stored verbatim.
// Stored value is a string-table key like "npc.elder.greeting"
// GetStringVariable returns the localized text such as "Welcome, traveler."
FString Greeting = SF->GetStringVariable("elderGreeting", true);
// Stored value is a literal string like "Bandit Hideout"
// GetStringVariable passes it through unchanged
FString Location = SF->GetStringVariable("currentLocation", true); Setting Variables
The component also exposes typed setter functions. Like the getters, these are available under the StoryFlow|Variables category in Blueprints.
| Function | Parameters | Returns |
|---|---|---|
SetBoolVariable | FString VariableName, bool Value, bool bGlobal | void |
SetIntVariable | FString VariableName, int32 Value, bool bGlobal | void |
SetFloatVariable | FString VariableName, float Value, bool bGlobal | void |
SetStringVariable | FString VariableName, FString Value, bool bGlobal | void |
SetEnumVariable | FString VariableName, FString Value, bool bGlobal | void |
Setting a variable updates the value in the appropriate scope and fires the OnVariableChanged delegate (see below). This means your game logic can react immediately to any change, whether triggered by a node in the StoryFlow graph or by your own Blueprint/C++ code.
// C++ examples
UStoryFlowComponent* SF = GetOwner()->FindComponentByClass<UStoryFlowComponent>();
// Set a local boolean (e.g., after player picks up a key)
SF->SetBoolVariable("hasKey", true, false);
// Set a global integer (e.g., award gold for completing a quest)
SF->SetIntVariable("playerGold", 500, true);
// Set a global enum (e.g., change difficulty at runtime)
SF->SetEnumVariable("difficulty", TEXT("Hard"), true); OnVariableChanged Delegate
Every time a variable changes - whether from node execution inside the StoryFlow graph or from a direct Blueprint/C++ call - the OnVariableChanged delegate fires.
Signature:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(
FOnVariableChanged,
const FStoryFlowVariable&, Variable,
bool, bIsGlobal
); Parameters:
- Variable - The full
FStoryFlowVariablestruct containingId,Name,Type,Value, and other metadata. Break the struct pin in Blueprint to access individual fields. - bIsGlobal - Whether the change occurred in the global scope.
Binding in C++:
// In your actor's BeginPlay
UStoryFlowComponent* SF = FindComponentByClass<UStoryFlowComponent>();
SF->OnVariableChanged.AddDynamic(this, &AMyActor::HandleVariableChanged);
// Handler
void AMyActor::HandleVariableChanged(const FStoryFlowVariable& Variable, bool bIsGlobal)
{
if (Variable.Name == "playerGold")
{
int32 NewGold = Variable.Value.GetInt();
UpdateGoldUI(NewGold);
}
// You can also check by type or internal Id:
// Variable.Id - internal hash identifier
// Variable.Type - EStoryFlowVariableType enum
} Blueprint Binding
In Blueprints, select the StoryFlow Component, then in the Details panel find the OnVariableChanged event and click the + button to create a bound event node. The event node provides the Variable struct and bIsGlobal as output pins. Break the Variable pin to access Id, Name, Type, and Value directly.
For character variable mutations including Name, Image and any custom field, use OnCharacterVariableChanged. See Characters.
Variable Interpolation in Dialogue
Dialogue text in StoryFlow can reference variables using the {varname} syntax. When the runtime builds the dialogue state, it automatically replaces these tokens with the current variable values.
// In the StoryFlow Editor dialogue node text:
"You have {playerGold} gold coins, {playerName}."
// At runtime, if playerGold = 500 and playerName = "Alice":
"You have 500 gold coins, Alice."
Interpolation is resolved automatically when the OnDialogueUpdated delegate fires. You do not need to perform any manual string replacement - the text in the dialogue state is already fully resolved.
Live Re-rendering on Variable Change
When a Set* node (setBool, setInt, setFloat, etc.) changes a variable and has no outgoing edge, the runtime returns to the current dialogue node and re-renders it with the updated variable values. This means the OnDialogueUpdated delegate fires again with the new interpolated text. Your UI simply needs to respond to OnDialogueUpdated as usual - the updated text arrives automatically.
Arrays
Variables can be arrays (bIsArray = true). An array variable holds an ordered list of FStoryFlowVariant values, all of the same type. Arrays are supported for Bool, Int, Float, String, Image, Character and Audio variables. The editor does not offer enum arrays.
Array Operations
The StoryFlow node graph provides a full set of array manipulation nodes. These operations execute as part of the story flow and update the variable automatically:
| Operation | Description |
|---|---|
| Get / Set Array | Read or replace the entire array |
| Get / Set Element | Read or write a single element by index |
| Add | Append an element to the end of the array |
| Remove | Remove an element by value or index |
| Clear | Remove all elements from the array |
| Length | Get the number of elements in the array |
| Contains | Check if a value exists in the array (returns boolean) |
| FindIn | Get the index of a value (-1 if not found) |
| GetRandom | Retrieve a random element from the array |
The forEach loop node iterates over all elements in an array, executing the connected subgraph once per element. This is useful for processing inventories, applying effects to party members, or evaluating a list of quest objectives.
Arrays in C++ / Blueprint
From Blueprint, read array variables with the typed Get Bool/Int/Float/String/Enum/Image/Audio Array Variable nodes (see Typed Array Getters) and write them with the typed Set Bool/Int/Float/String/Enum/Image/Audio/Character Array Variable nodes on the StoryFlow Component (available since v1.2.0) — each takes a plain array (TArray<bool>, TArray<int32>, TArray<float> or TArray<FString>) and replaces the variable's elements. From C++, the same component functions are available, or you can work with the variant directly: GetArray() returns a TArray<FStoryFlowVariant>, and SetArray() replaces it. All write paths fire OnVariableChanged just like scalar changes.
Reading Array Variables
The UStoryFlowComponent exposes GetArrayVariable(VariableName, bGlobal) as a one-call way to read any array variable as a TArray<FStoryFlowVariant>. The same string-table resolution rules from String Table Resolution apply per element: String and Enum elements are routed through the string table using the component's LanguageCode, while Image, Audio and Character elements pass through as raw keys.
When bGlobal is false the function searches local script variables first, then falls back to globals. When bGlobal is true the function searches globals only. The function returns an empty array if the variable is missing or is not an array.
UStoryFlowComponent* SF = GetOwner()->FindComponentByClass<UStoryFlowComponent>();
// Read a local array of inventory item names (strings)
TArray<FStoryFlowVariant> Items = SF->GetArrayVariable(TEXT("inventory"));
for (const FStoryFlowVariant& Item : Items)
{
UE_LOG(LogTemp, Log, TEXT("Inventory: %s"), *Item.GetString());
}
// Read a global array of quest stage numbers (ints)
TArray<FStoryFlowVariant> Stages = SF->GetArrayVariable(TEXT("completedStages"), true);
for (const FStoryFlowVariant& Stage : Stages)
{
int32 StageNumber = Stage.GetInt();
// ...
}
For a character-typed array variable, use GetCharacterArrayVariable(VariableName) on the component instead. It returns TArray<FString> character paths ready to pass into the character APIs. See Character Lists.
Typed Array Getters
GetArrayVariable hands back TArray<FStoryFlowVariant>, which means every element has to be unwrapped with a variant getter before you can use it. When you already know the element type, the component also exposes a typed getter per type that unpacks each element in C++ and returns a plain Blueprint array. From Blueprint this means you never have to touch FStoryFlowVariant at all.
| Function | Return Type | Element Resolution |
|---|---|---|
GetBoolArrayVariable | TArray<bool> | Unpacked directly |
GetIntArrayVariable | TArray<int32> | Unpacked directly |
GetFloatArrayVariable | TArray<float> | Unpacked directly |
GetStringArrayVariable | TArray<FString> | Resolved through the string table |
GetEnumArrayVariable | TArray<FString> | Enum option strings, resolved through the string table |
GetImageArrayVariable | TArray<FString> | Raw asset keys (not resolved) |
GetAudioArrayVariable | TArray<FString> | Raw asset keys (not resolved) |
Every typed getter takes the same (FString VariableName, bool bGlobal = false) parameters and shares the scoping rules of GetArrayVariable: with bGlobal false it searches local script variables first and then falls back to globals, and with bGlobal true it searches globals only. Each getter requires the variable to be an array of its own element type. A missing, non-array or wrong-typed variable logs a warning and returns an empty array. These are the read counterparts to the typed Set*ArrayVariable setters.
UStoryFlowComponent* SF = GetOwner()->FindComponentByClass<UStoryFlowComponent>();
// Read a local integer array as a native TArray<int32> - no variant unwrapping
TArray<int32> Stages = SF->GetIntArrayVariable(TEXT("completedStages"));
for (int32 Stage : Stages)
{
// ...
}
// Read a global string array; elements come back localized via the string table
TArray<FString> Party = SF->GetStringArrayVariable(TEXT("partyNames"), true);
// Read an image array as raw asset keys
TArray<FString> Portraits = SF->GetImageArrayVariable(TEXT("unlockedPortraits")); Blueprint: Skip the Variant
In Blueprint, the typed getters appear as Get Bool/Int/Float/String/Enum/Image/Audio Array Variable nodes on the StoryFlow Component. Each returns a ready-to-use array pin (Boolean, Integer, Float or String), so you can wire it straight into a ForEach loop without breaking a variant. Reach for the variant-based Get Array Variable only when the element type is not known ahead of time.
Maps
Added in v1.2.0. A map variable holds an ordered list of key-value entries. Keys can be String, Integer or Enum typed and values can be any scalar variable type. Entry order is preserved exactly as the StoryFlow Editor serializes it, so key listings, value listings and iteration order match the editor's HTML runtime.
Map Operations
The node graph provides ten map operation nodes. Like the array nodes, they execute as part of the story flow and update the variable automatically:
| Operation | Description |
|---|---|
| getMap / setMap | Read the whole map or assign one map variable to another (see setMap Aliasing) |
| getMapValue / setMapValue | Read or write the value stored under a key |
| hasMapKey | Check if a key exists in the map (returns boolean) |
| mapSize | Get the number of entries in the map |
| mapKeys / mapValues | Get all keys or all values as an array, in entry order |
| removeMapKey | Remove the entry stored under a key |
| clearMap | Remove all entries from the map |
The forEachMap loop node iterates over a map's entries, executing the connected subgraph once per entry. The entry list is snapshotted once when the loop starts, and each iteration exposes the current key and value as loop outputs for the body to read. Mutations inside the body land on the live map but do not skip, repeat or extend iteration.
setMap Aliasing
Assigning one map variable to another with setMap aliases the live storage instead of copying it. After the assignment, both variables observe the same entries: mutating or clearing the map through either variable is visible through the other. This matches the reference semantics of the editor's HTML runtime.
Aliases are detached at asset-to-runtime copy boundaries. When script locals, subsystem globals or runtime characters are copied out of an imported asset, every map variable receives fresh storage, so runtime mutations never write into the script asset and never leak between runs.
Reading Map Variables
The UStoryFlowComponent exposes GetMapVariable(VariableName, Keys, Values, bGlobal) to read a map variable from Blueprint or C++. It returns the entries as two parallel TArray<FStoryFlowVariant> output arrays where Keys[i] pairs with Values[i], in the map's entry order. String and Enum values are resolved through the string table using the component's LanguageCode so callers receive localized text, while keys stay raw identifiers and never resolve. Both arrays come back empty if the variable is missing or is not a map.
UStoryFlowComponent* SF = GetOwner()->FindComponentByClass<UStoryFlowComponent>();
// Read a global map of quest names keyed by quest id
TArray<FStoryFlowVariant> Keys;
TArray<FStoryFlowVariant> Values;
SF->GetMapVariable(TEXT("questLog"), Keys, Values, true);
// Keys[i] pairs with Values[i], in the map's entry order
for (int32 i = 0; i < Keys.Num(); ++i)
{
UE_LOG(LogTemp, Log, TEXT("Quest %s: %s"),
*Keys[i].GetString(), // raw key identifier
*Values[i].GetString()); // localized display text
} Typed Map Access
GetMapVariable returns parallel variant arrays, which means you index two arrays and unwrap each entry yourself. When you know the map's key and value types up front, the component also exposes typed getters that return a native TMap. Each one is named for its key-and-value pair, so the type is obvious at the call site and Blueprint receives a real map pin.
| Function | Return Type | Key Type / Value Type |
|---|---|---|
GetStringToBoolMap | TMap<FString, bool> | String or Enum key / Boolean value |
GetStringToIntMap | TMap<FString, int32> | String or Enum key / Integer value |
GetStringToFloatMap | TMap<FString, float> | String or Enum key / Float value |
GetStringToStringMap | TMap<FString, FString> | String or Enum key / String-family value |
GetIntToBoolMap | TMap<int32, bool> | Integer key / Boolean value |
GetIntToIntMap | TMap<int32, int32> | Integer key / Integer value |
GetIntToFloatMap | TMap<int32, float> | Integer key / Float value |
GetIntToStringMap | TMap<int32, FString> | Integer key / String-family value |
Every typed map getter takes the same (FString VariableName, bool bGlobal = false) parameters and applies the same scoping as the array readers: locals during dialogue, then globals. The variable must be a map whose key and value types match the requested pair, or the getter logs a warning and returns an empty map. A few details worth knowing:
- The
StringTo*getters accept both String and Enum keyed maps. An enum-keyed map comes back keyed by the enum option string. - The
*ToStringMapgetters accept any string-family value type: String, Enum, Image, Audio and Character. String and Enum values are resolved through the string table; Image, Audio and Character values come back as raw asset keys. - Boolean, Integer and Float value getters return their value type unchanged.
TMap Does Not Preserve Order
A native TMap is unordered, so the typed getters do not retain the map's entry order. When you need to walk the map in the exact order the StoryFlow Editor serialized it, read the ordered key list with GetMapKeysInOrder (below) and look up each value through the typed map.
UStoryFlowComponent* SF = GetOwner()->FindComponentByClass<UStoryFlowComponent>();
// Read a global string-keyed, integer-valued map (e.g. reputation per faction)
TMap<FString, int32> Reputation = SF->GetStringToIntMap(TEXT("factionReputation"), true);
int32 GuildStanding = Reputation.FindRef(TEXT("guild"));
// Read an integer-keyed, string-valued map (e.g. quest titles by quest id)
TMap<int32, FString> QuestTitles = SF->GetIntToStringMap(TEXT("questTitles"), true);
if (const FString* Title = QuestTitles.Find(42))
{
// *Title is localized through the string table
} Reading Map Keys in Order
GetMapKeysInOrder(VariableName, bGlobal) returns the map's keys as a TArray<FString> in the map's serialized entry order. This is the only ordered view of a map's keys exposed as native types - the typed map getters above hand back an unordered TMap. String and Enum keys are returned verbatim; Integer keys are stringified. Combine it with a typed map getter to iterate entries in order:
UStoryFlowComponent* SF = GetOwner()->FindComponentByClass<UStoryFlowComponent>();
// Ordered keys + the unordered typed map = ordered iteration
TArray<FString> Order = SF->GetMapKeysInOrder(TEXT("factionReputation"), true);
TMap<FString, int32> Reputation = SF->GetStringToIntMap(TEXT("factionReputation"), true);
for (const FString& Key : Order)
{
int32 Value = Reputation.FindRef(Key);
UE_LOG(LogTemp, Log, TEXT("%s = %d"), *Key, Value);
} Stringified Integer Keys
For an integer-keyed map, GetMapKeysInOrder returns each key as its string form (for example 3 becomes "3"). To look the value up in a TMap<int32, ...> returned by GetIntToIntMap or GetIntToStringMap, convert the key back with FCString::Atoi first.
Writing Typed Maps
Each typed map getter has a matching setter that takes a native TMap and replaces the variable's entries. Like the scalar and array setters, the map setters fire OnVariableChanged, and on a missing, non-map or mistyped variable they do nothing except log a warning. Because TMap is unordered, the written entry order is not preserved.
| Function | Values Parameter |
|---|---|
SetStringToBoolMap | TMap<FString, bool> |
SetStringToIntMap | TMap<FString, int32> |
SetStringToFloatMap | TMap<FString, float> |
SetStringToStringMap | TMap<FString, FString> |
SetIntToBoolMap | TMap<int32, bool> |
SetIntToIntMap | TMap<int32, int32> |
SetIntToFloatMap | TMap<int32, float> |
SetIntToStringMap | TMap<int32, FString> |
The StringTo* setters accept a map whose key type is String or Enum: when the target variable's keys are enum-typed, each key string is stored as an enum value. The *ToStringMap setters store their values verbatim, with no string-table key created, so written string and enum values are language-locked exactly like SetStringVariable.
UStoryFlowComponent* SF = GetOwner()->FindComponentByClass<UStoryFlowComponent>();
// Replace a string-keyed, integer-valued map wholesale
TMap<FString, int32> Reputation;
Reputation.Add(TEXT("guild"), 25);
Reputation.Add(TEXT("thieves"), -10);
SF->SetStringToIntMap(TEXT("factionReputation"), Reputation, true);
// Fires OnVariableChanged just like a scalar setter Typed Maps in Blueprint
In Blueprint, the typed getters and setters appear as Get/Set String To Int Map, Get/Set Int To String Map, and so on, each with a native map pin. Build a map with Make Map nodes and feed it to a setter, or read a map and pull values with Find - no FStoryFlowVariant handling required.
Maps and Characters
Map variables cannot be created on characters in this release. The character system is getting a redesign soon and maps will come to characters with it.
Resetting Variables
The plugin provides functions to reset variables back to their initial values as defined in the StoryFlow project. This is useful for restarting a story, resetting a scene, or clearing state for a new game.
| Function | Class | What It Resets |
|---|---|---|
ResetVariables() | UStoryFlowComponent | Resets local variables on this component to their initial values from the script definition |
ResetGlobalVariables() | UStoryFlowSubsystem | Resets global variables to their project defaults |
ResetAllState() | UStoryFlowSubsystem | Resets global variables, characters, and once-only option tracking - a full session reset |
// Reset just this component's local variables
StoryFlowComponent->ResetVariables();
// Reset global variables across all components
UStoryFlowSubsystem* Subsystem = GetGameInstance()->GetSubsystem<UStoryFlowSubsystem>();
Subsystem->ResetGlobalVariables();
// Full state reset (globals + characters + once-only options)
Subsystem->ResetAllState(); Reset Scope
ResetVariables() only affects the local variables of the specific UStoryFlowComponent you call it on. If you have multiple components in your world (e.g., multiple NPCs), each must be reset individually. For a full new-game reset, call ResetAllState() on the subsystem and then ResetVariables() on each active component.