Interaction, NPCs and dialogue¶
All · 15 min read · No code
What the player sees: walking up to something usable shows a prompt beside the character ("A Talk", "A Open", sometimes "X Trade"), and the button does exactly that. Talking to someone frames the two speakers with the camera, shows each line in a box over the speaker's head, and waits for A between lines.
Every interactable thing decides its own prompt word and range, and XenoCore picks the nearest one in range. An NPC's On Interact event (in its Blueprint graph) decides what talking does: play some lines, offer a quest, open a shop, recruit a party member. The idea that makes the rest make sense: what the prompt shows is exactly what the button does, because the press acts on whatever the prompt last offered.
What you can change¶
- A talking NPC: Make an NPC talk.
- A conversation with choices: Branch a conversation.
- An NPC who gives a quest, or is a quest's target: Quests, Give a quest to defeat enemies, talk to someone, or go somewhere.
- An NPC who joins the party: Recruit a party member from an NPC.
- A shopkeeper or trader: Open a shop, Set up a trade.
- A lever, door, sign or pickup: Add an interactable object.
- How the prompt, name plate and dialogue box look: Extending it.
How it fits together¶
| Piece | Kind | Job |
|---|---|---|
| Interaction system | Built in, nothing to place | Picks the nearest interactable in range every 0.2 s, draws the prompt, routes the button |
XenoCoreInteractableActor |
Parent class for your Blueprints | A door, lever, sign or pickup. Two verb fields; Can Interact, On Interact, On Focused, On Unfocused events |
UserInterface/HUD/W_XenoCore_InteractPrompt |
Widget, set by Interact Prompt in XenoCore UI settings | The "button + verb" chips beside the player. It can draw four; the subsystem sends it at most two |
Input/Abilities/GA_XenoCore_InteractPress and GA_XenoCore_InteractPressSecondary |
Input abilities | Call Handle Interact Press with verb 0 (A) or verb 1 (X) |
Characters/NPC/B_XenoCore_Npc |
NPC Blueprint | A townsperson: name plate, quest marker, idle clip, the On Interact event. Starts blank: no lines, no quest, no marker |
Characters/NPC/B_XenoCore_Npc_Sample |
Child of B_XenoCore_Npc |
A finished example carrying the sample lines and the sample quest DA_XenoCore_Quest_Collection01 |
UserInterface/HUD/W_XenoCore_NpcLabel |
Widget | The name, chevron and quest bubble over an NPC's head, as one widget |
| Dialogue system | Built in, nothing to place | Shows one line at a time over the speaker, waits for A, holds the player still |
Characters/NPC/BP_XenoCore_DialogueAnchor |
Actor Blueprint, set by XenoCore Content › Dialogue Anchor | Carries the dialogue box and attaches it to whoever is speaking |
UserInterface/HUD/W_XenoCore_DialogueBox |
Widget | The speech box itself |
Cameras/CameraRig_XenoCore_Dialogue, set by XenoCore Content › Dialogue Camera Rig |
Camera rig (Field of View + XenoCore Dialogue Framing node) | Moves the camera in over the player's shoulder for a conversation and back out after |
| Show Dialogue, Play Dialogue, Close Dialogue | Blueprint nodes (XenoCore › Dialogue) | One line and wait; a whole list of lines then close; close the box and release the player |
The treasure chest (see Loot) is found the same way. Lyra's own interaction ability,
Input/Abilities/GA_XenoCore_Interact, is still granted by Game/AbilitySet_XenoCore_Interact, but
it no longer decides what A does. It still traces for Lyra interactables and, while it finds one,
holds Status.XenoCore.InteractAvailable, which stops Palette Confirm; the gameplay event it
waits on (XenoCore.Event.Interact) is sent by nothing.
The interaction abilities reach the player through the party, not through the pawn data:
AbilitySet_XenoCore_Interact is the party's Leader Only Ability Set, granted to whichever body
the player drives. (Experiences/B_XenoCore_Experience also grants it to LyraPlayerState, where it
does nothing.)
Lifecycle¶
Registering. An NPC, a chest or a child of XenoCoreInteractableActor signs itself up when the
level starts playing and signs off when it is removed. Nothing to set up.
Choosing. Every 0.2 seconds XenoCore looks at every interactable, skips any that say they are unavailable (an opened chest, for example), and takes the nearest one within that actor's own range, measured from the player character's location to the actor's origin. The prompt then shows the actor's verbs: the main verb on A and the first extra verb on X. Any further verbs are dropped (see below). When the chosen actor changes, the old one is told it lost focus and then the new one that it has it. While the prompt is up, A does not also jump, and that lasts 0.5 s after the prompt goes away, so a held button does not turn into a jump.
Hidden prompt. The prompt hides whenever the world is covered: a menu is open, a quest reward or level-up banner is showing, or a panel has suppressed it (the loot panel, a conversation).
Pressing. The press runs in a fixed order:
- If a conversation is on screen, A advances it. Nothing else happens.
- If the world is covered by a banner, A dismisses the newest banner early.
- Otherwise A acts on whatever the prompt is currently offering, and nothing else. No prompt, no interaction.
Talking. Before the graph runs, an NPC with a Quest Id counts as talked to for every active
quest whose Talk To NPC objective names it (so a last step at the quest giver hands in during the
same conversation). Then its Blueprint event On Interact runs, with the pressed verb's index. The shipped B_XenoCore_Npc graph branches on Is Trade Verb, plays dialogue, offers
or turns in its quest, recruits its Member To Recruit if it has one, and opens a shop at the end
of the conversation if it has a Shop Table (see Quests and
Shops and trade).
Recruiting. An NPC with Member To Recruit set adds that character to the party at the end of the talk (or after a turn-in, when Recruit After Quest names a quest that must be complete first). The member arrives at least at the party's level, their body steps into the NPC's place, and the NPC leaves. On every other NPC this does nothing. See Recruit a party member from an NPC.
Party members are interactables too: out of battle, stopping beside a companion offers Talk (a voiced line, see Battle voices), and a downed ally offers Revive (see Party Gauge, downed and revive).
A conversation. The first line puts the player on hold:
- The player cannot move or turn the camera, so the camera cannot swing the box around.
- The dialogue camera blends in (0.6 s) to frame the player and the NPC, and holds that shot for the whole conversation; replies move the box, never the camera. When the conversation closes it blends back (0.5 s) to exactly where the camera was.
- The player and the NPC turn to face each other (XenoCore Content › Dialogue Turn Seconds, 0.3 s). After the conversation the NPC turns back to how it was placed; the player stays facing it.
- Arts, the auto-attack and target mode are blocked (by rows in
Game/TagRelationships_XenoCore). - The interaction prompt and the NPC's own name plate hide.
Each line appears over the speaker's head. The first A press finishes the typing effect, the next advances. Close Dialogue releases all of it. It does nothing when no conversation is open, so it is safe to end every branch with it.
A conversation left open. A conversation that is open, has no line waiting for A, and has no
quest, trade or shop panel covering the box can never move on: A has nothing to advance. The
dialogue system checks for exactly that state 2 seconds after each A press, after a panel
closes, and after an NPC's On Interact returns. If it finds it, it logs a LogXenoDialogue
warning naming the NPC and closes the conversation, so the player is never stuck. The check waits
2 seconds because a graph may do other work between two lines; a pause longer than that closes the
box and the next line reopens it.
Settings¶
On a placed NPC (select it in the level; all of these are per instance):
| Setting | Where it lives | What it does |
|---|---|---|
| Display Name | XenoCore › NPC | The name on the plate, and the speaker name for lines with no Speaker |
| Has Quest | XenoCore › NPC | Shows the quest bubble. Off by default. Only used when Quest is empty |
| Quest | XenoCore › NPC | The quest this NPC gives. When set, the bubble follows the quest's state |
| Trade Offers | XenoCore › NPC | A trade table. Setting it adds a Trade verb on X |
| Shop Table | XenoCore › NPC | A shop table. The shop opens at the end of the conversation |
| Portrait | XenoCore › NPC | The face shown on the trade screen |
| Quest Id | XenoCore › NPC | The name a quest's Talk To NPC objective uses for this NPC (its Target Id). Empty for anyone no quest sends you to. See Give a quest to defeat enemies, talk to someone, or go somewhere |
| Member To Recruit | XenoCore › NPC › Recruit | The party member who joins when this NPC is talked to. Empty for everyone else |
| Recruit After Quest | XenoCore › NPC › Recruit | Join only once this quest is turned in. Empty = on the first talk |
| Join At Party Level | XenoCore › NPC › Recruit | The recruit arrives at least at the party's level. On by default |
| Leave When Recruited | XenoCore › NPC › Recruit | The NPC leaves and the member stands in its place. Off for a recruiter who stays behind |
| Dialogue | XenoCore › NPC › Dialogue | The lines played when talked to |
| Accepted / Declined / In Progress / Turn In Dialogue | XenoCore › NPC › Dialogue | Lines for each quest moment. Empty falls back to Dialogue |
| Face Player When Talked To | XenoCore › NPC › Dialogue | The NPC turns to face the player. On by default; turn off for someone seated or behind a counter (the player still turns) |
| Turn Back After Talking | XenoCore › NPC › Dialogue | After the conversation, turn back to the placed facing. On by default |
| Use Dialogue Camera | XenoCore › NPC › Dialogue | Frame the conversation. On by default; turn off for an NPC talked to often, such as a vendor |
| Dialogue Camera Rig | XenoCore › NPC › Dialogue | A framing for this NPC alone (duplicate CameraRig_XenoCore_Dialogue). Empty uses the project's |
| Interact Verb | XenoCore › NPC › Interaction | The word on the prompt. Default "Talk" |
| Extra Interact Verbs | XenoCore › NPC › Interaction | More verbs, after Trade. Only two verbs in total can be offered: see below |
| Interact Range | XenoCore › NPC › Interaction | Distance for the prompt, the name plate and the bubble. Default 200 |
| Idle Animation | XenoCore › NPC › Animation | The clip the NPC loops. No anim Blueprint is used |
Each dialogue line has three fields: Speaker (the name on the plate; empty means "use the
actor's own name"), Line (keep it under 165 characters or a warning is logged), and Source
(Npc or Player: whose head the box sits over).
On Blueprint class defaults:
| Setting | Where it lives | What it does |
|---|---|---|
| Overhead Widget Class, Overhead Height | B_XenoCore_Npc › XenoCore › NPC › Overhead |
The plate widget and where its bottom edge sits |
| Box Height | BP_XenoCore_DialogueAnchor › XenoCore › Dialogue |
How far above the speaker the dialogue box's bottom edge sits. Default 120 |
| Box Widget Class | BP_XenoCore_DialogueAnchor › XenoCore › Dialogue |
The dialogue box widget. Empty uses XenoCore UI › Dialogue Box |
| Bob Amplitude, Bob Speed | W_XenoCore_NpcLabel › XenoCore › NPC |
The chevron's bounce |
A Show Dialogue chain that never closes
Show Dialogue does not close the box, and Play Dialogue does. End every branch that
uses Show Dialogue with Close Dialogue. A branch that forgets is closed for you after
2 seconds, with a LogXenoDialogue warning: "conversation with ... was left open with no line
waiting - closing it." The player is released, but the last line hangs on screen for those
2 seconds, so treat the warning as a bug in the graph.
Branch on Is Trade Verb, never on Verb Index
Trade is inserted before your Extra Interact Verbs, so the verb numbers move when you add one. A graph comparing Verb Index to 1 opens the wrong thing without any error.
Only two verbs: a third is dropped
Only A (IA_XenoCore_Interact, verb 0) and X (IA_XenoCore_InteractSecondary, verb 1) have
inputs. Every interactable's list is cut to two before the prompt draws it, and the press
checks the same list, so a third verb is neither drawn nor pressable. It logs one warning per actor (LogXenoInteract:
"offers N verbs but only 2 interact inputs exist (A, X) - dropping ..."). An NPC with a
Trade Offers table already uses X for Trade, so its Extra Interact Verbs are all
dropped.
Extending it¶
- A new NPC: place
B_XenoCore_Npc(or your own child of it underContent/MyGame/) and fill in the per-instance fields. It starts blank; copy settings fromB_XenoCore_Npc_Sampleif you want a worked example. A town is one class with many placed actors, not a Blueprint per person. See the recipe Make an NPC talk. - A place a quest sends you to: place a XenoCore Quest Location (in Place Actors) and give it a Location Id matching the objective's Target Id. It counts when the leader walks in; it has no prompt. See Give a quest to defeat enemies, talk to someone, or go somewhere.
- Branching conversations: replace the Play Dialogue node in On Interact with a chain of Show Dialogue nodes and ordinary Blueprint branches. See Branch a conversation.
- Anything else the player can use (a lever, a door, a sign): create a Blueprint Class with
XenoCoreInteractableActoras its parent, set Interact Verb, Secondary Interact Verb and Interact Range, and handle On Interact. It registers itself. Set Interact Enabled switches it off and makes the prompt re-decide at once; override Can Interact for conditions. See Add an interactable object. - Restyling: duplicate
W_XenoCore_InteractPrompt,W_XenoCore_DialogueBoxorW_XenoCore_NpcLabelinto your own folder and change the look. Point Project Settings › Game › XenoCore UI › Interact Prompt or Dialogue Box at your copy (the name label is set on the NPC's Overhead Widget Class). The dialogue anchor itself is XenoCore Content › Dialogue Anchor. Keep the parent class, and see The two settings pages for the cooking caveat.
Never edit the chest's Lyra side or Lyra's interaction ability; the chest's behaviour lives in XenoCore.
For programmers: classes
UXenoCoreInteractionSubsystem (world subsystem) keeps the registry, picks the nearest actor,
draws the prompt and routes the press (Handle Interact Press, called by
GA_XenoCore_InteractPress / GA_XenoCore_InteractPressSecondary with verb 0 or 1; the list is
capped by MaxPressableVerbs in Get Offered Verbs). Anything with a prompt implements
IXenoCoreInteractable and registers in BeginPlay / unregisters in EndPlay;
AXenoCoreInteractableActor does that for Blueprint children, and a C++ class implementing the
interface directly must do it itself. The NPC is AXenoCoreNpcCharacter (its Interact calls
On Interact), the label UXenoCoreWorldLabelBase, the prompt UXenoCoreInteractPromptBase,
dialogue UXenoCoreDialogueSubsystem with AXenoCoreDialogueAnchor. The chest implements both
IXenoCoreInteractable and Lyra's IInteractableTarget. While the prompt is up the player holds
Status.XenoCore.Looting; a conversation adds Gameplay.MovementStopped,
Status.XenoCore.Dialogue and SetIgnoreLookInput.
Why it's built this way¶
For programmers
- Proximity, not aim. Lyra's interaction ability scans with a camera line trace, which answers "what am I looking at". Every prompt here means "what is near me", so XenoCore uses a registry and a distance check instead. Lyra's option list is also protected on an unexported class, so C++ outside Lyra cannot read it.
- One owner for the button. A is also Jump (Lyra) and Palette Confirm, so the subsystem both shows the prompt and claims the button. A second system drawing its own prompt would be a second owner of the same button.
- A base class for designers, not a Blueprint interface. Making the interface
Blueprint-implementable would have left every Blueprint responsible for registering itself, and
forgetting reads as "my lever has no prompt" with nothing logged.
AXenoCoreInteractableActorregisters in its own Begin Play, which a child's Begin Play runs inside. - Two verb fields, not a list. Only two interact buttons exist, so the base cannot express a third one nobody can press.
- Each actor owns its range. The prompt, the name plate and the press all read one number from the actor, so nothing can show at one distance and act at another.
- Blueprint decides what happens. C++ decides when someone was talked to; the NPC's On Interact graph decides what happens. Blueprint is already a branching editor with breakpoints, so there is no custom dialogue-tree asset.
- The box is attached, not projected. The dialogue box is a screen-space widget component on an anchor actor that attaches to the speaker, so it moves in step with the rendered frame.
- Holding the camera as well as the pawn.
Gameplay.MovementStoppedonly reaches the movement component. Look input goes straight to the controller, so the dialogue subsystem also callsSetIgnoreLookInput. Both are counters, and the subsystem balances them.
Next: Quests · Shops and trade · Events you can listen to